コード例 #1
0
ファイル: h5_test.py プロジェクト: liadomide/tvb-root
    class PropsDataTypeFile(H5File):
        def __init__(self, path):
            super(PropsDataTypeFile, self).__init__(path)

            self.n_node = Scalar(PropsDataType.n_node, self)
            # You cannot define Accessors for trait_properties
            # You have to manually map them, using datatype independent accessors
            # breaks: self.weights = DataSet(PropsDataType.weights, self)
            self.weights = DataSet(NArray(), self, name='weights')
            # As any independent accessors weights will be ignored by H5File.load_into, H5File.store

            # Properties have no obvious serialization semantics.
            # They might not be writable or may need a specific initalisation order
            # in this case setting n_node before weights

            self.is_directed = Scalar(Attr(bool), self, name='is_directed')
            self.once = DataSet(NArray(), self, name='once')

        def store(self, datatype, scalars_only=False):
            super(PropsDataTypeFile, self).store(datatype,
                                                 scalars_only=scalars_only)
            # handle the trait_properties manually
            self.weights.store(datatype.weights)
            # is_directed is read only, We choose to store it in the h5 as an example
            # it will never be read from there.
            # One might want to store these in h5 so that manually opened h5 are more informative
            self.is_directed.store(datatype.is_directed)
            # self.once is read only, no need to store

        def load_into(self, datatype):
            super(PropsDataTypeFile, self).load_into(datatype)
            # n_node is loaded, so weights will not complain about missing shape info
            datatype.weights = self.weights.load()
コード例 #2
0
ファイル: sensors_h5.py プロジェクト: nedkab/tvb-framework
class SensorsH5(H5File):
    def __init__(self, path):
        super(SensorsH5, self).__init__(path)
        self.sensors_type = Scalar(Sensors.sensors_type, self)
        self.labels = DataSet(NArray(dtype=STORE_STRING), self, "labels")
        self.locations = DataSet(Sensors.locations, self)
        self.has_orientation = Scalar(Sensors.has_orientation, self)
        self.orientations = DataSet(Sensors.orientations, self)
        self.number_of_sensors = Scalar(Sensors.number_of_sensors, self)
        self.usable = DataSet(Sensors.usable, self)

    def get_locations(self):
        return self.locations.load()

    def get_labels(self):
        return self.labels.load()

    def store(self, datatype, scalars_only=False, store_references=False):
        # type: (Sensors, bool, bool) -> None
        super(SensorsH5, self).store(datatype, scalars_only, store_references)
        self.labels.store(datatype.labels.astype(STORE_STRING))

    def load_into(self, datatype):
        # type: (Sensors) -> None
        super(SensorsH5, self).load_into(datatype)
        datatype.labels = self.labels.load().astype(MEMORY_STRING)
コード例 #3
0
class ConnectivityH5(H5File):
    def __init__(self, path):
        super(ConnectivityH5, self).__init__(path)
        self.region_labels = DataSet(NArray(dtype=STORE_STRING), self, "region_labels")
        self.weights = DataSet(Connectivity.weights, self)
        self.undirected = Scalar(Connectivity.undirected, self)
        self.tract_lengths = DataSet(Connectivity.tract_lengths, self)
        self.centres = DataSet(Connectivity.centres, self)
        self.cortical = DataSet(Connectivity.cortical, self)
        self.hemispheres = DataSet(Connectivity.hemispheres, self)
        self.orientations = DataSet(Connectivity.orientations, self)
        self.areas = DataSet(Connectivity.areas, self)
        self.number_of_regions = Scalar(Connectivity.number_of_regions, self)
        self.number_of_connections = Scalar(Connectivity.number_of_connections, self)
        self.parent_connectivity = Scalar(Connectivity.parent_connectivity, self)
        self.saved_selection = Json(Connectivity.saved_selection, self)

    def get_centres(self):
        return self.centres.load()

    def get_region_labels(self):
        return self.region_labels.load()

    def store(self, datatype, scalars_only=False, store_references=False):
        # type: (Connectivity, bool, bool) -> None
        super(ConnectivityH5, self).store(datatype, scalars_only, store_references)
        self.region_labels.store(datatype.region_labels.astype(STORE_STRING))

    def load_into(self, datatype):
        # type: (Connectivity) -> None
        super(ConnectivityH5, self).load_into(datatype)
        datatype.region_labels = self.region_labels.load().astype(MEMORY_STRING)
コード例 #4
0
class StimuliSurfaceH5(H5File):
    def __init__(self, path):
        super(StimuliSurfaceH5, self).__init__(path)
        self.spatial = Scalar(Attr(str), self, name='spatial')
        self.temporal = Scalar(Attr(str), self, name='temporal')
        self.surface = Reference(StimuliSurface.surface, self)
        self.focal_points_surface = DataSet(
            StimuliSurface.focal_points_surface, self)
        self.focal_points_triangles = DataSet(
            StimuliSurface.focal_points_triangles, self)

    def store(self, datatype, scalars_only=False):
        self.surface.store(datatype.surface)
        self.focal_points_surface.store(datatype.focal_points_surface)
        self.focal_points_triangles.store(datatype.focal_points_triangles)
        self.spatial.store(datatype.spatial.to_json(datatype.spatial))
        self.temporal.store(datatype.temporal.to_json(datatype.temporal))

    def load_into(self, datatype):
        datatype.gid = self.gid.load()
        datatype.surface = self.surface.load()
        datatype.focal_points_triangles = self.focal_points_triangles.load()
        datatype.focal_points_surface = self.focal_points_surface.load()
        spatial_eq = self.spatial.load()
        spatial_eq = datatype.spatial.from_json(spatial_eq)
        datatype.spatial = spatial_eq
        temporal_eq = self.temporal.load()
        temporal_eq = datatype.temporal.from_json(temporal_eq)
        datatype.temporal = temporal_eq
コード例 #5
0
ファイル: simulator_h5.py プロジェクト: yop0/tvb-root
class SimulatorH5(SimulatorConfigurationH5):
    def __init__(self, path):
        super(SimulatorH5, self).__init__(path)
        self.connectivity = Reference(Simulator.connectivity, self)
        self.conduction_speed = Scalar(Simulator.conduction_speed, self)
        self.coupling = Reference(Simulator.coupling, self)
        self.surface = Reference(Simulator.surface, self)
        self.stimulus = Reference(Simulator.stimulus, self)
        self.model = Reference(Simulator.model, self)
        self.integrator = Reference(Simulator.integrator, self)
        self.initial_conditions = DataSet(Simulator.initial_conditions, self)
        self.monitors = Json(Simulator.monitors, self)
        self.simulation_length = Scalar(Simulator.simulation_length, self)
        self.simulation_state = Reference(Attr(field_type=uuid.UUID),
                                          self,
                                          name='simulation_state')

    def store(self, datatype, scalars_only=False, store_references=False):
        # type: (Simulator, bool, bool) -> None
        self.gid.store(datatype.gid)
        self.connectivity.store(datatype.connectivity)
        self.conduction_speed.store(datatype.conduction_speed)
        self.initial_conditions.store(datatype.initial_conditions)
        self.simulation_length.store(datatype.simulation_length)

        integrator_gid = self.store_config_as_reference(datatype.integrator)
        self.integrator.store(integrator_gid)

        coupling_gid = self.store_config_as_reference(datatype.coupling)
        self.coupling.store(coupling_gid)

        model_gid = self.store_config_as_reference(datatype.model)
        self.model.store(model_gid)

        # TODO: handle multiple monitors
        monitor_gid = self.store_config_as_reference(datatype.monitors[0])
        self.monitors.store([monitor_gid.hex])

        if datatype.surface:
            cortex_gid = self.store_config_as_reference(datatype.surface)
            self.surface.store(cortex_gid)

        if datatype.stimulus:
            self.stimulus.store(datatype.stimulus)

        self.type.store(self.get_full_class_name(type(datatype)))

    def load_into(self, datatype):
        # type: (Simulator) -> None
        datatype.conduction_speed = self.conduction_speed.load()
        datatype.initial_conditions = self.initial_conditions.load()
        datatype.simulation_length = self.simulation_length.load()
        datatype.integrator = self.load_from_reference(self.integrator.load())
        datatype.coupling = self.load_from_reference(self.coupling.load())
        datatype.model = self.load_from_reference(self.model.load())
        # TODO: handle multiple monitors
        datatype.monitors = [self.load_from_reference(self.monitors.load()[0])]
        if self.surface.load():
            datatype.surface = self.load_from_reference(self.surface.load())
コード例 #6
0
class StimuliSurfaceH5(H5File):
    def __init__(self, path):
        super(StimuliSurfaceH5, self).__init__(path)
        self.spatial = EquationScalar(StimuliSurface.spatial, self)
        self.temporal = EquationScalar(StimuliSurface.temporal, self)
        self.surface = Reference(StimuliSurface.surface, self)
        self.focal_points_surface = DataSet(NArray(dtype=int),
                                            self,
                                            name='focal_points_surface')
        self.focal_points_triangles = DataSet(
            StimuliSurface.focal_points_triangles, self)

    def store(self, datatype, scalars_only=False):
        super(StimuliSurfaceH5, self).store(datatype, scalars_only)
        self.focal_points_surface.store(datatype.focal_points_surface)
コード例 #7
0
class StimuliRegionH5(H5File):
    def __init__(self, path):
        super(StimuliRegionH5, self).__init__(path)
        self.spatial = Scalar(Attr(str), self, name='spatial')
        self.temporal = Scalar(Attr(str), self, name='temporal')
        self.connectivity = Reference(StimuliRegion.connectivity, self)
        self.weight = DataSet(StimuliRegion.weight, self)

    def store(self, datatype, scalars_only=False):
        self.connectivity.store(datatype.connectivity)
        self.weight.store(datatype.weight)
        self.spatial.store(datatype.spatial.to_json(datatype.spatial))
        self.temporal.store(datatype.temporal.to_json(datatype.temporal))

    def load_into(self, datatype):
        datatype.gid = self.gid.load()
        datatype.connectivity = self.connectivity.load()
        datatype.weight = self.weight.load()
        spatial_eq = self.spatial.load()
        spatial_eq = datatype.spatial.from_json(spatial_eq)
        datatype.spatial = spatial_eq
        temporal_eq = self.temporal.load()
        temporal_eq = datatype.temporal.from_json(temporal_eq)
        datatype.temporal = temporal_eq
コード例 #8
0
class SimulationStateH5(H5File):
    def __init__(self, path):
        super(SimulationStateH5, self).__init__(path)
        self.history = DataSet(NArray(), self, name='history')
        self.current_state = DataSet(NArray(), self, name='current_state')
        self.current_step = Scalar(Int(), self, name='current_step')

        for i in range(1, 16):
            setattr(self, 'monitor_stock_%i' % i,
                    DataSet(NArray(), self, name='monitor_stock_%i' % i))

        self.integrator_noise_rng_state_algo = Scalar(
            Attr(str), self, name='integrator_noise_rng_state_algo')
        self.integrator_noise_rng_state_keys = DataSet(
            NArray(dtype='uint32'),
            self,
            name='integrator_noise_rng_state_keys')
        self.integrator_noise_rng_state_pos = Scalar(
            Int(), self, name='integrator_noise_rng_state_pos')
        self.integrator_noise_rng_state_has_gauss = Scalar(
            Int(), self, name='integrator_noise_rng_state_has_gauss')
        self.integrator_noise_rng_state_cached_gauss = Scalar(
            Float(), self, name='integrator_noise_rng_state_cached_gauss')

    def store(self, simulator, scalars_only=False):
        # type: (Simulator, bool) -> None
        self.history.store(simulator.history.buffer.copy())
        self.current_step.store(simulator.current_step)
        self.current_state.store(simulator.current_state)

        for i, monitor in enumerate(simulator.monitors):
            field_name = "monitor_stock_" + str(i + 1)
            getattr(self, field_name).store(monitor._stock)

        if isinstance(simulator.integrator, IntegratorStochastic):
            rng_state = simulator.integrator.noise.random_stream.get_state()
            self.integrator_noise_rng_state_algo.store(rng_state[0])
            self.integrator_noise_rng_state_keys.store(rng_state[1])
            self.integrator_noise_rng_state_pos.store(rng_state[2])
            self.integrator_noise_rng_state_has_gauss.store(rng_state[3])
            self.integrator_noise_rng_state_cached_gauss.store(rng_state[4])

    def load_into(self, simulator):
        """
        Populate a Simulator object from current stored-state.
        """
        simulator.history.initialize(self.history.load())
        simulator.current_step = self.current_step.load()
        simulator.current_state = self.current_state.load()

        for i, monitor in enumerate(simulator.monitors):
            monitor._stock = getattr(self,
                                     "monitor_stock_" + str(i + 1)).load()

        if self.integrator_noise_rng_state_algo is not None:
            rng_state = (self.integrator_noise_rng_state_algo.load(),
                         self.integrator_noise_rng_state_keys.load(),
                         self.integrator_noise_rng_state_pos.load(),
                         self.integrator_noise_rng_state_has_gauss.load(),
                         self.integrator_noise_rng_state_cached_gauss.load())
            simulator.integrator.noise.random_stream.set_state(rng_state)
コード例 #9
0
ファイル: surface_h5.py プロジェクト: nuuria8/tvb-root
class SurfaceH5(H5File):

    def __init__(self, path):
        super(SurfaceH5, self).__init__(path)
        self.vertices = DataSet(Surface.vertices, self)
        self.triangles = DataSet(Surface.triangles, self)
        self.vertex_normals = DataSet(Surface.vertex_normals, self)
        self.triangle_normals = DataSet(Surface.triangle_normals, self)
        self.number_of_vertices = Scalar(Surface.number_of_vertices, self)
        self.number_of_triangles = Scalar(Surface.number_of_triangles, self)
        self.edge_mean_length = Scalar(Surface.edge_mean_length, self)
        self.edge_min_length = Scalar(Surface.edge_min_length, self)
        self.edge_max_length = Scalar(Surface.edge_max_length, self)
        self.zero_based_triangles = Scalar(Surface.zero_based_triangles, self)

        self.split_triangles = DataSet(NArray(dtype=int), self, name="split_triangles")
        self.number_of_split_slices = Scalar(Int(), self, name="number_of_split_slices")
        self.split_slices = Json(Attr(field_type=dict), self, name="split_slices")

        self.bi_hemispheric = Scalar(Surface.bi_hemispheric, self)
        self.surface_type = Scalar(Surface.surface_type, self)
        self.valid_for_simulations = Scalar(Surface.valid_for_simulations, self)

        # cached header like information, needed to interpret the rest of the file
        # Load the data that is required in order to interpret the file format
        # number_of_vertices and split_slices are needed for the get_vertices_slice read call

        if not self.is_new_file:
            self._split_slices = self.split_slices.load()
            self._split_triangles = self.split_triangles.load()
            self._number_of_vertices = self.number_of_vertices.load()
            self._number_of_triangles = self.number_of_triangles.load()
            self._number_of_split_slices = self.number_of_split_slices.load()
            self._bi_hemispheric = self.bi_hemispheric.load()
        # else: this is a new file

    def store(self, datatype, scalars_only=False, store_references=True):
        # type: (Surface, bool, bool) -> None
        super(SurfaceH5, self).store(datatype, scalars_only=scalars_only, store_references=store_references)
        # When any of the header fields change we have to update our cache of them
        # As they are an invariant of SurfaceH5 we don't do that in the accessors but here.
        # This implies that direct public writes to them via the accessors will break the invariant.
        # todo: should we make the accessors private? In complex formats like this one they are private
        # for this type direct writes to accessors should not be done
        self._number_of_vertices = datatype.number_of_vertices
        self._number_of_triangles = datatype.number_of_triangles
        self._bi_hemispheric = datatype.bi_hemispheric
        self.prepare_slices(datatype)
        self.number_of_split_slices.store(self._number_of_split_slices)
        self.split_slices.store(self._split_slices)
        self.split_triangles.store(self._split_triangles)

    def read_subtype_attr(self):
        return self.surface_type.load()

    def center(self):
        """
        Compute the center of the surface as the mean spot on all the three axes.
        """
        # is this different from return numpy.mean(self.vertices, axis=0) ?
        return [float(numpy.mean(self.vertices[:, 0])),
                float(numpy.mean(self.vertices[:, 1])),
                float(numpy.mean(self.vertices[:, 2]))]

    def get_number_of_split_slices(self):
        return self._number_of_split_slices

    def prepare_slices(self, datatype):
        """
        Before storing Surface in H5, make sure vertices/triangles are split in
        slices that are readable by WebGL.
        WebGL only supports triangle indices in interval [0.... 2^16]
        """
        # Do not split when size is conveniently small:
        if self._number_of_vertices <= SPLIT_MAX_SIZE + SPLIT_BUFFER_SIZE and not self._bi_hemispheric:
            self._number_of_split_slices = 1
            self._split_slices = {0: {KEY_TRIANGLES: {KEY_START: 0, KEY_END: self._number_of_triangles},
                                      KEY_VERTICES: {KEY_START: 0, KEY_END: self._number_of_vertices},
                                      KEY_HEMISPHERE: HEMISPHERE_UNKNOWN}}
            self._split_triangles = numpy.array([], dtype=numpy.int32)
            return

        # Compute the number of split slices:
        left_hemisphere_slices = 0
        left_hemisphere_vertices_no = 0
        if self._bi_hemispheric:
            # when more than one hemisphere
            right_hemisphere_vertices_no = numpy.count_nonzero(datatype.hemisphere_mask)
            left_hemisphere_vertices_no = self._number_of_vertices - right_hemisphere_vertices_no
            LOG.debug("Right %d Left %d" % (right_hemisphere_vertices_no, left_hemisphere_vertices_no))
            left_hemisphere_slices = self._get_slices_number(left_hemisphere_vertices_no)
            self._number_of_split_slices = left_hemisphere_slices
            self._number_of_split_slices += self._get_slices_number(right_hemisphere_vertices_no)
            LOG.debug("Hemispheres Total %d Left %d" % (self._number_of_split_slices, left_hemisphere_slices))
        else:
            # when a single hemisphere
            self._number_of_split_slices = self._get_slices_number(self._number_of_vertices)

        LOG.debug("Start to compute surface split triangles and vertices")
        split_triangles = []
        ignored_triangles_counter = 0
        self._split_slices = {}

        for i in range(self._number_of_split_slices):
            split_triangles.append([])
            if not self._bi_hemispheric:
                self._split_slices[i] = {KEY_VERTICES: {KEY_START: i * SPLIT_MAX_SIZE,
                                                        KEY_END: min(self._number_of_vertices,
                                                                     (i + 1) * SPLIT_MAX_SIZE + SPLIT_BUFFER_SIZE)},
                                         KEY_HEMISPHERE: HEMISPHERE_UNKNOWN}
            else:
                if i < left_hemisphere_slices:
                    self._split_slices[i] = {KEY_VERTICES: {KEY_START: i * SPLIT_MAX_SIZE,
                                                            KEY_END: min(left_hemisphere_vertices_no,
                                                                         (i + 1) * SPLIT_MAX_SIZE + SPLIT_BUFFER_SIZE)},
                                             KEY_HEMISPHERE: HEMISPHERE_LEFT}
                else:
                    self._split_slices[i] = {KEY_VERTICES: {KEY_START: left_hemisphere_vertices_no +
                                                                        (i - left_hemisphere_slices) * SPLIT_MAX_SIZE,
                                                            KEY_END: min(self._number_of_vertices,
                                                                         left_hemisphere_vertices_no + SPLIT_MAX_SIZE *
                                                                         (i + 1 - left_hemisphere_slices)
                                                                         + SPLIT_BUFFER_SIZE)},
                                             KEY_HEMISPHERE: HEMISPHERE_RIGHT}

        # Iterate Triangles and find the slice where it fits best, based on its vertices indexes:
        for i in range(self._number_of_triangles):
            current_triangle = [datatype.triangles[i][j] for j in range(3)]
            fit_slice, transformed_triangle = self._find_slice(current_triangle)

            if fit_slice is not None:
                split_triangles[fit_slice].append(transformed_triangle)
            else:
                # triangle ignored, as it has vertices over multiple slices.
                ignored_triangles_counter += 1
                continue

        final_split_triangles = []
        last_triangles_idx = 0

        # Concatenate triangles, to be stored in a single HDF5 array.
        for slice_idx, split_ in enumerate(split_triangles):
            self._split_slices[slice_idx][KEY_TRIANGLES] = {KEY_START: last_triangles_idx,
                                                            KEY_END: last_triangles_idx + len(split_)}
            final_split_triangles.extend(split_)
            last_triangles_idx += len(split_)
        self._split_triangles = numpy.array(final_split_triangles, dtype=numpy.int32)

        if ignored_triangles_counter > 0:
            LOG.warning("Ignored triangles from multiple hemispheres: " + str(ignored_triangles_counter))
        LOG.debug("End compute surface split triangles and vertices " + str(self._split_slices))

    @staticmethod
    def _get_slices_number(vertices_number):
        """
        Slices are for vertices [SPLIT_MAX_SIZE * i ... SPLIT_MAX_SIZE * (i + 1) + SPLIT_BUFFER_SIZE]
        Slices will overlap :
        |........SPLIT_MAX_SIZE|...SPLIT_BUFFER_SIZE|                           <-- split 1
                               |......... SPLIT_MAX_SIZE|...SPLIT_BUFFER_SIZE|  <-- split 2
        If we have trailing data smaller than the SPLIT_BUFFER_SIZE,
        then we no longer split but we need to have at least 1 slice.
        """
        slices_number, trailing = divmod(vertices_number, SPLIT_MAX_SIZE)
        if trailing > SPLIT_BUFFER_SIZE or (slices_number == 0 and trailing > 0):
            slices_number += 1
        return slices_number

    def _find_slice(self, triangle):
        mn = min(triangle)
        mx = max(triangle)
        for i in range(self._number_of_split_slices):
            v = self._split_slices[i][KEY_VERTICES]  # extracted for performance
            slice_start = v[KEY_START]
            if slice_start <= mn and mx < v[KEY_END]:
                return i, [triangle[j] - slice_start for j in range(3)]
        return None, triangle


    def get_slice_vertex_boundaries(self, slice_idx):
        if str(slice_idx) in self._split_slices:
            start_idx = max(0, self._split_slices[str(slice_idx)][KEY_VERTICES][KEY_START])
            end_idx = min(self._split_slices[str(slice_idx)][KEY_VERTICES][KEY_END], self._number_of_vertices)
            return start_idx, end_idx
        else:
            LOG.warning("Could not access slice indices, possibly due to an incompatibility with code update!")
            return 0, min(SPLIT_BUFFER_SIZE, self._number_of_vertices)

    def _get_slice_triangle_boundaries(self, slice_idx):
        if str(slice_idx) in self._split_slices:
            start_idx = max(0, self._split_slices[str(slice_idx)][KEY_TRIANGLES][KEY_START])
            end_idx = min(self._split_slices[str(slice_idx)][KEY_TRIANGLES][KEY_END], self._number_of_triangles)
            return start_idx, end_idx
        else:
            LOG.warn("Could not access slice indices, possibly due to an incompatibility with code update!")
            return 0, self._number_of_triangles

    def get_vertices_slice(self, slice_number=0):
        """
        Read vertices slice, to be used by WebGL visualizer.
        """
        slice_number = int(slice_number)
        start_idx, end_idx = self.get_slice_vertex_boundaries(slice_number)
        return self.vertices[start_idx: end_idx: 1]

    def get_vertex_normals_slice(self, slice_number=0):
        """
        Read vertex-normal slice, to be used by WebGL visualizer.
        """
        slice_number = int(slice_number)
        start_idx, end_idx = self.get_slice_vertex_boundaries(slice_number)
        return self.vertex_normals[start_idx: end_idx: 1]

    def get_triangles_slice(self, slice_number=0):
        """
        Read split-triangles slice, to be used by WebGL visualizer.
        """
        if self._number_of_split_slices == 1:
            return self.triangles.load()
        slice_number = int(slice_number)
        start_idx, end_idx = self._get_slice_triangle_boundaries(slice_number)
        return self._split_triangles[start_idx: end_idx: 1]

    def get_lines_slice(self, slice_number=0):
        """
        Read the gl lines values for the current slice number.
        """
        return Surface._triangles_to_lines(self.get_triangles_slice(slice_number))

    def get_slices_to_hemisphere_mask(self):
        """
        :return: a vector af length number_of_slices, with 1 when current chunk belongs to the Right hemisphere
        """
        if not self._bi_hemispheric or self._split_slices is None:
            return None
        result = [1] * self._number_of_split_slices
        for key, value in self._split_slices.items():
            if value[KEY_HEMISPHERE] == HEMISPHERE_LEFT:
                result[int(key)] = 0
        return result

    # todo: many of these do not belong in the data access layer but higher, adapter or gui layer
    ####################################### Split for Picking
    #######################################
    def get_pick_vertices_slice(self, slice_number=0):
        """
        Read vertices slice, to be used by WebGL visualizer with pick.
        """
        slice_number = int(slice_number)
        slice_triangles = self.triangles[
                          slice_number * SPLIT_PICK_MAX_TRIANGLE:
                          min(self._number_of_triangles, (slice_number + 1) * SPLIT_PICK_MAX_TRIANGLE)
                          ]
        result_vertices = []
        cache_vertices = self.vertices.load()
        for triang in slice_triangles:
            result_vertices.append(cache_vertices[triang[0]])
            result_vertices.append(cache_vertices[triang[1]])
            result_vertices.append(cache_vertices[triang[2]])
        return numpy.array(result_vertices)

    def get_pick_vertex_normals_slice(self, slice_number=0):
        """
        Read vertex-normals slice, to be used by WebGL visualizer with pick.
        """
        slice_number = int(slice_number)
        slice_triangles = self.triangles[
                          slice_number * SPLIT_PICK_MAX_TRIANGLE:
                          min(self.number_of_triangles.load(), (slice_number + 1) * SPLIT_PICK_MAX_TRIANGLE)
                          ]
        result_normals = []
        cache_vertex_normals = self.vertex_normals.load()

        for triang in slice_triangles:
            result_normals.append(cache_vertex_normals[triang[0]])
            result_normals.append(cache_vertex_normals[triang[1]])
            result_normals.append(cache_vertex_normals[triang[2]])
        return numpy.array(result_normals)

    def get_pick_triangles_slice(self, slice_number=0):
        """
        Read triangles slice, to be used by WebGL visualizer with pick.
        """
        slice_number = int(slice_number)
        no_of_triangles = (min(self._number_of_triangles, (slice_number + 1) * SPLIT_PICK_MAX_TRIANGLE)
                           - slice_number * SPLIT_PICK_MAX_TRIANGLE)
        triangles_array = numpy.arange(no_of_triangles * 3).reshape((no_of_triangles, 3))
        return triangles_array