From 5643bd511fb2ddfc476aa0f9454f8f61d18f7b3b Mon Sep 17 00:00:00 2001 From: WGolay Date: Wed, 20 Dec 2023 10:39:23 -0500 Subject: [PATCH] Fixes to schedtel table writer and transition block included in table now --- pyscope/telrun/sch.py | 4 +- pyscope/telrun/schedtab.py | 138 ++++++++-------------- pyscope/telrun/schedtel.py | 52 ++++---- tests/reference/simulator_observatory.cfg | 2 +- tests/telrun/test_schedtel.py | 8 +- 5 files changed, 89 insertions(+), 115 deletions(-) diff --git a/pyscope/telrun/sch.py b/pyscope/telrun/sch.py index cf013a85..66981cec 100644 --- a/pyscope/telrun/sch.py +++ b/pyscope/telrun/sch.py @@ -841,6 +841,8 @@ def read( final_fname = f"{fname}_{j}" else: final_fname = f"{fname}" + temp_id = astrotime.Time.now() + temp_id.format = "mjd" blocks.append( astroplan.ObservingBlock( target=obj, @@ -867,7 +869,7 @@ def read( "pm_dec": pm_dec, "comment": comment, "sch": filename.split("/")[-1].split(".")[0], - "ID": astrotime.Time.now(), + "ID": temp_id, "status": "U", "message": "Unscheduled", "sched_time": None, diff --git a/pyscope/telrun/schedtab.py b/pyscope/telrun/schedtab.py index 590d767a..228394d5 100644 --- a/pyscope/telrun/schedtab.py +++ b/pyscope/telrun/schedtab.py @@ -31,21 +31,31 @@ def blocks_to_table(observing_blocks): unscheduled_blocks_mask = np.array( [ - type(block) is astroplan.ObservingBlock and block.start_time is None + hasattr(block, "target") and block.start_time is None for block in observing_blocks ] ) open_slots_mask = np.array( - [type(block) is astroplan.Slot for block in observing_blocks] + [not hasattr(block, "target") for block in observing_blocks] + ) + + t["ID"] = np.ma.array( + [ + block.configuration["ID"] + if hasattr(block, "target") + else astrotime.Time(0, format="mjd") + for block in observing_blocks + ], + mask=open_slots_mask, ) # Populate simple columns t["name"] = [ block.name - if type(block) is astroplan.ObservingBlock + if hasattr(block, "target") else "TransitionBlock" - if type(block) is astroplan.TransitionBlock + if type(block) is not astroplan.Slot else "EmptyBlock" for block in observing_blocks ] @@ -53,37 +63,37 @@ def blocks_to_table(observing_blocks): t["start_time"] = astrotime.Time( np.ma.array( [ - block.start.jd + block.start.mjd if type(block) is astroplan.Slot else 0 if block.start_time is None - else block.start_time.jd + else block.start_time.mjd for block in observing_blocks ], mask=unscheduled_blocks_mask, ), - format="jd", + format="mjd", ) t["end_time"] = astrotime.Time( np.ma.array( [ - block.end.jd + block.end.mjd if type(block) is astroplan.Slot else 0 if block.end_time is None - else block.end_time.jd + else block.end_time.mjd for block in observing_blocks ], mask=unscheduled_blocks_mask, ), - format="jd", + format="mjd", ) t["target"] = coord.SkyCoord( [ block.target.to_string("hmsdms") - if type(block) is astroplan.ObservingBlock + if hasattr(block, "target") else "0h0m0.0s -90d0m0.0s" for block in observing_blocks ] @@ -91,16 +101,14 @@ def blocks_to_table(observing_blocks): t["priority"] = np.ma.array( [ - block.priority if type(block) is astroplan.ObservingBlock else 0 + block.priority if hasattr(block, "target") else 0 for block in observing_blocks ], mask=open_slots_mask, ) temp_list = [ - block.configuration["observer"] - if type(block) is astroplan.ObservingBlock - else [""] + block.configuration["observer"] if hasattr(block, "target") else [""] for block in observing_blocks ] t["observer"] = np.ma.array( @@ -109,9 +117,7 @@ def blocks_to_table(observing_blocks): t["code"] = np.ma.array( [ - block.configuration["code"] - if type(block) is astroplan.ObservingBlock - else "" + block.configuration["code"] if hasattr(block, "target") else "" for block in observing_blocks ], mask=open_slots_mask, @@ -119,9 +125,7 @@ def blocks_to_table(observing_blocks): t["title"] = np.ma.array( [ - block.configuration["title"] - if type(block) is astroplan.ObservingBlock - else "" + block.configuration["title"] if hasattr(block, "target") else "" for block in observing_blocks ], mask=open_slots_mask, @@ -129,9 +133,7 @@ def blocks_to_table(observing_blocks): t["filename"] = np.ma.array( [ - block.configuration["filename"] - if type(block) is astroplan.ObservingBlock - else "" + block.configuration["filename"] if hasattr(block, "target") else "" for block in observing_blocks ], mask=open_slots_mask, @@ -139,9 +141,7 @@ def blocks_to_table(observing_blocks): t["type"] = np.ma.array( [ - block.configuration["type"] - if type(block) is astroplan.ObservingBlock - else "" + block.configuration["type"] if hasattr(block, "target") else "" for block in observing_blocks ], mask=open_slots_mask, @@ -149,9 +149,7 @@ def blocks_to_table(observing_blocks): t["backend"] = np.ma.array( [ - block.configuration["backend"] - if type(block) is astroplan.ObservingBlock - else "" + block.configuration["backend"] if hasattr(block, "target") else "" for block in observing_blocks ], mask=open_slots_mask, @@ -159,9 +157,7 @@ def blocks_to_table(observing_blocks): t["filter"] = np.ma.array( [ - block.configuration["filter"] - if type(block) is astroplan.ObservingBlock - else "" + block.configuration["filter"] if hasattr(block, "target") else "" for block in observing_blocks ], mask=open_slots_mask, @@ -169,9 +165,7 @@ def blocks_to_table(observing_blocks): t["exposure"] = np.ma.array( [ - block.configuration["exposure"] - if type(block) is astroplan.ObservingBlock - else 0 + block.configuration["exposure"] if hasattr(block, "target") else 0 for block in observing_blocks ], mask=open_slots_mask, @@ -179,18 +173,14 @@ def blocks_to_table(observing_blocks): t["nexp"] = np.ma.array( [ - block.configuration["nexp"] - if type(block) is astroplan.ObservingBlock - else 0 + block.configuration["nexp"] if hasattr(block, "target") else 0 for block in observing_blocks ], mask=open_slots_mask, ) temp_list = [ - block.configuration["repositioning"] - if type(block) is astroplan.ObservingBlock - else (0, 0) + block.configuration["repositioning"] if hasattr(block, "target") else (0, 0) for block in observing_blocks ] t["repositioning"] = np.ma.array( @@ -199,9 +189,7 @@ def blocks_to_table(observing_blocks): t["shutter_state"] = np.ma.array( [ - block.configuration["shutter_state"] - if type(block) is astroplan.ObservingBlock - else False + block.configuration["shutter_state"] if hasattr(block, "target") else False for block in observing_blocks ], mask=open_slots_mask, @@ -209,18 +197,14 @@ def blocks_to_table(observing_blocks): t["readout"] = np.ma.array( [ - block.configuration["readout"] - if type(block) is astroplan.ObservingBlock - else 0 + block.configuration["readout"] if hasattr(block, "target") else 0 for block in observing_blocks ], mask=open_slots_mask, ) temp_list = [ - block.configuration["binning"] - if type(block) is astroplan.ObservingBlock - else (1, 1) + block.configuration["binning"] if hasattr(block, "target") else (1, 1) for block in observing_blocks ] t["binning"] = np.ma.array( @@ -228,9 +212,7 @@ def blocks_to_table(observing_blocks): ) temp_list = [ - block.configuration["frame_position"] - if type(block) is astroplan.ObservingBlock - else (0, 0) + block.configuration["frame_position"] if hasattr(block, "target") else (0, 0) for block in observing_blocks ] t["frame_position"] = np.ma.array( @@ -238,9 +220,7 @@ def blocks_to_table(observing_blocks): ) temp_list = [ - block.configuration["frame_size"] - if type(block) is astroplan.ObservingBlock - else (0, 0) + block.configuration["frame_size"] if hasattr(block, "target") else (0, 0) for block in observing_blocks ] t["frame_size"] = np.ma.array( @@ -250,7 +230,7 @@ def blocks_to_table(observing_blocks): t["pm_ra_cosdec"] = np.ma.array( [ block.configuration["pm_ra_cosdec"].to(u.arcsec / u.hour).value - if type(block) is astroplan.ObservingBlock + if hasattr(block, "target") else 0 for block in observing_blocks ], @@ -260,7 +240,7 @@ def blocks_to_table(observing_blocks): t["pm_dec"] = np.ma.array( [ block.configuration["pm_dec"].to(u.arcsec / u.hour).value - if type(block) is astroplan.ObservingBlock + if hasattr(block, "target") else 0 for block in observing_blocks ], @@ -269,9 +249,7 @@ def blocks_to_table(observing_blocks): t["comment"] = np.ma.array( [ - block.configuration["comment"] - if type(block) is astroplan.ObservingBlock - else "" + block.configuration["comment"] if hasattr(block, "target") else "" for block in observing_blocks ], mask=open_slots_mask, @@ -279,19 +257,7 @@ def blocks_to_table(observing_blocks): t["sch"] = np.ma.array( [ - block.configuration["sch"] - if type(block) is astroplan.ObservingBlock - else "" - for block in observing_blocks - ], - mask=open_slots_mask, - ) - - t["ID"] = np.ma.array( - [ - block.configuration["ID"] - if type(block) is astroplan.ObservingBlock - else astrotime.Time(0, format="jd") + block.configuration["sch"] if hasattr(block, "target") else "" for block in observing_blocks ], mask=open_slots_mask, @@ -299,9 +265,7 @@ def blocks_to_table(observing_blocks): t["status"] = np.ma.array( [ - block.configuration["status"] - if type(block) is astroplan.ObservingBlock - else "" + block.configuration["status"] if hasattr(block, "target") else "" for block in observing_blocks ], mask=open_slots_mask, @@ -309,9 +273,7 @@ def blocks_to_table(observing_blocks): t["message"] = np.ma.array( [ - block.configuration["message"] - if type(block) is astroplan.ObservingBlock - else "" + block.configuration["message"] if hasattr(block, "target") else "" for block in observing_blocks ], mask=open_slots_mask, @@ -320,7 +282,7 @@ def blocks_to_table(observing_blocks): t["sched_time"] = np.ma.array( [ block.configuration["sched_time"] - if type(block) is astroplan.ObservingBlock + if hasattr(block, "target") else astrotime.Time(0, format="jd") for block in observing_blocks ], @@ -333,9 +295,7 @@ def blocks_to_table(observing_blocks): len(observing_blocks), np.max( [ - len(block.constraints) - if type(block) is astroplan.ObservingBlock - else 0 + len(block.constraints) if hasattr(block, "target") else 0 for block in observing_blocks ] ), @@ -346,15 +306,13 @@ def blocks_to_table(observing_blocks): constraint_list = np.full( np.max( [ - len(block.constraints) - if type(block) is astroplan.ObservingBlock - else 0 + len(block.constraints) if hasattr(block, "target") else 0 for block in observing_blocks ] ), dict(), ) - if type(block) is astroplan.ObservingBlock: + if hasattr(block, "target"): for constraint_num, constraint in enumerate(block.constraints): if type(constraint) is astroplan.TimeConstraint: constraint_dict = { @@ -419,6 +377,8 @@ def blocks_to_table(observing_blocks): constraints, mask=_mask_expander(constraints, open_slots_mask) ) + t.add_index("ID", unique=True) + return t diff --git a/pyscope/telrun/schedtel.py b/pyscope/telrun/schedtel.py index e9ebb4c3..8a779020 100644 --- a/pyscope/telrun/schedtel.py +++ b/pyscope/telrun/schedtel.py @@ -11,6 +11,7 @@ import matplotlib.dates as mdates import matplotlib.pyplot as plt import timezonefinder +import tqdm from astropy import coordinates as coord from astropy import table from astropy import time as astrotime @@ -263,7 +264,7 @@ def schedtel_cli( filename=None, telrun=False, plot=None, - yes=True, + yes=False, quiet=False, verbose=0, ): @@ -298,6 +299,7 @@ def schedtel_cli( # Set the schedule time sched_time = astrotime.Time.now() + sched_time.format = "mjd" # Define the observatory if observatory is None: @@ -461,6 +463,7 @@ def schedtel_cli( block_groups[i][j].configuration["ID"] except: block_groups[i][j].configuration["ID"] = astrotime.Time.now() + block_groups[i][j].configuration["ID"].format = "mjd" previously_queued_blocks = None if queue is not None and len(block_groups) > 0: @@ -521,6 +524,8 @@ def schedtel_cli( # Transitioner logger.info("Defining transitioner") + if instrument_reconfig_times == {}: + instrument_reconfig_times = None transitioner = astroplan.Transitioner( slew_rate, instrument_reconfig_times=instrument_reconfig_times ) @@ -557,7 +562,7 @@ def schedtel_cli( ) logger.info("Scheduling ObservingBlocks") - for i in range(len(block_groups)): + for i in tqdm.tqdm(range(len(block_groups))): logger.debug("Block group %i of %i" % (i + 1, len(block_groups))) schedule_handler(block_groups[i], schedule) @@ -566,16 +571,15 @@ def schedtel_cli( # Get scheduled ObservingBlocks scheduled_blocks = [ - slot.block - for slot in schedule.slots - if isinstance(slot.block, astroplan.ObservingBlock) + slot.block for slot in schedule.slots if hasattr(slot.block, "target") ] transition_blocks = [ slot.block for slot in schedule.slots - if isinstance(slot.block, astroplan.TransitionBlock) + if slot.block is not None and not hasattr(slot.block, "target") ] - unscheduled_slots = [slot for slot in schedule.slots if not slot.occupied] + + unscheduled_slots = [slot for slot in schedule.slots if slot.block is None] # Update ephem for non-sidereal targets, update object types, set filenames for block_number, block in enumerate(scheduled_blocks): @@ -585,8 +589,8 @@ def schedtel_cli( if ( block.configuration["pm_ra_cosdec"].value != 0 or block.configuration["pm_dec"].value != 0 - ): - logger.info("Updating ephemeris for %s at scheduled time" % block.name) + ) and block.name != "": + logger.info("Updating ephemeris for '%s' at scheduled time" % block.name) try: ephemerides = mpc.MPC.get_ephemeris( target=block.name, @@ -714,7 +718,7 @@ def schedtel_cli( """ ) - logger.warning("\nInvalid blocks:") + logger.warning("Invalid blocks:") for block in invalid_blocks: logger.warning( f""" @@ -738,11 +742,11 @@ def schedtel_cli( # Blocks to be placed in an execution schedule exec_blocks = scheduled_blocks + transition_blocks + invalid_blocks if queue is None: - logger.info("No queue provided, including unscheduled in execution schedule") - logger.info("Note that these blocks will not actually be executed") + logger.info( + "No queue provided, including unscheduled blocks in execution schedule. Note that these blocks will not actually be executed." + ) exec_blocks += unscheduled_blocks elif queue is not None: - exec_blocks.sort(key=lambda x: x.configuration["ID"]) exec_table = schedtab.blocks_to_table(exec_blocks) # Blocks to be placed back in the queue @@ -753,20 +757,17 @@ def schedtel_cli( if previously_queued_blocks is not None: queue_blocks += previously_queued_blocks - queue_blocks.sort(key=lambda x: x.configuration["ID"]) queue_table = schedtab.blocks_to_table(queue_blocks) - exec_blocks.sort(key=lambda x: x.configuration["ID"]) exec_blocks = exec_blocks + unscheduled_slots exec_table = schedtab.blocks_to_table(exec_blocks) - # TODO: Report observing statistics (time used, transition, unscheduled, etc.) - # reports.pre_exec_report(exec_table) - # Write the schedule to file logger.info("Writing schedule to file") if filename is None or telrun: - first_time = exec_table[0]["start_time"].strftime("%Y%m%d_%H%M%S") + first_time = np.min(exec_table["start time"]).strftime( + "%YYYY-%mm-%dd_%HH-%MM-%SS" + ) filename = "telrun_" + first_time + ".ecsv" write_queue = False @@ -799,22 +800,29 @@ def schedtel_cli( else: write_queue = False path = os.getcwd() + "/" - logger.info("-t/--telrun flag not set, writing schedule to %s" % path) + logger.info("-t/--telrun flag not set") logger.info("If queue was provided, it will not be written to file") - exec_table.write(path + filename, overwrite=True) + if not telrun: + write_fname = filename + else: + write_fname = path + filename + exec_table.write(write_fname, overwrite=True, format="ascii.ecsv") # If a queue was passed, update the queue if --telrun is set # and the file was written to the expected location if queue is not None: if write_queue: logger.info("Writing queue to file") - queue_table.write(queue, overwrite=True) + queue_table.write(queue, overwrite=True, format="ascii.ecsv") else: logger.info("Not writing queue to file") else: logger.info("No queue provided") + # TODO: Report observing statistics (time used, transition, unscheduled, etc.) + # reports.pre_exec_report(exec_table) + # Plot the schedule ax = None match plot: diff --git a/tests/reference/simulator_observatory.cfg b/tests/reference/simulator_observatory.cfg index fc587f2e..6f000059 100644 --- a/tests/reference/simulator_observatory.cfg +++ b/tests/reference/simulator_observatory.cfg @@ -142,6 +142,6 @@ driver_2 = [scheduling] # degrees/second -slew_rate = 2 +slew_rate = 0.5 instrument_reconfig_times = {} diff --git a/tests/telrun/test_schedtel.py b/tests/telrun/test_schedtel.py index 1b6cc3ca..e542d8f3 100644 --- a/tests/telrun/test_schedtel.py +++ b/tests/telrun/test_schedtel.py @@ -7,8 +7,12 @@ def test_schedtel(tmp_path): catalog = "./tests/reference/test_schedtel.cat" observatory = "./tests/reference/simulator_observatory.cfg" - schedule = schedtel(catalog=catalog, observatory=observatory) + schedule = schedtel( + catalog=catalog, + observatory=observatory, + filename=str(tmp_path) + "test_schedtel.ecsv", + ) if __name__ == "__main__": - test_schedtel("") + test_schedtel("./")