Exemplo n.º 1
0
  def __init__(self, tracker, mirror, alignment, input_y, tilted=False, **kwargs):
    self._serial = kwargs.pop('serial', 'unsorted')
    self.tracker = tracker
    self.mirror = mirror
    self.tilted = tilted
    self.input_y = input_y
    self.alignment = None
    if alignment is not None:
      try:
        if alignment.alignment_date() is not None:
          self.alignment = alignment
      except AttributeError:
        try:
          file_data = load_object(alignment)
          if file_data.alignment_date() is not None:
            self.alignment = file_data
        except (AttributeError, IOError):
          # Input alignment file is not valid.
          pass
    if self.alignment is None:
      self.alignment = Alignment()
      self.tracker.devices['driver'].home()
      self.alignment.align(self.tracker, home=True, tilted=tilted,
          mirror=mirror)
      save_object(self.alignment, alignment)

    # Output data.
    self.data = []
Exemplo n.º 2
0
def simulate_alignment(
    beam_a_direction, beam_b_direction, beam_a_intercept, separation,
    samples=25, calibration_file=None):
  """Return the beam construction parameters and an itop.Alignment of the
  simulated beams."""
  alignment = DataAlignment(calibration_file)
  ray_a = Ray(beam_a_direction, beam_a_intercept)
  ray_a = Ray(beam_a_direction, ray_a.sample(150))

  ray_b = Ray(beam_b_direction,
      np.array(beam_a_intercept) + np.array(separation))
  ray_b = Ray(beam_b_direction, ray_b.sample(150))
  beam_a = DataBeam()
  beam_b = DataBeam()

  for tracker_z in np.arange(125, -95, -220/samples).tolist() + [-95]:
    beam_a.add_sample(ray_a.sample(tracker_z))
    beam_b.add_sample(ray_b.sample(tracker_z))
  alignment.beams = [beam_a, beam_b]
  alignment.displacements = [
      alignment.beams[index].intercept - alignment.beams[0].intercept
      for index in range(2)]
  return alignment
Exemplo n.º 3
0
class Instrument(object):
  """An iTOP mirror scanning instrument.

  The instrument consists of a beam tracker, a mirror fixed to a calibrated
  mirror translation stage, and a valid set of stage-beam alignment data.

  Output data is kept in order to make descisions about future movements
  relative to the mirror.

  """
  def __init__(self, tracker, mirror, alignment, input_y, tilted=False, **kwargs):
    self._serial = kwargs.pop('serial', 'unsorted')
    self.tracker = tracker
    self.mirror = mirror
    self.tilted = tilted
    self.input_y = input_y
    self.alignment = None
    if alignment is not None:
      try:
        if alignment.alignment_date() is not None:
          self.alignment = alignment
      except AttributeError:
        try:
          file_data = load_object(alignment)
          if file_data.alignment_date() is not None:
            self.alignment = file_data
        except (AttributeError, IOError):
          # Input alignment file is not valid.
          pass
    if self.alignment is None:
      self.alignment = Alignment()
      self.tracker.devices['driver'].home()
      self.alignment.align(self.tracker, home=True, tilted=tilted,
          mirror=mirror)
      save_object(self.alignment, alignment)

    # Output data.
    self.data = []

  def sample_position(self, mirror_x, start_point=None,
      x_scan_direction=1):
    """Returns the reflected beam trajectories with the mirror at the given
    mirror stage position.

    Takes the optional keyword arguments.
      start_point (None):
        Start the scan at a position given by the coordinates in the form
        [x, y, z]. By default, the start point is determined from the
        stage limits.

      x_scan_direction (1):
        The direction to scan for the beam in x.

    """
    self.mirror.position(mirror_x, wait=True)
    tracked_beams = []
    if start_point is None:
      start_point, x_scan_direction = self._find_start_point(mirror_x)
    for beam_index, in_range in enumerate(
        tuple(self._beams_in_range(mirror_x))):
      if not in_range:
        print('Skipping Beam {}'.format(beam_index))
        tracked_beams.append(None)
        continue
      expose_single_beam(self.tracker.devices['driver'],
          beam_index,
          self.alignment.beam_count())
      time.sleep(0.25)
      tracked_beams.append(
          self.tracker.find_beam_trajectory(
              start_point,
              x_scan_direction,
              scan_direction_z=(1 if start_point[2] < 0 else -1),
              measure_power=True
              ))
      if tracked_beams[-1] is None:
        print('Failed to find beam {}.'.format(beam_index))
      start_point = self.tracker.position().array()
    self.data.append(
        DataPoint([self.mirror.position().value, self.input_y, 0],
                  tracked_beams))
    return self.data[-1]

  def save_data(self, path):
    """Saves the data in a serialized object format to a gzipped tarball at
    the given path. To reopen the data, unpickle it using
    itop.utilities.load_object()

    """
    output = list(self.data)
    output.insert(0, (self.input_y, self.alignment, self._serial))
    save_object(output, path)

  def _find_start_point(self, mirror_x):
    """Return the best starting point and scan direction for the beam
    intercept scan."""
    start_point = None
    scan_direction = 1
    first_index = self._lowest_beam_in_range(mirror_x)
    if first_index is None:
      raise InstrumentError(
          'No beam reflected (mirror position = {})'.format(mirror_x))
    last_index, start_point = self._last_beam_sample()
    if start_point is not None and last_index is not None:
      if first_index == last_index:
        if (mirror_x - self.data[-1].mirror_position[0]) < 0:
          scan_direction = -1
      elif start_point[2] > 0:
        if first_index > last_index:
          start_point = start_point - [35, 0, 0]
        else:
          start_point = start_point + [35, 0, 0]
          scan_direction = -1
      else:
        if first_index > last_index:
          start_point = start_point + [35, 0, 0]
          scan_direction = -1
        else:
          start_point = start_point - [35, 0, 0]
    else:
      start_point = [self.tracker.axes[0].limits.lower,
                     self.tracker.axes[1].limits.lower,
                     self.tracker.axes[2].limits.lower]
    return (start_point, scan_direction)

  def _beams_in_range(self, mirror_x):
    """Return a generator of booleans indicating that the ith indexed beam is
    in range at the given mirror position."""
    if not self.tilted:
      for index in self.alignment.beam_indexes():
        yield not self.alignment.out_of_range(index, [mirror_x, 0, 0])
    else:
      for index in self.alignment.beam_indexes():
        yield True if index == 0 else False

  def _lowest_beam_in_range(self, mirror_x):
    """Return the lowest beam index that is in range or None if no beams are
    in range."""
    return next(
        (i for i, j in enumerate(self._beams_in_range(mirror_x)) if j),
        None)
  def _last_beam_samples(self):
    """Return a generator of the last beam sample for each beam. None is used
    if a beam was not visible in the last sampling.
    """
    try:
      for index, beam in enumerate(self.data[-1].beams):
        yield (index, beam.last_sample() if beam else None)
    except (IndexError, AttributeError):
      # Last data point has no beams.
      yield (None, None)

  def _last_beam_sample(self):
    """Return the (index, position) of the last beam sample in data. If no
    beam has been sampled, return (None, None)."""
    return next(
        (i for i in reversed(tuple(self._last_beam_samples())) if i[1]),
        (None, None))