Source code for neuror.cut_plane.legacy_detection
'''Module for the legacy cut plane detection.
As implemented in:
https://bbpgitlab.epfl.ch/nse/morphologyrepair/BlueRepairSDK/-/blob/main/BlueRepairSDK/src/repair.cpp#L263
'''
import logging
from collections import defaultdict
import numpy as np
from morph_tool import apical_point_section_segment
from neurom import iter_sections
from neurom.core import Section
from neurom.core.dataformat import COLS
from neuror.exceptions import NeuroRError
from neuror.utils import RepairType, repair_type_map
L = logging.getLogger(__name__)
[docs]def children_ids(section):
'''Return the children IDs.
.. note::
This is a re-implementation of:
https://bbpgitlab.epfl.ch/nse/morphologyrepair/BlueRepairSDK/-/blob/main/BlueRepairSDK/src/helper_dendrite.cpp#L111
The original code returns the ids of the descendant sections
but this implementation return the Section objects instead.
'''
return list(section.ipreorder())
[docs]def cut_detect(neuron, cut, offset, axis):
'''Detect the cut leaves the old way.
The cut leaves are simply the leaves that live
on the half-space (split along the 'axis' coordinate)
with the biggest number of leaves
'''
count_plus = count_minus = sum_plus = sum_minus = 0
for leaf in iter_sections(neuron, iterator_type=Section.ileaf):
coord = leaf.points[-1, axis]
if coord > offset:
count_plus += 1
sum_plus += coord
else:
count_minus += 1
sum_minus += coord
if count_plus == 0 or count_minus == 0:
raise NeuroRError(
"cut detection warning:one of the sides is empty. can't decide on cut side"
)
if -sum_minus / count_minus > sum_plus / count_plus:
sign = 1
else:
sign = -1
for leaf in iter_sections(neuron, iterator_type=Section.ileaf):
if leaf.points[-1, axis] * sign > offset:
cut[leaf] = True
return sign
[docs]def internal_cut_detection(neuron, axis):
'''Use cut_detect to get the side of the half space the points live in.
Then mark points which are children of the apical section.
.. note::
This is a re-implementation of:
https://bbpgitlab.epfl.ch/nse/morphologyrepair/BlueRepairSDK/-/blob/main/BlueRepairSDK/src/repair.cpp#L263
'''
axis = {'x': COLS.X, 'y': COLS.Y, 'z': COLS.Z}[axis.lower()]
cut = defaultdict(lambda key: False)
side = cut_detect(neuron, cut, 0, axis)
# reclassify cut points in tuft,based on apical point position
apical_section_id, point_id = apical_point_section_segment(neuron)
if apical_section_id is not None:
apical_section = neuron.sections[apical_section_id]
apical_offset = apical_section.points[point_id, axis]
cut_mark(children_ids(apical_section), cut, apical_offset, side, axis)
else:
apical_section = None
extended_types = repair_type_map(neuron, apical_section)
oblique_roots = get_obliques(neuron, extended_types)
# reclassify points in obliques. based on the position of their root.
for root in oblique_roots:
offset = root.points[0]
# FIXME: z is hard coded in the original code as well. It's probably a bug.
cut_mark(root.children, cut, offset[COLS.Z], side, axis)
cut_leaves = np.array([sec.points[-1, COLS.XYZ] for sec, is_cut in cut.items() if is_cut])
return cut_leaves, side
[docs]def get_obliques(neuron, extended_types):
'''Returns the oblique roots.
.. note::
This is a re-implementation of:
https://bbpgitlab.epfl.ch/nse/morphologyrepair/BlueRepairSDK/-/blob/main/BlueRepairSDK/src/helper_dendrite.cpp#L212
'''
return [section for section in iter_sections(neuron)
if (extended_types[section] == RepairType.oblique and
(section.parent is None or extended_types[section.parent] == RepairType.trunk))]
[docs]def cut_mark(sections, cut, offset, side, axis):
'''Find which sections should be cut.
.. note::
This is a re-implementation of:
https://bbpgitlab.epfl.ch/nse/morphologyrepair/BlueRepairSDK/-/blob/main/BlueRepairSDK/src/helper_dendrite.cpp#L654
'''
for sec in sections:
if sec.children:
cut[sec] = False
continue
r = sec.points[-1, axis]
growing_back = False
mysec = sec
while mysec.parent:
for point in mysec.points:
mr = point[axis]
growing_back |= (mr - (r + (float(side) * 15.0))) * side > 0
if growing_back:
break
mysec = mysec.parent
cut[sec] = (r - offset) * side > 0 and not growing_back
return cut