From b77ed354fa434f51a97ed680450a1093a5c0bb77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20S=C3=A1nchez-Gallego?= Date: Wed, 27 Nov 2024 20:25:59 +0000 Subject: [PATCH] Move ephemeris tools to lvmopstools 0.4.1 --- pyproject.toml | 2 +- src/lvmapi/routers/ephemeris.py | 3 +- src/lvmapi/routers/weather.py | 2 +- src/lvmapi/tools/__init__.py | 3 - src/lvmapi/tools/logs.py | 2 +- src/lvmapi/tools/schedule.py | 186 -------------------------------- uv.lock | 27 +++-- 7 files changed, 20 insertions(+), 205 deletions(-) delete mode 100644 src/lvmapi/tools/schedule.py diff --git a/pyproject.toml b/pyproject.toml index 02223ad..7ba1bb8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ dependencies = [ "sdsstools>=1.8.1", "fastapi[standard]>=0.112.0", "lvmgort>=1.1.2", - "lvmopstools[influxdb,kubernetes]>=0.4.0", + "lvmopstools[influxdb,kubernetes,schedule]>=0.4.1", "gunicorn>=22.0.0", "uvicorn[standard]>=0.24.0", "sdss-clu>=2.2.1", diff --git a/src/lvmapi/routers/ephemeris.py b/src/lvmapi/routers/ephemeris.py index d32ea17..229174b 100644 --- a/src/lvmapi/routers/ephemeris.py +++ b/src/lvmapi/routers/ephemeris.py @@ -13,10 +13,9 @@ from fastapi import APIRouter, Query from pydantic import BaseModel +from lvmopstools.schedule import get_ephemeris_summary from sdsstools import get_sjd -from lvmapi.tools.schedule import get_ephemeris_summary - class EphemerisSummaryOut(BaseModel): """Summary of the ephemeris.""" diff --git a/src/lvmapi/routers/weather.py b/src/lvmapi/routers/weather.py index 52aef5d..44e6900 100644 --- a/src/lvmapi/routers/weather.py +++ b/src/lvmapi/routers/weather.py @@ -8,7 +8,7 @@ from __future__ import annotations -from time import time +import time from typing import Annotated diff --git a/src/lvmapi/tools/__init__.py b/src/lvmapi/tools/__init__.py index c4d06d7..48ad03b 100644 --- a/src/lvmapi/tools/__init__.py +++ b/src/lvmapi/tools/__init__.py @@ -10,8 +10,5 @@ from .alerts import * from .gort import * -from .influxdb import * from .rabbitmq import * -from .redis import * -from .schedule import * from .spectrograph import * diff --git a/src/lvmapi/tools/logs.py b/src/lvmapi/tools/logs.py index 3b77ae6..c1c5293 100644 --- a/src/lvmapi/tools/logs.py +++ b/src/lvmapi/tools/logs.py @@ -27,12 +27,12 @@ from psycopg.sql import SQL, Identifier from pydantic import BaseModel +from lvmopstools.schedule import get_ephemeris_summary from sdsstools import get_sjd, run_in_executor from lvmapi import config from lvmapi.tools.notifications import create_notification, get_notifications from lvmapi.tools.rabbitmq import CluClient -from lvmapi.tools.schedule import get_ephemeris_summary class ExposureDataDict(BaseModel): diff --git a/src/lvmapi/tools/schedule.py b/src/lvmapi/tools/schedule.py deleted file mode 100644 index a2ba68f..0000000 --- a/src/lvmapi/tools/schedule.py +++ /dev/null @@ -1,186 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# @Author: José Sánchez-Gallego (gallegoj@uw.edu) -# @Date: 2024-03-24 -# @Filename: schedule.py -# @License: BSD 3-clause (http://www.opensource.org/licenses/BSD-3-Clause) - -from __future__ import annotations - -import pathlib - -import astroplan -import numpy -import polars -from astropy import units as uu -from astropy.time import Time -from cachetools import TTLCache, cached - -from sdsstools import get_sjd - - -EPHEMERIS_FILE = pathlib.Path(__file__).parent / "../data/ephemeris.parquet" - - -@cached(TTLCache(maxsize=3, ttl=3600)) -def get_ephemeris_data(filename: pathlib.Path | str) -> polars.DataFrame: - """Returns and caches the data from the ephemeris file.""" - - return polars.read_parquet(filename) - - -def sjd_ephemeris(sjd: int, twilight_horizon: float = -15) -> polars.DataFrame: - """Returns the ephemeris for a given SJD.""" - - observer = astroplan.Observer.at_site("Las Campanas Observatory") - observer.pressure = 0.76 * uu.bar - - # Calculate Elevation of True Horizon. Astroplan does not provide this directly. - # See https://github.com/astropy/astroplan/issues/242 - h_observer = observer.elevation - R_earth = 6378100.0 * uu.m - dd = numpy.sqrt(h_observer * (2 * R_earth + h_observer)) - phi = (numpy.arccos((dd / R_earth).value) * uu.radian).to(uu.deg) - hzel = phi - 90 * uu.deg - - # Calculate time at ~15UT, which corresponds to about noon at LCO, so always - # before the beginning of the night. - time = Time(sjd - 0.35, format="mjd", scale="utc") - - sunset = observer.sun_set_time( - time, - which="next", - horizon=hzel - 0.5 * uu.deg, # Apparent size of the Sun. - ) - sunset_twilight = observer.sun_set_time( - time, - which="next", - horizon=twilight_horizon * uu.deg, - ) - - sunrise = observer.sun_rise_time( - time, - which="next", - horizon=hzel - 0.5 * uu.deg, - ) - sunrise_twilight = observer.sun_rise_time( - time, - which="next", - horizon=twilight_horizon * uu.deg, - ) - - moon_illumination = observer.moon_illumination(time) - - df = polars.DataFrame( - [ - ( - sjd, - time.isot.split("T")[0], - sunset.jd, - sunset_twilight.jd, - sunrise_twilight.jd, - sunrise.jd, - moon_illumination, - ) - ], - schema={ - "SJD": polars.Int32, - "date": polars.String, - "sunset": polars.Float64, - "twilight_end": polars.Float64, - "twilight_start": polars.Float64, - "sunrise": polars.Float64, - "moon_illumination": polars.Float32, - }, - orient="row", - ) - - return df - - -def create_schedule( - start_sjd: int, - end_sjd: int, - twilight_horizon: float = -15, -) -> polars.DataFrame: - """Creates a schedule for the given time range. - - Parameters - ---------- - start_sjd - The initial SJD. - end_sjd - The final SJD of the schedule. - - Returns - ------- - schedule - The schedule as a Polars dataframe. - - """ - - start_sjd = start_sjd or get_sjd("LCO") - - ephemeris: list[polars.DataFrame] = [] - for sjd in range(start_sjd, end_sjd + 1): - sjd_eph = sjd_ephemeris(sjd, twilight_horizon=twilight_horizon) - ephemeris.append(sjd_eph) - - return polars.concat(ephemeris) - - -def get_ephemeris_summary(sjd: int | None = None) -> dict: - """Returns a summary of the ephemeris for a given SJD.""" - - sjd = sjd or get_sjd("LCO") - - from_file = True - eph = get_ephemeris_data(EPHEMERIS_FILE) - - data = eph.filter(polars.col("SJD") == sjd) - if len(data) == 0: - data = sjd_ephemeris(sjd) - from_file = False - - sunset = Time(data["sunset"][0], format="jd") - sunrise = Time(data["sunrise"][0], format="jd") - twilight_end = Time(data["twilight_end"][0], format="jd") - twilight_start = Time(data["twilight_start"][0], format="jd") - - time_to_sunset = (sunset - Time.now()).to(uu.h).value - time_to_sunrise = (sunrise - Time.now()).to(uu.h).value - - is_twilight_evening = ( - Time(data["sunset"][0], format="jd") - < Time.now() - < Time(data["twilight_end"][0], format="jd") - ) - - is_twilight_morning = ( - Time(data["twilight_start"][0], format="jd") - < Time.now() - < Time(data["sunrise"][0], format="jd") - ) - - is_night = ( - Time(data["twilight_end"][0], format="jd") - < Time.now() - < Time(data["twilight_start"][0], format="jd") - ) - - return { - "SJD": int(sjd), - "request_jd": float(Time.now().jd), - "date": data["date"][0], - "sunset": float(sunset.jd), - "twilight_end": float(twilight_end.jd), - "twilight_start": float(twilight_start.jd), - "sunrise": float(sunrise.jd), - "is_night": bool(is_night), - "is_twilight": bool(is_twilight_evening or is_twilight_morning), - "time_to_sunset": round(float(time_to_sunset), 3), - "time_to_sunrise": round(float(time_to_sunrise), 3), - "moon_illumination": round(float(data["moon_illumination"][0]), 3), - "from_file": from_file, - } diff --git a/uv.lock b/uv.lock index a2e1ed1..5adcf27 100644 --- a/uv.lock +++ b/uv.lock @@ -932,8 +932,8 @@ name = "ipdb" version = "0.13.13" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "decorator" }, - { name = "ipython" }, + { name = "decorator", marker = "python_full_version >= '3.11' and python_full_version < '4'" }, + { name = "ipython", marker = "python_full_version >= '3.11' and python_full_version < '4'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3d/1b/7e07e7b752017f7693a0f4d41c13e5ca29ce8cbcfdcc1fd6c4ad8c0a27a0/ipdb-0.13.13.tar.gz", hash = "sha256:e3ac6018ef05126d442af680aad863006ec19d02290561ac88b8b1c0b0cfc726", size = 17042 } wheels = [ @@ -954,7 +954,7 @@ dependencies = [ { name = "pygments" }, { name = "stack-data" }, { name = "traitlets" }, - { name = "typing-extensions", marker = "python_full_version < '3.12'" }, + { name = "typing-extensions", marker = "python_full_version < '3.12' and python_full_version >= '3.11' and python_full_version < '4'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/85/e0/a3f36dde97e12121106807d80485423ae4c5b27ce60d40d4ab0bab18a9db/ipython-8.29.0.tar.gz", hash = "sha256:40b60e15b22591450eef73e40a027cf77bd652e757523eebc5bd7c7c498290eb", size = 5497513 } wheels = [ @@ -1051,7 +1051,7 @@ dependencies = [ { name = "jinja2" }, { name = "kubernetes" }, { name = "lvmgort" }, - { name = "lvmopstools", extra = ["influxdb", "kubernetes"] }, + { name = "lvmopstools", extra = ["influxdb", "kubernetes", "schedule"] }, { name = "passlib", extra = ["bcrypt"] }, { name = "polars" }, { name = "psycopg", extra = ["binary"] }, @@ -1093,7 +1093,7 @@ requires-dist = [ { name = "jinja2", specifier = ">=3.1.4" }, { name = "kubernetes", specifier = ">=31.0.0" }, { name = "lvmgort", specifier = ">=1.1.2" }, - { name = "lvmopstools", extras = ["influxdb", "kubernetes"], specifier = ">=0.4.0" }, + { name = "lvmopstools", extras = ["influxdb", "kubernetes", "schedule"], specifier = ">=0.4.1" }, { name = "passlib", extras = ["bcrypt"], specifier = ">=1.7.4" }, { name = "polars", specifier = ">=1.7.1" }, { name = "psycopg", extras = ["binary"], specifier = ">=3.2.2" }, @@ -1146,7 +1146,7 @@ wheels = [ [[package]] name = "lvmopstools" -version = "0.4.0" +version = "0.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "asyncudp" }, @@ -1157,9 +1157,9 @@ dependencies = [ { name = "sdsstools" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5d/b2/919b2d8358f799ce4a3a10bbb1e2351b23426c781ef665fdb0d600b34a8c/lvmopstools-0.4.0.tar.gz", hash = "sha256:f864c28a58d136e720f3b8b03b4e008e6ebc0686202685c6efa4c724e1c20842", size = 21439 } +sdist = { url = "https://files.pythonhosted.org/packages/2b/43/c651e01ae6ec70b9fe07a2541b0c46f7c8fbbc73c533c999f78cdc2ec7cb/lvmopstools-0.4.1.tar.gz", hash = "sha256:c0db7d685be239fa326c2e2c9d00ad1f5d3b271e8e372edd18e97da8af4d6212", size = 123140 } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/90/70046d9388a4941e79aa881400bfa7f5fc0c3e2c47b5e6d189f75961a256/lvmopstools-0.4.0-py3-none-any.whl", hash = "sha256:5a1c6e59ed94581f3825bf10654bc685c6fa888a1654a8969b3a317eb463963a", size = 28923 }, + { url = "https://files.pythonhosted.org/packages/b2/db/04e924ff3ad0f60a260a5ea064ea6792994a192b8d3965ae28d422489fa5/lvmopstools-0.4.1-py3-none-any.whl", hash = "sha256:c19ff93debb83f87acb5a38f5d3e95291bdfa0ae5a74d9caaa340089c28093a8", size = 128752 }, ] [package.optional-dependencies] @@ -1169,6 +1169,11 @@ influxdb = [ kubernetes = [ { name = "kubernetes" }, ] +schedule = [ + { name = "astroplan" }, + { name = "astropy", marker = "python_full_version >= '3.11' and python_full_version < '4'" }, + { name = "cachetools" }, +] [[package]] name = "makefun" @@ -1563,7 +1568,7 @@ name = "psycopg" version = "3.2.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13' and python_full_version >= '3.11' and python_full_version < '4'" }, { name = "tzdata", marker = "sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d1/ad/7ce016ae63e231575df0498d2395d15f005f05e32d3a2d439038e1bd0851/psycopg-3.2.3.tar.gz", hash = "sha256:a5764f67c27bec8bfac85764d23c534af2c27b893550377e37ce59c12aac47a2", size = 155550 } @@ -1972,7 +1977,7 @@ name = "redis" version = "5.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "async-timeout", marker = "python_full_version < '3.11.3'" }, + { name = "async-timeout", marker = "python_full_version < '3.11.3' and python_full_version >= '3.11' and python_full_version < '4'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/53/17/2f4a87ffa4cd93714cf52edfa3ea94589e9de65f71e9f99cbcfa84347a53/redis-5.2.0.tar.gz", hash = "sha256:0b1087665a771b1ff2e003aa5bdd354f15a70c9e25d5a7dbf9c722c16528a7b0", size = 4607878 } wheels = [ @@ -2171,7 +2176,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "daemonocle" }, { name = "invoke" }, - { name = "numpy" }, + { name = "numpy", marker = "python_full_version >= '3.11' and python_full_version < '4'" }, { name = "packaging" }, { name = "pygments" }, { name = "python-json-logger" },