copying to personal repo
This commit is contained in:
12
cnmodel/morphology/__init__.py
Executable file
12
cnmodel/morphology/__init__.py
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Morphology definitions for models.
|
||||
#
|
||||
# This file includes readers for
|
||||
#
|
||||
# Paul B. Manis, Ph.D. 2009 (August - November 2009)
|
||||
#
|
||||
from neuron import h
|
||||
|
||||
from .morphology import Morphology
|
||||
from .hoc_reader import HocReader
|
||||
90
cnmodel/morphology/bushy_stick.hoc
Normal file
90
cnmodel/morphology/bushy_stick.hoc
Normal file
@@ -0,0 +1,90 @@
|
||||
objref soma
|
||||
soma = new SectionList()
|
||||
objref primarydendrite
|
||||
primarydendrite = new SectionList()
|
||||
objref secondarydendrite
|
||||
secondarydendrite = new SectionList()
|
||||
objref hillock
|
||||
hillock = new SectionList()
|
||||
objref unmyelinatedaxon
|
||||
unmyelinatedaxon = new SectionList()
|
||||
objref myelinatedaxon
|
||||
myelinatedaxon = new SectionList()
|
||||
|
||||
create sections[9]
|
||||
access sections[0]
|
||||
soma.append()
|
||||
sections[0] {
|
||||
pt3dadd(0., 0., 0., 25.)
|
||||
pt3dadd(0., 25., 0., 25.)
|
||||
}
|
||||
|
||||
// axon hillock, 15 microns long, tapered
|
||||
access sections[1]
|
||||
hillock.append()
|
||||
connect sections[1](0), sections[0](0)
|
||||
sections[1] {
|
||||
pt3dadd(0., 0., 0., 2.5)
|
||||
pt3dadd(0., -15., 0., 1.0)
|
||||
}
|
||||
|
||||
// initial segment, unmyelinated, 10 microns long, not tapering
|
||||
access sections[2]
|
||||
unmyelinatedaxon.append()
|
||||
connect sections[2](0), sections[1](1)
|
||||
sections[2] {
|
||||
pt3dadd(0., -15., 0., 1.0)
|
||||
pt3dadd(0., -25., 0., 1.0)
|
||||
|
||||
}
|
||||
|
||||
// beginning of myelinated axon, 20 micron, enlarging with distance
|
||||
access sections[3]
|
||||
myelinatedaxon.append()
|
||||
connect sections[3](0), sections[2](1)
|
||||
sections[3] {
|
||||
pt3dadd(0., -25., 0., 1.0)
|
||||
pt3dadd(0., -45., 0., 2.0)
|
||||
|
||||
}
|
||||
|
||||
access sections[4]
|
||||
primarydendrite.append()
|
||||
connect sections[4](0), sections[0](1)
|
||||
sections[4] {
|
||||
pt3dadd(0., 25., 0., 3.0)
|
||||
pt3dadd(0., 45., 0., 2.0)
|
||||
}
|
||||
|
||||
access sections[5]
|
||||
secondarydendrite.append()
|
||||
connect sections[5](0), sections[4](1)
|
||||
sections [5] {
|
||||
pt3dadd(0., 45., 0., 2.0)
|
||||
pt3dadd(0., 55., -50., 1.5)
|
||||
}
|
||||
|
||||
access sections[6]
|
||||
secondarydendrite.append()
|
||||
connect sections[6](0), sections[4](1)
|
||||
sections [6] {
|
||||
pt3dadd(0., 45., 0., 2.0)
|
||||
pt3dadd(0., 55., 50., 1.5)
|
||||
}
|
||||
|
||||
access sections[7]
|
||||
secondarydendrite.append()
|
||||
connect sections[7](0), sections[4](1)
|
||||
sections [7] {
|
||||
pt3dadd(0., 45., 0., 2.0)
|
||||
pt3dadd(-50., 55., 0., 1.5)
|
||||
}
|
||||
|
||||
access sections[8]
|
||||
secondarydendrite.append()
|
||||
connect sections[8](0), sections[4](1)
|
||||
sections [8] {
|
||||
pt3dadd(0., 45., 0., 2.0)
|
||||
pt3dadd(50., 55., 0, 1.5)
|
||||
}
|
||||
|
||||
622
cnmodel/morphology/hoc_reader.py
Normal file
622
cnmodel/morphology/hoc_reader.py
Normal file
@@ -0,0 +1,622 @@
|
||||
from __future__ import print_function
|
||||
from neuron import h
|
||||
import neuron
|
||||
import collections
|
||||
import numpy as np
|
||||
import pyqtgraph as pg
|
||||
import os
|
||||
import re
|
||||
import os.path
|
||||
|
||||
try:
|
||||
basestring
|
||||
except NameError:
|
||||
basestring = str
|
||||
|
||||
|
||||
class HocReader(object):
|
||||
def __init__(self, hoc):
|
||||
"""
|
||||
Provides useful methods for reading hoc structures.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
hoc : :obj: `hoc` or str
|
||||
Either a hoc object that hs been already created, or a string that defines a hoc file name.
|
||||
"""
|
||||
|
||||
self.file_loaded = False
|
||||
if isinstance(hoc, basestring):
|
||||
fullfile = os.path.join(os.getcwd(), hoc)
|
||||
if not os.path.isfile(fullfile):
|
||||
raise Exception("File not found: %s" % (fullfile))
|
||||
neuron.h.hoc_stdout(
|
||||
"/dev/null"
|
||||
) # prevent junk from printing while reading the file
|
||||
success = neuron.h.load_file(str(fullfile))
|
||||
neuron.h.hoc_stdout()
|
||||
if success == 0: # indicates failure to read the file
|
||||
raise NameError("Found file, but NEURON load failed: %s" % (fullfile))
|
||||
self.file_loaded = True
|
||||
self.h = h # save a copy of the hoc object itself.
|
||||
else:
|
||||
self.h = hoc # just use the passed argument
|
||||
self.file_loaded = True
|
||||
|
||||
# geometry containers
|
||||
self.edges = None
|
||||
self.vertexes = None
|
||||
|
||||
# all sections in the hoc {sec_name: hoc Section}
|
||||
self.sections = collections.OrderedDict()
|
||||
# {sec_name: index} indicates index into self.sections.values() where
|
||||
# Section can be found.
|
||||
self.sec_index = {}
|
||||
# {sec_name: [mechanism, ...]}
|
||||
self.mechanisms = collections.OrderedDict()
|
||||
# {sec_group_name: set(sec_name, ...)}
|
||||
self.sec_groups = {}
|
||||
|
||||
# topology {section: (parent, [children,...])}
|
||||
self.topology = {}
|
||||
|
||||
# populate self.sections, self.sec_index, and self.mechanisms
|
||||
self.read_section_info()
|
||||
|
||||
# auto-generate section groups based on either hoc section lists, or
|
||||
# on section name prefixes.
|
||||
sec_lists = self.get_section_lists()
|
||||
sec_prefixes = self.get_section_prefixes()
|
||||
|
||||
# Add groupings by section list if possible:
|
||||
if len(sec_lists) > 1:
|
||||
self.add_groups_by_section_list(sec_lists)
|
||||
|
||||
# Otherwise, try section prefixes
|
||||
elif len(sec_prefixes) > 1:
|
||||
for group, sections in sec_prefixes.items():
|
||||
self.add_section_group(group, sections)
|
||||
|
||||
# generate topology
|
||||
self._generate_topology()
|
||||
|
||||
def get_section(self, sec_name):
|
||||
"""
|
||||
Get the section associated with the section name
|
||||
|
||||
Parameters
|
||||
----------
|
||||
sec_name : str
|
||||
The name of the section object.
|
||||
|
||||
Returns
|
||||
-------
|
||||
The hoc Section object with the given name.
|
||||
|
||||
"""
|
||||
try:
|
||||
return self.sections[sec_name]
|
||||
except KeyError:
|
||||
raise KeyError("No section named '%s'" % sec_name)
|
||||
|
||||
def get_section_prefixes(self):
|
||||
"""
|
||||
Go through all the sections and generate a dictionary mapping their
|
||||
name prefixes to the list of sections with that prefix.
|
||||
|
||||
For example, with sections names axon[0], axon[1], ais[0], and soma[0],
|
||||
we would generate the following structure:
|
||||
|
||||
{'axon': ['axon[0]', 'axon[1]'],
|
||||
'ais': ['ais[0]'],
|
||||
'soma': ['soma[0]']}
|
||||
"""
|
||||
prefixes = {}
|
||||
regex = re.compile("(?P<prefix>\w+)\[(\d*)\]")
|
||||
for sec_name in self.sections:
|
||||
g = regex.match(sec_name)
|
||||
if g is None:
|
||||
continue
|
||||
prefix = g.group("prefix")
|
||||
prefixes.setdefault(prefix, []).append(sec_name)
|
||||
return prefixes
|
||||
|
||||
def get_mechanisms(self, section):
|
||||
"""
|
||||
Get a set of all of the mechanisms inserted into a given section
|
||||
|
||||
Parameters
|
||||
----------
|
||||
section : :obj: `NEURON section`
|
||||
The NEURON section object.
|
||||
|
||||
Returns
|
||||
-------
|
||||
A list of mechanism names
|
||||
|
||||
"""
|
||||
return self.mechanisms[section]
|
||||
|
||||
def get_density(self, section, mechanism):
|
||||
"""
|
||||
Get density mechanism that may be found the section.
|
||||
mechanism is a list ['name', 'gbarname']. This is needed because
|
||||
some mechanisms do not adhere to any convention and may have a different
|
||||
kind of 'gbarname' than 'gbar<name>_mechname'
|
||||
returns the average of the conductance density, as that may range across different
|
||||
values in a section (e.g., can vary by segments)
|
||||
|
||||
Parameters
|
||||
----------
|
||||
section : :obj: `NEURON section`
|
||||
The NEURON section object.
|
||||
mechanism : list
|
||||
mechanism is a list ['name', 'gbarname']. It is used to
|
||||
retrieve the mechanism density from HOC as
|
||||
`segment.name.gbarname`.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Mean conductance of the selected mechanism in the section, averaged across all segments of the section.
|
||||
"""
|
||||
|
||||
gmech = []
|
||||
for seg in section:
|
||||
try:
|
||||
x = getattr(seg, mechanism[0])
|
||||
mecbar = "%s_%s" % (mechanism[1], mechanism[0])
|
||||
if mecbar in dir(x):
|
||||
gmech.append(getattr(x, mechanism[1]))
|
||||
else:
|
||||
print(
|
||||
"hoc_reader:get_density did not find the mechanism in dir x",
|
||||
dir(x),
|
||||
)
|
||||
except NameError:
|
||||
return 0.0
|
||||
except:
|
||||
print("hoc_reader:get_density failed to evaluate the mechanisms... ")
|
||||
raise
|
||||
|
||||
# print gmech
|
||||
if len(gmech) == 0:
|
||||
gmech = 0.0
|
||||
return np.mean(gmech)
|
||||
|
||||
def get_sec_info(self, section, html=False):
|
||||
"""
|
||||
Get the info of the given section
|
||||
modified from: neuronvisio
|
||||
|
||||
Parameters
|
||||
----------
|
||||
section : :obj: `NEURON section`
|
||||
The NEURON section object.
|
||||
|
||||
Returns
|
||||
-------
|
||||
str
|
||||
containing the information, with html formatting.
|
||||
"""
|
||||
if html:
|
||||
br = " <b>"
|
||||
bre = "</b>"
|
||||
lbrk = "<br/>"
|
||||
li = "<li>"
|
||||
lie = "</li>"
|
||||
else:
|
||||
br = " "
|
||||
bre = ""
|
||||
li = ""
|
||||
lie = ""
|
||||
lbrk = "\n"
|
||||
info = f"{br:s}Section Name:{bre:s} {section.name():s}{lbrk:s}"
|
||||
info += f"{br:s}Length [um]:{bre:s} {section.L:f}{lbrk:s}"
|
||||
info += f"{br:s}Diameter [um]:{bre:s} {section.diam:f}{lbrk:s}"
|
||||
info += f"{br:s}Membrane Capacitance:{bre:s} {section.cm:f}{lbrk:s}"
|
||||
info += f"{br:s}Axial Resistance :{bre:s} {section.Ra:f}{lbrk:s}"
|
||||
info += f"{br:s}Number of Segments:{bre:s} {section.nseg:f}{lbrk:s}"
|
||||
mechs = []
|
||||
for seg in section:
|
||||
for mech in seg:
|
||||
mechs.append(mech.name())
|
||||
mechs = set(mechs) # Excluding the repeating ones
|
||||
|
||||
mech_info = f"{br:s}Mechanisms in the section{bre:s}{lbrk:s}"
|
||||
for mech_name in mechs:
|
||||
s = f"{li:s} {mech_name:s} {lie:s}"
|
||||
mech_info += s
|
||||
info += mech_info
|
||||
return info
|
||||
|
||||
def read_section_info(self):
|
||||
"""
|
||||
Read all the information about the sections in the current hoc file
|
||||
Stores the result in the mechanisms class variable.
|
||||
"""
|
||||
# Collect list of all sections and their mechanism names.
|
||||
self.sections = collections.OrderedDict()
|
||||
self.mechanisms = collections.OrderedDict()
|
||||
for i, sec in enumerate(self.h.allsec()):
|
||||
self.sections[sec.name()] = sec
|
||||
self.sec_index[sec.name()] = i
|
||||
mechs = set()
|
||||
for seg in sec:
|
||||
for mech in seg:
|
||||
mechs.add(mech.name())
|
||||
self.mechanisms[sec.name()] = mechs
|
||||
|
||||
def hoc_namespace(self):
|
||||
"""
|
||||
Get a dict of the HOC namespace {'variable_name': hoc_object}.
|
||||
NOTE: this method requires NEURON >= 7.3
|
||||
"""
|
||||
names = {}
|
||||
for hvar in dir(self.h): # look through the whole list, no other way
|
||||
try:
|
||||
# some variables can't be pointed to...
|
||||
if hvar in [
|
||||
"nseg",
|
||||
"diam_changed",
|
||||
"nrn_shape_changed_",
|
||||
"secondorder",
|
||||
"stoprun",
|
||||
]:
|
||||
continue
|
||||
u = getattr(self.h, hvar)
|
||||
names[hvar] = u
|
||||
except:
|
||||
continue
|
||||
return names
|
||||
|
||||
def find_hoc_hname(self, regex):
|
||||
"""
|
||||
Find hoc names matching a pattern
|
||||
|
||||
Parameters
|
||||
----------
|
||||
regex : str
|
||||
Regular expression (Python Re module) to search for.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list
|
||||
The names of HOC objects whose *hname* matches regex.
|
||||
"""
|
||||
objs = []
|
||||
ns = self.hoc_namespace()
|
||||
for n, v in ns.items():
|
||||
try:
|
||||
hname = v.hname()
|
||||
if re.match(regex, hname):
|
||||
objs.append(n)
|
||||
except:
|
||||
continue
|
||||
return objs
|
||||
|
||||
def add_section_group(self, name, sections, overwrite=False):
|
||||
"""
|
||||
Declare a grouping of sections (or section names). Sections may be
|
||||
grouped by any arbitrary criteria (cell, anatomical type, etc).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
name of the section group
|
||||
sections: list
|
||||
section names or hoc Section objects.
|
||||
|
||||
"""
|
||||
if name in self.sec_groups and not overwrite:
|
||||
raise Exception(
|
||||
"Group name %s is already used (use overwrite=True)." % name
|
||||
)
|
||||
|
||||
group = set()
|
||||
for sec in sections:
|
||||
if not isinstance(sec, basestring):
|
||||
sec = sec.name()
|
||||
group.add(sec)
|
||||
self.sec_groups[name] = group
|
||||
|
||||
def get_section_group(self, name):
|
||||
"""
|
||||
Get a section group by name
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
name of the group (dendrite, for example)
|
||||
|
||||
Returns
|
||||
-------
|
||||
The set of section names in the group *name*.
|
||||
|
||||
"""
|
||||
return self.sec_groups[name]
|
||||
|
||||
def get_section_lists(self):
|
||||
"""
|
||||
Search through all of the hoc variables to find those that are "SectionLists"
|
||||
"""
|
||||
return self.find_hoc_hname(regex=r"SectionList\[")
|
||||
# ns = self.hoc_namespace()
|
||||
# return [name for name in ns if ns[name].hname().startswith('SectionList[')]
|
||||
|
||||
def add_groups_by_section_list(self, names):
|
||||
"""
|
||||
Add a new section groups from the hoc variables indicated in *names*.
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
names : list
|
||||
List containing variable names as strings. Each name must refer to a list of
|
||||
Sections in hoc. If a dict is supplied instead, then it
|
||||
maps {hoc_list_name: section_group_name}.
|
||||
|
||||
Side effects (modifies)
|
||||
-----------------------
|
||||
calls add_section_group
|
||||
|
||||
"""
|
||||
# if a list is supplied, then the names of groups to create are
|
||||
# exactly the same as the names of hoc lists.
|
||||
if not isinstance(names, dict):
|
||||
names = {name: name for name in names}
|
||||
for hoc_name, group_name in names.items():
|
||||
var = getattr(self.h, hoc_name)
|
||||
self.add_section_group(group_name, list(var))
|
||||
|
||||
def get_geometry(self):
|
||||
"""
|
||||
modified from:neuronvisio
|
||||
Generate structures that describe the geometry of the sections and their segments (all segments are returned)
|
||||
|
||||
Returns
|
||||
-------
|
||||
vertexes : record array containing {pos: (x,y,z), dia, sec_id}
|
||||
for each segment.
|
||||
edges : array of pairs indicating the indexes of connected
|
||||
vertexes.
|
||||
Side effects
|
||||
------------
|
||||
Modifies vertexes and edges.
|
||||
|
||||
"""
|
||||
|
||||
# return cached geometry if this method has already run.
|
||||
if self.vertexes is not None:
|
||||
return self.vertexes, self.edges
|
||||
|
||||
self.h.define_shape()
|
||||
|
||||
# map segments (lines) to the section that contains them
|
||||
self.segment_to_section = {}
|
||||
|
||||
vertexes = []
|
||||
connections = []
|
||||
|
||||
for secid, sec in enumerate(self.sections.values()):
|
||||
x_sec, y_sec, z_sec, d_sec = self.retrieve_coordinate(sec)
|
||||
|
||||
for i, xi in enumerate(x_sec):
|
||||
vertexes.append(((x_sec[i], y_sec[i], z_sec[i]), d_sec[i], secid))
|
||||
indx_geom_seg = len(vertexes) - 1
|
||||
if len(vertexes) > 1 and i > 0:
|
||||
connections.append([indx_geom_seg, indx_geom_seg - 1])
|
||||
|
||||
self.edges = np.array(connections)
|
||||
self.vertexes = np.empty(
|
||||
len(vertexes), dtype=[("pos", float, 3), ("dia", float), ("sec_index", int)]
|
||||
)
|
||||
self.vertexes[:] = vertexes
|
||||
return self.vertexes, self.edges
|
||||
|
||||
def retrieve_coordinate(self, section):
|
||||
"""Retrieve the coordinates of a section avoiding duplicates
|
||||
|
||||
Parameters
|
||||
----------
|
||||
section : :obj: `NEURON section`
|
||||
The NEURON section object.
|
||||
|
||||
Returns
|
||||
-------
|
||||
array
|
||||
arrays of x, y, z, d for all the segments of the specified section.
|
||||
|
||||
"""
|
||||
|
||||
section.push()
|
||||
x, y, z, d = [], [], [], []
|
||||
|
||||
tot_points = 0
|
||||
connect_next = False
|
||||
for i in range(int(self.h.n3d())):
|
||||
present = False
|
||||
x_i = self.h.x3d(i)
|
||||
y_i = self.h.y3d(i)
|
||||
z_i = self.h.z3d(i)
|
||||
d_i = self.h.diam3d(i)
|
||||
# Avoiding duplicates in the sec
|
||||
if x_i in x:
|
||||
ind = len(x) - 1 - x[::-1].index(x_i) # Getting the index of last value
|
||||
if y_i == y[ind]:
|
||||
if z_i == z[ind]:
|
||||
present = True
|
||||
|
||||
if not present:
|
||||
k = (x_i, y_i, z_i)
|
||||
x.append(x_i)
|
||||
y.append(y_i)
|
||||
z.append(z_i)
|
||||
d.append(d_i)
|
||||
self.h.pop_section()
|
||||
return (np.array(x), np.array(y), np.array(z), np.array(d))
|
||||
|
||||
def _generate_topology(self):
|
||||
for name, sec in self.sections.items():
|
||||
sref = self.h.SectionRef(sec=sec)
|
||||
parent = sref.parent().sec.name() if sref.has_parent() else None
|
||||
if name not in self.topology:
|
||||
self.topology[name] = [None, []]
|
||||
self.topology[name][0] = parent
|
||||
if parent is not None:
|
||||
if parent not in self.topology:
|
||||
self.topology[parent] = [None, []]
|
||||
self.topology[parent][1].append(name)
|
||||
|
||||
def get_branch(self, root):
|
||||
"""
|
||||
Return all sections in a branch, starting with root.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
root : :obj: `NEURON section`
|
||||
The NEURON section object.
|
||||
|
||||
"""
|
||||
branch = [root]
|
||||
childs = [root]
|
||||
while len(childs) > 0:
|
||||
new_childs = []
|
||||
for ch in childs:
|
||||
new_childs.extend(self.topology[ch][1])
|
||||
childs = new_childs
|
||||
branch.extend(childs)
|
||||
return branch
|
||||
|
||||
def translate_branch(self, root, dx):
|
||||
"""
|
||||
Move the branch beginning at *root* by *dx*.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
root : :obj: `NEURON section`
|
||||
The NEURON section object.
|
||||
dx : array
|
||||
Which must be an array of length 3 defining the translation.
|
||||
|
||||
"""
|
||||
self.get_geometry()
|
||||
dx[np.newaxis, :]
|
||||
for name in self.get_branch(root):
|
||||
sid = self.sec_index[name]
|
||||
mask = self.vertexes["sec_index"] == sid
|
||||
self.vertexes["pos"][mask] += dx
|
||||
|
||||
def make_volume_data(self, resolution=1.0, max_size=500e6):
|
||||
"""
|
||||
Using the current state of vertexes, edges, generates a scalar field
|
||||
useful for building isosurface or volumetric renderings.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
resolution: float, default=1.0 microns
|
||||
width (um) of a single voxel in the scalar field.
|
||||
max_size: int
|
||||
maximum allowed scalar field size (bytes).
|
||||
Returns
|
||||
-------
|
||||
* 3D scalar field indicating distance from nearest membrane,
|
||||
* 3D field indicating section IDs of nearest membrane,
|
||||
* QTransform that maps from 3D array indexes to original vertex
|
||||
coordinates.
|
||||
"""
|
||||
vertexes, lines = self.get_geometry()
|
||||
|
||||
maxdia = vertexes["dia"].max() # maximum diameter (defines shape of kernel)
|
||||
kernel_size = int(maxdia / resolution) + 3 # width of kernel
|
||||
|
||||
# read vertex data
|
||||
pos = vertexes["pos"]
|
||||
d = vertexes["dia"]
|
||||
sec_id = vertexes["sec_index"]
|
||||
|
||||
# decide on dimensions of scalar field
|
||||
mx = pos.max(axis=0)
|
||||
mn = pos.min(axis=0)
|
||||
diff = mx - mn
|
||||
shape = tuple((diff / resolution + kernel_size).astype(int))
|
||||
|
||||
# prepare blank scalar field for drawing
|
||||
size = np.dtype(np.float32).itemsize * shape[0] * shape[1] * shape[2]
|
||||
if size > max_size:
|
||||
raise Exception(
|
||||
"Scalar field would be larger than max_size (%dMB > %dMB), resolution is%f"
|
||||
% (size / 1e6, max_size / 1e6, resolution)
|
||||
)
|
||||
scfield = np.zeros(shape, dtype=np.float32)
|
||||
scfield[:] = -1000
|
||||
|
||||
# array for holding IDs of sections that contribute to each area
|
||||
idfield = np.empty(shape, dtype=int)
|
||||
idfield[:] = -1
|
||||
|
||||
# map vertex locations to voxels
|
||||
vox_pos = pos.copy()
|
||||
vox_pos -= mn.reshape((1, 3))
|
||||
vox_pos *= 1.0 / resolution
|
||||
|
||||
# Define kernel used to draw scalar field along dendrites
|
||||
def cone(i, j, k):
|
||||
# value decreases linearly with distance from center of kernel.
|
||||
w = kernel_size / 2
|
||||
return w - ((i - w) ** 2 + (j - w) ** 2 + (k - w) ** 2) ** 0.5
|
||||
|
||||
kernel = resolution * np.fromfunction(cone, (kernel_size,) * 3)
|
||||
kernel -= kernel.max()
|
||||
|
||||
def array_intersection(arr1, arr2, pos):
|
||||
"""
|
||||
Return slices used to access the overlapping area between two
|
||||
arrays that are offset such that the origin of *arr2* is a *pos*
|
||||
relative to *arr1*.
|
||||
"""
|
||||
s1 = [0] * 3
|
||||
s2 = [0] * 3
|
||||
t1 = [0] * 3
|
||||
t2 = [0] * 3
|
||||
pos = map(int, pos)
|
||||
for axis in range(3):
|
||||
s1[axis] = max(0, -pos[axis])
|
||||
s2[axis] = min(arr2.shape[axis], arr1.shape[axis] - pos[axis])
|
||||
t1[axis] = max(0, pos[axis])
|
||||
t2[axis] = min(arr1.shape[axis], pos[axis] + arr2.shape[axis])
|
||||
slice1 = (slice(t1[0], t2[0]), slice(t1[1], t2[1]), slice(t1[2], t2[2]))
|
||||
slice2 = (slice(s1[0], s2[0]), slice(s1[1], s2[1]), slice(s1[2], s2[2]))
|
||||
return slice1, slice2
|
||||
|
||||
# Draw lines into volume using *kernel* as the brush
|
||||
vox_pos[:, 0] = np.clip(vox_pos[:, 0], 0, scfield.shape[0] - 1)
|
||||
vox_pos[:, 1] = np.clip(vox_pos[:, 1], 0, scfield.shape[1] - 1)
|
||||
vox_pos[:, 2] = np.clip(vox_pos[:, 2], 0, scfield.shape[2] - 1)
|
||||
for c in range(lines.shape[0]):
|
||||
i = lines[c, 0]
|
||||
j = lines[c, 1]
|
||||
p1 = vox_pos[i].copy()
|
||||
p2 = vox_pos[j].copy()
|
||||
diff = p2 - p1
|
||||
axis = np.argmax(np.abs(diff))
|
||||
dia = d[i]
|
||||
nvoxels = abs(int(diff[axis])) + 1
|
||||
for k in range(nvoxels):
|
||||
kern = kernel + (dia / 2.0)
|
||||
sl1, sl2 = array_intersection(
|
||||
scfield, kern, p1
|
||||
) # find the overlapping area between the field and the kernel
|
||||
idfield[sl1] = np.where(
|
||||
scfield[sl1] > kern[sl2], idfield[sl1], sec_id[i]
|
||||
)
|
||||
scfield[sl1] = np.where(
|
||||
scfield[sl1] > kern[sl2], scfield[sl1], kern[sl2]
|
||||
)
|
||||
dia += (d[j] - d[i]) / nvoxels
|
||||
p1 += diff / nvoxels
|
||||
|
||||
# return transform relating volume data to original vertex data
|
||||
transform = pg.Transform3D()
|
||||
w = resolution * kernel_size / 2 # offset introduced due to kernel
|
||||
transform.translate(*(mn - w))
|
||||
transform.scale(resolution, resolution, resolution)
|
||||
transform.translate(1, 1, 1)
|
||||
return scfield, idfield, transform
|
||||
31
cnmodel/morphology/morphology.py
Normal file
31
cnmodel/morphology/morphology.py
Normal file
@@ -0,0 +1,31 @@
|
||||
class Morphology(object):
|
||||
"""
|
||||
Base class for morphological structure
|
||||
Provides the ability to read .hoc files for NEURON simulations.
|
||||
|
||||
"""
|
||||
|
||||
def init():
|
||||
pass
|
||||
|
||||
def hocReader(self, filename=None):
|
||||
"""
|
||||
Access the hoc reader
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str (default: None)
|
||||
The hoc file to read and save as the morphology object
|
||||
"""
|
||||
self.morphology = hoc_reader(hoc=filename)
|
||||
|
||||
def swcReader(self, filename=None):
|
||||
"""
|
||||
Access the swc reader (***NOT IMPLEMENTED***)
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str (default: None)
|
||||
The swc file to read and save as the morphology object
|
||||
"""
|
||||
raise ValueError("swcReader not implmented.")
|
||||
76
cnmodel/morphology/octopus_spencer_stick.hoc
Normal file
76
cnmodel/morphology/octopus_spencer_stick.hoc
Normal file
@@ -0,0 +1,76 @@
|
||||
// Octopus cell, stick representation
|
||||
// From Spencer et al., Front. Comput. Neurosci., 22 October 2012 | https://doi.org/10.3389/fncom.2012.00083
|
||||
// Figure 1.
|
||||
|
||||
objref soma
|
||||
soma = new SectionList()
|
||||
objref primarydendrite
|
||||
primarydendrite = new SectionList()
|
||||
objref hillock
|
||||
hillock = new SectionList()
|
||||
objref unmyelinatedaxon
|
||||
unmyelinatedaxon = new SectionList()
|
||||
|
||||
create sections[7]
|
||||
|
||||
access sections[0]
|
||||
soma.append()
|
||||
sections[0] {
|
||||
pt3dadd(0., 0., 0., 25.)
|
||||
pt3dadd(0., 25., 0., 25.)
|
||||
}
|
||||
|
||||
// axon hillock, 30 microns long, untapered
|
||||
access sections[1]
|
||||
hillock.append()
|
||||
connect sections[1](0), sections[0](0)
|
||||
sections[1] {
|
||||
pt3dadd(0., 0., 0., 3)
|
||||
pt3dadd(0., -30., 0., 3)
|
||||
}
|
||||
|
||||
// initial segment, unmyelinated, 10 microns long, not tapering
|
||||
access sections[2]
|
||||
unmyelinatedaxon.append()
|
||||
connect sections[2](0), sections[1](1)
|
||||
sections[2] {
|
||||
pt3dadd(0., -30., 0., 3.0)
|
||||
pt3dadd(0., -32., 0., 3.0)
|
||||
}
|
||||
|
||||
// angle dendrites out a bit from original model for visibility, so
|
||||
// length for 20 u end deviation is 279.285 um, end pos 304.285
|
||||
|
||||
access sections[3]
|
||||
primarydendrite.append()
|
||||
connect sections[3](0), sections[0](1)
|
||||
sections[3] {
|
||||
pt3dadd(0., 25., 0., 3)
|
||||
pt3dadd(20., 304.285, 0., 3)
|
||||
}
|
||||
|
||||
access sections[4]
|
||||
primarydendrite.append()
|
||||
connect sections[4](0), sections[0](1)
|
||||
sections [4] {
|
||||
pt3dadd(0., 25., 0., 3)
|
||||
pt3dadd(0., 304.285, 20., 3)
|
||||
}
|
||||
|
||||
access sections[5]
|
||||
primarydendrite.append()
|
||||
connect sections[5](0), sections[0](1)
|
||||
sections [5] {
|
||||
pt3dadd(0., 25., 0., 3)
|
||||
pt3dadd(-20., 304.285, 0., 3)
|
||||
}
|
||||
|
||||
access sections[6]
|
||||
primarydendrite.append()
|
||||
connect sections[6](0), sections[0](1)
|
||||
sections [6] {
|
||||
pt3dadd(0., 25., 0., 3)
|
||||
pt3dadd(0., 304.285, -20., 3)
|
||||
}
|
||||
|
||||
|
||||
82
cnmodel/morphology/tstellate_stick.hoc
Normal file
82
cnmodel/morphology/tstellate_stick.hoc
Normal file
@@ -0,0 +1,82 @@
|
||||
objref soma
|
||||
soma = new SectionList()
|
||||
objref primarydendrite
|
||||
primarydendrite = new SectionList()
|
||||
objref secondarydendrite
|
||||
secondarydendrite = new SectionList()
|
||||
objref hillock
|
||||
hillock = new SectionList()
|
||||
objref unmyelinatedaxon
|
||||
unmyelinatedaxon = new SectionList()
|
||||
objref myelinatedaxon
|
||||
myelinatedaxon = new SectionList()
|
||||
|
||||
create sections[8]
|
||||
access sections[0]
|
||||
soma.append()
|
||||
sections[0] {
|
||||
pt3dadd(0., 0., 0., 25.)
|
||||
pt3dadd(0., 25., 0., 25.)
|
||||
}
|
||||
|
||||
// axon hillock, 15 microns long, tapered
|
||||
access sections[1]
|
||||
hillock.append()
|
||||
connect sections[1](0), sections[0](0)
|
||||
sections[1] {
|
||||
pt3dadd(0., 0., 0., 2.5)
|
||||
pt3dadd(0., -15., 0., 1.0)
|
||||
}
|
||||
|
||||
// initial segment, unmyelinated, 10 microns long, not tapering
|
||||
access sections[2]
|
||||
unmyelinatedaxon.append()
|
||||
connect sections[2](0), sections[1](1)
|
||||
sections[2] {
|
||||
pt3dadd(0., -15., 0., 1.0)
|
||||
pt3dadd(0., -25., 0., 1.0)
|
||||
|
||||
}
|
||||
|
||||
// beginning of myelinated axon, 20 micron, enlarging with distance
|
||||
access sections[3]
|
||||
myelinatedaxon.append()
|
||||
connect sections[3](0), sections[2](1)
|
||||
sections[3] {
|
||||
pt3dadd(0., -25., 0., 1.0)
|
||||
pt3dadd(0., -45., 0., 2.0)
|
||||
|
||||
}
|
||||
|
||||
access sections[4]
|
||||
primarydendrite.append()
|
||||
connect sections[4](0), sections[0](1)
|
||||
sections[4] {
|
||||
pt3dadd(0., 25., 0., 2)
|
||||
pt3dadd(125., 25., 25., 1.5)
|
||||
}
|
||||
|
||||
access sections[5]
|
||||
primarydendrite.append()
|
||||
connect sections[5](0), sections[0](1)
|
||||
sections [5] {
|
||||
pt3dadd(0., 25., 0., 2.0)
|
||||
pt3dadd(-125., 25., 25., 1.5)
|
||||
}
|
||||
|
||||
access sections[6]
|
||||
primarydendrite.append()
|
||||
connect sections[6](0), sections[0](1)
|
||||
sections [6] {
|
||||
pt3dadd(0., 25., 0., 2.0)
|
||||
pt3dadd(125, 25., -25., 1.5)
|
||||
}
|
||||
|
||||
access sections[7]
|
||||
primarydendrite.append()
|
||||
connect sections[7](0), sections[0](1)
|
||||
sections [7] {
|
||||
pt3dadd(0., 25., 0., 2.0)
|
||||
pt3dadd(-125., 25., -25., 1.5)
|
||||
}
|
||||
|
||||
32
cnmodel/morphology/tv_stick.hoc
Normal file
32
cnmodel/morphology/tv_stick.hoc
Normal file
@@ -0,0 +1,32 @@
|
||||
objref soma
|
||||
soma = new SectionList()
|
||||
objref axon
|
||||
axon = new SectionList()
|
||||
objref dendrite
|
||||
dendrite = new SectionList()
|
||||
|
||||
create sections[3]
|
||||
access sections[0]
|
||||
soma.append()
|
||||
sections[0] {
|
||||
pt3dadd(0., 0., 0., 25.)
|
||||
pt3dadd(0., 25., 0., 25.)
|
||||
}
|
||||
|
||||
access sections[1]
|
||||
dendrite.append()
|
||||
connect sections[1](0), sections[0](1)
|
||||
sections[1] {
|
||||
pt3dadd(0., 25., 0., 1.5)
|
||||
pt3dadd(0., 220., 50., 1.5)
|
||||
}
|
||||
|
||||
access sections[2]
|
||||
dendrite.append()
|
||||
connect sections[2](0), sections[0](1)
|
||||
sections[2] {
|
||||
pt3dadd(0., 25., 0., 1.5)
|
||||
pt3dadd(0., 220., -50., 1.5)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user