Sensitivity analysis enlightens effects of connectivity in a Neural Mass Model under Control-Target mode.
Paper
Loaded from Europe PMC by your browser; OSCR does not store it: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Python · 780 lines · 19 KB · no license
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- Created on Tue Jan 20 14:39:12 2026
- @author: anais
- """
- from numpy import *
- import math
- #%% parameters for the neural model
- def get_FixedParametersForCurrents() :
- Jnmda=0.15
- G=0.69
- Wplus = 1.4
- Wminus = 1
- Wi = 0.7
- We = 1
- I0 = 0.382
- global autocoupling_E
- global basal_forcing_E
- global coupling_EtoI
- global autocoupling_I_abs
- global basal_forcing_I
- autocoupling_E = Wplus*Jnmda
- basal_forcing_E = We * I0
- coupling_EtoI = Jnmda
- autocoupling_I_abs = Wminus #inhibitory autocoupling (in absolute value)
- basal_forcing_I = Wi*I0
- return(autocoupling_E,basal_forcing_E,coupling_EtoI,autocoupling_I_abs,basal_forcing_I,Jnmda,G)
- def get_FixedParametersForStates() :
- BetaE=6.6
- AlphaE=72
- BetaI=180
- AlphaI=530
- return(BetaE,AlphaE,BetaI,AlphaI)
- def get_FixedParametersForExcFiringRates() :
- a=310.
- b=125
- d=0.16
- return(a,b,d)
- def get_FixedParametersForInhFiringRates() :
- a=615.
- b=177
- d=0.087
- return(a,b,d)
- #%% parameters for the hemodynamic and bold models
- def get_FixedParametersForHemodynamics() :
- alpha=0.32
- gamma=0.41
- kappa=0.65
- tau=0.98
- rho=0.34
- return(alpha,gamma,kappa,tau,rho)
- def get_FixedParametersForBold() :
- Theta0=28.265*3
- rho=0.34
- TE=0.03 #30ms
- epsilon=0.47
- r0=110
- V0=0.02
- k1 = 4.3*Theta0*rho*TE
- k2 = epsilon*r0*rho*TE
- k3 = 1-epsilon
- return(V0,k1,k2,k3)
- #%% Fixing the type of connectivity
- def get_Matrix_kE_ForATypeOfConnectivity(TypeOfConnectivity):
- if TypeOfConnectivity=='EE':
- k = array([[0., 1.],
- [1., 0.]])
- elif TypeOfConnectivity=='II':
- k = array([[0., 0.],
- [0., 0.]])
- elif TypeOfConnectivity=='EI':
- k = array([[0., 1.],
- [0., 0.]])
- elif TypeOfConnectivity == 'IE':
- k = array([[0., 0.],
- [1., 0.]])
- return(k)
- def get_k_inh(k): # for the inhibitory pool. k_inh is a matrix that contains 0 on the diagonal and (1-k) everywhere else.
- mat1_0diago = ones(k.shape)
- for i in range(len(k)):
- mat1_0diago[i,i] = 0 #mat1_0diago contains 0 on the diagonal and 1 everywhere else
- k_inh = mat1_0diago-k
- return(k_inh)
- #%% Simulations with the neural model
- def FindFixedPoint(autocoupling_E,coupling_ItoE_abs,basal_forcing_E,coupling_EtoI,autocoupling_I_abs,basal_forcing_I,M,G,k,Jnmda,Tglu,Tgaba,N): #cf fonction EtudeStabilite papier tuning
- #----------Duration of the first simulation and timeline
- T0=0
- Tmax = 10
- (Time,dt) = get_Timeline(T0,Tmax)
- #---- Stimulation forcing on the excitatory pools
- StimulationFunction = zeros((N,len(Time)))
- #------- Initial conditions
- dsn_dt = 1
- dsg_dt = 1
- sn_fp = 0.5*ones((N,1))
- sg_fp = 0.5*ones((N,1))
- sn_fp = 0.1*ones((N,1))
- sg_fp = 0.05*ones((N,1))
- simu=0
- while all(abs(dsn_dt)>1e-10) and all(abs(dsg_dt)>1e-10): #We continue the simulation until we get close enough to the fixed point
- simu=simu+1
- Sn0 = sn_fp
- Sg0 = sg_fp
- (Xn,Xg,Rn,Rg,dSndt,dSgdt,Sn,Sg) = get_Dynamics(autocoupling_E,coupling_ItoE_abs,basal_forcing_E,coupling_EtoI,autocoupling_I_abs,basal_forcing_I,M,G,k,Jnmda,Tglu,Tgaba,Sn0,Sg0,dt,Time,StimulationFunction)
- sn_fp = reshape(Sn[:,-1],(N,1))
- sg_fp = reshape(Sg[:,-1],(N,1))
- dsn_dt = reshape(dSndt[:,-1],(N,1))
- dsg_dt = reshape(dSgdt[:,-1],(N,1))
- xn_fp = reshape(Xn[:,-1],(N,1))
- xg_fp = reshape(Xg[:,-1],(N,1))
- rn_fp = reshape(Rn[:,-1],(N,1))
- rg_fp = reshape(Rg[:,-1],(N,1))
- return(sn_fp,sg_fp,xn_fp,xg_fp,rn_fp,rg_fp)
- def get_Timeline(T0,Tmax):
- dt=0.001
- sampling=round((Tmax-T0)/dt)
- Tmax = T0 + dt*sampling
- Time=linspace(T0,Tmax,int(sampling)+1)
- return(Time,dt)
- def get_Dynamics(autocoupling_E,coupling_ItoE_abs,basal_forcing_E,coupling_EtoI,autocoupling_I_abs,basal_forcing_I,M,G,k,Jnmda,Tglu,Tgaba,Sn0,Sg0,dt,Time,StimulationFunction):
- N= Sn0.shape[0]
- # memory allocation
- Sn = zeros((N,len(Time)))
- Sg = zeros((N,len(Time)))
- dSndt = zeros((N,len(Time)))
- dSgdt = zeros((N,len(Time)))
- Xn = zeros((N,len(Time)))
- Xg = zeros((N,len(Time)))
- Rn = zeros((N,len(Time)))
- Rg = zeros((N,len(Time)))
- # we save the initial condition
- Sn[:,0] = reshape(Sn0,(Sn0.T).shape)
- Sg[:,0] = reshape(Sg0,(Sg0.T).shape)
- for j in range(len(Time)):
- sn_past = reshape(Sn[:,j],(N,1))
- sg_past = reshape(Sg[:,j],(N,1))
- t=Time[j]
- (xn,xg,rn,rg,dsndt,dsgdt,sn_new,sg_new) = Integration(autocoupling_E,coupling_ItoE_abs,basal_forcing_E,coupling_EtoI,autocoupling_I_abs,basal_forcing_I,M,G,k,Jnmda,Tglu,Tgaba,sn_past,sg_past,dt,j,StimulationFunction)
- dSndt[:,j] = reshape(dsndt,(dsndt.T).shape)
- dSgdt[:,j] = reshape(dsgdt,(dsgdt.T).shape)
- Rn[:,j] = reshape(rn,(rn.T).shape)
- Rg[:,j] = reshape(rg,(rg.T).shape)
- Xn[:,j] = reshape(xn,(xn.T).shape)
- Xg[:,j] = reshape(xg,(xg.T).shape)
- if j<len(Time)-1: # We do not keep the last point (i.e. Sn(t+dt) obtained with dSndt(t), for t=Time[-1]). Thus, Sn and dSndt have the same dimensions and the last point of each array corresponds to Sn(t) and dSndt(t) with t=Time[-1]
- Sn[:,j+1] = reshape(sn_new,(sn_new.T).shape)
- Sg[:,j+1] = reshape(sg_new,(sg_new.T).shape)
- return(Xn,Xg,Rn,Rg,dSndt,dSgdt,Sn,Sg)
- def Integration(autocoupling_E,coupling_ItoE_abs,basal_forcing_E,coupling_EtoI,autocoupling_I_abs,basal_forcing_I,M,G,k,Jnmda,Tglu,Tgaba,sn,sg,dt,j,StimulationFunction):
- StimulationFunction_at_t = reshape(StimulationFunction[:,j],sn.shape)
- (xn,xg,rn,rg,dsndt,dsgdt) = get_Derivatives(sn,sg,autocoupling_E,coupling_ItoE_abs,basal_forcing_E,coupling_EtoI,autocoupling_I_abs,basal_forcing_I,M,G,k,Jnmda,Tglu,Tgaba,j,StimulationFunction_at_t)
- N = sn.shape[0]
- sn_next=zeros(sn.shape, dtype=float)
- sg_next=zeros(sg.shape, dtype=float)
- sn_next = sn + dt*dsndt
- sg_next = sg + dt*dsgdt
- return(xn,xg,rn,rg,dsndt,dsgdt,sn_next,sg_next)
- def get_Derivatives(sn,sg,autocoupling_E,coupling_ItoE_abs,basal_forcing_E,coupling_EtoI,autocoupling_I_abs,basal_forcing_I,M,G,k,Jnmda,Tglu,Tgaba,j,StimulationFunction_at_t):
- #--- Currents
- xn = ExcitatoryCurrent(autocoupling_E,coupling_ItoE_abs,basal_forcing_E,sn,sg,j,StimulationFunction_at_t,M,G,k,Jnmda)
- xg = InhibitoryCurrent (coupling_EtoI,autocoupling_I_abs,basal_forcing_I,sn,sg,j,M,G,k,Jnmda)
- #--- Firing rates
- rn=ExcitatoryFiringRate(xn)
- rg=InhibitoryFiringRate(xg)
- #--- Differential equations on state variables
- (BetaE,AlphaE,BetaI,AlphaI) = get_FixedParametersForStates()
- dsndt = -BetaE*sn+AlphaE*Tglu*(1-sn)*rn
- dsgdt = -BetaI*sg+AlphaI*Tgaba*(1-sg)*rg
- return(xn,xg,rn,rg,dsndt,dsgdt)
- #--- functions for firing rates
- def ExcitatoryFiringRate(x):
- (a,b,d) = get_FixedParametersForExcFiringRates()
- y=a*x-b
- result=zeros(y.shape, dtype=float)
- for i in range(len(y)):
- result[i] = y[i]/(1-math.exp(-d*y[i]))
- # if y[i]!=0:
- # result[i] = y[i]/(1-math.exp(-d*y[i]))
- # else:
- # result[i]=0
- return(result)
- def InhibitoryFiringRate(x):
- (a,b,d) = get_FixedParametersForInhFiringRates()
- y=a*x-b
- result=zeros(y.shape, dtype=float)
- for i in range(len(y)):
- result[i] = y[i]/(1-math.exp(-d*y[i]))
- # if y[i]!=0:
- # result[i] = y[i]/(1-math.exp(-d*y[i]))
- # else:
- # result[i]=0
- return(result)
- #--- functions for currents
- def ExcitatoryCurrent (autocoupling_E,coupling_ItoE_abs,basal_forcing_E,sn,sg,j,StimulationFunction_at_t,M,G,k,Jnmda):
- xn = autocoupling_E*sn - coupling_ItoE_abs*sg + basal_forcing_E + StimulationFunction_at_t + G*Jnmda*dot( k*M,sn )
- return(xn)
- def InhibitoryCurrent (coupling_EtoI,autocoupling_I_abs,basal_forcing_I,sn,sg,j,M,G,k,Jnmda):
- k_inh = get_k_inh(k)
- xg = coupling_EtoI*sn - autocoupling_I_abs*sg + basal_forcing_I + G*Jnmda*dot( k_inh*M,sn )
- return(xg)
- #%% Simulations with the hemodynamic and bold models
- def HemoBoldDynamics(SnDyna,z0,f0,v0,q0,dt,Time):
- bold0=BoldFunction(v0,q0)
- N= SnDyna.shape[0]
- #allocation mémoire
- Z = zeros((N,len(Time)))
- F = zeros((N,len(Time)))
- V = zeros((N,len(Time)))
- Q = zeros((N,len(Time)))
- BOLD = zeros((N,len(Time)))
- # we keep the initial condition
- Z[:,0] = reshape(z0,(z0.T).shape)
- F[:,0] = reshape(f0,(f0.T).shape)
- V[:,0] = reshape(v0,(v0.T).shape)
- Q[:,0] = reshape(q0,(q0.T).shape)
- BOLD[:,0] = reshape(bold0,(bold0.T).shape)
- for j in range(1,len(Time)):
- sn_past = SnDyna[0:N,j-1:j]
- z_past = reshape(Z[:,j-1],(N,1))
- f_past = reshape(F[:,j-1],(N,1))
- v_past = reshape(V[:,j-1],(N,1))
- q_past = reshape(Q[:,j-1],(N,1))
- bold_past=BoldFunction(v_past,q_past)
- (z_new,f_new,v_new,q_new) = HemodynamicsIntegration(sn_past,z_past,f_past,v_past,q_past,dt)
- bold_new=BoldFunction(v_new,q_new)
- Z[:,j] = reshape(z_new,(z_new.T).shape)
- F[:,j] = reshape(f_new,(f_new.T).shape)
- V[:,j] = reshape(v_new,(v_new.T).shape)
- Q[:,j] = reshape(q_new,(q_new.T).shape)
- BOLD[:,j] = reshape(bold_new,(bold_new.T).shape)
- return(Z,F,V,Q,BOLD)
- def HemodynamicsIntegration(sn,z,f,v,q,dt):
- (alpha,gamma,kappa,tau,rho) = get_FixedParametersForHemodynamics()
- dzdt = sn-kappa*z-gamma*(f-1)
- dfdt = z
- dvdt = (1/tau)*(f-pow(v,1/alpha))
- dqdt = (1/(tau*rho))*f*(1-pow((1-rho),1/f)) - (1/tau)*q*pow(v,(1/alpha)-1)
- z_next=zeros(z.shape, dtype=float)
- f_next=zeros(f.shape, dtype=float)
- v_next=zeros(v.shape, dtype=float)
- q_next=zeros(q.shape, dtype=float)
- z_next=z+dt*dzdt
- f_next=f+dt*dfdt
- v_next=v+dt*dvdt
- q_next=q+dt*dqdt
- return(z_next,f_next,v_next,q_next)
- def BoldFunction(v,q):
- (V0,k1,k2,k3) = get_FixedParametersForBold()
- y = V0*(k1*(1-q)+k2*(1-q*(1/v))+k3*(1-v))
- return(y)
- #%%% Sensitivities
- #%% Sensitivities of the isolated pools (with their autocoupling)
- def CloseLoopSensitivity_Pool_E(Sn,zE,autocoupling_E,Tglu):
- Sensi_Sn_zE = zeros(Sn.shape)
- (BetaE,AlphaE,BetaI,AlphaI) = get_FixedParametersForStates()
- (XN,RN,DRN_DXN) = Calculate_XN_RN_DRNDXN_PoolE(Sn,autocoupling_E,zE)
- # Sensitivity of sn w.r.t. the forcing zE
- Sensi_Sn_zE = 1/( ( (BetaE + AlphaE*Tglu*RN)/(AlphaE*Tglu*(1-Sn)*DRN_DXN) ) - autocoupling_E)
- # Feedback gain
- Gain = (AlphaE*Tglu*(1-Sn)*DRN_DXN*autocoupling_E)/(BetaE + AlphaE*Tglu*RN)
- return(Sensi_Sn_zE, Gain)
- def CloseLoopSensitivity_Pool_I(Sg,zI,autocoupling_I_abs,Tgaba):
- Sensi_Sg_zI = zeros(Sg.shape)
- (BetaE,AlphaE,BetaI,AlphaI) = get_FixedParametersForStates()
- (XG,RG,DRG_DXG) = Calculate_XG_RG_DRGDXG_PoolI(Sg,autocoupling_I_abs,zI)
- # Sensitivity of sg w.r.t. the forcing zI
- Sensi_Sg_zI = 1/( ( (BetaI + AlphaI*Tgaba*RG)/(AlphaI*Tgaba*(1-Sg)*DRG_DXG) ) + autocoupling_I_abs )
- # Feedback gain
- Gain = (AlphaI*Tgaba*(1-Sg)*DRG_DXG * (-autocoupling_I_abs))/(BetaI + AlphaI*Tgaba*RG)
- return(Sensi_Sg_zI, Gain)
- def Calculate_XN_RN_DRNDXN_PoolE(Sn,autocoupling_E,zE):
- XN = zeros(Sn.shape)
- RN = zeros(Sn.shape)
- DRN_DXN = zeros(Sn.shape)
- (Aexc,Bexc,Dexc) = get_FixedParametersForExcFiringRates()
- XN = autocoupling_E*Sn + zE
- RN = (Aexc * XN-Bexc) /(1-exp(-Dexc*(Aexc * XN - Bexc)))
- DRN_DXN = (Aexc/2) * ( (exp(Dexc*(Aexc * XN - Bexc)) -1 - Dexc*(Aexc * XN - Bexc) ) / (cosh(Dexc*(Aexc * XN - Bexc)) -1) )
- return(XN,RN,DRN_DXN)
- def Calculate_XG_RG_DRGDXG_PoolI(Sg,autocoupling_I_abs,zI):
- XG = zeros(Sg.shape)
- RG = zeros(Sg.shape)
- DRG_DXG = zeros(Sg.shape)
- (Ainh,Binh,Dinh) = get_FixedParametersForInhFiringRates()
- XG = - autocoupling_I_abs*Sg + zI
- RG = (Ainh * XG - Binh) /(1-exp(-Dinh*(Ainh * XG - Binh)))
- DRG_DXG =(Ainh/2) * ( (exp(Dinh*(Ainh * XG - Binh)) -1 - Dinh*(Ainh * XG - Binh) ) / (cosh(Dinh*(Ainh * XG - Binh)) -1) )
- return(XG,RG,DRG_DXG)
- #%% Sensitivities of the isolated regions (as functions of open loop sensitivities of the pools)
- #---- Open loop sensitivities of the pools
- def OpenLoopSensitivities_Pools(Sn,Sg,zE,zI,autocoupling_E,autocoupling_I_abs,Tglu,Tgaba):
- (Sensi_Sn_zE, Gain_E) = CloseLoopSensitivity_Pool_E(Sn,zE,autocoupling_E,Tglu)
- (Sensi_Sg_zI, Gain_I) = CloseLoopSensitivity_Pool_I(Sg,zI,autocoupling_I_abs,Tgaba)
- return(Sensi_Sn_zE, Sensi_Sg_zI)
- #---- Close loop sensitivities of the isolated area
- def CloseLoopSensitivities_OneRegion(Sn,Sg,xE,xI,autocoupling_E,coupling_ItoE_abs,coupling_EtoI,autocoupling_I_abs,Tglu,Tgaba):
- (BetaE,AlphaE,BetaI,AlphaI) = get_FixedParametersForStates()
- # ---initialisation
- # open loop sensitivities
- Sensi_Sn_xE_O = zeros(Sn.shape)
- Sensi_Sg_xI_O = zeros(Sn.shape)
- # close loop sensitivities
- Sensi_Sn_xE = zeros(Sn.shape) # sensitivity of sn w.r.t. the forcing xE
- Sensi_Sg_xE = zeros(Sn.shape) # sensitivity of sg w.r.t. the forcing xE
- Sensi_Sn_xI = zeros(Sn.shape) # sensitivity of sn w.r.t. the forcing xI
- Sensi_Sg_xI = zeros(Sn.shape) # sensitivity of sg w.r.t. the forcing xI
- # We evaluate the open loop sensitivities using the fixed point in the close loop system
- ZE = - coupling_ItoE_abs*Sg + xE
- ZI = coupling_EtoI*Sn + xI
- (Sensi_Sn_xE_O, Sensi_Sg_xI_O) = OpenLoopSensitivities_Pools(Sn,Sg,ZE,ZI,autocoupling_E,autocoupling_I_abs,Tglu,Tgaba)
- # Feedback gain
- Gain = -coupling_EtoI * coupling_ItoE_abs * Sensi_Sn_xE_O * Sensi_Sg_xI_O
- # We calculate the close loop sensitivities, using the open loop sensitivities and the feedback gain
- Sensi_Sn_xE = Sensi_Sn_xE_O/(1-Gain)
- Sensi_Sg_xE = (coupling_EtoI * Sensi_Sn_xE_O * Sensi_Sg_xI_O )/(1-Gain)
- Sensi_Sn_xI = (-coupling_ItoE_abs * Sensi_Sn_xE_O * Sensi_Sg_xI_O)/(1-Gain)
- Sensi_Sg_xI = Sensi_Sg_xI_O/(1-Gain)
- return(Sensi_Sn_xE,Sensi_Sg_xE,Sensi_Sn_xI,Sensi_Sg_xI,Sensi_Sn_xE_O,Sensi_Sg_xI_O,Gain)
- #%% Sensitivities of two regions (as functions of open loop sensitivitie of each region)
- #---- Open loop sensitivities of one region
- def OpenLoopSensitivities_OneRegion(Sni,Sgi,xEi,xIi,autocoupling_E_i,coupling_ItoE_abs_i,coupling_EtoI_i,autocoupling_I_abs_i,Tglui,Tgabai): #give the input arguments only for the region of interest
- (Sensi_Sni_xEi,Sensi_Sgi_xEi,Sensi_Sni_xIi,Sensi_Sgi_xIi,Sensi_Sni_xEi_O,Sensi_Sgi_xIi_O,Gain) = CloseLoopSensitivities_OneRegion(Sni,Sgi,xEi,xIi,autocoupling_E_i,coupling_ItoE_abs_i,coupling_EtoI_i,autocoupling_I_abs_i,Tglui,Tgabai)
- return(Sensi_Sni_xEi,Sensi_Sgi_xEi,Sensi_Sni_xIi,Sensi_Sgi_xIi)
- #---- Close loop sensitivities of two regions
- def CloseLoopSensitivities_TwoRegions(Sn_fp,Sg_fp,autocoupling_E,coupling_ItoE_abs,basal_forcing_E,coupling_EtoI,autocoupling_I_abs,basal_forcing_I,Tglu,Tgaba,G,Jnmda,k,M,control,target):
- Kappa = G*Jnmda*M
- Currents_OtherRegions_ToE = dot(k*Kappa,Sn_fp)
- k_inh = get_k_inh(k)
- Currents_OtherRegions_ToI = dot(k_inh*Kappa,Sn_fp)
- #--- Region 1 (open loop)
- i=control
- (SnC,SgC,coupling_ItoE_abs_C,TgabaC,TgluC) = get_ParametersForRegion_i(i,Sn_fp,Sg_fp,coupling_ItoE_abs,Tgaba,Tglu)
- xEC = basal_forcing_E[i] + Currents_OtherRegions_ToE[i]
- xIC = basal_forcing_I + Currents_OtherRegions_ToI[i]
- (Sensi_SnC_xEC,Sensi_SgC_xEC,Sensi_SnC_xIC,Sensi_SgC_xIC) = OpenLoopSensitivities_OneRegion(SnC,SgC,xEC,xIC,autocoupling_E,coupling_ItoE_abs_C,coupling_EtoI,autocoupling_I_abs,TgluC,TgabaC)
- #--- Region 2 (open loop)
- i=target
- (SnT,SgT,coupling_ItoE_abs_T,TgabaT,TgluT) = get_ParametersForRegion_i(i,Sn_fp,Sg_fp,coupling_ItoE_abs,Tgaba,Tglu)
- xET = basal_forcing_E[i] + Currents_OtherRegions_ToE[i]
- xIT = basal_forcing_I + Currents_OtherRegions_ToI[i]
- (Sensi_SnT_xET,Sensi_SgT_xET,Sensi_SnT_xIT,Sensi_SgT_xIT) = OpenLoopSensitivities_OneRegion(SnT,SgT,xET,xIT,autocoupling_E,coupling_ItoE_abs_T,coupling_EtoI,autocoupling_I_abs,TgluT,TgabaT)
- #--- Feedback gain
- (G12,G21,Gain) = FeedbackGain_TwoRegions(k,Kappa,Sensi_SnC_xEC,Sensi_SnC_xIC,Sensi_SnT_xET,Sensi_SnT_xIT)
- #--- Close loop system
- (dSnC_dBEC,dSnT_dBEC) = SensitivitiesTwoRegions_Sn_wrt_BEC(Sensi_SnC_xEC,Gain,G21)
- return(dSnC_dBEC, dSnT_dBEC, Gain, Sensi_SnC_xEC, Sensi_SgC_xEC, Sensi_SnC_xIC, Sensi_SgC_xIC, Sensi_SnT_xET, Sensi_SgT_xET, Sensi_SnT_xIT, Sensi_SgT_xIT)
- def get_ParametersForRegion_i(i,Sn,Sg,b,Tgaba,Tglu):
- Sni = Sn[i]
- Sgi = Sg[i]
- bi = b[i]
- Tgabai = Tgaba[i]
- Tglui = Tglu[i]
- return(Sni,Sgi,bi,Tgabai,Tglui)
- def FeedbackGain_TwoRegions(k,Kappa,Sensi_Sn1_xE1,Sensi_Sn1_xI1,Sensi_Sn2_xE2,Sensi_Sn2_xI2):
- G12 = Sensi_Sn1_xE1 * k[0,1]* Kappa[0,1] + Sensi_Sn1_xI1 * (1-k[0,1])* Kappa[0,1]
- G21 = Sensi_Sn2_xE2 * k[1,0] * Kappa[1,0] + Sensi_Sn2_xI2 * (1-k[1,0]) * Kappa[1,0]
- Gain = G12 * G21
- return(G12,G21,Gain)
- def SensitivitiesTwoRegions_Sn_wrt_BEC(Sensi_Sn1_xE1,Gain,G21):
- dSn1_dBE1 = (Sensi_Sn1_xE1)/(1-Gain)
- dSn2_dBE1 = G21 * dSn1_dBE1
- return(dSn1_dBE1,dSn2_dBE1)
functions.py, no license · at the source
Overview
- Normandie Univ, UNICAEN, PSL Research University, EPHE, INSERM, U1077, CHU de Caen, GIP Cyceron, Neuropsychologie et Imagerie de la Mémoire Humaine, Université de Normandie, Caen, France
- CNRS, INPT, UPS, LAPLACE, Université de Toulouse, Toulouse, France
- Centre de Recherches sur la Cognition Animale (CRCA), Centre de Biologie Intégrative (CBI), CNRS, UPS, Université de Toulouse, Toulouse, France
- LMD/IPSL, CNRS, École Polytechnique, ENS, Sorbonne Université, Paris, France
Abstract
Biophysical models of human brain represent the latter as a graph of inter-connected neural regions. Building from the model by Naskar et al. (Network Neuroscience, 2021), our motivation was to understand how these brain regions can be connected at neural level to implement some inhibitory control, which calls for inhibitory connectivity rarely considered in such models. In this model, regions are made of inter-connected excitatory and inhibitory pools of neurons, but are long-range connected only via excitatory pools (mutual excitation). We thus extend this model by generalizing connectivity, and we analyse how connectivity affects the behaviour of this model. Focusing on the simplest paradigm made of a Control area and a Target area, we explore four typical kinds of connectivity: mutual excitation, Target inhibition by Control, Control inhibition by Target, and mutual inhibition. For this, we build an analytical sensitivity framework, nesting up sensitivities of isolated pools, of isolated regions, and of the full system. We show that inhibitory control can emerge only in Target inhibition by Control and mutual inhibition connectivities. We next offer an analysis of how the model sensitivities depends on connectivity structure, depending on a parameter controling the strength of the self-inhibition within Target region. Finally, we illustrate the effect of connectivity structure upon control effectivity in response to an external forcing in the Control area. Beyond the case explored here, our methodology to build analytical sensitivities by nesting up levels (pool, region, system) lays the groundwork for expressing nested sensitivities for more complex network configurations, either for this model or any other one.
Reproduced under the paper's license (CC BY), from the paper cited above.
Repository
Its files are read in the Code ↔ Paper reader above.
supp:PMC13008111/pcbi.1014035.s003.zip
Availability: 1 check, the latest on 30 September 2026: the link answers (HTTP 200)
- 30 September 2026: the link answers (HTTP 200)
12 files
- 00-functions/
functions.py , Python, 780 lines - 02-fig02/
run.py , Python, 133 lines - 04-fig04/
run.py , Python, 259 lines - 05-fig05/
run.py , Python, 258 lines - 07-fig07/
run.py , Python, 449 lines - 08-fig08/
run.py , Python, 379 lines - 09-fig09/
run.py , Python, 379 lines - 10-fig10/
run.py , Python, 379 lines - 11-fig11/
run.py , Python, 379 lines - 12-fig12/
run.py , Python, 268 lines - 13-fig13/
run.py , Python, 210 lines - run.sh, Shell, 26 lines
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 12 scripts, each with its path and the digest of its content;
- no match between paragraphs and code yet;
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
No dataset and no data link were found in the paper.
Data Availability
All relevant data are within the manuscript and its Supporting Information files.
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 1, 30 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 9 authors, 8 MeSH terms, 3 funders, 36 references.
Cite
This paper
Vallet, A., Blanco, S., Chevallier, C., Eustache, F., Gautrais, J., Grandpeix, J.-Y., Joly, J.-L., Segobin, S., & Gagnepain, P. (2026). Sensitivity analysis enlightens effects of connectivity in a Neural Mass Model under Control-Target mode. PLoS computational biology, 22(3), e1014035. https://
BibTeX
@article{vallet2026sensi
author = {Vallet, Anaïs and Blanco, Stéphane and Chevallier, Coline and Eustache, Francis and Gautrais, Jacques and Grandpeix, Jean-Yves and Joly, Jean-Louis and Segobin, Shailendra and Gagnepain, Pierre},
title = {{Sensitivity analysis enlightens effects of connectivity in a Neural Mass Model under Control-Target mode}},
journal = {PLoS computational biology},
year = {2026},
month = mar,
volume = {22},
number = {3},
pages = {e1014035},
publisher = {PLOS},
issn = {1553-734X},
doi = {10.1371/
url = {https://
pmid = {41871132},
pmcid = {PMC13008111}
}
RIS
TY - JOUR
AU - Vallet, Anaïs
AU - Blanco, Stéphane
AU - Chevallier, Coline
AU - Eustache, Francis
AU - Gautrais, Jacques
AU - Grandpeix, Jean-Yves
AU - Joly, Jean-Louis
AU - Segobin, Shailendra
AU - Gagnepain, Pierre
TI - Sensitivity analysis enlightens effects of connectivity in a Neural Mass Model under Control-Target mode
T2 - PLoS computational biology
J2 - PLoS Comput Biol
PY - 2026
DA - 2026/
VL - 22
IS - 3
SP - e1014035
SN - 1553-734X
PB - PLOS
DO - 10.1371/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1371/
"type": "article-journal",
"title": "Sensitivity analysis enlightens effects of connectivity in a Neural Mass Model under Control-Target mode",
"container-title": "PLoS computational biology",
"author": [
{
"family": "Vallet",
"given": "Anaïs"
},
{
"family": "Blanco",
"given": "Stéphane"
},
{
"family": "Chevallier",
"given": "Coline"
},
{
"family": "Eustache",
"given": "Francis"
},
{
"family": "Gautrais",
"given": "Jacques"
},
{
"family": "Grandpeix",
"given": "Jean-Yves"
},
{
"family": "Joly",
"given": "Jean-Louis"
},
{
"family": "Segobin",
"given": "Shailendra"
},
{
"family": "Gagnepain",
"given": "Pierre"
}
],
"container-title-short":
"volume": "22",
"issue": "3",
"page": "e1014035",
"DOI": "10.1371/
"PMID": "41871132",
"PMCID": "PMC13008111",
"ISSN": "1553-734X",
"publisher": "PLOS",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
3,
23
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1016/j.isci.2022.105516 [code]
- Attentional capture mediates the emergence and suppression of intrusive memories.Journal: iScienceIn common: 5 references, 2 authors
- [2] doi:10.1126/sciadv.adq8336 [code]
- Plasticity of human resilience mechanisms.Journal: Science advancesIn common: 4 references, 2 authors
- [3] doi:10.1038/s41467-022-30855-x [code]
- Altered predictive control during memory suppression in PTSD.Journal: Nature communicationsIn common: computational, 3 references, 2 authors
- [4] doi:10.7554/elife.106194 [code]
- Virtual Brain Inference (VBI), a flexible and integrative toolkit for efficient probabilistic inference on whole-brain models.Journal: eLifeIn common: Matplotlib, NumPy, computational, 10 references
- [5] doi:10.1002/advs.202406440 [code]
- TVB C++: A Fast and Flexible Back-End for The Virtual Brain.Journal: Advanced science (Weinheim, Baden-Wurttemberg, Germany)In common: Matplotlib, NumPy, 8 references
- [6] doi:10.1038/s41598-024-83542-w [code]
- Symmetry breaking organizes the brain's resting state manifold.Journal: Scientific reportsIn common: computational, 8 references
- [7] doi:10.1371/journal.pcbi.1012595 [code]
- Homeodynamic feedback inhibition control in whole-brain simulations.Journal: PLoS computational biologyIn common: Matplotlib, NumPy, computational, 7 references
- [8] doi:10.1016/j.neuroimage.2023.119926 [code]
- Reduced emergent character of neural dynamics in patients with a disrupted connectome.Journal: NeuroImageIn common: NumPy, 8 references
- [9] doi:10.1371/journal.pcbi.1011434 [code]
- A multi-layer mean-field model of the cerebellum embedding microstructure and population-specific dynamics.Journal: PLoS computational biologyIn common: Matplotlib, NumPy, computational, 6 references
- [10] doi:10.1162/netn_a_00410 [code]
- Neural mass modeling for the masses: Democratizing access to whole-brain biophysical modeling with FastDMF.Journal: Network neuroscience (Cambridge, Mass.)In common: NumPy, computational, 7 references
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 1 repository of the authors' code, each at its verified commit and with its license, 12 scripts, and 0 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:7f4cb05453b7dccf…
Add the badge to the code's README
If you are an author or a maintainer of this paper's code, you can add this badge. It says what OSCR knows of the paper (its code, its validated tracing map) and links the code to this page. Paste one of these snippets under the README's title. Keep the two marks around it, so that the badge can be replaced in place and is never added twice. OSCR changes nothing in your repository.
Markdown
<!-- oscr-badge:start -->
[](https://openscicode.org/badge/doi/10.1371/journal.pcbi.1014035)
<!-- oscr-badge:end -->reStructuredText
.. oscr-badge:start
.. image:: https://openscicode.org/badge/doi/10.1371/journal.pcbi.1014035.svg
:target: https://openscicode.org/badge/doi/10.1371/journal.pcbi.1014035
:alt: OSCR
.. oscr-badge:endHTML
<!-- oscr-badge:start -->
<a href="https://openscicode.org/badge/doi/10.1371/journal.pcbi.1014035"><img src="https://openscicode.org/badge/doi/10.1371/journal.pcbi.1014035.svg" alt="OSCR"></a>
<!-- oscr-badge:end -->If you choose to, you can have the badge kept up to date for you, with oscr badge --write from the command line or with the GitHub Action in your repository's workflows. Every other form and option (a card, AsciiDoc, LaTeX, shields.io) is on the badge page.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: code errors and mismatches between the code and the paper about this paper and its code, from readers and its authors, beside the paper and its tracing map.
Report a mismatch between the code and the paper · Report a code error (signed in)
Reproductions: reports from readers who ran the authors' code and did not get the paper's result, what they ran, with which environment, commit and data.
Report a reproduction failure (signed in)
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
