"
]
},
{
"cell_type": "markdown",
"id": "0c24a66f-8db0-44b0-948e-c4dbf9f93210",
"metadata": {},
"source": [
"If we search Open Source Brain, we can see other more recent versions of [L5 Pyramidal Cell models based on the original L5PC Hay model](https://v2.opensourcebrain.org/repositories/2180). Suppose we wanted to incorporate these newer models alongside the original L5 PC network created above. We would need to do the following:\n",
"1. Download the [files](https://github.com/OpenSourceBrain/267587/tree/master/Single%20Cell%20Modelling/Current-Step%20Simulations/L5Pyr_young)\n",
"2. Move the morphology, mode, and model template files to their appropriate location\n",
"3. Since these files also include new .mod files, we would have to recompile them:\n",
"```bash\n",
" $ cd components/mechanisms && nrnivmodl modfiles\n",
"```\n",
"\n",
"The newer models have a different morphology file (`Hl5PN1.swc`) and HOC Template name (`HNTemplate`). So in order to add these new cells to the old one we can add the following call in our build script (**build_network.L5_updated.py**):\n",
"\n",
"```python\n",
"net.add_nodes(\n",
" N=5,\n",
" model_type='biophysical',\n",
" model_template='hoc:HNTemplate',\n",
" morphology='HL5PN1.swc'\n",
")\n",
"```\n",
"\n",
"*Note: We'll also modify the script to write the network to a different directory*\n"
]
},
{
"cell_type": "markdown",
"id": "1d73fd45-d720-42d8-81da-7bb889872012",
"metadata": {},
"source": [
"We could try to run the **L5_updated** model like before, but it would throw an error\n",
"\n",
"\n",
"⚠️ NEURON: init not enough arguments\n",
"
\n",
"\n",
"The Reason: **We are not calling the HNTemplate correctly.**"
]
},
{
"cell_type": "markdown",
"id": "cbae5da5-3592-4020-a4cb-51e53284cac7",
"metadata": {},
"source": [
"If we look through the code and the documentation, we can see that, to instantiate an HNTemplate cell model instance, we must pass two parameters: The morphology file and the cell-type (one of a preset number of string values that will determine how specific properties are set within the model). In this case, the call would look like:\n",
"\n",
"```python\n",
" h.HNTemplate(morphology_file_path, \"HL5PN1\")\n",
"```\n",
"\n",
"The built-in BMTK function that tries to load hoc files, [loadHOC](https://github.com/AllenInstitute/bmtk/blob/develop/bmtk/simulator/bionet/default_setters/cell_models.py#L43), does not know how to load this specific template. And even if it did, you may run into other models that require different, unseen ways of initialization. \n",
"\n",
"While it is possible to overwrite the `loadHOC` function, it is not ideal. To avoid breaking existing models, we would need to have multiple cases based on each possible template."
]
},
{
"cell_type": "markdown",
"id": "0dcb4381-0ca6-4460-8973-bac09438a69b",
"metadata": {},
"source": [
"**Solution**\n",
"\n",
"Instead of using one function to load in every template, we can create our own custom function to load the HNTemplate. To achieve this, BMTK uses a special [python decorator](https://peps.python.org/pep-0318/) to assign to function users have written (in either the notebook or run_bionet.py script). Below, we show an example of how to do this using a custom function we'll call loadHNTemplate():"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "861c2dfc-ce17-420b-b5e1-beb294996ff5",
"metadata": {},
"outputs": [],
"source": [
"from neuron import h\n",
"from bmtk.simulator.bionet import cell_model\n",
"from bmtk.simulator.bionet.io_tools import io\n",
"\n",
"@cell_model(directive='hoc:HNTemplate', model_type='biophysical')\n",
"def loadHNTemplate(cell, template_name, dynamics_params):\n",
" io.log_info(f'Calling loadHNTemplate() for cell {cell[\"node_id\"]}, template {template_name}')\n",
" hobj = h.HNTemplate(cell['morphology'], \"HL5PN1\")\n",
" return hobj"
]
},
{
"cell_type": "markdown",
"id": "8f99de13-a200-445e-b70a-bd2b3fbdd08e",
"metadata": {},
"source": [
" * The `@cell_model` is a decorator we put at the front of our function. Using `directive=hoc:Template` and `model_type=biophysical` parameters indicates to BMTK that whenever a cell model needs to be built for a *biophysical*, *HNTemplate* hoc template, it will use this function.\n",
" * Our function requires three parameters;\n",
" * The `cell` parameter contains attributes of each individual cell and can be used to extract properties like the morphology file, the node-id, coordinates, etc.\n",
" * The `template_name` is, in this case, just the string value \"HNTemplate\"\n",
" * The `dynamics_params` is a dictionary from the **dynamics_params** json or hdf5. In this network, we never set the dynamics_params attributes, so the value will be None.\n",
" * We need to return either a hoc-object or some other Python class built using the NEURON API.\n",
" * For a sanity check, we also included a log statement. We should only see this message for the 5 newer HNTemplate models, not for the other original \"L5PCTemplate\" cells.\n",
"\n",
"\n",
"During simulation, this function will be called for every cell with matching \"template_name\" and \"model_type\"."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "d315eb04-6c0f-415b-aedd-21a8c8253ba8",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2024-10-21 18:39:10,266 [INFO] Created log file\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:NEURONIOUtils:Created log file\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Mechanisms already loaded from path: ./components/mechanisms. Aborting.\n",
"2024-10-21 18:39:10,335 [INFO] Building cells.\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:NEURONIOUtils:Building cells.\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"2024-10-21 18:39:14,153 [INFO] Calling loadHNTemplate() for cell 5, template HNTemplate\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:NEURONIOUtils:Calling loadHNTemplate() for cell 5, template HNTemplate\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"2024-10-21 18:39:14,377 [INFO] Calling loadHNTemplate() for cell 6, template HNTemplate\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:NEURONIOUtils:Calling loadHNTemplate() for cell 6, template HNTemplate\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"2024-10-21 18:39:14,596 [INFO] Calling loadHNTemplate() for cell 7, template HNTemplate\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:NEURONIOUtils:Calling loadHNTemplate() for cell 7, template HNTemplate\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"2024-10-21 18:39:14,813 [INFO] Calling loadHNTemplate() for cell 8, template HNTemplate\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:NEURONIOUtils:Calling loadHNTemplate() for cell 8, template HNTemplate\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"2024-10-21 18:39:15,043 [INFO] Calling loadHNTemplate() for cell 9, template HNTemplate\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:NEURONIOUtils:Calling loadHNTemplate() for cell 9, template HNTemplate\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"2024-10-21 18:39:15,258 [INFO] Building recurrent connections\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:NEURONIOUtils:Building recurrent connections\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"2024-10-21 18:39:15,282 [INFO] Building virtual cell stimulations for virt_exc_spikes\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:NEURONIOUtils:Building virtual cell stimulations for virt_exc_spikes\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"2024-10-21 18:39:15,346 [INFO] Running simulation for 2000.000 ms with the time step 0.100 ms\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:NEURONIOUtils:Running simulation for 2000.000 ms with the time step 0.100 ms\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"2024-10-21 18:39:15,347 [INFO] Starting timestep: 0 at t_sim: 0.000 ms\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:NEURONIOUtils:Starting timestep: 0 at t_sim: 0.000 ms\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"2024-10-21 18:39:15,348 [INFO] Block save every 5000 steps\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:NEURONIOUtils:Block save every 5000 steps\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"2024-10-21 18:39:35,798 [INFO] step:5000 t_sim:500.00 ms\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:NEURONIOUtils: step:5000 t_sim:500.00 ms\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"2024-10-21 18:39:56,404 [INFO] step:10000 t_sim:1000.00 ms\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:NEURONIOUtils: step:10000 t_sim:1000.00 ms\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"2024-10-21 18:40:17,730 [INFO] step:15000 t_sim:1500.00 ms\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:NEURONIOUtils: step:15000 t_sim:1500.00 ms\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"2024-10-21 18:40:38,490 [INFO] step:20000 t_sim:2000.00 ms\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:NEURONIOUtils: step:20000 t_sim:2000.00 ms\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"2024-10-21 18:40:38,524 [INFO] Simulation completed in 83.18 seconds \n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:NEURONIOUtils:Simulation completed in 83.18 seconds \n"
]
}
],
"source": [
"bionet.reset()\n",
"conf = bionet.Config.from_json('config.L5_updated.json')\n",
"conf.build_env()\n",
"\n",
"net = bionet.BioNetwork.from_config(conf)\n",
"sim = bionet.BioSimulator.from_config(conf, network=net)\n",
"sim.run()"
]
},
{
"cell_type": "markdown",
"id": "76b4dafc-4f86-4013-aee0-3188269e5a43",
"metadata": {},
"source": [
"### 1.3. Example: Loading a python-based neuronal model into your simulation