# -*- coding: utf-8 -*-
"""
Created on Thu Aug 27 16:39:32 2015
@author: ebachelet
"""
from __future__ import division
import numpy as np
import astropy.io.fits as fits
from pyLIMA import microltoolbox
from pyLIMA import microlparallax
# Conventions for magnitude and flux lightcurves for all pyLIMA. If the injected lightcurve format differs, please
# indicate this in the correponding lightcurve_magnitude_dictionnary or lightcurve_flux_dictionnary, see below.
[docs]PYLIMA_LIGHTCURVE_MAGNITUDE_CONVENTION = ['time', 'mag', 'err_mag']
[docs]PYLIMA_LIGHTCURVE_FLUX_CONVENTION = ['time', 'flux', 'err_flux']
[docs]class Telescope(object):
"""
######## Telescope module ########
This class create a telescope object.
Attributes :
location : The location of your observatory. Should be "Earth" (default) or "Space".
altitude : Altitude in meter of the telescope. Default is 0.0 (sea level).
longitude : Longitude of the telescope in degrees. Default is 0.57.
latitude : Latitude in degrees. Default is 49.49 .
gamma : (Microlensing covention) Limb darkening coefficient :math:`\\Gamma` associated to the filter.
The classical (Milne definition) linear limb darkening coefficient can be found using:
u=(3*gamma)/(2+gamma).
Default is 0.0 (i.e uniform source brightness)
lightcurve_magnitude : a numpy array describing your data in magnitude.
lightcurve_magnitude_dictionnary : a python dictionnary to transform the lightcurve_magnitude
input to pyLIMA convention.
lightcurve_flux : a numpy array describing your data in flux.
lightcurve_flux_dictionnary : a python dictionnary to transform the lightcurve_flux input to pyLIMA convention.
reference_flux : a float used for the transformation of difference fluxes to real fluxes. Default is 10000.0 .
deltas_positions : a list containing the position shift of this observatory due to parallax.
Default is an empty list. More details in microlparallax.
:param string name: name of the telescope. Default is 'NDG'
:param string camera_filter: telescope filter used. Should be a string which follows the convention of :
" Gravity and limb-darkening coefficients for the Kepler, CoRoT, Spitzer, uvby,
UBVRIJHK,
and Sloan photometric systems"
Claret, A. and Bloemen, S. 2011A&A...529A..75C. For example, 'I' (default) is
Johnson_Cousins I filter
and 'i'' is the SDSS-i' Sloan filter.
:param array_like light_curve_magnitude: a numpy array with time, magnitude and error in magnitude.
Default is an None.
:param dict light_curve_magnitude_dictionnary: a python dictionnary that informs your columns convention. Used to
translate to pyLIMA convention [time,mag,err_mag].
Default is {'time': 0, 'mag' : 1, 'err_mag' : 2 }
:param array-like light_curve_flux: a numpy array with time, flux and error in flux. Default is an None.
:param dict light_curve_flux_dictionnary: a python dictionnary that informs your columns convention. Used to
translate to pyLIMA convention [time,flux,err_flux].
Default is {'time': 0, 'flux' : 1, 'err_flux' : 2 }
:param float reference_flux: a float used for the transformation of difference fluxes to real fluxes.
Default is 0.0 .
:param str clean_the_lightcurve : a string indicated if you want pyLIMA to clean your lightcurves.
Highly recommanded!
"""
def __init__(self, name='NDG', camera_filter='I', light_curve_magnitude=None,
light_curve_magnitude_dictionnary=None,
light_curve_flux=None, light_curve_flux_dictionnary=None,
reference_flux=0.0, clean_the_lightcurve='Yes',
location = 'Earth', spacecraft_name=None):
"""Initialization of the attributes described above."""
self.name = name
self.filter = camera_filter # Claret2011 convention
if light_curve_magnitude_dictionnary is None:
light_curve_magnitude_dictionnary = {'time': 0, 'mag': 1, 'err_mag': 2}
if light_curve_flux_dictionnary is None:
light_curve_flux_dictionnary = {'time': 0, 'flux': 1, 'err_flux': 2}
self.lightcurve_magnitude_dictionnary = light_curve_magnitude_dictionnary
self.lightcurve_flux_dictionnary = light_curve_flux_dictionnary
self.reference_flux = reference_flux
self.lightcurve_magnitude = []
self.lightcurve_flux = []
if light_curve_magnitude is None:
pass
else:
self.lightcurve_magnitude = light_curve_magnitude
self.lightcurve_magnitude = self.arrange_the_lightcurve_columns('magnitude')
if clean_the_lightcurve == 'Yes':
self.lightcurve_magnitude = self.clean_data_magnitude()
self.lightcurve_flux = self.lightcurve_in_flux()
if clean_the_lightcurve == 'Yes':
self.lightcurve_flux = self.clean_data_flux()
if light_curve_flux is None:
pass
else:
self.lightcurve_flux = light_curve_flux
self.lightcurve_flux = self.arrange_the_lightcurve_columns('flux')
if clean_the_lightcurve == 'Yes':
self.lightcurve_flux = self.clean_data_flux()
self.lightcurve_magnitude = self.lightcurve_in_magnitude()
self.location = location
self.altitude = 0.0 # meters
self.longitude = 0.57 # degrees
self.latitude = 49.49 # degrees
self.gamma = 0.0 # This mean you will fit uniform source brightness
self.deltas_positions = []
self.spacecraft_name = spacecraft_name # give the true name of the satellite, according to JPL horizon
self.spacecraft_positions = [] #only for space base observatory, should be a list as
# [dates(JD), ra(degree) , dec(degree) , distances(AU) ]
self.hidden()
[docs] def arrange_the_lightcurve_columns(self, choice):
"""Rearange the lightcurve to the pyLIMA convention.
:param string choice: 'magnitude' or 'flux'. A string which indicated on which lightcurves apply
the sorting.
:return: the lightcurve sorted in pyLIMA convention
:rtype: array_like
"""
if choice == 'magnitude':
lightcurve = []
for good_column in PYLIMA_LIGHTCURVE_MAGNITUDE_CONVENTION:
lightcurve.append(self.lightcurve_magnitude[:, self.lightcurve_magnitude_dictionnary[good_column]])
lightcurve = np.array(lightcurve).T
return lightcurve
if choice == 'flux':
lightcurve = []
for good_column in PYLIMA_LIGHTCURVE_FLUX_CONVENTION:
lightcurve.append(self.lightcurve_flux[:, self.lightcurve_flux_dictionnary[good_column]])
lightcurve = np.array(lightcurve).T
lightcurve[:, 1] = lightcurve[:, 1] + self.reference_flux
return lightcurve
[docs] def n_data(self, choice='magnitude'):
""" Return the number of data points in the lightcurve.
:param string choice: 'magnitude' (default) or 'flux' The unit you want to check data for.
:return: the size of the corresponding lightcurve
:rtype: int
"""
if choice == 'flux':
return len(self.lightcurve_flux[:, 0])
if choice == 'magnitude':
return len(self.lightcurve_magnitude[:, 0])
[docs] def find_gamma(self, star):
"""
Set the associated :math:`\\Gamma` linear limb-darkening coefficient associated to the filter.
:param object star: a stars object.
"""
self.gamma = star.find_gamma(self.filter)
[docs] def compute_parallax(self, event, parallax):
""" Compute and set the deltas_positions attribute due to the parallax.
:param object event: a event object. More details in the event module.
:param list parallax: a list containing the parallax model and to_par. More details in microlparallax module.
"""
para = microlparallax.MLParallaxes(event, parallax)
para.parallax_combination(self)
print('Parallax(' + parallax[0] + ') estimated for the telescope ' + self.name + ': SUCCESS')
[docs] def clean_data_magnitude(self):
"""
Clean outliers of the telescope for the fits. Points are considered as outliers if they
are 10 mag brighter
or fainter than the lightcurve median or if nan appears in any columns or errobar higher
than a 1 mag.
:return: the cleaned magnitude lightcurve
:rtype: array_like
"""
maximum_accepted_precision = 1.0
index = np.where((~np.isnan(self.lightcurve_magnitude).any(axis=1)) &
(np.abs(self.lightcurve_magnitude[:, 2]) <= maximum_accepted_precision))[0]
lightcurve = self.lightcurve_magnitude[index]
index = np.where((np.isnan(self.lightcurve_magnitude).any(axis=1)) |
(np.abs(self.lightcurve_magnitude[:, 2]) > maximum_accepted_precision))[0]
if len(index) != 0:
self.bad_points_magnitude = index
print('pyLIMA found some bad points in the telescope ' + self.name + ', you can found these in the ' \
'bad_points_magnitude attribute.')
return lightcurve
[docs] def clean_data_flux(self):
"""
Clean outliers of the telescope for the fits. Points are considered as outliers if they
are 10 mag brighter
or fainter than the lightcurve median or if nan appears in any columns or errobar higher
than a 1 mag.
:return: the cleaned magnitude lightcurve
:rtype: array_like
"""
maximum_accepted_precision = 1.0
flux = self.lightcurve_flux[:, 1]
error_flux = self.lightcurve_flux[:, 2]
index = np.where(
(~np.isnan(self.lightcurve_flux).any(axis=1)) & (np.abs(error_flux / flux) <= maximum_accepted_precision) & (flux>0))[
0]
lightcurve = self.lightcurve_flux[index]
index = np.where(
(np.isnan(self.lightcurve_flux).any(axis=1)) | (np.abs(error_flux / flux) > maximum_accepted_precision) | (flux<=0))[0]
if len(index) != 0:
self.bad_points_flux = index
print('pyLIMA found some bad points in the telescope ' + self.name + ', you can found these in the ' \
'bad_points_flux attribute.')
return lightcurve
[docs] def lightcurve_in_flux(self):
"""
Transform magnitude to flux using m=27.4-2.5*log10(flux) convention. Transform error bar
accordingly. More details in microltoolbox module.
:return: the lightcurve in flux, lightcurve_flux.
:rtype: array_like
"""
lightcurve = self.lightcurve_magnitude
time = lightcurve[:, 0]
mag = lightcurve[:, 1]
err_mag = lightcurve[:, 2]
flux = microltoolbox.magnitude_to_flux(mag)
error_flux = microltoolbox.error_magnitude_to_error_flux(err_mag, flux)
lightcurve_in_flux = np.array([time, flux, error_flux]).T
return lightcurve_in_flux
[docs] def lightcurve_in_magnitude(self):
"""
Transform flux to magnitude using m = 27.4-2.5*log10(flux) convention. Transform error bar
accordingly. More details in microltoolbox module.
:return: the lightcurve in magnitude, lightcurve_magnitude.
:rtype: array_like
"""
lightcurve = self.lightcurve_flux
time = lightcurve[:, 0]
flux = lightcurve[:, 1]
error_flux = lightcurve[:, 2]
magnitude = microltoolbox.flux_to_magnitude(flux)
error_magnitude = microltoolbox.error_flux_to_error_magnitude(error_flux, flux)
ligthcurve_magnitude = np.array([time, magnitude, error_magnitude]).T
return ligthcurve_magnitude
[docs] def hidden(self):
try:
import webbrowser
controller = webbrowser.get()
if self.name =='Mexicola':
controller.open("https://www.youtube.com/watch?v=GcQdU2qA7D4&t=1684s")
except:
pass