{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "e0104276",
   "metadata": {},
   "source": [
    "# Overview: How Integration Works\n",
    "\n",
    "Every dynamical model in `braincell` — a single ion channel, a point neuron,\n",
    "a branching dendrite — is ultimately a system of differential equations\n",
    "\n",
    "$$\\frac{dy}{dt} = f(t, y),$$\n",
    "\n",
    "where $y$ stacks together every time-varying quantity (membrane potential,\n",
    "gating variables, ion concentrations). Turning that system into a simulation\n",
    "means repeatedly answering one question: *given the state now, what is it one\n",
    "small step `dt` later?*\n",
    "\n",
    "`braincell` separates that question into two responsibilities:\n",
    "\n",
    "| Responsibility | Who owns it | Where it lives |\n",
    "| --- | --- | --- |\n",
    "| **What** to integrate — the variables and their right-hand side $f$ | your model | `DiffEqState` + `DiffEqModule` |\n",
    "| **How** to advance one step | a numerical solver | `braincell.quad` |\n",
    "\n",
    "This separation is the whole design. You describe the equations once; you can\n",
    "then swap solvers freely without rewriting the model."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e93f08a1",
   "metadata": {},
   "source": [
    "## The two protocol pieces\n",
    "\n",
    "- **`DiffEqState`** is a state variable that participates in integration. It is\n",
    "  an ordinary `brainstate` state with two extra slots the solver fills in:\n",
    "  `derivative` (the right-hand side $f(t, y)$) and, for stochastic systems,\n",
    "  `diffusion`. You meet it again in [Defining Differential Equations](diffeq).\n",
    "\n",
    "- **`DiffEqModule`** is a mixin that marks a class as integrable. It exposes a\n",
    "  three-method *lifecycle* that every solver calls in the same order on each\n",
    "  step."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dbff9250",
   "metadata": {},
   "source": [
    "## The per-step lifecycle\n",
    "\n",
    "A solver never reaches inside your model. It only calls three hooks, always in\n",
    "this order, once per step:\n",
    "\n",
    "```\n",
    "        ┌─────────────────────────────────────────────┐\n",
    "        │  one integration step (advances t by dt)     │\n",
    "        └─────────────────────────────────────────────┘\n",
    "\n",
    "   pre_integral(...)        # refresh rate constants, gather inputs\n",
    "        │\n",
    "        ▼\n",
    "   compute_derivative(...)  # REQUIRED: write state.derivative for each DiffEqState\n",
    "        │\n",
    "        ▼\n",
    "   << solver combines values + derivatives to produce y(t + dt) >>\n",
    "        │\n",
    "        ▼\n",
    "   post_integral(...)       # clamp / project / fire post-step events\n",
    "```\n",
    "\n",
    "Only `compute_derivative` is mandatory; `pre_integral` and `post_integral`\n",
    "default to no-ops. The current time `t` and step size `dt` are not passed as\n",
    "arguments — solvers read them from the active\n",
    "[`brainstate.environ`](https://brainstate.readthedocs.io) context, which is why\n",
    "you will see every simulation wrapped in `with brainstate.environ.context(dt=...)`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2007e437",
   "metadata": {},
   "source": [
    "## The solver registry\n",
    "\n",
    "Solvers are looked up by name through a registry. You rarely import a step\n",
    "function directly; instead you name it — either by passing `solver=\"...\"` to a\n",
    "cell, or by asking the registry for it. Let's see what is available."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "d8049f02",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-05-25T08:58:00.156283Z",
     "iopub.status.busy": "2026-05-25T08:58:00.156032Z",
     "iopub.status.idle": "2026-05-25T08:58:01.855572Z",
     "shell.execute_reply": "2026-05-25T08:58:01.854589Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "25 integrators registered\n",
      "\n",
      "['backward_euler', 'cn_exp_euler', 'cn_rk4', 'dhs_voltage', 'euler', 'exp_euler', 'exp_exp_euler', 'explicit', 'heun2', 'heun3', 'implicit_euler', 'implicit_exp_euler', 'implicit_rk4', 'ind_exp_euler', 'midpoint', 'ralston2', 'ralston3', 'ralston4', 'rk2', 'rk3', 'rk4', 'splitting', 'ssprk3', 'stagger', 'staggered']\n"
     ]
    }
   ],
   "source": [
    "import braincell.quad as quad\n",
    "\n",
    "integrators = sorted(quad.all_integrators)\n",
    "print(f\"{len(integrators)} integrators registered\\n\")\n",
    "print(integrators)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "206b651b",
   "metadata": {},
   "source": [
    "`get_integrator` resolves a name (or alias) to its step function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "a064d36c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-05-25T08:58:01.858602Z",
     "iopub.status.busy": "2026-05-25T08:58:01.858071Z",
     "iopub.status.idle": "2026-05-25T08:58:01.865545Z",
     "shell.execute_reply": "2026-05-25T08:58:01.864494Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<function braincell.quad._runge_kutta.rk4_step(target: braincell.DiffEqModule, *args)>"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rk4 = quad.get_integrator(\"rk4\")\n",
    "rk4"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "315aadba",
   "metadata": {},
   "source": [
    "That is the entire mental model:\n",
    "\n",
    "1. Describe equations with `DiffEqState` / `DiffEqModule`.\n",
    "2. Pick a solver by name from `braincell.quad`.\n",
    "3. Step inside a `brainstate.environ` context that supplies `dt` (and `t`).\n",
    "\n",
    "The next page makes this concrete by building a model from scratch."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
