Пример #1
0
    def execute(self, namespace):
        from PYME.Analysis.points.traveling_salesperson import sort

        points = namespace[self.input]

        try:
            positions = np.stack([points['x_um'], points['y_um']], axis=1)
        except KeyError:
            # units don't matter for these calculations, but we want to preserve them on the other side
            positions = np.stack([points['x'], points['y']], axis=1) / 1e3

        start_index = 0 if not self.start_from_corner else np.argmin(positions.sum(axis=1))

        positions, ogd, final_distance = sort.tsp_sort(positions, start_index, self.epsilon, return_path_length=True)

        out = tabular.DictSource({'x_um': positions[:, 0],
                                     'y_um': positions[:, 1]})
        out.mdh = MetaDataHandler.NestedClassMDHandler()
        try:
            out.mdh.copyEntriesFrom(points.mdh)
        except AttributeError:
            pass
        out.mdh['TravelingSalesperson.Distance'] = final_distance
        out.mdh['TravelingSalesperson.OriginalDistance'] = ogd

        namespace[self.output] = out
Пример #2
0
def test_tsp_sort():
    from PYME.Analysis.points.traveling_salesperson import sort
    n = 500
    x = np.random.rand(n) * 4e3
    y = np.random.rand(n) * 4e3
    og_positions = np.stack([x, y], axis=1)
    positions, og_distance, final_distance = sort.tsp_sort(og_positions, return_path_length=True)
    np.testing.assert_array_equal(np.unique(positions), np.unique(og_positions))
    assert final_distance < og_distance
Пример #3
0
    def measure_offsets(self, optimize_path=True, use_previous_scan=True):
        """
        Visit each position and log the offset

        Parameters
        ----------
        optimize_path : bool
            Flag to toggle visiting the positions in an order which minimizes the path relative to the microscope
            starting position.

        """
        from PYME.Analysis.points.traveling_salesperson import sort
        n_positions = len(self._positions)
        offset = np.zeros(len(self._positions), dtype=float)
        lock_ok = np.ones(len(self._positions), dtype=bool)
        x, y = np.zeros_like(offset), np.zeros_like(offset)
        positions = np.zeros((n_positions, 2), dtype=float)
        for ind in range(n_positions):
            positions[ind, :] = (self._positions[ind]['x'],
                                 self._positions[ind]['y'])

        if optimize_path:
            current_pos = self._scope.GetPos()
            positions = sort.tsp_sort(positions,
                                      start=(current_pos['x'],
                                             current_pos['y']))

        for ind in range(n_positions):
            self._scope.SetPos(x=positions[ind, 0], y=positions[ind, 1])

            time.sleep(self._pause_on_relocate)
            if hasattr(self, '_focus_lock') and not self._focus_lock.LockOK():
                logger.debug('focus lock not OK, scanning offset')
                if use_previous_scan:
                    try:
                        start_at = self.lookup_offset(positions[ind, 0],
                                                      positions[ind, 1])
                    except:
                        start_at = -25
                else:
                    start_at = -25
                self._focus_lock.ReacquireLock(start_at=start_at)
                time.sleep(1.)

                if self._focus_lock.LockOK():
                    time.sleep(1.)
            actual = self._scope.GetPos()
            x[ind], y[ind] = actual['x'], actual['y']
            offset[ind] = self._offset_piezo.GetOffset()
            try:
                lock_ok[ind] = self._focus_lock.LockOK()
                logger.debug('lock OK %s, x %.1f, y %.1f, offset %.1f' %
                             (lock_ok[ind], x[ind], y[ind], offset[ind]))
            except AttributeError:
                logger.debug('x %.1f, y %.1f, offset %.1f' %
                             (x[ind], y[ind], offset[ind]))

        self._scans.append({
            'x': x[lock_ok],
            'y': y[lock_ok],
            'offset': offset[lock_ok]
        })
Пример #4
0
    def save(self, namespace, context={}):
        """
        Parameters
        ----------
        namespace : dict
            The recipe namespace
        context : dict
            Information about the source file to allow pattern substitution to 
            generate the output name. At least 'basedir' (which is the fully 
            resolved directory name in which the input file resides) and 
            'file_stub' (which is the filename without any extension) should be 
            resolved.
        
        Notes
        -----
        str spool_settings values can context-substitute templated parameters,
        e.g. spool_settings = {'subdirectory': '{file_stub}',
                               'extra_metadata: {'Samples.Well': '{file_stub}'}}
        """
        # substitute spool settings
        spool_settings = self.spool_settings.copy()
        format_values(spool_settings, context)

        try:  # get positions in units of micrometers
            positions = np.stack((namespace[self.input_positions]['x_um'],
                                  namespace[self.input_positions]['y_um']),
                                 axis=1)  # (N, 2), [um]
        except KeyError:  # assume x and y are in nanometers
            positions = np.stack((namespace[self.input_positions]['x'],
                                  namespace[self.input_positions]['y']),
                                 axis=1) / 1e3  # (N, 2), [nm] -> [um]

        if self.optimize_path:
            from PYME.Analysis.points.traveling_salesperson import sort
            start = -1 if self.lifo else 0
            positions = sort.tsp_sort(positions, start)
        else:
            positions = positions[::-1, :] if self.lifo else positions

        dest = self.action_server_url + '/queue_actions'
        session = requests.Session()
        actions = list()
        for ri in range(positions.shape[0]):
            actions.append({
                'CentreROIOn': {
                    'x': positions[ri, 0],
                    'y': positions[ri, 1],
                    'then': {
                        'SpoolSeries': spool_settings
                    }
                }
            })
        session.post(dest + '?timeout=%f&nice=%d&max_duration=%f' %
                     (self.timeout, self.nice, self.max_duration),
                     data=json.dumps(actions),
                     headers={'Content-Type': 'application/json'})

        # queue a high-nice call to shut off all lasers when we're done
        # FIXME - there has to be a better way of handling this!
        # a) protocols should turn lasers off anyway
        # b) maybe have a a specific 'safe state' fallback in the action manager for when the queue is empty?
        session.post(dest + '?timeout=%f&nice=%d&max_duration=%f' %
                     (self.timeout, 20, self.max_duration),
                     data=json.dumps([{
                         'FunctionAction': {
                             'functionName': 'turnAllLasersOff',
                             'args': {}
                         }
                     }]),
                     headers={'Content-Type': 'application/json'})