def test_LC_request_response(self): # Call the service, which will send a request to the server. X1_list, X4_list, oot_list, intr_list, bkg_list, apmask_list, arrshape_list, t_list, T0_list, tpf_filt_list, TESS_unbinned_t_l, TESS_binned_t_l, small_binned_t_l, TESS_unbinned_l, TESS_binned_l, small_binned_l, tpf_list = utils.download_tpf( indir, transit_sec, transit_list, tic, test='./LATTE/tests/tic55525572_tp.fits') #If the request is sent successfully, then I expect a response to be returned. self.assertAlmostEqual(float(X1_list[0][0][0]), float(23.402481079101562), places=5, msg='TP data is not what it should be.') self.assertAlmostEqual(float(X4_list[0][0][0]), float(22.052828), places=5, msg='TP data is not what it should be.') self.assertAlmostEqual(float(oot_list[0][0]), float(0.0)) self.assertAlmostEqual(float(intr_list[0][0]), float(0.0)) self.assertAlmostEqual(float(bkg_list[0][0][0]), float(29.239688873291016), places=5) self.assertAlmostEqual(float(apmask_list[0][0][0]), float(0.0)) self.assertAlmostEqual(float(arrshape_list[0][0]), float(18944.0)) self.assertAlmostEqual( float(t_list[0][0]), float(1437.9924102871835), places=5, ) self.assertAlmostEqual(float(T0_list[0]), float(1454.7))
def brew_LATTE(tic, indir, syspath, transit_list, simple, BLS, model, save, DV, sectors, sectors_all, alltime, allflux, allflux_err, all_md, alltimebinned, allfluxbinned, allx1, allx2, ally1, ally2, alltime12, allfbkg, start_sec, end_sec, in_sec, upper_axis_lim_final, lower_axis_lim_final, tessmag, teff, srad, ra, dec, input_numax, input_analysis_window, url_list, args): ''' This function combines all the results from LATTE and calls all the different functions - it makes the plots, saves them, runs the BLS model and the pyaneti model before making a PHT DV report (if this option is selected.) Parameters ---------- tic : str target TIC ID indir : str path to directory where all the plots and data will be saved. transit_list : list list of the transit-like events simple : boolean whether or not to run the simple version BLS : boolean whether or not to run the BLS routine model : boolean whether or not to model the transit using pyaneti save : boolean whether or not to save the figures and data DV : boolean whether or not to write and save a DV report sectors_all : list all the sectors in which the target has been/ will be observed alltime : list times (not binned) allflux : list normalized flux (not binned) allflux_err : list normalized flux errors (not binned) all_md : list times of the momentum dumps alltimebinned : list binned time allfluxbinned : list normalized binned flux allx1 : list CCD column position of target’s flux-weighted centroid. In x direction allx2 : list The CCD column local motion differential velocity aberration (DVA), pointing drift, and thermal effects. In x direction ally1 : list CCD column position of target’s flux-weighted centroid. In y direction ally2 : list The CCD column local motion differential velocity aberration (DVA), pointing drift, and thermal effects. In y direction alltimel2 : list time used for the x and y centroid position plottin allfbkg : list background flux start_sec : list times of the start of the sector end_sec : list times of the end of the sector in_sec : list the sectors for which data was downloaded tessmag : list TESS magnitude of the target star teff : float effective temperature of the tagret star (K) srad : float radius of the target star (solar radii) ra : float the right ascension of the target stars dec : float the declination of the target star ''' # ------------------- # SAVE THE DATA FILES # ------------------- if (save == True) or (DV == True): save = True # if this folder doesn't exist then create it. These are the folder where the images, data and reports for each TIC ID will be stored. newpath = '{}/{}'.format(indir,tic) if not exists(newpath): os.makedirs(newpath) # save the data used as a text file - these often come in use later for a quick re-analysis. with open('{}/{}/{}_data.txt'.format(indir, tic, tic), "w") as f: # get rid of nan values first using a mask good_mask = np.isfinite(np.array(alltime)) * np.isfinite(np.array(allflux)) * np.isfinite(np.array(allflux_err)) alltime_ar = np.array(alltime)[good_mask] allflux_ar = np.array(allflux)[good_mask] allflux_err_ar = np.array(allflux_err)[good_mask] # save writer = csv.writer(f, delimiter='\t') writer.writerow(['time', 'flux', 'flux_err']) writer.writerows(zip(alltime_ar,allflux_ar,allflux_err_ar)) ''' if the modelling option was also chose, save another data file with slightly different formatting to be called by Pyaneti. Pyaneti requires a very specific data format. Furhermore, in order for Pyaneti to run more efficiently (it has a Bayesian backend which scales with number of data points) we create a cutout of the times around the times of the marked transit events. ''' if len(transit_list) != 0: if model == True: with open('{}/{}/{}_data_pyaneti.dat'.format(indir, tic, tic), "w") as f: writer = csv.writer(f, delimiter='\t') writer.writerow(['#time', 'flux', 'flux_err']) # If the dip separations are too small, then don't create cut outs and save the whole dataset if (len(transit_list) > 1) and ((transit_list[1] - transit_list[0]) < 2): # if there are LOTS of transit events on short period (if so it's probably a TOI but let's keep it here as a condition) with open('{}/{}/{}_data_pyaneti.dat'.format(indir, tic, tic), "a") as f: writer = csv.writer(f, delimiter='\t') writer.writerows(zip(alltime_ar,allflux_ar,allflux_err_ar)) # save all the data # else create a cut out of the data around the time of the transit events else: for transit in transit_list: # save the data # get rid of nan values first - this is used for the pyaneti code pyaneti_mask = (alltime_ar > (transit - 1)) * (alltime_ar < (transit + 1)) with open('{}/{}/{}_data_pyaneti.dat'.format(indir, tic, tic), "a") as f: writer = csv.writer(f, delimiter='\t') writer.writerows(zip(alltime_ar[pyaneti_mask],allflux_ar[pyaneti_mask],allflux_err_ar[pyaneti_mask])) # ----------------------------------- # START PLOTTING - calls functions from LATTEutils.py # ----------------------------------- if len(transit_list) != 0: # this is always the case unless the asteroseismic only option ws chosen # create a plot of the fulllighcurves with the momentum dumps (MDs) marked and a zoom-in of the marked transits # this plit is saved but not shown (as already shown in the interact part fo the code) utils.plot_full_md(tic, indir, alltime,allflux,all_md,alltimebinned,allfluxbinned, transit_list, upper_axis_lim_final, lower_axis_lim_final, args) # Get a list of the sectors that have transit marked in them # this is so that we no longer have to loop through all of the sectors, and can focus on the ones which are important. transit_sec = utils.transit_sec(in_sec, start_sec, end_sec, transit_list) # ----------- # plot how the centroids moved during the transit event utils.plot_centroid(tic, indir,alltime12, allx1, ally1, allx2, ally2, transit_list, args) # plot the background flux at the time of the transit event. utils.plot_background(tic, indir,alltime, allfbkg, transit_list, args) print ("Centroid and background plots... done.") # ----------- # if the 'simple' option is chosen in the GUI, then the code will end here - this is designed to provide a quick analysis requiring no TPFs. if simple == True: print ("Simple option was selected, therefore end analysis here.") sys.exit('') # ----------- # call function to extract the Target Pixel File information # this is needed in order to extract the LCs in different aperture sizes. # the data is extracted using the open source Lightkurve package as they a built in function to extract LCs using different aperture sizes #TESS_unbinned_t_l, TESS_binned_t_l, small_binned_t_l, TESS_unbinned_l, TESS_binned_l, small_binned_l, tpf_list = utils.download_tpf_lightkurve(indir, transit_list, sectors, tic) print ("\n Start downloading of the target pixel files - this can take a little while (up to a minute) as the files are large \n") X1_list, X4_list, oot_list, intr_list, bkg_list, apmask_list, arrshape_list, t_list, T0_list, tpf_filt_list,TESS_unbinned_t_l, TESS_binned_t_l, small_binned_t_l, TESS_unbinned_l, TESS_binned_l, small_binned_l, tpf_list = utils.download_tpf(indir, transit_sec, transit_list, tic, url_list) # if the TPF wasn't corrupt then make the TPF files (only very ocassionally corrupt but don't want code to crash if it is corrrupt) if (TESS_unbinned_t_l[0] != -111): tpf_corrupt = False # plot the LCs using two different aperture sizes. utils.plot_aperturesize(tic,indir,TESS_unbinned_t_l, TESS_binned_t_l, small_binned_t_l, TESS_unbinned_l, TESS_binned_l, small_binned_l, transit_list, args) print ("Aperture size plots... done.") # ------------ ''' Plot the average pixel brightness of the cut-out around the target star and the corresponding SDSS field of view. Both are oriented so that North is pointing upwards. The former also shows the nearby stars with TESS magnitude brighter than 17. Queried from GAIA using astroquery. The function returns the mass of the star (also output from astroquery)- this is a useful input for the Pyaneti modelling ''' if args.mpi == False: test_astroquery, _, _, mstar, vmag, logg, plx, c_id = utils.plot_TESS_stars(tic,indir, transit_sec, tpf_list, args) if test_astroquery == -111: tessmag, teff, srad, mstar, vmag, logg, plx, c_id = utils.plot_TESS_stars_not_proj(tic,indir, transit_list, transit_sec, tpf_list, args) args.mpi = True else: test_astroquery, _, _, mstar, vmag, logg, plx, c_id = utils.plot_TESS_stars_not_proj(tic,indir, transit_list, transit_sec, tpf_list, args) # keep track of whether astroquery is working (sometimes the site is down and we don't want this to stop us from running the code) astroquery_corrupt = False if test_astroquery == -999: astroquery_corrupt = True print ("Star Aperture plots... failed.") else: print ("Star Aperture plots... done.") # ------------ # Download the Target Pixel File using the raw MAST data - this comes in a different format as the TPFs extracted using Lightkurve # This data is then corrected using Principal Component Analysis is orderto get rid of systematics. #X1_list, X4_list, oot_list, intr_list, bkg_list, apmask_list, arrshape_list, t_list, T0_list, tpf_filt_list = utils.download_tpf_mast(indir, transit_sec, transit_list, tic) # ------------ ''' plot the in and out of transit flux comparison. By default the images are NOT oriented north - this is because the reprojection takes longer to run and for a simple analysis to check whether the brightest pixel moves during the transit this is not required. The orientation towards north can be defined in the command line with '--north'. ''' if args.north == True: utils.plot_in_out_TPF_proj(tic, indir, X4_list, oot_list, t_list, intr_list, T0_list, tpf_filt_list, tpf_list, args) print ("In and out of aperture flux comparison with reprojection... done. ") else: utils.plot_in_out_TPF(tic, indir, X4_list, oot_list, t_list, intr_list, T0_list, tpf_filt_list, args) print ("In and out of aperture flux comparison... done.") # ------------ # For each pixel in the TPF, extract and plot a lightcurve around the time of the marked transit event. utils.plot_pixel_level_LC(tic, indir, X1_list, X4_list, oot_list, intr_list, bkg_list, tpf_list, apmask_list, arrshape_list, t_list, T0_list, args) print ("Pixel level LCs plot... done.") # ------------ else: tpf_corrupt = True mstar = 1 # need to define mstar otherwise pyaneti will complain - just make it one as an approximation. tessmag = np.nan teff = np.nan srad = np.nan vmag = np.nan logg = np.nan plx = np.nan c_id = np.nan astroquery_corrupt = True # ------------ # end of plots that require target pixel files # ------------ # If more than one transit has been marked by the user, the LC is phase folded based on the period of the separation of the first two maarked peaks. # These plots are saved but do not feature in the DV report. if len (transit_list) > 1: # needs to know a period so can only do this if more than one transit has been marked. period = transit_list[1] - transit_list[0] t0 = transit_list[0] # time of the first marking # calculate the phase phased = np.array([-0.5+( ( t - t0-0.5*period) % period) / period for t in alltimebinned]) fig, ax = plt.subplots(figsize=(5.55,5)) ax.plot(phased, allfluxbinned, marker='.',color = 'k', alpha = 1, lw = 0, markersize = 4, label = 'None', markerfacecolor='k') #ax.plot(phased, allflux,marker='o',color = 'navy', alpha = 0.7, lw = 0, markersize = 2, label = 'binning = 7', markerfacecolor='white') plt.title("Phase folded LC") ax.set_xlabel("Phase (days)") ax.set_ylabel("Normalized Flux") plt.plot() if save == True: plt.savefig('{}/{}/{}_phase_folded.png'.format(indir, tic, tic), format='png') if args.noshow == False: plt.show() print ("Phase folded plot... done.") else: print ("\n Only one transit marked - therefore can't be phase folded. \n") # ------------ ''' Plot LCs of the six closest TESS target stars. This allows us to check whether the transit-like events also appear in other nearby LCs which would be a sign that this is caused by a background event. ''' # get the tic IDs of the six nearest stars if args.FFI == False: ticids, distance, target_ra, target_dec = utils.nn_ticids(indir, transit_sec, tic) # download the data for these stars alltime_nn, allflux_nn, all_md_nn, alltimebinned_nn, allfluxbinned_nn,outtics,tessmag_list, distance = utils.download_data_neighbours(indir, transit_sec[0], ticids, distance) # plot the LCs utils.plot_nn(tic, indir,alltime_nn, allflux_nn, alltimebinned_nn, allfluxbinned_nn, transit_list, outtics, tessmag_list, distance, args) else: target_ra = ra target_dec = dec distance = None print ("Nearest neighbour plot... done.") # ------------ # if the BLS option is chose, a BLS search is run. The LCs are first detrended and smoothed using a moving average. # The corrected and uncorrected LCs are saves as a single plot for comparison and to verify that the correction worked well - saved but do not feature in the DV report. if BLS == True: print ("Running BLS algorithm...", end =" ") bls_stats1, bls_stats2 = utils.data_bls(tic, indir, alltime, allflux, allfluxbinned, alltimebinned, args) print ("done.") else: from astroquery.mast import Catalogs #plot the main LC with only one panel and no transit events marked utils.plot_full_md_notransits(tic, indir, alltime, allflux, all_md, alltimebinned, allfluxbinned, upper_axis_lim_final, lower_axis_lim_final, args) target_ra = ra target_dec = dec tpf_corrupt = False # get the star information that would otherwise come from the plot_TESS_stars function starName = "TIC " + str(tic) radSearch = 5/60 #radius in degrees # this function depends on astroquery working, and sometimes it doesn't. # for when it doesn't work (or simply can't connect to it), just skip plotting the other TESS stars. try: astroquery_corrupt = False catalogData = Catalogs.query_object(starName, radius = radSearch, catalog = "TIC") except: astroquery_corrupt = True print ("Currently cannot connect to Astroquery.") # return values that we know aren't real so that we can tell the code that the plotting didn't work return -999, -999, -999, 1, -999,-999,-999,-999 # ra and dec of the target star ra = catalogData[0]['ra'] dec = catalogData[0]['dec'] # while we have the astroquery loaded, let's collect some other information about the star # these paramaters can help us find out what type of star we have with just a glance vmag = catalogData['Vmag'][0] # v magnitude (this migth be more useful than the TESS mag for things such as osbevring) logg = catalogData['logg'][0] # logg of the star mstar = catalogData['mass'][0] # mass of the star plx = catalogData['plx'][0] # parallax # sometimes these values aren't accessible through astroquery - so we shoudl just quickly check. if not np.isfinite(vmag): vmag = '--' # this is what will appear in the table of the report to indicate that it's unknown if not np.isfinite(logg): logg = '--' if not np.isfinite(mstar): mass = '--' if not np.isfinite(plx): plx = '--' # sometimes it's useufl to know if the star has another name # check whether it was osberved by one of these four large surveys catalogs = ['HIP', 'TYC', 'TWOMASS', 'GAIA'] for cat in catalogs: c_id = str(catalogData[0][cat]) if c_id != '--': cat_id = "{} {}".format(cat,c_id) break else: continue tessmag = catalogData['Tmag'][0] teff = catalogData['Teff'][0] srad = catalogData['rad'][0] c_id = c_id # ------------ # period analysis # always make a peridoogram? QUestion for later. print ("Periodogram plot...", end =" ") mass_ast, radius_ast, logg_ast, numax, deltanu = utils.plot_periodogram(tic, indir, alltime, allflux, teff, input_numax, input_analysis_window, args) print ("done.") # ------------ # stellar evolutionary tracks print ("Evolutionary tracks plot...", end =" ") utils.eep_target(tic, indir, syspath, teff, srad, args) print ("done.") # ------------ # SKIP FROM HERE.... ''' NOTE: CURRENTLY ONLY WORKS ON NORA'S COMPUTER - WILL BE AVAILABLE IN NEXT RELEASE SO PLEASE SKIP THIS PART OF THE CODE If the modelling option is selected (in the GUI), model the transit event using Pyaneti (Barragan et al 2018) which uses an Bayesian approach with an MCMC sampling to best fit and model the transit. The code runs slightly differently depending on whether one or multiple transits have been marked. This is because with multiple transits the code has information about the possible orbital period. Need to ensure that the code has compiled correctly on the users computer. Reason why is doesn't work else where: the priors need to be set up ver carefully, and this has not been tested enough to know it can be automated to work reliably. Also, this code requires a fortran backend, which has not yet been included in LATTE. ---> we're working on implementing this as it will be very useful. ''' # First check if Pyaneti is installed... if os.path.exists("{}/pyaneti_LATTE.py".format(syspath)): if model == True: print ("Running Pyaneti modelling - this could take a while so be patient...") transit_list_model = ("{}".format(str(np.asarray(transit_list)))[1:-1]) # change the list into a string and get rid of the brackets # the code is usually run through the command line so call it using the os.system function. os.system("python3 {}/pyaneti_LATTE.py {} {} {} {} {} {} {}".format(syspath, tic, indir, syspath, mstar, teff, srad, transit_list_model)) else: #print ("Pyaneti has not been installed so you can't model anything yet. Contact Nora or Oscar for the LATTE version of the Pyaneti code.") model = False # ... UNTIL HERE # ------------ # Finally, create a DV report which summarises all of the plots and tables. if DV == True: from LATTE import LATTE_DV as ldv if BLS == True: ldv.LATTE_DV(tic, indir, syspath, transit_list, sectors_all, target_ra, target_dec, tessmag, teff, srad, mstar, vmag, logg, mass_ast, radius_ast, logg_ast, numax, deltanu, plx, c_id, bls_stats1, bls_stats2, tpf_corrupt, astroquery_corrupt, FFI = args.FFI, bls = True, model = model, mpi = args.mpi) else: ldv.LATTE_DV(tic, indir, syspath, transit_list, sectors_all, target_ra, target_dec, tessmag, teff, srad, mstar, vmag, logg, mass_ast, radius_ast, logg_ast, numax, deltanu, plx, c_id, [0], [0], tpf_corrupt, astroquery_corrupt, FFI = args.FFI, bls = False, model = model, mpi = args.mpi)
def test_plot(self): # download data needed to generate the plots alltime, allflux, allflux_err, all_md, alltimebinned, allfluxbinned, allx1, allx2, ally1, ally2, alltime12, allfbkg, start_sec, end_sec, in_sec, tessmag, teff, srad = utils.download_data( indir, sector, tic, binfac=5, test='./LATTE/tests/tic55525572_lc.fits') #X1_list, X4_list, oot_list, intr_list, bkg_list, apmask_list, arrshape_list, t_list, T0_list, tpf_filt_list = utils.download_tpf_mast(indir, transit_sec, transit_list, tic, test = './LATTE/tests/tic55525572_tp.fits') # this function downloads the data and saved plots that show the aperture sizes (for the large and small apertures) X1_list, X4_list, oot_list, intr_list, bkg_list, apmask_list, arrshape_list, t_list, T0_list, tpf_filt_list, TESS_unbinned_t_l, TESS_binned_t_l, small_binned_t_l, TESS_unbinned_l, TESS_binned_l, small_binned_l, tpf_list = utils.download_tpf( indir, transit_sec, transit_list, tic, test='./LATTE/tests/tic55525572_tp.fits') # --------- # create the plots that the normal routine makes utils.plot_full_md(tic, indir, alltime, allflux, all_md, alltimebinned, allfluxbinned, transit_list, args) utils.plot_centroid(tic, indir, alltime12, allx1, ally1, allx2, ally2, transit_list, args) utils.plot_background(tic, indir, alltime, allfbkg, transit_list, args) utils.plot_pixel_level_LC(tic, indir, X1_list, X4_list, oot_list, intr_list, bkg_list, apmask_list, arrshape_list, t_list, transit_list, args) utils.plot_aperturesize(tic, indir, TESS_unbinned_t_l, TESS_binned_t_l, small_binned_t_l, TESS_unbinned_l, TESS_binned_l, small_binned_l, transit_list, args) utils.plot_periodigram(tic, indir, alltime, allflux, args) utils.eep_target(tic, indir, syspath, teff, srad, args) # -------- # now check that the plots were actually made! # in order to be able to run this code multiple times, assert that the files were created in the last minuet - if the code takes lomger than that to run something is goimg wrong...? # without checking when the file is made, the files would have to be manually deleted after every test # these are the paths of the files that should have bee created full_LC_path = '{}/55525572/55525572_fullLC_md.png'.format(indir) full_centroid = '{}/55525572/55525572_centroids.png'.format(indir) bkg_path = '{}/55525572/55525572_background.png'.format(indir) pixel_path = '{}/55525572/55525572_individual_pixel_LCs_0.png'.format( indir) ap_LC_path = '{}/55525572/55525572_aperture_size.png'.format(indir) apertures_path = '{}/55525572/55525572_apertures_0.png'.format(indir) # Get file's Last modification time stamp only in terms of seconds since epoch time_created_full_LC = os.path.getmtime(full_LC_path) time_created_centroid = os.path.getmtime(full_centroid) time_created_bkg = os.path.getmtime(bkg_path) time_created_pixel = os.path.getmtime(pixel_path) time_created_ap_LC = os.path.getmtime(ap_LC_path) time_created_apertures = os.path.getmtime(apertures_path) # Convert seconds since epoch to readable timestamp t_create_full_LC = parser.parse( time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time_created_full_LC))) t_create_centroid = parser.parse( time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time_created_centroid))) t_create_bkg = parser.parse( time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time_created_bkg))) t_create_pixel = parser.parse( time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time_created_pixel))) t_create_ap_LC = parser.parse( time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time_created_ap_LC))) t_create_apertures = parser.parse( time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time_created_apertures))) # the time now (needed to get the time since creation) t_now = (datetime.datetime.now()) # ------- # time difference in minutes time_since_creation_full_LC = ((t_now - t_create_full_LC).seconds / 60) time_since_creation_centroid = ((t_now - t_create_centroid).seconds / 60) time_since_creation_bkg = ((t_now - t_create_bkg).seconds / 60) time_since_creation_pixel = ((t_now - t_create_pixel).seconds / 60) # check that the expected files were created less than a minute ago self.assertLess( time_since_creation_full_LC, 1, "No (new) full LC plot was made in the last five minutes" ) # a less than b self.assertLess( time_since_creation_centroid, 1, "No (new) centroid plot was made in the last five minutes" ) # a less than b self.assertLess( time_since_creation_bkg, 1, "No (new) background plot was made in the last five minutes" ) # a less than b self.assertLess( time_since_creation_pixel, 1, "No (new) pixel level LC plot was made in the last five minutes" ) # a less than b