diff --git a/rubin_scheduler/scheduler/schedulers/core_scheduler.py b/rubin_scheduler/scheduler/schedulers/core_scheduler.py index c1a4783..59d0a83 100644 --- a/rubin_scheduler/scheduler/schedulers/core_scheduler.py +++ b/rubin_scheduler/scheduler/schedulers/core_scheduler.py @@ -97,6 +97,10 @@ def __init__( # Counter for observations added to the queue self.target_id_counter = target_id_counter + # Set to something so it doesn't fail if never set later + self.queue_fill_mjd_ns = -1 + self.queue_reward_df = None + def flush_queue(self): """Like it sounds, clear any currently queued desired observations.""" self.queue = [] diff --git a/rubin_scheduler/scheduler/sim_runner.py b/rubin_scheduler/scheduler/sim_runner.py index b795fce..25a4dbe 100644 --- a/rubin_scheduler/scheduler/sim_runner.py +++ b/rubin_scheduler/scheduler/sim_runner.py @@ -158,7 +158,11 @@ def sim_runner( observatory.mjd = observatory.mjd + step_none scheduler.update_conditions(observatory.return_conditions()) nskip += 1 - continue + # Check we didn't skip so far we should end + if observatory.mjd > sim_end_mjd: + break + else: + continue completed_obs, new_night = observatory.observe(desired_obs) if completed_obs is not None: @@ -218,23 +222,26 @@ def sim_runner( # Only warn if it's a low-accuracy astropy conversion lsst = Site("LSST") - # Using pseudo_parallactic_angle, see https://smtn-019.lsst.io/v/DM-44258/index.html - pa, alt, az = pseudo_parallactic_angle( - np.degrees(observations["RA"]), - np.degrees(observations["dec"]), - observations["mjd"], - lon=lsst.longitude, - lat=lsst.latitude, - height=lsst.height, - ) - observations["alt"] = np.radians(alt) - observations["az"] = np.radians(az) - observations["pseudo_pa"] = np.radians(pa) - observations["rotTelPos"] = rc._rotskypos2rottelpos(observations["rotSkyPos"], observations["pseudo_pa"]) - - # Also include traditional parallactic angle - pa = _approx_altaz2pa(observations["alt"], observations["az"], lsst.latitude_rad) - observations["pa"] = pa + if len(observations) > 0: + # Using pseudo_parallactic_angle, see https://smtn-019.lsst.io/v/DM-44258/index.html + pa, alt, az = pseudo_parallactic_angle( + np.degrees(observations["RA"]), + np.degrees(observations["dec"]), + observations["mjd"], + lon=lsst.longitude, + lat=lsst.latitude, + height=lsst.height, + ) + observations["alt"] = np.radians(alt) + observations["az"] = np.radians(az) + observations["pseudo_pa"] = np.radians(pa) + observations["rotTelPos"] = rc._rotskypos2rottelpos( + observations["rotSkyPos"], observations["pseudo_pa"] + ) + + # Also include traditional parallactic angle + pa = _approx_altaz2pa(observations["alt"], observations["az"], lsst.latitude_rad) + observations["pa"] = pa runtime = time.time() - t0 print("Skipped %i observations" % nskip) diff --git a/tests/scheduler/test_sim_runner.py b/tests/scheduler/test_sim_runner.py new file mode 100644 index 0000000..1bbe6e1 --- /dev/null +++ b/tests/scheduler/test_sim_runner.py @@ -0,0 +1,46 @@ +import logging +import unittest + +import numpy as np + +import rubin_scheduler.utils as utils +from rubin_scheduler.scheduler import sim_runner +from rubin_scheduler.scheduler.model_observatory import ModelObservatory +from rubin_scheduler.scheduler.schedulers import CoreScheduler +from rubin_scheduler.scheduler.surveys import BaseSurvey + + +class NoObsSurvey(BaseSurvey): + """Dummy class that always returns no valid reward""" + + def calc_reward_function(self, conditions): + return -np.inf + + +class TestSimRunner(unittest.TestCase): + + def test_no_obs(self): + """Check that sim ends even if we stop returning observations.""" + mjd_start = utils.SURVEY_START_MJD + nside = 32 + survey_length = 1.5 # days + + scheduler = CoreScheduler([NoObsSurvey([], detailers=[])]) + observatory = ModelObservatory(nside=nside, mjd_start=mjd_start) + # Turn off noisy log warnings + logging.disable(logging.CRITICAL) + observatory, scheduler, observations = sim_runner( + observatory, scheduler, sim_duration=survey_length, filename=None + ) + + assert len(observations) == 0 + + observatory, scheduler, observations, reward_df, obs_rewards_series = sim_runner( + observatory, scheduler, sim_duration=survey_length, filename=None, record_rewards=True + ) + + assert len(observations) == 0 + + +if __name__ == "__main__": + unittest.main()