def target_observable(self, Nights, constraints, delta_midnight=None): """ Calculates for which times during the time span of Nights, the target is observable under the given constraints. LATER : Could include plotting of target observability. Parameters ---------- Nights : class Nights at Paranal for which to compute if the target is observable. constraints : list list of Astroplan constraints to constrain the observability. delta_midnight : numpy.linspace, Obtional grid of timesteps within 24 hours for which the observation should be calculated. """ if delta_midnight == None: # defines number of timesteps per 24 hours delta_midnight = np.linspace(-12, 12, 1000) * u.hour print(self.name + ' is getting processed') for date in Nights.date: """ Check if Nights object has attribute nights to calculate observability of target """ if hasattr(Nights, 'night'): k = list.index(Nights.date, date) night = Nights.night[k] else: Nights.Calculate_nights_paranal(delta_midnight) night = Nights.night[k] """ Check if target observable """ tar_obs = astroplan.is_event_observable( constraints=constraints, observer=paranal, target=self.Coordinates, times=night) if any(tar_obs[0] == True): print( '{} Target is observable without any primary eclipse'.format(self.name)) for n, tar in enumerate(tar_obs[0]): if tar == True: moon_target_sep, moon_phase, airmass, obs_altazs = fun.airmass_moon_sep_obj_altaz( self, night[n]) self.target_observable.append({ 'Name': self.name, 'Effective Temperature': self.star_Teff, 'J-magnitude': self.star_jmag, 'Object observable?': tar, 'Obs Data': {'time': night[n], 'airmass': airmass, 'moon sep': moon_target_sep[0], 'moon phase': moon_phase, 'az': obs_altazs.az, 'alt': obs_altazs.alt }})
def __init__(self, d, Max_Delta_days, LoadFromPickle=0): """ Calculates the nights at paranal for a certain start date ''d'' and end date, reached after ''Max_Delta_days''. Retrieves the sun coordinates for each night from astroplan to determine the night times. Parameters ---------- d : datetime.date Start date from which the nights at paranal are computed. Max_Delta_days : int Time span for which the nights at paranal are computed. LoadFromPickle : int If ''LoadFromPickle'' = 1, checks if Night data for given time span is available. """ dt = datetime.timedelta(days=1) d_end = d + dt * Max_Delta_days self.Max_Delta_days = Max_Delta_days if LoadFromPickle == 1: """ Check if there exist pkl files with night data for the preferred range, if not: initializes empty lists for Nights instance """ try: d_str = d.isoformat() # start date from which the nights in paranal are calculated filename = 'Nights_paranal_{}_{}d.pkl'.format( d_str, self.Max_Delta_days) nights = fun.pickled_items(filename) self.start = nights.__next__() self.end = nights.__next__() self.Max_Delta_days = nights.__next__() self.date = nights.__next__() self.night = nights.__next__() self.loaded = 1 except Exception as e: print(e) self.loaded = 0 d_str = d.isoformat() # start date from which the nights in paranal are calculated filename = 'Nights_paranal_{}_{}d.pkl'.format( d_str, self.Max_Delta_days) print('No Night data found for {}, computing nights...'.format(filename)) self.start = d self.end = d_end self.Max_Delta_days = (d_end - d).days self.date = [] # self.night = [] self.loaded = 0 for k in range(self.Max_Delta_days): date = self.start + dt * k # list with datetime objects for the midnights in question self.date.append(date)
def load_Eclipses_from_file(filename, Max_Delta_days, path = None): """ Loads Eclipses class objects from pickled file with ''filename''. Parameters ---------- filename : str Name of file containing the pickled Eclipses class object data. Max_Delta_days : int Days for which the eclipses got computed, necessary to initialize Eclipses class. Returns ------- Eclipses_List : list Contains all Eclipses class objects that have been loaded from the file. """ Eclipses_List = [] def att_identifier(att): if type(att) == int: Planet.num_eclipses = att elif type(att) == FixedTarget: Planet.Coordinates = att elif type(att) == astroplan.periodic.EclipsingSystem: Planet.Planets_eclipse = att else: return att if path == None: planet = fun.pickled_items(filename) else: planet = fun.pickled_items(filename, path) att = None while True: Planet = Eclipses(Max_Delta_days) try: if att != None: print(att) Planet.name = att else: Planet.name = next(planet) Planet.epoch = next(planet) Planet.tranmid_err = next(planet) Planet.period = next(planet) Planet.period_err = next(planet) Planet.transit_duration = next(planet) Planet.eccentricity = next(planet) Planet.star_Teff = next(planet) Planet.star_jmag = next(planet) Planet.pl_radj = next(planet) att = None while att == None: att = next(planet) att = att_identifier(att) target_observable = att eclipse_observable = next(planet) att = None while att == None: att = next(planet) att = att_identifier(att) Planet.eclipse_observable.extend(eclipse_observable) Planet.target_observable.extend(target_observable) Eclipses_List.append(Planet) except StopIteration: print('Eclipses_List has been loaded from {}'.format(filename)) logging.info( 'Eclipses_List has bin loaded from {}'.format(filename)) Planet.eclipse_observable.extend(eclipse_observable) Planet.target_observable.extend(target_observable) Eclipses_List.append(Planet) break return Eclipses_List
def Observability(self, obs_time, Nights, constraints): #check_eclipse, check_target=0, delta_midnight=None """ Calculates if the Transit and the target are observable for each date during the given timespan in ''Nights'' under the given ''constraints'' and writes it as dict objects into ''~self.eclipse_observable'' or ''~self.target_observable''. Parameters ---------- obs_time : astropy.time.Time Contains the datetime as Time format after which the possible observations should be found. Nights : class Nights Containing night data of paranal, see Nights documentation. constraints : class astroplan.Constraint Constraints under which the observational events should get constrained. check_eclipse : int If ''check_eclipse'' = 1, checks if transits/eclipses are observable. check_target : int, optional If ''check_target'' = 1, checks if target is observable during the given nights. The default is 0. delta_midnight : numpy.linspace, obtional array containing a grid of timesteps for which the nights datetimes should get computed. Default is None """ Planet_next_eclipse_Times = self.Planets_eclipse.next_primary_eclipse_time( obs_time, n_eclipses=self.num_eclipses) print(self.name + ' is getting processed') # n_max = np.ceil(1/self.period_err) # for date in Nights.date: # if check_target == 1: # """ Check if Nights object has attribute nights to calculate observability of target """ # if hasattr(Nights, 'night'): # k = list.index(Nights.date, date) # night = Nights.night[k] # else: # Nights.Calculate_nights_paranal(delta_midnight) # night = Nights.night[0] Planet_Eclipes_NIGHTs_All = [] for n, planet_next_eclipse_by_date in enumerate(Planet_next_eclipse_Times): """ Loop over all eclipses coming up in the given timespan of object planet """ """ Barycentric light travel time correction, since mid transit times are in barycentric frame. Need to transform time to geocentric frame: """ planet_next_eclipse_by_date.location = paranal.location ltt_bary = planet_next_eclipse_by_date.light_travel_time(self.Coordinates.coord) planet_next_eclipse_by_date = planet_next_eclipse_by_date - ltt_bary # barycentric correction, # the minus comes from that we transform from the barycentric into the geocentric frame. # Check which eclipse can be observed in which night # if date == planet_next_eclipse_by_date.datetime.date(): # if check_eclipse == 1: Planet_next_eclipse_per_night_MID = planet_next_eclipse_by_date Planet_next_eclipse_per_night_BEGIN = Planet_next_eclipse_per_night_MID - \ self.transit_duration / 2 Planet_next_eclipse_per_night_END = Planet_next_eclipse_per_night_MID + \ self.transit_duration / 2 Planet_Eclipse_ERROR = (np.sqrt(self.tranmid_err.sec**2+(n+1)**2*self.period_err.to_value(u.second)**2)*u.second).to(u.hour) Planet_Eclipes_NIGHT = [Planet_next_eclipse_per_night_BEGIN, Planet_next_eclipse_per_night_MID, Planet_next_eclipse_per_night_END] # Begin, midpoint and end of transit # Planet_Eclipes_NIGHTs_All = Planet_Eclipes_NIGHTs_All + Planet_Eclipes_NIGHT """ Computes observability of the Transit """ ecl_obs = astroplan.is_event_observable( constraints=constraints, observer=paranal, target=self.Coordinates, times=Planet_Eclipes_NIGHT) # ecl_obs_test = astroplan.is_event_observable( # constraints=constraints, observer=paranal, target=self.Coordinates, times=Planet_Eclipes_NIGHTs_All) # for k in range(int(len(ecl_obs_test[0])/3)): # flag_not_obs = False # for n in range(3): # if ecl_obs_test[0][n+k] == False: # flag_not_obs = True # if not flag_not_obs: # Planet_Eclipes_NIGHT_obs = [Planet_Eclipes_NIGHTs_All[0+k], Planet_Eclipes_NIGHTs_All[1+k], Planet_Eclipes_NIGHTs_All[2+k]] if all(ecl_obs[0] == True): print('{} total Eclipse is observable'.format(self.name)) airmass_moon_sep_obj_altaz_RESULT = [ fun.airmass_moon_sep_obj_altaz(self, tim) for tim in Planet_Eclipes_NIGHT] #HERE Planet_Eclipes_NIGHT_obs moon_target_sep = [ out[0] for out in airmass_moon_sep_obj_altaz_RESULT] moon_phase = [out[1] for out in airmass_moon_sep_obj_altaz_RESULT] airmass = [out[2] for out in airmass_moon_sep_obj_altaz_RESULT] obs_altazs = [out[3] for out in airmass_moon_sep_obj_altaz_RESULT] # print(moon_target_sep, moon_phase, airmass, obs_altazs) self.eclipse_observable.append({ 'Name': self.name, 'Radius R_J': self.pl_radj, 'Transit Midpoint Time': Planet_next_eclipse_per_night_MID, #Planet_Eclipes_NIGHT_obs[1], 'Transit Midpoint Time uncertainty [h]': Planet_Eclipse_ERROR, 'Primary eclipse observable?': ecl_obs[0][0], 'Transit Duration [h]': self.transit_duration.to(u.hour), 'Effective Temperature K': self.star_Teff, 'J-magnitude': self.star_jmag, 'Eclipse Begin': {'time': Planet_next_eclipse_per_night_BEGIN, #Planet_Eclipes_NIGHT_obs[0] , 'airmass': airmass[0], 'moon sep': moon_target_sep[0][0], 'moon phase': moon_phase[0], 'az': obs_altazs[0].az, 'alt': obs_altazs[0].alt }, 'Eclipse Mid': {'time': Planet_next_eclipse_per_night_MID, #Planet_Eclipes_NIGHT_obs[1] , 'airmass': airmass[1], 'moon sep': moon_target_sep[1][0], 'moon phase': moon_phase[1], 'az': obs_altazs[1].az, 'alt': obs_altazs[1].alt }, 'Eclipse End': {'time': Planet_next_eclipse_per_night_END, #Planet_Eclipes_NIGHT_obs[2], 'airmass': airmass[2], 'moon sep': moon_target_sep[2][0], 'moon phase': moon_phase[2], 'az': obs_altazs[2].az, 'alt': obs_altazs[2].alt }})
def Calculate_nights_paranal(self, delta_midnight, observatory=paranal, WriteToPickle=0): """ Calculates the nights at ''observatory'', default=paranal for a certain start date and end date. Retrieves the sun coordinates for each night from astroplan. Parameters ---------- delta_midnight : numpy.linspace array containing a grid of timesteps for which the nights datetimes should get computed. observatory : astroplan.Observer (optional) contains EarthLocation and timezone info about the observer at, default is paranal. WriteToPickle : int Object Nights gets written into a pickle file. Returns ------- self.dates : list Contains datetime.date objects for each night between d and d_end. self.coords : list Contains dict with sun coordinates for each time in Nights.night. self.night : list Contains lists with nighttimes for each night. The number timesteps for each nights is defined in delta_midnight. """ if self.loaded == 1: """ If the nights at paranal with startdate d could be loaded from file, yield: """ print( 'Nights loaded from file, continueing with processing planets for observability') else: """ All times are in UTC respectively """ print('Calculating the nights of paranal from the {} until the {}'.format( self.start, self.end)) self.night = [] midnight = datetime.time(0, 0, 0) for date in self.date: # list with datetime objects for the midnights in question midnight_datetime = datetime.datetime.combine(date, midnight) # Time object for each midnight gets created in UTC, midnight in UTC. midnight_at_site_UTC = observatory.datetime_to_astropy_time( midnight_datetime) Night_paranal = midnight_at_site_UTC + delta_midnight # in UTC # compute frame AltAz for get_sun frame_24_h_paranal = AltAz( obstime=Night_paranal, location=observatory.location) sunaltazs_24_h = get_sun( Night_paranal).transform_to(frame_24_h_paranal) night = [] for n, _ in enumerate(delta_midnight): """ Calculates the night times for each night """ if sunaltazs_24_h[n].alt < -18 * u.deg: night.append(str(sunaltazs_24_h[n].obstime.value)) self.night.append(Time(night)) if WriteToPickle == 1: """Write Nights_paranal_table to file""" d = self.start d = d.isoformat() # start date from which the nights in paranal are calculated filename = 'Nights_paranal_{}_{}d.pkl'.format( d, self.Max_Delta_days) fun.pickle_dumper_objects(filename, self)
during the transit. The Number of exposures possible is added to the list eclipse_observable and eclipse_mid_observable for comparison. Each exposure is optimised to have NDIT between 16 and 32 with a minimum S/N = 100. The resulting S/N ratios of each exposure are used to compute the overall median. More values like DIT, NDIT, SN of each exposure for each transit could be stored as well, but this has not been implemented yet. If one gets stuck in this loop due to internet connection or unexpected errors, one may rerun the code from here, instead of rerunning everything again. """ for planet in Eclipses_List: if planet.name == 'WASP-163 b': #Work around for planets which are missing data but did not get filtered. Get the name of the planet that was last called and enter it here. Can contain several names. Eclipses_List.remove(planet) for planet in Eclipses_List: for eclipse in planet.eclipse_observable: try: minimum_SN_tot = fun.req_SN(planet.pl_radj, planet.star_Teff) if minimum_SN_tot >= 450: minimum_SN = 100 else: minimum_SN = np.sqrt(minimum_SN_tot**2 / 20) fun.SN_estimate_num_of_exp(eclipse, planet, snr=minimum_SN) except Warning as w: print(w) print( 'Something went wrong in:{}:{}, taking next observation...' .format(planet.name, eclipse['Transit Midpoint Time'])) logging.exception(w) logging.error( 'Something went wrong in:{}:{}, taking next observation...' .format(planet.name, eclipse['Transit Midpoint Time']))
Eclipses_List_new = [] for filename in filenames_pickles: Eclipses_List = load_Eclipses_from_file( filename, Max_Delta_days, path= '/Users/jonaszbinden/Desktop/Target Selection Paper/Results/P108_metric_2D/original_files/' ) time.sleep(3) for name in name_list: for planet in Eclipses_List: if planet.name == name: print(planet.name, 'here') Eclipses_List_new.append(planet) Eclipses_List_new.pop(-2) delta_midnight = np.linspace(-12, 12, 1000) * u.hour Nights_paranal = Nights(d, Max_Delta_days, LoadFromPickle=0) Nights_paranal.Calculate_nights_paranal(delta_midnight) beg_end_night = [] for night in Nights_paranal.night: beg_end_night.append({'beg': night[0], 'end': night[-1]}) ranking, df_gen, df_frame, _ = fun.data_sorting_and_storing(Eclipses_List_new, write_to_csv=1) ranked_events, Obs_events = fun.postprocessing_events(d, Max_Delta_days, Nights, Eclipses_List_new) fun.xlsx_writer(filename, df_gen, df_frame, Obs_events) ranking = fun.plotting_transit_data(d, Max_Delta_days, ranking, Eclipses_List_new, Nights, ranked_events)