def init_target_with_bad_json(self): missingfilter = ( '{"targetid": 3, "fieldid": 2573, "ra_rad": 5.24504477561707, ' '"dec_rad": -0.030036505561584215, "ang_rad": 0.7853981633974483, ' '"num_exp": 2, "exp_times": [15.0, 15.0], "_exp_time": null, ' '"time": 0.0, "airmass": 0.0, "sky_brightness": 0.0, "cloud": 0.0, ' '"seeing": 0.0, "propid": 0, "need": 0.0, "bonus": 0.0, "value": 0.0, ' '"goal": 0, "visits": 0, "progress": 0.0, ' '"sequenceid": 0, "subsequencename": "", "groupid": 0, "groupix": 0, ' '"is_deep_drilling": false, "is_dd_firstvisit": false, "remaining_dd_visits": 0, ' '"dd_exposures": 0, "dd_filterchanges": 0, "dd_exptime": 0.0, ' '"alt_rad": 0.7853981633974483, "az_rad": 3.9269908169872414, ' '"rot_rad": 0.5235987755982988, "telalt_rad": 0.7853981633974483, ' '"telaz_rad": 3.9269908169872414, "telrot_rad": 0.5235987755982988, "propboost": 1.0, ' '"slewtime": 0.0, "cost": 0.0, "rank": 0.0, "num_props": 0, "propid_list": [], ' '"need_list": [], "bonus_list": [], "value_list": [], "propboost_list": [], ' '"sequenceid_list": [], "subsequencename_list": [], "groupid_list": [], ' '"groupix_list": [], "is_deep_drilling_list": [], ' '"is_dd_firstvisit_list": [], "remaining_dd_visits_list": [], ' '"dd_exposures_list": [], "dd_filterchanges_list": [], "dd_exptime_list": [], ' '"last_visit_time": 0.0, "note": ""}' ) t = Target() t.from_json(missingfilter)
def test_driver_state_copy(self): target2 = Target() target2.copy_driver_state(self.target) self.assertEqual(target2.alt_rad, self.alt_rad) self.assertEqual(target2.az_rad, self.az_rad) self.assertEqual(target2.ang_rad, self.ang_rad) self.assertEqual(target2.rot_rad, self.rot_rad) self.assertEqual(target2.telalt_rad, self.telalt_rad) self.assertEqual(target2.telaz_rad, self.telaz_rad) self.assertEqual(target2.telrot_rad, self.telrot_rad)
def read_script(self): scriptfilepath = self.script_file lines = file(scriptfilepath).readlines() targetid = 0 self.targetsList = [] for line in lines: line = line.strip() if not line: # skip blank line continue if line[0] == '#': # skip comment line continue targetid += 1 values = line.split() target = Target() target.fieldid = eval(values[0]) target.filter = values[1] target.ra_rad = math.radians(eval(values[2])) target.dec_rad = math.radians(eval(values[3])) target.ang_rad = math.radians(eval(values[4])) target.num_exp = eval(values[5]) target.exp_times = [int(x) for x in values[6].split(',')] self.targetsList.append(target) self.log.info("%d targets" % len(self.targetsList))
def test_json_serialization(self): jsondump = self.target.to_json() target2 = Target() target2.from_json(jsondump) self.assertEqual(self.target.targetid, target2.targetid) self.assertEqual(self.target.fieldid, target2.fieldid) self.assertEqual(self.target.filter, target2.filter) self.assertEqual(self.target.ra_rad, target2.ra_rad) self.assertEqual(self.target.dec_rad, target2.dec_rad) self.assertEqual(self.target.num_exp, target2.num_exp) self.assertListEqual(self.target.exp_times, target2.exp_times)
def __init__(self): self.log = logging.getLogger("schedulerDriver") self.params = DriverParameters() self.location = ObservatoryLocation() self.observatoryModel = ObservatoryModel(self.location, WORDY) self.observatoryModel2 = ObservatoryModel(self.location, WORDY) self.observatoryState = ObservatoryState() self.sky = AstronomicalSkyModel(self.location) self.db = FieldsDatabase() self.build_fields_dict() self.propid_counter = 0 self.science_proposal_list = [] self.start_time = 0.0 self.time = 0.0 self.targetid = 0 self.survey_started = False self.isnight = False self.sunset_timestamp = 0.0 self.sunrise_timestamp = 0.0 self.survey_duration_DAYS = 0.0 self.survey_duration_SECS = self.survey_duration_DAYS * 24 * 60 * 60.0 self.darktime = False self.mounted_filter = "" self.unmounted_filter = "" self.midnight_moonphase = 0.0 self.nulltarget = Target() self.nulltarget.targetid = -1 self.nulltarget.num_exp = 1 self.nulltarget.exp_times = [0.0] self.nulltarget.num_props = 1 self.nulltarget.propid_list = [0] self.nulltarget.need_list = [0.0] self.nulltarget.bonus_list = [0.0] self.nulltarget.value_list = [0.0] self.nulltarget.propboost_list = [1.0] self.last_winner_target = self.nulltarget.get_copy() self.deep_drilling_target = None self.need_filter_swap = False self.filter_to_unmount = "" self.filter_to_mount = "" self.cloud = 0.0 self.seeing = 0.0
def test_creation_from_topic(self): topic = collections.namedtuple( "topic", [ "targetId", "fieldId", "filter", "ra", "decl", "skyAngle", "numExposures", "exposureTimes", ], ) topic.targetId = 1 topic.fieldId = -1 topic.filter = "z" topic.ra = 274.279376 topic.decl = -14.441534 topic.skyAngle = 45.0 topic.numExposures = 3 topic.exposureTimes = [5.0, 10.0, 5.0] target = Target.from_topic(topic) self.assertEqual(target.targetid, topic.targetId) self.assertEqual(target.fieldid, topic.fieldId) self.assertEqual(target.filter, topic.filter) self.assertEqual(target.ra, topic.ra) self.assertAlmostEqual(target.dec, topic.decl, delta=1e-7) self.assertEqual(target.num_exp, topic.numExposures) self.assertListEqual(target.exp_times, topic.exposureTimes)
def test_get_deep_drilling_time(self): target = Target() target.is_deep_drilling = True target.is_dd_firstvisit = True target.remaining_dd_visits = 96 target.dd_exposures = 2 * 96 target.dd_filterchanges = 3 target.dd_exptime = 96 * 2 * 15.0 ddtime = self.model.get_deep_drilling_time(target) self.assertEqual(ddtime, 3808.0)
def setUp(self): self.targetId = 3 self.fieldId = 2573 self.band_filter = "r" self.ra = 300.518929 self.dec = -1.720965 self.ang = 45.0 self.num_exposures = 2 self.exposure_times = [15.0, 15.0] self.alt = 45.0 self.az = 225.0 self.rot = 30.0 self.telalt = 45.0 self.telaz = 225.0 self.telrot = 30.0 self.ra_rad = math.radians(self.ra) self.dec_rad = math.radians(self.dec) self.ang_rad = math.radians(self.ang) self.alt_rad = math.radians(self.alt) self.az_rad = math.radians(self.az) self.rot_rad = math.radians(self.rot) self.telalt_rad = math.radians(self.telalt) self.telaz_rad = math.radians(self.telaz) self.telrot_rad = math.radians(self.telrot) self.target = Target( self.targetId, self.fieldId, self.band_filter, self.ra_rad, self.dec_rad, self.ang_rad, self.num_exposures, self.exposure_times, ) self.target.alt_rad = self.alt_rad self.target.az_rad = self.az_rad self.target.rot_rad = self.rot_rad self.target.telalt_rad = self.telalt_rad self.target.telaz_rad = self.telaz_rad self.target.telrot_rad = self.telrot_rad
def slew(self, target): """Perform the slewing operation for the observatory to the given target. Parameters ---------- target : SALPY_scheduler.targetC The Scheduler topic instance holding the target information. Returns ------- float The time to slew the telescope from its current position to the target position. """ self.slew_count += 1 self.log.log(LoggingLevel.TRACE.value, "Slew count: {}".format(self.slew_count)) initial_slew_state = copy.deepcopy(self.model.current_state) self.log.log(LoggingLevel.TRACE.value, "Initial slew state: {}".format(initial_slew_state)) self.slew_initial_state = self.get_slew_state(initial_slew_state) sched_target = Target.from_topic(target) self.model.slew(sched_target) final_slew_state = copy.deepcopy(self.model.current_state) self.log.log(LoggingLevel.TRACE.value, "Final slew state: {}".format(final_slew_state)) self.slew_final_state = self.get_slew_state(final_slew_state) slew_time = (final_slew_state.time - initial_slew_state.time, "seconds") slew_distance = palpy.dsep(final_slew_state.ra_rad, final_slew_state.dec_rad, initial_slew_state.ra_rad, initial_slew_state.dec_rad) self.slew_history = SlewHistory(self.slew_count, initial_slew_state.time, final_slew_state.time, slew_time[0], math.degrees(slew_distance), self.observations_made) self.get_slew_activities() self.slew_maxspeeds = SlewMaxSpeeds(self.slew_count, final_slew_state.domalt_peakspeed, final_slew_state.domaz_peakspeed, final_slew_state.telalt_peakspeed, final_slew_state.telaz_peakspeed, final_slew_state.telrot_peakspeed, self.slew_count) return slew_time
def test_park(self): self.model.update_state(0) self.model.params.rotator_followsky = False self.model.params.rotator_resume_angle = False # Start at park, slew to target. # Use default configuration (dome crawl, CL updates, etc.) target = Target() target.ra_rad = math.radians(60) target.dec_rad = math.radians(-20) target.ang_rad = math.radians(0) target.filter = "z" self.model.slew(target) expected_state = "t=156.0 ra=60.000 dec=-20.000 ang=243.495 filter=z track=True " \ "alt=61.191 az=76.196 pa=243.224 rot=359.729 telaz=76.196 telrot=-0.271 " \ "mounted=['g', 'r', 'i', 'z', 'y'] unmounted=['u']" self.assertEqual(str(self.model.current_state), expected_state) self.check_delay_and_state( self.model, self.make_slewact_dict((8.387, 11.966, 0.0, 7.387, 36.0, 18.775, 48.507, 1.0, 120.0, 2.0)), ['telopticsclosedloop', 'filter'], (-3.50, 7.00, 0.0, -1.75, 1.50)) self.model.park() expected_state = "t=241.1 ra=30.487 dec=-26.744 ang=180.000 filter=z track=False " \ "alt=86.500 az=0.000 pa=180.000 rot=0.000 telaz=0.000 telrot=0.000 " \ "mounted=['g', 'r', 'i', 'z', 'y'] unmounted=['u']" self.assertEqual(str(self.model.current_state), expected_state) self.check_delay_and_state( self.model, self.make_slewact_dict( (8.231, 11.885, 1.041, 7.231, 36.0, 18.462, 48.130, 1.0, 0.0, 2.0)), ['telopticsclosedloop', 'domazsettle', 'domaz'], (3.50, -7.00, 0.520, 1.75, -1.50))
def __init__(self): self.log = logging.getLogger("schedulerDriver") self.params = DriverParameters() self.location = ObservatoryLocation() self.observatoryModel = ObservatoryModel(self.location, WORDY) self.observatoryModel2 = ObservatoryModel(self.location, WORDY) self.observatoryState = ObservatoryState() self.sky = AstronomicalSkyModel(self.location) self.propid_counter = 0 self.night = 0 self.start_time = 0.0 self.time = 0.0 self.targetid = 0 self.survey_started = False self.isnight = False self.sunset_timestamp = 0.0 self.sunrise_timestamp = 0.0 self.survey_duration_DAYS = 0.0 self.survey_duration_SECS = self.survey_duration_DAYS * 24 * 60 * 60.0 self.darktime = False self.mounted_filter = "" self.unmounted_filter = "" self.midnight_moonphase = 0.0 self.nulltarget = Target() self.nulltarget.targetid = -1 self.nulltarget.num_exp = 1 self.nulltarget.exp_times = [0.0] self.nulltarget.num_props = 1 self.nulltarget.propid_list = [0] self.nulltarget.need_list = [0.0] self.nulltarget.bonus_list = [0.0] self.nulltarget.value_list = [0.0] self.nulltarget.propboost_list = [1.0] self.last_winner_target = self.nulltarget.get_copy() self.deep_drilling_target = None self.need_filter_swap = False self.filter_to_unmount = "" self.filter_to_mount = "" self.cloud = 0.0 self.seeing = 0.0
def test_creation_from_topic(self): topic = collections.namedtuple('topic', ['targetId', 'fieldId', 'filter', 'ra', 'decl', 'skyAngle', 'numExposures', 'exposureTimes']) topic.targetId = 1 topic.fieldId = -1 topic.filter = 'z' topic.ra = 274.279376 topic.decl = -14.441534 topic.skyAngle = 45.0 topic.numExposures = 3 topic.exposureTimes = [5.0, 10.0, 5.0] target = Target.from_topic(topic) self.assertEqual(target.targetid, topic.targetId) self.assertEqual(target.fieldid, topic.fieldId) self.assertEqual(target.filter, topic.filter) self.assertEqual(target.ra, topic.ra) self.assertAlmostEqual(target.dec, topic.decl, delta=1e-7) self.assertEqual(target.num_exp, topic.numExposures) self.assertListEqual(target.exp_times, topic.exposureTimes)
def test_domecrawl(self): self.model.update_state(0) self.assertEqual( str(self.model.current_state), "t=0.0 ra=29.480 dec=-26.744 ang=180.000 " "filter=r track=False alt=86.500 az=0.000 pa=180.000 rot=0.000 " "telaz=0.000 telrot=0.000 " "mounted=['g', 'r', 'i', 'z', 'y'] unmounted=['u']") target = Target() target.ra_rad = math.radians(35) target.dec_rad = math.radians(-27) target.ang_rad = math.radians(0) target.filter = "r" # Just test whether dome crawl is faster or not. # If we test the final slew state, this is including other aspects of slew model (such as CLoptics). self.model.params.domaz_free_range = 0 delay_nocrawl = self.model.get_slew_delay(target) self.model.params.domaz_free_range = np.radians(4.0) delay_crawl = self.model.get_slew_delay(target) self.assertTrue(delay_crawl < delay_nocrawl)
def test_slewdata(self): self.model.update_state(0) # Use old values, to avoid updating final states. self.model.params.domaz_free_range = 0 self.model.params.optics_cl_delay = [0, 20.0] self.model.params.rotator_followsky = True target = Target() target.ra_rad = math.radians(60) target.dec_rad = math.radians(-20) target.ang_rad = math.radians(0) target.filter = "r" self.model.slew(target) self.assertEqual( str(self.model.current_state), "t=74.2 ra=60.000 dec=-20.000 ang=180.000 " "filter=r track=True alt=60.904 az=76.495 pa=243.368 rot=63.368 " "telaz=76.495 telrot=63.368 " "mounted=['g', 'r', 'i', 'z', 'y'] unmounted=['u']") self.check_delay_and_state( self.model, self.make_slewact_dict( (8.387, 11.966, 21.641, 7.387, 20.0, 18.775, 53.174, 1.0, 0.0, 2.0)), ['telopticsclosedloop', 'domazsettle', 'domaz'], (-3.50, 7.00, 3.50, -1.75, 1.50)) target = Target() target.ra_rad = math.radians(60) target.dec_rad = math.radians(-20) target.ang_rad = math.radians(0) target.filter = "i" self.model.slew(target) self.assertEqual( str(self.model.current_state), "t=194.2 ra=60.000 dec=-20.000 ang=180.000 " "filter=i track=True alt=61.324 az=76.056 pa=243.156 rot=63.156 " "telaz=76.056 telrot=63.156 " "mounted=['g', 'r', 'i', 'z', 'y'] unmounted=['u']") self.check_delay_and_state( self.model, self.make_slewact_dict( (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 120.0, 2.0)), ['filter'], (0, 0, 0, 0, 0)) target = Target() target.ra_rad = math.radians(61) target.dec_rad = math.radians(-21) target.ang_rad = math.radians(1) target.filter = "i" self.model.slew(target) self.assertEqual( str(self.model.current_state), "t=199.0 ra=61.000 dec=-21.000 ang=181.000 " "filter=i track=True alt=60.931 az=78.751 pa=245.172 rot=64.172 " "telaz=78.751 telrot=64.172 " "mounted=['g', 'r', 'i', 'z', 'y'] unmounted=['u']") self.check_delay_and_state( self.model, self.make_slewact_dict((0.683, 1.244, 2.022, 0.117, 0.0, 1.365, 3.801, 1.0, 0.000, 2.000)), ['domazsettle', 'domaz'], (-1.194, 4.354, 1.011, -0.598, 1.425))
def test_slew(self): self.model.update_state(0) self.model.params.domaz_free_range = 0 self.model.params.optics_cl_delay = [0, 20.0] self.model.params.rotator_followsky = True self.assertEqual( str(self.model.current_state), "t=0.0 ra=29.480 dec=-26.744 ang=180.000 " "filter=r track=False alt=86.500 az=0.000 pa=180.000 rot=0.000 " "telaz=0.000 telrot=0.000 " "mounted=['g', 'r', 'i', 'z', 'y'] unmounted=['u']") target = Target() target.ra_rad = math.radians(60) target.dec_rad = math.radians(-20) target.ang_rad = math.radians(0) target.filter = "r" self.model.slew(target) self.assertEqual( str(self.model.current_state), "t=74.2 ra=60.000 dec=-20.000 ang=180.000 " "filter=r track=True alt=60.904 az=76.495 pa=243.368 rot=63.368 " "telaz=76.495 telrot=63.368 " "mounted=['g', 'r', 'i', 'z', 'y'] unmounted=['u']") target = Target() target.ra_rad = math.radians(60) target.dec_rad = math.radians(-20) target.ang_rad = math.radians(0) target.filter = "i" self.model.slew(target) self.assertEqual( str(self.model.current_state), "t=194.2 ra=60.000 dec=-20.000 ang=180.000 " "filter=i track=True alt=61.324 az=76.056 pa=243.156 rot=63.156 " "telaz=76.056 telrot=63.156 " "mounted=['g', 'r', 'i', 'z', 'y'] unmounted=['u']")
def test_get_slew_delay_followsky_false(self): # Test slew time without followsky option. Similar to test_get_slew_delay above. self.model.update_state(0) self.model.params.rotator_followsky = False expected_state = "t=0.0 ra=29.480 dec=-26.744 ang=180.000 " \ "filter=r track=False alt=86.500 az=0.000 pa=180.000 rot=0.000 " \ "telaz=0.000 telrot=0.000 " \ "mounted=['g', 'r', 'i', 'z', 'y'] unmounted=['u']" self.assertEqual(str(self.model.current_state), expected_state) target = Target() target.ra_rad = math.radians(60) target.dec_rad = math.radians(-20) target.ang_rad = math.radians(0) target.filter = "r" delay, status = self.model.get_slew_delay(target) self.assertAlmostEqual(delay, 85.507, delta=1e-3) self.model.slew(target) target = Target() target.ra_rad = math.radians(60) target.dec_rad = math.radians(-20) target.ang_rad = math.radians(0) target.filter = "g" delay, status = self.model.get_slew_delay(target) self.assertAlmostEqual(delay, 120, delta=1e-3) target = Target() target.ra_rad = math.radians(50) target.dec_rad = math.radians(-10) target.ang_rad = math.radians(10) target.filter = "r" delay, status = self.model.get_slew_delay(target) self.assertAlmostEqual(delay, 17.913, delta=1e-3) self.model.slew(target) delay, status = self.model.get_slew_delay(target) self.assertAlmostEqual(delay, 2.0, delta=1e-3) # Here is the difference when using followsky = False target.ang_rad = math.radians(15) delay, status = self.model.get_slew_delay(target) self.assertAlmostEqual(delay, 2.0, delta=1e-3)
def test_get_slew_delay(self): self.model.update_state(0) # Use old values, to avoid updating final states. self.model.params.rotator_followsky = True self.assertEqual( str(self.model.current_state), "t=0.0 ra=29.480 dec=-26.744 ang=180.000 " "filter=r track=False alt=86.500 az=0.000 pa=180.000 rot=0.000 " "telaz=0.000 telrot=0.000 " "mounted=['g', 'r', 'i', 'z', 'y'] unmounted=['u']") # This slew will include a CL optics correction. target = Target() target.ra_rad = math.radians(60) target.dec_rad = math.radians(-20) target.ang_rad = math.radians(0) target.filter = "r" delay, status = self.model.get_slew_delay(target) self.assertAlmostEqual(delay, 85.507, delta=1e-3) self.model.slew(target) # This slew simply includes a filter change. target = Target() target.ra_rad = math.radians(60) target.dec_rad = math.radians(-20) target.ang_rad = math.radians(0) target.filter = "g" delay, status = self.model.get_slew_delay(target) self.assertAlmostEqual(delay, 120, delta=1e-3) # This slew does not include OL correction, but does involve dome crawl. target = Target() target.ra_rad = math.radians(50) target.dec_rad = math.radians(-10) target.ang_rad = math.radians(10) target.filter = "r" delay, status = self.model.get_slew_delay(target) self.assertAlmostEqual(delay, 17.913, delta=1e-3) # This slew is only readout. self.model.slew(target) delay, status = self.model.get_slew_delay(target) self.assertAlmostEqual(delay, 2.0, delta=1e-3) # This slew involves rotator. target.ang_rad = math.radians(15) delay, status = self.model.get_slew_delay(target) self.assertAlmostEqual(delay, 4.472, delta=1e-3)
class Driver(object): def __init__(self): self.log = logging.getLogger("schedulerDriver") self.params = DriverParameters() self.location = ObservatoryLocation() self.observatoryModel = ObservatoryModel(self.location, WORDY) self.observatoryModel2 = ObservatoryModel(self.location, WORDY) self.observatoryState = ObservatoryState() self.sky = AstronomicalSkyModel(self.location) self.db = FieldsDatabase() self.build_fields_dict() self.propid_counter = 0 self.science_proposal_list = [] self.start_time = 0.0 self.time = 0.0 self.targetid = 0 self.survey_started = False self.isnight = False self.sunset_timestamp = 0.0 self.sunrise_timestamp = 0.0 self.survey_duration_DAYS = 0.0 self.survey_duration_SECS = self.survey_duration_DAYS * 24 * 60 * 60.0 self.darktime = False self.mounted_filter = "" self.unmounted_filter = "" self.midnight_moonphase = 0.0 self.nulltarget = Target() self.nulltarget.targetid = -1 self.nulltarget.num_exp = 1 self.nulltarget.exp_times = [0.0] self.nulltarget.num_props = 1 self.nulltarget.propid_list = [0] self.nulltarget.need_list = [0.0] self.nulltarget.bonus_list = [0.0] self.nulltarget.value_list = [0.0] self.nulltarget.propboost_list = [1.0] self.last_winner_target = self.nulltarget.get_copy() self.deep_drilling_target = None self.need_filter_swap = False self.filter_to_unmount = "" self.filter_to_mount = "" self.cloud = 0.0 self.seeing = 0.0 def configure_survey(self, survey_conf_file): prop_conf_path = os.path.dirname(survey_conf_file) confdict = read_conf_file(survey_conf_file) self.survey_duration_DAYS = confdict["survey"]["survey_duration"] self.survey_duration_SECS = self.survey_duration_DAYS * 24 * 60 * 60.0 self.propid_counter = 0 self.science_proposal_list = [] if 'scripted_propconf' in confdict["proposals"]: scripted_propconflist = confdict["proposals"]["scripted_propconf"] else: scripted_propconflist = [] if not isinstance(scripted_propconflist, list): # turn it into a list with one entry propconf = scripted_propconflist scripted_propconflist = [] scripted_propconflist.append(propconf) self.log.info("configure_survey: scripted proposals %s" % (scripted_propconflist)) for k in range(len(scripted_propconflist)): self.propid_counter += 1 scripted_prop = ScriptedProposal(self.propid_counter, os.path.join(prop_conf_path, "{}".format(scripted_propconflist[k])), self.sky) self.science_proposal_list.append(scripted_prop) if 'areadistribution_propconf' in confdict["proposals"]: areadistribution_propconflist = confdict["proposals"]["areadistribution_propconf"] else: areadistribution_propconflist = [] self.log.info("areadistributionPropConf:%s default" % (areadistribution_propconflist)) if not isinstance(areadistribution_propconflist, list): # turn it into a list with one entry propconf = areadistribution_propconflist areadistribution_propconflist = [] areadistribution_propconflist.append(propconf) self.log.info("init: areadistribution proposals %s" % (areadistribution_propconflist)) for k in range(len(areadistribution_propconflist)): self.propid_counter += 1 configfilepath = os.path.join(prop_conf_path, "{}".format(areadistribution_propconflist[k])) (path, name_ext) = os.path.split(configfilepath) (name, ext) = os.path.splitext(name_ext) proposal_confdict = read_conf_file(configfilepath) self.create_area_proposal(self.propid_counter, name, proposal_confdict) for prop in self.science_proposal_list: prop.configure_constraints(self.params) def configure_duration(self, survey_duration): self.survey_duration_DAYS = survey_duration self.survey_duration_SECS = survey_duration * 24 * 60 * 60.0 def configure(self, confdict): self.params.configure(confdict) self.log.log(WORDY, "configure: coadd_values=%s" % (self.params.coadd_values)) self.log.log(WORDY, "configure: time_balancing=%s" % (self.params.time_balancing)) self.log.log(WORDY, "configure: timecost_dc=%.3f" % (self.params.timecost_dc)) self.log.log(WORDY, "configure: timecost_dt=%.3f" % (self.params.timecost_dt)) self.log.log(WORDY, "configure: timecost_k=%.3f" % (self.params.timecost_k)) self.log.log(WORDY, "configure: timecost_weight=%.3f" % (self.params.timecost_weight)) self.log.log(WORDY, "configure: night_boundary=%.1f" % (self.params.night_boundary)) self.log.log(WORDY, "configure: ignore_sky_brightness=%s" % (self.params.ignore_sky_brightness)) self.log.log(WORDY, "configure: ignore_airmass=%s" % (self.params.ignore_airmass)) self.log.log(WORDY, "configure: ignore_clouds=%s" % (self.params.ignore_clouds)) self.log.log(WORDY, "configure: ignore_seeing=%s" % (self.params.ignore_seeing)) self.log.log(WORDY, "configure: new_moon_phase_threshold=%.2f" % (self.params.new_moon_phase_threshold)) for prop in self.science_proposal_list: prop.configure_constraints(self.params) def configure_location(self, confdict): self.location.configure(confdict) self.observatoryModel.location.configure(confdict) self.observatoryModel2.location.configure(confdict) self.sky.update_location(self.location) def configure_observatory(self, confdict): self.observatoryModel.configure(confdict) self.observatoryModel2.configure(confdict) def configure_telescope(self, confdict): self.observatoryModel.configure_telescope(confdict) self.observatoryModel2.configure_telescope(confdict) def configure_rotator(self, confdict): self.observatoryModel.configure_rotator(confdict) self.observatoryModel2.configure_rotator(confdict) def configure_dome(self, confdict): self.observatoryModel.configure_dome(confdict) self.observatoryModel2.configure_dome(confdict) def configure_optics(self, confdict): self.observatoryModel.configure_optics(confdict) self.observatoryModel2.configure_optics(confdict) def configure_camera(self, confdict): self.observatoryModel.configure_camera(confdict) self.observatoryModel2.configure_camera(confdict) def configure_slew(self, confdict): self.observatoryModel.configure_slew(confdict) self.observatoryModel2.configure_slew(confdict) def configure_park(self, confdict): self.observatoryModel.configure_park(confdict) self.observatoryModel2.configure_park(confdict) def create_area_proposal(self, propid, name, config_dict): self.propid_counter += 1 area_prop = AreaDistributionProposal(propid, name, config_dict, self.sky) area_prop.configure_constraints(self.params) self.science_proposal_list.append(area_prop) def create_sequence_proposal(self, propid, name, config_dict): self.propid_counter += 1 seq_prop = TimeDistributionProposal(propid, name, config_dict, self.sky) seq_prop.configure_constraints(self.params) self.science_proposal_list.append(seq_prop) def build_fields_dict(self): sql = "select * from Field" res = self.db.query(sql) self.fields_dict = {} for row in res: field = Field() fieldid = row[0] field.fieldid = fieldid field.fov_rad = math.radians(row[1]) field.ra_rad = math.radians(row[2]) field.dec_rad = math.radians(row[3]) field.gl_rad = math.radians(row[4]) field.gb_rad = math.radians(row[5]) field.el_rad = math.radians(row[6]) field.eb_rad = math.radians(row[7]) self.fields_dict[fieldid] = field self.log.log(EXTENSIVE, "buildFieldsTable: %s" % (self.fields_dict[fieldid])) self.log.info("buildFieldsTable: %d fields" % (len(self.fields_dict))) def get_fields_dict(self): return self.fields_dict def start_survey(self, timestamp, night): self.start_time = timestamp self.log.info("start_survey t=%.6f" % timestamp) self.survey_started = True for prop in self.science_proposal_list: prop.start_survey() self.sky.update(timestamp) (sunset, sunrise) = self.sky.get_night_boundaries(self.params.night_boundary) self.log.debug("start_survey sunset=%.6f sunrise=%.6f" % (sunset, sunrise)) # if round(sunset) <= round(timestamp) < round(sunrise): if sunset <= timestamp < sunrise: self.start_night(timestamp, night) self.sunset_timestamp = sunset self.sunrise_timestamp = sunrise def end_survey(self): self.log.info("end_survey") for prop in self.science_proposal_list: prop.end_survey() def start_night(self, timestamp, night): timeprogress = (timestamp - self.start_time) / self.survey_duration_SECS self.log.info("start_night t=%.6f, night=%d timeprogress=%.2f%%" % (timestamp, night, 100 * timeprogress)) self.isnight = True for prop in self.science_proposal_list: prop.start_night(timestamp, self.observatoryModel.current_state.mountedfilters, night) def end_night(self, timestamp, night): timeprogress = (timestamp - self.start_time) / self.survey_duration_SECS self.log.info("end_night t=%.6f, night=%d timeprogress=%.2f%%" % (timestamp, night, 100 * timeprogress)) self.isnight = False self.last_winner_target = self.nulltarget self.deep_drilling_target = None total_filter_visits_dict = {} total_filter_goal_dict = {} total_filter_progress_dict = {} for prop in self.science_proposal_list: prop.end_night(timestamp) filter_visits_dict = {} filter_goal_dict = {} filter_progress_dict = {} for filter in self.observatoryModel.filters: if filter not in total_filter_visits_dict: total_filter_visits_dict[filter] = 0 total_filter_goal_dict[filter] = 0 filter_visits_dict[filter] = prop.get_filter_visits(filter) filter_goal_dict[filter] = prop.get_filter_goal(filter) filter_progress_dict[filter] = prop.get_filter_progress(filter) total_filter_visits_dict[filter] += filter_visits_dict[filter] total_filter_goal_dict[filter] += filter_goal_dict[filter] self.log.debug("end_night propid=%d name=%s filter=%s progress=%.2f%%" % (prop.propid, prop.name, filter, 100 * filter_progress_dict[filter])) for filter in self.observatoryModel.filters: if total_filter_goal_dict[filter] > 0: total_filter_progress_dict[filter] = \ float(total_filter_visits_dict[filter]) / total_filter_goal_dict[filter] else: total_filter_progress_dict[filter] = 0.0 self.log.info("end_night filter=%s progress=%.2f%%" % (filter, 100 * total_filter_progress_dict[filter])) previous_midnight_moonphase = self.midnight_moonphase self.sky.update(timestamp) (sunset, sunrise) = self.sky.get_night_boundaries(self.params.night_boundary) self.log.debug("end_night sunset=%.6f sunrise=%.6f" % (sunset, sunrise)) self.sunset_timestamp = sunset self.sunrise_timestamp = sunrise next_midnight = (sunset + sunrise) / 2 self.sky.update(next_midnight) info = self.sky.get_moon_sun_info(numpy.array([0.0]), numpy.array([0.0])) self.midnight_moonphase = info["moonPhase"] self.log.info("end_night next moonphase=%.2f%%" % (self.midnight_moonphase)) self.need_filter_swap = False self.filter_to_mount = "" self.filter_to_unmount = "" if self.darktime: if self.midnight_moonphase > previous_midnight_moonphase: self.log.info("end_night dark time waxing") if self.midnight_moonphase > self.params.new_moon_phase_threshold: self.need_filter_swap = True self.filter_to_mount = self.unmounted_filter self.filter_to_unmount = self.mounted_filter self.darktime = False else: self.log.info("end_night dark time waning") else: if self.midnight_moonphase < previous_midnight_moonphase: self.log.info("end_night bright time waning") if self.midnight_moonphase < self.params.new_moon_phase_threshold: self.need_filter_swap = True self.filter_to_mount = self.observatoryModel.params.filter_darktime max_progress = -1.0 for filter in self.observatoryModel.params.filter_removable_list: if total_filter_progress_dict[filter] > max_progress: self.filter_to_unmount = filter max_progress = total_filter_progress_dict[filter] self.darktime = True else: self.log.info("end_night bright time waxing") if self.need_filter_swap: self.log.debug("end_night filter swap %s=>cam=>%s" % (self.filter_to_mount, self.filter_to_unmount)) def swap_filter(self, filter_to_unmount, filter_to_mount): self.log.info("swap_filter swap %s=>cam=>%s" % (filter_to_mount, filter_to_unmount)) self.observatoryModel.swap_filter(filter_to_unmount) self.unmounted_filter = filter_to_unmount self.mounted_filter = filter_to_mount return def update_time(self, timestamp, night): self.time = timestamp self.observatoryModel.update_state(self.time) if not self.survey_started: self.start_survey(timestamp, night) if self.isnight: # if round(timestamp) >= round(self.sunrise_timestamp): if timestamp >= self.sunrise_timestamp: self.end_night(timestamp, night) else: # if round(timestamp) >= round(self.sunset_timestamp): if timestamp >= self.sunset_timestamp: self.start_night(timestamp, night) return self.isnight def get_need_filter_swap(self): return (self.need_filter_swap, self.filter_to_unmount, self.filter_to_mount) def update_internal_conditions(self, observatory_state, night): if observatory_state.unmountedfilters != self.observatoryModel.current_state.unmountedfilters: unmount = observatory_state.unmountedfilters[0] mount = self.observatoryModel.current_state.unmountedfilters[0] self.swap_filter(unmount, mount) for prop in self.science_proposal_list: prop.start_night(observatory_state.time, observatory_state.mountedfilters, night) self.time = observatory_state.time self.observatoryModel.set_state(observatory_state) self.observatoryState.set(observatory_state) def update_external_conditions(self, cloud, seeing): self.cloud = cloud self.seeing = seeing return def select_next_target(self): if not self.isnight: return self.nulltarget targets_dict = {} ranked_targets_list = [] propboost_dict = {} sumboost = 0.0 timeprogress = (self.time - self.start_time) / self.survey_duration_SECS for prop in self.science_proposal_list: progress = prop.get_progress() if self.params.time_balancing: if progress > 0.0: if timeprogress < 1.0: needindex = (1.0 - progress) / (1.0 - timeprogress) else: needindex = 0.0 if timeprogress > 0.0: progressindex = progress / timeprogress else: progressindex = 1.0 propboost_dict[prop.propid] = needindex / progressindex else: propboost_dict[prop.propid] = 1.0 else: propboost_dict[prop.propid] = 1.0 sumboost += propboost_dict[prop.propid] if self.deep_drilling_target is not None: self.log.debug("select_next_target: in deep drilling %s" % str(self.deep_drilling_target)) if self.observatoryModel.is_filter_change_allowed(): constrained_filter = None else: constrained_filter = self.observatoryModel.current_state.filter num_filter_changes = self.observatoryModel.get_number_filter_changes() delta_burst = self.observatoryModel.get_delta_filter_burst() delta_avg = self.observatoryModel.get_delta_filter_avg() self.log.debug("select_next_target: filter changes num=%i tburst=%.1f tavg=%.1f constrained=%s" % (num_filter_changes, delta_burst, delta_avg, constrained_filter)) for prop in self.science_proposal_list: propboost_dict[prop.propid] = \ (propboost_dict[prop.propid] * len(self.science_proposal_list) / sumboost) ** self.params.propboost_weight proptarget_list = prop.suggest_targets(self.time, self.deep_drilling_target, constrained_filter, self.cloud, self.seeing) self.log.log(EXTENSIVE, "select_next_target propid=%d name=%s " "targets=%d progress=%.2f%% propboost=%.3f" % (prop.propid, prop.name, len(proptarget_list), 100 * progress, propboost_dict[prop.propid])) for target in proptarget_list: target.num_props = 1 target.propboost = propboost_dict[prop.propid] target.propid_list = [prop.propid] target.need_list = [target.need] target.bonus_list = [target.bonus] target.value_list = [target.value] target.propboost_list = [target.propboost] target.sequenceid_list = [target.sequenceid] target.subsequencename_list = [target.subsequencename] target.groupid_list = [target.groupid] target.groupix_list = [target.groupix] target.is_deep_drilling_list = [target.is_deep_drilling] target.is_dd_firstvisit_list = [target.is_dd_firstvisit] target.remaining_dd_visits_list = [target.remaining_dd_visits] target.dd_exposures_list = [target.dd_exposures] target.dd_filterchanges_list = [target.dd_filterchanges] target.dd_exptime_list = [target.dd_exptime] fieldfilter = (target.fieldid, target.filter) if fieldfilter in targets_dict: if self.params.coadd_values: targets_dict[fieldfilter][0] = targets_dict[fieldfilter][0].get_copy() targets_dict[fieldfilter][0].need += target.need targets_dict[fieldfilter][0].bonus += target.bonus targets_dict[fieldfilter][0].value += target.value targets_dict[fieldfilter][0].propboost += target.propboost if target.is_deep_drilling: # overrides to make the coadded target a consistent deep drilling targets_dict[fieldfilter][0].is_deep_drilling = target.is_deep_drilling targets_dict[fieldfilter][0].is_dd_firstvisit = target.is_dd_firstvisit targets_dict[fieldfilter][0].remaining_dd_visits = target.remaining_dd_visits targets_dict[fieldfilter][0].dd_exposures = target.dd_exposures targets_dict[fieldfilter][0].dd_filterchanges = target.dd_filterchanges targets_dict[fieldfilter][0].dd_exptime = target.dd_exptime targets_dict[fieldfilter][0].sequenceid = target.sequenceid targets_dict[fieldfilter][0].subsequencename = target.subsequencename targets_dict[fieldfilter][0].groupid = target.groupid targets_dict[fieldfilter][0].groupix = target.groupix else: # new target to coadd is not deep drilling if not targets_dict[fieldfilter][0].is_deep_drilling: # coadded target is not deep drilling # overrides with new sequence information targets_dict[fieldfilter][0].sequenceid = target.sequenceid targets_dict[fieldfilter][0].subsequencename = target.subsequencename targets_dict[fieldfilter][0].groupid = target.groupid targets_dict[fieldfilter][0].groupix = target.groupix # if coadded target is already deep drilling, don't override targets_dict[fieldfilter][0].num_props += 1 targets_dict[fieldfilter][0].propid_list.append(prop.propid) targets_dict[fieldfilter][0].need_list.append(target.need) targets_dict[fieldfilter][0].bonus_list.append(target.bonus) targets_dict[fieldfilter][0].value_list.append(target.value) targets_dict[fieldfilter][0].propboost_list.append(target.propboost) targets_dict[fieldfilter][0].sequenceid_list.append(target.sequenceid) targets_dict[fieldfilter][0].subsequencename_list.append(target.subsequencename) targets_dict[fieldfilter][0].groupid_list.append(target.groupid) targets_dict[fieldfilter][0].groupix_list.append(target.groupix) targets_dict[fieldfilter][0].is_deep_drilling_list.append(target.is_deep_drilling) targets_dict[fieldfilter][0].is_dd_firstvisit_list.append(target.is_dd_firstvisit) targets_dict[fieldfilter][0].remaining_dd_visits_list.append( target.remaining_dd_visits) targets_dict[fieldfilter][0].dd_exposures_list.append(target.dd_exposures) targets_dict[fieldfilter][0].dd_filterchanges_list.append(target.dd_filterchanges) targets_dict[fieldfilter][0].dd_exptime_list.append(target.dd_exptime) else: targets_dict[fieldfilter].append(target) else: targets_dict[fieldfilter] = [target] filtercost = self.compute_filterchange_cost() * self.params.filtercost_weight for fieldfilter in targets_dict: slewtime = self.observatoryModel.get_slew_delay(targets_dict[fieldfilter][0]) if slewtime >= 0: timecost = self.compute_slewtime_cost(slewtime) * self.params.timecost_weight for target in targets_dict[fieldfilter]: target.slewtime = slewtime if target.filter != self.observatoryModel.current_state.filter: target.cost = timecost + filtercost else: target.cost = timecost target.rank = (target.value * target.propboost) - target.cost ranked_targets_list.append((-target.rank, target)) sorted_list = sorted(ranked_targets_list, key=itemgetter(0)) winner_found = False while len(sorted_list) > 0 and not winner_found: winner_target = sorted_list.pop(0)[1] self.observatoryModel2.set_state(self.observatoryState) self.observatoryModel2.observe(winner_target) if winner_target.is_dd_firstvisit: ttime = self.observatoryModel2.get_deep_drilling_time(winner_target) else: ttime = 0.0 ntime = self.observatoryModel2.current_state.time + ttime + 30.0 if ntime < self.sunrise_timestamp: self.observatoryModel2.update_state(ntime) if self.observatoryModel2.current_state.tracking: self.targetid += 1 winner_target.targetid = self.targetid winner_target.time = self.time winner_found = True else: self.log.debug("select_next_target: target rejected ttime=%.1f %s" % (ttime, str(winner_target))) self.log.debug("select_next_target: state rejected %s" % str(self.observatoryModel2.current_state)) else: self.log.debug("select_next_target: target rejected ttime=%.1f %s" % (ttime, str(winner_target))) self.log.debug("select_next_target: rejected due to end of night") if ttime == 0.0: # ttime == 0 means it is a regular visit (not DD) # if there is no time left for a single visit then quit break if winner_found: if not self.params.coadd_values: first_target = targets_dict[(winner_target.fieldid, winner_target.filter)][0] if first_target.propid != winner_target.propid: winner_target.copy_driver_state(first_target) self.last_winner_target = winner_target.get_copy() else: self.last_winner_target = self.nulltarget return self.last_winner_target def register_observation(self, observation): target_list = [] if observation.targetid > 0: if self.observation_fulfills_target(observation, self.last_winner_target): observation = self.last_winner_target else: self.log.info("register_observation: unexpected observation %s" % str(observation)) for prop in self.science_proposal_list: target = prop.register_observation(observation) if target is not None: target_list.append(target) self.last_observation = observation.get_copy() if self.last_observation.is_deep_drilling and (self.last_observation.remaining_dd_visits > 1): self.deep_drilling_target = self.last_observation else: self.deep_drilling_target = None return target_list def compute_slewtime_cost(self, slewtime): cost = (self.params.timecost_k / (slewtime + self.params.timecost_dt) - self.params.timecost_dc - self.params.timecost_cref) / (1.0 - self.params.timecost_cref) #cost = self.params.timecost_k / (slewtime + self.params.timecost_dt) - self.params.timecost_dc return cost def compute_filterchange_cost(self): t = self.observatoryModel.get_delta_last_filterchange() T = self.observatoryModel.params.filter_max_changes_avg_interval if t < T: cost = 1.0 - t / T else: cost = 0.0 return cost def observation_fulfills_target(self, observ, target): return (observ.fieldid == target.fieldid) and (observ.filter == target.filter)
def observe(self, observation): """Try to make an observation Returns ------- observation : observation object None if there was no observation taken. Completed observation with meta data filled in. new_night : bool Have we started a new night. """ start_night = self.night.copy() # Make sure the kinematic model is set to the correct mjd t = Time(self.mjd, format='mjd') self.observatory.update_state(t.unix) if np.isnan(observation['rotSkyPos']): observation = self._update_rotSkyPos(observation) target = Target(band_filter=observation['filter'], ra_rad=observation['RA'], dec_rad=observation['dec'], ang_rad=observation['rotSkyPos'], num_exp=observation['nexp'], exp_times=[observation['exptime']]) start_ra = self.observatory.current_state.ra_rad start_dec = self.observatory.current_state.dec_rad slewtime, visittime = self.observatory.observe_times(target) # Check if the mjd after slewtime and visitime is fine: observation_worked, new_mjd = self.check_mjd(self.mjd + (slewtime + visittime) / 24. / 3600.) if observation_worked: observation['visittime'] = visittime observation['slewtime'] = slewtime observation['slewdist'] = _angularSeparation( start_ra, start_dec, self.observatory.current_state.ra_rad, self.observatory.current_state.dec_rad) self.mjd = self.mjd + slewtime / 24. / 3600. # Reach into the observatory model to pull out the relevant data it has calculated # Note, this might be after the observation has been completed. observation['alt'] = self.observatory.current_state.alt_rad observation['az'] = self.observatory.current_state.az_rad observation['pa'] = self.observatory.current_state.pa_rad observation['rotTelPos'] = self.observatory.current_state.rot_rad observation['rotSkyPos'] = self.observatory.current_state.ang_rad # Metadata on observation is after slew and settle, so at start of exposure. result = self.observation_add_data(observation) self.mjd = self.mjd + visittime / 24. / 3600. new_night = False else: result = None self.observatory.park() # Skip to next legitimate mjd self.mjd = new_mjd now_night = self.night if now_night == start_night: new_night = False else: new_night = True return result, new_night
def start_night(self, timestamp, filters_mounted_tonight_list, night): Proposal.start_night(self, timestamp, filters_mounted_tonight_list, night) self.fieldsvisitedtonight = {} self.tonight_filters_list = [] self.tonight_targets = 0 self.tonight_targets_dict = {} for filter in filters_mounted_tonight_list: self.tonight_filters_list.append(filter) self.build_tonight_fields_list(timestamp, night) self.tonight_fields = len(self.tonight_fields_list) # compute at start night for field in self.tonight_fields_list: fieldid = field.fieldid # add new fields to fields dictionary if fieldid not in self.survey_fields_dict: self.survey_fields_dict[fieldid] = field.get_copy() self.survey_fields += 1 # add new fields to targets dictionary if fieldid not in self.survey_targets_dict: self.survey_targets_dict[fieldid] = {} self.tonight_targets_dict[fieldid] = {} for filter in filters_mounted_tonight_list: if filter in self.params.filter_list: if self.params.filter_goal_dict[filter] > 0: if filter not in self.survey_targets_dict[fieldid]: target = Target() target.fieldid = fieldid target.filter = filter target.num_exp = self.params.filter_num_exp_dict[ filter] target.exp_times = self.params.filter_exp_times_dict[ filter] target.ra_rad = field.ra_rad target.dec_rad = field.dec_rad target.propid = self.propid target.goal = self.params.filter_goal_dict[filter] target.visits = 0 target.progress = 0.0 target.groupid = 1 target.groupix = 1 self.survey_targets_dict[fieldid][filter] = target self.survey_targets += 1 self.survey_targets_goal += target.goal self.survey_filters_goal_dict[ filter] += target.goal target = self.survey_targets_dict[fieldid][filter] if target.progress < 1.0: self.tonight_targets_dict[fieldid][filter] = target self.tonight_targets += 1 for filter in self.params.filter_list: if self.survey_filters_goal_dict[filter] > 0: self.survey_filters_progress_dict[filter] = \ float(self.survey_filters_visits_dict[filter]) / self.survey_filters_goal_dict[filter] else: self.survey_filters_progress_dict[filter] = 0.0 if self.survey_targets_goal > 0: self.survey_targets_progress = float( self.survey_targets_visits) / self.survey_targets_goal else: self.survey_targets_progress = 0.0 self.log.debug("start_night tonight fields=%i targets=%i" % (self.tonight_fields, self.tonight_targets)) self.last_observation = None self.last_observation_was_for_this_proposal = False
class TargetTest(unittest.TestCase): def setUp(self): self.targetId = 3 self.fieldId = 2573 self.band_filter = 'r' self.ra = 300.518929 self.dec = -1.720965 self.ang = 45.0 self.num_exposures = 2 self.exposure_times = [15.0, 15.0] self.alt = 45.0 self.az = 225.0 self.rot = 30.0 self.telalt = 45.0 self.telaz = 225.0 self.telrot = 30.0 self.ra_rad = math.radians(self.ra) self.dec_rad = math.radians(self.dec) self.ang_rad = math.radians(self.ang) self.alt_rad = math.radians(self.alt) self.az_rad = math.radians(self.az) self.rot_rad = math.radians(self.rot) self.telalt_rad = math.radians(self.telalt) self.telaz_rad = math.radians(self.telaz) self.telrot_rad = math.radians(self.telrot) self.target = Target(self.targetId, self.fieldId, self.band_filter, self.ra_rad, self.dec_rad, self.ang_rad, self.num_exposures, self.exposure_times) self.target.alt_rad = self.alt_rad self.target.az_rad = self.az_rad self.target.rot_rad = self.rot_rad self.target.telalt_rad = self.telalt_rad self.target.telaz_rad = self.telaz_rad self.target.telrot_rad = self.telrot_rad def test_basic_information_after_creation(self): self.assertEqual(self.target.targetid, self.targetId) self.assertEqual(self.target.fieldid, self.fieldId) self.assertEqual(self.target.filter, self.band_filter) self.assertEqual(self.target.ra, self.ra) self.assertEqual(self.target.dec, self.dec) self.assertEqual(self.target.num_exp, self.num_exposures) self.assertListEqual(self.target.exp_times, self.exposure_times) def test_json_serialization(self): jsondump = self.target.to_json() target2 = Target() target2.from_json(jsondump) self.assertEqual(self.target.targetid, target2.targetid) self.assertEqual(self.target.fieldid, target2.fieldid) self.assertEqual(self.target.filter, target2.filter) self.assertEqual(self.target.ra_rad, target2.ra_rad) self.assertEqual(self.target.dec_rad, target2.dec_rad) self.assertEqual(self.target.num_exp, target2.num_exp) self.assertListEqual(self.target.exp_times, target2.exp_times) def test_json_ingest_has_required_params(self): self.assertRaises(KeyError, self.init_target_with_bad_json) def init_target_with_bad_json(self): missingfilter = '{"targetid": 3, "fieldid": 2573, "ra_rad": 5.24504477561707, "dec_rad": -0.030036505561584215, "ang_rad": 0.7853981633974483, "num_exp": 2, "exp_times": [15.0, 15.0], "_exp_time": null, "time": 0.0, "airmass": 0.0, "sky_brightness": 0.0, "cloud": 0.0, "seeing": 0.0, "propid": 0, "need": 0.0, "bonus": 0.0, "value": 0.0, "goal": 0, "visits": 0, "progress": 0.0, "sequenceid": 0, "subsequencename": "", "groupid": 0, "groupix": 0, "is_deep_drilling": false, "is_dd_firstvisit": false, "remaining_dd_visits": 0, "dd_exposures": 0, "dd_filterchanges": 0, "dd_exptime": 0.0, "alt_rad": 0.7853981633974483, "az_rad": 3.9269908169872414, "rot_rad": 0.5235987755982988, "telalt_rad": 0.7853981633974483, "telaz_rad": 3.9269908169872414, "telrot_rad": 0.5235987755982988, "propboost": 1.0, "slewtime": 0.0, "cost": 0.0, "rank": 0.0, "num_props": 0, "propid_list": [], "need_list": [], "bonus_list": [], "value_list": [], "propboost_list": [], "sequenceid_list": [], "subsequencename_list": [], "groupid_list": [], "groupix_list": [], "is_deep_drilling_list": [], "is_dd_firstvisit_list": [], "remaining_dd_visits_list": [], "dd_exposures_list": [], "dd_filterchanges_list": [], "dd_exptime_list": [], "last_visit_time": 0.0, "note": ""}' t = Target() t.from_json(missingfilter) def test_string_representation(self): truth_str = "targetid=3 field=2573 filter=r exp_times=[15.0, 15.0] "\ "ra=300.519 dec=-1.721 ang=45.000 alt=45.000 az=225.000 "\ "rot=30.000 telalt=45.000 telaz=225.000 telrot=30.000 "\ "time=0.0 airmass=0.000 brightness=0.000 "\ "cloud=0.00 seeing=0.00 visits=0 progress=0.00% "\ "seqid=0 ssname= groupid=0 groupix=0 "\ "firstdd=False ddvisits=0 "\ "need=0.000 bonus=0.000 value=0.000 propboost=1.000 "\ "propid=[] need=[] bonus=[] value=[] propboost=[] "\ "slewtime=0.000 cost=0.000 rank=0.000 note=" self.assertEqual(str(self.target), truth_str) def test_driver_state_copy(self): target2 = Target() target2.copy_driver_state(self.target) self.assertEqual(target2.alt_rad, self.alt_rad) self.assertEqual(target2.az_rad, self.az_rad) self.assertEqual(target2.ang_rad, self.ang_rad) self.assertEqual(target2.rot_rad, self.rot_rad) self.assertEqual(target2.telalt_rad, self.telalt_rad) self.assertEqual(target2.telaz_rad, self.telaz_rad) self.assertEqual(target2.telrot_rad, self.telrot_rad) def test_copy_creation(self): target2 = self.target.get_copy() target2.targetid = 10 target2.fieldid = 2142 self.assertEqual(self.target.targetid, self.targetId) self.assertEqual(target2.targetid, 10) self.assertEqual(self.target.fieldid, self.fieldId) self.assertEqual(target2.fieldid, 2142) def test_creation_from_topic(self): topic = collections.namedtuple('topic', ['targetId', 'fieldId', 'filter', 'ra', 'decl', 'skyAngle', 'numExposures', 'exposureTimes']) topic.targetId = 1 topic.fieldId = -1 topic.filter = 'z' topic.ra = 274.279376 topic.decl = -14.441534 topic.skyAngle = 45.0 topic.numExposures = 3 topic.exposureTimes = [5.0, 10.0, 5.0] target = Target.from_topic(topic) self.assertEqual(target.targetid, topic.targetId) self.assertEqual(target.fieldid, topic.fieldId) self.assertEqual(target.filter, topic.filter) self.assertEqual(target.ra, topic.ra) self.assertAlmostEqual(target.dec, topic.decl, delta=1e-7) self.assertEqual(target.num_exp, topic.numExposures) self.assertListEqual(target.exp_times, topic.exposureTimes)
class Driver(object): def __init__(self): self.log = logging.getLogger("schedulerDriver") self.params = DriverParameters() self.location = ObservatoryLocation() self.observatoryModel = ObservatoryModel(self.location, WORDY) self.observatoryModel2 = ObservatoryModel(self.location, WORDY) self.observatoryState = ObservatoryState() self.sky = AstronomicalSkyModel(self.location) self.propid_counter = 0 self.night = 0 self.start_time = 0.0 self.time = 0.0 self.targetid = 0 self.survey_started = False self.isnight = False self.sunset_timestamp = 0.0 self.sunrise_timestamp = 0.0 self.survey_duration_DAYS = 0.0 self.survey_duration_SECS = self.survey_duration_DAYS * 24 * 60 * 60.0 self.darktime = False self.mounted_filter = "" self.unmounted_filter = "" self.midnight_moonphase = 0.0 self.nulltarget = Target() self.nulltarget.targetid = -1 self.nulltarget.num_exp = 1 self.nulltarget.exp_times = [0.0] self.nulltarget.num_props = 1 self.nulltarget.propid_list = [0] self.nulltarget.need_list = [0.0] self.nulltarget.bonus_list = [0.0] self.nulltarget.value_list = [0.0] self.nulltarget.propboost_list = [1.0] self.last_winner_target = self.nulltarget.get_copy() self.deep_drilling_target = None self.need_filter_swap = False self.filter_to_unmount = "" self.filter_to_mount = "" self.cloud = 0.0 self.seeing = 0.0 def configure_scheduler(self, **kwargs): raise NotImplemented def configure_duration(self, survey_duration): self.survey_duration_DAYS = survey_duration self.survey_duration_SECS = survey_duration * 24 * 60 * 60.0 def configure(self, confdict): self.params.configure(confdict) self.log.log(WORDY, "configure: night_boundary=%.1f" % (self.params.night_boundary)) def configure_location(self, confdict): self.location.configure(confdict) self.observatoryModel.location.configure(confdict) self.observatoryModel2.location.configure(confdict) self.sky.update_location(self.location) def configure_observatory(self, confdict): """This method calls the configure()method in ObservatoryModel class, which configures all its submodules. When initializing one can issue a call to this method with a complete set of parameters on confdict. Parameters ---------- confdict : dict() Returns ------- None """ self.observatoryModel.configure(confdict) self.observatoryModel2.configure(confdict) def configure_telescope(self, confdict): self.observatoryModel.configure_telescope(confdict) self.observatoryModel2.configure_telescope(confdict) def configure_rotator(self, confdict): self.observatoryModel.configure_rotator(confdict) self.observatoryModel2.configure_rotator(confdict) def configure_dome(self, confdict): self.observatoryModel.configure_dome(confdict) self.observatoryModel2.configure_dome(confdict) def configure_optics(self, confdict): self.observatoryModel.configure_optics(confdict) self.observatoryModel2.configure_optics(confdict) def configure_camera(self, confdict): self.observatoryModel.configure_camera(confdict) self.observatoryModel2.configure_camera(confdict) def configure_slew(self, confdict): self.observatoryModel.configure_slew(confdict) self.observatoryModel2.configure_slew(confdict) def configure_park(self, confdict): self.observatoryModel.configure_park(confdict) self.observatoryModel2.configure_park(confdict) def start_survey(self, timestamp, night): """This method begins the survey. Parameters ---------- timestamp : float night : int Returns ------- None """ self.start_time = timestamp self.log.info("start_survey t=%.6f" % timestamp) self.survey_started = True self.sky.update(timestamp) (sunset, sunrise) = self.sky.get_night_boundaries(self.params.night_boundary) self.log.debug("start_survey sunset=%.6f sunrise=%.6f" % (sunset, sunrise)) # if round(sunset) <= round(timestamp) < round(sunrise): if sunset <= timestamp < sunrise: self.start_night(timestamp, night) self.sunset_timestamp = sunset self.sunrise_timestamp = sunrise def end_survey(self): """This method ends the survey. Parameters ---------- None Returns ------- None """ self.log.info("end_survey") def start_night(self, timestamp, night): """This method is called once per night before observations begin. It is not called if the observatory is undergoing downtime. Parameters ---------- timestamp : float night : int Returns ------- None """ timeprogress = (timestamp - self.start_time) / self.survey_duration_SECS self.log.info("start_night t=%.6f, night=%d timeprogress=%.2f%%" % (timestamp, night, 100 * timeprogress)) self.isnight = True def end_night(self, timestamp, night): """This method is called once per night after observing completes. Parameters ---------- timestamp : float night : int Returns ------- None """ pass def swap_filter(self, filter_to_unmount, filter_to_mount): self.log.info("swap_filter swap %s=>cam=>%s" % (filter_to_mount, filter_to_unmount)) self.observatoryModel.swap_filter(filter_to_unmount) self.unmounted_filter = filter_to_unmount self.mounted_filter = filter_to_mount return def update_time(self, timestamp, night): self.time = timestamp self.observatoryModel.update_state(self.time) if not self.survey_started: self.start_survey(timestamp, night) if self.isnight: # if round(timestamp) >= round(self.sunrise_timestamp): if timestamp >= self.sunrise_timestamp: self.end_night(timestamp, night) else: # if round(timestamp) >= round(self.sunset_timestamp): if timestamp >= self.sunset_timestamp: self.start_night(timestamp, night) return self.isnight def get_need_filter_swap(self): """When scheduler determines that a filter swap is needed, this shall return a tuple where the first element is a TRUE value, and the second and third elements are single-character strings identifying which filter to remove from the carousel, and which filter to add, respectively. Parameters ---------- None Returns ------- Tuple (bool, str, str) """ return (self.need_filter_swap, self.filter_to_unmount, self.filter_to_mount) def update_internal_conditions(self, observatory_state, night): if observatory_state.unmountedfilters != self.observatoryModel.current_state.unmountedfilters: unmount = observatory_state.unmountedfilters[0] mount = self.observatoryModel.current_state.unmountedfilters[0] self.swap_filter(unmount, mount) self.time = observatory_state.time self.observatoryModel.set_state(observatory_state) self.observatoryState.set(observatory_state) def update_external_conditions(self, cloud, seeing): self.cloud = cloud self.seeing = seeing return def cold_start(self, observations): """Rebuilds the internal state of the scheduler from a list of observations. Parameters ---------- observations : list of Observation objects Returns ------- None """ raise NotImplemented def select_next_target(self): """Picks a target and returns it as a target object. Parameters ---------- None Returns ------- Target """ raise NotImplemented def register_observation(self, observation): """Validates observation and returns a list of successfully completed observations. Parameters ---------- observation : Observation or a python list of Observations Returns ------- Python list of one or more Observations """ raise NotImplemented
def generate_target(self, fb_observation, tag='generate'): '''Takes an observation array given by the feature based scheduler and generate an appropriate OpSim target. :param fb_observation: numpy.array :return: Target ''' # self.log.debug('%s: %s' % (tag, fb_observation)) self.targetid += 1 filtername = fb_observation['filter'] propid = fb_observation['survey_id'] target = Target() target.targetid = self.targetid target.fieldid = fb_observation['field_id'] target.filter = str(filtername) target.num_exp = fb_observation['nexp'] target.exp_times = [ fb_observation['exptime'] / fb_observation['nexp'] ] * fb_observation['nexp'] target.ra_rad = fb_observation['RA'] target.dec_rad = fb_observation['dec'] target.ang_rad = fb_observation['rotSkyPos'] target.propid = propid target.goal = 100 target.visits = 0 target.progress = 0.0 target.groupid = 1 target.groupix = 0 target.propid_list = [propid] target.need_list = [target.need] target.bonus_list = [target.bonus] target.value_list = [target.value] target.propboost_list = [target.propboost] target.sequenceid_list = [target.sequenceid] target.subsequencename_list = [target.subsequencename] target.groupid_list = [target.groupid] target.groupix_list = [target.groupix] target.is_deep_drilling_list = [target.is_deep_drilling] target.is_dd_firstvisit_list = [target.is_dd_firstvisit] target.remaining_dd_visits_list = [target.remaining_dd_visits] target.dd_exposures_list = [target.dd_exposures] target.dd_filterchanges_list = [target.dd_filterchanges] target.dd_exptime_list = [target.dd_exptime] return target
def __init__(self, propid, field, name, params): self.propid = propid self.field = field self.name = name self.num_events = params.subsequence_num_events[name] self.num_max_missed = params.subsequence_num_max_missed[name] self.time_interval = params.subsequence_time_interval[name] self.time_window_start = params.subsequence_time_window_start[name] self.time_window_max = params.subsequence_time_window_max[name] self.time_window_end = params.subsequence_time_window_end[name] self.filter_list = params.subsequence_filter_list[name] self.visits_list = params.subsequence_visits_list[name] self.filter_num_exp_dict = dict(params.filter_num_exp_dict) self.filter_exp_times_dict = dict(params.filter_exp_times_dict) self.num_visits_per_event = 0 self.filters_goal_dict = {} self.dd_exposures = 0 self.dd_exptime = 0.0 self.num_subevents = len(self.filter_list) for ix, filter in enumerate(self.filter_list): if filter not in self.filters_goal_dict: self.filters_goal_dict[filter] = 0 self.filters_goal_dict[filter] += self.num_events * self.visits_list[ix] self.num_visits_per_event += self.visits_list[ix] self.dd_exposures += self.visits_list[ix] * self.filter_num_exp_dict[filter] self.dd_exptime += self.visits_list[ix] * sum(self.filter_exp_times_dict[filter]) self.goal = self.num_events * self.num_visits_per_event if (len(self.visits_list) > 1) or (self.visits_list[0] > 1): self.is_deep_drilling = True self.dd_visits = self.num_visits_per_event self.dd_filterchanges = max(len(self.filter_list) - 1, 0) else: self.is_deep_drilling = False self.dd_visits = 0 self.dd_filterchanges = 0 self.subevent_index = 0 self.subevent_num_visits_left = self.visits_list[0] self.event_visits_list = [] self.all_events_list = [] self.obs_events_list = [] self.mis_events_list = [] self.in_deep_drilling = False self.target = Target() self.target.fieldid = field.fieldid self.target.filter = self.filter_list[self.subevent_index] self.target.num_exp = self.filter_num_exp_dict[self.target.filter] self.target.exp_times = self.filter_exp_times_dict[self.target.filter] self.target.ra_rad = field.ra_rad self.target.dec_rad = field.dec_rad self.target.propid = self.propid self.target.goal = self.goal self.target.visits = 0 self.target.progress = 0.0 self.target.sequenceid = self.field.fieldid self.target.subsequencename = self.name self.target.groupid = 1 self.target.groupix = 1 self.target.is_deep_drilling = self.is_deep_drilling self.target.is_dd_firstvisit = self.is_deep_drilling self.target.remaining_dd_visits = self.dd_visits self.target.dd_exposures = self.dd_exposures self.target.dd_filterchanges = self.dd_filterchanges self.target.dd_exptime = self.dd_exptime self.update_state()