NMDA receptor kinetics drive distinct routes to chaotic firing in pyramidal neurons.
The 26 matches
- [1] § Materials and methods › Data analysis pipeline › Frequency band classification ↔ v_StimW_Beta_5_6_1D.py, lines 399–414 · score 0.96 · 7–33 ms, 33–77 ms, 77–125 ms, 125–250 ms, 250–2000 ms, 0.5–4 Hz
- [2] § Materials and methods › Data analysis pipeline › Frequency band classification ↔ v_StimW_Beta_5_6_1D_CaMKII_6_5_GABA_4_Complete_6.py, lines 516–531 · score 0.96 · 7–33 ms, 33–77 ms, 77–125 ms, 125–250 ms, 250–2000 ms, 0.5–4 Hz
- [3] § Materials and methods › Initial conditions robustness ↔ Sensitivity.py, lines 1–19 · score 0.91 · phase plane trajectories, mAMPA, mGABA, mNMDA, Steady state, synaptic gating
- [4] § Results › Differential excitatory and inhibitory neuron responses ↔ reviewer_response_simulations_final.py, lines 635–778 · score 0.82 · Conductance tuning, balance heatmaps, Glutamatergic scaling, inhibitory neuron, firing rate, GABAergic
- [5] § Results › Oscillatory band evolution and spectral consolidation ↔ v4_6_8_CaMKII_3.py, lines 90–144 · score 0.79 · neural oscillations, 0.5–4 Hz, 13–30 Hz, 8–13 Hz, 30–100 Hz, Frequency band
- [6] § Results › Oscillatory band evolution and spectral consolidation ↔ v4_6.py, lines 636–666 · score 0.78 · 0.5–4 Hz, 13–30 Hz, 8–13 Hz, 30–100 Hz, Frequency band, 4–8 Hz
- [7] § Results › Oscillatory band evolution and spectral consolidation ↔ v4_6_8_CaMKII_3.py, lines 90–144 · score 0.76 · 0.5–4 Hz, 13–30 Hz, 8–13 Hz, 30–100 Hz, Frequency band, 4–8 Hz
- [8] § Results › Oscillatory band evolution and spectral consolidation ↔ v4_6.py, lines 636–666 · score 0.74 · 0.5–4 Hz, 13–30 Hz, 8–13 Hz, 30–100 Hz, Frequency band, 4–8 Hz
- [9] § Materials and methods › Data analysis pipeline › Dynamical analysis measures › Maximum Lyapunov exponents ↔ v_StimW_Beta_5_6_1D.py, lines 141–175 · score 0.72 · nearest neighbor, KD tree, Lyapunov exponent, efficient, computationally
- [10] § Results ↔ v4_6_8_CaMKII_sub_21.py, lines 569–640 · score 0.70 · GABA mediated modulation, state transitions, Parameter space, plasticity region, E1, GABA frequencies
- [11] § Materials and methods › Data analysis pipeline › Bifurcation diagram construction ↔ gaba_bifurcation.py, lines 185–232 · score 0.67 · inter spike intervals, chaotic regions, branches, background, scatter, Bifurcation
- [12] § Materials and methods › Data analysis pipeline › Bifurcation diagram construction ↔ v_StimW_Beta_5_6_1D.py, lines 141–175 · score 0.65 · nearest neighbor, KD tree, Lyapunov exponent, simulations
- [13] § Results › Bifurcation analysis reveals period-doubling routes to chaos ↔ v4_6.py, lines 745–852 · score 0.63 · bifurcation diagram, frequency bands, Lyapunov exponent, chaotic regions, chaos, alpha
- [14] § Materials and methods › Data analysis pipeline › Dynamical analysis measures › Maximum Lyapunov exponents ↔ v4_6.py, lines 745–852 · score 0.61 · chaotic dynamics, Lyapunov exponent, bifurcation diagrams, chaos, ISI
- [15] § Materials and methods › Neuronal model overview ↔ v_StimW_Beta_5_6_1D_CaMKII_6_5_GABA_4_Complete_6.py, lines 286–331 · score 0.60 · isAHP, GABAergic, IKdr, IL, INaP, ICa
- [16] § Results › Differential excitatory and inhibitory neuron responses ↔ reviewer_response_simulations_final.py, lines 1–36 · score 0.60 · excitatory neuron, inhibitory neuron, GABAergic, sensitivity, glutamate, stimulation
- [17] § Materials and methods › Neuronal model overview ↔ Code1.py, lines 540–580 · score 0.59 · isAHP, GABAergic, IKdr, IL, INaP, ICa
- [18] § Results › GABA modulates CaMKII-mediated plasticity states ↔ v4_6_8_CaMKII_3.py, lines 456–521 · score 0.58 · phosphorylation states, dependent plasticity, GABA frequency, classified, CaMKII, space
- [19] § Results › GABAergic inhibition provides frequency-selective stabilization ↔ v4_6_8_CaMKII_3.py, lines 315–342 · score 0.58 · moderate inhibitory, low GABA frequencies, 20 ms, modulated, NMDA
- [20] § Results › Differential excitatory and inhibitory neuron responses ↔ reviewer_response_simulations_final.py, lines 781–819 · score 0.57 · fast spiking, inhibitory neurons, neuron responses, glutamate, GABA, NMDA
- [21] § Results › Model validation and basic neuronal response ↔ Code1.py, lines 582–656 · score 0.57 · spike detection, post transient, membrane potential, CaMKII, models, AMPA
- [22] § Results › Bifurcation analysis reveals period-doubling routes to chaos ↔ gaba_bifurcation.py, lines 131–183 · score 0.55 · bifurcation diagram, Lyapunov exponent, chaotic regions, doubled, scatter, intervals
- [23] § Results › Model validation and basic neuronal response ↔ v4_6_8_CaMKII_3.py, lines 736–779 · score 0.54 · transition zone, LTP thresholds, LTD, modulation, plasticity, calcium
- [24] § Materials and methods › Synaptic currents › NMDA receptors ↔ reviewer_response_simulations_final.py, lines 124–168 · score 0.53 · decay rate, NMDA receptor, intrinsic, neurons, synaptic
- [25] § Materials and methods › Data analysis pipeline › Statistical analysis and validation ↔ reviewer_response_simulations_final.py, lines 1–36 · score 0.53 · response curves, parameter sweeps, heatmaps, simulated
- [26] § Materials and methods › Data analysis pipeline › Bifurcation diagram construction ↔ gaba_bifurcation.py, lines 185–232 · score 0.50 · inter spike interval, chaotic regions, bifurcation, chaos
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Python · 1,127 lines · 48 KB · MIT · 5 matches
- # -*- coding: utf-8 -*-
- """
- Excitatory/Inhibitory Neuron Simulations with Parameter Sensitivity
- ====================================================================
- Supplementary analyses:
- 1) Excitatory vs inhibitory neuron responses under different synaptic
- conditions (glutamate-only, GABA-only, combined)
- 2) β_NMDA parameter sweep across neuron types
- 3) Conductance tuning of GABAergic and glutamatergic stimulation
- 4) β_AMPA (AMPA receptor closing rate) sensitivity analysis
- Figures produced:
- Fig 1 — Synaptic input pulse profiles (glutamate, GABA, combined)
- Fig 2 — Three stimulation conditions: excitatory neuron
- Fig 3 — Excitatory vs inhibitory neuron comparison under combined input
- Fig 4 — β_NMDA parameter sweep: firing rate, CaMKII, E/I balance
- Fig 5 — Conductance tuning: dose-response curves + E/I balance heatmaps
- Fig 6 — Three stimulation conditions: inhibitory neuron
- Fig 7 — β_NMDA × neuron type × input condition interaction matrix
- Fig 8 — β_AMPA sensitivity: EPSC waveforms, firing rate, CaMKII,
- E/I ratio, and β_AMPA × β_NMDA interaction heatmaps
- Core simulation model: UNCHANGED from original manuscript.
- @author: Mehdi Borjkhani
- """
- import numpy as np
- import matplotlib.pyplot as plt
- import matplotlib.gridspec as gridspec
- from matplotlib.lines import Line2D
- import os
- import warnings
- warnings.filterwarnings('ignore')
- # == Publication-quality settings =============================================
- plt.rcParams.update({
- 'font.size': 11,
- 'axes.titlesize': 12,
- 'axes.labelsize': 11,
- 'xtick.labelsize': 9,
- 'ytick.labelsize': 9,
- 'legend.fontsize': 9,
- 'font.family': 'serif',
- 'font.serif': ['Times New Roman', 'DejaVu Serif', 'serif'],
- 'mathtext.fontset': 'dejavuserif',
- 'axes.linewidth': 1.0,
- 'axes.spines.top': False,
- 'axes.spines.right': False,
- 'lines.linewidth': 1.5,
- 'legend.frameon': False,
- 'axes.grid': False,
- 'savefig.dpi': 300,
- 'savefig.bbox': 'tight',
- })
- save_directory = os.path.join(os.getcwd(), "supplementary_figures")
- os.makedirs(save_directory, exist_ok=True)
- # =============================================================================
- # MODEL PARAMETERS (Same as original manuscript)
- # =============================================================================
- # Stimulation parameters
- FreqS = 10; StimW = 1000 / FreqS; App = 1; Puls = 5
- FreqS_GABA = 10; StimW_GABA = 1000 / FreqS_GABA; App_GABA = 1; Puls_GABA = 5
- # NMDA/AMPA/GABA synapse parameters
- alpha_nmda = 0.38
- alpha_ampa = 1.1; beta_ampa = 0.67; k_ampa = 1; g_ampa = 0.35
- k_nmda = 1
- g_gaba = 0.35; alpha_gaba = 5; beta_gaba = 0.18; k_gaba = 1
- # Simulation time
- Tmax = 8.0e3 # 8 seconds (allows CaMKII to equilibrate)
- deltaT = 0.05
- tn = int(Tmax / deltaT)
- t = np.arange(0, Tmax + deltaT, deltaT)
- # Reversal potentials
- vna = 55; vk = -90; vl = -70; vca = 120; E_gaba = -80
- # Conductance densities (excitatory pyramidal neuron defaults)
- gna_exc = 50; gnap_exc = 0.2; gl_exc = 0.1; gkdr_exc = 10
- gA_exc = 1; gM_exc = 0.5; gca_exc = 0.1; gc_exc = 5; gsAHP_exc = 2
- # Gating parameters
- theta_m, tau_m = -35, 8
- theta_h, tau_h = -50, -6
- theta_n, tau_n = -40, 12
- theta_a, tau_a = -55, 15
- theta_z, tau_z = -45, 4
- theta_p, tau_p = -40, 2
- theta_ht, theta_nt = -45, -30
- theta_b, tau_b = -85, -5
- theta_r, tau_r = -25, 8
- theta_c, tau_c = -35, 5
- # CaMKII parameters
- k_I = 0.001; nh1 = 3; vCaN = 2.0e-3; kM = 20
- kh1 = 4.0; kh2 = 0.7; vPKA = 0.45e-3; kpk = 0.0059
- ck1 = 0.5e-3; ck2 = 10e-3; ck3 = 1e-3; ck4 = 1e-6
- # --- Inhibitory interneuron parameter rationale ---
- # Fast-spiking (FS) interneurons differ from pyramidal neurons in:
- # - Higher g_Kdr: faster repolarisation -> narrower action potentials
- # (cf. Erisir et al., 1999, J Neurophysiol)
- # - Reduced g_M, g_sAHP: minimal spike-frequency adaptation
- # (cf. Bhatt et al., 2019, Front Cell Neurosci)
- # - Lower g_NaP: reduced persistent Na+ current
- # - Lower g_Ca, g_C: weaker Ca2+-dependent K+ coupling
- # - Slightly higher g_leak: lower input resistance
- # - Higher resting potential (~-65 mV vs -70 mV)
- # These adjustments produce the characteristic FS phenotype: high-frequency
- # non-adapting firing with narrow spikes.
- INHIBITORY_PARAMS = {
- 'gna': 55, 'gnap': 0.05, 'gl': 0.15, 'gkdr': 15,
- 'gA': 0.3, 'gM': 0.1, 'gca': 0.02, 'gc': 1.0, 'gsAHP': 0.2,
- 'v_init': -65,
- }
- # =============================================================================
- # CORE SIMULATION FUNCTION (parameterised -- UNCHANGED from original)
- # =============================================================================
- def run_neuron_simulation(beta_nmda, neuron_type='excitatory',
- enable_glutamate=True, enable_gaba=True,
- g_ampa_scale=1.0, g_gaba_scale=1.0,
- g_nmda_scale=1.0, beta_ampa_val=None):
- """
- Run a single neuron simulation under specified conditions.
- Parameters
- ----------
- beta_nmda : float
- NMDA receptor decay rate parameter.
- neuron_type : str
- 'excitatory' or 'inhibitory'. Adjusts intrinsic conductances.
- enable_glutamate : bool
- Enable glutamatergic (AMPA + NMDA) input.
- enable_gaba : bool
- Enable GABAergic input.
- g_ampa_scale, g_gaba_scale, g_nmda_scale : float
- Scaling factors for tuning synaptic conductances.
- beta_ampa_val : float or None
- AMPA receptor closing (unbinding) rate. If None, uses global beta_ampa.
- Returns
- -------
- dict : All recorded traces and metadata.
- """
- # -- Adjust intrinsic properties by neuron type --
- if neuron_type == 'inhibitory':
- gna = INHIBITORY_PARAMS['gna']
- gnap = INHIBITORY_PARAMS['gnap']
- gl = INHIBITORY_PARAMS['gl']
- gkdr = INHIBITORY_PARAMS['gkdr']
- gA = INHIBITORY_PARAMS['gA']
- gM = INHIBITORY_PARAMS['gM']
- gca = INHIBITORY_PARAMS['gca']
- gc = INHIBITORY_PARAMS['gc']
- gsAHP = INHIBITORY_PARAMS['gsAHP']
- v_init = INHIBITORY_PARAMS['v_init']
- else:
- gna = gna_exc; gnap = gnap_exc; gl = gl_exc; gkdr = gkdr_exc
- gA = gA_exc; gM = gM_exc; gca = gca_exc; gc = gc_exc; gsAHP = gsAHP_exc
- v_init = -70
- # Scale synaptic conductances
- g_ampa_eff = g_ampa * g_ampa_scale
- g_gaba_eff = g_gaba * g_gaba_scale
- beta_ampa_eff = beta_ampa_val if beta_ampa_val is not None else beta_ampa
- # -- Allocate arrays --
- temp = np.zeros(tn + 1)
- v = temp.copy(); v[0] = v_init
- h = temp.copy(); h[0] = 0.98
- n = temp.copy(); n[0] = 0.01
- b = temp.copy(); b[0] = 0
- z = temp.copy(); z[0] = 0.050
- r = temp.copy()
- c = temp.copy()
- q = temp.copy()
- Ca = temp.copy()
- m_ampa = temp.copy()
- m_nmda = temp.copy()
- g_VDpost = temp.copy()
- I_ampa = temp.copy()
- I_nmda = temp.copy()
- m_gaba = temp.copy()
- I_gaba = temp.copy()
- Iapp = np.zeros(tn)
- Iapp_GABA = np.zeros(tn)
- # CaMKII
- CaMKII_p = np.zeros(tn + 1)
- cam = np.zeros(tn + 1)
- ep = np.zeros(tn + 1); ep[0] = 1.0
- I_camkii = np.zeros(tn + 1)
- P0 = 1.0
- P1 = P2 = P3 = P4 = P5 = P6 = P7 = P8 = P9 = P10 = 0.0
- # -- Integration loop --
- for i in range(tn):
- # Stimulus pulses
- if enable_glutamate and (0 <= (t[i] % StimW) <= Puls):
- Iapp[i] = App
- if enable_gaba and (0 <= (t[i] % StimW_GABA) <= Puls_GABA):
- Iapp_GABA[i] = App_GABA
- # Gating steady-states
- m_inf = 1 / (1 + np.exp(-(v[i] - theta_m) / tau_m))
- h_inf = 1 / (1 + np.exp(-(v[i] - theta_h) / tau_h))
- n_inf = 1 / (1 + np.exp(-(v[i] - theta_n) / tau_n))
- a_inf = 1 / (1 + np.exp(-(v[i] - theta_a) / tau_a))
- b_inf = 1 / (1 + np.exp(-(v[i] - theta_b) / tau_b))
- z_inf = 1 / (1 + np.exp(-(v[i] - theta_z) / tau_z))
- p_inf = 1 / (1 + np.exp(-(v[i] - theta_p) / tau_p))
- r_inf = 1 / (1 + np.exp(-(v[i] - theta_r) / tau_r))
- tau_ht_mod = 0.1 + 0.75 / (1 + np.exp(-(v[i] - theta_ht) / (-6)))
- tau_nt_mod = 0.1 + 0.5 / (1 + np.exp(-(v[i] - theta_nt) / (-15)))
- d_inf = 1 / (1 + 6 / (Ca[i] + 1e-6))
- c_inf = 1 / (1 + np.exp(-(v[i] - theta_c) / tau_c))
- q_inf = 1 / (1 + (2 / (Ca[i] + 1e-6))**4)
- # Gating variable updates
- h[i+1] = h[i] + deltaT * ((h_inf - h[i]) / tau_ht_mod)
- n[i+1] = n[i] + deltaT * ((n_inf - n[i]) / tau_nt_mod)
- b[i+1] = b[i] + deltaT * ((b_inf - b[i]) / 15)
- z[i+1] = z[i] + deltaT * ((z_inf - z[i]) / 75)
- r[i+1] = r[i] + deltaT * ((r_inf - r[i]) / 1)
- c[i+1] = c[i] + deltaT * ((c_inf - c[i]) / 2)
- q[i+1] = q[i] + deltaT * ((q_inf - q[i]) / 450)
- # Ionic currents
- ina = gna * m_inf**3 * h[i] * (v[i] - vna)
- inap = gnap * p_inf * (v[i] - vna)
- ikdr = gkdr * n[i]**4 * (v[i] - vk)
- iA = gA * a_inf**3 * b[i] * (v[i] - vk)
- iM = gM * z[i] * (v[i] - vk)
- il = gl * (v[i] - vl)
- ica = gca * r[i]**2 * (v[i] - vca)
- ic = gc * d_inf * c[i] * (v[i] - vk)
- isAHP = gsAHP * q[i] * (v[i] - vk)
- # Synaptic currents
- G_syn = Iapp[i]
- m_ampa[i+1] = m_ampa[i] + deltaT * (alpha_ampa * G_syn * (1 - m_ampa[i]) - beta_ampa_eff * m_ampa[i])
- I_ampa[i] = k_ampa * g_ampa_eff * m_ampa[i] * (v[i] - 55)
- m_nmda[i+1] = m_nmda[i] + deltaT * (alpha_nmda * G_syn * (1 - m_nmda[i]) - beta_nmda * m_nmda[i])
- g_conpost = g_VDpost[i] + 1
- g_VDinfpost = 0.0007 * (v[i] - (-100))
- g_VDpost[i+1] = g_VDpost[i] + deltaT * ((g_VDinfpost - g_VDpost[i]) / 0.05)
- MG = 1 / (1 + (1.4 / 3.75) * np.exp(-0.062 * v[i]))
- I_nmda[i] = k_nmda * g_nmda_scale * g_conpost * MG * m_nmda[i] * (v[i] - 55)
- G_syn_gaba = Iapp_GABA[i]
- m_gaba[i+1] = m_gaba[i] + deltaT * (alpha_gaba * G_syn_gaba * (1 - m_gaba[i]) - beta_gaba * m_gaba[i])
- I_gaba[i] = k_gaba * g_gaba_eff * m_gaba[i] * (v[i] - E_gaba)
- # Calcium update
- Ca[i+1] = Ca[i] + deltaT * (-0.13 * ica - 0.0012 * I_ampa[i] - 0.012 * I_nmda[i] - Ca[i] / 13)
- # CaMKII
- Ca_uM = Ca[i] * 1
- num_cv1 = 10 * ck1 * P0 * (Ca_uM / kh1) ** (2 * nh1)
- den_cv1 = (1 + (Ca_uM / kh1) ** nh1) ** 2
- cv1 = num_cv1 / den_cv1
- cv2 = ck1 * (Ca_uM / kh1) ** nh1 / (1 + (Ca_uM / kh1) ** nh1)
- sum_k_Pk = P1 + 2*P2 + 3*P3 + 4*P4 + 5*P5 + 6*P6 + 7*P7 + 8*P8 + 9*P9 + 10*P10
- cv3 = ck2 * ep[i] / (kM + sum_k_Pk)
- P0 += deltaT * (-cv1 + cv3 * P1)
- P1 += deltaT * (cv1 - cv3*P1 - cv2*P1 + 2*cv3*P2)
- P2 += deltaT * (cv2*P1 - 2*cv3*P2 - 1.8*cv2*P2 + 3*cv3*P3)
- P3 += deltaT * (1.8*cv2*P2 - 3*cv3*P3 - 2.3*cv2*P3 + 4*cv3*P4)
- P4 += deltaT * (2.3*cv2*P3 - 4*cv3*P4 - 2.7*cv2*P4 + 5*cv3*P5)
- P5 += deltaT * (2.7*cv2*P4 - 5*cv3*P5 - 2.8*cv2*P5 + 6*cv3*P6)
- P6 += deltaT * (2.8*cv2*P5 - 6*cv3*P6 - 2.7*cv2*P6 + 7*cv3*P7)
- P7 += deltaT * (2.7*cv2*P6 - 7*cv3*P7 - 2.3*cv2*P7 + 8*cv3*P8)
- P8 += deltaT * (2.3*cv2*P7 - 8*cv3*P8 - 1.8*cv2*P8 + 9*cv3*P9)
- P9 += deltaT * (1.8*cv2*P8 - 9*cv3*P9 - cv2*P9 + 10*cv3*P10)
- P10 += deltaT * (cv2*P9 - 10*cv3*P10)
- cam[i+1] = P1+P2+P3+P4+P5+P6+P7+P8+P9+P10
- total_P = P0+P1+P2+P3+P4+P5+P6+P7+P8+P9+P10
- CaMKII_p[i+1] = cam[i+1] / total_P
- ep[i+1] = ep[i] + deltaT * (-ck3*I_camkii[i]*ep[i] + ck4*(ep[0]-ep[i]) + k_I*1.0)
- I_camkii[i+1] = I_camkii[i] + deltaT * (
- -ck3*I_camkii[i]*ep[i] + ck4*(ep[0]-ep[i]) +
- vPKA*(1.0/(kpk+1.0)) -
- (vCaN*I_camkii[i]*(Ca_uM/kh2)**3 / (1+(Ca_uM/kh2)**3))
- )
- I_syn = I_ampa[i] + I_nmda[i] + I_gaba[i]
- v[i+1] = v[i] + deltaT * (-(ina + inap + ikdr + iA + iM + il + ica + ic + isAHP + I_syn))
- # Spike detection
- spike_indices = np.where((v[:-1] < 0) & (v[1:] >= 0))[0]
- spike_times = t[spike_indices]
- firing_rate = len(spike_times) / (Tmax / 1000) if Tmax > 0 else 0
- return {
- 't': t, 'v': v, 'Ca': Ca, 'CaMKII_p': CaMKII_p,
- 'Iapp': Iapp, 'Iapp_GABA': Iapp_GABA,
- 'I_ampa': I_ampa, 'I_nmda': I_nmda, 'I_gaba': I_gaba,
- 'm_ampa': m_ampa, 'm_nmda': m_nmda, 'm_gaba': m_gaba,
- 'spike_times': spike_times, 'firing_rate': firing_rate,
- 'neuron_type': neuron_type, 'beta_nmda': beta_nmda,
- 'enable_glutamate': enable_glutamate, 'enable_gaba': enable_gaba,
- }
- # =============================================================================
- # ANALYSIS HELPERS
- # =============================================================================
- def count_spikes(v_trace, t_array, t_start=2000):
- """Count spikes after t_start ms to exclude transients."""
- idx_start = int(t_start / deltaT)
- v_seg = v_trace[idx_start:]
- spikes = np.where((v_seg[:-1] < 0) & (v_seg[1:] >= 0))[0]
- duration_s = (t_array[-1] - t_start) / 1000
- return len(spikes), len(spikes) / duration_s if duration_s > 0 else 0
- def compute_ei_ratio(res, t_start=2000):
- """
- Compute excitation/inhibition (E/I) current ratio in steady state.
- E/I ratio = |mean(I_AMPA + I_NMDA)| / |mean(I_GABA)|
- Returns np.inf if GABA current is zero.
- """
- idx_ss = int(t_start / deltaT)
- I_exc = np.abs(np.mean(res['I_ampa'][idx_ss:] + res['I_nmda'][idx_ss:]))
- I_inh = np.abs(np.mean(res['I_gaba'][idx_ss:]))
- if I_inh < 1e-12:
- return np.inf if I_exc > 1e-12 else 1.0
- return I_exc / I_inh
- def compute_mean_currents(res, t_start=2000):
- """Compute mean absolute synaptic currents in steady state."""
- idx_ss = int(t_start / deltaT)
- return {
- 'I_ampa': np.mean(np.abs(res['I_ampa'][idx_ss:])),
- 'I_nmda': np.mean(np.abs(res['I_nmda'][idx_ss:])),
- 'I_gaba': np.mean(np.abs(res['I_gaba'][idx_ss:])),
- 'I_exc_total': np.mean(np.abs(res['I_ampa'][idx_ss:] + res['I_nmda'][idx_ss:])),
- }
- def save_fig(fig, name):
- """Save figure in both PNG and PDF format."""
- fig.savefig(os.path.join(save_directory, f'{name}.png'), dpi=300)
- fig.savefig(os.path.join(save_directory, f'{name}.pdf'), dpi=300)
- plt.close(fig)
- # =============================================================================
- # FIGURE 1: PULSE PROFILES OF GABA AND GLUTAMATE
- # =============================================================================
- def figure1_pulse_profiles():
- """Show the synaptic input pulse profiles clearly."""
- print(" Figure 1: Pulse profiles ...")
- t_short = np.arange(0, 300 + deltaT, deltaT)
- glu_pulse = np.array([App if 0 <= (ti % StimW) <= Puls else 0 for ti in t_short])
- gaba_pulse = np.array([App_GABA if 0 <= (ti % StimW_GABA) <= Puls_GABA else 0 for ti in t_short])
- fig, axes = plt.subplots(3, 1, figsize=(7, 5.5), sharex=True)
- # Glutamate
- axes[0].fill_between(t_short, 0, glu_pulse, color='#2E86C1', alpha=0.35, step='mid')
- axes[0].step(t_short, glu_pulse, color='#2E86C1', linewidth=1.8, where='mid')
- axes[0].set_ylabel('Glutamate\nInput (a.u.)')
- axes[0].set_title('(A) Glutamatergic Pulse Profile', loc='left', fontweight='bold')
- axes[0].set_ylim(-0.1, 1.5)
- axes[0].text(0.75, 0.8, f'Freq = {FreqS} Hz\nWidth = {Puls} ms',
- transform=axes[0].transAxes, fontsize=9,
- bbox=dict(boxstyle='round', fc='white', alpha=0.8))
- # GABA
- axes[1].fill_between(t_short, 0, gaba_pulse, color='#E74C3C', alpha=0.35, step='mid')
- axes[1].step(t_short, gaba_pulse, color='#E74C3C', linewidth=1.8, where='mid')
- axes[1].set_ylabel('GABA\nInput (a.u.)')
- axes[1].set_title('(B) GABAergic Pulse Profile', loc='left', fontweight='bold')
- axes[1].set_ylim(-0.1, 1.5)
- axes[1].text(0.75, 0.8, f'Freq = {FreqS_GABA} Hz\nWidth = {Puls_GABA} ms',
- transform=axes[1].transAxes, fontsize=9,
- bbox=dict(boxstyle='round', fc='white', alpha=0.8))
- # Combined
- axes[2].fill_between(t_short, 0, glu_pulse, color='#2E86C1', alpha=0.3, step='mid', label='Glutamate')
- axes[2].fill_between(t_short, 0, gaba_pulse, color='#E74C3C', alpha=0.3, step='mid', label='GABA')
- axes[2].step(t_short, glu_pulse, color='#2E86C1', linewidth=1.5, where='mid')
- axes[2].step(t_short, gaba_pulse, color='#E74C3C', linewidth=1.5, where='mid', linestyle='--')
- axes[2].set_ylabel('Input (a.u.)')
- axes[2].set_xlabel('Time (ms)')
- axes[2].set_title('(C) Combined Input Profile', loc='left', fontweight='bold')
- axes[2].set_ylim(-0.1, 1.5)
- axes[2].legend(loc='upper right', fontsize=9)
- fig.tight_layout()
- save_fig(fig, 'Fig1_pulse_profiles')
- # =============================================================================
- # FIGURE 2: GLUTAMATE-ONLY vs GABA-ONLY vs COMBINED (Excitatory)
- # =============================================================================
- def figure2_three_conditions(beta_nmda_val=0.03):
- """
- Separate panels showing excitatory neuron under three conditions:
- (i) Glutamate only, (ii) GABA only, (iii) Combined.
- """
- print(" Figure 2: Three stimulation conditions (excitatory neuron) ...")
- res_glu = run_neuron_simulation(beta_nmda_val, 'excitatory', enable_glutamate=True, enable_gaba=False)
- res_gaba = run_neuron_simulation(beta_nmda_val, 'excitatory', enable_glutamate=False, enable_gaba=True)
- res_both = run_neuron_simulation(beta_nmda_val, 'excitatory', enable_glutamate=True, enable_gaba=True)
- t0, t1 = 7000, 7500
- i0, i1 = int(t0/deltaT), int(t1/deltaT)
- conditions = [
- (res_glu, 'Glutamate Only (AMPA + NMDA)', '#2E86C1'),
- (res_gaba, 'GABA Only', '#E74C3C'),
- (res_both, 'Combined (Glutamate + GABA)', '#2C3E50'),
- ]
- fig, axes = plt.subplots(6, 1, figsize=(10, 14), sharex=True)
- labels = 'ABCDEF'
- for j, (res, title, color) in enumerate(conditions):
- ax_v = axes[2*j]
- ax_c = axes[2*j + 1]
- tt = res['t'][i0:i1]
- # Membrane potential
- ax_v.plot(tt, res['v'][i0:i1], color=color, linewidth=1.2)
- ax_v.axhline(0, color='gray', ls='--', lw=0.7, alpha=0.5)
- n_spk, rate = count_spikes(res['v'], res['t'], t_start=t0)
- ax_v.set_ylabel('V (mV)')
- ax_v.set_title(f'({labels[2*j]}) {title} | Firing rate: {rate:.1f} Hz',
- loc='left', fontweight='bold', fontsize=10)
- ax_v.set_ylim(-95, 55)
- # Synaptic currents
- ax_c.plot(tt, res['I_ampa'][i0:i1], color='#27AE60', lw=1.2, label='$I_{AMPA}$')
- ax_c.plot(tt, res['I_nmda'][i0:i1], color='#8E44AD', lw=1.2, label='$I_{NMDA}$')
- ax_c.plot(tt, res['I_gaba'][i0:i1], color='#F39C12', lw=1.2, label='$I_{GABA}$')
- ax_c.set_ylabel('Current (nA)')
- ax_c.set_title(f'({labels[2*j+1]}) Synaptic Currents | {title}',
- loc='left', fontsize=10)
- ax_c.legend(loc='upper right', ncol=3, fontsize=8)
- axes[-1].set_xlabel('Time (ms)')
- fig.suptitle(f'Excitatory Neuron Responses Under Different Synaptic Conditions '
- r'($\beta_{NMDA}$' + f' = {beta_nmda_val})', fontsize=13, fontweight='bold', y=1.01)
- fig.tight_layout()
- save_fig(fig, 'Fig2_three_conditions_excitatory')
- return res_glu, res_gaba, res_both
- # =============================================================================
- # FIGURE 3: EXCITATORY vs INHIBITORY NEURON COMPARISON
- # =============================================================================
- def figure3_exc_vs_inh(beta_nmda_val=0.03):
- """
- Side-by-side comparison of excitatory and inhibitory neurons
- under combined GABA + Glutamate input.
- """
- print(" Figure 3: Excitatory vs Inhibitory neuron comparison ...")
- res_exc = run_neuron_simulation(beta_nmda_val, 'excitatory', True, True)
- res_inh = run_neuron_simulation(beta_nmda_val, 'inhibitory', True, True)
- t0, t1 = 7000, 7500
- i0, i1 = int(t0/deltaT), int(t1/deltaT)
- fig, axes = plt.subplots(4, 2, figsize=(12, 10), sharex='col')
- for col, (res, ntype, clr) in enumerate([
- (res_exc, 'Excitatory (Pyramidal)', '#2E86C1'),
- (res_inh, 'Inhibitory (Fast-Spiking)', '#E74C3C')]):
- tt = res['t'][i0:i1]
- _, rate = count_spikes(res['v'], res['t'], t_start=t0)
- axes[0, col].plot(tt, res['v'][i0:i1], color=clr, lw=1.2)
- axes[0, col].axhline(0, color='gray', ls='--', lw=0.6, alpha=0.5)
- axes[0, col].set_ylabel('V (mV)')
- axes[0, col].set_title(f'{ntype}\nFiring rate: {rate:.1f} Hz', fontweight='bold')
- axes[1, col].plot(tt, res['I_ampa'][i0:i1], '#27AE60', lw=1, label='AMPA')
- axes[1, col].plot(tt, res['I_nmda'][i0:i1], '#8E44AD', lw=1, label='NMDA')
- axes[1, col].plot(tt, res['I_gaba'][i0:i1], '#F39C12', lw=1, label='GABA')
- axes[1, col].set_ylabel('I$_{syn}$ (nA)')
- axes[1, col].legend(fontsize=7, ncol=3)
- axes[2, col].plot(tt, res['Ca'][i0:i1], color='#16A085', lw=1.2)
- axes[2, col].set_ylabel('[Ca$^{2+}$]$_i$ (a.u.)')
- axes[3, col].plot(tt, res['CaMKII_p'][i0:i1], color='black', lw=1.2)
- axes[3, col].set_ylabel('CaMKII$_p$')
- axes[3, col].set_xlabel('Time (ms)')
- fig.suptitle(f'Excitatory vs Inhibitory Neuron | Combined Input '
- r'($\beta_{NMDA}$' + f' = {beta_nmda_val})',
- fontsize=13, fontweight='bold')
- fig.tight_layout()
- save_fig(fig, 'Fig3_exc_vs_inh')
- # =============================================================================
- # FIGURE 4: NMDA beta PARAMETER SWEEP (ENHANCED)
- # =============================================================================
- def figure4_nmda_parameter_sweep():
- """
- Sweep beta_NMDA over a wider range and show:
- (A) Firing rate vs beta_NMDA for both neuron types
- (B) CaMKII phosphorylation vs beta_NMDA
- (C) E/I current ratio vs beta_NMDA
- (D-F) Representative voltage traces at low, mid, high beta_NMDA
- """
- print(" Figure 4: NMDA parameter sweep (enhanced) ...")
- # Wider range with finer resolution
- beta_vals = np.arange(0.005, 0.121, 0.005)
- n_beta = len(beta_vals)
- rates_exc = np.zeros(n_beta)
- rates_inh = np.zeros(n_beta)
- camkii_exc = np.zeros(n_beta)
- camkii_inh = np.zeros(n_beta)
- ei_ratio_exc = np.zeros(n_beta)
- ei_ratio_inh = np.zeros(n_beta)
- # Store full results at selected beta values for traces
- beta_trace_vals = [0.01, 0.04, 0.10]
- trace_results = {bv: {} for bv in beta_trace_vals}
- idx_ss = int(5000 / deltaT)
- for k, bv in enumerate(beta_vals):
- print(f" beta_NMDA = {bv:.3f} ({k+1}/{n_beta})")
- re = run_neuron_simulation(bv, 'excitatory', True, True)
- ri = run_neuron_simulation(bv, 'inhibitory', True, True)
- _, rates_exc[k] = count_spikes(re['v'], re['t'])
- _, rates_inh[k] = count_spikes(ri['v'], ri['t'])
- camkii_exc[k] = np.mean(re['CaMKII_p'][idx_ss:])
- camkii_inh[k] = np.mean(ri['CaMKII_p'][idx_ss:])
- ei_ratio_exc[k] = compute_ei_ratio(re)
- ei_ratio_inh[k] = compute_ei_ratio(ri)
- # Save traces at selected values
- for btv in beta_trace_vals:
- if abs(bv - btv) < 1e-6:
- trace_results[btv] = {'exc': re, 'inh': ri}
- # -- Create figure: 2 rows x 3 columns --
- fig = plt.figure(figsize=(14, 9))
- gs = gridspec.GridSpec(2, 3, hspace=0.45, wspace=0.35)
- clr_exc = '#2E86C1'
- clr_inh = '#E74C3C'
- # (A) Firing rate
- ax_a = fig.add_subplot(gs[0, 0])
- ax_a.plot(beta_vals, rates_exc, 'o-', color=clr_exc, lw=2, ms=4, label='Excitatory')
- ax_a.plot(beta_vals, rates_inh, 's--', color=clr_inh, lw=2, ms=4, label='Inhibitory')
- ax_a.set_xlabel(r'$\beta_{NMDA}$')
- ax_a.set_ylabel('Firing Rate (Hz)')
- ax_a.set_title(r'(A) Firing Rate vs $\beta_{NMDA}$', loc='left', fontweight='bold')
- ax_a.legend(fontsize=8)
- # Mark trace locations
- for btv in beta_trace_vals:
- ax_a.axvline(btv, color='gray', ls=':', lw=0.8, alpha=0.5)
- # (B) CaMKII
- ax_b = fig.add_subplot(gs[0, 1])
- ax_b.semilogy(beta_vals, camkii_exc, 'o-', color=clr_exc, lw=2, ms=4, label='Excitatory')
- ax_b.semilogy(beta_vals, camkii_inh, 's--', color=clr_inh, lw=2, ms=4, label='Inhibitory')
- ax_b.set_xlabel(r'$\beta_{NMDA}$')
- ax_b.set_ylabel('Mean CaMKII$_p$ (log scale)')
- ax_b.set_title('(B) CaMKII Phosphorylation', loc='left', fontweight='bold')
- ax_b.legend(fontsize=8)
- # (C) E/I ratio
- ax_c = fig.add_subplot(gs[0, 2])
- # Clip inf values for plotting
- ei_exc_plot = np.clip(ei_ratio_exc, 0, 50)
- ei_inh_plot = np.clip(ei_ratio_inh, 0, 50)
- ax_c.plot(beta_vals, ei_exc_plot, 'o-', color=clr_exc, lw=2, ms=4, label='Excitatory')
- ax_c.plot(beta_vals, ei_inh_plot, 's--', color=clr_inh, lw=2, ms=4, label='Inhibitory')
- ax_c.axhline(1.0, color='gray', ls='--', lw=1, alpha=0.6, label='E/I = 1')
- ax_c.set_xlabel(r'$\beta_{NMDA}$')
- ax_c.set_ylabel('E/I Current Ratio')
- ax_c.set_title('(C) Excitation/Inhibition Balance', loc='left', fontweight='bold')
- ax_c.legend(fontsize=8)
- # (D-F) Representative traces
- trace_labels = [r'(D) Low $\beta_{NMDA}$', r'(E) Mid $\beta_{NMDA}$', r'(F) High $\beta_{NMDA}$']
- t0_tr, t1_tr = 7000, 7400 # 400 ms window
- i0_tr = int(t0_tr / deltaT)
- i1_tr = int(t1_tr / deltaT)
- for j, btv in enumerate(beta_trace_vals):
- ax_tr = fig.add_subplot(gs[1, j])
- if btv in trace_results and trace_results[btv]:
- tt = trace_results[btv]['exc']['t'][i0_tr:i1_tr]
- ax_tr.plot(tt, trace_results[btv]['exc']['v'][i0_tr:i1_tr],
- color=clr_exc, lw=1.2, label='Exc')
- ax_tr.plot(tt, trace_results[btv]['inh']['v'][i0_tr:i1_tr],
- color=clr_inh, lw=1.2, alpha=0.8, label='Inh')
- ax_tr.axhline(0, color='gray', ls='--', lw=0.5, alpha=0.4)
- ax_tr.set_ylabel('V (mV)')
- ax_tr.set_xlabel('Time (ms)')
- ax_tr.set_title(f'{trace_labels[j]} = {btv}', loc='left', fontweight='bold')
- ax_tr.set_ylim(-95, 55)
- if j == 0:
- ax_tr.legend(fontsize=8)
- fig.suptitle(r'Effect of $\beta_{NMDA}$ on Excitatory and Inhibitory Neuron Responses',
- fontsize=14, fontweight='bold')
- fig.tight_layout(rect=[0, 0, 1, 0.96])
- save_fig(fig, 'Fig4_nmda_sweep_enhanced')
- # =============================================================================
- # FIGURE 5: CONDUCTANCE TUNING -- DOSE-RESPONSE + DUAL HEATMAPS
- # =============================================================================
- def figure5_conductance_tuning():
- """
- (A) GABA dose-response (glutamate fixed at 1x) for both cell types
- (B) Glutamate dose-response (GABA fixed at 1x) for both cell types
- (C) E-I balance heatmap: excitatory neuron
- (D) E-I balance heatmap: inhibitory neuron
- """
- print(" Figure 5: Conductance tuning (enhanced) ...")
- beta_val = 0.03
- clr_exc = '#2E86C1'
- clr_inh = '#E74C3C'
- # -- (A) GABA dose-response --
- gaba_scales_1d = np.array([0, 0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0, 4.0])
- rates_gaba_exc = np.zeros(len(gaba_scales_1d))
- rates_gaba_inh = np.zeros(len(gaba_scales_1d))
- print(" GABA dose-response ...")
- for k, gs in enumerate(gaba_scales_1d):
- en_gab = gs > 0
- re = run_neuron_simulation(beta_val, 'excitatory', True, en_gab,
- g_gaba_scale=max(gs, 1e-6))
- ri = run_neuron_simulation(beta_val, 'inhibitory', True, en_gab,
- g_gaba_scale=max(gs, 1e-6))
- _, rates_gaba_exc[k] = count_spikes(re['v'], re['t'])
- _, rates_gaba_inh[k] = count_spikes(ri['v'], ri['t'])
- # -- (B) Glutamate dose-response --
- glu_scales_1d = np.array([0, 0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0, 4.0])
- rates_glu_exc = np.zeros(len(glu_scales_1d))
- rates_glu_inh = np.zeros(len(glu_scales_1d))
- print(" Glutamate dose-response ...")
- for k, gs in enumerate(glu_scales_1d):
- en_glu = gs > 0
- re = run_neuron_simulation(beta_val, 'excitatory', en_glu, True,
- g_ampa_scale=max(gs, 1e-6),
- g_nmda_scale=max(gs, 1e-6))
- ri = run_neuron_simulation(beta_val, 'inhibitory', en_glu, True,
- g_ampa_scale=max(gs, 1e-6),
- g_nmda_scale=max(gs, 1e-6))
- _, rates_glu_exc[k] = count_spikes(re['v'], re['t'])
- _, rates_glu_inh[k] = count_spikes(ri['v'], ri['t'])
- # -- (C, D) 2D heatmaps for both neuron types --
- gaba_scales_2d = np.array([0, 0.5, 1.0, 1.5, 2.0, 3.0])
- glu_scales_2d = np.array([0, 0.5, 1.0, 1.5, 2.0, 3.0])
- rate_map_exc = np.zeros((len(gaba_scales_2d), len(glu_scales_2d)))
- rate_map_inh = np.zeros((len(gaba_scales_2d), len(glu_scales_2d)))
- print(" 2D heatmaps ...")
- for gi, gs_gaba in enumerate(gaba_scales_2d):
- for gj, gs_glu in enumerate(glu_scales_2d):
- en_glu = gs_glu > 0
- en_gab = gs_gaba > 0
- re = run_neuron_simulation(
- beta_val, 'excitatory', en_glu, en_gab,
- g_ampa_scale=max(gs_glu, 1e-6),
- g_gaba_scale=max(gs_gaba, 1e-6),
- g_nmda_scale=max(gs_glu, 1e-6))
- ri = run_neuron_simulation(
- beta_val, 'inhibitory', en_glu, en_gab,
- g_ampa_scale=max(gs_glu, 1e-6),
- g_gaba_scale=max(gs_gaba, 1e-6),
- g_nmda_scale=max(gs_glu, 1e-6))
- _, rate_map_exc[gi, gj] = count_spikes(re['v'], re['t'])
- _, rate_map_inh[gi, gj] = count_spikes(ri['v'], ri['t'])
- # -- Plot --
- fig = plt.figure(figsize=(14, 10))
- gs_fig = gridspec.GridSpec(2, 2, hspace=0.38, wspace=0.3)
- # (A) GABA dose-response
- ax_a = fig.add_subplot(gs_fig[0, 0])
- ax_a.plot(gaba_scales_1d, rates_gaba_exc, 'o-', color=clr_exc, lw=2, ms=5, label='Excitatory')
- ax_a.plot(gaba_scales_1d, rates_gaba_inh, 's--', color=clr_inh, lw=2, ms=5, label='Inhibitory')
- ax_a.axvline(1.0, color='gray', ls=':', lw=0.8, alpha=0.6, label='Baseline')
- ax_a.set_xlabel('GABAergic Conductance Scale ($g_{GABA}$ / $g_{GABA,0}$)')
- ax_a.set_ylabel('Firing Rate (Hz)')
- ax_a.set_title('(A) GABA Dose-Response\n(Glutamate fixed at 1$\\times$)',
- loc='left', fontweight='bold')
- ax_a.legend(fontsize=8)
- # (B) Glutamate dose-response
- ax_b = fig.add_subplot(gs_fig[0, 1])
- ax_b.plot(glu_scales_1d, rates_glu_exc, 'o-', color=clr_exc, lw=2, ms=5, label='Excitatory')
- ax_b.plot(glu_scales_1d, rates_glu_inh, 's--', color=clr_inh, lw=2, ms=5, label='Inhibitory')
- ax_b.axvline(1.0, color='gray', ls=':', lw=0.8, alpha=0.6, label='Baseline')
- ax_b.set_xlabel('Glutamatergic Conductance Scale ($g_{AMPA/NMDA}$ / $g_0$)')
- ax_b.set_ylabel('Firing Rate (Hz)')
- ax_b.set_title('(B) Glutamate Dose-Response\n(GABA fixed at 1$\\times$)',
- loc='left', fontweight='bold')
- ax_b.legend(fontsize=8)
- # (C) Heatmap -- excitatory
- ax_c = fig.add_subplot(gs_fig[1, 0])
- vmax = max(rate_map_exc.max(), rate_map_inh.max())
- im_c = ax_c.imshow(rate_map_exc, origin='lower', aspect='auto',
- extent=[glu_scales_2d[0]-0.25, glu_scales_2d[-1]+0.25,
- gaba_scales_2d[0]-0.25, gaba_scales_2d[-1]+0.25],
- cmap='RdYlBu_r', interpolation='bilinear',
- vmin=0, vmax=vmax)
- for gi, gs_gaba in enumerate(gaba_scales_2d):
- for gj, gs_glu in enumerate(glu_scales_2d):
- val = rate_map_exc[gi, gj]
- ax_c.text(gs_glu, gs_gaba, f'{val:.0f}',
- ha='center', va='center', fontsize=7,
- color='white' if val > vmax*0.5 else 'black')
- fig.colorbar(im_c, ax=ax_c, label='Firing Rate (Hz)', shrink=0.85)
- ax_c.set_xlabel('Glutamatergic Scale')
- ax_c.set_ylabel('GABAergic Scale')
- ax_c.set_title('(C) E-I Balance | Excitatory Neuron', loc='left', fontweight='bold')
- ax_c.set_xticks(glu_scales_2d)
- ax_c.set_yticks(gaba_scales_2d)
- # (D) Heatmap -- inhibitory
- ax_d = fig.add_subplot(gs_fig[1, 1])
- im_d = ax_d.imshow(rate_map_inh, origin='lower', aspect='auto',
- extent=[glu_scales_2d[0]-0.25, glu_scales_2d[-1]+0.25,
- gaba_scales_2d[0]-0.25, gaba_scales_2d[-1]+0.25],
- cmap='RdYlBu_r', interpolation='bilinear',
- vmin=0, vmax=vmax)
- for gi, gs_gaba in enumerate(gaba_scales_2d):
- for gj, gs_glu in enumerate(glu_scales_2d):
- val = rate_map_inh[gi, gj]
- ax_d.text(gs_glu, gs_gaba, f'{val:.0f}',
- ha='center', va='center', fontsize=7,
- color='white' if val > vmax*0.5 else 'black')
- fig.colorbar(im_d, ax=ax_d, label='Firing Rate (Hz)', shrink=0.85)
- ax_d.set_xlabel('Glutamatergic Scale')
- ax_d.set_ylabel('GABAergic Scale')
- ax_d.set_title('(D) E-I Balance | Inhibitory Neuron', loc='left', fontweight='bold')
- ax_d.set_xticks(glu_scales_2d)
- ax_d.set_yticks(gaba_scales_2d)
- fig.suptitle(r'Tuning GABAergic and Glutamatergic Stimulation ($\beta_{NMDA}$' + f' = {beta_val})',
- fontsize=14, fontweight='bold')
- fig.tight_layout(rect=[0, 0, 1, 0.96])
- save_fig(fig, 'Fig5_conductance_tuning_enhanced')
- # =============================================================================
- # FIGURE 6: THREE CONDITIONS FOR INHIBITORY NEURON
- # =============================================================================
- def figure6_three_conditions_inhibitory(beta_nmda_val=0.03):
- """Same three-condition comparison but for the inhibitory neuron."""
- print(" Figure 6: Three conditions (inhibitory neuron) ...")
- res_glu = run_neuron_simulation(beta_nmda_val, 'inhibitory', True, False)
- res_gaba = run_neuron_simulation(beta_nmda_val, 'inhibitory', False, True)
- res_both = run_neuron_simulation(beta_nmda_val, 'inhibitory', True, True)
- t0, t1 = 7000, 7500
- i0, i1 = int(t0/deltaT), int(t1/deltaT)
- conditions = [
- (res_glu, 'Glutamate Only', '#2E86C1'),
- (res_gaba, 'GABA Only', '#E74C3C'),
- (res_both, 'Combined', '#2C3E50'),
- ]
- fig, axes = plt.subplots(3, 1, figsize=(10, 7), sharex=True)
- for j, (res, title, color) in enumerate(conditions):
- tt = res['t'][i0:i1]
- ax = axes[j]
- ax.plot(tt, res['v'][i0:i1], color=color, lw=1.2)
- ax.axhline(0, color='gray', ls='--', lw=0.6, alpha=0.5)
- _, rate = count_spikes(res['v'], res['t'], t_start=t0)
- ax.set_ylabel('V (mV)')
- ax.set_title(f'({chr(65+j)}) Inhibitory Neuron | {title} | '
- f'Rate: {rate:.1f} Hz', loc='left', fontweight='bold', fontsize=10)
- ax.set_ylim(-95, 55)
- axes[-1].set_xlabel('Time (ms)')
- fig.suptitle(f'Inhibitory (Fast-Spiking) Neuron Responses '
- r'($\beta_{NMDA}$' + f' = {beta_nmda_val})',
- fontsize=13, fontweight='bold')
- fig.tight_layout()
- save_fig(fig, 'Fig6_three_conditions_inhibitory')
- # =============================================================================
- # FIGURE 7: beta_NMDA x NEURON TYPE x INPUT CONDITION INTERACTION
- # =============================================================================
- def figure7_interaction_summary():
- """
- Comprehensive summary: how beta_NMDA modulates firing rate under each
- input condition (Glu only, GABA only, Combined) for both neuron types.
- """
- print(" Figure 7: Interaction summary ...")
- beta_vals = np.arange(0.005, 0.101, 0.01)
- n_beta = len(beta_vals)
- conditions = [
- ('Glutamate Only', True, False),
- ('GABA Only', False, True),
- ('Combined', True, True),
- ]
- neuron_types = [
- ('Excitatory', 'excitatory', '#2E86C1'),
- ('Inhibitory', 'inhibitory', '#E74C3C'),
- ]
- # results[condition_name][neuron_label] = array of firing rates
- results = {}
- camkii_results = {}
- idx_ss = int(5000 / deltaT)
- for cond_name, en_glu, en_gab in conditions:
- results[cond_name] = {}
- camkii_results[cond_name] = {}
- for n_label, n_type, _ in neuron_types:
- rates = np.zeros(n_beta)
- camkii = np.zeros(n_beta)
- for k, bv in enumerate(beta_vals):
- res = run_neuron_simulation(bv, n_type, en_glu, en_gab)
- _, rates[k] = count_spikes(res['v'], res['t'])
- camkii[k] = np.mean(res['CaMKII_p'][idx_ss:])
- results[cond_name][n_label] = rates
- camkii_results[cond_name][n_label] = camkii
- # -- Plot: 2 rows x 3 columns --
- fig, axes = plt.subplots(2, 3, figsize=(14, 8), sharey='row')
- panel_labels = iter('ABCDEF')
- for j, (cond_name, _, _) in enumerate(conditions):
- ax_rate = axes[0, j]
- ax_cam = axes[1, j]
- lbl = next(panel_labels)
- lbl2 = next(panel_labels)
- for n_label, n_type, clr in neuron_types:
- ax_rate.plot(beta_vals, results[cond_name][n_label],
- 'o-' if n_label == 'Excitatory' else 's--',
- color=clr, lw=2, ms=4, label=n_label)
- # Guard against zero/negative values for log scale
- # Clamp floor at 1e-10 (values below are numerical zero)
- cam_data = camkii_results[cond_name][n_label]
- cam_data_safe = np.clip(cam_data, 1e-10, None)
- ax_cam.semilogy(beta_vals, cam_data_safe,
- 'o-' if n_label == 'Excitatory' else 's--',
- color=clr, lw=2, ms=4, label=n_label)
- ax_rate.set_title(f'({lbl}) {cond_name}', loc='left', fontweight='bold')
- ax_rate.set_xlabel(r'$\beta_{NMDA}$')
- if j == 0:
- ax_rate.set_ylabel('Firing Rate (Hz)')
- ax_rate.legend(fontsize=8)
- ax_cam.set_title(f'({lbl2}) {cond_name}', loc='left', fontweight='bold')
- ax_cam.set_xlabel(r'$\beta_{NMDA}$')
- if j == 0:
- ax_cam.set_ylabel('Mean CaMKII$_p$ (log)')
- ax_cam.set_ylim(bottom=1e-10) # floor: values below are numerical zero
- fig.suptitle(r'$\beta_{NMDA}$ $\times$ Neuron Type $\times$ Input Condition Interaction',
- fontsize=14, fontweight='bold')
- fig.tight_layout(rect=[0, 0, 1, 0.96])
- save_fig(fig, 'Fig7_interaction_summary')
- # =============================================================================
- # FIGURE 8: AMPA RECEPTOR CLOSING RATE (β_AMPA) SENSITIVITY ANALYSIS
- # =============================================================================
- def figure8_ampa_closing_rate_sensitivity():
- """
- AMPA receptor closing rate (β_AMPA) sensitivity analysis.
- β_AMPA (AMPA unbinding rate) controls AMPA EPSC decay kinetics.
- Physiological range: ~0.2–2.0 ms⁻¹ (decay τ ≈ 0.5–5 ms).
- Default value: 0.67 ms⁻¹ (τ ≈ 1.5 ms).
- Panels:
- (A) AMPA EPSC waveforms at selected β_AMPA values
- (B) Firing rate vs β_AMPA — excitatory & inhibitory neurons
- (C) Mean CaMKII phosphorylation vs β_AMPA — both neuron types
- (D) E/I current ratio vs β_AMPA — both neuron types
- (E) 2D heatmap: β_AMPA × β_NMDA interaction (firing rate, excitatory)
- (F) 2D heatmap: β_AMPA × β_NMDA interaction (CaMKII, excitatory)
- """
- print(" Figure 8: β_AMPA (AMPA closing rate) sensitivity ...")
- # --- β_AMPA values (finer resolution around 0.3–0.7 transition) ---
- beta_ampa_1d = np.array([0.1, 0.2, 0.3, 0.35, 0.4, 0.45, 0.5, 0.6,
- 0.67, 0.8, 1.0, 1.5, 2.0, 3.0])
- beta_nmda_fixed = 0.03 # fixed for 1D sweeps
- clr_exc = '#2E86C1'
- clr_inh = '#E74C3C'
- idx_ss = int(5000 / deltaT) # steady-state index
- # ── 1D sweeps ──────────────────────────────────────────────────────
- fr_exc = np.zeros(len(beta_ampa_1d))
- fr_inh = np.zeros(len(beta_ampa_1d))
- camk_exc = np.zeros(len(beta_ampa_1d))
- camk_inh = np.zeros(len(beta_ampa_1d))
- ei_exc = np.zeros(len(beta_ampa_1d))
- ei_inh = np.zeros(len(beta_ampa_1d))
- print(" 1D β_AMPA sweep ...")
- for k, ba in enumerate(beta_ampa_1d):
- re = run_neuron_simulation(beta_nmda_fixed, 'excitatory',
- beta_ampa_val=ba)
- ri = run_neuron_simulation(beta_nmda_fixed, 'inhibitory',
- beta_ampa_val=ba)
- _, fr_exc[k] = count_spikes(re['v'], re['t'])
- _, fr_inh[k] = count_spikes(ri['v'], ri['t'])
- camk_exc[k] = np.mean(re['CaMKII_p'][idx_ss:])
- camk_inh[k] = np.mean(ri['CaMKII_p'][idx_ss:])
- ei_exc[k] = compute_ei_ratio(re)
- ei_inh[k] = compute_ei_ratio(ri)
- if k % 3 == 0:
- print(f" β_AMPA = {ba:.2f}: FR(exc) = {fr_exc[k]:.1f} Hz, "
- f"CaMKII = {camk_exc[k]:.2e}")
- # ── 2D heatmap: β_AMPA × β_NMDA ──────────────────────────────────
- beta_ampa_2d = np.array([0.2, 0.4, 0.67, 1.0, 1.5, 2.0])
- beta_nmda_2d = np.array([0.005, 0.01, 0.02, 0.03, 0.05, 0.08, 0.12])
- rate_map = np.zeros((len(beta_ampa_2d), len(beta_nmda_2d)))
- camk_map = np.zeros((len(beta_ampa_2d), len(beta_nmda_2d)))
- print(" 2D β_AMPA × β_NMDA heatmap ...")
- for ai, ba in enumerate(beta_ampa_2d):
- for nj, bn in enumerate(beta_nmda_2d):
- re = run_neuron_simulation(bn, 'excitatory', beta_ampa_val=ba)
- _, rate_map[ai, nj] = count_spikes(re['v'], re['t'])
- camk_map[ai, nj] = np.mean(re['CaMKII_p'][idx_ss:])
- # ── AMPA EPSC waveforms (analytical, for illustration) ────────────
- # Single-pulse AMPA gating: m_AMPA(t) = (α/(α+β)) * exp(-β*t) for t > pulse
- t_epsc = np.linspace(0, 30, 600) # 30 ms window
- pulse_dur = 5.0 # ms
- epsc_betas = [0.2, 0.67, 1.5, 3.0]
- epsc_colors = ['#2C3E50', '#2E86C1', '#E67E22', '#E74C3C']
- # ── Plot ───────────────────────────────────────────────────────────
- fig = plt.figure(figsize=(18, 11))
- gs_fig = gridspec.GridSpec(2, 3, hspace=0.38, wspace=0.32)
- # (A) AMPA EPSC waveforms
- ax_a = fig.add_subplot(gs_fig[0, 0])
- for ba_val, col in zip(epsc_betas, epsc_colors):
- # Simulate single-pulse AMPA gating
- dt_ep = 0.05
- tn_ep = int(30 / dt_ep)
- t_ep = np.arange(tn_ep + 1) * dt_ep
- m_ep = np.zeros(tn_ep + 1)
- for i_ep in range(tn_ep):
- G_ep = 1.0 if t_ep[i_ep] <= pulse_dur else 0.0
- m_ep[i_ep + 1] = m_ep[i_ep] + dt_ep * (
- alpha_ampa * G_ep * (1 - m_ep[i_ep]) - ba_val * m_ep[i_ep])
- # Normalise to peak for shape comparison
- if m_ep.max() > 0:
- m_norm = m_ep / m_ep.max()
- else:
- m_norm = m_ep
- tau_decay = 1.0 / ba_val
- ax_a.plot(t_ep, m_norm, color=col, lw=2,
- label=f'β = {ba_val:.2f} (τ ≈ {tau_decay:.1f} ms)')
- ax_a.set_xlabel('Time (ms)')
- ax_a.set_ylabel('Normalised AMPA conductance')
- ax_a.set_title('(A) AMPA EPSC Waveforms\n(single pulse, normalised)',
- loc='left', fontweight='bold')
- ax_a.legend(fontsize=8, title='$β_{AMPA}$', title_fontsize=9)
- # (B) Firing rate vs β_AMPA
- ax_b = fig.add_subplot(gs_fig[0, 1])
- ax_b.plot(beta_ampa_1d, fr_exc, 'o-', color=clr_exc, lw=2, ms=6,
- label='Excitatory')
- ax_b.plot(beta_ampa_1d, fr_inh, 's--', color=clr_inh, lw=2, ms=6,
- label='Inhibitory')
- ax_b.axvline(0.67, color='gray', ls=':', lw=1, alpha=0.6, label='Default (0.67)')
- ax_b.set_xlabel(r'$\beta_{AMPA}$ (ms$^{-1}$)')
- ax_b.set_ylabel('Firing Rate (Hz)')
- ax_b.set_title(f'(B) Firing Rate vs $β_{{AMPA}}$\n'
- f'($β_{{NMDA}}$ = {beta_nmda_fixed})',
- loc='left', fontweight='bold')
- ax_b.legend(fontsize=8)
- # (C) CaMKII vs β_AMPA
- ax_c = fig.add_subplot(gs_fig[0, 2])
- ax_c.semilogy(beta_ampa_1d, camk_exc, 'o-', color=clr_exc, lw=2, ms=6,
- label='Excitatory')
- ax_c.semilogy(beta_ampa_1d, camk_inh, 's--', color=clr_inh, lw=2, ms=6,
- label='Inhibitory')
- ax_c.axvline(0.67, color='gray', ls=':', lw=1, alpha=0.6, label='Default')
- ax_c.set_xlabel(r'$\beta_{AMPA}$ (ms$^{-1}$)')
- ax_c.set_ylabel('Mean CaMKII$_p$ (log scale)')
- ax_c.set_title(f'(C) CaMKII Phosphorylation vs $β_{{AMPA}}$',
- loc='left', fontweight='bold')
- ax_c.legend(fontsize=8)
- # (D) E/I ratio vs β_AMPA
- ax_d = fig.add_subplot(gs_fig[1, 0])
- ax_d.plot(beta_ampa_1d, ei_exc, 'o-', color=clr_exc, lw=2, ms=6,
- label='Excitatory')
- ax_d.plot(beta_ampa_1d, ei_inh, 's--', color=clr_inh, lw=2, ms=6,
- label='Inhibitory')
- ax_d.axvline(0.67, color='gray', ls=':', lw=1, alpha=0.6, label='Default')
- ax_d.axhline(1.0, color='black', ls=':', lw=0.8, alpha=0.4)
- ax_d.set_xlabel(r'$\beta_{AMPA}$ (ms$^{-1}$)')
- ax_d.set_ylabel('E/I Current Ratio')
- ax_d.set_title('(D) Excitation–Inhibition Balance vs $β_{AMPA}$',
- loc='left', fontweight='bold')
- ax_d.legend(fontsize=8)
- # (E) 2D heatmap: β_AMPA × β_NMDA → Firing Rate
- ax_e = fig.add_subplot(gs_fig[1, 1])
- im_e = ax_e.imshow(rate_map, origin='lower', aspect='auto',
- extent=[beta_nmda_2d[0], beta_nmda_2d[-1],
- beta_ampa_2d[0], beta_ampa_2d[-1]],
- cmap='viridis', interpolation='bilinear')
- for ai, ba in enumerate(beta_ampa_2d):
- for nj, bn in enumerate(beta_nmda_2d):
- val = rate_map[ai, nj]
- ax_e.text(bn, ba, f'{val:.0f}', ha='center', va='center',
- fontsize=6, color='white' if val > rate_map.max()*0.5 else 'black')
- fig.colorbar(im_e, ax=ax_e, label='Firing Rate (Hz)', shrink=0.85)
- ax_e.set_xlabel(r'$\beta_{NMDA}$')
- ax_e.set_ylabel(r'$\beta_{AMPA}$ (ms$^{-1}$)')
- ax_e.set_title('(E) $β_{AMPA}$ × $β_{NMDA}$ → FR\n(Excitatory)',
- loc='left', fontweight='bold')
- # Mark default
- ax_e.plot(0.03, 0.67, 'r*', markersize=12, zorder=5)
- # (F) 2D heatmap: β_AMPA × β_NMDA → CaMKII
- ax_f = fig.add_subplot(gs_fig[1, 2])
- # Use log scale for CaMKII
- camk_log = np.log10(camk_map + 1e-30)
- im_f = ax_f.imshow(camk_log, origin='lower', aspect='auto',
- extent=[beta_nmda_2d[0], beta_nmda_2d[-1],
- beta_ampa_2d[0], beta_ampa_2d[-1]],
- cmap='magma', interpolation='bilinear')
- for ai, ba in enumerate(beta_ampa_2d):
- for nj, bn in enumerate(beta_nmda_2d):
- val = camk_map[ai, nj]
- ax_f.text(bn, ba, f'{val:.0e}', ha='center', va='center',
- fontsize=5, color='white')
- fig.colorbar(im_f, ax=ax_f, label='log₁₀(CaMKII$_p$)', shrink=0.85)
- ax_f.set_xlabel(r'$\beta_{NMDA}$')
- ax_f.set_ylabel(r'$\beta_{AMPA}$ (ms$^{-1}$)')
- ax_f.set_title('(F) $β_{AMPA}$ × $β_{NMDA}$ → CaMKII\n(Excitatory)',
- loc='left', fontweight='bold')
- ax_f.plot(0.03, 0.67, 'r*', markersize=12, zorder=5)
- fig.suptitle(
- r'AMPA Receptor Closing Rate ($\beta_{AMPA}$) Sensitivity Analysis',
- fontsize=14, fontweight='bold')
- fig.tight_layout(rect=[0, 0, 1, 0.96])
- save_fig(fig, 'Fig8_beta_AMPA_sensitivity')
- # ── Print summary ──────────────────────────────────────────────────
- print("\n ── β_AMPA Sensitivity Summary ──")
- print(f" Range tested: {beta_ampa_1d[0]:.2f} – {beta_ampa_1d[-1]:.2f} ms⁻¹")
- print(f" Default value: 0.67 ms⁻¹ (τ_decay ≈ 1.5 ms)")
- fr_range = fr_exc.max() - fr_exc.min()
- fr_pct = 100 * fr_range / fr_exc[beta_ampa_1d == 0.67][0] if 0.67 in beta_ampa_1d else 0
- print(f" Excitatory FR range: {fr_exc.min():.1f} – {fr_exc.max():.1f} Hz "
- f"(Δ = {fr_pct:.1f}%)")
- print(f" Inhibitory FR range: {fr_inh.min():.1f} – {fr_inh.max():.1f} Hz")
- camk_ratio = camk_exc.max() / (camk_exc.min() + 1e-30)
- print(f" CaMKII range (exc): {camk_exc.min():.2e} – {camk_exc.max():.2e} "
- f"({camk_ratio:.1f}× variation)")
- # =============================================================================
- # RUN ALL FIGURES
- # =============================================================================
- if __name__ == '__main__':
- print("=" * 60)
- print("Generating Supplementary Figures")
- print("=" * 60)
- figure1_pulse_profiles()
- figure2_three_conditions()
- figure3_exc_vs_inh()
- figure4_nmda_parameter_sweep()
- figure5_conductance_tuning()
- figure6_three_conditions_inhibitory()
- figure7_interaction_summary()
- figure8_ampa_closing_rate_sensitivity()
- print("\n" + "=" * 60)
- print(f"All figures saved to: {save_directory}")
- print("=" * 60)
reviewer_response_simulations_final.py at commit 006879e, under MIT · at the source
Overview
- International Centre for Translational Eye Research (ICTER), Institute of Physical Chemistry, Polish Academy of Sciences, Warsaw, Poland
- Institute of Physical Chemistry, Polish Academy of Sciences, Warsaw, Poland
- School of Engineering – Energy and Information, HTW Berlin – University of Applied Sciences, Berlin, Germany
- Optics and Laser Engineering Group, Faculty of Electrical Engineering, Urmia University of Technology, Urmia, Iran
- CIPCE, Motor Control and Computational Neuroscience Laboratory, School of ECE, College of Engineering, University of Tehran, Tehran, Iran
- Neuroscience Research Center and Department of Physiology, Medical School, Shahid Beheshti University of Medical Sciences, Tehran, Iran
Abstract
Introduction: Neuronal firing patterns emerge from complex interactions between intrinsic membrane properties and synaptic receptor dynamics. N-methyl-D-aspartate (NMDA) receptors critically shape calcium influx and synaptic plasticity through their voltage-dependent Mg2+ block and prolonged activation kinetics, yet how their closing kinetics interact with glutamatergic drive and GABAergic modulation to control neuronal dynamics and information processing remains incompletely understood.
Methods: We developed a Hodgkin–Huxley-type computational model incorporating NMDA, AMPA, and GABA receptor kinetics to investigate how the NMDA receptor closing rate βNMDA and glutamatergic stimulation frequency control neuronal dynamics. We performed a systematic analysis of over 2.9 million inter-spike intervals across a large multi-parameter sweep of NMDA kinetics, glutamatergic stimulation frequency, and GABAergic modulation. Dynamical behavior was characterized using entropy–Lyapunov correlation analysis and frequency-dependent bifurcation analysis, and CaMKII phosphorylation was quantified to link kinetic regimes to downstream plasticity signaling.
Results: The analysis revealed two mechanistically distinct pathways to firing irregularity. Pathway 1 (rapid-deactivation irregularity) emerged under relatively fast NMDA deactivation combined with specific input-frequency conditions, producing deterministic chaos with compromised information encoding. Pathway 2 (prolonged-activation irregularity) resulted from slow NMDA deactivation under weak drive, creating irregularity through sustained receptor activation and calcium influx. An optimal kinetic window emerged at βNMDA = 0.042 ms−1, maximizing information transfer (0.275 bits) while maintaining stable dynamics. Entropy–Lyapunov correlation analysis confirmed deterministic chaos, and frequency-dependent bifurcation analysis demonstrated progressive narrowing and displacement of chaotic windows across the analyzed βNMDA range as stimulation frequency increased. GABAergic inhibition provided frequency-selective stabilization, expanding the stable parameter space by 34.2% while preserving gamma oscillations. CaMKII phosphorylation analysis revealed that prolonged NMDA activation maintained elevated phosphorylation levels, creating conditions for pathological long-term potentiation.
Discussion: These findings establish NMDA receptor kinetics as fundamental controllers of cortical excitability and information processing. The dual-pathway framework provides mechanistic insights into addiction-related memory formation, where prolonged NMDA activation enables pathological plasticity, and into visual processing disorders, where altered kinetics disrupt retinal function and cortical oscillatory balance. The identification of optimal kinetic windows and frequency-selective GABA modulation suggests therapeutic strategies based on kinetically specific interventions for neuropsychiatric disorders involving NMDA dysfunction.
Reproduced under the paper's license (CC BY), from the paper cited above.
Repository
Its files are read in the Code ↔ Paper reader above, with 26 matches between paragraphs and lines of code.
borjkhani/Bifurcation_NMDA_FCN
006879efec965df60df84b7d103bc00b714a8983, 27 February 2026Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
11 files
- Code1.py, Python, 725 lines, 2 matches
- Sensitivity.py, Python, 531 lines, 1 match
- gaba_bifurcation.py, Python, 281 lines, 3 matches
- reviewer_response_simula
tions_final.py , Python, 1,127 lines, 5 matches - v4_6.py, Python, 1,320 lines, 4 matches
- v4_6_8_CaMKII_3.py, Python, 1,011 lines, 5 matches
- v4_6_8_CaMKII_sub_21.py, Python, 732 lines, 1 match
- v_StimW_Beta_5_6_1D.py, Python, 592 lines, 3 matches
- v_StimW_Beta_5_6_1D_CaMK
II_6_5_GABA_4_Complete_6 , Python, 1,756 lines, 2 matches.py - LICENSE, License, 21 lines
- README.md, Text, 278 lines
The paper's code and data availability statement is in the Data section.
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;
- 9 scripts, each with its path and the digest of its content;
- 26 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- 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 statement
The datasets presented in this study can be found in online repositories. The names of the repository/
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 2, 28 September 2026
- Authors: added Mehdi Borjkhani (0000-0003-0469-0902); Hadi Borjkhani (0000-0001-5495-3964); removed Mehdi Borjkhani; Hadi Borjkhani
- Funding: added European Commission; Fundacja na rzecz Nauki Polskiej
Version 1, 27 September 2026: the first record
Recorded: type, language, journal, volume, pages, dates, 5 authors, 8 keywords, 82 references.
Cite
This paper
Borjkhani, M., Borjkhani, H., Sharif, M. A., Bahrami, F., & Janahmadi, M. (2026). NMDA receptor kinetics drive distinct routes to chaotic firing in pyramidal neurons. Frontiers in computational neuroscience, 20, 1753444. https://
BibTeX
@article{borjkhani2026nm
author = {Borjkhani, Mehdi and Borjkhani, Hadi and Sharif, Morteza A and Bahrami, Fariba and Janahmadi, Mahyar},
title = {{NMDA receptor kinetics drive distinct routes to chaotic firing in pyramidal neurons}},
journal = {Frontiers in computational neuroscience},
year = {2026},
month = jun,
volume = {20},
pages = {1753444},
publisher = {Frontiers Media SA},
issn = {1662-5188},
doi = {10.3389/
url = {https://
pmid = {42318008},
pmcid = {PMC13272316}
}
RIS
TY - JOUR
AU - Borjkhani, Mehdi
AU - Borjkhani, Hadi
AU - Sharif, Morteza A
AU - Bahrami, Fariba
AU - Janahmadi, Mahyar
TI - NMDA receptor kinetics drive distinct routes to chaotic firing in pyramidal neurons
T2 - Frontiers in computational neuroscience
J2 - Front Comput Neurosci
PY - 2026
DA - 2026/
VL - 20
SP - 1753444
SN - 1662-5188
PB - Frontiers Media SA
DO - 10.3389/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.3389/
"type": "article-journal",
"title": "NMDA receptor kinetics drive distinct routes to chaotic firing in pyramidal neurons",
"container-title": "Frontiers in computational neuroscience",
"author": [
{
"family": "Borjkhani",
"given": "Mehdi"
},
{
"family": "Borjkhani",
"given": "Hadi"
},
{
"family": "Sharif",
"given": "Morteza A"
},
{
"family": "Bahrami",
"given": "Fariba"
},
{
"family": "Janahmadi",
"given": "Mahyar"
}
],
"container-title-short":
"volume": "20",
"page": "1753444",
"DOI": "10.3389/
"PMID": "42318008",
"PMCID": "PMC13272316",
"ISSN": "1662-5188",
"publisher": "Frontiers Media SA",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
6,
3
]
]
}
}
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.1038/s41598-026-42120-y [code]
- Qualitative EEG abnormalities in ASD reflect inhibition-dominated brain dynamics.Journal: Scientific reportsIn common: seaborn, pandas, SciPy, 2 other tools, 3 references
- [2] doi:10.1016/j.patter.2026.101619 [code]
- Sampling bias corrections for discrete and Gaussian partial information decompositions.Journal: Patterns (New York, N.Y.)In common: seaborn, scikit-learn, pandas, 3 other tools, 2 references
- [3] doi:10.7554/elife.105482 [code]
- Principles of gamma synchrony predict figure-ground perception in texture stimuli.Journal: eLifeIn common: seaborn, scikit-learn, pandas, 3 other tools, 2 references
- [4] doi:10.1162/imag.a.1252 [code]
- Does the brain's E:I balance really shape long-range temporal correlations? Lessons learned from 3T MRI.Journal: Imaging neuroscience (Cambridge, Mass.)In common: seaborn, scikit-learn, pandas, 3 other tools, 2 references
- [5] doi:10.1371/journal.pcbi.1014304 [code]
- Linking reduced prefrontal microcircuit inhibition in schizophrenia to EEG biomarkers in silico.Journal: PLoS computational biologyIn common: scikit-learn, pandas, SciPy, 2 other tools, 2 references
- [6] doi:10.1371/journal.pcbi.1014391 [code]
- Multi-stable oscillations in cortical networks with two classes of inhibition.Journal: PLoS computational biologyIn common: seaborn, scikit-learn, pandas, 3 other tools, none (in silico), 1 reference
- [7] doi:10.1371/journal.pcbi.1014571 [code]
- SynAPSeg: A novel dataset and image analysis framework for deep learning-based synapse detection and quantification.Journal: PLoS computational biologyIn common: seaborn, scikit-learn, pandas, 3 other tools, 1 reference
- [8] doi:10.1038/s41467-026-74227-1 [code]
- Age-related changes in behavioural and neural variability in a decision-making task.Journal: Nature communicationsIn common: seaborn, scikit-learn, pandas, 3 other tools, 1 reference
- [9] doi:10.1038/s41586-026-10331-y [code]
- Active dissociation of intracortical spiking and high gamma activity.Journal: NatureIn common: scikit-learn, pandas, SciPy, 2 other tools, 2 references
- [10] doi:10.1016/j.isci.2026.115488 [code]
- An integrated &
lt;i& gt;i& lt;/ i& gt; & lt;i& gt;n vitro& lt;/ i& gt; platform and biophysical modeling approach for studying synaptic transmission in isolated neuronal pairs. Journal: iScienceIn common: seaborn, scikit-learn, pandas, 3 other tools, cellular / molecular, 1 reference
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, 9 scripts, and 26 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:3bc917f2bc6a1199…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
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: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
