Coverage for /wheeldirectory/casa-6.7.0-12-py3.10.el8/lib/py/lib/python3.10/site-packages/casatasks/private/task_importasdm.py: 86%

226 statements  

« prev     ^ index     » next       coverage.py v7.6.4, created at 2024-11-01 07:19 +0000

1import os 

2import shutil 

3 

4from casatasks import casalog 

5from casatools import table, agentflagger, ms, imager, measures, msmetadata, sdm 

6from .mstools import write_history 

7from . import flaghelper as fh 

8from . import convertephem as ce 

9from .parallel.parallel_data_helper import ParallelDataHelper 

10 

11_tb = table() 

12 

13def importasdm( 

14 asdm=None, 

15 vis=None, 

16 createmms=None, 

17 separationaxis=None, 

18 numsubms=None, 

19 corr_mode=None, 

20 srt=None, 

21 time_sampling=None, 

22 ocorr_mode=None, 

23 compression=None, 

24 lazy=None, 

25 asis=None, 

26 wvr_corrected_data=None, 

27 scans=None, 

28 ignore_time=None, 

29 process_syspower=None, 

30 process_caldevice=None, 

31 process_pointing=None, 

32 process_flags=None, 

33 tbuff=None, 

34 applyflags=None, 

35 savecmds=None, 

36 outfile=None, 

37 flagbackup=None, 

38 verbose=None, 

39 overwrite=None, 

40 bdfflags=None, 

41 with_pointing_correction=None, 

42 convert_ephem2geo=None, 

43 polyephem_tabtimestep=None 

44 ): 

45 """Convert an ALMA Science Data Model observation into a CASA visibility file (MS) or single-dish data format (Scantable). 

46 The conversion of the ALMA SDM archive format into a measurement set. This version 

47 is under development and is geared to handling many spectral windows of different 

48 shapes. 

49 

50 Keyword arguments: 

51 asdm -- Name of input ASDM file (directory) 

52 default: none; example: asdm='ExecBlock3' 

53 

54 vis -- Root ms or scantable name, note a prefix (.ms or .asap) is NOT appended to this name 

55 default: none 

56  

57 createmms -- Create a Multi-MS 

58 default: False 

59  

60 corr_mode -- correlation mode to be considered on input. Could 

61 be one or more of the following, ao, co, ac, or all 

62 default: all 

63 

64 srt -- spectral resolution type. Could be one or more of 

65 the following, fr, ca, bw, or all 

66 default: all 

67 

68 time_sampling -- specifies the time sampling, INTEGRATION and/or 

69 SUBINTEGRATION. could be one or more of the following 

70 i, si, or all. 

71 default: all 

72 

73 ocorr_mode -- output data for correlation mode AUTO_ONLY  

74 (ao) or CROSS_ONLY (co) or CROSS_AND_AUTO (ca) 

75 default: ca 

76 

77 compression -- produces comrpressed columns in the resulting measurement set. 

78 default: False 

79 

80 lazy -- Make the MS DATA column read the ASDM Binary data directly 

81 (faster import, smaller MS) 

82 default: False 

83 

84 asis -- creates verbatim copies of the ASDM tables in  

85 the output measurement set. The value given to 

86 this option must be a list of table names separated 

87 by space characters; the wildcard character '*' is  

88 allowed in table names. 

89 

90 wvr_corrected_data -- specifies which values are considered in the  

91 ASDM binary data to fill the DATA column in  

92 the MAIN table of the MS. Expected values for  

93 this option are 'no' for the uncorrected data  

94 (this is the default), 'yes' for the corrected 

95 data and 'both' for corrected and uncorrected  

96 data. In the latter case, two measurement sets 

97 are created, one containing the uncorrected  

98 data and the other one, whose name is suffixed 

99 by '-wvr-corrected', containing the corrected  

100 data. 

101 

102 scans -- processes only the scans specified in the option's value. This value is a semicolon  

103 separated list of scan specifications. A scan specification consists in an exec bock index  

104 followed by the character ':' followed by a comma separated list of scan indexes or scan  

105 index ranges. A scan index is relative to the exec block it belongs to. Scan indexes are  

106 1-based while exec blocks's are 0-based. "0:1" or "2:2~6" or "0:1,1:2~6,8;2:,3:24~30" "1,2"  

107 are valid values for the option. "3:" alone will be interpreted as 'all the scans of the  

108 exec block#3'. An scan index or a scan index range not preceded by an exec block index will 

109 be interpreted as 'all the scans with such indexes in all the exec blocks'. By default  

110 all the scans are considered. 

111 

112 ignore_time -- All the rows of the tables Feed, History, Pointing, Source, SysCal, CalDevice, SysPower, 

113 and Weather are processed independently of the time range of the selected exec block / scan. 

114 

115 process_syspower -- The SysPower table is processed if and only if this parameter is set to True. 

116 default: True 

117 

118 process_caldevice -- The CalDevice table is processed if and only if this parameter is set to True. 

119 default: True 

120 

121 process_pointing -- The Pointing table is processed if and only if this parameter is set to True. 

122 If the parameter is set to False the resulting MS will have an empty POINTING table. 

123 default: True 

124 

125 process_flags -- Process the online flags and save them to the FLAG_CMD sub-table. 

126 default: True 

127 

128 >>> process_flags expandable parameter 

129 tbuff -- Time padding buffer (in seconds). 

130 default: 0.0 

131 

132 applyflags -- Apply the online flags to the MS. 

133 default: False 

134 

135 savecmds -- Save the online flags to an ASCII file. 

136 default: False 

137  

138 outfile -- Filename to save the online flags. 

139 default: '' 

140 

141 flagbackup -- Backup the FLAG column in the .flagversions. 

142 default: True 

143 

144 verbose -- produce log output as asdm2MS is being run. 

145 

146 overwrite -- Over write an existing MS. 

147 

148 bdfflags -- Set the MS FLAG column according to the ASDM _binary_ flags 

149 default: false 

150 

151 with_pointing_correction -- add (ASDM::Pointing::encoder - ASDM::Pointing::pointingDirection) 

152 to the value to be written in MS::Pointing::direction  

153 default: false 

154 

155 convert_ephem2geo -- if True, convert any attached ephemerides to the GEO reference frame 

156 

157 polyephem_tabtimestep -- Timestep (days) for the tabulation of polynomial ephemerides. A value <= 0 disables tabulation. 

158 Presently, VLA data can contain polynomial ephemerides. ALMA data uses tabulated values. 

159 default: 0.  

160 

161 """ 

162 

163 # Python script 

164 

165 casalog.origin('importasdm') 

166 

167 # fill in empty vis parameter 

168 if vis is None or type(vis) is str and len(vis) == 0: 

169 vis = asdm+".ms" 

170 

171 # make local sdm tool - CASA6 only, CASA5 uses asdm2MS executable 

172 sdmlocal = sdm(asdm) 

173 

174 # make agentflagger tool local 

175 aflocal = agentflagger() 

176 

177 # make table tool local 

178 tblocal = table() 

179 

180 viso = '' 

181 visoc = '' # for the wvr corrected version, if needed 

182 if len(vis) > 0: 

183 viso = vis 

184 tmps = vis.rstrip('.ms') 

185 if tmps == vis: 

186 visoc = vis + '-wvr-corrected' 

187 else: 

188 visoc = tmps + '-wvr-corrected.ms' 

189 else: 

190 viso = asdm.rstrip("/") + '.ms' 

191 visoc = asdm.rstrip("/") + '-wvr-corrected.ms' 

192 vis = asdm.rstrip("/") 

193 

194 # Compression 

195 if compression: 

196 # viso = viso + '.compressed' 

197 viso = viso.rstrip('.ms') + '.compressed.ms' 

198 visoc = visoc.rstrip('.ms') + '.compressed.ms' 

199 

200 vistoproc = [] # the output MSs to post-process 

201 if wvr_corrected_data == 'no' or wvr_corrected_data == 'both': 

202 vistoproc.append(viso) 

203 if (wvr_corrected_data == 'yes' or wvr_corrected_data == 'both'): 

204 vistoproc.append(visoc) 

205 

206 for ff in vistoproc: 

207 if not overwrite and os.path.exists(ff): 

208 raise Exception('You have specified an existing MS and have indicated you do not wish to overwrite it: %s'%ff) 

209 

210 # If viso+".flagversions" then process differently depending on the value of overwrite.. 

211 # 

212 if flagbackup: 

213 for myviso in vistoproc: 

214 dotFlagversion = myviso + '.flagversions' 

215 if os.path.exists(dotFlagversion): 

216 if overwrite: 

217 casalog.post("Found '" + dotFlagversion 

218 + "' . It'll be deleted before running the filler." 

219 ) 

220 os.system('rm -rf %s' % dotFlagversion) 

221 else: 

222 casalog.post("Found '%s' but can't overwrite it." % dotFlagversion) 

223 raise Exception("Found '%s' but can't overwrite it." % dotFlagversion) 

224 

225 # Make outfile always a list 

226 if isinstance(outfile, str): 

227 if outfile == '': 

228 outfile = [] 

229 else: 

230 noutfile = [outfile] 

231 outfile = noutfile 

232 

233 if savecmds: 

234 if len(outfile) == 0: 

235 # Create default names for the online flags 

236 for myviso in vistoproc: 

237 outfile.append(myviso.replace('.ms','_cmd.txt')) 

238 elif len(outfile) != len(vistoproc): 

239 casalog.post('List of outfile names does not match list of MSs','WARN') 

240 casalog.post('Will save online flags to temporary filenames', 'WARN') 

241 outfile = [] 

242 for myviso in vistoproc: 

243 online_file = myviso.replace('.ms','_TEMP_cmd.txt') 

244 outfile.append(online_file) 

245 

246 if not overwrite: 

247 for of in outfile: 

248 if os.path.exists(of): 

249 raise RuntimeError("Cannot overwrite online flags file '%s'; overwrite is set to False."% of) 

250 

251 

252 if (polyephem_tabtimestep!=None) and (type(polyephem_tabtimestep)==int or type(polyephem_tabtimestep)==float): 

253 if polyephem_tabtimestep>0: 

254 casalog.post('Will tabulate all attached polynomial ephemerides with a time step of ' 

255 +str(polyephem_tabtimestep)+' days.') 

256 if polyephem_tabtimestep>1.: 

257 casalog.post('A tabulation timestep of <= 1 days is recommended.', 'WARN') 

258 # one more addition to the asdm2MS execution string 

259 

260 try: 

261 exitcode = sdmlocal.toms( vis, createmms, separationaxis, numsubms, corr_mode, srt, time_sampling, 

262 ocorr_mode, compression, lazy, asis, wvr_corrected_data, scans, 

263 ignore_time, process_syspower, process_caldevice, process_pointing, 

264 process_flags, tbuff, applyflags, savecmds, outfile, flagbackup, 

265 verbose, overwrite, bdfflags, 

266 with_pointing_correction, convert_ephem2geo, 

267 polyephem_tabtimestep ) 

268 

269 if exitcode != True: 

270 casalog.post("initial creation of the measurement set failed", 'SEVERE') 

271 raise Exception('ASDM conversion error. Please check if it is a valid ASDM and that data/alma/asdm is up to date.') 

272 except Exception as instance: 

273 # I think an exception is more likely than a non-zero error code and will often involve a partial fill into the MS 

274 casalog.post("initial creation of the measurementset failed", 'SEVERE') 

275 casalog.post("Note: if an MS exists then additional steps usually done after that initial (partial) fill were not completed", 'SEVERE') 

276 casalog.post("The MS should only be used for looking into why the fill failed, it should not be used for any additional processing", 'SEVERE') 

277 raise Exception('ASDM conversion error. Check the logs for additional details.') from instance 

278 

279 

280 # 

281 # Possibly remove the name of the measurement set expected to contain the corrected data from the list of of produced measurement 

282 # sets if it appears the filler did not find any corrected data. 

283 # 

284 if not os.path.exists(visoc): 

285 vistoproc = [myviso for myviso in vistoproc if myviso != visoc] 

286 

287 if convert_ephem2geo: 

288 for myviso in vistoproc: 

289 ce.convert2geo(myviso, '*') # convert any attached ephemerides to GEO 

290 

291 for myviso in vistoproc: 

292 theephemfields = ce.findattachedephemfields(myviso,field='*') 

293 if len(theephemfields)>0: 

294 # until asdm2MS or sdm.toms does this internally: recalc the UVW coordinates for ephem fields 

295 imt = imager() 

296 imt.open(myviso, usescratch=False) 

297 imt.calcuvw(theephemfields, refcode='J2000', reuse=False) 

298 imt.close() 

299 

300 if len(theephemfields)>0: 

301 # also set the direction column in the SOURCE table 

302 tblocal.open(myviso+'/FIELD', nomodify=False) 

303 sourceids = tblocal.getcol('SOURCE_ID') 

304 ftimes = tblocal.getcol('TIME') 

305 ftimekw = tblocal.getcolkeywords('TIME') 

306 tmpa = tblocal.getcol('PHASE_DIR') 

307 origphasedir = tmpa 

308 

309 affectedsids = [] 

310 thesamplefields = [] 

311 for fld in theephemfields: # determine all source ids used by the ephem fields 

312 if not (sourceids[fld] in affectedsids): # this source id wasn't handled yet 

313 affectedsids.append(sourceids[fld]) 

314 thesamplefields.append(fld) 

315 # need to temporarily change the offset (not all mosaics have an element at (0,0)) 

316 tmpa[0][0][fld]=0. 

317 tmpa[1][0][fld]=0. 

318 #endif 

319 #endfor 

320 tblocal.putcol('PHASE_DIR', tmpa) 

321 tblocal.close() 

322 

323 tblocal.open(myviso+'/SOURCE') 

324 sourceposref = tblocal.getcolkeywords('DIRECTION')['MEASINFO']['Ref'] 

325 tblocal.close() 

326 

327 directions = [] 

328 melocal = measures() 

329 msmdlocal = msmetadata() 

330 msmdlocal.open(myviso) 

331 

332 for fld in thesamplefields: 

333 thedirmeas = msmdlocal.phasecenter(fld) 

334 if thedirmeas['refer']!=sourceposref: 

335 casalog.post('Ephemeris is in '+thedirmeas['refer']+' instead of '+sourceposref 

336 +' frame.\nEntry in SOURCE table will be converted to '+sourceposref, 'WARN') 

337 melocal.doframe(thedirmeas) 

338 thedirmeas = melocal.measure(thedirmeas, sourceposref) 

339 

340 directions.append([thedirmeas['m0']['value'], thedirmeas['m1']['value']]) 

341 thetime = melocal.epoch(v0=str(ftimes[fld])+'s', rf=ftimekw['MEASINFO']['Ref']) 

342 casalog.post("Will set SOURCE direction for SOURCE_ID "+str(sourceids[fld]) 

343 +" to ephemeris phase center for time "+str(thetime['m0']['value'])+" "+thetime['m0']['unit']+" "+thetime['refer']) 

344 #endfor 

345 msmdlocal.close() 

346 

347 # restore original PHASE_DIR 

348 tblocal.open(myviso+'/FIELD', nomodify=False) 

349 tblocal.putcol('PHASE_DIR', origphasedir) 

350 tblocal.close() 

351 

352 # write source directions 

353 tblocal.open(myviso+'/SOURCE', nomodify=False) 

354 ssourceids = tblocal.getcol('SOURCE_ID') 

355 sdirs = tblocal.getcol('DIRECTION') 

356 for row in range(0,len(ssourceids)): 

357 for i in range(0,len(affectedsids)): 

358 if ssourceids[row]==affectedsids[i]: 

359 sdirs[0][row] = directions[i][0] 

360 sdirs[1][row] = directions[i][1] 

361 break 

362 #endfor 

363 #endfor 

364 tblocal.putcol('DIRECTION', sdirs) # write back corrected directions 

365 tblocal.close() 

366 

367 #end if 

368 #end for 

369 

370 ##############################################################################################3 

371 # CAS-7369 - Create an output Multi-MS (MMS) 

372 if createmms: 

373 fpars = { } 

374 # Get the default parameters of partition 

375 import inspect 

376 from casatasks import partition as pt 

377 for k,v in inspect.signature(pt).parameters.items( ): 

378 fpars[k] = v.default 

379 

380 # Call the cluster for each MS 

381 for myviso in vistoproc: 

382 casalog.origin('importasdm') 

383 

384 # Move original MS to tempdir 

385 tempname = myviso+'.temp.ms' 

386 outputmms = myviso 

387 shutil.move(myviso, tempname) 

388 

389 # Get the proper column 

390 datacolumn = 'DATA' 

391 dcols = ['DATA', 'FLOAT_DATA'] 

392 _tb.open(tempname) 

393 for dc in dcols: 

394 if dc in _tb.colnames( ): 

395 datacolumn = dc 

396 break 

397 _tb.close( ) 

398 

399 fpars['datacolumn'] = datacolumn 

400 

401 casalog.post('Will create a Multi-MS for: '+myviso) 

402 

403 fpars['vis'] = tempname 

404 fpars['flagbackup'] = False 

405 fpars['outputvis'] = outputmms 

406 fpars['separationaxis'] = separationaxis 

407 fpars['numsubms'] = numsubms 

408 

409 # Run partition only at the MPIServers 

410 pdh = ParallelDataHelper('partition', fpars) 

411 

412 # Get a cluster 

413 pdh.setupCluster(thistask='partition') 

414 try: 

415 pdh.go() 

416 

417 # Remove original MS 

418 shutil.rmtree(tempname) 

419 

420 except Exception as instance: 

421 # Restore MS in case of error in MMS creation 

422 shutil.move(tempname, myviso) 

423 raise 

424 

425 casalog.origin('importasdm') 

426 

427 # Create a .flagversions for the MS or MMS 

428 if flagbackup: 

429 for myviso in vistoproc: 

430 if os.path.exists(myviso): 

431 aflocal.open(myviso) 

432 aflocal.saveflagversion('Original', 

433 comment='Original flags at import into CASA', 

434 merge='save') 

435 aflocal.done() 

436 

437 # Importasdm Flag Parsing 

438 if os.access(asdm + '/Flag.xml', os.F_OK): 

439 # Find Flag.xml 

440 casalog.post('Found Flag.xml in SDM') 

441 

442 # Find Antenna.xml 

443 if os.access(asdm + '/Antenna.xml', os.F_OK): 

444 casalog.post('Found Antenna.xml in SDM') 

445 

446 else: 

447 raise Exception('Failed to find Antenna.xml in SDM') 

448 

449 # Find SpectralWindow.xml 

450 if os.access(asdm + '/SpectralWindow.xml', os.F_OK): 

451 casalog.post('Found SpectralWindow.xml in SDM') 

452 

453 else: 

454 raise Exception('Failed to find SpectralWindow.xml in SDM') 

455 

456 # 

457 # Parse Flag.xml into flag dictionary 

458 # 

459 if process_flags: 

460 flagcmds = fh.parseXML(asdm, float(tbuff)) 

461 onlinekeys = flagcmds.keys() 

462 nflags = onlinekeys.__len__() 

463 

464 # Apply flags to the MS 

465 if nflags > 0: 

466 idx = 0 

467 for myviso in vistoproc: 

468 if applyflags: 

469 # Open the MS and attach it to the tool 

470 aflocal.open(myviso) 

471 # Select the data 

472 aflocal.selectdata() 

473 # Setup the agent's parameters 

474 fh.parseAgents(aflocal, flagcmds, [], True, True, '') 

475 # Initialize the agents 

476 aflocal.init() 

477 # Run the tool 

478 aflocal.run(True, True) 

479 casalog.post('Applied %s flag commands to %s'%(nflags,myviso)) 

480 # Destroy the tool and de-attach the MS 

481 aflocal.done() 

482 # Save to FLAG_CMD table. APPLIED is set to True. 

483 fh.writeFlagCommands(myviso, flagcmds, True, '', '', True) 

484 else: 

485 casalog.post('Will not apply flags to %s (apply_flags=False), use flagcmd to apply'%myviso) 

486 

487 # Write to FLAG_CMD, APPLIED is set to False 

488 fh.writeFlagCommands(myviso, flagcmds, False, '', '', True) 

489 

490 # Save the flag cmds to an ASCII file 

491 if savecmds: 

492 # Save to standard filename 

493 fh.writeFlagCommands(myviso, flagcmds, False, '', outfile[idx], False) 

494 casalog.post('Saved %s flag commands to %s'%(nflags,outfile[idx])) 

495 idx += 1 

496 

497 else: 

498 casalog.post('There are no flag commands to process') 

499 

500 else: 

501 casalog.post('There is no Flag.xml in ASDM', 'WARN') 

502 

503 

504 # CAS-7369. HISTORY should be written after createmms is tested 

505 # 

506 # Populate the HISTORY table of the MS with information about the context in which it's been created 

507 # 

508 try: 

509 mslocal = ms() 

510 param_names = importasdm.__code__.co_varnames[:importasdm.__code__.co_argcount] 

511 vars = locals( ) 

512 param_vals = [vars[p] for p in param_names] 

513 

514 for myviso in vistoproc: 

515 write_history(mslocal, myviso, 'importasdm', param_names, param_vals, casalog) 

516 

517 except Exception as instance: 

518 casalog.post("*** Error \'%s\' updating HISTORY" % (instance),'WARN') 

519 finally: 

520 if mslocal: 

521 mslocal = None