Пример #1
0
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])
Пример #2
0
    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
Пример #3
0
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
Пример #4
0
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)
Пример #5
0
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
Пример #6
0
    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)