Source code for pyobs.environment

import datetime
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) -> datetime.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.datetime] = None) -> datetime.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.datetime.utcnow() # 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.datetime, Time]] = None) -> datetime.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.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 += datetime.timedelta(days=-1) return loc_dt.date()
[docs] @functools.lru_cache() def lst(self, time: Union[datetime.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"]