--- title: ASTR 597 W23 HW #2 author: Andy Tzanidakis and friends tags: LSST Class --- [TOC] # Homework 2 - ASTR 597 W23 - Author: Anastasios (Andy) Tzanidakis - Collaborators: None - Course ID: ASTR 597 W23 # Problem 1 We will initialize our set-up for this problem and importing our favorite libraries ```python= # Import general python packages import numpy as np import matplotlib.pyplot as plt import pandas from astropy import units as u from astropy.coordinates import SkyCoord import astropy.units as u # Import the Rubin TAP service utilities from lsst.rsp import get_tap_service, retrieve_query %matplotlib inline %config InlineBackend.figure_format = "retina" from tqdm import tqdm from matplotlib import rcParams rcParams["savefig.dpi"] = 100 rcParams["font.size"] = 20 # create the TAP service client service = get_tap_service() # we will all use the same input coordinates and radii center_coords = "62, -37" radius_deg = 0.5 # degrees ``` ## Exercise 1a. How many `isPrimary` How many `isPrimary` objects are in all of DP0.2? ```python= results = service.search("SELECT count(detect_isPrimary)" "FROM dp02_dc2_catalogs.Object " "WHERE detect_isPrimary = 1 ").to_table() >> Total number of rows 161025835 ``` Hooray, our query is complete. We find in the DP.0.2 object catalogue over 160,000,000 rows that satisfy `isPrimary`. ## Exercise 1b. Memory How much memory do you need to load one row of the Object table? *Hint: use the dtypes of all the columns.* To calculate this problem, we can enumerate through each column and take into account the `dtype` where we can sum the number of bits and convert it to bytes: ```python= job = service.submit_job("SELECT TOP 1 *" "FROM dp02_dc2_catalogs.Object ") job.run() job.wait(phases=['COMPLETED', 'ERROR']) # final table res = job.fetch_result().to_table() bites = 0 for k in res.keys(): d_format = res[f'{k}'].dtype if d_format=='float32' or d_format=='int32': bites += 32 elif d_format=='float64' or d_format=='int64': bites += 64 elif d_format=='bool': bites +=1 print ('Total row memory:' + (bites*u.bit).to(u.kilobyte)) >> Total row memory: 4.1725 kbyte ``` Using one row in DP.0.2 is roughly 4.2 kilobytes! ## Exercise 1c. Maximum rows on `daata.lsst.cloud` What's the maximum number of full rows of the Object table can you load into a Medium instance on data.lsst.cloud? Let's assume we can use up to 6.11 Gigabytes in memory RAM for a medium lsst.cloud instance: ```python= print (((6.1*u.gigabyte).to(u.kilobyte))/(4.14*u.kilobyte)) ``` $$\begin{equation} \text{Max Rows} = \frac{\text{Max Memory Medium Instance}}{\text{Memory per Row}} = \frac{6.1 \ Gb}{3.312 \times 10^{-5} Gb} \approx 1 473 430 \ \text{rows} \end{equation}$$ # Problem 2 ## Exercise 2a. Extendedness What values can the `{band}_extendedness` entry take? What fraction of the time do the values disagree between bands? What if you only look at rows where none of the `{band}_extendedness_flag` are set? We will use the query from the first problem and look at the top 100000 entries for this problem: ```python= # coords and radius (in deg) center_coords = "62, -37" rad = 0.5 results = service.search("SELECT TOP 100000 *" "FROM dp02_dc2_catalogs.Object " "WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec), " f"CIRCLE('ICRS', {center_coords}, {rad})) = 1 ") table = results.to_table() ``` To find out the unique entries for `{band}_extendedness`: ```python= print (np.unique(table['z_extendedness'].data.data)) >> array([ 0., 1., nan]) ``` Now we want to know what fraction of times do the values between the `X_extendedness` disagree between each band: ```python= # coords and radis (in deg) center_coords = "62, -37" rad = 0.5 results = service.search("SELECT u_extendedness, g_extendedness, r_extendedness, i_extendedness, z_extendedness, y_extendedness" "FROM dp02_dc2_catalogs.Object " "WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec), " f"CIRCLE('ICRS', {center_coords}, {rad})) = 1 " "AND detect_isPrimary = 1") table = results.to_table() passed_1 = np.where((table['u_extendedness']==1) & (table['g_extendedness']==1) & (table['r_extendedness']==1) & (table['i_extendedness']==1) & (table['z_extendedness']==1) & (table['y_extendedness']==1)) passed_0 = np.where((table['u_extendedness']==0) & (table['g_extendedness']==0) & (table['r_extendedness']==0) & (table['i_extendedness']==0) & (table['z_extendedness']==0) & (table['y_extendedness']==0)) total = len(passed_1[0]) + len(passed_0[0]) # total number of agreed values frac_total_extendedness = (100 - total/len(table) * 100) # 100 - total print (f"Percentage of all rows that have have extrendedness (0 or 1): {frac_total_extendedness} percent") >> 56.62 percent ``` We find that approximately 56% of each band disagrees with each other. We can also investigate how this fraction changes when the `X_extendedness_flag` is not set: ```python= cond_1 = np.where((table['u_extendedness_flag']==False) & (table['g_extendedness_flag']==False) & (table['r_extendedness_flag']==False) & (table['i_extendedness_flag']==False) & (table['z_extendedness_flag']==False) & (table['y_extendedness_flag']==False)) tab_new = table[cond_1] # new table passed_1_ = np.where((tab_new['u_extendedness']==1) & (tab_new['g_extendedness']==1) & (tab_new['r_extendedness']==1) & (tab_new['i_extendedness']==1) & (tab_new['z_extendedness']==1) & (tab_new['y_extendedness']==1)) passed_0_ = np.where((tab_new['u_extendedness']==0) & (tab_new['g_extendedness']==0) & (tab_new['r_extendedness']==0) & (tab_new['i_extendedness']==0) & (tab_new['z_extendedness']==0) & (tab_new['y_extendedness']==0)) print (f"Fraciton of X_extendedness when flag is not set: {1 - (len(passed_1_[0]) + len(passed_0_[0]))/len(tab_new)}") >> Fraciton of X_extendedness when flag is not set: 0.18672121303107636 ``` We find that the fraction is significantly smaller, about 19% when the `_flag` is not set. ## Exercise 2b. Signal to Noise Make a plot of PSF magnitude vs. magnitude error for r-band point sources in our region of interest. Exclude sources with the PSF Flux general failure flag set. Set the axes extents to a reasonable range and label your axes! Hints: Consult the [schema browser](https://dm.lsst.org/sdm_schemas/browser/dp02.html#Object) for column names. Consider using [hexbin](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.hexbin.html) instead of a scatter plot with `bins='log'`... We will first begin with our query and leverage the `nanojanskyToAbMag` to convert the PSF fluxes to AB magnitudes: ```python= # convert to AB magnitues & error for the LSST-r results = service.search("SELECT coord_ra, coord_dec, " "scisql_nanojanskyToAbMag(r_calibFlux) as r_psf_mag, " "scisql_nanojanskyToAbMagSigma(r_calibFlux, r_calibFluxErr) as r_psf_mag_err " "FROM dp02_dc2_catalogs.Object " "WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec), " "CIRCLE('ICRS', "+center_coords+", 0.5)) = 1 " "AND detect_isPrimary = 1 ", maxrec=250_000) # fetch table table = results.to_table() ``` |<img src="https://i.imgur.com/6fcFe6p.png" alt="Image" width="500" height="500" style="display: block; margin: 0 auto" />| |:--:| | Figure 1. -- AB apparent magnitude and error estimated from the PSF flux estimates.| ## Exercise 3: Find a Transient or Variable Using the `DIAObject` table, find an object with more than 1 magnitude of variability and plot its lightcurve. One quick way to search through the light curves and check for >1 mag variability (i.e let's say we're interested in the LSST-r band magnitudes): ```python= for i in tqdm(range(100)): sel_objid = table[i]['objectId'] # From Tutorial 07b to fetch the light curve information query = "SELECT src.band, src.ccdVisitId, src.coord_ra, src.coord_dec, "\ "src.objectId, src.psfFlux, src.psfFluxErr, "\ "scisql_nanojanskyToAbMag(psfFlux) as psfMag, "\ "visinfo.ccdVisitId, visinfo.band, "\ "visinfo.expMidptMJD, visinfo.zeroPoint "\ "FROM dp02_dc2_catalogs.ForcedSource as src "\ "JOIN dp02_dc2_catalogs.CcdVisit as visinfo "\ "ON visinfo.ccdVisitId = src.ccdVisitId "\ "WHERE src.objectId = "+str(sel_objid)+" " # Query results = service.search(query) lc = results.to_table() # light curve table # Select band r = lc['band2']=='r' diff = np.median(lc['psfMag'][r])-min(lc['psfMag'][r]) if diff>1: print (f"Warning obj_id candidate {sel_objid} has >1 mag variability in the LSST-r bandpass") # Plotting light curve plt.figure(figsize=(10, 4)) plt.scatter(lc['expMidptMJD'][r], lc['psfMag'][r], color='crimson') plt.axhline(np.median(lc['psfMag'][r]), color='k', ls='--') plt.xlabel('MJD') plt.ylabel('m$_{LSST-r}$ [AB mag]') plt.ylim(plt.ylim()[::-1]) break ``` |<img src="https://i.imgur.com/ukNM9XM.png" alt="Image" width="500" height="230" style="display: block; margin: 0 auto" />| |:--:| | Figure 1. -- Sample LSST-r AB mag light curve with >1 mag variability.|