tglc 0.6.5__py3-none-any.whl → 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
tglc/quick_lc.py CHANGED
@@ -9,24 +9,30 @@ import matplotlib.pyplot as plt
9
9
  from multiprocessing import Pool
10
10
  from functools import partial
11
11
  from tglc.target_lightcurve import epsf
12
- from tglc.ffi_cut import ffi_cut
12
+ from tglc.ffi_cut import ffi_cut, _dot_wait
13
13
  from astroquery.mast import Catalogs
14
14
  import astropy.units as u
15
15
  from astropy.coordinates import SkyCoord
16
16
  from astroquery.mast import Tesscut
17
+ import sys
18
+ import warnings
19
+ import requests
20
+ import time
17
21
  # Tesscut._service_api_connection.TIMEOUT = 6000
18
-
19
22
  # warnings.simplefilter('ignore', UserWarning)
20
23
  from threadpoolctl import ThreadpoolController, threadpool_limits
21
24
  import numpy as np
22
25
  import seaborn as sns
23
26
  import itertools
27
+ from astropy import units
28
+ from astroquery.utils.tap.core import TapPlus
24
29
  controller = ThreadpoolController()
25
30
 
26
31
 
27
32
  @controller.wrap(limits=1, user_api='blas')
28
33
  def tglc_lc(target='TIC 264468702', local_directory='', size=90, save_aper=True, limit_mag=16, get_all_lc=False,
29
- first_sector_only=False, last_sector_only=False, sector=None, prior=None, transient=None):
34
+ first_sector_only=False, last_sector_only=False, sector=None, prior=None, transient=None, ffi='SPOC',
35
+ mast_timeout=3600):
30
36
  '''
31
37
  Generate light curve for a single target.
32
38
 
@@ -36,81 +42,152 @@ def tglc_lc(target='TIC 264468702', local_directory='', size=90, save_aper=True,
36
42
  :kind local_directory: str, required
37
43
  :param size: size of the FFI cut, default size is 90. Recommend large number for better quality. Cannot exceed 100.
38
44
  :kind size: int, optional
45
+ :param mast_timeout: timeout in seconds for MAST Tesscut requests
46
+ :kind mast_timeout: int, optional
39
47
  '''
40
48
  os.makedirs(local_directory + f'logs/', exist_ok=True)
41
49
  os.makedirs(local_directory + f'lc/', exist_ok=True)
42
50
  os.makedirs(local_directory + f'epsf/', exist_ok=True)
51
+ os.makedirs(local_directory + f'plots/', exist_ok=True)
43
52
  os.makedirs(local_directory + f'source/', exist_ok=True)
44
53
  print(f'Target: {target}')
45
- target_ = Catalogs.query_object(target, radius=42 * 0.707 / 3600, catalog="Gaia", version=2)
46
- if len(target_) == 0:
47
- target_ = Catalogs.query_object(target.name, radius=5 * 21 * 0.707 / 3600, catalog="Gaia", version=2)
54
+ if ffi.upper() == 'TICA':
55
+ warnings.warn('TICA support is experimental; Tesscut product availability may be limited.')
56
+
57
+ def _parse_tic_id(t):
58
+ if not isinstance(t, str):
59
+ return None
60
+ s = t.strip()
61
+ if s.upper().startswith('TIC'):
62
+ parts = s.split()
63
+ if len(parts) > 1 and parts[1].isdigit():
64
+ return int(parts[1])
65
+ s = s[3:].strip()
66
+ return int(s) if s.isdigit() else None
67
+ def _is_tic_id(t):
68
+ if not isinstance(t, str):
69
+ return False
70
+ s = t.strip()
71
+ return s.upper().startswith('TIC') or s.isdigit()
72
+
73
+ radius_deg = 42 * 0.707 / 3600
74
+ target_ = None
75
+ is_tic = _is_tic_id(target) and _parse_tic_id(target) is not None
76
+ try:
77
+ target_ = Catalogs.query_object(target, radius=radius_deg, catalog="Gaia", version=2)
78
+ except requests.exceptions.RequestException as e:
79
+ warnings.warn(f'MAST name lookup failed for "{target}": {e}')
80
+
81
+ if target_ is None or len(target_) == 0:
82
+ if is_tic:
83
+ raise RuntimeError(
84
+ f'MAST name lookup failed for TIC target "{target}". Please retry when MAST is available.'
85
+ )
86
+ try:
87
+ if not isinstance(target, str):
88
+ target_ = Catalogs.query_object(target.name, radius=5 * 21 * 0.707 / 3600, catalog="Gaia", version=2)
89
+ except Exception as e:
90
+ warnings.warn(f'MAST name lookup (target.name) failed: {e}')
91
+
92
+ if target_ is None or len(target_) == 0:
93
+ raise RuntimeError(
94
+ f'Unable to resolve target "{target}". MAST name lookup appears unavailable; '
95
+ f'try passing RA/Dec or a different target.'
96
+ )
97
+
48
98
  ra = target_[0]['ra']
49
99
  dec = target_[0]['dec']
50
100
  coord = SkyCoord(ra=ra, dec=dec, unit=(u.degree, u.degree), frame='icrs')
51
101
  sector_table = Tesscut.get_sectors(coordinates=coord)
52
102
  print(sector_table)
103
+ print(f'Found {len(sector_table)} sector(s) for this target.')
53
104
  if get_all_lc:
54
105
  name = None
55
106
  else:
56
- catalogdata = Catalogs.query_object(str(target), radius=0.02, catalog="TIC")
57
- if target[0:3] == 'TIC':
58
- name = int(target[4:])
107
+ if is_tic:
108
+ TIC_ID = int(target.strip().split()[-1])
109
+ with _dot_wait('Resolving TIC -> Gaia DR3 designation via TAP'):
110
+ ticvals = Catalogs.query_object(
111
+ f'TIC {TIC_ID}',
112
+ radius=3.0 * units.arcsec.to('degree'),
113
+ catalog="tic"
114
+ ).to_pandas()
115
+ if ticvals.shape[0] > 1:
116
+ ticvals = ticvals[ticvals.ID.astype(int).isin([TIC_ID])].reset_index(drop=True)
117
+ tmpgaiavals = TapPlus(url="https://gea.esac.esa.int/tap-server/tap").launch_job(
118
+ "SELECT TOP 1 * FROM gaiadr3.dr2_neighbourhood WHERE dr2_source_id = {}".format(
119
+ ticvals.loc[0, 'GAIA'])).get_results().to_pandas()
120
+ gaiavals = TapPlus(url="https://gea.esac.esa.int/tap-server/tap").launch_job(
121
+ "SELECT TOP 1 * FROM gaiadr3.gaia_source WHERE source_id = {}".format(
122
+ tmpgaiavals.loc[0, 'dr3_source_id'])).get_results().to_pandas()
123
+ dr2_id = tmpgaiavals.loc[0, 'dr2_source_id']
124
+ dr3_designation = gaiavals.loc[0, 'designation'.upper()]
125
+ print(f'DR2 source_id: {dr2_id}; DR3 designation: {dr3_designation}')
126
+ name = f'{dr3_designation}'
59
127
  elif transient is not None:
60
128
  name = transient[0]
61
129
  else:
130
+ try:
131
+ catalogdata = Catalogs.query_object(str(target), radius=0.02, catalog="TIC")
132
+ except requests.exceptions.RequestException as e:
133
+ raise RuntimeError(f'MAST name lookup failed for "{target}": {e}')
62
134
  name = int(np.array(catalogdata['ID'])[0])
63
135
  print("Since the provided target is not TIC ID, the resulted light curve with get_all_lc=False can not be "
64
136
  "guaranteed to be the target's light curve. Please check the TIC ID of the output file before using "
65
137
  "the light curve or try use TIC ID as the target in the format of 'TIC 12345678'.")
66
138
  if type(sector) == int:
67
139
  print(f'Only processing Sector {sector}.')
68
- print('Downloading Data from MAST and Gaia ...')
140
+ print('Downloading data from MAST and Gaia.')
141
+ print(f'MAST Tesscut timeout set to {mast_timeout}s.')
69
142
  source = ffi_cut(target=target, size=size, local_directory=local_directory, sector=sector,
70
- limit_mag=limit_mag, transient=transient) # sector
143
+ limit_mag=limit_mag, transient=transient, ffi=ffi, mast_timeout=mast_timeout) # sector
71
144
  source.select_sector(sector=sector)
72
145
  epsf(source, factor=2, sector=source.sector, target=target, local_directory=local_directory,
73
- name=name, limit_mag=limit_mag, save_aper=save_aper, prior=prior)
146
+ name=name, limit_mag=limit_mag, save_aper=save_aper, prior=prior, ffi=ffi)
74
147
  elif first_sector_only:
75
148
  print(f'Only processing the first sector the target is observed in: Sector {sector_table["sector"][0]}.')
76
- print('Downloading Data from MAST and Gaia ...')
149
+ print('Downloading data from MAST and Gaia.')
150
+ print(f'MAST Tesscut timeout set to {mast_timeout}s.')
77
151
  sector = sector_table["sector"][0]
78
152
  source = ffi_cut(target=target, size=size, local_directory=local_directory, sector=sector,
79
- limit_mag=limit_mag, transient=transient) # sector
153
+ limit_mag=limit_mag, transient=transient, ffi=ffi, mast_timeout=mast_timeout) # sector
80
154
  source.select_sector(sector=source.sector_table['sector'][0])
81
155
  epsf(source, factor=2, sector=source.sector, target=target, local_directory=local_directory,
82
- name=name, limit_mag=limit_mag, save_aper=save_aper, prior=prior)
156
+ name=name, limit_mag=limit_mag, save_aper=save_aper, prior=prior, ffi=ffi)
83
157
  elif last_sector_only:
84
158
  print(f'Only processing the last sector the target is observed in: Sector {sector_table["sector"][-1]}.')
85
- print('Downloading Data from MAST and Gaia ...')
159
+ print('Downloading data from MAST and Gaia.')
160
+ print(f'MAST Tesscut timeout set to {mast_timeout}s.')
86
161
  sector = sector_table["sector"][-1]
87
162
  source = ffi_cut(target=target, size=size, local_directory=local_directory, sector=sector,
88
- limit_mag=limit_mag, transient=transient) # sector
163
+ limit_mag=limit_mag, transient=transient, ffi=ffi, mast_timeout=mast_timeout) # sector
89
164
  source.select_sector(sector=source.sector_table['sector'][-1])
90
165
  epsf(source, factor=2, sector=source.sector, target=target, local_directory=local_directory,
91
- name=name, limit_mag=limit_mag, save_aper=save_aper, prior=prior)
166
+ name=name, limit_mag=limit_mag, save_aper=save_aper, prior=prior, ffi=ffi)
92
167
  elif sector == None:
93
168
  print(f'Processing all available sectors of the target.')
94
- print('Downloading Data from MAST and Gaia ...')
169
+ print('Downloading data from MAST and Gaia.')
170
+ print(f'MAST Tesscut timeout set to {mast_timeout}s.')
95
171
  for j in range(len(sector_table)):
96
172
  print(f'################################################')
97
- print(f'Downloading Sector {sector_table["sector"][j]}.')
173
+ print(f'Downloading Sector {sector_table["sector"][j]} (product={ffi}).')
98
174
  source = ffi_cut(target=target, size=size, local_directory=local_directory,
99
175
  sector=sector_table['sector'][j],
100
- limit_mag=limit_mag, transient=transient)
176
+ limit_mag=limit_mag, transient=transient, ffi=ffi, mast_timeout=mast_timeout)
101
177
  epsf(source, factor=2, sector=source.sector, target=target, local_directory=local_directory,
102
- name=name, limit_mag=limit_mag, save_aper=save_aper, prior=prior)
178
+ name=name, limit_mag=limit_mag, save_aper=save_aper, prior=prior, ffi=ffi)
103
179
  else:
104
180
  print(
105
181
  f'Processing all available sectors of the target in a single run. Note that if the number of sectors is '
106
182
  f'large, the download might cause a timeout error from MAST.')
107
- print('Downloading Data from MAST and Gaia ...')
183
+ print('Downloading data from MAST and Gaia.')
184
+ print(f'MAST Tesscut timeout set to {mast_timeout}s.')
108
185
  source = ffi_cut(target=target, size=size, local_directory=local_directory, sector=sector,
109
- limit_mag=limit_mag, transient=transient) # sector
186
+ limit_mag=limit_mag, transient=transient, ffi=ffi, mast_timeout=mast_timeout) # sector
110
187
  for j in range(len(source.sector_table)):
111
188
  source.select_sector(sector=source.sector_table['sector'][j])
112
189
  epsf(source, factor=2, sector=source.sector, target=target, local_directory=local_directory,
113
- name=name, limit_mag=limit_mag, save_aper=save_aper, prior=prior)
190
+ name=name, limit_mag=limit_mag, save_aper=save_aper, prior=prior, ffi=ffi)
114
191
 
115
192
 
116
193
  def search_stars(i, sector=1, tics=None, local_directory=None):
@@ -222,83 +299,123 @@ def plot_aperture(local_directory=None, kind='cal_aper_flux'):
222
299
  ])
223
300
  data = np.append(data, data_, axis=1)
224
301
  np.savetxt(f'{local_directory}TESS_TOI-5344_5_5_aper.csv', data, delimiter=',')
225
-
226
-
227
- def plot_pf_lc(local_directory=None, period=None, mid_transit_tbjd=None, kind='cal_aper_flux'):
228
- files = glob(f'{local_directory}*.fits')
302
+ def _phase_centered(t, period, t0):
303
+ # phase in [-0.5, 0.5)
304
+ return ((t - t0)/period + 0.5) % 1.0 - 0.5
305
+
306
+ def phasebin_centered(time, meas, meas_err, period, t0, binsize_days=None, nbins=None):
307
+ phase = _phase_centered(time, period, t0)
308
+
309
+ if nbins is None:
310
+ if binsize_days is None:
311
+ raise ValueError("Provide binsize_days (days) or nbins.")
312
+ bw = binsize_days / period
313
+ nbins = max(1, int(np.floor(1.0 / bw))) # at least one bin
314
+
315
+ edges = np.linspace(-0.5, 0.5, nbins + 1)
316
+ centers = 0.5 * (edges[:-1] + edges[1:])
317
+
318
+ # Bin index for each point
319
+ idx = np.digitize(phase, edges) - 1
320
+ valid = (idx >= 0) & (idx < nbins) & np.isfinite(meas) & np.isfinite(meas_err)
321
+
322
+ # Build weights; if all invalid or <=0, fall back to unweighted
323
+ w = np.zeros_like(meas, dtype=float)
324
+ with np.errstate(divide="ignore", invalid="ignore"):
325
+ w = 1.0 / np.square(meas_err)
326
+ badw = ~np.isfinite(w) | (w <= 0)
327
+ if np.all(~valid) or np.all(badw[valid]):
328
+ # fallback to ones for all finite measurements
329
+ valid = (idx >= 0) & (idx < nbins) & np.isfinite(meas)
330
+ w = np.ones_like(meas, dtype=float)
331
+
332
+ # Apply validity mask
333
+ idx_v = idx[valid]
334
+ w_v = w[valid]
335
+ y_v = meas[valid]
336
+
337
+ # Accumulate per-bin sums
338
+ wsum = np.bincount(idx_v, weights=w_v, minlength=nbins)
339
+ ysum = np.bincount(idx_v, weights=w_v * y_v, minlength=nbins)
340
+
341
+ # Bin mean and error (1/sqrt(sum of weights)); if unweighted, this becomes 1/sqrt(N)
342
+ y = np.divide(ysum, wsum, out=np.full(nbins, np.nan), where=wsum > 0)
343
+ yerr = np.divide(1.0, np.sqrt(wsum), out=np.full(nbins, np.nan), where=wsum > 0)
344
+
345
+ m = wsum > 0
346
+ return centers[m], y[m], yerr[m]
347
+
348
+ def plot_pf_lc(local_directory=None, period=None, mid_transit_tbjd=None, kind='cal_aper_flux',
349
+ binsize_days=60/86400, nbins=None):
350
+ files = sorted(glob(f'{local_directory}*.fits'))
229
351
  os.makedirs(f'{local_directory}plots/', exist_ok=True)
352
+
230
353
  fig = plt.figure(figsize=(13, 5))
231
- t_all = np.array([])
232
- f_all = np.array([])
233
- f_err_all = np.array([])
234
- for j in range(len(files)):
235
- not_plotted_num = 0
236
- with fits.open(files[j], mode='denywrite') as hdul:
237
- q = [a and b for a, b in
238
- zip(list(hdul[1].data['TESS_flags'] == 0), list(hdul[1].data['TGLC_flags'] == 0))]
239
- # q = [a and b for a, b in zip(q, list(hdul[1].data[kind] > 0.85))]
240
- # if hdul[0].header['sector'] == 15:
241
- # q = [a and b for a, b in zip(q, list(hdul[1].data['time'] < 1736))]
242
- if len(hdul[1].data['cal_aper_flux']) == len(hdul[1].data['time']):
243
- if hdul[0].header["SECTOR"] <= 26:
244
- t = hdul[1].data['time'][q]
245
- f = hdul[1].data[kind][q]
246
- elif hdul[0].header["SECTOR"] <= 55:
247
- t = np.mean(hdul[1].data['time'][q][:len(hdul[1].data['time'][q]) // 3 * 3].reshape(-1, 3), axis=1)
248
- f = np.mean(
249
- hdul[1].data[kind][q][:len(hdul[1].data[kind][q]) // 3 * 3].reshape(-1, 3), axis=1)
250
- else:
251
- t = np.mean(hdul[1].data['time'][q][:len(hdul[1].data['time'][q]) // 9 * 9].reshape(-1, 9), axis=1)
252
- f = np.mean(
253
- hdul[1].data[kind][q][:len(hdul[1].data[kind][q]) // 9 * 9].reshape(-1, 9), axis=1)
254
- t_all = np.append(t_all, t)
255
- f_all = np.append(f_all, f)
256
- f_err_all = np.append(f_err_all, np.array([hdul[1].header['CAPE_ERR']] * len(t)))
257
-
258
- # plt.plot(hdul[1].data['time'] % period / period, hdul[1].data[kind], '.', c='silver', ms=3)
259
- plt.errorbar(t % period / period, f, hdul[1].header['CAPE_ERR'], c='silver', ls='', elinewidth=0.1,
260
- marker='.', ms=3, zorder=2)
261
- # time_out, meas_out, meas_err_out = timebin(time=t % period, meas=f,
262
- # meas_err=np.array([hdul[1].header['CAPE_ERR']] * len(t)),
263
- # binsize=600 / 86400)
264
- # plt.errorbar(np.array(time_out) / period, meas_out, meas_err_out, c=f'C{j}', ls='', elinewidth=1.5,
265
- # marker='.', ms=8, zorder=3, label=f'Sector {hdul[0].header["sector"]}')
266
- else:
267
- not_plotted_num += 1
268
- title = f'TIC_{hdul[0].header["TICID"]} with {len(files) - not_plotted_num} sector(s) of data, {kind}'
269
- # PDCSAP_files = glob('/home/tehan/Documents/GEMS/TIC 172370679/PDCSAP/*.txt')
270
- # for i in range(len(files)):
271
- # PDCSAP = ascii.read(PDCSAP_files[i])
272
- # t = np.mean(PDCSAP['col1'][:len(PDCSAP['col1']) // 15 * 15].reshape(-1, 15), axis=1)
273
- # f = np.mean(PDCSAP['col2'][:len(PDCSAP['col2']) // 15 * 15].reshape(-1, 15), axis=1)
274
- # ferr = np.mean(PDCSAP['col3'][:len(PDCSAP['col3']) // 15 * 15].reshape(-1, 15), axis=1)
275
- # plt.errorbar((t - 2457000) % period / period, f, ferr, c='C0', ls='', elinewidth=0, marker='.', ms=2, zorder=1)
276
- time_out, meas_out, meas_err_out = timebin(time=t_all % period, meas=f_all,
277
- meas_err=f_err_all,
278
- binsize=300 / 86400)
279
- plt.errorbar(np.array(time_out) / period, meas_out, meas_err_out, c=f'r', ls='', elinewidth=1.5,
280
- marker='.', ms=8, zorder=3, label=f'All sectors')
281
-
282
- plt.ylim(0.998, 1.001)
283
- # plt.xlim(0.3, 0.43)
354
+ t_all = []
355
+ f_all = []
356
+ f_err_all = []
357
+ ticid = None
358
+ n_used = 0
359
+
360
+ for path in files:
361
+ with fits.open(path, mode='denywrite') as hdul:
362
+ hdr = hdul[0].header
363
+ dat = hdul[1].data
364
+ ticid = hdr.get("TICID", ticid)
365
+
366
+ # Good-time mask
367
+ q = (dat['TESS_flags'] == 0) & (dat['TGLC_flags'] == 0)
368
+
369
+ if len(dat[kind]) == len(dat['time']):
370
+ t = dat['time'][q]
371
+ f = dat[kind][q]
372
+ ferr = np.full(len(t), hdul[1].header['CAPE_ERR'], dtype=float)
373
+
374
+ # Scatter (phase-folded, centered on mid-transit)
375
+ ph = _phase_centered(t, period, mid_transit_tbjd)
376
+ # plt.errorbar(ph, f, ferr, c='silver', ls='', elinewidth=0.1,
377
+ # marker='.', ms=3, zorder=2)
378
+ plt.scatter(ph, f, c='silver', s=20, marker='.', zorder=2) # s ~ ms^2
379
+ t_all.append(t); f_all.append(f); f_err_all.append(ferr)
380
+ n_used += 1
381
+
382
+ if n_used == 0:
383
+ plt.close(fig)
384
+ raise RuntimeError("No valid data to plot.")
385
+
386
+ t_all = np.concatenate(t_all)
387
+ f_all = np.concatenate(f_all)
388
+ f_err_all = np.concatenate(f_err_all)
389
+ print(f_err_all)
390
+ # Phase-bin AFTER fold
391
+ ph_c, f_c, f_cerr = phasebin_centered(
392
+ time=t_all, meas=f_all, meas_err=f_err_all,
393
+ period=period, t0=mid_transit_tbjd,
394
+ binsize_days=binsize_days, nbins=nbins
395
+ )
396
+ plt.errorbar(ph_c, f_c, f_cerr, c='r', ls='', elinewidth=1.5,
397
+ marker='.', ms=8, zorder=3, label='All sectors (binned)')
398
+ plt.ylim(0., 2.)
284
399
  plt.legend()
400
+ title = f'TIC_{ticid} with {n_used} sector(s) of data, {kind}'
285
401
  plt.title(title)
286
- # plt.xlim(mid_transit_tbjd % period - 0.1 * period, mid_transit_tbjd % period + 0.1 * period)
287
- # plt.ylim(0.9, 1.1)
288
- # plt.hlines(y=0.92, xmin=0, xmax=1, ls='dotted', colors='k')
289
- # plt.hlines(y=0.93, xmin=0, xmax=1, ls='dotted', colors='k')
290
- plt.vlines(x=(mid_transit_tbjd % period), ymin=0, ymax=2, ls='dotted', colors='grey')
291
- plt.xlabel('Phase')
402
+
403
+ # Zoom ±1% of period around transit (now at phase 0)
404
+ dphi = 0.05 # = 1% of phase since centered
405
+ plt.xlim(-dphi, dphi)
406
+ plt.vlines(x=0.0, ymin=0, ymax=2, ls='dotted', colors='grey')
407
+
408
+ plt.xlabel('Phase (centered at mid-transit)')
292
409
  plt.ylabel('Normalized flux')
410
+ plt.tight_layout()
293
411
  plt.savefig(f'{local_directory}/plots/{title}.png', dpi=300)
294
412
  plt.close(fig)
295
413
 
296
-
297
- def plot_contamination(local_directory=None, gaia_dr3=None, ymin=None, ymax=None, pm_years=3000):
414
+ # newest
415
+ def plot_contamination(local_directory=None, gaia_dr3=None, ymin=None, ymax=None, pm_years=3000, detrend=True):
298
416
  sns.set(rc={'font.family': 'serif', 'font.serif': 'DejaVu Serif', 'font.size': 12,
299
417
  'axes.edgecolor': '0.2', 'axes.labelcolor': '0.', 'xtick.color': '0.', 'ytick.color': '0.',
300
- 'axes.facecolor': '0.95', "axes.grid": False})
301
-
418
+ 'axes.facecolor': '0.95', 'grid.color': '0.9'})
302
419
  files = glob(f'{local_directory}lc/*{gaia_dr3}*.fits')
303
420
  os.makedirs(f'{local_directory}plots/', exist_ok=True)
304
421
  for i in range(len(files)):
@@ -327,10 +444,10 @@ def plot_contamination(local_directory=None, gaia_dr3=None, ymin=None, ymax=None
327
444
  np.nanmedian(
328
445
  source.flux[:, round(star_y) - 2:round(star_y) + 3, round(star_x) - 2:round(star_x) + 3],
329
446
  axis=0))
330
- fig = plt.figure(constrained_layout=False, figsize=(20, 12))
447
+ fig = plt.figure(constrained_layout=False, figsize=(15, 9))
331
448
  gs = fig.add_gridspec(21, 10)
332
- gs.update(wspace=0.03, hspace=0.1)
333
- ax0 = fig.add_subplot(gs[:10, :3])
449
+ gs.update(wspace=0.05, hspace=0.15)
450
+ ax0 = fig.add_subplot(gs[:9, :3])
334
451
  ax0.imshow(np.median(source.flux, axis=0), cmap='RdBu', vmin=-max_flux, vmax=max_flux, origin='lower')
335
452
  ax0.set_xlabel('x pixel')
336
453
  ax0.set_ylabel('y pixel')
@@ -340,7 +457,7 @@ def plot_contamination(local_directory=None, gaia_dr3=None, ymin=None, ymax=None
340
457
  ax0.scatter(source.gaia[f'sector_{sector}_x'][nearby_stars[nearby_stars != star_num[0][0]]],
341
458
  source.gaia[f'sector_{sector}_y'][nearby_stars[nearby_stars != star_num[0][0]]],
342
459
  s=30, c='r', edgecolor='black', linewidth=1, label='background stars')
343
-
460
+ ax0.grid(False)
344
461
  for l in range(len(nearby_stars)):
345
462
  index = np.where(
346
463
  source.tic['dr3_source_id'] == int(source.gaia['DESIGNATION'][nearby_stars[l]].split(' ')[-1]))
@@ -380,25 +497,28 @@ def plot_contamination(local_directory=None, gaia_dr3=None, ymin=None, ymax=None
380
497
  ax0.vlines(round(star_x) + 2.5, round(star_y) - 2.5, round(star_y) + 2.5, colors='k', lw=1.2)
381
498
  ax0.hlines(round(star_y) - 2.5, round(star_x) - 2.5, round(star_x) + 2.5, colors='k', lw=1.2)
382
499
  ax0.hlines(round(star_y) + 2.5, round(star_x) - 2.5, round(star_x) + 2.5, colors='k', lw=1.2)
383
- t_, y_, x_ = np.shape(hdul[0].data)
500
+ try:
501
+ t_, y_, x_ = np.shape(hdul[0].data)
502
+ except ValueError:
503
+ warnings.warn('Light curves need to have the primary hdu. Set save_aperture=True when producing the light curve to enable this plot.')
504
+ sys.exit()
384
505
  max_flux = np.max(
385
506
  np.median(source.flux[:, int(star_y) - 2:int(star_y) + 3, int(star_x) - 2:int(star_x) + 3], axis=0))
386
- sns.set(rc={'font.family': 'serif', 'font.serif': 'DejaVu Serif', 'font.size': 12,
387
- 'axes.edgecolor': '0.2', 'axes.labelcolor': '0.', 'xtick.color': '0.', 'ytick.color': '0.',
388
- 'axes.facecolor': '0.95', 'grid.color': '0.9'})
389
507
  arrays = []
390
508
  for j in range(y_):
391
509
  for k in range(x_):
392
510
  ax_ = fig.add_subplot(gs[(19 - 2 * j):(21 - 2 * j), (2 * k):(2 + 2 * k)])
393
511
  ax_.patch.set_facecolor('#4682B4')
394
512
  ax_.patch.set_alpha(min(1, max(0, 5 * np.nanmedian(hdul[0].data[:, j, k]) / max_flux)))
395
-
396
- _, trend = flatten(hdul[1].data['time'][q],
397
- hdul[0].data[:, j, k][q] - np.nanmin(hdul[0].data[:, j, k][q]) + 1000,
398
- window_length=1, method='biweight', return_trend=True)
399
- cal_aper = (hdul[0].data[:, j, k][q] - np.nanmin(
400
- hdul[0].data[:, j, k][q]) + 1000 - trend) / np.nanmedian(
401
- hdul[0].data[:, j, k][q]) + 1
513
+ if detrend:
514
+ _, trend = flatten(hdul[1].data['time'][q],
515
+ hdul[0].data[:, j, k][q] - np.nanmin(hdul[0].data[:, j, k][q]) + 1000,
516
+ window_length=1, method='biweight', return_trend=True)
517
+ cal_aper = (hdul[0].data[:, j, k][q] - np.nanmin(
518
+ hdul[0].data[:, j, k][q]) + 1000 - trend) / np.nanmedian(
519
+ hdul[0].data[:, j, k][q]) + 1
520
+ else:
521
+ cal_aper = (hdul[0].data[:, j, k][q]) / np.nanmedian(hdul[0].data[:, j, k][q])
402
522
  if 1 <= j <= 3 and 1 <= k <= 3:
403
523
  arrays.append(cal_aper)
404
524
  ax_.plot(hdul[1].data['time'][q], cal_aper, '.k', ms=0.5)
@@ -425,13 +545,13 @@ def plot_contamination(local_directory=None, gaia_dr3=None, ymin=None, ymax=None
425
545
  print(f"Interquartile Range (IQR): {iqr}")
426
546
  std_dev = np.std(median_abs_diffs)
427
547
  print(f"Standard Deviation: {std_dev}")
428
- ax1 = fig.add_subplot(gs[:10, 4:7])
548
+ ax1 = fig.add_subplot(gs[:9, 3:6])
429
549
  ax1.hist(median_abs_diffs, color='k', edgecolor='k', facecolor='none', rwidth=0.8, linewidth=2)
430
550
  ax1.set_box_aspect(1)
431
- ax1.set_title(f'Distribution of the MADs among combinations of the center 3*3 pixels')
432
- ax1.set_xlabel('MAD between combinations of center 3*3 pixel fluxes')
551
+ # ax1.set_title(f'Distribution of the MADs among combinations of the center 3*3 pixels')
552
+ ax1.set_xlabel('MAD between combinations of fluxes')
433
553
  ax1.set_ylabel('Counts')
434
- text_ax = fig.add_axes([0.71, 0.9, 0.3, 0.3]) # [left, bottom, width, height] in figure coordinates
554
+ text_ax = fig.add_axes([0.6, 0.95, 0.3, 0.3]) # [left, bottom, width, height] in figure coordinates
435
555
  text_ax.axis('off') # Turn off axis lines, ticks, etc.
436
556
  text_ax.text(0., 0., f"Gaia DR3 {gaia_dr3} \n"
437
557
  f" ←← TESS SPOC FFI and TIC/Gaia stars with proper motions. \n"
@@ -440,7 +560,6 @@ def plot_contamination(local_directory=None, gaia_dr3=None, ymin=None, ymax=None
440
560
  f" ↓ Fluxes of each pixels after contaminations are removed. \n"
441
561
  f" The fluxes are normalized and detrended. The background \n"
442
562
  f" color shows the pixel brightness after the decontamination. \n"
443
- f"\n"
444
563
  f"How to interpret these plots: \n"
445
564
  f" If the signals you are interested in (i.e. transits, \n"
446
565
  f" eclipses, variable stars) show similar amplitudes in \n"
@@ -455,15 +574,14 @@ def plot_contamination(local_directory=None, gaia_dr3=None, ymin=None, ymax=None
455
574
  f"Interquartile Range (IQR): {iqr:05f} \n"
456
575
  f"Standard Deviation: {std_dev:05f}", transform=text_ax.transAxes, ha='left',
457
576
  va='top')
458
- plt.subplots_adjust(top=.98, bottom=0.05, left=0.05, right=0.95)
577
+ plt.subplots_adjust(top=.97, bottom=0.06, left=0.05, right=0.95)
459
578
  plt.savefig(
460
579
  f'{local_directory}plots/contamination_sector_{hdul[0].header["SECTOR"]:04d}_Gaia_DR3_{gaia_dr3}.pdf',
461
- dpi=300)
580
+ dpi=300,)
462
581
  # plt.savefig(f'{local_directory}plots/contamination_sector_{hdul[0].header["SECTOR"]:04d}_Gaia_DR3_{gaia_dr3}.png',
463
582
  # dpi=600)
464
583
  plt.close()
465
584
 
466
-
467
585
  def plot_epsf(local_directory=None):
468
586
  files = glob(f'{local_directory}epsf/*.npy')
469
587
  os.makedirs(f'{local_directory}plots/', exist_ok=True)
@@ -497,7 +615,7 @@ def choose_prior(tics, local_directory=None, priors=np.logspace(-5, 0, 100)):
497
615
  # plt.show()
498
616
 
499
617
 
500
- def get_tglc_lc(tics=None, method='query', server=1, directory=None, prior=None):
618
+ def get_tglc_lc(tics=None, method='query', server=1, directory=None, prior=None, ffi='SPOC', mast_timeout=3600):
501
619
  if method == 'query':
502
620
  for i in range(len(tics)):
503
621
  target = f'TIC {tics[i]}'
@@ -505,22 +623,23 @@ def get_tglc_lc(tics=None, method='query', server=1, directory=None, prior=None)
505
623
  os.makedirs(local_directory, exist_ok=True)
506
624
  tglc_lc(target=target, local_directory=local_directory, size=90, save_aper=True, limit_mag=16,
507
625
  get_all_lc=False, first_sector_only=False, last_sector_only=False, sector=None, prior=prior,
508
- transient=None)
509
- plot_lc(local_directory=f'{directory}TIC {tics[i]}/', kind='cal_aper_flux')
626
+ transient=None, ffi=ffi, mast_timeout=mast_timeout)
627
+ plot_lc(local_directory=f'{directory}TIC {tics[i]}/', kind='cal_aper_flux', ffi=ffi)
510
628
  if method == 'search':
511
629
  star_spliter(server=server, tics=tics, local_directory=directory)
512
630
 
513
631
 
514
632
  if __name__ == '__main__':
515
- tics = [16005254]
516
- directory = f'/home/tehan/data/'
633
+ tics = [16005254] # can be a list of TIC IDs
634
+ directory = f'/Users/tehan/Downloads/'
635
+ # directory = f'/home/tehan/data/WD/'
517
636
  os.makedirs(directory, exist_ok=True)
518
- get_tglc_lc(tics=tics, method='query', server=1, directory=directory)
637
+ get_tglc_lc(tics=tics, directory=directory, ffi='SPOC')
519
638
  # plot_lc(local_directory=f'{directory}TIC {tics[0]}/', kind='cal_aper_flux')
520
639
  # plot_lc(local_directory=f'/home/tehan/Documents/tglc/TIC 16005254/', kind='cal_aper_flux', ylow=0.9, yhigh=1.1)
521
640
  # plot_contamination(local_directory=f'{directory}TIC {tics[0]}/', gaia_dr3=5751990597042725632)
522
641
  # plot_epsf(local_directory=f'{directory}TIC {tics[0]}/')
523
- # plot_pf_lc(local_directory=f'{directory}TIC {tics[0]}/lc/', period=0.71912603, mid_transit_tbjd=2790.58344,
524
- # kind='cal_psf_flux')
642
+ plot_pf_lc(local_directory=f'{directory}TIC {tics[0]}/lc/', period=1.4079405, mid_transit_tbjd=1779.3750828,
643
+ kind='cal_aper_flux')
525
644
  # plot_pf_lc(local_directory=f'{directory}TIC {tics[0]}/lc/', period=0.23818244, mid_transit_tbjd=1738.71248,
526
- # kind='cal_aper_flux')
645
+ # kind='cal_aper_flux')