def test_get_obliques(): '''Comparing results with the old repair launch with the following commands: repair --dounravel 0 --inputdir /gpfs/bbp.cscs.ch/project/proj83/home/bcoste/release/out-new/01_ConvertMorphologies --input rp120430_P-2_idA --overlap=true --incremental=false --restrict=true --distmethod=mirror The arguments are the one used in the legacy morphology workflow. ''' neuron = load_neuron(DATA_PATH / 'compare-bbpsdk/rp120430_P-2_idA.h5') apical_section = neuron.sections[apical_point_section_segment(neuron)[0]] extended_types = repair_type_map(neuron, apical_section) assert_equal([sec.id + OFFSET for sec in test_module.get_obliques(neuron, extended_types)], [217])
def __init__(self, inputfile: Path, axons: Optional[Path] = None, seed: Optional[int] = 0, cut_leaves_coordinates: Optional[NDArray[(3, Any)]] = None, legacy_detection: bool = False, repair_flags: Optional[Dict[RepairType, bool]] = None): '''Repair the input morphology Args: inputfile: the input neuron to repair axons: donor axons whose section will be used to repair this axon seed: the numpy seed cut_leaves_coordinates: List of 3D coordinates from which to start the repair legacy_detection: if True, use the legacy cut plane detection (see neuror.legacy_detection) repair_flags: a dict of flags where key is a RepairType and value is whether it should be repaired or not. If not provided, all types will be repaired. Note: based on https://bbpcode.epfl.ch/browse/code/platform/BlueRepairSDK/tree/BlueRepairSDK/src/repair.cpp#n469 # noqa, pylint: disable=line-too-long ''' np.random.seed(seed) self.legacy_detection = legacy_detection self.inputfile = inputfile self.axon_donors = axons or list() self.donated_intact_axon_sections = list() self.repair_flags = repair_flags or dict() if legacy_detection: self.cut_leaves = CutPlane.find_legacy(inputfile, 'z').cut_leaves_coordinates elif cut_leaves_coordinates is None: self.cut_leaves = CutPlane.find( inputfile, bin_width=15).cut_leaves_coordinates else: self.cut_leaves = np.asarray(cut_leaves_coordinates) self.neuron = load_neuron(inputfile) self.repair_type_map = dict() self.max_y_cylindrical_extent = _max_y_dendritic_cylindrical_extent( self.neuron) self.max_y_extent = max( np.max(section.points[:, COLS.Y]) for section in self.neuron.iter()) self.info = dict() apical_section_id, _ = apical_point_section_segment(self.neuron) if apical_section_id: self.apical_section = self.neuron.sections[apical_section_id] else: self.apical_section = None
def internal_cut_detection(neuron, axis): '''As in: https://bbpcode.epfl.ch/source/xref/platform/BlueRepairSDK/BlueRepairSDK/src/repair.cpp#263 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. ''' 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
def test__find_apical_section_segment(): neuron = Morphology(os.path.join(DATA, 'apical_test.swc')) section, segment = apical_point_section_segment(neuron) eq_(section, 1) eq_(segment, 1)
def test__find_apical_section_segment(): neuron = Morphology(DATA / 'apical_test.swc') section, segment = apical_point_section_segment(neuron) assert section == 1 assert segment == 1
def __init__( self, # pylint: disable=too-many-arguments inputfile: Path, axons: Optional[Path] = None, seed: Optional[int] = 0, cut_leaves_coordinates: Optional[NDArray[(3, Any)]] = None, legacy_detection: bool = False, repair_flags: Optional[Dict[RepairType, bool]] = None, apical_point: NDArray[3, float] = None, params: Dict = None): '''Repair the input morphology The repair algorithm uses sholl analysis of intact branches to grow new branches from cut leaves. The algorithm is fairly complex, but can be controled via a few parameters in the params dictionary. By default, they are: _PARAMS = { 'seg_length': 5.0, # lenghts of new segments 'sholl_layer_size': 10, # resoluion of the shll profile 'noise_continuation': 0.5, # together with seg_length, this controls the tortuosity 'soma_repulsion': 0.2, # if 0, previous section direction, if 1, radial direction 'bifurcation_angle': 20, # noise amplitude in degree around mean bif angle on the cell 'path_length_ratio': 0.5, # a smaller value will make a strornger taper rate 'children_diameter_ratio': 0.8, # 1: child diam = parent diam, 0: child diam = tip diam 'tip_percentile': 25, # percentile of tip radius distributions to use as tip radius } Args: inputfile: the input neuron to repair axons: donor axons whose section will be used to repair this axon seed: the numpy seed cut_leaves_coordinates: List of 3D coordinates from which to start the repair legacy_detection: if True, use the legacy cut plane detection (see neuror.legacy_detection) repair_flags: a dict of flags where key is a RepairType and value is whether it should be repaired or not. If not provided, all types will be repaired. apical_point: 3d vector for apical point, else, the automatic apical detection is used if apical_point == -1, no automatic detection will be tried params: repair internal parameters (see comments in code for details) Note: based on https://bbpcode.epfl.ch/browse/code/platform/BlueRepairSDK/tree/BlueRepairSDK/src/repair.cpp#n469 # noqa, pylint: disable=line-too-long ''' np.random.seed(seed) self.legacy_detection = legacy_detection self.inputfile = inputfile self.axon_donors = axons or list() self.donated_intact_axon_sections = list() self.repair_flags = repair_flags or dict() self.params = params if params is not None else _PARAMS if legacy_detection: self.cut_leaves = CutPlane.find_legacy(inputfile, 'z').cut_leaves_coordinates elif cut_leaves_coordinates is None: self.cut_leaves = CutPlane.find( inputfile, bin_width=15).cut_leaves_coordinates else: self.cut_leaves = np.asarray(cut_leaves_coordinates) self.neuron = load_neuron(inputfile) self.repair_type_map = dict() self.max_y_cylindrical_extent = _max_y_dendritic_cylindrical_extent( self.neuron) self.max_y_extent = max( np.max(section.points[:, COLS.Y]) for section in self.neuron.iter()) self.info = dict() apical_section_id = None if apical_point != -1: if apical_point: # recall MorphIO ID = NeuroM ID - 1 apical_section_id = point_to_section_segment( self.neuron, apical_point)[0] - 1 else: apical_section_id, _ = apical_point_section_segment( self.neuron) if apical_section_id: self.apical_section = self.neuron.sections[apical_section_id] else: self.apical_section = None # record the tip radius as a lower bound for diameters with taper, excluding axons # because they are treated separately, with thinner diameters _diameters = [ np.mean(leaf.points[:, COLS.R]) for neurite in self.neuron.neurites if neurite.type is not NeuriteType.axon for leaf in iter_sections(neurite, iterator_type=Section.ileaf) ] self.tip_radius = (np.percentile( _diameters, self.params["tip_percentile"]) if _diameters else None) self.current_trunk_radius = None # estimate a global tapering rate of the morphology as a function of trunk radius, # such that the tip radius is attained on average af max_path_length, defined as a fraction # of the maximal path length via the parameter path_lengt_ratio. The smaller this parameter # the faster the radii will convert to tip_radius. # TODO: maybe we would need this per neurite_type max_path_length = self.params["path_length_ratio"] * np.max( nm.get("terminal_path_lengths_per_neurite", self.neuron)) self.taper = (lambda trunk_radius: (trunk_radius - self.tip_radius) * self.params["seg_length"] / max_path_length)