Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement LFPy backend #385

Merged
merged 51 commits into from
Dec 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
65a4855
Update doctsrings and minor changes
Feb 23, 2022
1459882
Clean LFPy port
alejoe91 Mar 1, 2022
819a553
docstrings
alejoe91 Mar 1, 2022
4547971
Merge with master
alejoe91 Mar 1, 2022
7c4bf9d
Merge branch 'master' into lfpy
wvangeit Mar 21, 2022
fba3f4f
Fix parameterscalerrs value
alejoe91 Mar 23, 2022
dc7cf86
Merge branch 'lfpy' of https://github.com/alejoe91/BluePyOpt into lfpy
alejoe91 Mar 23, 2022
1e0275e
rm workflow
alejoe91 Jul 21, 2022
ac16ef2
Merge branch 'master' into lfpy
wvangeit Jul 25, 2022
4b510a9
Add Dummy LFPy Cell and add lfpy stimuli tests
Jul 25, 2022
2f64d53
add lfpy simulator tests
Jul 25, 2022
34e1167
Add more lfpy model tests
Jul 25, 2022
bf5e7b7
add objectives tests
Jul 25, 2022
e4724be
fix typo
Jul 25, 2022
0749d97
add recording tests
Jul 25, 2022
00b7139
Add protocols tests
Jul 25, 2022
2708ba8
Merge branch 'master' of github.com:BlueBrain/BluePyOpt into lfpy
alejoe91 Jul 25, 2022
c555fee
param_dependancies -> param_dependEncies
alejoe91 Jul 25, 2022
98a7208
Merge branch 'lfpy' of github.com:alejoe91/BluePyOpt into lfpy
alejoe91 Jul 25, 2022
5ec9824
Fix typo
alejoe91 Jul 25, 2022
7925bc5
Add parameterscaler tests
Jul 26, 2022
d8a954b
Add test for extraFELFeature
Jul 26, 2022
f785619
Some refactoring
Jul 26, 2022
166c783
Add extra_features_utils tests with test data
Jul 26, 2022
0d0f5db
lint fix and mark extra_features_utils tests as unit tests
Jul 26, 2022
048ecf7
Merge branch 'lfpy' of https://github.com/alejoe91/BluePyOpt into lfp…
Jul 26, 2022
1c60a0c
Merge pull request #32 from AurelienJaquier/lfpy-add-tests
alejoe91 Jul 28, 2022
e8eeecb
Merge branch 'lfpy' of https://github.com/alejoe91/BluePyOpt into cle…
Jul 28, 2022
e2529da
fix tests
Jul 28, 2022
0b1fffc
use LFPy without mpi4py from special LFPy branch
Jul 28, 2022
55f94ae
improve syntax in extra_features_utils.py
Jul 28, 2022
1d4a64c
Turn pkl data file into npy file for py37 compatibility
Jul 29, 2022
eda3976
Fix expected value in test_lfpy_evaluator
Jul 29, 2022
cc39eef
Fix lfpy evaluator and lfpy test
Jul 29, 2022
3206e0d
improve lfpy evaluator example
Jul 29, 2022
1dbebd4
Improve lfpy example scripts
Jul 29, 2022
9de5202
Add LFPStimulus base class for lfp stimuli
Jul 29, 2022
2212a7a
small fix
Jul 29, 2022
84802f0
Fix instantiate arguments of LFPStimulus
Jul 29, 2022
efeb84a
Merge pull request #31 from alejoe91/cleaning
alejoe91 Jul 29, 2022
b139c64
Merge branch 'master' into lfpy
wvangeit Jul 29, 2022
bf60eaa
Add sim to LFPstimulus instantiate
alejoe91 Jul 29, 2022
c192c6a
Merge branch 'lfpy' of github.com:alejoe91/BluePyOpt into lfpy
alejoe91 Jul 29, 2022
79c9fc5
Small changes
Jul 29, 2022
d9bb8e5
Merge branch 'lfpy' of https://github.com/alejoe91/BluePyOpt into sma…
Jul 29, 2022
306c905
lint fixes
Jul 29, 2022
1363f71
fix stimuli test
Jul 29, 2022
d12dd08
Merge pull request #33 from alejoe91/small-changes
alejoe91 Aug 2, 2022
46dbc84
Merge branch 'master' of https://github.com/BlueBrain/BluePyOpt into …
Aug 22, 2022
2ab0c58
Install LFPy from master (no MPI needed)
alejoe91 Aug 23, 2022
1e56736
Merge branch 'master' into lfpy
wvangeit Dec 6, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
420 changes: 420 additions & 0 deletions bluepyopt/ephys/efeatures.py

Large diffs are not rendered by default.

500 changes: 500 additions & 0 deletions bluepyopt/ephys/extra_features_utils.py

Large diffs are not rendered by default.

316 changes: 314 additions & 2 deletions bluepyopt/ephys/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,6 @@ def create_empty_template(
''' % dict(template_name=template_name, objref_str=objref_str,
newseclist_str=newseclist_str,
create_str=create_str)

return template

@staticmethod
Expand Down Expand Up @@ -246,7 +245,8 @@ def instantiate(self, sim=None):

if self.params is not None:
for param in self.params.values():
param.instantiate(sim=sim, icell=self.icell)
param.instantiate(sim=sim, icell=self.icell,
params=self.params)

def destroy(self, sim=None): # pylint: disable=W0613
"""Destroy instantiated model in simulator"""
Expand Down Expand Up @@ -479,3 +479,315 @@ def load_hoc_template(sim, hoc_string):
'NEURON does not have template: ' + template_name

return template_name


class LFPyCellModel(Model):

"""LFPy.Cell model class"""

def __init__(
self,
name,
electrode=None,
morph=None,
mechs=None,
params=None,
dt=0.025,
v_init=-65.0,
gid=0,
seclist_names=None,
secarray_names=None,
):
"""Constructor

Args:
name (str): name of this object
should be alphanumeric string, underscores are allowed,
first char should be a letter
morph (Morphology):
underlying Morphology of the cell
mechs (list of Mechanisms):
Mechanisms associated with the cell
params (list of Parameters):
Parameters of the cell model
seclist_names (list of strings):
Names of the lists of sections
secarray_names (list of strings):
Names of the sections
"""
super(LFPyCellModel, self).__init__(name)
self.check_name()
self.morphology = morph
self.mechanisms = mechs
self.params = collections.OrderedDict()
if params is not None:
for param in params:
self.params[param.name] = param

# Cell instantiation in simulator
self.icell = None
self.lfpy_cell = None
self.electrode = electrode
self.lfpy_electrode = None

self.dt = dt
self.v_init = v_init

self.param_values = None
self.gid = gid

if seclist_names is None:
self.seclist_names = [
"all",
"somatic",
"basal",
"apical",
"axonal",
"myelinated",
]
else:
self.seclist_names = seclist_names

if secarray_names is None:
self.secarray_names = ["soma", "dend", "apic", "axon", "myelin"]
else:
self.secarray_names = secarray_names

def check_name(self):
"""Check if name complies with requirements"""

allowed_chars = string.ascii_letters + string.digits + "_"

if sys.version_info[0] < 3:
translate_args = [None, allowed_chars]
else:
translate_args = [str.maketrans("", "", allowed_chars)]

if (
self.name == ""
or self.name[0] not in string.ascii_letters
or not str(self.name).translate(*translate_args) == ""
):
raise TypeError(
'CellModel: name "%s" provided to constructor does not comply '
"with the rules for Neuron template name: name should be "
"alphanumeric "
"non-empty string, underscores are allowed, "
"first char should be letter" % self.name
)

def params_by_names(self, param_names):
"""Get parameter objects by name"""

return [self.params[param_name] for param_name in param_names]

def freeze(self, param_dict):
"""Set params"""

for param_name, param_value in param_dict.items():
self.params[param_name].freeze(param_dict[param_name])

def unfreeze(self, param_names):
"""Unset params"""

for param_name in param_names:
self.params[param_name].unfreeze()

@staticmethod
def create_empty_template(
template_name, seclist_names=None, secarray_names=None
):
"""create an hoc template named template_name for an empty cell"""

objref_str = "objref this, CellRef"
newseclist_str = ""

if seclist_names:
for seclist_name in seclist_names:
objref_str += ", %s" % seclist_name
newseclist_str += (
" %s = new SectionList()\n" % seclist_name
)

create_str = ""
if secarray_names:
create_str = "create "
create_str += ", ".join(
"%s[1]" % secarray_name for secarray_name in secarray_names
)
create_str += "\n"

template = """\
begintemplate %(template_name)s
%(objref_str)s
proc init() {\n%(newseclist_str)s
forall delete_section()
CellRef = this
}

gid = 0

proc destroy() {localobj nil
CellRef = nil
}

%(create_str)s
endtemplate %(template_name)s
""" % dict(
template_name=template_name,
objref_str=objref_str,
newseclist_str=newseclist_str,
create_str=create_str,
)

return template

@staticmethod
def create_empty_cell(name, sim, seclist_names=None, secarray_names=None):
"""Create an empty cell in Neuron"""

# TODO minize hardcoded definition
# E.g. sectionlist can be procedurally generated
hoc_template = CellModel.create_empty_template(
name, seclist_names, secarray_names
)
sim.neuron.h(hoc_template)

template_function = getattr(sim.neuron.h, name)

return template_function()

def instantiate(self, sim=None):
"""Instantiate model in simulator"""
from LFPy import Cell
from lfpykit import RecExtElectrode

# TODO replace this with the real template name
if not hasattr(sim.neuron.h, self.name):
self.icell = self.create_empty_cell(
self.name,
sim=sim,
seclist_names=self.seclist_names,
secarray_names=self.secarray_names,
)
else:
self.icell = getattr(sim.neuron.h, self.name)()

self.icell.gid = self.gid

self.morphology.instantiate(sim=sim, icell=self.icell)

self.lfpy_cell = Cell(
morphology=sim.neuron.h.allsec(),
dt=self.dt,
v_init=self.v_init,
pt3d=True,
delete_sections=False,
nsegs_method=None,
)

self.lfpy_electrode = RecExtElectrode(
self.lfpy_cell, probe=self.electrode
)

if self.mechanisms is not None:
for mechanism in self.mechanisms:
mechanism.instantiate(sim=sim, icell=self.icell)

if self.params is not None:
for param in self.params.values():
param.instantiate(sim=sim, icell=self.icell,
params=self.params)

def destroy(self, sim=None): # pylint: disable=W0613
"""Destroy instantiated model in simulator"""

# Make sure the icell's destroy() method is called
# without it a circular reference exists between CellRef and the object
# this prevents the icells from being garbage collected, and
# cell objects pile up in the simulator
self.icell.destroy()

# The line below is some M. Hines magic
# DON'T remove it, because it will make sure garbage collection
# is called on the icell object
sim.neuron.h.Vector().size()

self.icell = None

self.morphology.destroy(sim=sim)
for mechanism in self.mechanisms:
mechanism.destroy(sim=sim)
for param in self.params.values():
param.destroy(sim=sim)

def check_nonfrozen_params(self, param_names): # pylint: disable=W0613
"""Check if all nonfrozen params are set"""

for param_name, param in self.params.items():
if not param.frozen:
raise Exception(
"CellModel: Nonfrozen param %s needs to be "
"set before simulation" % param_name
)

def create_hoc(
self,
param_values,
ignored_globals=(),
template="cell_template.jinja2",
disable_banner=False,
template_dir=None,
):
"""Create hoc code for this model"""

to_unfreeze = []
for param in self.params.values():
if not param.frozen:
param.freeze(param_values[param.name])
to_unfreeze.append(param.name)

template_name = self.name
morphology = os.path.basename(self.morphology.morphology_path)
if self.morphology.do_replace_axon:
replace_axon = self.morphology.replace_axon_hoc
else:
replace_axon = None

ret = create_hoc.create_hoc(
mechs=self.mechanisms,
parameters=self.params.values(),
morphology=morphology,
ignored_globals=ignored_globals,
replace_axon=replace_axon,
template_name=template_name,
template_filename=template,
template_dir=template_dir,
disable_banner=disable_banner,
)

self.unfreeze(to_unfreeze)

return ret

def __str__(self):
"""Return string representation"""

content = "%s:\n" % self.name

content += " morphology:\n"

if self.morphology is not None:
content += " %s\n" % str(self.morphology)

content += " mechanisms:\n"
if self.mechanisms is not None:
for mechanism in self.mechanisms:
content += " %s\n" % mechanism

content += " params:\n"
if self.params is not None:
for param in self.params.values():
content += " %s\n" % param

return content
14 changes: 11 additions & 3 deletions bluepyopt/ephys/morphologies.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ class NrnFileMorphology(Morphology, DictMixin):

"""Morphology loaded from a file"""
SERIALIZED_FIELDS = ('morphology_path', 'do_replace_axon', 'do_set_nseg',
'replace_axon_hoc', )
'replace_axon_hoc', 'nseg_frequency',
'morph_modifiers', 'morph_modifiers_hoc',
'morph_modifiers_kwargs')

def __init__(
self,
Expand All @@ -53,7 +55,8 @@ def __init__(
replace_axon_hoc=None,
nseg_frequency=40,
morph_modifiers=None,
morph_modifiers_hoc=None):
morph_modifiers_hoc=None,
morph_modifiers_kwargs=None):
"""Constructor

Args:
Expand All @@ -73,6 +76,7 @@ def __init__(
with (sim, icell) as arguments
morph_modifiers_hoc (list): list of hoc strings corresponding
to morph_modifiers
morph_modifiers_kwargs (dict): kwargs for morph_modifiers functions
"""
name = os.path.basename(morphology_path)
super(NrnFileMorphology, self).__init__(name=name, comment=comment)
Expand All @@ -84,6 +88,9 @@ def __init__(
self.nseg_frequency = nseg_frequency
self.morph_modifiers = morph_modifiers
self.morph_modifiers_hoc = morph_modifiers_hoc
self.morph_modifiers_kwargs = morph_modifiers_kwargs
if self.morph_modifiers_kwargs is None:
self.morph_modifiers_kwargs = {}

if replace_axon_hoc is None:
self.replace_axon_hoc = self.default_replace_axon_hoc
Expand Down Expand Up @@ -146,7 +153,8 @@ def instantiate(self, sim=None, icell=None):

if self.morph_modifiers is not None:
for morph_modifier in self.morph_modifiers:
morph_modifier(sim=sim, icell=icell)
morph_modifier(sim=sim, icell=icell,
**self.morph_modifiers_kwargs)

def destroy(self, sim=None):
"""Destroy morphology instantiation"""
Expand Down
Loading