Coverage for /wheeldirectory/casa-6.7.0-12-py3.10.el8/lib/py/lib/python3.10/site-packages/casatasks/private/task_getcalmodvla.py: 91%
111 statements
« prev ^ index » next coverage.py v7.6.4, created at 2024-10-31 18:48 +0000
« prev ^ index » next coverage.py v7.6.4, created at 2024-10-31 18:48 +0000
1from casatools import componentlist, measures, quanta
2from casatasks import casalog
3import certifi
4from datetime import datetime, timedelta
5import json
6import numbers
7import os, re, shutil
8import ssl
9from urllib import request
10from urllib.error import URLError, HTTPError
11from urllib.parse import urlparse, quote
14def __is_valid_url_host(url):
15 parsed = urlparse(url)
16 return bool(parsed.netloc)
19def __query(url):
20 components = None
21 response = None
22 try:
23 context = ssl.create_default_context(cafile=certifi.where())
24 with request.urlopen(url, context=context, timeout=400) as response:
25 if response.status == 200:
26 components = json.loads(response.read().decode('utf-8'))
27 except HTTPError as e:
28 casalog.post(
29 f"Caught HTTPError: {e.code} {e.reason}: {e.read().decode('utf-8')}",
30 "WARN"
31 )
32 except URLError as e:
33 casalog.post(f"Caught URLError: {str(e)}", "WARN")
34 except Exception as e:
35 casalog.post(f"Caught Exception when trying to connect: {str(e)}", "WARN")
36 return components
39def __getMJD(date_or_mjd, varname):
40 if isinstance(date_or_mjd, numbers.Number):
41 is_number = True
42 mjd = date_or_mjd
43 elif isinstance(date_or_mjd, str):
44 pattern = "^\d{4}-\d{2}-\d{2}$"
45 if re.match(pattern, date_or_mjd):
46 is_number = False
47 qa = quanta()
48 mjd = int(qa.time(date_or_mjd, form="mjd")[0][:5])
49 else:
50 raise ValueError(
51 f"If specified as a string, {varname} must be of the form "
52 + "YYYY-MM-DD"
53 )
54 else:
55 raise ValueError(
56 f"{varname} must either be a number or a string of the form "
57 + "YYYY-MM-DD"
58 )
59 return mjd
62# function declaration and summary generated by casadocs
63def getcalmodvla(outfile='', overwrite=False, source='', direction='', band='', obsdate='0', refdate='0', hosts=['http://obs.vla.nrao.edu/calmodvla']):
64 r"""
65Retrieve calibrator brightness distributions from a VLA web service.
67[`Description`_] [`Examples`_] [`Development`_] [`Details`_]
70Parameters
71 - outfile_ (path='') - The name of the output component list to be written. Must be specified
72 - overwrite_ (bool=False) - Overwrite a file or directory of the same name as outfile if it exists.
73 - source_ (string='') - The calibrator name.
74 - direction_ (string='') - The direction of the calibrator
75 - band_ (string='') - The receiver band for which the source structure is needed
76 - obsdate_ (variant='0') - The observation date
77 - refdate_ (variant='0') - The reference date after which new database entries will be ignored.
78 - hosts_ (stringVec=['http://obs.vla.nrao.edu/calmodvla']) - List of hostnames to use when querying the web service.
81.. _Description:
83Description
85 This task retrieves VLA-specific calibrator information via a web service
86 and writes this information as a component list so that it may be used by applications
87 downstream.
89 One of either a calibrator name or direction may be specified.
90 The names '3C48', '3C138', '3C147', and '3C286' are currently supported by the web
91 service. A direction is specified as 'FRAME LONGITUDE LATITUDE', so for example
92 "J2000 01:37:41.1 33.09.32" for 3C48. Latitude and longitude may be specified in
93 their familiar sexigesimal forms, or as angular quantities which must include
94 units (eg '33.15deg'). If a direction is specified, the web service will attempt to
95 find a supported calibrator near (as defined by the web service) that position. If
96 one cannot be found, the web server will return an error code and the task will
97 throw an exception.
99 The observing band must be specified. For the VLA, supported bands are 'P'. 'L', 'S',
100 'C', 'X', 'U', 'K', 'A', and 'Q'.
102 The observation date must be specified as either an MJD (assumed if the value is a number)
103 or a date of the form "YYYY-MM-DD" (assumed if the value is specified as a string).
105 A reference date may be specified. If so, the specification rules for the observation
106 date also hold for this parameter, Specifying this parameter allows older versions of the data
107 and/or algorithms to be retrieved, thus allowing historical reproducibility even
108 after data and algorithms may have been updated. This input represents the latest date
109 for which versioned data and algorithms should be used.
111 If successful, the task will write a component list generated from the data returned
112 by the web service which represents the brightness distribution for the specified
113 calibrator for the specified band at the specified date (with the reference date applied
114 if one is specified). This component list, being a CASA table, will include the table
115 keyword "web_service". The value of this keyword will be a dictionary containing the inputs
116 specified in the task, the response of the web service (usually a very long JSON string),
117 the URL that was used to make the query, and other possibly useful metadata.
120.. _Examples:
122Examples
124 ::
126 # get the intensity distribution of 3C48 at Q band on MJD 55000
127 getcalmodevla(
128 outfile='3C48.cl', source='3C48', band='Q', obsdate=55000,
129 hosts=['http://some-host-that-works.nrao.edu']
130 )
132 # the same thing, but do not use any data or algorithms that were
133 # created after MJD 56000
134 getcalmodevla(
135 outfile='3C48.cl', source='3C48', band='Q', obsdate=55000,
136 refdate=56000, hosts=['http://some-host-that-works.nrao.edu']
137 )
139 # get the same information as the first query based on 3C48's direction,
140 # not its name
141 getcalmodevla(
142 outfile='3C48.cl', direction='J2000 01h37m41.1s 33.155deg', band='Q',
143 obsdate=55000, hosts=['http://some-host-that-works.nrao.edu']
144 )
148.. _Development:
150Development
156.. _Details:
159Parameter Details
160 Detailed descriptions of each function parameter
162.. _outfile:
164| ``outfile (path='')`` - The name of the output component list to be written. Must be specified
165| Default: none, must be specified
166| Example: outfile="3c273.cl"
168.. _overwrite:
170| ``overwrite (bool=False)`` - Overwrite a file or directory of the same name of outfile if it exists. If overwrite=False and a file or directory of the same name as outfile exists, an exception will be thrown.
172.. _source:
174| ``source (string='')`` - The calibrator name. The case-insensitive names
175| "3C48", "3C286", "3C138",
176| and "3C147" are supported. Exactly one of source
177| or direction must be specified.
179.. _direction:
181| ``direction (string='')`` - An alternative to source. It is the direction of the calibrator. The supported
182| formats are of the form "EPOCH LONGITUDE LATITUDE", eg
183|
184| "J2000 12:34:56 -12.34.56".
185| "J2000 19h53m50 40d06m00"
186| "B1950 292.5deg -40.0deg"
187| "ICRS 13:05:27.2780 -049.28.04.458"
188| "GALACTIC 47.5rad -60.22rad"
189| Only astronomical coordinate systems should be used; eg AZEL is right out. The web service
190| will attempt to locate a known calibrator near this direction, where "near" is defined by
191| the web service team. Exactly one of source or direction must be specified.
193.. _band:
195| ``band (string='')`` - A string representing the case-insensitive code of
196| the band for which the data are required. For the VLA,
197| supported codes are "P", "L", "S", "C", "X", "U", "K", "A", and "Q".
199.. _obsdate:
201| ``obsdate (variant='0')`` - The date for which to obtain the calibrator information. If numeric,
202| is assumed to be an MJD. If a string, is assumed to be a date and must
203| be of the form "YYYY-MM-DD".
205.. _refdate:
207| ``refdate (variant='0')`` - The reference date after which new database entries will be ignored. If numeric,
208| is assumed to be an MJD. If a string, is assumed to be a date and must
209| be of the form "YYYY-MM-DD". Used to support
210| historical reproducibility. A non-positive value will result in this parameter being ignored,
211| and the most recent entry will be used (which may be later than obsdate).
213.. _hosts:
215| ``hosts (stringVec=['http://obs.vla.nrao.edu/calmodvla'])`` - List of hostnames to use when querying the web service. They will be queried in
216| order until a successful response is received.
219 """
221 if not outfile.strip():
222 raise ValueError("outfile must be specified")
223 if not overwrite and os.path.exists(outfile):
224 raise RuntimeError(
225 f"The overwrite parameter is False and a file or directory named {outfile} "
226 "already exists. Either remove or rename it, or change overwrite to True, "
227 "or both."
228 )
229 if not (source.strip() or direction.strip()):
230 raise ValueError("Exactly one of source or direction must be specified")
231 if source and direction:
232 raise ValueError("Both source and direction may not be simultaneously specified")
233 if source:
234 source = source.upper()
235 if direction:
236 dirstr = direction.split(" ")
237 if not (len(dirstr) == 3 and measures().direction(dirstr[0], dirstr[1], dirstr[2])):
238 raise ValueError(f"Illegal direction specification {direction}")
239 src_or_dir = source if source else direction
240 if not band:
241 raise ValueError("band must be specified")
242 if band.upper() not in ["P", "L", "S", "C", "X", "U", "K", "A", "Q"]:
243 raise ValueError(f"band {band} not supported")
244 obsdate_mjd = __getMJD(obsdate, "obsdate")
245 refdate_mjd = __getMJD(refdate, "refdate")
246 if not hosts:
247 raise ValueError("hosts must be specified")
248 wsid = "type=setjy"
249 wsid += f"&source={quote(source)}" if source else f"&position={quote(direction)}"
250 wsid += f"&band={quote(band)}"
251 wsid += f"&obsdate={int(obsdate_mjd)}"
252 if refdate > 0:
253 wsid += f"&refdate={int(refdate_mjd)}"
254 components = None
255 for h in hosts:
256 if not __is_valid_url_host(h):
257 raise ValueError(f"{h} is not a valid host expressed as a URL")
258 url = f"{h}?{wsid}"
259 casalog.post(f"Trying {url} ...", "NORMAL")
260 components = __query(url)
261 if components:
262 break
263 if not components:
264 raise RuntimeError("All URLs failed to return a component list")
265 cl = componentlist()
266 cl.fromrecord(components)
267 if os.path.exists(outfile):
268 if overwrite:
269 if os.path.isdir(outfile):
270 shutil.rmtree(outfile)
271 else:
272 os.remove(outfile)
273 else:
274 raise RuntimeError(
275 "Logic Error: Should not have gotten to this point with overwrite=False"
276 )
277 cl.rename(outfile)
278 web_service = {}
279 if source:
280 web_service["source"] = source
281 if direction:
282 web_service["direction"] = direction
283 if obsdate:
284 web_service["obsdate"] = obsdate
285 if refdate:
286 web_service["refdate"] = refdate
287 web_service["band"] = band
288 web_service["hosts"] = hosts
289 qa = quanta()
290 web_service["run_mjd"] = int(
291 qa.time(
292 f"{datetime.today().strftime('%Y-%m-%d')} 00:00:00", form="mjd"
293 )[0][:5]
294 )
295 web_service["run_date"] = datetime.today().strftime("%Y-%m-%d")
296 web_service["url"] = url
297 web_service["response"] = components
298 cl.putkeyword("web_service", web_service)
299 casalog.post(f"component list {outfile} has been written", "NORMAL")
300 cl.done()