Source code for pyobs.environment

from datetime import datetime, timezone, timedelta, tzinfo, date
import functools
import logging
from typing import Union, Optional, Any, Dict
import pytz
from astropy.coordinates import EarthLocation, Longitude, SkyCoord, ICRS, get_sun, AltAz
from pyobs.utils.time import Time


log = logging.getLogger(__name__)


[docs] class Environment: """An Environment object hold information about the location of the observatory and provides some convenience methode. An object of this type is usually never instantiated manually, but is part of a :class:`~pyobs.modules.Module`, automatically created from the configuration file like this:: timezone: Africa/Johannesburg location: longitude: 20.810808 latitude: -32.375823 elevation: 1798. """ def __init__( self, timezone: str = "utc", location: Union[Dict[str, Any], EarthLocation] = None, *args: Any, **kwargs: Any ): # get timezone self._timezone = pytz.timezone(timezone) log.info("Using timezone %s.", timezone) # get location self._location: Optional[EarthLocation] = None if location is not None: if isinstance(location, EarthLocation): # store directly self._location = location elif isinstance(location, dict): # dictionary? if ( "longitude" in location and location["longitude"] is not None and "latitude" in location and location["latitude"] is not None and "elevation" in location and location["elevation"] is not None ): self._location = EarthLocation(location["longitude"], location["latitude"], location["elevation"]) else: log.error("Location must be provided as dict of longitude/latitude/elevation values.") else: # nothing log.error("Could not initialize location.") if self._location is not None: log.info( "Setting location to longitude=%s, latitude=%s, and elevation=%s.", self._location.lon, self._location.lat, self._location.height, ) @property def timezone(self) -> tzinfo: """Returns the timezone of the observatory.""" return self._timezone @property def location(self) -> Optional[EarthLocation]: """Returns the location of the observatory.""" return self._location
[docs] @functools.lru_cache() def localtime(self, utc: Optional[datetime] = None) -> datetime: """Returns the local time at the observatory, either for a given UTC time or for now, if none is given. Args: utc: UTC to convert. Use now if none is given. Returns: Local time. """ # get UTC if utc is None: utc = datetime.now(timezone.utc) # mark as UTC utc_dt = pytz.utc.localize(utc) # convert to local timezone return utc_dt.astimezone(self._timezone)
[docs] @functools.lru_cache() def night_obs(self, time: Optional[Union[datetime, Time]] = None) -> date: """Returns the date of the night for the given night, i.e. the date of the start of the night. Args: time: Time to return night for. If none is given, current time is used. Returns: Night of observation. """ # None given? if time is None: time = Time.now() # convert to Time if isinstance(time, Time): time = time.datetime # get local datetime if not isinstance(time, datetime): raise ValueError("Invalid time") utc_dt = pytz.utc.localize(time) loc_dt = utc_dt.astimezone(self._timezone) # get night if loc_dt.hour < 15: loc_dt += timedelta(days=-1) return loc_dt.date()
[docs] @functools.lru_cache() def lst(self, time: Union[datetime, Time]) -> Longitude: """Returns the local sidereal time for a given time. Args: time: Time to convert to LST. Returns: Local sidereal time. """ # no location if not isinstance(self._location, EarthLocation): raise ValueError("No location given.") # convert to Time if not isinstance(time, Time): time = Time(time) # return LST return time.sidereal_time("mean", longitude=self._location.lon)
[docs] @functools.lru_cache() def zenith_position(self, lst: Longitude) -> SkyCoord: """Returns the RA/Dec position of the zenith. Args: lst: Local sidereal time to use. Returns: SkyCoord with current zenith position. """ if not isinstance(self._location, EarthLocation): raise ValueError("No location given.") return SkyCoord(lst, self._location.lat, frame=ICRS)
[docs] def now(self) -> Time: """Returns current time.""" return Time.now()
[docs] def to_altaz(self, radec: SkyCoord, time: Optional[Time] = None) -> SkyCoord: """Converts a given set of RA/Dec to Alt/Az for the current location at a given time. Args: radec: RA/Dec coordinates to convert. time: Time to use, or none for now. Returns: Alt/Az coordinates for given RA/Dec. """ if time is None: time = Time.now() return radec.transform_to(AltAz(obstime=time, location=self.location))
[docs] def to_radec(self, altaz: SkyCoord, time: Optional[Time] = None) -> SkyCoord: """Converts a given set of Alt/Az to RA/Dec for the current location at a given time. Args: altaz: Alt/Az coordinates to convert. time: Time to use, or none for now. Returns: RA/Dec coordinates for given Alt/Az. """ if time is None: time = Time.now() altaz.location = self.location altaz.obstime = time return altaz.icrs
[docs] @functools.lru_cache() def sun(self, time: Time, altaz: bool = True) -> SkyCoord: """Returns the position of the sun, either as RA/Dec or Alt/Az for the given time. Args: time: Time to calculate position for. altaz: If True, Alt/Az is returned, otherwise RA/Dec. Returns: Coordinates of sun. """ # alt/az or ra/dec? if altaz: return self.to_altaz(get_sun(time), time) else: return get_sun(time)
__all__ = ["Environment"]