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 19:53 +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 

12 

13 

14def __is_valid_url_host(url): 

15 parsed = urlparse(url) 

16 return bool(parsed.netloc) 

17 

18 

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 

37 

38 

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 

60 

61 

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. 

66 

67[`Description`_] [`Examples`_] [`Development`_] [`Details`_] 

68 

69 

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. 

79 

80 

81.. _Description: 

82 

83Description 

84 

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. 

88 

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. 

98 

99 The observing band must be specified. For the VLA, supported bands are 'P'. 'L', 'S', 

100 'C', 'X', 'U', 'K', 'A', and 'Q'. 

101 

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). 

104 

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. 

110 

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.  

118 

119 

120.. _Examples: 

121 

122Examples 

123  

124 :: 

125 

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 )  

131 

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 )  

138 

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 )  

145 

146 

147 

148.. _Development: 

149 

150Development 

151 

152  

153 

154 

155 

156.. _Details: 

157 

158 

159Parameter Details 

160 Detailed descriptions of each function parameter 

161 

162.. _outfile: 

163 

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" 

167 

168.. _overwrite: 

169 

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. 

171 

172.. _source: 

173 

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. 

178 

179.. _direction: 

180 

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. 

192 

193.. _band: 

194 

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". 

198 

199.. _obsdate: 

200 

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". 

204 

205.. _refdate: 

206 

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). 

212 

213.. _hosts: 

214 

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. 

217 

218 

219 """ 

220 

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() 

301