Coverage for /home/casatest/venv/lib/python3.12/site-packages/casatasks/private/task_uvcontsub_old.py: 7%

241 statements  

« prev     ^ index     » next       coverage.py v7.10.4, created at 2025-08-21 07:43 +0000

1import os 

2import re 

3import shutil 

4import time 

5import tempfile 

6import numpy as np 

7 

8from casatools import calibrater, ms, table 

9from casatasks import casalog, virtualconcat 

10 

11from .mstools import write_history 

12from .update_spw import * 

13from .parallel.parallel_data_helper import ParallelDataHelper 

14from .parallel.parallel_task_helper import ParallelTaskHelper 

15 

16mytb = table( ) 

17mycb = calibrater( ) 

18myms = ms() 

19_ms = ms() # task also referenced the old global ms object 

20 

21def uvcontsub_old(vis, field, fitspw, excludechans, combine, solint, fitorder, spw, want_cont): 

22 

23 if ParallelDataHelper.isMMSAndNotServer(vis): 

24 helper = ParallelTaskHelper('uvcontsub_old', locals()) 

25 helper._consolidateOutput = False 

26 retVar = helper.go() 

27 

28 # Gather the list of continuum subtraction-SubMSs  

29 cont_subMS_list = [] 

30 contsub_subMS_list = [] 

31 for subMS in retVar: 

32 if retVar[subMS]: 

33 cont_subMS_list.append(subMS + ".cont") 

34 contsub_subMS_list.append(subMS + ".contsub") 

35 

36 if len(cont_subMS_list) <= 0: 

37 raise ValueError("No continuum-subtracted sub-MSs for concatenation","SEVERE") 

38 

39 # We have to sort the list because otherwise it  

40 # depends on the time the engines dispatches their sub-MSs 

41 cont_subMS_list.sort() 

42 contsub_subMS_list.sort() 

43 

44 # deal with the pointing table 

45 auxfile = "uvcontsub_aux2_"+str(time.time()) 

46 pnrows = 0 

47 try: 

48 mytb.open(vis+'/POINTING') 

49 pnrows = mytb.nrows() 

50 mytb.close() 

51 if(pnrows>0): 

52 shutil.copytree(os.path.realpath(vis+'/POINTING'), auxfile) 

53 except Exception as instance: 

54 raise RuntimeError("Error handling POINTING table %s: %s" % 

55 (vis+'/POINTING',str(instance))) 

56 

57 if want_cont: 

58 try: 

59 virtualconcat(concatvis=helper._arg['vis'] + ".cont",vis=cont_subMS_list, 

60 copypointing=False) 

61 except Exception as instance: 

62 raise RuntimeError("Error concatenating continuum sub-MSs %s: %s" % 

63 (str(cont_subMS_list),str(instance))) 

64 try: 

65 virtualconcat(concatvis=helper._arg['vis'] + ".contsub",vis=contsub_subMS_list, 

66 copypointing=False) 

67 except Exception as instance: 

68 raise RuntimeError("Error concatenating continuum-subtracted sub-MSs %s: %s" % 

69 (str(contsub_subMS_list),str(instance))) 

70 

71 # Remove continuum subtraction-SubMSs 

72 if want_cont: 

73 for subMS in cont_subMS_list: 

74 if (os.system("rm -rf " + subMS ) != 0): 

75 casalog.post("Problem removing continuum sub-MS %s into working directory" % (subMS),'SEVERE') 

76 for subMS in contsub_subMS_list: 

77 if (os.system("rm -rf " + subMS ) != 0): 

78 casalog.post("Problem removing continuum-subtracted sub-MS %s into working directory" % (subMS),'SEVERE') 

79 

80 if(pnrows>0): # put back the POINTING table 

81 casalog.post("Restoring the POINTING table ...",'NORMAL') 

82 try: 

83 if want_cont: 

84 theptab = os.path.realpath(helper._arg['vis'] + ".cont/POINTING") 

85 os.system('rm -rf '+theptab) 

86 shutil.copytree(auxfile, theptab) 

87 theptab = os.path.realpath(helper._arg['vis'] + ".contsub/POINTING") 

88 os.system('rm -rf '+theptab) 

89 os.system('mv '+auxfile+' '+theptab) 

90 except Exception as instance: 

91 raise RuntimeError("Error restoring pointing table from %s: %s" % 

92 (auxfile,str(instance))) 

93 

94 # Restore origin (otherwise gcwrap shows virtualconcat) 

95 casalog.origin('uvcontsub_old') 

96 

97 return 

98 

99 # Run normal code 

100 try: 

101 casalog.origin('uvcontsub_old') 

102 

103 casalog.post('This task is deprecated and will be removed in an upcoming release.', 

104 'WARN') 

105 

106 # Get these checks done and out of the way. 

107 # This one is redundant - it is already checked at the XML level. 

108 if not os.path.isdir(vis): 

109 raise ValueError('Visibility data set not found - please verify the name') 

110 

111 # 

112 if excludechans: 

113 locfitspw=_quantityRangesToChannels(vis,field,fitspw,excludechans) 

114 casalog.post("Exclude channels in fitspw: spws:channels will be used in the fit are:%s" % locfitspw) 

115 elif fitspw.count('Hz'): 

116 locfitspw=_quantityRangesToChannels(vis,field,fitspw,excludechans) 

117 else: 

118 locfitspw=fitspw 

119 # casalog.post("locfitspw=",locfitspw) 

120 mytb.open(vis + '/SPECTRAL_WINDOW') 

121 allspw = '0~' + str(mytb.nrows() - 1) 

122 mytb.close() 

123 

124 # Verify fitspw and spw as plausible 

125 if len(locfitspw)>0: 

126 fitspwerr=subtract_spws(locfitspw,allspw) 

127 if fitspwerr: 

128 badfitspw='' 

129 for ispw in range(len(fitspwerr)): 

130 badfitspw+=str(fitspwerr.pop()) 

131 raise ValueError("fitspw contains non-existent spw(s): "+badfitspw) 

132 if len(spw)>0: 

133 spwerr=subtract_spws(spw,allspw) 

134 if spwerr: 

135 badspw='' 

136 for ispw in range(len(spwerr)): 

137 badspw+=str(spwerr.pop()) 

138 raise ValueError("spw contains non-existent spw(s): "+badspw) 

139 

140 if 'spw' not in combine: 

141 #spwmfitspw = subtract_spws(spw, fitspw) 

142 spwmfitspw = subtract_spws(spw, locfitspw) 

143 if spwmfitspw == 'UNKNOWN': 

144 #spwmfitspw = subtract_spws(allspw, fitspw) 

145 spwmfitspw = subtract_spws(allspw, locfitspw) 

146 if spwmfitspw: 

147 raise ValueError("combine must include 'spw' when the fit is being applied to spws outside fitspw.") 

148 

149 # cb will put the continuum-subtracted data in CORRECTED_DATA, so 

150 # protect vis by splitting out its relevant parts to a working copy. 

151 csvis = vis.rstrip('/') + '.contsub' 

152 

153 # The working copy will need all of the channels in fitspw + spw, so we 

154 # may or may not need to filter it down to spw at the end. 

155 #myfitspw = fitspw 

156 myfitspw = locfitspw 

157 myspw = spw 

158 

159 # We only need the spws in the union of fitspw and spw, but keep all 

160 # the channels or the weights (as used by calibrater) will be messed up. 

161 #tempspw = re.sub(r':[^,]+', '', join_spws(fitspw, spw)) 

162 tempspw = re.sub(r':[^,]+', '', join_spws(locfitspw, spw)) 

163 if tempspw == allspw: 

164 tempspw = '' 

165 if tempspw: 

166 # The split will reindex the spws. Update spw and fitspw. 

167 # Do fitspw first because the spws in spw are supposed to be 

168 # a subset of the ones in fitspw. 

169 casalog.post('split is being run internally, and the selected spws') 

170 casalog.post('will be renumbered to start from 0 in the output!') 

171 

172 # Now get myfitspw. 

173 #myfitspw = update_spwchan(vis, tempspw, fitspw) 

174 myfitspw = update_spwchan(vis, tempspw, locfitspw) 

175 myspw = update_spwchan(vis, tempspw, spw) 

176 

177 final_csvis = csvis 

178 workingdir = os.path.abspath(os.path.dirname(vis.rstrip('/'))) 

179 csvis = tempfile.mkdtemp(prefix=csvis.split('/')[-1], dir=workingdir) 

180 

181 # ms does not have a colnames method, so open vis with tb even though 

182 # it is already open with myms. Note that both use nomodify=True, 

183 # however, and no problem was revealed in testing. 

184 mytb.open(vis, nomodify=True) 

185 if 'CORRECTED_DATA' in mytb.colnames(): 

186 whichcol = 'CORRECTED_DATA' 

187 else: 

188 # DON'T remind the user that split before uvcontsub wastes time - 

189 # scratch columns will eventually go away. 

190 whichcol = 'DATA' 

191 mytb.close() 

192 

193 casalog.post('Preparing to add scratch columns.') 

194 myfield = field 

195 if field == '': 

196 myfield = '*' 

197 if myfield != '*' and set(_ms.msseltoindex(vis, 

198 field=myfield)['field']) == set(_ms.msseltoindex(vis, 

199 field='*')['field']): 

200 myfield = '*' 

201 if whichcol != 'DATA' or tempspw != '' or myfield != '*': 

202 casalog.post('splitting to ' + csvis + ' with spw="' 

203 + tempspw + '"') 

204 myms.open(vis, nomodify=True) 

205 split_result = myms.split(csvis, spw=tempspw, field=myfield, whichcol=whichcol) 

206 myms.close() 

207 # jagonzal (CAS-4113): Take care of the trivial parallelization 

208 if not split_result: 

209 msg = "MSSelectionNullSelection: %s does not have data for spw=%s, field=%s, bailing out!" % (vis,tempspw,field) 

210 shutil.rmtree(csvis) 

211 raise RuntimeError(msg) 

212 else: 

213 # This takes almost 30s/GB. (lustre, 8/2011) 

214 casalog.post('Copying ' + vis + ' to ' + csvis + ' with cp.') 

215 shutil.copytree(vis, csvis, symlinks=True, dirs_exist_ok=True) 

216 

217 # It is less confusing if we write the history now that the "root" MS 

218 # is made, but before cb adds its messages. 

219 # 

220 param_names = uvcontsub_old.__code__.co_varnames[:uvcontsub_old.__code__.co_argcount] 

221 local_vars = locals( ) 

222 param_vals = [local_vars[p] for p in param_names] 

223 

224 write_history(myms, csvis, 'uvcontsub_old', param_names, param_vals, 

225 casalog) 

226 

227 if (type(csvis) == str) and os.path.isdir(csvis): 

228 mycb.setvi(old=True,quiet=False); # old VI, for now 

229 mycb.open(csvis) 

230 else: 

231 raise RuntimeError('Visibility data set not found - please verify the name') 

232 

233 # select the data for continuum subtraction 

234 mycb.reset() 

235 mycb.selectvis(spw=myfitspw) 

236 

237 # Set up the solve 

238 amuellertab = tempfile.mkdtemp(prefix='Temp_contsub.tab', 

239 dir=workingdir) 

240 

241 mycb.setsolve(type='A', t=solint, table=amuellertab, combine=combine, 

242 fitorder=fitorder) 

243 

244 # solve for the continuum 

245 mycb.solve() 

246 

247 # subtract the continuum 

248 mycb.selectvis(spw=myspw) 

249 aspwmap=-1 

250 # if we combined on spw in solve, fanout the result with spwmap=-999; 

251 if 'spw' in combine: 

252 aspwmap = -999 

253 mycb.setapply(table=amuellertab, spwmap=aspwmap) 

254 

255 # Generate CORRECTED_DATA without continuum 

256 mycb.correct() 

257 

258 if want_cont: 

259 # Generate MODEL_DATA with only the continuum model 

260 mycb.corrupt() 

261 

262 mycb.close() 

263 

264 # Delete the temporary caltable 

265 shutil.rmtree(amuellertab) 

266 

267 # Move the line data from CORRECTED_DATA to DATA, and do any 

268 # final filtering by spw. 

269 myms.open(csvis) 

270 # Using ^ in spw is untested here! 

271 myms.split(final_csvis, spw=myspw, whichcol='corrected') 

272 myms.close() 

273 

274 #casalog.post("\"want_cont\" = \"%s\"" % want_cont, 'WARN') 

275 #casalog.post("\"csvis\" = \"%s\"" % csvis, 'WARN') 

276 if want_cont: 

277 myms.open(csvis) 

278 # No channel averaging (== skipping for fitorder == 0) is done 

279 # here, but it would be a reasonable option. The user can always 

280 # do it by running split again. 

281 myms.split(final_csvis[:-3], # .contsub -> .cont 

282 whichcol='MODEL_DATA', 

283 spw=myspw) 

284 myms.close() 

285 

286 #casalog.post("rming \"%s\"" % csvis, 'WARN') 

287 shutil.rmtree(csvis) 

288 

289 finally: 

290 mycb.close() # Harmless if cb is closed. 

291 

292 

293def _quantityRangesToChannels(vis,field,infitspw,excludechans): 

294 """ 

295 private function to convert frequnecy (in the future, velocity 

296 as well) ranges in fitspw to channel indexes. 

297 For excludeechans=True, it will select channels outside given by infitspw 

298 returns: list containing new channel ranges 

299 """ 

300 mytb.open(vis+'/SPECTRAL_WINDOW') 

301 nspw=mytb.nrows() 

302 mytb.close() 

303 

304 fullspwids=str(list(range(nspw))).strip('[,]') 

305 tql={'field':field,'spw':fullspwids} 

306 myms.open(vis) 

307 myms.msselect(tql,True) 

308 allsels=myms.msselectedindices() 

309 myms.reset() 

310 # input fitspw selection 

311 tql['spw']=infitspw 

312 myms.msselect(tql,True) 

313 usersels=myms.msselectedindices()['channel'] 

314 myms.close() 

315 # sort the arrays so that chan ranges are 

316 # in order 

317 usersels=usersels[np.lexsort((usersels[:,1],usersels[:,0]))] 

318 spwsels='' 

319 spwid=-1 

320 prevspwid=None 

321 newchanlist=[] 

322 nsels=len(usersels) 

323 # casalog.post("Usersels=",usersels) 

324 if excludechans: 

325 for isel in range(nsels): 

326 prevspwid = spwid 

327 spwid=usersels[isel][0] 

328 lochan=usersels[isel][1] 

329 hichan=usersels[isel][2] 

330 stp=usersels[isel][3] 

331 maxchanid=allsels['channel'][spwid][2] 

332 # find left and right side ranges of the selected range 

333 if spwid != prevspwid: 

334 # first line in the selected spw 

335 if lochan > 0: 

336 outloL=0 

337 outhiL=lochan-1 

338 outloR= (0 if hichan+1>=maxchanid else hichan+1) 

339 if outloR: 

340 if isel<nsels-1 and usersels[isel+1][0]==spwid: 

341 outhiR=usersels[isel+1][1]-1 

342 else: 

343 outhiR=maxchanid 

344 else: 

345 outhiR=0 # higher end of the user selected range reaches maxchanid 

346 # so no right hand side range 

347 # casalog.post("outloL,outhiL,outloR,outhiR==", outloL,outhiL,outloR,outhiR) 

348 else: 

349 # no left hand side range 

350 outloL=0 

351 outhiL=0 

352 outloR=hichan+1 

353 if isel<nsels-1 and usersels[isel+1][0]==spwid: 

354 outhiR=usersels[isel+1][1]-1 

355 else: 

356 outhiR=maxchanid 

357 else: 

358 #expect the left side range is already taken care of 

359 outloL=0 

360 outhiL=0 

361 outloR=hichan+1 

362 if outloR>=maxchanid: 

363 #No more boundaries to consider 

364 outloR=0 

365 outhiR=0 

366 else: 

367 if isel<nsels-1 and usersels[isel+1][0]==spwid: 

368 outhiR=min(usersels[isel+1][1]-1,maxchanid) 

369 else: 

370 outhiR=maxchanid 

371 if outloR > outhiR: 

372 outloR = 0 

373 outhiR = 0 

374 

375 # 

376 if (not(outloL == 0 and outhiL == 0)) and outloL <= outhiL: 

377 newchanlist.append([spwid,outloL,outhiL,stp]) 

378 if (not(outloR == 0 and outhiR == 0)) and outloR <= outhiR: 

379 newchanlist.append([spwid,outloR,outhiR,stp]) 

380 # casalog.post("newchanlist=",newchanlist) 

381 else: 

382 # excludechans=False 

383 newchanlist=usersels 

384 

385 #return newchanlist 

386 # create spw selection string from newchanlist 

387 spwstr='' 

388 for irange in range(len(newchanlist)): 

389 chanrange=newchanlist[irange] 

390 spwstr+=str(chanrange[0])+':'+str(chanrange[1])+'~'+str(chanrange[2]) 

391 if irange != len(newchanlist)-1: 

392 spwstr+=',' 

393 return spwstr