diff --git a/pocs/camera/camera.py b/pocs/camera/camera.py index a419184b3..cbb97ddc0 100644 --- a/pocs/camera/camera.py +++ b/pocs/camera/camera.py @@ -208,7 +208,10 @@ def take_observation(self, observation, headers=None, filename=None, *args, **kw # Add most recent exposure to list if self.is_primary: - observation.exposure_list[image_id] = file_path + if 'POINTING' in headers: + observation.pointing_images[image_id] = file_path + else: + observation.exposure_list[image_id] = file_path # Process the exposure once readout is complete t = Thread(target=self.process_exposure, args=( @@ -493,7 +496,12 @@ def _process_fits(self, file_path, info): return file_path def __str__(self): - s = "{} ({}) on {}".format(self.name, self.uid, self.port) + name = self.name + if self.is_primary: + name += ' [Primary]' + + s = "{} ({}) on {}".format(name, self.uid, self.port) + if hasattr(self, 'focuser') and self.focuser is not None: s += ' with {}'.format(self.focuser.name) diff --git a/pocs/camera/simulator.py b/pocs/camera/simulator.py index c0becc109..97e330cb7 100644 --- a/pocs/camera/simulator.py +++ b/pocs/camera/simulator.py @@ -38,11 +38,6 @@ def take_observation(self, observation, headers=None, filename=None, *args, **kw kwargs['exp_time'] = 1 self.logger.debug("Trimming camera simulator exposure to 1 s") - # If POCSTIME is set for testing then the simulator will generate - # duplicate filenames each time so we pass a filename here. Full path - # is added in `camera._setup_observation`. - filename = 'simulator_{:02d}.{}'.format(observation.current_exp, self.file_extension) - return super().take_observation(observation, headers, filename, diff --git a/pocs/observatory.py b/pocs/observatory.py index 4f57c8ce8..c4f81c3dc 100644 --- a/pocs/observatory.py +++ b/pocs/observatory.py @@ -376,7 +376,7 @@ def analyze_recent(self): # Clear the offset info self.current_offset_info = None - pointing_image = self.current_observation.pointing_image + pointing_image_id, pointing_image = self.current_observation.pointing_image self.logger.debug( "Analyzing recent image using pointing image: '{}'".format(pointing_image)) @@ -430,7 +430,8 @@ def update_tracking(self): self.logger.debug("Updating the tracking") # Get the pier side of pointing image - pointing_ha = self.current_observation.pointing_image.header_ha + _, pointing_image = self.current_observation.pointing_image + pointing_ha = pointing_image.header_ha try: pointing_ha = pointing_ha.value diff --git a/pocs/scheduler/observation.py b/pocs/scheduler/observation.py index 4154822d4..f7e3a86d5 100644 --- a/pocs/scheduler/observation.py +++ b/pocs/scheduler/observation.py @@ -56,25 +56,24 @@ def __init__(self, field, exp_time=120 * u.second, min_nexp=60, self.field = field - self.current_exp = 0 - self.exp_time = exp_time self.min_nexp = min_nexp self.exp_set_size = exp_set_size self.exposure_list = OrderedDict() + self.pointing_images = OrderedDict() self.priority = float(priority) self._min_duration = self.exp_time * self.min_nexp self._set_duration = self.exp_time * self.exp_set_size - self.pointing_image = None - self._image_dir = self.config['directories']['images'] self._seq_time = None self.merit = 0.0 + self.reset() + self.logger.debug("Observation created: {}".format(self)) @@ -127,6 +126,15 @@ def directory(self): self.field.field_name) return self._directory + @property + def current_exp_num(self): + """ Return the current number of exposures. + + Returns: + int: The size of `self.exposure_list`. + """ + return len(self.exposure_list) + @property def first_exposure(self): """ Return the latest exposure information @@ -151,16 +159,29 @@ def last_exposure(self): except IndexError: self.logger.warning("No exposure available") + @property + def pointing_image(self): + """Return the last pointing image. + + Returns: + tuple: `image_id` and full path of most recent pointing image from + the primary camera. + """ + try: + return list(self.pointing_images.items())[-1] + except IndexError: + self.logger.warning("No pointing image available") + ################################################################################################## # Methods ################################################################################################## def reset(self): - """Resets the exposure values for the observation """ + """Resets the exposure information for the observation """ self.logger.debug("Resetting observation {}".format(self)) - self.current_exp = 0 + self.exposure_list = OrderedDict() self.merit = 0.0 self.seq_time = None @@ -179,7 +200,7 @@ def status(self): equinox = 'J2000' status = { - 'current_exp': self.current_exp, + 'current_exp': self.current_exp_num, 'dec_mnt': self.field.coord.dec.value, 'equinox': equinox, 'exp_set_size': self.exp_set_size, diff --git a/pocs/state/states/default/analyzing.py b/pocs/state/states/default/analyzing.py index 0892e60b3..80f2f7d13 100644 --- a/pocs/state/states/default/analyzing.py +++ b/pocs/state/states/default/analyzing.py @@ -4,7 +4,7 @@ def on_enter(event_data): observation = pocs.observatory.current_observation - pocs.say("Analyzing image {} / {}".format(observation.current_exp, observation.min_nexp)) + pocs.say("Analyzing image {} / {}".format(observation.current_exp_num, observation.min_nexp)) pocs.next_state = 'tracking' try: @@ -16,9 +16,9 @@ def on_enter(event_data): pocs.next_state = 'scheduling' # Check for minimum number of exposures - if observation.current_exp >= observation.min_nexp: + if observation.current_exp_num >= observation.min_nexp: # Check if we have completed an exposure block - if observation.current_exp % observation.exp_set_size == 0: + if observation.current_exp_num % observation.exp_set_size == 0: pocs.next_state = 'scheduling' except Exception as e: pocs.logger.error("Problem in analyzing: {}".format(e)) diff --git a/pocs/state/states/default/observing.py b/pocs/state/states/default/observing.py index ece2bb355..0ac10672c 100644 --- a/pocs/state/states/default/observing.py +++ b/pocs/state/states/default/observing.py @@ -27,7 +27,5 @@ def on_enter(event_data): pocs.logger.warning("Problem with imaging: {}".format(e)) pocs.say("Hmm, I'm not sure what happened with that exposure.") else: - pocs.observatory.current_observation.current_exp += 1 pocs.logger.debug('Finished with observing, going to analyze') - pocs.next_state = 'analyzing' diff --git a/pocs/state/states/default/pointing.py b/pocs/state/states/default/pointing.py index 1b43f0aca..952c0faab 100644 --- a/pocs/state/states/default/pointing.py +++ b/pocs/state/states/default/pointing.py @@ -51,18 +51,18 @@ def on_enter(event_data): # Analyze pointing if observation is not None: - pointing_id, pointing_path = observation.last_exposure + pointing_id, pointing_path = observation.pointing_image pointing_image = Image( pointing_path, location=pocs.observatory.earth_location ) - pointing_image.solve_field() - - observation.pointing_image = pointing_image - - pocs.logger.debug("Pointing file: {}".format(pointing_image)) + pocs.logger.debug("Pointing image: {}".format(pointing_image)) pocs.say("Ok, I've got the pointing picture, let's see how close we are.") + pointing_image.solve_field() + + # Store the solved image object + observation.pointing_images[pointing_id] = pointing_image pocs.logger.debug("Pointing Coords: {}", pointing_image.pointing) pocs.logger.debug("Pointing Error: {}", pointing_image.pointing_error) diff --git a/pocs/tests/test_config.py b/pocs/tests/test_config.py index 489a73bb8..4a231a7ea 100644 --- a/pocs/tests/test_config.py +++ b/pocs/tests/test_config.py @@ -172,4 +172,4 @@ def test_location_positive_elevation(config): def test_directories(config): - assert config['directories']['data'] == '{}/data'.format(os.getenv('PANDIR')) + assert config['directories']['data'] == os.path.join(os.getenv('PANDIR'), 'data') diff --git a/pocs/tests/test_observation.py b/pocs/tests/test_observation.py index 895813683..5935f59d6 100644 --- a/pocs/tests/test_observation.py +++ b/pocs/tests/test_observation.py @@ -92,34 +92,37 @@ def test_no_exposures(field): obs = Observation(field, exp_time=17.5 * u.second, min_nexp=27, exp_set_size=9) assert obs.first_exposure is None assert obs.last_exposure is None + assert obs.pointing_image is None def test_last_exposure_and_reset(field): obs = Observation(field, exp_time=17.5 * u.second, min_nexp=27, exp_set_size=9) status = obs.status() - assert status['current_exp'] == obs.current_exp + assert status['current_exp'] == obs.current_exp_num # Mimic taking exposures obs.merit = 112.5 for i in range(5): - obs.current_exp += 1 obs.exposure_list['image_{}'.format(i)] = 'full_image_path_{}'.format(i) last = obs.last_exposure assert isinstance(last, tuple) assert obs.merit > 0.0 - assert obs.current_exp == 5 + assert obs.current_exp_num == 5 assert last[0] == 'image_4' assert last[1] == 'full_image_path_4' + assert isinstance(obs.first_exposure, tuple) + assert obs.first_exposure[0] == 'image_0' + assert obs.first_exposure[1] == 'full_image_path_0' + obs.reset() status2 = obs.status() assert status2['current_exp'] == 0 assert status2['merit'] == 0.0 - - assert isinstance(obs.first_exposure, tuple) - assert obs.first_exposure[0] == 'image_0' - assert obs.first_exposure[1] == 'full_image_path_0' + assert obs.first_exposure is None + assert obs.last_exposure is None + assert obs.seq_time is None diff --git a/pocs/tests/test_observatory.py b/pocs/tests/test_observatory.py index f41729a24..2d1944114 100644 --- a/pocs/tests/test_observatory.py +++ b/pocs/tests/test_observatory.py @@ -228,9 +228,9 @@ def test_observe(observatory): assert len(observatory.scheduler.observed_list) == 1 - assert observatory.current_observation.current_exp == 0 + assert observatory.current_observation.current_exp_num == 0 observatory.observe() - assert observatory.current_observation.current_exp == 1 + assert observatory.current_observation.current_exp_num == 1 observatory.cleanup_observations() assert len(observatory.scheduler.observed_list) == 0