Skip to content
This repository was archived by the owner on Feb 26, 2025. It is now read-only.

Commit 70fddf8

Browse files
committed
Merge branch 'master' into arbor_integration
2 parents 5c9a5bf + 38ba649 commit 70fddf8

File tree

4 files changed

+124
-18
lines changed

4 files changed

+124
-18
lines changed

bluepyopt/neuroml/biophys.py

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -192,21 +192,57 @@ def add_nml_channel_to_nml_cell_file(
192192
channel_nml2_file = f"{channel_name}.channel.nml"
193193

194194
if channel_nml2_file not in included_channels:
195-
nml_mech_dir = get_nml_mech_dir()
196195
channel_new_path = Path(channel_dir) / channel_nml2_file
197196
cell_doc.includes.append(neuroml.IncludeType(href=channel_new_path))
198197

199198
# for some reason, pynml cannot accept absolute paths in IncludeType,
200199
# so copy paste files in current directory for the simulation to work
201200
if not skip_channels_copy:
202201
Path(channel_dir).mkdir(exist_ok=True)
203-
channel_path = Path(nml_mech_dir) / channel_nml2_file
202+
nml_mech_dir = Path(get_nml_mech_dir())
203+
channel_path = nml_mech_dir / channel_nml2_file
204204
if channel_path.is_file():
205205
shutil.copy(channel_path, channel_new_path)
206206

207207
included_channels.append(channel_nml2_file)
208208

209209

210+
def get_channel_ion(channel, custom_channel_ion=None):
211+
"""Get ion name given channel name.
212+
213+
Arguments:
214+
channel (str): ion channel (e.g. StochKv)
215+
custom_channel_ion (dict): dict mapping channel to ion
216+
"""
217+
ion = channel_ions.get(channel, None)
218+
if ion is None and custom_channel_ion is not None:
219+
ion = custom_channel_ion.get(channel, None)
220+
if ion is None:
221+
raise KeyError(
222+
f"Ion not found for channel {channel}."
223+
" Please set channel-ion mapping using custom_channel_ion."
224+
)
225+
return ion
226+
227+
228+
def get_erev(ion, custom_ion_erevs=None):
229+
"""Get reversal potential as str given ion name.
230+
231+
Arguments:
232+
ion (str): ion name (e.g. na)
233+
custom_ion_erevs (dict): dict mapping ion to erev (reversal potential)
234+
"""
235+
erev = ion_erevs.get(ion, None)
236+
if erev is None and custom_ion_erevs is not None:
237+
erev = custom_ion_erevs.get(ion, None)
238+
if erev is None:
239+
raise KeyError(
240+
f"Reversal potential not found for ion {ion}."
241+
" Please set ion-erev mapping using custom_ion_erevs."
242+
)
243+
return erev
244+
245+
210246
def get_arguments(
211247
params,
212248
parameter_name,
@@ -216,6 +252,8 @@ def get_arguments(
216252
variable_parameters,
217253
cond_density,
218254
release_params,
255+
custom_channel_ion=None,
256+
custom_ion_erevs=None,
219257
):
220258
"""Get arguments for channel density function.
221259
@@ -230,11 +268,13 @@ def get_arguments(
230268
parameters for non-uniform distributions
231269
cond_density (str): conductance density
232270
release_params (dict): optimized parameters
271+
custom_channel_ion (dict): dict mapping channel to ion
272+
custom_ion_erevs (dict): dict mapping ion to erev (reversal potential)
233273
"""
234274
arguments = {}
235275

236-
arguments["ion"] = channel_ions[channel]
237-
erev = ion_erevs[arguments["ion"]]
276+
arguments["ion"] = get_channel_ion(channel, custom_channel_ion)
277+
erev = get_erev(arguments["ion"], custom_ion_erevs)
238278

239279
channel_class = "ChannelDensity"
240280

@@ -331,12 +371,14 @@ def get_density(
331371
skip_non_uniform,
332372
release_params,
333373
skip_channels_copy,
374+
custom_channel_ion=None,
375+
custom_ion_erevs=None,
334376
):
335377
"""Return density.
336378
337379
Arguments:
338380
cell_doc (NeuroMLDocument): nml document of the cell model
339-
cell (ephys.CellModel)
381+
cell (ephys.CellModel): bluepyopt cell
340382
parameter (ephys.parameters)
341383
section_list (str): location
342384
included_channels (list): list of channels already included
@@ -345,6 +387,8 @@ def get_density(
345387
release_params (dict): optimized parameters
346388
skip_channels_copy (bool): True to skip the copy pasting
347389
of the neuroml channel files
390+
custom_channel_ion (dict): dict mapping channel to ion
391+
custom_ion_erevs (dict): dict mapping ion to erev (reversal potential)
348392
"""
349393
channel = get_channel_from_param_name(parameter.param_name)
350394

@@ -375,6 +419,8 @@ def get_density(
375419
variable_parameters=variable_parameters,
376420
cond_density=cond_density,
377421
release_params=release_params,
422+
custom_channel_ion=custom_channel_ion,
423+
custom_ion_erevs=custom_ion_erevs,
378424
)
379425

380426
density = getattr(neuroml, channel_class)(**arguments)
@@ -413,16 +459,20 @@ def get_biophys(
413459
release_params,
414460
skip_non_uniform=False,
415461
skip_channels_copy=False,
462+
custom_channel_ion=None,
463+
custom_ion_erevs=None,
416464
):
417465
"""Get biophys in neuroml format.
418466
419467
Arguments:
420-
cell (ephys.CellModel)
468+
cell (ephys.CellModel): bluepyopt cell
421469
cell_doc (NeuroMLDocument): nml document of the cell model
422-
skip_non_uniform (bool): True to skip non uniform distributions
423470
release_params (dict): optimized parameters
471+
skip_non_uniform (bool): True to skip non uniform distributions
424472
skip_channels_copy (bool): True to skip the copy pasting
425473
of the neuroml channel files
474+
custom_channel_ion (dict): dict mapping channel to ion
475+
custom_ion_erevs (dict): dict mapping ion to erev (reversal potential)
426476
"""
427477
concentrationModels = {}
428478

@@ -458,6 +508,8 @@ def get_biophys(
458508
skip_non_uniform,
459509
release_params,
460510
skip_channels_copy,
511+
custom_channel_ion,
512+
custom_ion_erevs,
461513
)
462514

463515
if density is not None:

bluepyopt/neuroml/cell.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,22 @@
2727
logger = logging.getLogger(__name__)
2828

2929

30-
def create_neuroml_cell(bpo_cell, release_params, skip_channels_copy=False):
30+
def create_neuroml_cell(
31+
bpo_cell,
32+
release_params,
33+
skip_channels_copy=False,
34+
custom_channel_ion=None,
35+
custom_ion_erevs=None,
36+
):
3137
"""Create the cell.
3238
3339
Arguments:
34-
nml_mech_files (list): paths to the nml files
35-
containing the mechanisms
36-
bpo_cell
40+
bpo_cell (ephys.CellModel): bluepyopt cell
3741
release_params (dict): the optimized parameters
3842
skip_channels_copy (bool): True to skip the copy pasting
3943
of the neuroml channel files
44+
custom_channel_ion (dict): dict mapping channel to ion
45+
custom_ion_erevs (dict): dict mapping ion to erev (reversal potential)
4046
4147
:returns: name of the cell nml file
4248
"""
@@ -76,6 +82,8 @@ def create_neuroml_cell(bpo_cell, release_params, skip_channels_copy=False):
7682
release_params,
7783
skip_non_uniform=True,
7884
skip_channels_copy=skip_channels_copy,
85+
custom_channel_ion=custom_channel_ion,
86+
custom_ion_erevs=custom_ion_erevs,
7987
)
8088

8189
# Append biophys to cell

bluepyopt/neuroml/morphology.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,15 @@
2828
def create_loadcell_hoc(
2929
loadcell_hoc_filename, hoc_filename, morphology_path, v_init, cell_name
3030
):
31-
"""Create a hoc file able to load the cell."""
31+
"""Create a hoc file able to load the cell.
32+
33+
Arguments:
34+
loadcell_hoc_filename (str): path to the loadcell hoc file to output
35+
hoc_filename (str): file name of the cell hoc file
36+
morphology_path (str): path to the morphology file
37+
v_init (float): inital voltage in mV
38+
cell_name (str): cell name
39+
"""
3240
morph_path = Path(morphology_path)
3341
morph_dir = morph_path.parent
3442
morph_file = morph_path.name
@@ -56,7 +64,13 @@ def create_loadcell_hoc(
5664

5765

5866
def create_morph_nml(bpo_cell, network_filename, release_params):
59-
"""Create cell hoc file, then cell nml file."""
67+
"""Create cell hoc file, then cell nml file.
68+
69+
Arguments:
70+
bpo_cell (ephys.CellModel): bluepyopt cell
71+
network_filename (str): name of the neuroml network file
72+
release_params (dict): name and values of optimised parameters
73+
"""
6074
import pebble
6175

6276
hoc_filename = f"{bpo_cell.name}.hoc"

examples/neuroml/neuroml.ipynb

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@
2929
]
3030
},
3131
{
32+
"attachments": {},
3233
"cell_type": "markdown",
3334
"id": "63d69fd0-dd92-424b-b38a-be50f03e3dd7",
3435
"metadata": {},
3536
"source": [
3637
"Note that the bluepyopt neuroml module cannot yet handle:\n",
3738
"- non uniform parameter\n",
38-
"- axon replacement"
39+
"- axon replacement\n",
40+
"- stochasticity"
3941
]
4042
},
4143
{
@@ -57,7 +59,6 @@
5759
"import sys\n",
5860
"\n",
5961
"from pyneuroml import pynml\n",
60-
"from bluepyopt.ephys import models\n",
6162
"from bluepyopt.neuroml import cell\n",
6263
"from bluepyopt.neuroml import simulation"
6364
]
@@ -174,7 +175,7 @@
174175
"- a neuroml cell file named after the bluepyopt cell's name: Here, `l5pc_0_0.cell.nml`.\n",
175176
"- a neuroml network file containing the neuroml cell, named after the bluepyopt cell's name. Here, `l5pc.net.nml`.\n",
176177
"\n",
177-
"Note that the `create_neuroml_cell` function is designed to work with the mechanisms present in `bluepyopt/neuroml/NeuroML2_mechanisms/` and will likely crash if you try to use it with custom mechanisms."
178+
"Skip this step if you want to use custom mechanisms not present in `bluepyopt/neuroml/NeuroML2_mechanisms/`."
178179
]
179180
},
180181
{
@@ -185,7 +186,38 @@
185186
"outputs": [],
186187
"source": [
187188
"cell.create_neuroml_cell(\n",
188-
" l5pc_cell, release_params, skip_channels_copy=False\n",
189+
" l5pc_cell, release_params, skip_channels_copy=False,\n",
190+
")"
191+
]
192+
},
193+
{
194+
"attachments": {},
195+
"cell_type": "markdown",
196+
"id": "a0db4c6b",
197+
"metadata": {},
198+
"source": [
199+
"If you want to create a neuroml cell with custom mechanisms that are not present in `bluepyopt/neuroml/NeuroML2_mechanisms/`, you will have to:\n",
200+
"- copy your custom mechanisms in the `.nml` format in the `./channels` directory\n",
201+
"- give as argument `custom_channel_ion`, a dict mapping channel name to ion name, e.g. `custom_channel_ion = {\"NaCustom\": \"na\"}`\n",
202+
"- if one of the ion in `custom_channel_ion` is not in pre-registered ions (na, k, hcn, ca, pas), you'll also have to give as argument `custom_ion_erevs`, a dict mapping ions to their reversal potential\n",
203+
"\n",
204+
"Below is an example of how to use the `create_neuroml_cell` function with custom mechanisms.\n",
205+
"\n",
206+
"However, be aware that `create_neuroml_cell` might not be able to deal with any given custom mechanism, and some might break it."
207+
]
208+
},
209+
{
210+
"cell_type": "code",
211+
"execution_count": null,
212+
"id": "adf01098",
213+
"metadata": {},
214+
"outputs": [],
215+
"source": [
216+
"custom_channel_ion = {\"Cl_custom_mech_name\": \"cl\"}\n",
217+
"custom_ion_erevs = {\"cl\": \"-60.0 mV\"}\n",
218+
"\n",
219+
"cell.create_neuroml_cell(\n",
220+
" l5pc_cell, release_params, skip_channels_copy=False, custom_channel_ion=custom_channel_ion, custom_ion_erevs=custom_ion_erevs,\n",
189221
")"
190222
]
191223
},
@@ -385,7 +417,7 @@
385417
"name": "python",
386418
"nbconvert_exporter": "python",
387419
"pygments_lexer": "ipython3",
388-
"version": "3.10.8"
420+
"version": "3.10.8 (main, Oct 13 2022, 10:17:43) [Clang 14.0.0 (clang-1400.0.29.102)]"
389421
},
390422
"vscode": {
391423
"interpreter": {

0 commit comments

Comments
 (0)