{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# Clopath Rule: Spike pairing experiment\n\nThis script simulates one ``aeif_psc_delta_clopath`` neuron that is connected with\na Clopath connection [1]_. The synapse receives pairs of a pre- and a postsynaptic\nspikes that are separated by either 10 ms (pre before post) or -10 ms (post\nbefore pre). The change of the synaptic weight is measured after five of such\npairs. This experiment is repeated five times with different rates of the\nsequence of the spike pairs: 10Hz, 20Hz, 30Hz, 40Hz, and 50Hz.\n\n## References\n\n.. [1] Clopath C, B\u00fcsing L, Vasilaki E, Gerstner W (2010). Connectivity reflects coding:\n       a model of voltage-based STDP with homeostasis.\n       Nature Neuroscience 13:3, 344--352\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import numpy as np\nimport matplotlib.pyplot as plt\nimport nest"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "First we specify the neuron parameters. To enable voltage dependent\nprefactor ``A_LTD(u_bar_bar)`` add ``A_LTD_const: False`` to the dictionary.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "nrn_params = {'V_m': -70.6,\n              'E_L': -70.6,\n              'C_m': 281.0,\n              'theta_minus': -70.6,\n              'theta_plus': -45.3,\n              'A_LTD': 14.0e-5,\n              'A_LTP': 8.0e-5,\n              'tau_minus': 10.0,\n              'tau_plus': 7.0,\n              'delay_u_bars': 4.0,\n              'a': 4.0,\n              'b': 0.0805,\n              'V_reset': -70.6 + 21.0,\n              'V_clamp': 33.0,\n              't_clamp': 2.0,\n              't_ref': 0.0,\n              }"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Hardcoded spike times of presynaptic spike generator\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "spike_times_pre = [\n    # Presynaptic spike before the postsynaptic\n    [ 20.0,  120.0,  220.0,  320.0,  420.0],          # noqa\n    [ 20.0,   70.0,  120.0,  170.0,  220.0],          # noqa\n    [ 20.0,   53.3,   86.7,  120.0,  153.3],          # noqa\n    [ 20.0,   45.0,   70.0,   95.0,  120.0],          # noqa\n    [ 20.0,   40.0,   60.0,   80.0,  100.0],          # noqa\n    # Presynaptic spike after the postsynaptic\n    [120.0,  220.0,  320.0,  420.0,  520.0,  620.0],  # noqa\n    [ 70.0,  120.0,  170.0,  220.0,  270.0,  320.0],  # noqa\n    [ 53.3,   86.6,  120.0,  153.3,  186.6,  220.0],  # noqa\n    [ 45.0,   70.0,   95.0,  120.0,  145.0,  170.0],  # noqa\n    [ 40.0,   60.0,   80.0,  100.0,  120.0,  140.0]]  # noqa"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Hardcoded spike times of postsynaptic spike generator\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "spike_times_post = [\n    [ 10.0,  110.0,  210.0,  310.0,  410.0],          # noqa\n    [ 10.0,   60.0,  110.0,  160.0,  210.0],          # noqa\n    [ 10.0,   43.3,   76.7,  110.0,  143.3],          # noqa\n    [ 10.0,   35.0,   60.0,   85.0,  110.0],          # noqa\n    [ 10.0,   30.0,   50.0,   70.0,   90.0],          # noqa\n    [130.0,  230.0,  330.0,  430.0,  530.0,  630.0],  # noqa\n    [ 80.0,  130.0,  180.0,  230.0,  280.0,  330.0],  # noqa\n    [ 63.3,   96.6,  130.0,  163.3,  196.6,  230.0],  # noqa\n    [ 55.0,   80.0,  105.0,  130.0,  155.0,  180.0],  # noqa\n    [ 50.0,   70.0,   90.0,  110.0,  130.0,  150.0]]  # noqa\ninit_w = 0.5\nsyn_weights = []\nresolution = 0.1"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Loop over pairs of spike trains\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "for s_t_pre, s_t_post in zip(spike_times_pre, spike_times_post):\n    nest.ResetKernel()\n    nest.resolution = resolution\n\n    # Create one neuron\n    nrn = nest.Create(\"aeif_psc_delta_clopath\", 1, nrn_params)\n\n    # We need a parrot neuron since spike generators can only\n    # be connected with static connections\n    prrt_nrn = nest.Create(\"parrot_neuron\", 1)\n\n    # Create and connect spike generators\n    spike_gen_pre = nest.Create(\"spike_generator\", {\"spike_times\": s_t_pre})\n\n    nest.Connect(spike_gen_pre, prrt_nrn,\n                 syn_spec={\"delay\": resolution})\n\n    spike_gen_post = nest.Create(\"spike_generator\", {\"spike_times\": s_t_post})\n\n    nest.Connect(spike_gen_post, nrn, syn_spec={\"delay\": resolution, \"weight\": 80.0})\n\n    # Create weight recorder\n    wr = nest.Create('weight_recorder')\n\n    # Create Clopath connection with weight recorder\n    nest.CopyModel(\"clopath_synapse\", \"clopath_synapse_rec\",\n                   {\"weight_recorder\": wr})\n    syn_dict = {\"synapse_model\": \"clopath_synapse_rec\",\n                \"weight\": init_w, \"delay\": resolution}\n    nest.Connect(prrt_nrn, nrn, syn_spec=syn_dict)\n\n    # Simulation\n    simulation_time = (10.0 + max(s_t_pre[-1], s_t_post[-1]))\n    nest.Simulate(simulation_time)\n\n    # Extract and save synaptic weights\n    weights = wr.get(\"events\", \"weights\")\n    syn_weights.append(weights[-1])\n\nsyn_weights = np.array(syn_weights)\n# scaling of the weights so that they are comparable to [1]\nsyn_weights = 100.0 * 15.0 * (syn_weights - init_w) / init_w + 100.0\n\n# Plot results\nfig, ax = plt.subplots(1, sharex=False)\nax.plot([10., 20., 30., 40., 50.], syn_weights[5:], color='b', lw=2.5, ls='-',\n        label=\"pre-post pairing\")\nax.plot([10., 20., 30., 40., 50.], syn_weights[:5], color='g', lw=2.5, ls='-',\n        label=\"post-pre pairing\")\nax.set_ylabel(\"normalized weight change\")\nax.set_xlabel(\"rho (Hz)\")\nax.legend()\nax.set_title(\"synaptic weight\")\n\nplt.show()"
      ]
    }
  ],
  "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.8.6"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}