varie
This commit is contained in:
+2
-2
@@ -580,9 +580,9 @@ Voltage-Controlled Gated Channels: Qui per ora non gestiamo l'evoluzione della d
|
|||||||
container: BEH-PRE-VGCC
|
container: BEH-PRE-VGCC
|
||||||
|
|
||||||
tub_intricated:
|
tub_intricated:
|
||||||
- Ca2+ ( contained_by: BEH-PRE )
|
- Ca2+ ( contained_by: BEH-PRE )
|
||||||
|
|
||||||
context_intricated:
|
context_intricated:
|
||||||
- AP ( contained_by: BEH-SOMA )
|
- AP ( contained_by: BEH-SOMA )
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,321 +0,0 @@
|
|||||||
# The Biological "Cascade of Failure"
|
|
||||||
|
|
||||||
This model now demonstrates **Metabolic Silencing**, which is a highly consistent biological behavior:
|
|
||||||
|
|
||||||
1. High firing rate → **Vesicle Depletion** (Fast).
|
|
||||||
2. High firing rate → **ATP Depletion** (Slow).
|
|
||||||
3. Low ATP → **Pump Failure** (JPMCA slows down).
|
|
||||||
4. Pump Failure → **Residual Calcium** stays high.
|
|
||||||
5. Residual Calcium → **CDI stays active** (The VGCCs lock shut).
|
|
||||||
6. **Result:** The synapse stops firing to save itself from excitotoxicity.
|
|
||||||
|
|
||||||
**CASCADE 1 — Vesicle Depletion** appears at `Max_RRP`, `Max_RP`, `p_release_base`, `k_rec_fast/slow`, `stochastic_release`, `map_trace_to_speed`, and the recruitment block in Loop 1. The key annotation explains the asymmetry: `p_release_base * Ca_micro` makes each spike draw *more* vesicles as Ca_micro rises early in a burst — a positive feedback that accelerates the collapse before recruitment can respond.
|
|
||||||
|
|
||||||
**CASCADE 2 — ATP Depletion** is anchored at `Glucose_level` (the root input) and at `compute_astrocyte_metabolic_health` in Loop 3, where it explains that `ATP_level` is the bridge variable that carries minute-scale metabolic state into the millisecond Ca²⁺ world.
|
|
||||||
|
|
||||||
**CASCADE 3 — Pump Failure** is annotated at `k_PMCA`, `k_NCX`, `k_SERCA`, `ATP_half`, and `compute_pump_atp_factor`. The NCX comment explicitly notes its role as a floor-not-rescue — it keeps clearing during failure and enables the auto-reset, but cannot prevent accumulation alone.
|
|
||||||
|
|
||||||
**CASCADE 4 — Residual Ca²⁺** appears at `B_total`, `tau_buffer_rebind`, the `capture_fraction` block, and the buffer recharge lines. The buffer saturation note explains the two-phase dynamic: buffer is protective early but becomes invisible once `B_free → 0`.
|
|
||||||
|
|
||||||
**CASCADE 5 — CDI Lock-out** is annotated at `k_CDI_rise`, `Ca_micro_saturation`, `k_CDI_rec`, and both the rise and recovery lines in Loop 1. The recovery comment spells out the self-locking logic explicitly as a chain.
|
|
||||||
|
|
||||||
**CASCADE 6 — Silence** sits at `effective_conductance` with a timing note showing that mGluR fires first, eCB second, and CDI last but irreversibly. The eCB and mGluR annotations in Loop 2 explain their roles as early partial brakes versus the terminal lock.
|
|
||||||
|
|
||||||
## 5. Model Summary Checklist
|
|
||||||
|
|
||||||
- \[x\] **Timing:** Spans 0.1 ms (AP) to 300,000 ms (Metabolism).
|
|
||||||
- \[x\] **Conservation:** Vesicles and Neurotransmitters are conserved through the Gln→RP→RRP→Cleft→Astro loop.
|
|
||||||
- \[x\] **Stability:** CDI and mGluR/eCB provide three layers of negative feedback to prevent runaway excitation.
|
|
||||||
- \[x\] **Resource Constraints:** ATP and Pool guards prevent physically impossible negative values or infinite accumulation.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
This pseudocode serves as a comprehensive blueprint for a biologically consistent tripartite synapse. It is structured into three nested temporal loops to handle the transition from microseconds to minutes.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **Variable Reference Table**
|
|
||||||
|
|
||||||
| Variable | Definition | Scale | Role |
|
|
||||||
|---------------|------------------------------------|--------|-----------------------------|
|
|
||||||
| **Ca_micro** | Free calcium in the active zone | 0.1 ms | Triggers release and CDI |
|
|
||||||
| **B_free** | Available buffer sites (Calbindin) | 0.1 ms | Immediate calcium "sponge" |
|
|
||||||
| **N_RRP** | Readily Releasable Pool | 1 ms | Immediate vesicle supply |
|
|
||||||
| **N_RP** | Reserve Pool | 100 ms | Long-term vesicle warehouse |
|
|
||||||
| **Tr_Ca** | Calcium Trace | 10 ms | Memory of recent activity |
|
|
||||||
| **CDI_fac** | Inactivation Factor | 50 ms | Internal negative feedback |
|
|
||||||
| **mGluR_pre** | Autoreceptor activation | 500 ms | Cleft-sensing inhibition |
|
|
||||||
| **ATP_level** | Metabolic energy state | 1 min | Gates calcium clearance |
|
|
||||||
|
|
||||||
### **The Multi-Scale Engine**
|
|
||||||
|
|
||||||
```python
|
|
||||||
# --- SIMULATION CONFIGURATION ---
|
|
||||||
# dt = 0.1 ms (Fine-grained step)
|
|
||||||
# Total_Time = 300,000 ms (5 minutes)
|
|
||||||
|
|
||||||
while t < Total_Time:
|
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# 1. FINE-GRAINED NEURAL LOOP (Every 0.1ms)
|
|
||||||
# Handles: Electrical spikes, Buffering, and Influx
|
|
||||||
# ============================================================
|
|
||||||
|
|
||||||
# --- ACTION POTENTIAL & WAVEFORM ---
|
|
||||||
if is_AP_active(t):
|
|
||||||
# Layered Inhibition logic:
|
|
||||||
# CDI (Internal), eCB (Retrograde/Post), mGluR (Autoreceptor/Cleft)
|
|
||||||
total_inhibition = (1 - CDI_fac) * (1 - eCB_level) * (1 - mGluR_pre * alpha_mGluR)
|
|
||||||
|
|
||||||
# Calculate Influx via VGCC
|
|
||||||
# V_pre_pulse(t) accounts for the finite duration of the spike window
|
|
||||||
raw_influx = N_VGCC * total_inhibition * V_pre_pulse(t)
|
|
||||||
|
|
||||||
# --- FAST BUFFERING BEHAVIOR ---
|
|
||||||
# Immediate capture of influx by buffer proteins (e.g., Calbindin)
|
|
||||||
captured = raw_influx * (B_free / B_total)
|
|
||||||
B_free = max(0, B_free - captured)
|
|
||||||
Ca_bound += captured
|
|
||||||
|
|
||||||
# Resulting free Calcium that actually reaches the sensors
|
|
||||||
Ca_micro += (raw_influx - captured)
|
|
||||||
|
|
||||||
# --- STOCHASTIC RELEASE ---
|
|
||||||
if N_RRP > 0:
|
|
||||||
# Release probability is a function of Ca_micro
|
|
||||||
p_release = compute_stochastic_p(Ca_micro, N_RRP)
|
|
||||||
if random_uniform(0, 1) < p_release:
|
|
||||||
N_RRP -= 1 # Deplete one vesicle
|
|
||||||
Glu_cleft += 1 # Release NT into cleft
|
|
||||||
CDI_fac += k_CDI_rise # Increment inactivation per release
|
|
||||||
|
|
||||||
# --- CONTINUOUS CALCIUM CLEARANCE ---
|
|
||||||
# NCX (Sodium-Calcium Exchanger) - Fast, gradient driven
|
|
||||||
# PMCA (Plasma Membrane Ca-ATPase) - Slow, ATP dependent
|
|
||||||
atp_efficiency = ATP_level**2 / (ATP_level**2 + 0.3**2)
|
|
||||||
cleared = (k_NCX * Ca_micro) + (k_PMCA * Ca_micro * atp_efficiency)
|
|
||||||
Ca_micro = max(0.0, Ca_micro - cleared)
|
|
||||||
|
|
||||||
# --- RECOVERY MECHANISMS ---
|
|
||||||
# CDI Recovery: Decay of inactivation as Ca_micro falls
|
|
||||||
CDI_fac = max(0.0, CDI_fac - (dt / tau_CDI_rec))
|
|
||||||
|
|
||||||
# Buffer Recovery: Re-release of bound ions into microdomain
|
|
||||||
re_release = Ca_bound * (dt / tau_buf_release)
|
|
||||||
Ca_bound -= re_release
|
|
||||||
Ca_micro += re_release
|
|
||||||
B_free = B_total - Ca_bound
|
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# 2. MID-GRAINED INTEGRATION (Every 10ms - 100ms)
|
|
||||||
# Handles: Recruitment Traces and Autoreceptor Feedback
|
|
||||||
# ============================================================
|
|
||||||
if t % 10 == 0:
|
|
||||||
# TRACE INTEGRATOR: The memory of recent spikes
|
|
||||||
Tr_Ca = update_leaky_integrator(Tr_Ca, Ca_micro, tau_trace)
|
|
||||||
|
|
||||||
# RECRUITMENT LOGIC (RP -> RRP)
|
|
||||||
# Recruitment speed (k_rec) scales non-linearly with Tr_Ca
|
|
||||||
k_rec = compute_k_rec(Tr_Ca)
|
|
||||||
|
|
||||||
# Apply HARD CAPS and GUARDS:
|
|
||||||
# 1. Cannot take more than what is in RP
|
|
||||||
# 2. Cannot exceed the ceiling of RRP
|
|
||||||
refill_qty = k_rec * N_RP * (Max_RRP - N_RRP)
|
|
||||||
refill_qty = max(0, min(refill_qty, N_RP))
|
|
||||||
|
|
||||||
N_RRP += refill_qty
|
|
||||||
N_RP -= refill_qty
|
|
||||||
|
|
||||||
# AUTORECEPTOR FEEDBACK: Presynapse sensing its own NT
|
|
||||||
mGluR_pre += (Glu_cleft / (Glu_cleft + Km) - mGluR_pre) * (10 / tau_mGluR)
|
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# 3. COARSE-GRAINED METABOLIC LOOP (Every 1s - 1min)
|
|
||||||
# Handles: Astrocyte support, eCB Brake, and Sustainability
|
|
||||||
# ============================================================
|
|
||||||
if t % 1000 == 0:
|
|
||||||
# ASTROCYTE GLUTAMATE CLEARANCE
|
|
||||||
# Astrocytes clean the cleft; NT is recycled into the Glutamine pool
|
|
||||||
cleared_glu = Glu_cleft * EAAT_clearance_rate
|
|
||||||
Glu_cleft -= cleared_glu
|
|
||||||
Gln_pool += cleared_glu
|
|
||||||
|
|
||||||
# RETROGRADE BRAKE (eCB from Postsynapse)
|
|
||||||
# Postsynapse synthesizes eCB based on its own V_post activity
|
|
||||||
eCB_level = update_retrograde_brake(V_post_history)
|
|
||||||
|
|
||||||
# METABOLIC REPLENISHMENT
|
|
||||||
# Astrocyte health determines ATP; Glutamine refills the Reserve Pool
|
|
||||||
ATP_level = compute_atp_from_astro_health(Gln_pool, Metabolic_State)
|
|
||||||
|
|
||||||
# Long-term Refill of the Reserve Pool (The Warehouse)
|
|
||||||
N_RP = min(N_RP + (Gln_pool * metabolic_shuttle_rate), Max_RP)
|
|
||||||
Gln_pool *= 0.9 # Account for metabolic overhead/loss
|
|
||||||
|
|
||||||
t += dt # Increment simulation time
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. Biological Consistency Summary
|
|
||||||
|
|
||||||
1. **Metabolic Coupling:** The `atp_efficiency` variable creates a physical link between the 5-minute astrocyte clock and the 0.1ms calcium clock. If the astrocyte is exhausted, the pumps fail, and the `CDI_fac` locks the synapse into **silence**.
|
|
||||||
2. **Double-Lock Inhibition:** You have two distinct brakes. The `mGluR_pre` is "homosynaptic" (local self-check), while the `eCB_level` is "heterosynaptic" (feedback from the receiver). This prevents runaway excitation and excitotoxicity.
|
|
||||||
3. **Conservation of Mass:** Neurotransmitters follow a closed loop: `Gln_pool` -> `N_RP` -> `N_RRP` -> `Glu_cleft` -> `Astrocyte` -> `Gln_pool`.
|
|
||||||
4. **Buffer Buffer:** The `B_free` mechanism prevents numerical instability during high-frequency bursts by absorbing excess calcium influx instantly.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
The missing presynaptic behaviors are:
|
|
||||||
|
|
||||||
1. **Ca²⁺ clearance** (PMCA, NCX pumps) — without this, Ca²⁺ accumulates indefinitely
|
|
||||||
2. **Calcium buffer proteins** (calbindin, calmodulin) — fast buffering before pumps clear
|
|
||||||
3. **VGCC inactivation recovery** — CDI is mentioned but the recovery (de-inactivation) is missing
|
|
||||||
4. **RRP hard cap** — the refill logic can overshoot without a ceiling
|
|
||||||
5. **Reserve Pool (RP) depletion guard** — refill can go negative
|
|
||||||
6. **Presynaptic autoreceptors** (mGluR/CB1R feedback closing the loop from NT in cleft → presynaptic suppression) — separate from eCB which comes from postsynapse
|
|
||||||
7. **Spike refractory / AP waveform duration** — the effective window for Ca²⁺ entry is finite
|
|
||||||
|
|
||||||
Let me build an annotated code diagram and then write the enhanced model.Here is a full analysis of every missing loop, followed by the updated code for each section.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Missing behaviors and the reasoning behind each
|
|
||||||
|
|
||||||
**Why Ca²⁺ clearance is the most critical gap.** `Ca_micro` currently has no exit route — it only grows. Without PMCA pumps, NCX exchangers, and SERCA (ER uptake), every spike leaves residual Ca²⁺ that accumulates across the simulation and eventually locks the synapse in a permanently over-activated (or CDI-locked) state. The clearance mechanisms also run at different speeds: NCX is fast (tens of ms), PMCA is slower but higher-capacity, SERCA is slowest and stores calcium for later use as an internal buffer.
|
|
||||||
|
|
||||||
**Why Ca²⁺ buffer proteins must precede clearance.** Calbindin and calmodulin bind free Ca²⁺ within microseconds and act as a fast, temporary "sponge". They blunt the initial `Ca_micro` peak, protecting against excess CDI. They also slowly release Ca²⁺ back into the cytosol, which feeds the trace integrator more smoothly. Without buffers, the microdomain pulse is unrealistically sharp.
|
|
||||||
|
|
||||||
**Why CDI recovery closes a loop without itself.** The model already writes `CDI_factor` but never resets it. A VGCC that inactivated on spike N stays inactivated on spike N+1. CDI recovery is simply a decay back toward zero, with a time constant of \~100 ms, driven by Ca²⁺ falling (i.e., it depends on clearance — another reason clearance comes first).
|
|
||||||
|
|
||||||
**Why mGluR autoreceptors are needed.** The eCB pathway is a *retrograde* signal synthesized by the *postsynapse*. But the presynapse also has its own direct cleft-sensing system: presynaptic mGluR2/3 receptors bind glutamate in the cleft and suppress VGCC conductance and cAMP. This is a homosynaptic feedback loop that is entirely local to the presynapse and missing from the current model.
|
|
||||||
|
|
||||||
**Why pool guards matter.** The `refill_amount` calculation can produce `N_RP < 0` if `current_recruitment_rate * N_RP > N_RP`. The `N_RRP` overshoot is subtler but also real: if two slow-loop updates stack before the fast loop consumes RRP, you can exceed `Max_RRP`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Updated code, section by section
|
|
||||||
|
|
||||||
### Loop 1A — Ca²⁺ dynamics (replaces the current `Ca_micro +=` block)
|
|
||||||
|
|
||||||
```python
|
|
||||||
# --- PRESYNAPTIC Ca2+ DYNAMICS ---
|
|
||||||
|
|
||||||
if V_pre == 1: # AP arrives
|
|
||||||
effective_conductance = N_VGCC * (1 - eCB_level) * (1 - CDI_factor)
|
|
||||||
raw_influx = compute_flux(effective_conductance, V_pre_voltage)
|
|
||||||
|
|
||||||
# ADDED: Buffer proteins capture a fraction of influx immediately.
|
|
||||||
# Buffering capacity (B_free) depletes on capture, recovers slowly.
|
|
||||||
# VARIABLE: B_free – free buffer sites (calbindin/calmodulin)
|
|
||||||
# TIMING: rebinds saturated buffer in ~200 ms
|
|
||||||
captured = raw_influx * (B_free / B_total) # fraction caught
|
|
||||||
B_free = max(0, B_free - captured) # buffer saturates
|
|
||||||
Ca_micro += (raw_influx - captured) # only free Ca2+ counts
|
|
||||||
|
|
||||||
# --- ADDED: Ca2+ CLEARANCE (runs every ms, not just on spike) ---
|
|
||||||
# Three parallel mechanisms, each with its own rate constant:
|
|
||||||
# k_PMCA ~0.03 /ms (plasma membrane Ca-ATPase, ATP-dependent)
|
|
||||||
# k_NCX ~0.10 /ms (sodium-calcium exchanger, voltage-sensitive, fast)
|
|
||||||
# k_SERCA ~0.01 /ms (ER pump, slowest, fills internal Ca2+ store)
|
|
||||||
|
|
||||||
# ADDED: ATP gates pump speed — shared with metabolic loop below
|
|
||||||
pump_scale = compute_pump_atp_factor(ATP_level) # 0→1
|
|
||||||
|
|
||||||
cleared_PMCA = k_PMCA * Ca_micro * pump_scale
|
|
||||||
cleared_NCX = k_NCX * Ca_micro # NCX is not ATP-dependent
|
|
||||||
cleared_SERCA = k_SERCA * Ca_micro * pump_scale
|
|
||||||
|
|
||||||
Ca_micro -= (cleared_PMCA + cleared_NCX + cleared_SERCA)
|
|
||||||
Ca_micro = max(0.0, Ca_micro) # hard floor
|
|
||||||
|
|
||||||
# ADDED: SERCA fills an internal ER store (Ca_ER).
|
|
||||||
# This store can be released later (e.g. mGluR activation triggers IP3→ER release).
|
|
||||||
# For now it is simply a sink; ER-release can be wired later.
|
|
||||||
Ca_ER += cleared_SERCA
|
|
||||||
|
|
||||||
# ADDED: Buffer recharge — captured Ca2+ slowly re-releases back to cytosol,
|
|
||||||
# and free buffer sites recover as Ca2+ is extruded.
|
|
||||||
# TIMING: tau_buffer_rebind ~200 ms
|
|
||||||
Ca_micro += Ca_buffer_bound * dt / tau_buffer_rebind
|
|
||||||
Ca_buffer_bound *= (1 - dt / tau_buffer_rebind)
|
|
||||||
B_free = B_total - Ca_buffer_bound # bookkeeping
|
|
||||||
```
|
|
||||||
|
|
||||||
### Loop 1B — CDI recovery (adds a reset that was missing)
|
|
||||||
|
|
||||||
```python
|
|
||||||
# --- CDI INACTIVATION + RECOVERY ---
|
|
||||||
# EXISTING: CDI_factor rises with Ca_micro on each spike.
|
|
||||||
CDI_factor += map_calcium_to_inactivation(Ca_micro)
|
|
||||||
|
|
||||||
# ADDED: CDI_factor decays back to zero as Ca2+ is cleared.
|
|
||||||
# VARIABLE: tau_CDI_recovery ~100 ms
|
|
||||||
# LOGIC: Recovery tracks Ca_micro level — low Ca2+ → fast de-inactivation.
|
|
||||||
CDI_recovery_rate = k_CDI_rec * (1 - Ca_micro / Ca_micro_saturation)
|
|
||||||
CDI_factor = max(0.0, CDI_factor - CDI_recovery_rate * dt)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Loop 1C — Pool arithmetic with guards
|
|
||||||
|
|
||||||
```python
|
|
||||||
# --- RRP RELEASE (with hard cap) ---
|
|
||||||
if N_RRP > 0:
|
|
||||||
released_NT = stochastic_release(N_RRP, Ca_micro)
|
|
||||||
N_RRP = max(0, N_RRP - released_NT)
|
|
||||||
add_NT_to_cleft(released_NT)
|
|
||||||
|
|
||||||
# --- RP → RRP RECRUITMENT (with floor and ceiling guards) ---
|
|
||||||
current_recruitment_rate = map_trace_to_speed(Tr_Ca)
|
|
||||||
refill_amount = current_recruitment_rate * N_RP * (Max_RRP - N_RRP)
|
|
||||||
refill_amount = max(0.0, refill_amount) # ADDED: never negative
|
|
||||||
refill_amount = min(refill_amount, N_RP) # ADDED: can't take more than RP holds
|
|
||||||
|
|
||||||
N_RRP = min(N_RRP + refill_amount, Max_RRP) # ADDED: hard ceiling
|
|
||||||
N_RP = max(0.0, N_RP - refill_amount) # ADDED: hard floor
|
|
||||||
```
|
|
||||||
|
|
||||||
### Loop 2 — mGluR autoreceptor (new, 1 s loop)
|
|
||||||
|
|
||||||
```python
|
|
||||||
# --- ADDED: HOMOSYNAPTIC AUTORECEPTOR FEEDBACK ---
|
|
||||||
# VARIABLE: mGluR_activation – presynaptic mGluR2/3 occupancy (0→1)
|
|
||||||
# TIMING: rises in ~500 ms when NT_cleft is high, decays in ~2 s
|
|
||||||
# LOGIC: Directly reduces VGCC conductance AND suppresses cAMP
|
|
||||||
# (cAMP pathway gates RRP docking speed — can be added later).
|
|
||||||
# This loop is distinct from eCB: it is local, homosynaptic, and faster.
|
|
||||||
|
|
||||||
mGluR_activation += (NT_cleft / (NT_cleft + Km_mGluR) - mGluR_activation) * (dt_slow / tau_mGluR)
|
|
||||||
|
|
||||||
# The suppression factor enters the high-freq loop at Line 1A:
|
|
||||||
# effective_conductance = N_VGCC * (1 - eCB_level) * (1 - CDI_factor) * (1 - mGluR_activation * alpha_mGluR)
|
|
||||||
#
|
|
||||||
# alpha_mGluR: max fractional suppression (~0.4 for mGluR2/3 at physiological concentrations)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Loop 3 — ATP dependency on pumps (links metabolic health to Ca²⁺ clearance)
|
|
||||||
|
|
||||||
```python
|
|
||||||
# --- ADDED: ATP GATES CA2+ PUMP SPEED ---
|
|
||||||
# VARIABLE: ATP_level – normalized 0→1 (computed from astrocyte metabolic health)
|
|
||||||
# LOGIC: PMCA and SERCA are ATP-dependent.
|
|
||||||
# When ATP_level drops, Ca2+ clearance slows → Ca_micro stays elevated →
|
|
||||||
# CDI rises → effective VGCC conductance collapses → synapse silences.
|
|
||||||
# This is the realistic metabolic-silence cascade.
|
|
||||||
|
|
||||||
def compute_pump_atp_factor(ATP_level):
|
|
||||||
# Hill function: half-maximal at ATP_half = 0.3
|
|
||||||
return ATP_level**2 / (ATP_level**2 + ATP_half**2)
|
|
||||||
|
|
||||||
# The slowest metabolic loop already writes ATP_level via compute_astrocyte_metabolic_health().
|
|
||||||
# No further wiring needed — pump_scale above picks it up automatically.
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## The closed loop, stated plainly
|
|
||||||
|
|
||||||
Every Ca²⁺ that enters now has exactly one exit: PMCA, NCX, or SERCA. Buffers slow the peak. CDI rises with Ca²⁺ and falls as Ca²⁺ falls — it can no longer lock permanently. The cleft-sensing mGluR autoreceptor gives the presynapse its own, faster brake independent of the postsynapse. Pool arithmetic is bounded on both ends. And ATP depletion now cascades naturally: less ATP → slower pumps → higher residual Ca²⁺ → more CDI → fewer effective VGCCs → silence — which is precisely the metabolic-fatigue endpoint the deep loop was trying to express but couldn't reach without the pump link.
|
|
||||||
@@ -0,0 +1,205 @@
|
|||||||
|
```
|
||||||
|
BEH-AXO.md
|
||||||
|
BEH-AXO: Container
|
||||||
|
|
||||||
|
BEH-PRE: Container
|
||||||
|
[as previously defined]
|
||||||
|
|
||||||
|
BEH-POST: Container
|
||||||
|
|
||||||
|
ms: behaviors
|
||||||
|
|
||||||
|
POST-NTContext: Context
|
||||||
|
— NT_cleft level arriving from presynapse
|
||||||
|
— Desensitization_level of receptors at this moment
|
||||||
|
— these two together determine effective NT binding
|
||||||
|
|
||||||
|
NTDetection
|
||||||
|
NTDetectionMaximum: Episode
|
||||||
|
— NT_cleft full, Desensitization_level empty
|
||||||
|
— all receptors available, full NT signal
|
||||||
|
— receptor_conductance rises steeply
|
||||||
|
NTDetectionHigh: Episode
|
||||||
|
— NT_cleft full, Desensitization_level medium OR
|
||||||
|
— NT_cleft medium, Desensitization_level empty
|
||||||
|
— strong response, partially attenuated
|
||||||
|
NTDetectionMedium: Episode
|
||||||
|
— NT_cleft medium, Desensitization_level medium OR
|
||||||
|
— NT_cleft low, Desensitization_level empty
|
||||||
|
— moderate response
|
||||||
|
NTDetectionLow: Episode
|
||||||
|
— NT_cleft low, Desensitization_level medium OR
|
||||||
|
— NT_cleft medium, Desensitization_level full
|
||||||
|
— weak response, most receptors deaf
|
||||||
|
NTDetectionNone: Episode
|
||||||
|
— NT_cleft empty OR
|
||||||
|
— Desensitization_level full
|
||||||
|
— no effective binding regardless of NT
|
||||||
|
|
||||||
|
ReceptorDesensitization
|
||||||
|
DesensitizationRising: Episode
|
||||||
|
— NT_cleft sustained high
|
||||||
|
— receptors accumulate closed state each ms
|
||||||
|
— attenuates subsequent NTDetection episodes
|
||||||
|
DesensitizationRecovering: Episode
|
||||||
|
— NT_cleft low or empty
|
||||||
|
— receptors recover availability passively
|
||||||
|
— rate governed by tau_desensitization = 500 ms
|
||||||
|
|
||||||
|
VpostDecay
|
||||||
|
VpostDecayActive: Episode
|
||||||
|
— receptor_conductance non-zero
|
||||||
|
— V_post sustained by ongoing NT binding
|
||||||
|
VpostDecayPassive: Episode
|
||||||
|
— receptor_conductance near zero
|
||||||
|
— V_post decays with tau_post_membrane = 20 ms
|
||||||
|
— inter-burst silence
|
||||||
|
|
||||||
|
POST-Ca2+Context: Context
|
||||||
|
— V_post level (sets Mg block removal)
|
||||||
|
— NT_cleft level (ligand gate for NMDA)
|
||||||
|
— together these determine NMDA opening
|
||||||
|
— coincidence required: both must be non-zero for Ca_post to rise
|
||||||
|
|
||||||
|
NMDACoincidence
|
||||||
|
NMDACoincidenceMaximum: Episode
|
||||||
|
— NT_cleft full AND V_post full
|
||||||
|
— Mg block fully lifted, NMDA wide open
|
||||||
|
— Ca_post surges — LTP territory
|
||||||
|
NMDACoincidenceHigh: Episode
|
||||||
|
— NT_cleft full AND V_post medium OR
|
||||||
|
— NT_cleft medium AND V_post full
|
||||||
|
— strong Ca_post rise
|
||||||
|
NMDACoincidenceMedium: Episode
|
||||||
|
— NT_cleft medium AND V_post medium
|
||||||
|
— moderate Ca_post rise — LTP/LTD boundary zone
|
||||||
|
NMDACoincidenceLow: Episode
|
||||||
|
— NT_cleft low OR V_post low (but not both empty)
|
||||||
|
— weak Ca_post rise — LTD territory
|
||||||
|
NMDACoincidenceNone: Episode
|
||||||
|
— NT_cleft empty OR V_post empty
|
||||||
|
— one gate closed — Ca_post does not rise
|
||||||
|
— this is the hard gate: a single missing condition blocks all entry
|
||||||
|
|
||||||
|
CaPostClearance
|
||||||
|
CaPostClearanceHigh: Episode
|
||||||
|
— ATP_level_post full
|
||||||
|
— pump_scale_post near 1
|
||||||
|
— PMCA running at full rate + NCX
|
||||||
|
— Ca_post returns to baseline rapidly between events
|
||||||
|
CaPostClearanceMedium: Episode
|
||||||
|
— ATP_level_post medium
|
||||||
|
— pump_scale_post reduced
|
||||||
|
— Ca_post clears more slowly
|
||||||
|
— residual elevation between coincidence events
|
||||||
|
CaPostClearanceLow: Episode
|
||||||
|
— ATP_level_post low
|
||||||
|
— pump_scale_post near 0
|
||||||
|
— only NCX clearing (floor, not rescue)
|
||||||
|
— Ca_post accumulates across events
|
||||||
|
— eCB threshold approached without genuine coincidence
|
||||||
|
— excitotoxicity risk zone
|
||||||
|
|
||||||
|
ATPcostPost
|
||||||
|
— charged every ms:
|
||||||
|
NKA recharge proportional to V_post level
|
||||||
|
PMCA cost proportional to cleared_Ca_post_pump
|
||||||
|
— feeds ATP_demand_post accumulator
|
||||||
|
— reset in Loop 3
|
||||||
|
|
||||||
|
sec: behaviors
|
||||||
|
|
||||||
|
POST-SecContext: Context
|
||||||
|
— Ca_post history over past 2 s (mean of log)
|
||||||
|
— determines whether eCB synthesis threshold is crossed
|
||||||
|
— note: driven by Ca_post, not V_post
|
||||||
|
— ATP failure can push Ca_post above threshold
|
||||||
|
— without genuine coincidence (false retrograde signal)
|
||||||
|
|
||||||
|
eCBSynthesis
|
||||||
|
eCBSynthesisActive: Episode
|
||||||
|
— recent_Ca_post > eCB_threshold (0.7)
|
||||||
|
— eCB synthesised and released retrogradely
|
||||||
|
— eCB_level rises with tau_eCB_rise = 2000 ms
|
||||||
|
— suppresses presynaptic VGCCs via effective_conductance
|
||||||
|
— genuine trigger: sustained NMDA coincidence (overactivity)
|
||||||
|
— false trigger: Ca_post elevated by pump failure (ATP low)
|
||||||
|
eCBSynthesisInactive: Episode
|
||||||
|
— recent_Ca_post < eCB_threshold
|
||||||
|
— eCB_level decays with tau_eCB_decay = 10000 ms
|
||||||
|
— presynaptic suppression gradually lifts
|
||||||
|
|
||||||
|
min: behaviors
|
||||||
|
|
||||||
|
POST-MinContext: Context
|
||||||
|
— Glucose_level (shared with presynapse)
|
||||||
|
— ATP_demand_post accumulated since last cycle
|
||||||
|
— both sides draw from same astrocyte glucose budget
|
||||||
|
|
||||||
|
ATPreplenishment
|
||||||
|
— compute_astrocyte_metabolic_health(Glucose_level, ATP_demand_post)
|
||||||
|
— produces ATP_level_post for next metabolic window
|
||||||
|
— ATP_demand_post resets to zero
|
||||||
|
— when Glucose_level low: both ATP_level and ATP_level_post fall
|
||||||
|
— presynaptic silence (CDI lock-out) reduces NT release
|
||||||
|
— reduced NT reduces NMDA activation
|
||||||
|
— reduced Ca_post reduces ATP_demand_post
|
||||||
|
— presynaptic silence indirectly protects postsynaptic ATP
|
||||||
|
|
||||||
|
BEH-POST-RECEPTOR: Container
|
||||||
|
|
||||||
|
ms: behavior Receptors
|
||||||
|
|
||||||
|
ReceptorOccupancy
|
||||||
|
ReceptorOccupancyFull: Episode
|
||||||
|
— NT_cleft full, Desensitization_level empty
|
||||||
|
— maximum conductance, V_post rising steeply
|
||||||
|
ReceptorOccupancyReduced: Episode
|
||||||
|
— NT_cleft medium OR Desensitization_level medium
|
||||||
|
— partial conductance
|
||||||
|
ReceptorOccupancyPartial: Episode
|
||||||
|
— NT_cleft low OR Desensitization_level high
|
||||||
|
— weak conductance
|
||||||
|
ReceptorOccupancySuppressed: Episode
|
||||||
|
— NT_cleft low AND Desensitization_level high
|
||||||
|
— near-zero conductance despite NT present
|
||||||
|
ReceptorOccupancyClosed: Episode
|
||||||
|
— NT_cleft empty OR Desensitization_level full
|
||||||
|
— no conductance
|
||||||
|
|
||||||
|
BEH-POST-NMDA: Container
|
||||||
|
|
||||||
|
ms: behavior NMDA coincidence gate
|
||||||
|
|
||||||
|
NMDAgate
|
||||||
|
NMDAgateFull: Episode
|
||||||
|
— NT_cleft full AND V_post full
|
||||||
|
— Mg_block_removal near 1
|
||||||
|
— Ca_post surges maximally
|
||||||
|
NMDAgatReduced: Episode
|
||||||
|
— one condition full, other medium
|
||||||
|
— partial Mg block removal
|
||||||
|
— Ca_post rises moderately
|
||||||
|
NMDAgatPartial: Episode
|
||||||
|
— both conditions medium
|
||||||
|
— Mg block partially lifted
|
||||||
|
— Ca_post rises weakly
|
||||||
|
NMDAgateSuppressed: Episode
|
||||||
|
— one condition low, other any
|
||||||
|
— Mg block mostly intact
|
||||||
|
— Ca_post minimal rise
|
||||||
|
NMDAgateClosed: Episode
|
||||||
|
— either NT_cleft empty OR V_post empty
|
||||||
|
— hard gate closed
|
||||||
|
— Ca_post does not rise
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Three structural notes on how this mirrors the presynaptic taxonomy.
|
||||||
|
|
||||||
|
`BEH-POST-NMDA` is the postsynaptic equivalent of `BEH-PRE-VGCC`. Both are containers for a gated calcium entry mechanism. The difference is the gating logic: VGCC is gated by CDI, eCB, and mGluR (three suppressors multiplying together); NMDA is gated by a coincidence requirement (two conditions both required). VGCC can be suppressed by any one of its three brakes acting alone. NMDA can only be blocked by the absence of either NT or depolarisation — a fundamentally different logical structure, AND versus (1 - factor).
|
||||||
|
|
||||||
|
`NMDACoincidenceNone` is a hard gate in the same sense that `N_RRP = empty` was a hard gate in the NT release table. One missing condition alone is sufficient to prevent all Ca_post entry regardless of the other variable. This makes the postsynaptic calcium system more binary than the presynaptic one — there is no equivalent of the graded suppression that CDI or eCB provide.
|
||||||
|
|
||||||
|
`eCBSynthesisActive` has two distinct biological meanings depending on what is driving Ca_post — genuine overactivity (NMDA coincidence) versus pump failure (ATP depleted). The episode is the same computational event but with opposite implications for whether the retrograde signal is appropriate. This is the only place in the entire model where the same behavior has two different biological interpretations, and it is worth flagging explicitly in any documentation.
|
||||||
@@ -0,0 +1,690 @@
|
|||||||
|
# Tripartite Synapse - Multi-Scale Computational Model
|
||||||
|
# =====================================================
|
||||||
|
# Presynaptic + Postsynaptic perspectives, fully integrated.
|
||||||
|
#
|
||||||
|
# Change log:
|
||||||
|
# ORIG - present from the original document
|
||||||
|
# NEW - added in the missing-behavior integration pass
|
||||||
|
# DET - deterministic Ca2+-driven vesicle release
|
||||||
|
# NKA - explicit Na/K-ATPase V_pre decay and ATP cost
|
||||||
|
# POST-ATP - postsynaptic Ca2+ dynamics and ATP loop
|
||||||
|
# FIX - corrections applied in this pass:
|
||||||
|
# * NT_released_this_window accumulator (was missing entirely)
|
||||||
|
# * k_rec_fast / k_rec_slow converted to /s, recruitment moved to Loop 2
|
||||||
|
# * dt_slow_s added
|
||||||
|
# * mGluR now reads NT_released_this_window (not NT_cleft snapshot)
|
||||||
|
# * IP3 now reads NT_released_this_window (not cleared_NT residual)
|
||||||
|
# * wave_active flag + conversion_efficiency boost on astrocyte wave
|
||||||
|
# * CDI rise gated to spike window only
|
||||||
|
#
|
||||||
|
# Clock structure:
|
||||||
|
# Loop 1 - dt = 1 ms (Ca2+, vesicle release, traces, postsynaptic fast)
|
||||||
|
# Loop 2 - dt = 1000 ms (astrocyte clearance, eCB, mGluR, recruitment)
|
||||||
|
# Loop 3 - dt = 60000 ms (glutamine shuttle, metabolic health)
|
||||||
|
#
|
||||||
|
# =======================================================================
|
||||||
|
# THREE CLOSED LOOPS
|
||||||
|
# =======================================================================
|
||||||
|
#
|
||||||
|
# PRESYNAPTIC:
|
||||||
|
# NT loop : release (ms) -> cleft -> astrocyte clearance (s) ->
|
||||||
|
# glutamine shuttle (min) -> RP refill -> RRP -> release
|
||||||
|
# Ca2+ loop : VGCC influx (ms) -> Tr_Ca -> recruitment speed (s) ->
|
||||||
|
# eCB retrograde from post (s) -> VGCC suppression
|
||||||
|
# ATP loop : NKA + pump costs (ms) -> ATP_demand (min) -> ATP_level ->
|
||||||
|
# pump_scale -> Ca2+ clearance rate -> CDI recovery
|
||||||
|
#
|
||||||
|
# POSTSYNAPTIC:
|
||||||
|
# NT detection loop : NT_cleft -> AMPA -> V_post -> desensitization ->
|
||||||
|
# reduces next response
|
||||||
|
# Ca2+ coincidence : NMDA (NT + V_post) -> Ca_post -> eCB -> pre brake
|
||||||
|
# ATP loop : NKA + PMCA costs (ms) -> ATP_demand_post (min) ->
|
||||||
|
# ATP_level_post -> pump_scale_post -> Ca_post clearance
|
||||||
|
#
|
||||||
|
# SHARED:
|
||||||
|
# eCB_level : post synthesises -> pre reads (retrograde brake)
|
||||||
|
# NT_cleft : pre releases -> post detects -> astrocyte clears
|
||||||
|
# Glucose_level : astrocyte supplies both sides from same budget
|
||||||
|
#
|
||||||
|
# =======================================================================
|
||||||
|
# METABOLIC SILENCING CASCADE (presynaptic)
|
||||||
|
# =======================================================================
|
||||||
|
# [CASCADE 1] HIGH FIRING -> VESICLE DEPLETION (~seconds)
|
||||||
|
# release rate >> recruitment rate -> N_RRP -> 0
|
||||||
|
# [CASCADE 2] HIGH FIRING -> ATP DEPLETION (~minutes)
|
||||||
|
# NKA + PMCA + docking demand > glucose-driven supply
|
||||||
|
# [CASCADE 3] LOW ATP -> PUMP FAILURE
|
||||||
|
# pump_scale = Hill(ATP_level) -> cleared_PMCA/SERCA fall
|
||||||
|
# [CASCADE 4] PUMP FAILURE -> RESIDUAL Ca2+ STAYS HIGH
|
||||||
|
# Ca_micro persists between spikes
|
||||||
|
# [CASCADE 5] RESIDUAL Ca2+ -> CDI LOCKS VGCCs SHUT
|
||||||
|
# CDI rise (spike only) + recovery blocked by Ca2+ -> CDI -> 1
|
||||||
|
# [CASCADE 6] SYNAPSE SILENCES (excitotoxicity protection)
|
||||||
|
# effective_conductance = N_VGCC*(1-eCB)*(1-CDI)*(1-mGluR*alpha)
|
||||||
|
# -> 0; NCX auto-reset when drive stops
|
||||||
|
#
|
||||||
|
# POSTSYNAPTIC ATP CASCADE (no CDI equivalent -> dangerous):
|
||||||
|
# [POST-ATP 1] HIGH V_post + NMDA -> ATP_demand_post rises
|
||||||
|
# [POST-ATP 2] ATP_level_post falls -> pump_scale_post falls
|
||||||
|
# [POST-ATP 3] Ca_post clearance slows -> Ca_post stays elevated
|
||||||
|
# [POST-ATP 4] Ca_post > eCB_threshold without real coincidence
|
||||||
|
# -> false retrograde signal suppresses presynapse
|
||||||
|
# [POST-ATP 5] Critically low ATP_post -> runaway Ca_post -> excitotoxicity
|
||||||
|
# =======================================================================
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# CLOCK
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
dt = 1.0 # ms
|
||||||
|
dt_slow = 1000.0 # ms
|
||||||
|
dt_meta = 60_000.0 # ms
|
||||||
|
|
||||||
|
High_Freq_Multiplier = int(dt_slow / dt) # 1000
|
||||||
|
Metabolic_Multiplier = int(dt_meta / dt) # 60000
|
||||||
|
|
||||||
|
dt_s = dt / 1000.0 # 0.001 s/step - for /s rate constants in Loop 1
|
||||||
|
dt_slow_s = dt_slow / 1000.0 # 1.0 s/step - for /s rate constants in Loop 2
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# PRESYNAPTIC PARAMETERS
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
# -- Voltage / membrane --
|
||||||
|
tau_V_pre = 2.0 # ms - AP waveform decay (Na/K-ATPase recharge)
|
||||||
|
V_pre_peak = 1.0 # a.u. - normalised AP peak
|
||||||
|
V_rest = 0.0 # a.u. - resting potential
|
||||||
|
V_pre_voltage = -10.0 # mV - driving force for compute_flux
|
||||||
|
|
||||||
|
NKA_cost_per_AP = 0.002 # ATP units per AP (dominant drain at high rates)
|
||||||
|
|
||||||
|
# -- Ca2+ influx & buffering --
|
||||||
|
N_VGCC = 100 # number of VGCCs (ceiling of effective_conductance)
|
||||||
|
k_flux = 0.05 # Ca2+ influx per open channel per unit driving force
|
||||||
|
B_total = 1.0 # total buffer capacity (normalised)
|
||||||
|
tau_buffer_rebind = 200.0 # ms - buffer recharge time constant
|
||||||
|
|
||||||
|
# -- Ca2+ clearance (/ms constants) --
|
||||||
|
k_PMCA = 0.03 # ATP-dependent primary pump
|
||||||
|
k_NCX = 0.10 # ATP-independent floor
|
||||||
|
k_SERCA = 0.01 # ATP-dependent ER pump
|
||||||
|
ATP_half = 0.3 # Hill half-saturation for presynaptic pumps
|
||||||
|
|
||||||
|
ATP_cost_PMCA = 0.0005 # ATP per unit Ca2+ extruded by PMCA
|
||||||
|
ATP_cost_SERCA = 0.0002 # ATP per unit Ca2+ pumped into ER
|
||||||
|
ATP_cost_docking = 0.001 # ATP per vesicle docked (RP->RRP)
|
||||||
|
|
||||||
|
# -- Deterministic release (Hill + NT suppression) --
|
||||||
|
k_rel = 0.5 # max releasable fraction of RRP per spike
|
||||||
|
KD_rel = 1.0 # half-saturation [Ca2+]
|
||||||
|
n_rel = 4 # Hill cooperativity (synaptotagmin-1)
|
||||||
|
NT_suppression_weight = 0.3 # max NT_cleft brake on release fraction
|
||||||
|
NT_suppression_sat = 50.0 # NT_cleft level that saturates suppression
|
||||||
|
|
||||||
|
# -- CDI --
|
||||||
|
k_CDI_rise = 0.8 # /s - CDI build rate (applied * dt_s, spike only)
|
||||||
|
Ca_micro_saturation = 2.0 # normalisation ceiling for CDI recovery
|
||||||
|
k_CDI_rec = 0.015 # /s - CDI de-inactivation rate (applied * dt_s)
|
||||||
|
|
||||||
|
# -- Vesicle pools --
|
||||||
|
Max_RRP = 20
|
||||||
|
Max_RP = 200
|
||||||
|
|
||||||
|
# -- Calcium trace --
|
||||||
|
tau_Tr_Ca = 1000.0 # ms
|
||||||
|
T_high = 0.6 # Tr_Ca threshold -> fast recruitment
|
||||||
|
T_low = 0.2 # Tr_Ca threshold -> slow recruitment
|
||||||
|
|
||||||
|
# -- RP->RRP recruitment (/s, runs in Loop 2) --
|
||||||
|
k_rec_fast = 5.0 # /s - fast recruitment (at Tr_Ca > T_high)
|
||||||
|
k_rec_slow = 0.5 # /s - slow recruitment (at Tr_Ca < T_low)
|
||||||
|
|
||||||
|
# -- NT accumulator for Loop 2 signals --
|
||||||
|
NT_window_sat = 40.0 # vesicles/s that saturates mGluR and IP3
|
||||||
|
# at 20 Hz releasing ~2/spike = 40/s
|
||||||
|
|
||||||
|
# -- eCB retrograde brake --
|
||||||
|
tau_eCB_rise = 2000.0
|
||||||
|
tau_eCB_decay = 10_000.0
|
||||||
|
eCB_threshold = 0.7 # Ca_post level that triggers eCB synthesis
|
||||||
|
|
||||||
|
# -- mGluR presynaptic autoreceptor --
|
||||||
|
Km_mGluR = 0.5
|
||||||
|
tau_mGluR = 2000.0 # ms
|
||||||
|
alpha_mGluR = 0.4 # max fractional VGCC suppression
|
||||||
|
|
||||||
|
# -- Astrocyte / IP3 --
|
||||||
|
tau_IP3 = 3000.0 # ms
|
||||||
|
IP3_threshold = 0.8
|
||||||
|
wave_boost = 0.2 # conversion_efficiency boost when wave fires
|
||||||
|
tau_wave_decay = 2 # metabolic cycles before boost decays back
|
||||||
|
|
||||||
|
# -- Glutamine shuttle --
|
||||||
|
conversion_efficiency_base = 0.8
|
||||||
|
|
||||||
|
# -- NT cleft --
|
||||||
|
tau_NT_decay = 5.0 # ms
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# POSTSYNAPTIC PARAMETERS
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
# -- NMDA coincidence detection --
|
||||||
|
k_NMDA = 0.08 # Ca_post influx per unit NT * (1 - Mg_block) per ms
|
||||||
|
V_NMDA_half = 0.3 # V_post at which Mg block is 50% lifted
|
||||||
|
|
||||||
|
# -- Ca_post clearance --
|
||||||
|
k_Ca_post_clear = 0.05 # /ms - ATP-dependent PMCA in spine
|
||||||
|
k_Ca_post_NCX = 0.02 # /ms - ATP-independent NCX floor
|
||||||
|
ATP_half_post = 0.3 # Hill half-saturation for postsynaptic pumps
|
||||||
|
|
||||||
|
# -- Postsynaptic ATP costs --
|
||||||
|
NKA_cost_per_bAP_post = 0.002 # ATP per unit V_post per s (continuous)
|
||||||
|
ATP_cost_Ca_post_pump = 0.0005 # ATP per unit Ca_post cleared
|
||||||
|
ATP_demand_scale_post = 50.0 # normalisation (same as presynaptic)
|
||||||
|
|
||||||
|
# -- Receptor desensitization --
|
||||||
|
tau_membrane = 20.0 # ms
|
||||||
|
tau_desensitization = 500.0 # ms
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# HELPER FUNCTIONS
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
def compute_flux(conductance, voltage):
|
||||||
|
return k_flux * conductance * abs(voltage)
|
||||||
|
|
||||||
|
|
||||||
|
def deterministic_release(N_RRP, Ca_micro, NT_cleft):
|
||||||
|
# Hill equation: Ca2+ sensor cooperativity (synaptotagmin-1, n=4)
|
||||||
|
Ca_n = Ca_micro ** n_rel
|
||||||
|
release_frac = k_rel * Ca_n / (Ca_n + KD_rel ** n_rel)
|
||||||
|
# NT suppression: physical crowding + fast local autoreceptors
|
||||||
|
NT_norm = min(1.0, NT_cleft / NT_suppression_sat)
|
||||||
|
release_frac = release_frac * (1.0 - NT_suppression_weight * NT_norm)
|
||||||
|
release_frac = np.clip(release_frac, 0.0, 1.0)
|
||||||
|
return max(0.0, release_frac * N_RRP)
|
||||||
|
|
||||||
|
|
||||||
|
def map_trace_to_speed(Tr_Ca):
|
||||||
|
# Returns /s recruitment rate based on Tr_Ca level
|
||||||
|
if Tr_Ca > T_high:
|
||||||
|
return k_rec_fast
|
||||||
|
elif Tr_Ca < T_low:
|
||||||
|
return k_rec_slow
|
||||||
|
else:
|
||||||
|
t = (Tr_Ca - T_low) / (T_high - T_low)
|
||||||
|
return k_rec_slow + t * (k_rec_fast - k_rec_slow)
|
||||||
|
|
||||||
|
|
||||||
|
def compute_pump_atp_factor(atp, atp_half):
|
||||||
|
# Hill function: ATP gates pump speed (shared by pre and post)
|
||||||
|
return (atp ** 2) / (atp ** 2 + atp_half ** 2)
|
||||||
|
|
||||||
|
|
||||||
|
def compute_EPSP(receptor_conductance):
|
||||||
|
return receptor_conductance * 0.1
|
||||||
|
|
||||||
|
|
||||||
|
def compute_astrocyte_metabolic_health(Glucose_level, ATP_demand_accumulated,
|
||||||
|
demand_scale=50.0):
|
||||||
|
# Converts glucose supply and accumulated demand into ATP_level (0->1)
|
||||||
|
# and conversion_efficiency (0->1). Both sides use this function with
|
||||||
|
# their own demand accumulators but the same Glucose_level — shared
|
||||||
|
# metabolic vulnerability.
|
||||||
|
health = np.clip(Glucose_level - ATP_demand_accumulated / demand_scale,
|
||||||
|
0.0, 1.0)
|
||||||
|
return health, health # (conversion_efficiency, ATP_level)
|
||||||
|
|
||||||
|
|
||||||
|
def trigger_slow_astrocyte_calcium_wave():
|
||||||
|
# Placeholder - gliotransmitter release over ~10 s
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# STATE VARIABLES
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
# -- Presynaptic membrane --
|
||||||
|
V_pre_state = 0.0
|
||||||
|
|
||||||
|
# -- Presynaptic Ca2+ --
|
||||||
|
Ca_micro = 0.0
|
||||||
|
Ca_ER = 0.5
|
||||||
|
Ca_buffer_bound = 0.0
|
||||||
|
B_free = B_total
|
||||||
|
|
||||||
|
# -- CDI --
|
||||||
|
CDI_factor = 0.0
|
||||||
|
|
||||||
|
# -- Vesicle pools --
|
||||||
|
N_RRP = 15.0
|
||||||
|
N_RP = 150.0
|
||||||
|
|
||||||
|
# -- Calcium trace --
|
||||||
|
Tr_Ca = 0.0
|
||||||
|
|
||||||
|
# -- NT cleft --
|
||||||
|
NT_cleft = 0.0
|
||||||
|
|
||||||
|
# -- NT accumulator for slow signals --
|
||||||
|
# FIX: this was missing. Accumulates every ms in Loop 1,
|
||||||
|
# consumed by mGluR and IP3 in Loop 2, reset each second.
|
||||||
|
NT_released_this_window = 0.0
|
||||||
|
|
||||||
|
# -- Postsynaptic membrane + receptors --
|
||||||
|
V_post = 0.0
|
||||||
|
receptor_conductance = 0.0
|
||||||
|
Desensitization_level = 0.0
|
||||||
|
V_post_history = []
|
||||||
|
|
||||||
|
# -- Postsynaptic Ca2+ (spine compartment) --
|
||||||
|
Ca_post = 0.0
|
||||||
|
# Driven by NMDA coincidence (NT + V_post). Cleared by PMCA (ATP-gated)
|
||||||
|
# and NCX (always). Drives eCB synthesis. No CDI equivalent ->
|
||||||
|
# elevated Ca_post under ATP failure has no self-limiting mechanism.
|
||||||
|
|
||||||
|
# -- Retrograde / autoreceptor --
|
||||||
|
eCB_level = 0.0
|
||||||
|
mGluR_activation = 0.0
|
||||||
|
|
||||||
|
# -- Astrocyte --
|
||||||
|
IP3 = 0.0
|
||||||
|
wave_active = 0 # countdown: cycles remaining of wave boost
|
||||||
|
Glutamine_pool = 50.0
|
||||||
|
|
||||||
|
# -- Presynaptic ATP --
|
||||||
|
ATP_level = 1.0
|
||||||
|
ATP_demand = 0.0
|
||||||
|
conversion_efficiency = conversion_efficiency_base
|
||||||
|
Glucose_level = 1.0 # set < 1.0 to engage metabolic silencing
|
||||||
|
|
||||||
|
# -- Postsynaptic ATP --
|
||||||
|
ATP_level_post = 1.0 # separate pool; same glucose budget as presynaptic
|
||||||
|
ATP_demand_post = 0.0 # accumulates from NKA (V_post) and PMCA (Ca_post)
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# MAIN SIMULATION LOOP
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
def run_simulation(spike_train, total_steps, bAP_train=None):
|
||||||
|
"""
|
||||||
|
spike_train : list of int - presynaptic AP timestep indices
|
||||||
|
total_steps : int
|
||||||
|
bAP_train : list of int - postsynaptic bAP timestep indices (optional)
|
||||||
|
if None, no bAPs are delivered
|
||||||
|
"""
|
||||||
|
|
||||||
|
global V_pre_state
|
||||||
|
global Ca_micro, Ca_ER, Ca_buffer_bound, B_free
|
||||||
|
global CDI_factor
|
||||||
|
global N_RRP, N_RP, Tr_Ca, NT_cleft, NT_released_this_window
|
||||||
|
global V_post, receptor_conductance, Desensitization_level, V_post_history
|
||||||
|
global Ca_post
|
||||||
|
global eCB_level, mGluR_activation
|
||||||
|
global IP3, wave_active, Glutamine_pool
|
||||||
|
global ATP_level, ATP_demand, conversion_efficiency, Glucose_level
|
||||||
|
global ATP_level_post, ATP_demand_post
|
||||||
|
|
||||||
|
log = {k: [] for k in [
|
||||||
|
"V_pre_state", "Ca_micro", "Ca_ER", "CDI_factor", "B_free",
|
||||||
|
"N_RRP", "N_RP", "Tr_Ca", "NT_cleft",
|
||||||
|
"V_post", "Ca_post", "eCB_level", "mGluR_activation",
|
||||||
|
"released_NT", "ATP_level", "ATP_demand",
|
||||||
|
"ATP_level_post", "ATP_demand_post",
|
||||||
|
]}
|
||||||
|
|
||||||
|
spike_set = set(spike_train)
|
||||||
|
bAP_set = set(bAP_train) if bAP_train else set()
|
||||||
|
|
||||||
|
for step in range(total_steps):
|
||||||
|
|
||||||
|
# ==============================================================
|
||||||
|
# LOOP 1 — HIGH-FREQUENCY (dt = 1 ms)
|
||||||
|
# ==============================================================
|
||||||
|
|
||||||
|
V_pre = 1 if step in spike_set else 0
|
||||||
|
bAP = 1 if step in bAP_set else 0
|
||||||
|
released_NT = 0.0
|
||||||
|
|
||||||
|
# -- 1A. PRESYNAPTIC MEMBRANE / Na-K-ATPase -------------------
|
||||||
|
# AP fires: membrane jumps to peak, then decays with tau_V_pre.
|
||||||
|
# Ca2+ influx uses V_pre_state (continuous) not binary V_pre,
|
||||||
|
# giving a temporal influx profile that tapers as membrane repolarises.
|
||||||
|
if V_pre == 1:
|
||||||
|
V_pre_state = V_pre_peak
|
||||||
|
ATP_demand += NKA_cost_per_AP # dominant presynaptic ATP cost
|
||||||
|
|
||||||
|
V_pre_state += (V_rest - V_pre_state) * dt / tau_V_pre
|
||||||
|
|
||||||
|
# -- 1B. PRESYNAPTIC Ca2+ INFLUX ------------------------------
|
||||||
|
# Three multiplicative brakes on effective_conductance:
|
||||||
|
# eCB_level : retrograde brake from postsynapse (Loop 2)
|
||||||
|
# CDI_factor : Ca2+-dependent inactivation (below)
|
||||||
|
# mGluR_activation : autoreceptor brake (Loop 2)
|
||||||
|
effective_conductance = (
|
||||||
|
N_VGCC
|
||||||
|
* (1.0 - eCB_level)
|
||||||
|
* (1.0 - CDI_factor)
|
||||||
|
* (1.0 - mGluR_activation * alpha_mGluR)
|
||||||
|
)
|
||||||
|
raw_influx = compute_flux(effective_conductance, V_pre_state)
|
||||||
|
|
||||||
|
# Buffer proteins capture a fraction immediately (fast sponge).
|
||||||
|
# B_free -> 0 during sustained bursting -> capture_fraction -> 0
|
||||||
|
# -> full raw_influx enters Ca_micro (CASCADE 4 acceleration).
|
||||||
|
capture_fraction = B_free / B_total
|
||||||
|
captured = raw_influx * capture_fraction
|
||||||
|
B_free = max(0.0, B_free - captured)
|
||||||
|
Ca_buffer_bound += captured
|
||||||
|
Ca_micro += (raw_influx - captured)
|
||||||
|
|
||||||
|
# -- 1C. VESICLE RELEASE --------------------------------------
|
||||||
|
# Deterministic: Hill Ca2+ sensor * NT suppression * N_RRP.
|
||||||
|
# Runs every ms that Ca_micro > 0 (release profile follows Ca2+
|
||||||
|
# transient, not locked to spike flag).
|
||||||
|
if N_RRP > 0 and Ca_micro > 0:
|
||||||
|
released_NT = deterministic_release(N_RRP, Ca_micro, NT_cleft)
|
||||||
|
released_NT = min(released_NT, N_RRP)
|
||||||
|
N_RRP -= released_NT
|
||||||
|
NT_cleft += released_NT
|
||||||
|
# FIX: accumulate for Loop 2 mGluR and IP3 signals.
|
||||||
|
# This is the only correct way to feed slow signals from fast
|
||||||
|
# events — snapshot of NT_cleft at Loop 2 time would be ~0
|
||||||
|
# because passive diffusion has already cleared it.
|
||||||
|
NT_released_this_window += released_NT
|
||||||
|
|
||||||
|
# Passive NT diffusion out of cleft each ms.
|
||||||
|
NT_cleft *= (1.0 - dt / tau_NT_decay)
|
||||||
|
NT_cleft = max(0.0, NT_cleft)
|
||||||
|
|
||||||
|
# -- 1D. PRESYNAPTIC Ca2+ CLEARANCE ---------------------------
|
||||||
|
# pump_scale: Hill(ATP_level) — bridges Loop 3 ATP to Loop 1 clearance.
|
||||||
|
# NCX is ATP-independent (floor); PMCA and SERCA are ATP-gated.
|
||||||
|
pump_scale = compute_pump_atp_factor(ATP_level, ATP_half)
|
||||||
|
cleared_PMCA = k_PMCA * Ca_micro * pump_scale
|
||||||
|
cleared_NCX = k_NCX * Ca_micro
|
||||||
|
cleared_SERCA = k_SERCA * Ca_micro * pump_scale
|
||||||
|
|
||||||
|
Ca_micro -= (cleared_PMCA + cleared_NCX + cleared_SERCA)
|
||||||
|
Ca_micro = max(0.0, Ca_micro)
|
||||||
|
Ca_ER += cleared_SERCA
|
||||||
|
|
||||||
|
ATP_demand += ATP_cost_PMCA * cleared_PMCA
|
||||||
|
ATP_demand += ATP_cost_SERCA * cleared_SERCA
|
||||||
|
|
||||||
|
# Buffer recharge: bound Ca2+ slowly re-releases back to cytosol.
|
||||||
|
# During pump failure this sustains Ca_micro elevation (CASCADE 4).
|
||||||
|
rebind_flux = Ca_buffer_bound * dt / tau_buffer_rebind
|
||||||
|
Ca_micro += rebind_flux
|
||||||
|
Ca_buffer_bound = max(0.0, Ca_buffer_bound - rebind_flux)
|
||||||
|
B_free = B_total - Ca_buffer_bound
|
||||||
|
|
||||||
|
# -- 1E. CDI — RISE (spike only) AND RECOVERY (every ms) ------
|
||||||
|
# RISE: Ca2+ entering through open channels inactivates them locally.
|
||||||
|
# Gated to spike window — requires channels to be open.
|
||||||
|
# (Running every ms was wrong: CDI needs Ca2+ flowing through
|
||||||
|
# the channel, not ambient cytosolic Ca2+.)
|
||||||
|
if V_pre == 1:
|
||||||
|
CDI_factor += k_CDI_rise * Ca_micro * dt_s
|
||||||
|
|
||||||
|
# RECOVERY: continuous, suppressed when Ca_micro is high.
|
||||||
|
# Self-locking: pump failure -> Ca_micro high -> recovery ~0
|
||||||
|
# -> CDI_factor -> 1 -> effective_conductance -> 0 (CASCADE 5-6).
|
||||||
|
CDI_recovery_rate = k_CDI_rec * (1.0 - Ca_micro / Ca_micro_saturation)
|
||||||
|
CDI_factor = np.clip(CDI_factor - CDI_recovery_rate * dt_s, 0.0, 1.0)
|
||||||
|
|
||||||
|
# -- 1F. CALCIUM TRACE ----------------------------------------
|
||||||
|
# Leaky integrator — integrates full Ca2+ waveform every ms
|
||||||
|
# including inter-spike clearance. Drives Loop 2 recruitment speed.
|
||||||
|
Tr_Ca = Tr_Ca + (Ca_micro - Tr_Ca / tau_Tr_Ca) * dt
|
||||||
|
|
||||||
|
# -- 1G. POSTSYNAPTIC: NT DETECTION & AMPA --------------------
|
||||||
|
# Desensitization reduces effective NT — sustained NT exposure
|
||||||
|
# progressively silences receptors (postsynaptic equivalent of CDI).
|
||||||
|
effective_NT = released_NT * (1.0 - Desensitization_level)
|
||||||
|
receptor_conductance += effective_NT * 0.05
|
||||||
|
receptor_conductance *= (1.0 - dt / tau_membrane)
|
||||||
|
|
||||||
|
V_post += compute_EPSP(receptor_conductance) - (V_post / tau_membrane) * dt
|
||||||
|
V_post = max(0.0, V_post)
|
||||||
|
|
||||||
|
Desensitization_level += NT_cleft * 0.001 * dt
|
||||||
|
Desensitization_level -= (Desensitization_level / tau_desensitization) * dt
|
||||||
|
Desensitization_level = np.clip(Desensitization_level, 0.0, 1.0)
|
||||||
|
|
||||||
|
V_post_history.append(V_post)
|
||||||
|
if len(V_post_history) > 5000:
|
||||||
|
V_post_history.pop(0)
|
||||||
|
|
||||||
|
# -- 1H. POSTSYNAPTIC: NMDA COINCIDENCE DETECTION -------------
|
||||||
|
# Ca_post enters only when BOTH conditions hold simultaneously:
|
||||||
|
# (1) NT_cleft > 0 — ligand gate (glutamate present)
|
||||||
|
# (2) V_post elevated — voltage gate (Mg2+ block lifted)
|
||||||
|
# Mg block removal is a sigmoid of V_post.
|
||||||
|
# bAP (backpropagating AP) boosts V_post further, enabling
|
||||||
|
# full NMDA opening and larger Ca_post surge.
|
||||||
|
V_post_effective = V_post + (bAP * 0.5) # bAP adds depolarisation
|
||||||
|
Mg_block_removal = V_post_effective / (V_post_effective + V_NMDA_half)
|
||||||
|
NMDA_Ca_influx = k_NMDA * NT_cleft * Mg_block_removal
|
||||||
|
Ca_post += NMDA_Ca_influx
|
||||||
|
|
||||||
|
# Postsynaptic NKA: membrane recharge cost proportional to V_post.
|
||||||
|
# [POST-ATP 1] Dominant postsynaptic ATP drain at high activity.
|
||||||
|
ATP_demand_post += NKA_cost_per_bAP_post * V_post * dt_s
|
||||||
|
|
||||||
|
# -- 1I. POSTSYNAPTIC: Ca_post CLEARANCE ----------------------
|
||||||
|
# pump_scale_post: Hill(ATP_level_post) — same structure as presynaptic.
|
||||||
|
# NCX is ATP-independent floor (enables auto-reset after ATP recovery).
|
||||||
|
# [POST-ATP 3] When pump_scale_post falls, Ca_post stays elevated ->
|
||||||
|
# eCB threshold crossed without genuine coincidence -> false retrograde.
|
||||||
|
pump_scale_post = compute_pump_atp_factor(ATP_level_post, ATP_half_post)
|
||||||
|
cleared_Ca_post_pump = k_Ca_post_clear * Ca_post * pump_scale_post
|
||||||
|
cleared_Ca_post_NCX = k_Ca_post_NCX * Ca_post
|
||||||
|
Ca_post -= (cleared_Ca_post_pump + cleared_Ca_post_NCX)
|
||||||
|
Ca_post = max(0.0, Ca_post)
|
||||||
|
|
||||||
|
# [POST-ATP 2] ATP cost of postsynaptic PMCA.
|
||||||
|
ATP_demand_post += ATP_cost_Ca_post_pump * cleared_Ca_post_pump
|
||||||
|
|
||||||
|
# -- RECORD ---------------------------------------------------
|
||||||
|
log["V_pre_state"].append(V_pre_state)
|
||||||
|
log["Ca_micro"].append(Ca_micro)
|
||||||
|
log["Ca_ER"].append(Ca_ER)
|
||||||
|
log["CDI_factor"].append(CDI_factor)
|
||||||
|
log["B_free"].append(B_free)
|
||||||
|
log["N_RRP"].append(N_RRP)
|
||||||
|
log["N_RP"].append(N_RP)
|
||||||
|
log["Tr_Ca"].append(Tr_Ca)
|
||||||
|
log["NT_cleft"].append(NT_cleft)
|
||||||
|
log["V_post"].append(V_post)
|
||||||
|
log["Ca_post"].append(Ca_post)
|
||||||
|
log["eCB_level"].append(eCB_level)
|
||||||
|
log["mGluR_activation"].append(mGluR_activation)
|
||||||
|
log["released_NT"].append(released_NT)
|
||||||
|
log["ATP_level"].append(ATP_level)
|
||||||
|
log["ATP_demand"].append(ATP_demand)
|
||||||
|
log["ATP_level_post"].append(ATP_level_post)
|
||||||
|
log["ATP_demand_post"].append(ATP_demand_post)
|
||||||
|
|
||||||
|
# ==============================================================
|
||||||
|
# LOOP 2 — SLOW / ASTROCYTE (dt_slow = 1 s)
|
||||||
|
# ==============================================================
|
||||||
|
|
||||||
|
if (step % High_Freq_Multiplier) == 0:
|
||||||
|
|
||||||
|
# Astrocyte EAAT clearance — active NT removal from cleft.
|
||||||
|
cleared_NT = NT_cleft * 0.3
|
||||||
|
NT_cleft = max(0.0, NT_cleft - cleared_NT)
|
||||||
|
|
||||||
|
# FIX: IP3 integrates NT_released_this_window (total release
|
||||||
|
# since last Loop 2), not the post-diffusion NT_cleft residual
|
||||||
|
# which is ~0 by the time Loop 2 runs.
|
||||||
|
IP3 += NT_released_this_window - (IP3 / tau_IP3) * dt_slow
|
||||||
|
IP3 = max(0.0, IP3)
|
||||||
|
|
||||||
|
if IP3 > IP3_threshold:
|
||||||
|
trigger_slow_astrocyte_calcium_wave()
|
||||||
|
# FIX: wave boosts conversion_efficiency in the next mins cycle.
|
||||||
|
# The astrocyte responds to heavy load by upregulating its
|
||||||
|
# recycling machinery — shipping more glutamine back to the
|
||||||
|
# presynapse. Boost decays over tau_wave_decay metabolic cycles.
|
||||||
|
wave_active = tau_wave_decay
|
||||||
|
|
||||||
|
# FIX: mGluR reads NT_released_this_window (accumulated release
|
||||||
|
# load), not NT_cleft snapshot. NT_cleft is ~0 at Loop 2 time
|
||||||
|
# due to diffusion; the accumulator correctly represents the
|
||||||
|
# burst load the autoreceptor has sensed during this window.
|
||||||
|
NT_window_norm = min(1.0, NT_released_this_window / NT_window_sat)
|
||||||
|
mGluR_target = NT_window_norm
|
||||||
|
mGluR_activation += (mGluR_target - mGluR_activation) * (dt_slow / tau_mGluR)
|
||||||
|
mGluR_activation = np.clip(mGluR_activation, 0.0, 1.0)
|
||||||
|
|
||||||
|
# FIX: reset accumulator for next window.
|
||||||
|
NT_released_this_window = 0.0
|
||||||
|
|
||||||
|
# eCB retrograde synthesis: now driven by Ca_post (spine Ca2+),
|
||||||
|
# not V_post_history. The actual eCB synthesis in the spine is
|
||||||
|
# triggered by Ca2+-dependent enzymes (DAGL, PLC), not voltage.
|
||||||
|
# Under normal conditions Ca_post only rises with coincidence.
|
||||||
|
# Under POST-ATP failure Ca_post stays elevated without genuine
|
||||||
|
# coincidence -> false retrograde signal (POST-ATP 4).
|
||||||
|
recent_Ca_post = (np.mean(log["Ca_post"][-2000:])
|
||||||
|
if len(log["Ca_post"]) >= 2000
|
||||||
|
else (np.mean(log["Ca_post"]) if log["Ca_post"] else 0.0))
|
||||||
|
eCB_signal = max(0.0, recent_Ca_post - eCB_threshold)
|
||||||
|
if eCB_signal > 0:
|
||||||
|
eCB_level += eCB_signal * (dt_slow / tau_eCB_rise)
|
||||||
|
else:
|
||||||
|
eCB_level -= eCB_level * (dt_slow / tau_eCB_decay)
|
||||||
|
eCB_level = np.clip(eCB_level, 0.0, 1.0)
|
||||||
|
|
||||||
|
# FIX: RP->RRP recruitment moved here from Loop 1.
|
||||||
|
# Biological timescale: vesicle docking and priming take seconds,
|
||||||
|
# not milliseconds. k_rec_fast/slow are /s; * dt_slow_s = 1.0 s
|
||||||
|
# gives dimensionless per-step fraction — no hidden unit scaling.
|
||||||
|
current_recruitment_rate = map_trace_to_speed(Tr_Ca) # /s
|
||||||
|
refill_amount = (current_recruitment_rate * dt_slow_s
|
||||||
|
* N_RP * (Max_RRP - N_RRP) / Max_RRP)
|
||||||
|
refill_amount = max(0.0, refill_amount)
|
||||||
|
refill_amount = min(refill_amount, N_RP)
|
||||||
|
|
||||||
|
N_RRP = min(N_RRP + refill_amount, Max_RRP)
|
||||||
|
N_RP = max(0.0, N_RP - refill_amount)
|
||||||
|
ATP_demand += ATP_cost_docking * refill_amount
|
||||||
|
|
||||||
|
# ==============================================================
|
||||||
|
# LOOP 3 — METABOLIC (dt_meta = 1 min)
|
||||||
|
# ==============================================================
|
||||||
|
|
||||||
|
if (step % Metabolic_Multiplier) == 0:
|
||||||
|
|
||||||
|
# Presynaptic ATP: glucose supply minus accumulated demand.
|
||||||
|
conversion_efficiency, ATP_level = compute_astrocyte_metabolic_health(
|
||||||
|
Glucose_level, ATP_demand
|
||||||
|
)
|
||||||
|
ATP_demand = 0.0
|
||||||
|
|
||||||
|
# FIX: wave boost applied to conversion_efficiency.
|
||||||
|
# Astrocyte calcium wave (triggered by high IP3) upregulates
|
||||||
|
# glutamine synthetase -> faster NT recycling -> more RP refill.
|
||||||
|
# Boost decays over tau_wave_decay cycles.
|
||||||
|
if wave_active > 0:
|
||||||
|
conversion_efficiency = min(1.0, conversion_efficiency + wave_boost)
|
||||||
|
wave_active -= 1
|
||||||
|
|
||||||
|
# Glutamine shuttle: astrocyte converts cleared NT to glutamine,
|
||||||
|
# presynapse repackages it into vesicles -> N_RP replenished.
|
||||||
|
refill_RP = Glutamine_pool * conversion_efficiency
|
||||||
|
N_RP = min(Max_RP, N_RP + refill_RP)
|
||||||
|
Glutamine_pool = max(0.0, Glutamine_pool - refill_RP)
|
||||||
|
|
||||||
|
# Postsynaptic ATP: same glucose budget, own demand accumulator.
|
||||||
|
# Both sides draw from Glucose_level -> shared metabolic vulnerability.
|
||||||
|
# Presynaptic silence reduces NT -> less NMDA -> less Ca_post ->
|
||||||
|
# less ATP_demand_post: presynaptic protection indirectly
|
||||||
|
# protects the postsynapse.
|
||||||
|
_, ATP_level_post = compute_astrocyte_metabolic_health(
|
||||||
|
Glucose_level, ATP_demand_post, ATP_demand_scale_post
|
||||||
|
)
|
||||||
|
ATP_demand_post = 0.0
|
||||||
|
|
||||||
|
return log
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# EXAMPLE USAGE
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
|
total_steps = 10_000 # 10 seconds
|
||||||
|
|
||||||
|
# Presynaptic 20 Hz burst for 2 s.
|
||||||
|
spike_train = list(range(0, 2000, 50))
|
||||||
|
|
||||||
|
# Postsynaptic bAPs coincident with every 5th presynaptic spike
|
||||||
|
# (simulates partial coincidence for NMDA activation).
|
||||||
|
bAP_train = list(range(0, 2000, 250))
|
||||||
|
|
||||||
|
results = run_simulation(spike_train, total_steps, bAP_train)
|
||||||
|
t = np.arange(total_steps) * dt
|
||||||
|
|
||||||
|
fig, axes = plt.subplots(8, 1, figsize=(12, 18), sharex=True)
|
||||||
|
fig.suptitle("Tripartite Synapse — Presynaptic + Postsynaptic", fontsize=13)
|
||||||
|
|
||||||
|
axes[0].plot(t, results["V_pre_state"], color="slateblue", lw=0.8)
|
||||||
|
axes[0].set_ylabel("V_pre")
|
||||||
|
axes[0].set_title("Presynaptic membrane (AP waveform)", fontsize=9, loc="left")
|
||||||
|
|
||||||
|
axes[1].plot(t, results["Ca_micro"], color="darkorange", lw=0.8)
|
||||||
|
axes[1].set_ylabel("[Ca2+] pre")
|
||||||
|
axes[1].set_title("CASCADE 4 — presynaptic Ca2+", fontsize=9, loc="left")
|
||||||
|
|
||||||
|
axes[2].plot(t, results["CDI_factor"], color="firebrick", lw=0.8, label="CDI")
|
||||||
|
axes[2].plot(t, results["B_free"], color="steelblue", lw=0.8, label="Buffer free")
|
||||||
|
axes[2].set_ylabel("CDI / Buffer")
|
||||||
|
axes[2].set_title("CASCADE 5 — CDI lock-out", fontsize=9, loc="left")
|
||||||
|
axes[2].legend(fontsize=8)
|
||||||
|
|
||||||
|
axes[3].plot(t, results["N_RRP"], color="teal", lw=0.8, label="RRP")
|
||||||
|
axes[3].plot(t, results["N_RP"], color="purple", lw=0.8, label="RP")
|
||||||
|
axes[3].set_ylabel("Vesicles")
|
||||||
|
axes[3].set_title("CASCADE 1 — vesicle depletion", fontsize=9, loc="left")
|
||||||
|
axes[3].legend(fontsize=8)
|
||||||
|
|
||||||
|
axes[4].plot(t, results["NT_cleft"], color="darkgreen", lw=0.8, label="NT cleft")
|
||||||
|
axes[4].plot(t, results["mGluR_activation"], color="saddlebrown", lw=0.8, label="mGluR")
|
||||||
|
axes[4].plot(t, results["eCB_level"], color="crimson", lw=0.8, label="eCB")
|
||||||
|
axes[4].set_ylabel("Cleft / Feedback")
|
||||||
|
axes[4].set_title("CASCADE 6 — three brakes on conductance", fontsize=9, loc="left")
|
||||||
|
axes[4].legend(fontsize=8)
|
||||||
|
|
||||||
|
axes[5].plot(t, results["V_post"], color="navy", lw=0.8, label="V_post")
|
||||||
|
axes[5].plot(t, results["Ca_post"], color="coral", lw=0.8, label="Ca_post (spine)")
|
||||||
|
axes[5].set_ylabel("Postsynaptic")
|
||||||
|
axes[5].set_title("Postsynaptic potential + NMDA spine Ca2+", fontsize=9, loc="left")
|
||||||
|
axes[5].legend(fontsize=8)
|
||||||
|
|
||||||
|
axes[6].plot(t, results["ATP_level"], color="goldenrod", lw=0.8, label="ATP pre")
|
||||||
|
axes[6].plot(t, results["ATP_level_post"], color="darkorange", lw=0.8, label="ATP post")
|
||||||
|
axes[6].set_ylabel("ATP level")
|
||||||
|
axes[6].set_title("CASCADE 2 / POST-ATP — presynaptic and postsynaptic ATP", fontsize=9, loc="left")
|
||||||
|
axes[6].legend(fontsize=8)
|
||||||
|
|
||||||
|
axes[7].plot(t, results["ATP_demand"], color="tomato", lw=0.8, label="demand pre")
|
||||||
|
axes[7].plot(t, results["ATP_demand_post"], color="orangered", lw=0.8, label="demand post")
|
||||||
|
axes[7].set_ylabel("ATP demand")
|
||||||
|
axes[7].set_title("Accumulated ATP demand (resets each min cycle)", fontsize=9, loc="left")
|
||||||
|
axes[7].set_xlabel("Time (ms)")
|
||||||
|
axes[7].legend(fontsize=8)
|
||||||
|
|
||||||
|
plt.tight_layout()
|
||||||
|
plt.savefig("./synapse_simulation.png", dpi=150)
|
||||||
|
plt.close()
|
||||||
|
print("Done.")
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 237 KiB After Width: | Height: | Size: 243 KiB |
Reference in New Issue
Block a user