#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Coordinates-related functions
"""
# Third-party modules
from astropy import units as u
from astropy.coordinates import EarthLocation, Longitude, SkyCoord
from astropy.coordinates.name_resolve import NameResolveError
from astropy.io import fits
from astropy.time import Time
from astropy.wcs import WCS
# Other templates
from ..config.constants import alt, lat, lon, temp_fits
from ..devices import tel
from .analysis import fit_star
from .logger import log
[docs]
def to_radec(string):
"""Transform a string containing the object name, i.e. "Polaris", or
the object coordinates, i.e. "12 34 56.7 +89 00 00.0" in an array
of float coordinates in units of [hours, degrees].
"""
if isinstance(string, list):
return string
try:
coor = SkyCoord(string,
unit=("hourangle", "deg"),
equinox=Time.now())
return [coor.ra.hourangle, coor.dec.degree]
except ValueError as e:
log.warning("Cannot resolve coordinates, trying with name")
log.warning(e)
try:
coor = SkyCoord.from_name(string)
log.info("Found catalog name")
coorstr = coor.to_string(
style='hmsdms', sep=' ', precision=1, pad=True)
log.info(f"Correspond to {coorstr}")
return [coor.ra.hourangle, coor.dec.degree]
except NameResolveError as e:
log.error("Cannot resolve name")
log.error(e)
return [None, None]
[docs]
def to_radians(string, equinox=None):
"""Transform a string containing the object name, i.e. "Polaris", or
the object coordinates, i.e. "12 34 56.7 +89 00 00.0" in an array
of float coordinates in units of radians.
"""
if isinstance(string, list):
return string
if not equinox:
equinox = Time.now()
try:
coor = SkyCoord(string,
unit=("hourangle", "deg"),
equinox=equinox)
return [coor.ra.radian, coor.dec.radian]
except ValueError as e:
log.warning("Cannot resolve coordinates, trying with name")
log.warning(e)
try:
coor = SkyCoord.from_name(string)
log.info("Found catalog name")
return [coor.ra.radian, coor.dec.radian]
except NameResolveError as e:
log.error("Cannot resolve name")
log.error(e)
return [None, None]
[docs]
def to_hms_dms(array, join=False):
"""Transform an array of coordinates from units of degrees,
i.e. [12.0, 89.0] in an array of string coordinates,
i.e. ["12 00 00", "+89 00 00"].
"""
try:
coor = SkyCoord(ra=array[0], dec=array[1],
unit=("deg", "deg"),
equinox=Time.now())
if join:
return coor.to_string(
style="hmsdms", sep=" ", precision=1, pad=True)
return [
coor.ra.to_string(
sep=" ",
precision=1,
pad=True),
coor.dec.to_string(
sep=" ",
precision=1,
pad=True,
alwayssign=True)]
except Exception as e:
log.warning(e)
if join:
return None
return [None, None]
[docs]
def to_hms(number):
"""Transform a value in units of degrees,
i.e. 89.0, in a string coordinate,
i.e. "+89 00 00".
"""
try:
coor = Longitude(number, unit="deg")
return coor.wrap_at(
180 *
u.deg).to_string(
sep=" ",
precision=1,
pad=True)
except Exception as e:
log.error(e)
return None
[docs]
def calculate_offset(string="13 56 44 +27 28 01", header=None):
"""Take a string of coordinates representing what is expected to be
the center of an OARPAF FITS image, and the header of that FITS
image. Uses the coordinates of that image to calculate the
difference between that point and the center of the image in [alt,
az], units of deg.
"""
if not header:
header = fits.getheader(temp_fits)
location = EarthLocation(lat=lat, lon=lon, height=alt)
obstime = Time(header["date-obs"])
# Coordinates from the header of the image:
# They come from the telescope pointing model,
# and correspond to the CCD center
# (i.e. 2072.5, 2063.0 in full frame).
ra = header["ra"]
dec = header["dec"]
coor_center = SkyCoord(ra=ra, dec=dec,
unit=("deg", "deg"),
equinox=obstime,
obstime=obstime,
location=location)
# Coordinates of the star. They should be the header one
coor_star = SkyCoord(string,
unit=("hourangle", "deg"),
equinox=obstime,
obstime=obstime,
location=location)
# trans = coor_star.transform_to(coor_center.skyoffset_frame())
# log.warning(f"Ignoring that IERS accuracy is bad! Check if the server is back online")
# from astropy.utils import iers
# iers.conf.iers_degraded_accuracy = 'ignore'
# iers.conf.auto_max_age = None
# This is the offset in degrees
dalt = coor_center.altaz.alt - coor_star.altaz.alt
daz = coor_center.altaz.az - coor_star.altaz.az
log.info(f"Offset in arcsec (web): {dalt.arcsec}, {-daz.arcsec}]")
log.debug(f"Offset in deg (astelos): {dalt.deg}, {-daz.deg}")
return [dalt.deg, -daz.deg]
[docs]
def apply_offset(fits_file=temp_fits, box=100, model="moffat", display=False):
"""Take an image, fit a Moffat2d on a centered box center supposing
there is a star, calculate the offset with respect to the center,
sum it to the existing telescope offset.
"""
# Load data and header from an image
data = fits.getdata(fits_file)
header = fits.getheader(fits_file)
centx, centy = data.shape[0] // 2, data.shape[1] // 2
width = box
height = box
data = data[centx - width // 2:centx + width //
2, centy - height // 2:centy + height // 2]
log.debug(f"Taking subimage [{centx -
width //
2}:{centx +
width //
2}, {centy -
height //
2}:{centy +
height //
2}]")
# Fit on what you find there
try:
fitted = fit_star(data, model=model, display=display)
log.debug(
f"Subimage fit x:{
fitted.xc}, y:{
fitted.yc}, fwhm:{
fitted.fwhm}")
except Exception as e:
log.error("Error while fitting")
log.error(e)
return [0, 0]
true_x = centx - width // 2 + fitted.xc
true_y = centy - height // 2 + fitted.yc
log.debug(f"True xy x:{true_x}, y:{true_y}")
# Transform pixels to radec
wcs = WCS(header)
coords = wcs.pixel_to_world(true_x, true_y)
string_coords = to_hms_dms([coords.ra.deg, coords.dec.deg], join=True)
log.debug(f"True HMSDMS: {string_coords}")
dalt, daz = calculate_offset(string_coords, header=header)
try:
current_alt_offset, current_az_offset = tel.offset
log.debug(
f"Current offsets in arcsec: {
current_alt_offset *
3600}, {
current_az_offset *
3600}")
except Exception as e:
log.error("Cannot retrieve offset from cabinet:")
log.error(e)
return [0, 0]
updated_offset = [current_alt_offset + dalt, current_az_offset + daz]
tel.offset = updated_offset
log.debug(
f"Updated offset in arcsec: {
updated_offset[0] *
3600}, {
updated_offset[1] *
3600}")
return updated_offset