From 2e47e3825059769e61c1c829302ff112823d5acb Mon Sep 17 00:00:00 2001 From: Frits Sweijen Date: Sun, 6 Oct 2024 15:44:45 +0100 Subject: [PATCH 1/2] Add LoTSS DR2 FITS cutout server --- src/everystamp/downloaders.py | 85 +++++++++++++++++++++++++++++++---- src/everystamp/everystamp.py | 9 ++-- 2 files changed, 81 insertions(+), 13 deletions(-) diff --git a/src/everystamp/downloaders.py b/src/everystamp/downloaders.py index 2653fcc..a702097 100644 --- a/src/everystamp/downloaders.py +++ b/src/everystamp/downloaders.py @@ -27,8 +27,6 @@ logger = logging.getLogger("EveryStamp:Downloader") - - def flatten(xs): """Flatten a nested list, as per the example on https://stackoverflow.com/a/40857703. @@ -138,6 +136,60 @@ def download_file(self, url, filename=None, target_dir=None): return target_dest_dir +class LoTSSDownloader(FileDownloader): + """Downloader sub-class for the LOFAR Two-metre Sky Survey.""" + + supported_keywords = ["ra", "dec", "size_arcmin"] + logger = logging.getLogger("EveryStamp:LoTSSDownloader") + + def __init__(self): + self.url = "https://lofar-surveys.org/dr2-cutout.fits?pos={coord_str:s}&size={size_arcmin:f}" + + def format_url(self, ra: str = "", dec: str = "", size: float = 1.0) -> str: + """ + + Args: + ra: right ascension in HH:MM:SS format. + dec: declination in HH:MM:SS format. + size: size of the cutout area in degrees. + + Returns: + url: the formatted URL. + """ + size_arcmin = size * 60 + coord_str = ( + SkyCoord(ra, dec, unit="deg", frame="icrs") + .to_string("hmsdms") + .replace("h", ":") + .replace("m", ":") + .replace("d", ":") + .replace("s", "") + ) + url = self.url.format(coord_str=coord_str, size_arcmin=size_arcmin) + return url + + def download(self, **kwargs): + if kwargs["mode"] != "fits": + raise ValueError("LoTSSDownloader only supports FITS downloads.") + furl = self.format_url(ra=kwargs["ra"], dec=kwargs["dec"], size=kwargs["size"]) + logger.info(furl) + fname = "LoTSS-DR2_{ra:f}_{dec:f}_{size:.3f}.{mode:s}".format( + ra=kwargs["ra"], + dec=kwargs["dec"], + mode="fits", + size=kwargs["size"], + ) + if not kwargs["ddir"]: + self.logger.info( + "Download directory not specified, downloading to %s instead", + os.getcwd(), + ) + ddir = os.getcwd() + else: + ddir = kwargs["ddir"] + self.download_file(furl, filename=fname, target_dir=ddir) + + class LegacyDownloader(FileDownloader): """Downloader sub-class for the DESI Legacy Imaging Surveys.""" @@ -240,7 +292,8 @@ def download(self, **kwargs): try: self.download_file(furl, filename=fname, target_dir=ddir) except requests.exceptions.HTTPError: - self.logger.warning(f'Failed to download {fname}') + self.logger.warning(f"Failed to download {fname}") + class PanSTARRSDownloader: """Downloader sub-class for the VLASS survey.""" @@ -443,7 +496,9 @@ def get_subtiles(self, tilename, epoch, consider_QA_rejected): fname = np.array([val.split('"')[7] for val in vals]) # Split out the actual coordinate string - pos_raw = np.array([val.split(".")[4] for val in fname if val.startswith("VLASS")]) + pos_raw = np.array( + [val.split(".")[4] for val in fname if val.startswith("VLASS")] + ) if "-" in pos_raw[0]: # dec < 0 @@ -703,6 +758,7 @@ def download(self, ra=0.0, dec=0.0, size=0.1, ddir=os.getcwd(), suffix=""): ) ) + class HiPSDownloader: """Sub-class to download a file from a HiPS image using hips2fits.""" @@ -718,7 +774,9 @@ def __init__(self, hips, name=""): self.logger = logging.getLogger( "EveryStamp:HiPSDownloader[{:s}]".format(self.name) ) - self.logger.warning("downloading from a HiPS survey. Scientific accuracy of resulting FITS images is not guaranteed!") + self.logger.warning( + "downloading from a HiPS survey. Scientific accuracy of resulting FITS images is not guaranteed!" + ) def download( self, ra=0.0, dec=0.0, size=0.1, ddir=os.getcwd(), pixsize=1.0, mode="jpg" @@ -756,10 +814,21 @@ def download( os.mkdir(ddir) if mode == "jpg": from PIL import Image + imdata = Image.fromarray(img) - imdata.save(os.path.join(ddir, '{:s}_{:.4f}_{:.4f}_{:.5f}.jpeg'.format(self.name, ra, dec, size))) - elif mode == 'fits': - img.writeto(os.path.join(ddir, '{:s}_{:.4f}_{:.4f}_{:.5f}.fits'.format(self.name, ra, dec, size))) + imdata.save( + os.path.join( + ddir, + "{:s}_{:.4f}_{:.4f}_{:.5f}.jpeg".format(self.name, ra, dec, size), + ) + ) + elif mode == "fits": + img.writeto( + os.path.join( + ddir, + "{:s}_{:.4f}_{:.4f}_{:.5f}.fits".format(self.name, ra, dec, size), + ) + ) class SkyViewDownloader: diff --git a/src/everystamp/everystamp.py b/src/everystamp/everystamp.py index 49b5899..de283d2 100644 --- a/src/everystamp/everystamp.py +++ b/src/everystamp/everystamp.py @@ -1,5 +1,6 @@ #!/usr/bin/env python -""" Python library aiming to provide a wrapper around various astronomical surveys that offer cutouts.""" +"""Python library aiming to provide a wrapper around various astronomical surveys that offer cutouts.""" + __version__ = "1.5.0" __author__ = "Frits Sweijen" __license__ = "GPLv3" @@ -25,7 +26,6 @@ logger = logging.getLogger("EveryStamp") - # Check if LuminanceHDR is installed. HAS_LHDR = ( lhdr.has_luminance_hdr() @@ -825,16 +825,15 @@ def _process_args_download(args): ) vd.download(ra=ra, dec=dec, size=args.size, ddir=args.ddir) elif args.lotss_release == "dr2": - from everystamp.downloaders import HiPSDownloader + from everystamp.downloaders import LoTSSDownloader - vd = HiPSDownloader(hips="astron.nl/P/lotss_dr2_high", name="LoTSS-DR2") + vd = LoTSSDownloader() vd.download( ra=ra, dec=dec, size=args.size, ddir=args.ddir, mode=args.mode.replace("e", ""), - pixsize=1.5, ) elif args.survey == "tgss": if args.mode == "both" or args.mode == "jpeg": From 1b390b335d4ee50c492503e23e69740d2a487af8 Mon Sep 17 00:00:00 2001 From: Frits Sweijen Date: Sun, 6 Oct 2024 19:40:06 +0100 Subject: [PATCH 2/2] Add dr2-low --- src/everystamp/downloaders.py | 11 ++++++----- src/everystamp/everystamp.py | 5 +++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/everystamp/downloaders.py b/src/everystamp/downloaders.py index a702097..f64a631 100644 --- a/src/everystamp/downloaders.py +++ b/src/everystamp/downloaders.py @@ -143,9 +143,9 @@ class LoTSSDownloader(FileDownloader): logger = logging.getLogger("EveryStamp:LoTSSDownloader") def __init__(self): - self.url = "https://lofar-surveys.org/dr2-cutout.fits?pos={coord_str:s}&size={size_arcmin:f}" + self.url = "https://lofar-surveys.org/{release:s}-cutout.fits?pos={coord_str:s}&size={size_arcmin:f}" - def format_url(self, ra: str = "", dec: str = "", size: float = 1.0) -> str: + def format_url(self, ra: str, dec: str, release: str, size: float = 1.0) -> str: """ Args: @@ -165,19 +165,20 @@ def format_url(self, ra: str = "", dec: str = "", size: float = 1.0) -> str: .replace("d", ":") .replace("s", "") ) - url = self.url.format(coord_str=coord_str, size_arcmin=size_arcmin) + url = self.url.format(coord_str=coord_str, size_arcmin=size_arcmin, release=release) return url def download(self, **kwargs): if kwargs["mode"] != "fits": raise ValueError("LoTSSDownloader only supports FITS downloads.") - furl = self.format_url(ra=kwargs["ra"], dec=kwargs["dec"], size=kwargs["size"]) + furl = self.format_url(ra=kwargs["ra"], dec=kwargs["dec"], size=kwargs["size"], release=kwargs["release"]) logger.info(furl) - fname = "LoTSS-DR2_{ra:f}_{dec:f}_{size:.3f}.{mode:s}".format( + fname = "LoTSS-{release:s}_{ra:f}_{dec:f}_{size:.3f}.{mode:s}".format( ra=kwargs["ra"], dec=kwargs["dec"], mode="fits", size=kwargs["size"], + release=kwargs["release"].upper(), ) if not kwargs["ddir"]: self.logger.info( diff --git a/src/everystamp/everystamp.py b/src/everystamp/everystamp.py index de283d2..3582e70 100644 --- a/src/everystamp/everystamp.py +++ b/src/everystamp/everystamp.py @@ -198,7 +198,7 @@ def _add_args_download(parser): type=str, required=False, default="dr1", - choices=["pdr", "dr1", "dr2"], + choices=["pdr", "dr1", "dr2", "dr2-low"], help="Data release to download from.", ) @@ -824,7 +824,7 @@ def _process_args_download(args): name="LoTSS-DR1", ) vd.download(ra=ra, dec=dec, size=args.size, ddir=args.ddir) - elif args.lotss_release == "dr2": + elif args.lotss_release == "dr2" or args.lotss_release == "dr2-low": from everystamp.downloaders import LoTSSDownloader vd = LoTSSDownloader() @@ -834,6 +834,7 @@ def _process_args_download(args): size=args.size, ddir=args.ddir, mode=args.mode.replace("e", ""), + release=args.lotss_release ) elif args.survey == "tgss": if args.mode == "both" or args.mode == "jpeg":