diff --git a/notebooks_tsqr/NightLog.ipynb b/notebooks_tsqr/NightLog.ipynb index a0bf27a..8a02c3e 100644 --- a/notebooks_tsqr/NightLog.ipynb +++ b/notebooks_tsqr/NightLog.ipynb @@ -99,10 +99,12 @@ "metadata": {}, "outputs": [], "source": [ - "# TODO For Times Square, UNCOMMENT next line and COMMENT the one after.\n", - "!pip install git+https://github.com/lsst-ts/ts_logging_and_reporting.git@prototype >/dev/null\n", - "#!pip install --upgrade ..\n", + "# When running under Times Square, install pkg from github.\n", + "# Otherwise \n", + "if os.environ.get('EXTERNAL_INSTANCE_URL'):\n", + " !pip install git+https://github.com/lsst-ts/ts_logging_and_reporting.git@prototype \n", "import lsst.ts.logging_and_reporting.source_adapters as sad\n", + "import lsst.ts.logging_and_reporting.almanac as alm\n", "#from lsst.ts.logging_and_reporting.source_adapters import ExposurelogAdapter, NarrativelogAdapter" ] }, @@ -156,16 +158,8 @@ "metadata": {}, "outputs": [], "source": [ - "alm = sad.Almanac()\n", - "almtab = f'''\\\n", - "| Attribute | Value |\n", - "| --------- | ----- |\n", - "| Moon Rise | {alm.moon_rise_time.iso} |\n", - "| Moon Set | {alm.moon_set_time.iso} |\n", - "| Twilight Morning | {alm.twilight_morning.iso} |\n", - "| Twilight Evening | {alm.twilight_evening.iso} |\n", - "'''\n", - "display(Markdown(almtab))" + "a = alm.Almanac()\n", + "pd.DataFrame(a.as_dict).T" ] }, { diff --git a/python/lsst/ts/logging_and_reporting/almanac.py b/python/lsst/ts/logging_and_reporting/almanac.py new file mode 100644 index 0000000..d56a4b6 --- /dev/null +++ b/python/lsst/ts/logging_and_reporting/almanac.py @@ -0,0 +1,76 @@ +from datetime import datetime, date, time, timedelta +import math +from astroplan import Observer +from astropy.time import Time + +class Almanac: + + def __init__(self, *, day_obs=None, site='Rubin'): + if day_obs is None: + astro_day = date.today() - timedelta(days=1) + else: + astro_day = datetime.strptime(str(day_obs), '%Y%m%d').date() + + self.observer = Observer.at_site(site, timezone='Chile/Continental') + self.astro_day = astro_day + self.astro_noon = datetime.combine(self.astro_day,time(12)) + + self.get_moon() + self.get_sun() + + def get_moon(self): + self.moon_rise_time = self.observer.moon_rise_time(self.astro_noon) + self.moon_set_time = self.observer.moon_set_time(self.astro_noon) + + # Percent of moon lit + self.moon_illum = self.observer.moon_illumination(self.astro_noon) + + def get_sun(self): + time = self.observer.datetime_to_astropy_time(self.astro_noon) + + # ast(ronoimical) twilight: -18 degrees) + self.ast_twilight_morning = self.observer.twilight_morning_astronomical( + time) + self.ast_twilight_evening = self.observer.twilight_evening_astronomical( + time) + + # nau(tical) twilight: -12 degrees) + self.nau_twilight_morning = self.observer.twilight_morning_nautical( + time) + self.nau_twilight_evening = self.observer.twilight_evening_nautical( + time) + + # civ(il) twilight: -6 degrees) + self.civ_twilight_morning = self.observer.twilight_morning_civil( + time) + self.civ_twilight_evening = self.observer.twilight_evening_civil( + time) + + self.sun_rise_time = self.observer.sun_rise_time(time) + self.sun_set_time = self.observer.sun_set_time(time) + + @property + def as_dict(self): + data_dict = { + 'Moon Rise': self.moon_rise_time.iso, + 'Moon Set': self.moon_set_time.iso, + 'Moon Illumination': f'{self.moon_illum:.0%}', + 'Astronomical Twilight (morning)': self.ast_twilight_morning.iso, + 'Astronomical Twilight (evening)': self.ast_twilight_evening.iso, + 'Nautical Twilight (morning)': self.nau_twilight_morning.iso, + 'Nautical Twilight (evening)': self.nau_twilight_evening.iso, + 'Civil Twilight (morning)': self.civ_twilight_morning.iso, + 'Civil Twilight (evening)': self.civ_twilight_evening.iso, + } + help_dict = { + 'Moon Rise': '', + 'Moon Set': '', + 'Moon Illumination': '(% lit)', + 'Astronomical Twilight (morning)': '(-18 degrees)', + 'Astronomical Twilight (evening)': '(-18 degrees)', + 'Nautical Twilight (morning)': '(-12 degrees)', + 'Nautical Twilight (evening)': '(-12 degrees)', + 'Civil Twilight (morning)': '(-6 degrees)', + 'Civil Twilight (evening)': '(-6 degrees)', + } + return data_dict, help_dict diff --git a/python/lsst/ts/logging_and_reporting/dashboard.py b/python/lsst/ts/logging_and_reporting/dashboard.py new file mode 100644 index 0000000..d439bd2 --- /dev/null +++ b/python/lsst/ts/logging_and_reporting/dashboard.py @@ -0,0 +1,64 @@ +class Dashboard: # TODO Move to its own file (utils.py). + """Verify that we can get to all the API endpoints and databases we need for + any of our sources. + """ + + envs = dict( + summit = 'https://summit-lsp.lsst.codes', + usdf_dev = 'https://usdf-rsp-dev.slac.stanford.edu', + tucson = 'https://tucson-teststand.lsst.codes', + # Environments not currently used: + # rubin_usdf_dev = '', + # data_lsst_cloud = '', + # usdf = '', + # base_data_facility = '', + # rubin_idf_int = '', + ) + adapters = [ExposurelogAdapter, + NarrativelogAdapter, + # NightReportAdapter, # TODO + ] + + def report(self, timeout=None): + """Check our ability to connect to every Source on every Environment. + Report a summary. + + RETURN: percentage of good connectons. + """ + url_status = dict() + for env,server in self.envs.items(): + for adapter in self.adapters: + service = adapter(server_url=server) + # url_status[endpoint_url] = http_status_code + url_status.update(service.check_endpoints(timeout=timeout)) + + total_cnt = good_cnt = 0 + good = list() + bad = list() + for url,stat in url_status.items(): + total_cnt += 1 + if stat == 200: + good_cnt += 1 + good.append(url) + else: + bad.append((url,stat)) + + print(f'\nConnected to {good_cnt} out of {total_cnt} endpoints.' + f'({good_cnt/total_cnt:.0%})' + ) + goodstr = "\n\t".join(good) + print(f'Successful connects ({good_cnt}): ') + for gurl in good: + print(f'\t{gurl}') + + print(f'Failed connects ({total_cnt - good_cnt}): ') + for burl,stat in bad: + print(f'\t{stat}: {burl}') + + status = dict(num_good=good_cnt, + num_total=total_cnt, + good_urls=good, + bad_ursl=bad, + ) + return good_cnt/total_cnt +# END: class Dashboard diff --git a/python/lsst/ts/logging_and_reporting/source_adapters.py b/python/lsst/ts/logging_and_reporting/source_adapters.py index 5e92931..b2be102 100644 --- a/python/lsst/ts/logging_and_reporting/source_adapters.py +++ b/python/lsst/ts/logging_and_reporting/source_adapters.py @@ -418,106 +418,3 @@ def get_observation_gaps(self, instruments=None, return inst_day_rollup # END: class ExposurelogAdapter - - - -class Dashboard: # TODO Move to its own file (utils.py). - """Verify that we can get to all the API endpoints and databases we need for - any of our sources. - """ - - envs = dict( - summit = 'https://summit-lsp.lsst.codes', - usdf_dev = 'https://usdf-rsp-dev.slac.stanford.edu', - tucson = 'https://tucson-teststand.lsst.codes', - # Environments not currently used: - # rubin_usdf_dev = '', - # data_lsst_cloud = '', - # usdf = '', - # base_data_facility = '', - # rubin_idf_int = '', - ) - adapters = [ExposurelogAdapter, - NarrativelogAdapter, - # NightReportAdapter, # TODO - ] - - def report(self, timeout=None): - """Check our ability to connect to every Source on every Environment. - Report a summary. - - RETURN: percentage of good connectons. - """ - url_status = dict() - for env,server in self.envs.items(): - for adapter in self.adapters: - service = adapter(server_url=server) - # url_status[endpoint_url] = http_status_code - url_status.update(service.check_endpoints(timeout=timeout)) - - total_cnt = good_cnt = 0 - good = list() - bad = list() - for url,stat in url_status.items(): - total_cnt += 1 - if stat == 200: - good_cnt += 1 - good.append(url) - else: - bad.append((url,stat)) - - print(f'\nConnected to {good_cnt} out of {total_cnt} endpoints.' - f'({good_cnt/total_cnt:.0%})' - ) - goodstr = "\n\t".join(good) - print(f'Successful connects ({good_cnt}): ') - for gurl in good: - print(f'\t{gurl}') - - print(f'Failed connects ({total_cnt - good_cnt}): ') - for burl,stat in bad: - print(f'\t{stat}: {burl}') - - status = dict(num_good=good_cnt, - num_total=total_cnt, - good_urls=good, - bad_ursl=bad, - ) - return good_cnt/total_cnt -# END: class Dashboard - -from astroplan import Observer -from astropy.time import Time - -class Almanac: - - def __init__(self, *, day_obs=None, site='Rubin'): - if day_obs is None: - astro_day = date.today() - timedelta(days=1) - else: - astro_day = datetime.strptime(str(day_obs), '%Y%m%d').date() - - self.observer = Observer.at_site(site, timezone='Chile/Continental') - self.astro_day = astro_day - self.astro_noon = datetime.combine(self.astro_day,time(12)) - - self.get_moon() - self.get_twilight() - - def get_moon(self): - self.moon_rise_time = self.observer.moon_rise_time(self.astro_noon) - self.moon_set_time = self.observer.moon_set_time(self.astro_noon) - - @property - def moon_rise(self): - return self.moon_rise_time - - @property - def moon_set(self): - return self.moon_set_time - - def get_twilight(self): - self.twilight_morning = self.observer.twilight_morning_astronomical( - self.observer.datetime_to_astropy_time(self.astro_noon)) - self.twilight_evening = self.observer.twilight_evening_astronomical( - self.observer.datetime_to_astropy_time(self.astro_noon)) diff --git a/python/lsst/ts/logging_and_reporting/version.py b/python/lsst/ts/logging_and_reporting/version.py index 3272d5f..7babeeb 100644 --- a/python/lsst/ts/logging_and_reporting/version.py +++ b/python/lsst/ts/logging_and_reporting/version.py @@ -1,3 +1,3 @@ # Generated by setuptools_scm __all__ = ["__version__"] -__version__ = "0.1.dev49+gb8bd681.d20240913" +__version__ = "0.1.dev53+g1c878ef.d20240914"