{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Mean-field theory for random balanced network\n\nThis script performs a mean-field analysis of the spiking network of\nexcitatory and an inhibitory population of leaky-integrate-and-fire neurons\nsimulated in ``brunel_delta_nest.py``. We refer to this spiking network of LIF\nneurons with 'SLIFN'.\n\nThe self-consistent equation for the population-averaged firing rates\n(eq.27 in [1]_, [2]_) is solved by integrating a pseudo-time dynamics\n(eq.30 in [1]_). The latter constitutes a network of rate neurons, which is\nsimulated here. The asymptotic rates, i.e., the fixed points of the\ndynamics (eq.30), are the prediction for the population and\ntime-averaged from the spiking simulation.\n\n## References\n\n.. [1] Hahne J, Dahmen D, Schuecker J, Frommer A, Bolten M,\n       Helias M and Diesmann M. (2017).  Integration of continuous-time\n       dynamics in a spiking neural network simulator. Front. Neuroinform.\n       11:34. doi: 10.3389/fninf.2017.00034\n\n.. [2] Schuecker J, Schmidt M, van Albada SJ, Diesmann M.\n       and Helias, M. (2017). Fundamental activity constraints lead\n       to specific interpretations of the connectome.\n       PLOS Computational Biology 13(2): e1005179.\n       https://doi.org/10.1371/journal.pcbi.1005179\n\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import nest\nimport numpy\n\nnest.ResetKernel()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Assigning the simulation parameters to variables.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "dt = 0.1  # the resolution in ms\nsimtime = 50.0  # Simulation time in ms"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Definition of the network parameters in the SLIFN\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "g = 5.0  # ratio inhibitory weight/excitatory weight\neta = 2.0  # external rate relative to threshold rate\nepsilon = 0.1  # connection probability"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Definition of the number of neurons and connections in the SLIFN, needed\nfor the connection strength in the Siegert neuron network\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "order = 2500\nNE = 4 * order  # number of excitatory neurons\nNI = 1 * order  # number of inhibitory neurons\nCE = int(epsilon * NE)  # number of excitatory synapses per neuron\nCI = int(epsilon * NI)  # number of inhibitory synapses per neuron\nC_tot = int(CI + CE)  # total number of synapses per neuron"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Initialization of the parameters of the Siegert neuron and the connection\nstrength. The parameter are equivalent to the LIF-neurons in the SLIFN.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "tauMem = 20.0  # time constant of membrane potential in ms\ntheta = 20.0  # membrane threshold potential in mV\nneuron_params = {'tau_m': tauMem,\n                 't_ref': 2.0,\n                 'theta': theta,\n                 'V_reset': 0.0,\n                 }\n\nJ = 0.1  # postsynaptic amplitude in mV in the SLIFN\nJ_ex = J  # amplitude of excitatory postsynaptic potential\nJ_in = -g * J_ex  # amplitude of inhibitory postsynaptic potential\n# drift_factor in diffusion connections (see [1], eq. 28) for external\n# drive, excitatory and inhibitory neurons\ndrift_factor_ext = tauMem * 1e-3 * J_ex\ndrift_factor_ex = tauMem * 1e-3 * CE * J_ex\ndrift_factor_in = tauMem * 1e-3 * CI * J_in\n# diffusion_factor for diffusion connections (see [1], eq. 29)\ndiffusion_factor_ext = tauMem * 1e-3 * J_ex ** 2\ndiffusion_factor_ex = tauMem * 1e-3 * CE * J_ex ** 2\ndiffusion_factor_in = tauMem * 1e-3 * CI * J_in ** 2"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "External drive, this is equivalent to the drive in the SLIFN\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "nu_th = theta / (J * CE * tauMem)\nnu_ex = eta * nu_th\np_rate = 1000.0 * nu_ex * CE"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Configuration of the simulation kernel by the previously defined time\nresolution used in the simulation. Setting ``print_time`` to `True` prints the\nalready processed simulation time as well as its percentage of the total\nsimulation time.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "nest.SetKernelStatus({\"resolution\": dt, \"print_time\": True,\n                      \"overwrite_files\": True})\n\nprint(\"Building network\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Configuration of the model ``siegert_neuron`` using ``SetDefaults``.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "nest.SetDefaults(\"siegert_neuron\", neuron_params)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Creation of the nodes using ``Create``. One rate neuron represents the\nexcitatory population of LIF-neurons in the SLIFN and one the inhibitory\npopulation assuming homogeneity of the populations.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "siegert_ex = nest.Create(\"siegert_neuron\", 1)\nsiegert_in = nest.Create(\"siegert_neuron\", 1)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "The Poisson drive in the SLIFN is replaced by a driving rate neuron,\nwhich does not receive input from other neurons. The activity of the rate\nneuron is controlled by setting ``mean`` to the rate of the corresponding\npoisson generator in the SLIFN.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "siegert_drive = nest.Create('siegert_neuron', 1, params={'mean': p_rate})"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "To record from the rate neurons a multimeter is created and the parameter\n``record_from`` is set to `rate` as well as the recording interval to `dt`\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "multimeter = nest.Create(\n    'multimeter', params={'record_from': ['rate'], 'interval': dt})"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Connections between ``Siegert neurons`` are realized with the synapse model\n``diffusion_connection``. These two parameters reflect the prefactors in\nfront of the rate variable in eq. 27-29 in [1].\n\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Connections originating from the driving neuron\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "syn_dict = {'drift_factor': drift_factor_ext,\n            'diffusion_factor': diffusion_factor_ext,\n            'synapse_model': 'diffusion_connection'}\n\nnest.Connect(\n    siegert_drive, siegert_ex + siegert_in, 'all_to_all', syn_dict)\nnest.Connect(multimeter, siegert_ex + siegert_in)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Connections originating from the excitatory neuron\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "syn_dict = {'drift_factor': drift_factor_ex, 'diffusion_factor':\n            diffusion_factor_ex, 'synapse_model': 'diffusion_connection'}\nnest.Connect(siegert_ex, siegert_ex + siegert_in, 'all_to_all', syn_dict)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Connections originating from the inhibitory neuron\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "syn_dict = {'drift_factor': drift_factor_in, 'diffusion_factor':\n            diffusion_factor_in, 'synapse_model': 'diffusion_connection'}\nnest.Connect(siegert_in, siegert_ex + siegert_in, 'all_to_all', syn_dict)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Simulate the network\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "nest.Simulate(simtime)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Analyze the activity data. The asymptotic rate of the Siegert neuron\ncorresponds to the population- and time-averaged activity in the SLIFN.\nFor the symmetric network setup used here, the excitatory and inhibitory\nrates are identical. For comparison execute the example ``brunel_delta_nest.py``.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "data = multimeter.events\nrates_ex = data['rate'][numpy.where(data['senders'] == siegert_ex.global_id)]\nrates_in = data['rate'][numpy.where(data['senders'] == siegert_in.global_id)]\ntimes = data['times'][numpy.where(data['senders'] == siegert_in.global_id)]\nprint(\"Excitatory rate   : %.2f Hz\" % rates_ex[-1])\nprint(\"Inhibitory rate   : %.2f Hz\" % rates_in[-1])"
      ]
    }
  ],
  "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.6.12"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}