diff --git a/docs/changes/30.feature.rst b/docs/changes/30.feature.rst new file mode 100644 index 0000000..3e76de4 --- /dev/null +++ b/docs/changes/30.feature.rst @@ -0,0 +1 @@ +added command line tool for uvfits to measurement set conversion using casa diff --git a/pyproject.toml b/pyproject.toml index 7206300..0aa42a5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,6 +89,7 @@ dev = [ [project.scripts] radiotools-info = "radiotools.info:main" radiotools-vis = "radiotools.cli_tools.vis:main" +radiotools-fits2ms = "radiotools.cli_tools.fits2ms:main" [tool.hatch.version] source = "vcs" diff --git a/src/radiotools/cli_tools/fits2ms.py b/src/radiotools/cli_tools/fits2ms.py new file mode 100644 index 0000000..a768bc6 --- /dev/null +++ b/src/radiotools/cli_tools/fits2ms.py @@ -0,0 +1,52 @@ +"""Tool to convert uvfits files into measurement sets. +Single files or all files inside a directory can be converted. +""" + +from pathlib import Path + +import click +import numpy as np +from natsort import natsorted +from tqdm.auto import tqdm + +from radiotools.utils import rmtree, uvfits2ms + + +@click.command() +@click.argument("fits_path", type=click.Path(exists=True, dir_okay=True)) +@click.argument("ms_path", type=click.Path(exists=True, dir_okay=True)) +@click.option("--log", default=False) +def main(fits_path, ms_path, log=False): + """Convert uvfits files into measurement sets. + + Parameters + ---------- + fits_path : str + Path to fits file or directory with fits files + ms_path : str + Path to store ms file or directory for ms files + """ + fits_path = Path(fits_path) + ms_path = Path(ms_path) + + if ".ms" not in ms_path.name: + ms_path.mkdir(parents=True, exist_ok=True) + + if fits_path.is_dir(): + fits_files = natsorted(np.array([x for x in fits_path.iterdir()])) + else: + fits_files = fits_path + + for i, path in enumerate(tqdm(fits_files)): + if fits_path.is_dir(): + file_name = "vis_" + str(i) + ".ms" + out = ms_path / file_name + else: + out = ms_path.parent + "/vis_" + str(i) + ".ms" + if out.exists(): + rmtree(out) + uvfits2ms(path, out) + + +if __name__ == "__main__": + main() diff --git a/src/radiotools/utils/__init__.py b/src/radiotools/utils/__init__.py index 1f32665..805bcb3 100644 --- a/src/radiotools/utils/__init__.py +++ b/src/radiotools/utils/__init__.py @@ -1,7 +1,9 @@ -from .utils import get_array_names, img2jansky, rms +from .utils import get_array_names, img2jansky, rms, rmtree, uvfits2ms __all__ = [ "get_array_names", "img2jansky", "rms", + "uvfits2ms", + "rmtree", ] diff --git a/src/radiotools/utils/utils.py b/src/radiotools/utils/utils.py index 0ee4247..57fe9c3 100644 --- a/src/radiotools/utils/utils.py +++ b/src/radiotools/utils/utils.py @@ -1,4 +1,6 @@ import re +import subprocess +from pathlib import Path import numpy as np import requests @@ -73,3 +75,48 @@ def img2jansky(image: ArrayLike, header: fits.Header): * np.power(header["CDELT1"], 2) / (np.pi * header["BMIN"] * header["BMAJ"]) ) + + +def uvfits2ms(fits_path, ms_path): + """Converts a uvfits_file into a measurement set (ms file). + + Parameters + ---------- + fits_path : str + path to fits_file + ms_path : str + path to store ms_file + """ + casa = "casa --quiet --nologger --nologfile --nogui --norc --agg -c " + arg = ( + "importuvfits(fitsfile='" + + str(fits_path) + + "'" + + ", vis=" + + "'" + + str(ms_path) + + "'" + + ")" + ) + + command = casa + '"' + arg + '"' + + subprocess.run(command, shell=True) + + +def rmtree(root: Path): + """Recursively remove directories and files + starting from root directory. + + Parameters + ---------- + root : Path + Root path of the directories you want to delete. + """ + for p in root.iterdir(): + if p.is_dir(): + rmtree(p) + else: + p.unlink() + + root.rmdir()