Coverage for middlelayer / ngect / cli.py: 28.57%
42 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-16 06:04 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-16 06:04 +0000
1# -*- coding: utf-8 -*-
2# Copyright 2023 Associated Universities, Inc.
3#
4# This file is part of ngVLA Exposure Calculator Tool (ngECT).
5#
6# ngECT is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# any later version.
10#
11# ngECT is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with ngECT. If not, see <https://www.gnu.org/licenses/>.
19"""ngect cli interface. adapted from the ngVLA subarray sensitivity and key performance metric calculator by V. Rosero."""
21import argparse
22import logging
23import pickle
24import sys
25import textwrap
26from pprint import pformat
28import numpy as np
29from astropy import units as u
31from . import __version__, engine, system
33logger = logging.getLogger(__name__)
36def cli_run():
37 """Entry point for the ngECT command-line interface.
39 Parses CLI arguments and delegates to :func:`calculate_sensitivity` to
40 compute exposure metrics. This mirrors the historical
41 ``ngVLA_sensitivity_calculator.py`` workflow for comparison purposes.
43 Examples
44 --------
45 From a shell, compute sensitivities for a given setup:
47 >>> # doctest: +SKIP
48 ... ngect_cli main+long 24.5 1 --t_obs 4 --delta_v 2e3
49 """
51 description = r"""
52 ngect cli user interface, adapted from the ngVLA subarray sensitivity and key performance metric calculator by V. Rosero.
54 A comparison example:
55 $ ngect_cli main+long 24.5 1
56 vs.
57 $ ./ngVLA_sensitivity_calculator.py main+long 24.5 1
59 They should give similar results.
60 """
62 subarray_help = (
63 r"""name of array (string): sba, core, spiral, mid, long, main, main+long, spiral+mid, spiral+core, mid+long"""
64 )
66 freq_help = r"""frequency in GHz(float): e.g., 24.5"""
68 theta_help = r"""resolution in arcsec(float or -1): e.g., 0.5.
69 theta = -1 will calculate native resolution (natural, no taper)"""
71 t_obs_help = r"""on-source time in hours(float): e.g., 4. Default: 1"""
73 delta_v_help = r"""channel width in m/s(float): e.g., 2e3. Default: 10e3"""
75 parser = argparse.ArgumentParser(
76 description=textwrap.dedent(description), formatter_class=argparse.RawDescriptionHelpFormatter
77 )
78 parser.add_argument("subarray", type=str, help=subarray_help)
79 parser.add_argument("frequency", type=float, help=freq_help)
80 parser.add_argument("theta", type=float, help=theta_help)
81 parser.add_argument("--t_obs", type=float, default=1.0, help=t_obs_help)
82 parser.add_argument("--delta_v", type=float, default=10e3, help=delta_v_help)
83 parser.add_argument("-v", "--verbose", help="increase output verbosity", action="store_true")
84 args = parser.parse_args()
86 calculate_sensitivity(args.subarray, args.frequency, args.theta, args.t_obs, args.delta_v, args.verbose)
89def calculate_sensitivity(subarray, freq=-1, theta=-1, t_obs=1, delta_v=10e3, verbose=True):
90 """Calculate sensitivities for a given observing setup.
92 Parameters
93 ----------
94 subarray : str
95 Subarray name (e.g., ``"sba"``, ``"core"``, ``"main+long"``).
96 freq : float, optional
97 Representative frequency in GHz. Default is ``-1`` (uses engine logic).
98 theta : float, optional
99 Target resolution in arcsec (use ``-1`` for native resolution). Default ``-1``.
100 t_obs : float, optional
101 On-source time in hours. Default ``1``.
102 delta_v : float, optional
103 Channel width in m/s. Default ``1e4``.
104 verbose : bool, optional
105 If ``True``, log a human-readable report to the logger. Default ``True``.
107 Returns
108 -------
109 dict
110 A result mapping from :meth:`ngect.engine.ArrayPerformance.ect` containing
111 sensitivities and configuration details for the last processed specmode.
113 Notes
114 -----
115 This function evaluates both continuum (``cont``) and spectral line (``line``)
116 modes in sequence, logging their results. The returned dictionary corresponds
117 to the last evaluated mode.
118 """
120 ap = engine.ArrayPerformance()
122 for specmode in ["cont", "line"]:
123 input_dict = {
124 "freq": freq * u.GHz,
125 "theta": theta * u.arcsec,
126 "subarray": subarray,
127 "specmode": specmode,
128 "chanwidth": delta_v * u.m / u.s,
129 "npol": 2,
130 "tos": t_obs * u.hr,
131 "elevation": 45 * u.degree,
132 "ectmode": "tos2rms",
133 "pwv": "6 mm",
134 }
135 output_dict = ap.ect(input_dict)
137 logger.info("")
138 if specmode == "cont":
139 logger.info("Continuum Mode:")
140 if specmode == "line":
141 logger.info("Spectral-Line Mode:")
143 str1 = f'{subarray} array, {input_dict["tos"]} at frequency {output_dict["freq"]} ({output_dict["rx_name"]}) with resolution of {output_dict["theta"]} (eta_w = {output_dict["eta_W"]})'
144 logger.info(str1)
145 logger.info("-" * len(str1))
146 logger.info(f'continuum point source sensitivity: {output_dict["sigma_fl"]}')
147 logger.info(f'continuum brightness sensitivity: {output_dict["sigma_tb"]}')
148 return output_dict
151if __name__ == "__main__":
152 cli_run()