diff --git a/src/lksearch/MASTSearch.py b/src/lksearch/MASTSearch.py index e2fcecd..b171186 100644 --- a/src/lksearch/MASTSearch.py +++ b/src/lksearch/MASTSearch.py @@ -106,7 +106,11 @@ def __init__( self.target = target - if isinstance(table, type(None)): + if ( + isinstance(table, type(None)) + and isinstance(obs_table, type(None)) + and isinstance(prod_table, type(None)) + ): self._searchtable_from_target(target) self.table = self._fix_table_times(self.table) @@ -320,15 +324,15 @@ def _searchtable_from_table( # see if function was passed a joint table if isinstance(table, pd.DataFrame): self.table = table - # If we don't have a name or a joint table, # check to see if tables were passed + elif isinstance(obs_table, pd.DataFrame): # If we have an obs table and no name, use it self.obs_table = obs_table if isinstance(prod_table, type(None)): # get the prod table if we don't have it - prod_table = self._search_products(self) + prod_table = self._search_prod() self.prod_table = prod_table self.table = self._join_tables() else: diff --git a/src/lksearch/TESSSearch.py b/src/lksearch/TESSSearch.py index bf4b672..6af5f7d 100644 --- a/src/lksearch/TESSSearch.py +++ b/src/lksearch/TESSSearch.py @@ -8,6 +8,7 @@ from astropy import units as u from astropy.coordinates import SkyCoord from astropy.time import Time +from astroquery.mast import MastClass # from astropy.utils.decorators import deprecated from astroquery.mast import Tesscut @@ -18,7 +19,7 @@ from .MASTSearch import MASTSearch from . import conf, config, log -from .utils import SearchDeprecationError +from .utils import SearchDeprecationError, table_keys PREFER_CLOUD = conf.PREFER_CLOUD DOWNLOAD_CLOUD = conf.DOWNLOAD_CLOUD @@ -88,6 +89,40 @@ def __init__( self.mission_search = ["TESS"] else: self.mission_search = ["TESS", "HLSP"] + if pipeline != None: + pipeline = np.atleast_1d(pipeline).tolist() + + # Sending 'tesscut' as a pipeline options returns a SearchError to the mast search + # If only tesscut is desired, we can just do the search on its own. + add_tesscut = True + if isinstance(pipeline, list): + if "tesscut" in [p.lower() for p in pipeline]: + # If only tesscut is requested, we can skip the regular MAST search + if [p.lower() for p in pipeline] == ["tesscut"]: + log.debug(f"Only performing TESScut search") + if isinstance(target, SkyCoord): + self.target_search_string = f"{target.ra.deg}, {target.dec.deg}" + self.SkyCoord = target + elif isinstance(target, tuple): + self.target_search_string = f"{target[0]}, {target[1]}" + self.SkyCoord = SkyCoord(*target, frame="icrs", unit="deg") + elif isinstance(target, str): + self.SkyCoord = MastClass().resolve_object(target) + self.target_search_string = ( + f"{self.SkyCoord.ra.deg}, {self.SkyCoord.dec.deg}" + ) + tcut = self._get_tesscut_info(sector_list=sector) + # Make a df with the same keys as would be returned by the MAST search + mask = [i not in tcut.keys() for i in table_keys] + empty_df = pd.DataFrame(columns=table_keys[mask]) + table = pd.concat([empty_df, tcut], axis=1) + add_tesscut = False + pipeline = np.delete( + pipeline, [p.lower() for p in pipeline].index("tesscut") + ) + else: + # If pipeline is a list without 'tesscut', don't add it. + add_tesscut = False super().__init__( target=target, @@ -101,11 +136,11 @@ def __init__( sequence=sector, ) - if table is None: - if ("TESScut" in np.atleast_1d(pipeline)) or (type(pipeline) is type(None)): - self._add_tesscut_products(sector) - self._add_TESS_mission_product() - self._sort_TESS() + if add_tesscut: + # Do not append tesscut products if pipeline = 'TESScut' (it's already been done!) + self._add_tesscut_products(sector) + self._add_TESS_mission_product() + self._sort_TESS() @property def HLSPs(self): @@ -144,7 +179,7 @@ def _target_to_exact_name(self, target): return f"{target.group(2)}" def _add_TESS_mission_product(self): - """Determine whick products are HLSPs and which are mission products""" + """Determine which products are HLSPs and which are mission products""" mission_product = np.zeros(len(self.table), dtype=bool) mission_product[self.table["pipeline"] == "SPOC"] = True self.table["mission_product"] = mission_product diff --git a/src/lksearch/utils.py b/src/lksearch/utils.py index 715484d..3365324 100644 --- a/src/lksearch/utils.py +++ b/src/lksearch/utils.py @@ -1,5 +1,6 @@ import os import sys +import numpy as np from functools import wraps from . import config @@ -37,3 +38,70 @@ def wrapper(*args, **kwargs): sys.stdout = old_out return wrapper + + +# List of keys in a search result table +table_keys = np.array( + [ + "intentType", + "obs_collection_obs", + "provenance_name", + "instrument_name", + "project_obs", + "filters_obs", + "wavelength_region", + "target_name", + "target_classification", + "obs_id", + "s_ra", + "s_dec", + "dataproduct_type_obs", + "proposal_pi", + "calib_level_obs", + "t_min", + "t_max", + "exptime", + "em_min", + "em_max", + "obs_title", + "t_obs_release", + "proposal_id_obs", + "proposal_type", + "sequence_number", + "s_region", + "jpegURL", + "dataURL", + "dataRights_obs", + "mtFlag", + "srcDen", + "obsid", + "objID", + "objID1", + "distance", + "obsID", + "obs_collection", + "dataproduct_type", + "description", + "type", + "dataURI", + "productType", + "productGroupDescription", + "productSubGroupDescription", + "productDocumentationURL", + "project", + "prvversion", + "proposal_id", + "productFilename", + "size", + "parent_obsid", + "dataRights", + "calib_level_prod", + "filters_prod", + "pipeline", + "mission", + "year", + "start_time", + "end_time", + "targetid", + ] +) diff --git a/tests/test_missionsearch.py b/tests/test_missionsearch.py index e926199..2c46c07 100644 --- a/tests/test_missionsearch.py +++ b/tests/test_missionsearch.py @@ -440,9 +440,12 @@ def test_FFI_retrieval(): def test_tesscut(): """Can we find and download TESS tesscut tpfs""" results = TESSSearch("Kepler 16b", hlsp=False, sector=14) + results2 = TESSSearch("Kepler 16b", pipeline="TESScut", sector=14) assert len(results) == 12 assert len(results.cubedata) == 2 - manifest = results.cubedata[1].download() + assert len(results.tesscut) == 1 + assert len(results.tesscut) == len(results2) + manifest = results.tesscut.download() assert len(manifest) == 1 @@ -548,9 +551,9 @@ def test_filter(): def test_tess_clouduris(): """regression test - do tesscut/nan's in dataURI column break cloud uri fetching""" toi = TESSSearch("TOI 1161", sector=14) - # 17 products should be returned + # 20 products should be returned assert len(toi.cloud_uris) == 20 - # 5 of them should have cloud uris + # 6 of them should have cloud uris assert np.sum((toi.cloud_uris.values != None).astype(int)) == 6