diff --git a/MANIFEST.in b/MANIFEST.in index 3fd346e..85c57a5 100755 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,4 @@ include README.md LICENSE include tessreduce/tess_straps.csv -include tessreduce/calspec_mags.npy include tessreduce/Tonry_splines.txt include tessreduce/SMspline.txt -include tessreduce/sector_mjd.csv diff --git a/README.md b/README.md index 30c547f..17c6e4b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![DOI](https://img.shields.io/badge/DOI-10.3847%2F1538--3881%2Fac2c2e-blue.svg)](https://doi.org/10.3847/1538-3881/ac2c2e) -![plot](./figs/header.png) +![plot](https://raw.githubusercontent.com/CheerfulUser/TESSreduce/main/figs/header.png) With this package that builds on lightkurve, you can reduce TESS data while preserving transient signals. You can supply a TPF or give coordinates and sector to construct a TPF with TESScut. The background subtraction accounts for the smooth background and detector straps. Alongisde background subtraction TESSreduce also aligns images, performs difference imaging, and can even detect transient events! @@ -29,7 +29,7 @@ obs = tr.sn_lookup('sn2018fub') ```python tess = tr.tessreduce(obs_list=obs) ``` -![plot](./figs/fub.png) +![plot](https://raw.githubusercontent.com/CheerfulUser/TESSreduce/main/figs/fub.png) **OR** ```python @@ -75,7 +75,7 @@ Several options are available for flux and are interchangeable, however, mag is ```python tess.plotter() ``` -![plot](./figs/fub_cal.png) +![plot](https://raw.githubusercontent.com/CheerfulUser/TESSreduce/main/figs/fub_cal.png) # Extracting key variables diff --git a/setup.py b/setup.py index 9f277f7..56ab907 100755 --- a/setup.py +++ b/setup.py @@ -38,7 +38,7 @@ 'sep', 'tqdm', 'alerce', - 'tess-point', + 'tesswcs>=1.8', 'tabulate', 'TESS_PRF'] @@ -137,9 +137,11 @@ def run(self): 'License :: OSI Approved :: MIT License', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: Implementation :: CPython', - 'Programming Language :: Python :: Implementation :: PyPy' ], # $ setup.py publish support. cmdclass={ diff --git a/tessreduce/#__init__.py# b/tessreduce/#__init__.py# deleted file mode 100755 index 0da3e83..0000000 --- a/tessreduce/#__init__.py# +++ /dev/null @@ -1 +0,0 @@ -from .tessreduce import * \ No newline at end of file diff --git a/tessreduce/helpers.py b/tessreduce/helpers.py index c911f85..57892c5 100644 --- a/tessreduce/helpers.py +++ b/tessreduce/helpers.py @@ -38,7 +38,7 @@ from photutils.detection import StarFinder from PRF import TESS_PRF -from tess_stars2px import tess_stars2px_function_entry as focal_plane +import tesswcs from tabulate import tabulate package_directory = os.path.dirname(os.path.abspath(__file__)) + '/' @@ -520,6 +520,62 @@ def grad_flux_rad(flux): return rad +def _tess_pointing_table(): + """ + Sector start/end times (MJD), sourced from tesswcs.pointings so the table + stays current with tesswcs releases rather than a file pinned in this repo. + + Returns + ------- + sec_times : pd.DataFrame + Indexed by Sector, with mjd_start and mjd_end columns. + """ + pointings = tesswcs.pointings.to_pandas()[['Sector','Start','End']] + pointings = pointings.rename(columns={'Start':'mjd_start','End':'mjd_end'}) + pointings['mjd_start'] = Time(pointings['mjd_start'].values,format='jd').mjd + pointings['mjd_end'] = Time(pointings['mjd_end'].values,format='jd').mjd + return pointings.set_index('Sector').sort_index() + + +def _target_sectors(ra,dec): + """ + Find which TESS sectors, cameras and CCDs observe a given coordinate. + Replaces tess_stars2px_function_entry (tess-point) with tesswcs, which + covers both archived and predicted sector pointings. + + Returns + ------- + outSecs, outCam, outCcd, outColPix, outRowPix : np.array + Sector number, camera, CCD, and pixel column/row for each match, + sorted by sector. + """ + import logging + coord = SkyCoord(ra,dec,unit='deg') + + level = tesswcs.log.level + tesswcs.log.setLevel(logging.ERROR) + secs, cams, ccds, cols, rows = [], [], [], [], [] + try: + for sector in tesswcs.pointings['Sector']: + sector = int(sector) + for camera in range(1,5): + for ccd in range(1,5): + try: + wcs = tesswcs.WCS.from_sector(sector,camera,ccd) + except ValueError: + continue + if wcs.footprint_contains(coord): + col, row = wcs.world_to_pixel(coord) + secs += [sector]; cams += [camera]; ccds += [ccd] + cols += [float(col)]; rows += [float(row)] + finally: + tesswcs.log.setLevel(level) + + order = np.argsort(secs) + return (np.array(secs)[order], np.array(cams)[order], np.array(ccds)[order], + np.array(cols)[order], np.array(rows)[order]) + + def sn_lookup(name,time='disc',buffer=0,print_table=True, df = False): """ Check for overlapping TESS ovservations for a transient. Uses the Open SNe Catalog for @@ -589,16 +645,15 @@ def sn_lookup(name,time='disc',buffer=0,print_table=True, df = False): ra = c.ra.deg dec = c.dec.deg - outID, outEclipLong, outEclipLat, outSecs, outCam, outCcd, outColPix, \ - outRowPix, scinfo = focal_plane(0, ra, dec) - - sec_times = pd.read_csv(package_directory + 'sector_mjd.csv') - if len(outSecs) > 0: - ind = outSecs - 1 + outSecs, outCam, outCcd, outColPix, outRowPix = _target_sectors(ra, dec) - new_ind = [i for i in ind if i < len(sec_times)] + sec_times = _tess_pointing_table() + if len(outSecs) > 0: + keep = np.isin(outSecs, sec_times.index) + outSecs, outCam, outCcd, outColPix, outRowPix = \ + outSecs[keep], outCam[keep], outCcd[keep], outColPix[keep], outRowPix[keep] - secs = sec_times.iloc[new_ind] + secs = sec_times.loc[outSecs].reset_index() if type(time) == str: if (time.lower() == 'disc') | (time.lower() == 'discovery'): disc_start = secs['mjd_start'].values - disc_t.mjd @@ -679,16 +734,15 @@ def spacetime_lookup(ra,dec,time=None,buffer=0,print_table=True, df = False, pri ra = c.ra.deg dec = c.dec.deg - outID, outEclipLong, outEclipLat, outSecs, outCam, outCcd, outColPix, \ - outRowPix, scinfo = focal_plane(0, ra, dec) - - sec_times = pd.read_csv(package_directory + 'sector_mjd.csv') - if len(outSecs) > 0: - ind = outSecs - 1 + outSecs, outCam, outCcd, outColPix, outRowPix = _target_sectors(ra, dec) - new_ind = [i for i in ind if i < len(sec_times)] + sec_times = _tess_pointing_table() + if len(outSecs) > 0: + keep = np.isin(outSecs, sec_times.index) + outSecs, outCam, outCcd, outColPix, outRowPix = \ + outSecs[keep], outCam[keep], outCcd[keep], outColPix[keep], outRowPix[keep] - secs = sec_times.iloc[new_ind] + secs = sec_times.loc[outSecs].reset_index() disc_start = secs['mjd_start'].values - time disc_end = secs['mjd_end'].values - time diff --git a/tessreduce/sector_mjd.csv b/tessreduce/sector_mjd.csv deleted file mode 100755 index 2ca36ed..0000000 --- a/tessreduce/sector_mjd.csv +++ /dev/null @@ -1,108 +0,0 @@ -Sector,mjd_start,mjd_end -1,58324.81597222222,58352.68402777778 -2,58353.60763888889,58381.020833333336 -3,58382.225694444445,58408.875 -4,58410.40625,58436.35763888889 -5,58437.48263888889,58463.79513888889 -6,58464.711805555555,58489.552083333336 -7,58491.131944444445,58515.59375 -8,58516.84722222222,58541.506944444445 -9,58542.72222222222,58567.98263888889 -10,58568.9375,58595.1875 -11,58596.27777777778,58623.399305555555 -12,58624.45486111111,58652.399305555555 -13,58653.42013888889,58681.864583333336 -14,58682.854166666664,58709.711805555555 -15,58710.864583333336,58736.916666666664 -16,58738.15277777778,58762.82638888889 -17,58764.18402777778,58789.20138888889 -18,58790.15625,58814.538194444445 -19,58815.583333333336,58840.65625 -20,58842.00347222222,58868.32986111111 -21,58869.93402777778,58897.288194444445 -22,58898.805555555555,58926.0 -23,58927.604166666664,58954.381944444445 -24,58955.29513888889,58981.788194444445 -25,58983.131944444445,59008.8125 -26,59009.76736111111,59034.64236111111 -27,59035.77777777778,59060.149305555555 -28,59061.350694444445,59086.604166666664 -29,59087.739583333336,59113.94097222222 -30,59115.385416666664,59142.729166666664 -31,59144.01388888889,59171.53472222222 -32,59172.572916666664,59199.739583333336 -33,59201.23263888889,59227.07986111111 -34,59228.25,59253.572916666664 -35,59254.489583333336,59279.48611111111 -36,59280.40277777778,59305.49652777778 -37,59306.739583333336,59332.086805555555 -38,59333.354166666664,59360.05902777778 -39,59361.270833333336,59389.225694444445 -40,59390.15277777778,59418.36111111111 -41,59419.489583333336,59446.086805555555 -42,59447.19097222222,59472.666666666664 -43,59473.666666666664,59498.395833333336 -44,59499.6875,59523.947916666664 -45,59525.006944444445,59550.131944444445 -46,59551.06597222222,59578.27777777778 -47,59579.302083333336,59606.447916666664 -48,59607.43402777778,59635.493055555555 -49,59636.97222222222,59663.822916666664 -50,59664.770833333336,59691.01736111111 -51,59692.447916666664,59717.041666666664 -52,59718.135416666664,59742.583333333336 -53,59743.49652777778,59768.48611111111 -54,59769.399305555555,59795.635416666664 -55,59796.600694444445,59823.770833333336 -56,59824.756944444445,59852.645833333336 -57,59852.854166666664,59881.62152777778 -58,59881.82986111111,59909.555555555555 -59,59909.76388888889,59936.194444444445 -60,59936.40277777778,59962.09027777778 -61,59962.29861111111,59987.73263888889 -62,59987.94097222222,60013.65972222222 -63,60013.868055555555,60040.40625 -64,60040.614583333336,60068.03125 -65,60068.239583333336,60096.96527777778 -66,60097.17361111111,60125.93402777778 -67,60126.14236111111,60153.90277777778 -68,60154.11111111111,60181.645833333336 -69,60181.854166666664,60207.645833333336 -70,60207.854166666664,60233.34375 -71,60233.53472222222,60259.475694444445 -72,60259.68402777778,60285.09027777778 -73,60285.29861111111,60312.15625 -74,60312.364583333336,60339.07638888889 -75,60339.28472222222,60366.989583333336 -76,60367.197916666664,60394.77777777778 -77,60394.98611111111,60423.055555555555 -78,60423.26388888889,60451.82986111111 -79,60452.038194444445,60479.180555555555 -80,60479.38888888889,60505.84375 -81,60506.052083333336,60532.68402777778 -82,60532.89236111111,60558.75347222222 -83,60558.927083333336,60583.881944444445 -84,60584.09027777778,60609.84722222222 -85,60610.055555555555,60635.552083333336 -86,60635.760416666664,60662.333333333336 -87,60662.541666666664,60689.444444444445 -88,60689.65277777778,60717.430555555555 -89,60717.63888888889,60746.45138888889 -90,60746.65972222222,60774.583333333336 -91,60774.791666666664,60802.26388888889 -92,60802.47222222222,60829.149305555555 -93,60829.35763888889,60855.555555555555 -94,60855.76388888889,60881.625 -95,60881.833333333336,60907.06597222222 -96,60907.274305555555,60932.95138888889 -97,60933.15972222222,60987.791666666664 -98,60988.0,61045.40625 -99,61045.614583333336,61073.28472222222 -100,61073.493055555555,61099.97222222222 -101,61100.180555555555,61126.3125 -102,61126.520833333336,61164.729166666664 -103,61164.9375,61177.87847222222 -104,61178.086805555555,61204.708333333336 -105,61204.916666666664,61232.72222222222 -106,61232.930555555555,61261.57638888889 -107,61261.78472222222,61290.28125 diff --git a/tessreduce/web path b/tessreduce/web path deleted file mode 100755 index 3b9d168..0000000 --- a/tessreduce/web path +++ /dev/null @@ -1,2 +0,0 @@ -web path -/grp/websites/stsci-transients.stsci.edu/ \ No newline at end of file diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 967fc99..4471309 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -22,6 +22,8 @@ smooth_zp, Smooth_bkg, regional_stats_mask, + _tess_pointing_table, + _target_sectors, ) @@ -315,5 +317,43 @@ def test_outlier_masked(self): self.assertTrue(mask[15, 15]) +class TestTessPointingTable(unittest.TestCase): + + def test_indexed_by_sector_with_expected_columns(self): + table = _tess_pointing_table() + self.assertEqual(table.index.name, 'Sector') + self.assertIn('mjd_start', table.columns) + self.assertIn('mjd_end', table.columns) + + def test_end_after_start(self): + table = _tess_pointing_table() + self.assertTrue((table['mjd_end'] > table['mjd_start']).all()) + + def test_known_sector_one_start_time(self): + # Sector 1 start is 2018-07-25 19:00 UT, JD 2458324.5 -> MJD 58324.0 + table = _tess_pointing_table() + self.assertAlmostEqual(table.loc[1, 'mjd_start'], 58324.0, places=3) + + +class TestTargetSectors(unittest.TestCase): + + def test_known_target_returns_expected_sectors(self): + # Reference target cross-checked against tess_stars2px_function_entry + # (tess-point) output: sectors 2, 29, 69, 96, 103, 104, 105, 106. + outSecs, outCam, outCcd, outColPix, outRowPix = _target_sectors(10.127, -50.687) + expected = {2, 29, 69, 96, 103, 104, 105, 106} + self.assertTrue(expected.issubset(set(outSecs.tolist()))) + + def test_arrays_aligned_and_sorted(self): + outSecs, outCam, outCcd, outColPix, outRowPix = _target_sectors(10.127, -50.687) + lengths = {len(outSecs), len(outCam), len(outCcd), len(outColPix), len(outRowPix)} + self.assertEqual(len(lengths), 1) + assert_array_equal(outSecs, np.sort(outSecs)) + + def test_pixel_coordinates_within_ccd_bounds(self): + outSecs, outCam, outCcd, outColPix, outRowPix = _target_sectors(10.127, -50.687) + self.assertTrue(np.all((outColPix >= 0) & (outColPix <= 2136))) + self.assertTrue(np.all((outRowPix >= 0) & (outRowPix <= 2078))) + if __name__ == '__main__': unittest.main()