Coverage for  / home / casatest / venv / lib / python3.12 / site-packages / casatasks / private / imagerhelpers / _gclean.py: 61%

554 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2025-12-19 19:37 +0000

1# vim: syntax=python 

2######################################################################## 

3# 

4# _gclean.py 

5# 

6# Copyright (C) 2021,2022,2023 

7# Associated Universities, Inc. Washington DC, USA. 

8# 

9# This script is free software; you can redistribute it and/or modify it 

10# under the terms of the GNU Library General Public License as published by 

11# the Free Software Foundation; either version 2 of the License, or (at your 

12# option) any later version. 

13# 

14# This library is distributed in the hope that it will be useful, but WITHOUT 

15# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 

16# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 

17# License for more details. 

18# 

19# You should have received a copy of the GNU Library General Public License 

20# along with this library; if not, write to the Free Software Foundation, 

21# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. 

22# 

23# Correspondence concerning AIPS++ should be adressed as follows: 

24# Internet email: casa-feedback@nrao.edu. 

25# Postal address: AIPS++ Project Office 

26# National Radio Astronomy Observatory 

27# 520 Edgemont Road 

28# Charlottesville, VA 22903-2475 USA 

29# 

30 

31from __future__ import absolute_import 

32from casatools.typecheck import CasaValidator as _val_ctor 

33_pc = _val_ctor( ) 

34from casatools.coercetype import coerce as _coerce 

35from casatools.errors import create_error_string 

36from casatasks.private.task_logging import start_log as _start_log 

37from casatasks.private.task_logging import end_log as _end_log 

38from casatasks.private.task_logging import except_log as _except_log 

39 

40import os 

41import asyncio 

42from functools import reduce 

43import copy 

44import numpy as np 

45import shutil 

46import time 

47import subprocess 

48 

49import sys 

50 

51 

52 

53from casatasks.private import cleanhelper 

54from casatasks.private.imagerhelpers.imager_return_dict import ImagingDict, ConvergenceResult, StopCodes 

55from casatasks.private.imagerhelpers.input_parameters import ImagerParameters, sanitize_tclean_inputs 

56from casatasks import deconvolve, tclean, imstat 

57from casatasks import casalog 

58 

59### 

60### import check versions 

61### 

62_GCV001 = True 

63_GCV002 = True 

64_GCV003 = True 

65_GCV004 = True 

66 

67# from casatasks.private.imagerhelpers._gclean import gclean 

68class gclean: 

69 ''' 

70 tclean ---- Radio Interferometric Image Reconstruction 

71 

72 Form images from visibilities and reconstruct a sky model. 

73 This task handles continuum images and spectral line cubes, 

74 supports outlier fields, contains standard clean based algorithms 

75 along with algorithms for multi-scale and wideband image 

76 reconstruction, widefield imaging correcting for the w-term, 

77 full primary-beam imaging and joint mosaic imaging (with 

78 heterogeneous array support for ALMA). 

79 

80 --------- parameter descriptions --------------------------------------------- 

81 

82 vis Name(s) of input visibility file(s) 

83 default: none; 

84 example: vis='ngc5921.ms' 

85 vis=['ngc5921a.ms','ngc5921b.ms']; multiple MSs 

86 selectdata Enable data selection parameters. 

87 field to image or mosaic. Use field id(s) or name(s). 

88 ['go listobs' to obtain the list id's or names] 

89 default: ''= all fields. 

90 If field string is a non-negative integer, it is assumed to 

91 be a field index, otherwise it is assumed to be a 

92 field name. 

93 field='0~2'; field ids 0,1,2. 

94 field='0,4,5~7'; field ids 0,4,5,6,7. 

95 field='3C286,3C295'; field names 3C286 and 3C295. 

96 field = '3,4C\*'; field id 3, all names starting with 4C. 

97 For multiple MS input, a list of field strings can be used: 

98 field = ['0~2','0~4']; field ids 0-2 for the first MS and 0-4 

99 for the second. 

100 field = '0~2'; field ids 0-2 for all input MSs. 

101 spw l window/channels. 

102 NOTE: channels not selected here will contain all zeros if 

103 selected by other subparameters. 

104 default: ''=all spectral windows and channels. 

105 spw='0~2,4'; spectral windows 0,1,2,4 (all channels). 

106 spw='0:5~61'; spw 0, channels 5 to 61. 

107 spw='<2'; spectral windows less than 2 (i.e. 0,1). 

108 spw='0,10,3:3~45'; spw 0,10 all channels, and spw 3 

109 channels 3 to 45. 

110 spw='0~2:2~6'; spw 0,1,2 with channels 2 through 6 in each. 

111 For multiple MS input, a list of spw strings can be used: 

112 spw=['0','0~3']; spw ids 0 for the first MS and 0-3 for the second. 

113 spw='0~3' spw ids 0-3 for all input MS. 

114 spw='3:10~20;50~60' for multiple channel ranges within spw id 3. 

115 spw='3:10~20;50~60,4:0~30' for different channel ranges for spw ids 3 and 4. 

116 spw='0:0~10,1:20~30,2:1;2;3'; spw 0, channels 0-10, 

117 spw 1, channels 20-30, and spw 2, channels, 1,2 and 3. 

118 spw='1~4;6:15~48' for channels 15 through 48 for spw ids 1,2,3,4 and 6. 

119 timerange Range of time to select from data 

120 

121 default: '' (all); examples, 

122 timerange = 'YYYY/MM/DD/hh:mm:ss~YYYY/MM/DD/hh:mm:ss' 

123 Note: if YYYY/MM/DD is missing date defaults to first 

124 day in data set. 

125 timerange='09:14:0~09:54:0' picks 40 min on first day. 

126 timerange='25:00:00~27:30:00' picks 1 hr to 3 hr 

127 30min on NEXT day. 

128 timerange='09:44:00' pick data within one integration 

129 of time. 

130 timerange='> 10:24:00' data after this time. 

131 For multiple MS input, a list of timerange strings can be 

132 used: 

133 timerange=['09:14:0~09:54:0','> 10:24:00']. 

134 timerange='09:14:0~09:54:0''; apply the same timerange for 

135 all input MSs. 

136 uvrange Select data within uvrange (default unit is meters) 

137 default: '' (all); example: 

138 uvrange='0~1000klambda'; uvrange from 0-1000 kilo-lambda. 

139 uvrange='> 4klambda';uvranges greater than 4 kilo lambda. 

140 For multiple MS input, a list of uvrange strings can be 

141 used: 

142 uvrange=['0~1000klambda','100~1000klamda']. 

143 uvrange='0~1000klambda'; apply 0-1000 kilo-lambda for all 

144 input MSs. 

145 uvrange='0~1000'; apply 0-1000 meter for all input MSs. 

146 antenna Select data based on antenna/baseline 

147 

148 default: '' (all) 

149 If antenna string is a non-negative integer, it is 

150 assumed to be an antenna index, otherwise, it is 

151 considered an antenna name. 

152 antenna='5\&6'; baseline between antenna index 5 and 

153 index 6. 

154 antenna='VA05\&VA06'; baseline between VLA antenna 5 

155 and 6. 

156 antenna='5\&6;7\&8'; baselines 5-6 and 7-8. 

157 antenna='5'; all baselines with antenna index 5. 

158 antenna='05'; all baselines with antenna number 05 

159 (VLA old name). 

160 antenna='5,6,9'; all baselines with antennas 5,6,9 

161 index number. 

162 For multiple MS input, a list of antenna strings can be 

163 used: 

164 antenna=['5','5\&6']; 

165 antenna='5'; antenna index 5 for all input MSs. 

166 antenna='!DV14'; use all antennas except DV14. 

167 scan Scan number range 

168 

169 default: '' (all). 

170 example: scan='1~5'. 

171 For multiple MS input, a list of scan strings can be used: 

172 scan=['0~100','10~200']. 

173 scan='0~100; scan ids 0-100 for all input MSs. 

174 observation Observation ID range 

175 default: '' (all). 

176 example: observation='1~5'. 

177 intent Scan Intent(s) 

178 

179 default: '' (all). 

180 example: intent='TARGET_SOURCE'. 

181 example: intent='TARGET_SOURCE1,TARGET_SOURCE2'. 

182 example: intent='TARGET_POINTING\*'. 

183 datacolumn Data column to image (data or observed, corrected) 

184 default:'corrected' 

185 ( If 'corrected' does not exist, it will use 'data' instead ) 

186 imagename Pre-name of output images 

187 

188 example : imagename='try' 

189 

190 Output images will be (a subset of) : 

191 

192 try.psf - Point Spread Function (PSF). 

193 try.residual - Residual image. 

194 try.image - Restored image. 

195 try.model - Model image (contains only flux components). 

196 try.sumwt - Single pixel image containing sum-of-weights. 

197 (for natural weighting, sensitivity=1/sqrt(sumwt)). 

198 try.pb - Primary Beam (PB) model (values depend on the gridder used). 

199 

200 A-projection algorithms (gridder=mosaic,awproject, awp2) will 

201 compute the following images too. 

202 

203 try.weight - FT of gridded weights or the 

204 un-normalized sum of PB-square (for all pointings). 

205 Here, PB = sqrt(weight) normalized to a maximum of 1.0. 

206 

207 For multi-term wideband imaging, all relevant images above will 

208 have additional .tt0,.tt1, etc suffixes to indicate Taylor terms, 

209 plus the following extra output images. 

210 try.alpha - spectral index. 

211 try.alpha.error - estimate of error on spectral index. 

212 try.beta - spectral curvature (if nterms \> 2). 

213 

214 Tip : Include a directory name in 'imagename' for all 

215 output images to be sent there instead of the 

216 current working directory : imagename='mydir/try'. 

217 

218 Tip : Restarting an imaging run without changing 'imagename' 

219 implies continuation from the existing model image on disk. 

220 - If 'startmodel' was initially specified it needs to be set to "" 

221 for the restart run (or tclean will exit with an error message). 

222 - By default, the residual image and psf will be recomputed 

223 but if no changes were made to relevant parameters between 

224 the runs, set calcres=False, calcpsf=False to resume directly from 

225 the minor cycle without the (unnecessary) first major cycle. 

226 To automatically change 'imagename' with a numerical 

227 increment, set restart=False (see tclean docs for 'restart'). 

228 

229 Note : All imaging runs will by default produce restored images. 

230 For a niter=0 run, this will be redundant and can optionally 

231 be turned off via the 'restoration=T/F' parameter. 

232 imsize Number of pixels 

233 example: 

234 

235 imsize = [350,250]. 

236 imsize = 500 is equivalent to [500,500]. 

237 

238 To take proper advantage of internal optimized FFT routines, the 

239 number of pixels must be even and factorizable by 2,3,5 only. 

240 To find the nearest optimal imsize to that desired by the user, please use the following tool method: 

241 

242 from casatools import synthesisutils 

243 su = synthesisutils() 

244 su.getOptimumSize(345) 

245 Output : 360 

246 cell Cell size 

247 example: cell=['0.5arcsec,'0.5arcsec'] or 

248 cell=['1arcmin', '1arcmin']. 

249 cell = '1arcsec' is equivalent to ['1arcsec','1arcsec']. 

250 phasecenter Phase center of the image (string or field id); if the phasecenter is the name known major solar system object ('MERCURY', 'VENUS', 'MARS', 'JUPITER', 'SATURN', 'URANUS', 'NEPTUNE', 'PLUTO', 'SUN', 'MOON') or is an ephemerides table then that source is tracked and the background sources get smeared. There is a special case, when phasecenter='TRACKFIELD', which will use the ephemerides or polynomial phasecenter in the FIELD table of the MS's as the source center to track. 

251 

252 Note : If unspecified, tclean will use the phase-center from the first data field of the MS (or list of MSs) selected for imaging. 

253 

254 example: phasecenter='6'. 

255 phasecenter='J2000 19h30m00 -40d00m00'. 

256 phasecenter='J2000 292.5deg -40.0deg'. 

257 phasecenter='J2000 5.105rad -0.698rad'. 

258 phasecenter='ICRS 13:05:27.2780 -049.28.04.458'. 

259 phasecenter='myComet_ephem.tab'. 

260 phasecenter='MOON'. 

261 phasecenter='TRACKFIELD'. 

262 stokes Stokes Planes to make 

263 default='I'; example: stokes='IQUV'; 

264 Options: 'I','Q','U','V','IV','QU','IQ','UV','IQUV','RR','LL','XX','YY','RRLL','XXYY','pseudoI' 

265 

266 Note : Due to current internal code constraints, if any correlation pair 

267 is flagged, by default, no data for that row in the MS will be used. 

268 So, in an MS with XX,YY, if only YY is flagged, neither a 

269 Stokes I image nor an XX image can be made from those data points. 

270 In such a situation, please split out only the unflagged correlation into 

271 a separate MS, or use the option 'pseudoI'. 

272 

273 Note : The 'pseudoI' option is a partial solution, allowing Stokes I imaging 

274 when either of the parallel-hand correlations are unflagged. 

275 

276 The remaining constraints shall be removed (where logical) in a future release. 

277 projection Coordinate projection 

278 Examples : SIN, NCP. 

279 A list of supported (but untested) projections can be found here : 

280 http://casa.nrao.edu/active/docs/doxygen/html/classcasa_1_1Projection.html#a3d5f9ec787e4eabdce57ab5edaf7c0cd 

281 startmodel Name of starting model image 

282 

283 The contents of the supplied starting model image will be 

284 copied to the imagename.model before the run begins. 

285 

286 example : startmodel = 'singledish.im'. 

287 

288 For deconvolver='mtmfs', one image per Taylor term must be provided. 

289 example : startmodel = ['try.model.tt0', 'try.model.tt1']. 

290 startmodel = ['try.model.tt0'] will use a starting model only 

291 for the zeroth order term. 

292 startmodel = ['','try.model.tt1'] will use a starting model only 

293 for the first order term. 

294 

295 This starting model can be of a different image shape and size from 

296 what is currently being imaged. If so, an image regrid is first triggered 

297 to resample the input image onto the target coordinate system. 

298 

299 A common usage is to set this parameter equal to a single dish image. 

300 

301 Negative components in the model image will be included as is. 

302 

303 Note : If an error occurs during image resampling/regridding, 

304 please try using task imregrid to resample the starting model 

305 image onto a CASA image with the target shape and 

306 coordinate system before supplying it via startmodel. 

307 specmode Spectral definition mode (mfs,cube,cubedata, cubesource, mvc) 

308 

309 specmode='mfs' : Continuum imaging with only one output image channel. 

310 (mode='cont' can also be used here) 

311 

312 specmode='cube' : Spectral line imaging with one or more channels. 

313 Parameters start, width,and nchan define the spectral 

314 coordinate system and can be specified either in terms 

315 of channel numbers, frequency or velocity in whatever 

316 spectral frame is specified in 'outframe'. 

317 All internal and output images are made with outframe as the 

318 base spectral frame. However imaging code internally uses the fixed 

319 spectral frame, LSRK for automatic internal software 

320 Doppler correction, so that a spectral line observed over an 

321 extended time range will line up appropriately. 

322 Therefore the output images have additional spectral frame conversion 

323 layer in LSRK on the top the base frame. 

324 

325 

326 

327 

328 specmode='cubedata' : Spectral line imaging with one or more channels. 

329 There is no internal software Doppler correction, so 

330 a spectral line observed over an extended time range 

331 may be smeared out in frequency. There is strictly 

332 no valid spectral frame with which to associate with the 

333 output images, thus the image spectral frame will 

334 be labelled "Undefined". 

335 

336 

337 specmode='cubesource': Spectral line imaging while 

338 tracking moving source (near field or solar system 

339 objects). The velocity of the source is accounted 

340 and the frequency reported is in the source frame. 

341 As there is no "SOURCE" frame defined in CASA, 

342 the frame in the image will be labelled "REST" (but do note the 

343 velocity of a given line reported may be different from the rest frame 

344 velocity if the emission region is moving w.r.t the systemic 

345 velocity frame of the source). 

346 

347 specmode='mvc' : Multiterm continuum imaging with cube major cycles. 

348 This mode requires deconvolver='mtmfs' with nterms>1 

349 and user-set choices of 'reffreq' and 'nchan'. 

350 

351 The output images and minor cycle are similar to specmode='mfs' 

352 with deconvolver='mtmfs', but the major cycles are done in 

353 cube mode (and require a setting of 'reffreq' and 'nchan'). 

354 By default, frequency-dependent primary beam correction is 

355 applied to each channel, before being combined across frequency 

356 to make the inputs to the 'mtmfs' deconvolver. This results in 

357 implicit wideband pb-correction, with the deconvolver seeing only 

358 the sky spectral structure. 

359 

360 Note : There is currently no option to turn off wideband pb correction 

361 as part of the flat-sky normalization between the major and minor cycles. 

362 Therefore, 'mvc' with the 'standard' and 'wproject' gridders will also apply 

363 pblimits per channel, masking all regions outside of pblimit. 

364 An option to retain sources outside the pblimit will be added in a future release. 

365 

366 Note : Below is some guidance for choosing 'nchan' and 'reffreq' : 

367 

368 The cube produced by the major cycle is used in a linear least square fits for Taylor 

369 polynomials per pixel. Therefore, one only needs as many channels in the cube, as 

370 required for an accurate polynomial fit for sources that have the strongest 

371 spectral structure. 

372 

373 In general, 'nchan' needs to be greater than or equal to 'nterms', and the 

374 frequency range selected by the data will be evenly split into nchan channels. 

375 For a low-order polynomial fit, only a small number (around 10) 

376 channels are typically needed (for VLA/ALMA bandwidth ratios). 

377 'nchan=-1' applies a heuristic that results in a default of 10 cube channels 

378 for a 2:1 bandwidth ratio. 

379 

380 nchan = MAX( bandwidth/(0.1*startfreq) , nterms+1 ) 

381 

382 Note: When running in parallel, the nchan selected may limit the speedup if it 

383 is smaller than the number of processes used. 

384 

385 The 'reffreq' is the reference frequency used for the Taylor polynomial expansion. 

386 By default, in specmode='mvc', reffreq is set to the middle of the selected 

387 frequency range. 

388 reffreq Reference frequency of the output image coordinate system. 

389 

390 Example : reffreq='1.5GHz' as a string with units. 

391 

392 By default, it is calculated as the middle of the selected frequency range. 

393 

394 For deconvolver='mtmfs' the Taylor expansion is also done about 

395 this specified reference frequency. 

396 nchan Number of channels in the output image. 

397 For default (=-1), the number of channels will be automatically determined 

398 based on data selected by 'spw' with 'start' and 'width'. 

399 It is often easiest to leave nchan at the default value. 

400 example: nchan=100 

401 start First channel (e.g. start=3,start=\'1.1GHz\',start=\'15343km/s\') 

402 of output cube images specified by data channel number (integer), 

403 velocity (string with a unit), or frequency (string with a unit). 

404 Default:''; The first channel is automatically determined based on 

405 the 'spw' channel selection and 'width'. 

406 channels in 'spw'. 

407 Since the integer number in 'start' represents the data channel number, 

408 when the channel number is used along with the spectral window id selection 

409 in 'spw', 'start' specified as an integer should be carefully set otherwise 

410 it may result in the blank image channels if the 'start' channel (i.e. absolute 

411 channel number) is outside of the channel range specified in 'spw'. 

412 In such a case, 'start' can be left as a default (='') to ensure 

413 matching with the data spectral channel selection. 

414 For specmode='cube', when velocity or frequency is used it is 

415 interpreted with the frame defined in outframe. [The parameters of 

416 the desired output cube can be estimated by using the 'transform' 

417 functionality of 'plotms']. 

418 examples: start='5.0km/s'; 1st channel, 5.0km/s in outframe. 

419 start='22.3GHz'; 1st channel, 22.3GHz in outframe. 

420 width Channel width (e.g. width=2,width=\'0.1MHz\',width=\'10km/s\') of output cube images 

421 specified by data channel number (integer), velocity (string with a unit), or 

422 or frequency (string with a unit). 

423 Default:''; data channel width. 

424 The sign of width defines the direction of the channels to be incremented. 

425 For width specified in velocity or frequency with '-' in front gives image channels in 

426 decreasing velocity or frequency, respectively. 

427 For specmode='cube', when velocity or frequency is used it is interpreted with 

428 the reference frame defined in outframe. 

429 examples: width='2.0km/s'; results in channels with increasing velocity. 

430 width='-2.0km/s'; results in channels with decreasing velocity. 

431 width='40kHz'; results in channels with increasing frequency. 

432 width=-2; results in channels averaged of 2 data channels incremented from 

433 high to low channel numbers. 

434 outframe Spectral reference frame in which to interpret \'start\' and \'width\' 

435 Options: '','LSRK','LSRD','BARY','GEO','TOPO','GALACTO','LGROUP','CMB' 

436 example: outframe='bary' for Barycentric frame. 

437 

438 REST -- Rest frequency. 

439 LSRD -- Local Standard of Rest (J2000). 

440 -- as the dynamical definition (IAU, [9,12,7] km/s in galactic coordinates). 

441 LSRK -- LSR as a kinematical (radio) definition. 

442 -- 20.0 km/s in direction ra,dec = [270,+30] deg (B1900.0). 

443 BARY -- Barycentric (J2000). 

444 GEO --- Geocentric. 

445 TOPO -- Topocentric. 

446 GALACTO -- Galacto centric (with rotation of 220 km/s in direction l,b = [90,0] deg. 

447 LGROUP -- Local group velocity -- 308km/s towards l,b = [105,-7] deg (F. Ghigo). 

448 CMB -- CMB velocity -- 369.5km/s towards l,b = [264.4, 48.4] deg (F. Ghigo). 

449 DEFAULT = LSRK. 

450 veltype Velocity type (radio, z, ratio, beta, gamma, optical) 

451 For 'start' and/or 'width' specified in velocity, specifies the velocity definition 

452 Options: 'radio','optical','z','beta','gamma','optical' 

453 NOTE: the viewer always defaults to displaying the 'radio' frame, 

454 but that can be changed in the position tracking pull down. 

455 

456 The different types (with F = f/f0, the frequency ratio), are: 

457 

458 Z = (-1 + 1/F). 

459 RATIO = (F) \*. 

460 RADIO = (1 - F). 

461 OPTICAL == Z. 

462 BETA = ((1 - F^2)/(1 + F^2)). 

463 GAMMA = ((1 + F^2)/2F) \*. 

464 RELATIVISTIC == BETA (== v/c). 

465 DEFAULT == RADIO. 

466 Note that the ones with an '\*' have no real interpretation 

467 (although the calculation will proceed) if given as a velocity. 

468 restfreq List of rest frequencies or a rest frequency in a string. 

469 Specify rest frequency to use for output image. 

470 

471 Currently it uses the first rest frequency in the list for translation of 

472 velocities. The list will be stored in the output images. 

473 Default: []; look for the rest frequency stored in the MS, if not available, 

474 use center frequency of the selected channels. 

475 examples: restfreq=['1.42GHz']. 

476 restfreq='1.42GHz'. 

477 interpolation Spectral interpolation (nearest,linear,cubic) 

478 

479 Interpolation rules to use when binning data channels onto image channels 

480 and evaluating visibility values at the centers of image channels. 

481 

482 Note : 'linear' and 'cubic' interpolation requires data points on both sides of 

483 each image frequency. Errors are therefore possible at edge channels, or near 

484 flagged data channels. When image channel width is much larger than the data 

485 channel width there is nothing much to be gained using linear or cubic thus 

486 not worth the extra computation involved. 

487 perchanweightdensity When calculating weight density for Briggs 

488 style weighting in a cube, this parameter 

489 determines whether to calculate the weight 

490 density for each channel independently 

491 (the default, True) 

492 or a common weight density for all of the selected 

493 data. This parameter has no 

494 meaning for continuum (specmode='mfs') imaging 

495 or for natural and radial weighting schemes. 

496 For cube imaging 

497 perchanweightdensity=True is a recommended 

498 option that provides more uniform 

499 sensitivity per channel for cubes, but with 

500 generally larger psfs than the 

501 perchanweightdensity=False (prior behavior) 

502 option. When using Briggs style weight with 

503 perchanweightdensity=True, the imaging weight 

504 density calculations use only the weights of 

505 data that contribute specifically to that 

506 channel. On the other hand, when 

507 perchanweightdensity=False, the imaging 

508 weight density calculations sum all of the 

509 weights from all of the data channels 

510 selected whose (u,v) falls in a given uv cell 

511 on the weight density grid. Since the 

512 aggregated weights, in any given uv cell, 

513 will change depending on the number of 

514 channels included when imaging, the psf 

515 calculated for a given frequency channel will 

516 also necessarily change, resulting in 

517 variability in the psf for a given frequency 

518 channel when perchanweightdensity=False. In 

519 general, perchanweightdensity=False results 

520 in smaller psfs for the same value of 

521 robustness compared to 

522 perchanweightdensity=True, but the rms noise 

523 as a function of channel varies and increases 

524 toward the edge channels; 

525 perchanweightdensity=True provides more 

526 uniform sensitivity per channel for 

527 cubes. This may make it harder to find 

528 estimates of continuum when 

529 perchanweightdensity=False. If you intend to 

530 image a large cube in many smaller subcubes 

531 and subsequently concatenate, it is advisable 

532 to use perchanweightdensity=True to avoid 

533 surprisingly varying sensitivity and psfs 

534 across the concatenated cube. 

535 gridder Gridding options (standard, wproject, widefield, mosaic, awproject, awp2, awphpg) 

536 

537 

538 The following options choose different gridding convolution 

539 functions for the process of convolutional resampling of the measured 

540 visibilities onto a regular uv-grid prior to an inverse FFT. 

541 Model prediction (degridding) also uses these same functions. 

542 Several wide-field effects can be accounted for via careful choices of 

543 convolution functions. Gridding (degridding) runtime will rise in 

544 proportion to the support size of these convolution functions (in uv-pixels). 

545 

546 standard : Prolate Spheroid with 7x7 uv pixel support size. 

547 

548 [ This mode can also be invoked using 'ft' or 'gridft' ] 

549 

550 wproject : W-Projection algorithm to correct for the widefield 

551 non-coplanar baseline effect. [Cornwell et.al 2008] 

552 

553 wprojplanes is the number of distinct w-values at 

554 which to compute and use different gridding convolution 

555 functions (see help for wprojplanes). 

556 Convolution function support size can range 

557 from 5x5 to few 100 x few 100. 

558 

559 [ This mode can also be invoked using 'wprojectft' ] 

560 

561 widefield : Facetted imaging with or without W-Projection per facet. 

562 

563 A set of facets x facets subregions of the specified image 

564 are gridded separately using their respective phase centers 

565 (to minimize max W). Deconvolution is done on the joint 

566 full size image, using a PSF from the first subregion. 

567 

568 wprojplanes=1 : standard prolate spheroid gridder per facet. 

569 wprojplanes > 1 : W-Projection gridder per facet. 

570 nfacets=1, wprojplanes > 1 : Pure W-Projection and no facetting. 

571 nfacets=1, wprojplanes=1 : Same as standard,ft,gridft. 

572 

573 A combination of facetting and W-Projection is relevant only for 

574 very large fields of view. (In our current version of tclean, this 

575 combination runs only with parallel=False. 

576 

577 mosaic : A-Projection with azimuthally symmetric beams without 

578 sidelobes, beam rotation or squint correction. 

579 Gridding convolution functions per visibility are computed 

580 from FTs of PB models per antenna. 

581 This gridder can be run on single fields as well as mosaics. 

582 

583 VLA : PB polynomial fit model (Napier and Rots, 1982). 

584 EVLA : PB polynomial fit model (Perley, 2015). 

585 ALMA : Airy disks for a 10.7m dish (for 12m dishes) and 

586 6.25m dish (for 7m dishes) each with 0.75m 

587 blockages (Hunter/Brogan 2011). Joint mosaic 

588 imaging supports heterogeneous arrays for ALMA. 

589 

590 Typical gridding convolution function support sizes are 

591 between 7 and 50 depending on the desired 

592 accuracy (given by the uv cell size or image field of view). 

593 

594 [ This mode can also be invoked using 'mosaicft' or 'ftmosaic' ] 

595 

596 awproject : A-Projection with azimuthally asymmetric beams and 

597 including beam rotation, squint correction, 

598 conjugate frequency beams and W-projection. 

599 [Bhatnagar et.al, 2008] 

600 

601 Gridding convolution functions are computed from 

602 aperture illumination models per antenna and optionally 

603 combined with W-Projection kernels and a prolate spheroid. 

604 This gridder can be run on single fields as well as mosaics. 

605 

606 VLA : Uses ray traced model (VLA and EVLA) including feed 

607 leg and subreflector shadows, off-axis feed location 

608 (for beam squint and other polarization effects), and 

609 a Gaussian fit for the feed beams (Brisken 2009) 

610 ALMA : Similar ray-traced model as above (but the correctness 

611 of its polarization properties remains un-verified). 

612 

613 Typical gridding convolution function support sizes are 

614 between 7 and 50 depending on the desired 

615 accuracy (given by the uv cell size or image field of view). 

616 When combined with W-Projection they can be significantly larger. 

617 

618 [ This mode can also be invoked using 'awprojectft' ] 

619 

620 

621 awp2 : A-Projection with azimuthally asymmetric beams and 

622 including beam rotation, squint correction and W-projection. 

623 [Bhatnagar et.al, 2008] 

624 

625 Gridding convolution functions are computed from 

626 aperture illumination models (assuming similar antennas) and optionally 

627 combined with W-Projection kernels. 

628 This gridder can be run on single fields as well as mosaics. 

629 The other sub-parameters that are of significance when using this gridder 

630 are wprojplanes, computepastep, mosweight, usepointing, pblimit and normtype. 

631 

632 Only supports VLA : Uses ray traced model (VLA and EVLA) including feed 

633 leg and subreflector shadows, off-axis feed location 

634 (for beam squint and other polarization effects), and 

635 a Gaussian fit for the feed beams (Ref: Brisken 2009) 

636 

637 For squint correction the value passed in computepastep has to be smaller than 180. 

638 Anything larger awp2 will use an average of LL and RR beams. If computepastep=5, for 

639 e.g., PB every 5 degrees, over the range of parallactic angle covered by the data, will be calculated 

640 and the nearest beam to every integration will be used to correct for the squint between the L and R beams. 

641 

642 NOTE : For mtmfs with nterms >1 and using awp2 gridder, for accurate results always use specmode="mvc" 

643 as awp2 with specmode="mfs" does not use conjugate beams to remove the spectral 

644 index of the primary beam. 

645 

646 awphpg : Implementation of the high performance gridder (HPG; Pokorny, ngVLA Computing Memo #5). 

647 For CASA 6.7.0 this mode is only available on the internal VLASS release of CASA. 

648 It will be made available for general use in a future CASA release. 

649 

650 

651 imagemosaic : (untested implementation). 

652 

653 Grid and iFT each pointing separately and combine the 

654 images as a linear mosaic (weighted by a PB model) in 

655 the image domain before a joint minor cycle. 

656 

657 VLA/ALMA PB models are same as for gridder='mosaicft'. 

658 

659 ------ Notes on PB models : 

660 

661 (1) Several different sources of PB models are used in the modes 

662 listed above. This is partly for reasons of algorithmic flexibility 

663 and partly due to the current lack of a common beam model 

664 repository or consensus on what beam models are most appropriate. 

665 

666 (2) For ALMA and gridder='mosaic', ray-traced (TICRA) beams 

667 are also available via the vpmanager tool. 

668 For example, call the following before the tclean run. 

669 vp.setpbimage(telescope="ALMA", 

670 compleximage='/home/casa/data/trunk/alma/responses/ALMA_0_DV__0_0_360_0_45_90_348.5_373_373_GHz_ticra2007_VP.im', 

671 antnames=['DV'+'%02d'%k for k in range(25)]) 

672 vp.saveastable('mypb.tab') 

673 Then, supply vptable='mypb.tab' to tclean. 

674 ( Currently this will work only for non-parallel runs ) 

675 

676 

677 ------ Note on PB masks : 

678 

679 In tclean, A-Projection gridders (mosaic, awproject, and awp2) produce a 

680 .pb image and use the 'pblimit' subparameter to decide normalization 

681 cutoffs and construct an internal T/F mask in the .pb and .image images. 

682 However, this T/F mask cannot directly be used during deconvolution 

683 (which needs a 1/0 mask). There are two options for making a pb based 

684 deconvolution mask. 

685 -- Run tclean with niter=0 to produce the .pb, construct a 1/0 image 

686 with the desired threshold (using ia.open('newmask.im'); 

687 ia.calc('iif("xxx.pb">0.3,1.0,0.0)');ia.close() for example), 

688 and supply it via the 'mask' parameter in a subsequent run 

689 (with calcres=F and calcpsf=F to restart directly from the minor cycle). 

690 -- Run tclean with usemask='pb' for it to automatically construct 

691 a 1/0 mask from the internal T/F mask from .pb at a fixed 0.2 threshold. 

692 

693 

694 ----- Making PBs for gridders other than mosaic, awproject, awp2 

695 

696 After the PSF generation, a PB is constructed using the same 

697 models used in gridder='mosaic' but just evaluated in the image 

698 domain without consideration to weights. 

699 facets Number of facets on a side 

700 

701 A set of (facets x facets) subregions of the specified image 

702 are gridded separately using their respective phase centers 

703 (to minimize max W). Deconvolution is done on the joint 

704 full size image, using a PSF from the first subregion/facet. 

705 

706 In our current version of tclean, facets>1 may be used only 

707 with parallel=False. 

708 psfphasecenter For mosaic use psf centered on this 

709 optional direction. You may need to use 

710 this if for example the mosaic does not 

711 have any pointing in the center of the 

712 image. Another reason; as the psf is 

713 approximate for a mosaic, this may help 

714 to deconvolve a non central bright source 

715 well and quickly. 

716 

717 example: 

718 

719 psfphasecenter='6' #center psf on field 6. 

720 psfphasecenter='J2000 19h30m00 -40d00m00'. 

721 psfphasecenter='J2000 292.5deg -40.0deg'. 

722 psfphasecenter='J2000 5.105rad -0.698rad'. 

723 psfphasecenter='ICRS 13:05:27.2780 -049.28.04.458'. 

724 wprojplanes Number of distinct w-values at which to compute and use different 

725 gridding convolution functions for W-Projection 

726 

727 An appropriate value of wprojplanes depends on the presence/absence 

728 of a bright source far from the phase center, the desired dynamic 

729 range of an image in the presence of a bright far out source, 

730 the maximum w-value in the measurements, and the desired trade off 

731 between accuracy and computing cost. 

732 

733 As a (rough) guide, VLA L-Band D-config may require a 

734 value of 128 for a source 30arcmin away from the phase 

735 center. A-config may require 1024 or more. To converge to an 

736 appropriate value, try starting with 128 and then increasing 

737 it if artifacts persist. W-term artifacts (for the VLA) typically look 

738 like arc-shaped smears in a synthesis image or a shift in source 

739 position between images made at different times. These artifacts 

740 are more pronounced the further the source is from the phase center. 

741 

742 There is no harm in simply always choosing a large value (say, 1024) 

743 but there will be a significant performance cost to doing so, especially 

744 for gridder='awproject' where it is combined with A-Projection. 

745 

746 wprojplanes=-1 is an option for gridder='widefield' or 'wproject' 

747 in which the number of planes is automatically computed. 

748 vptable vpmanager 

749 

750 vptable="" : Choose default beams for different telescopes. 

751 ALMA : Airy disks. 

752 EVLA : old VLA models. 

753 

754 Other primary beam models can be chosen via the vpmanager tool. 

755 

756 Step 1 : Set up the vpmanager tool and save its state in a table. 

757 

758 vp.setpbpoly(telescope='EVLA', coeff=[1.0, -1.529e-3, 8.69e-7, -1.88e-10]) 

759 vp.saveastable('myvp.tab') 

760 

761 Step 2 : Supply the name of that table in tclean. 

762 

763 tclean(....., vptable='myvp.tab',....) 

764 

765 Please see the documentation for the vpmanager for more details on how to 

766 choose different beam models. Work is in progress to update the defaults 

767 for EVLA and ALMA. 

768 

769 Note : AWProjection currently does not use this mechanism to choose 

770 beam models. It instead uses ray-traced beams computed from 

771 parameterized aperture illumination functions, which are not 

772 available via the vpmanager. So, gridder='awproject' does not allow 

773 the user to set this parameter. 

774 mosweight When doing Brigg's style weighting (including uniform) to perform the weight density calculation for each field indepedently if True. If False the weight density is calculated from the average uv distribution of all the fields. 

775 aterm Use aperture illumination functions during gridding. 

776 

777 This parameter turns on the A-term of the AW-Projection gridder. 

778 Gridding convolution functions are constructed from aperture illumination 

779 function models of each antenna. 

780 psterm Include the Prolate Spheroidal (PS) funtion as the anti-aliasing 

781 operator in the gridding convolution functions used for gridding. 

782 

783 Setting this parameter to true is necessary when aterm is set to 

784 false. It can be set to false when aterm is set to true, though 

785 with this setting effects of aliasing may be there in the image, 

786 particularly near the edges. 

787 

788 When set to true, the .pb images will contain the fourier transform 

789 of the of the PS funtion. 

790 

791 For more information on the functional 

792 effects of the psterm, aterm and wprojplanes settings, see the 

793 'Wide-field Imaging' pages in CASA Docs (https://casadocs.readthedocs.io). 

794 wbawp Use frequency dependent A-terms. 

795 Scale aperture illumination functions appropriately with frequency 

796 when gridding and combining data from multiple channels. 

797 conjbeams Use conjugate frequency for wideband A-terms. 

798 

799 While gridding data from one frequency channel, choose a convolution 

800 function from a 'conjugate' frequency such that the resulting baseline 

801 primary beam is approximately constant across frequency. For a system in 

802 which the primary beam scales with frequency, this step will eliminate 

803 instrumental spectral structure from the measured data and leave only the 

804 sky spectrum for the minor cycle to model and reconstruct [Bhatnagar et al., ApJ, 2013]. 

805 

806 As a rough guideline for when this is relevant, a source at the half power 

807 point of the PB at the center frequency will see an artificial spectral 

808 index of -1.4 due to the frequency dependence of the PB [Sault and Wieringa, 1994]. 

809 If left uncorrected during gridding, this spectral structure must be modeled 

810 in the minor cycle (using the mtmfs algorithm) to avoid dynamic range limits 

811 (of a few hundred for a 2:1 bandwidth). 

812 This works for specmode='mfs' and its value is ignored for cubes. 

813 cfcache Convolution function cache directory name. 

814 

815 Name of a directory in which to store gridding convolution functions. 

816 This cache is filled at the beginning of an imaging run. This step can be time 

817 consuming but the cache can be reused across multiple imaging runs that 

818 use the same image parameters (cell size, image size , spectral data 

819 selections, wprojplanes, wbawp, psterm, aterm). The effect of the wbawp, 

820 psterm and aterm settings is frozen-in in the cfcache. Using an existing cfcache 

821 made with a different setting of these parameters will not reflect the current 

822 settings. 

823 

824 In a parallel execution, the construction of the cfcache is also parallelized 

825 and the time to compute scales close to linearly with the number of compute 

826 cores used. With the re-computation of Convolution Functions (CF) due to PA 

827 rotation turned-off (the computepastep parameter), the total number of in the 

828 cfcache can be computed as [No. of wprojplanes x No. of selected spectral windows x 4] 

829 

830 By default, cfcache = imagename + '.cf' 

831 usepointing The usepointing flag informs the gridder that it should utilize the pointing table 

832 to use the correct direction in which the antenna is pointing with respect to the pointing phasecenter. 

833 computepastep Parallactic angle interval after the AIFs are recomputed (deg). 

834 

835 This parameter controls the accuracy of the aperture illumination function 

836 used with AProjection for alt-az mount dishes where the AIF rotates on the 

837 sky as the synthesis image is built up. Once the PA in the data changes by 

838 the given interval, AIFs are re-computed at the new PA. 

839 

840 A value of 360.0 deg (the default) implies no re-computation due to PA rotation. 

841 AIFs are computed for the PA value of the first valid data received and used for 

842 all of the data. 

843 

844 For gridder=awp2 a value of 180.0 deg or larger implies no squint correction will be 

845 attempted i.e an average beam of the left hand and right hand polarization will be calculated 

846 rotatepastep Parallactic angle interval after which the nearest AIF is rotated (deg) 

847 

848 Instead of recomputing the AIF for every timestep's parallactic angle, 

849 the nearest existing AIF is used and rotated 

850 after the PA changed by rotatepastep value. 

851 

852 A value of 360.0 deg (the default) disables rotation of the AIF. 

853 

854 For example, computepastep=360.0 and rotatepastep=5.0 will compute 

855 the AIFs at only the starting parallactic angle and all other timesteps will 

856 use a rotated version of that AIF at the nearest 5.0 degree point. 

857 pointingoffsetsigdev Corrections for heterogenous and time-dependent pointing 

858 offsets via AWProjection are controlled by this parameter. 

859 It is a vector of 2 ints or doubles each of which is interpreted 

860 in units of arcsec. Based on the first threshold, a clustering 

861 algorithm is applied to entries from the POINTING subtable 

862 of the MS to determine how distinct antenna groups for which 

863 the pointing offset must be computed separately. The second 

864 number controls how much a pointing change across time can 

865 be ignored and after which an antenna rebinning is required. 

866 

867 

868 Note : The default value of this parameter is [], due a programmatic constraint. 

869 If run with this value, it will internally pick [600,600] and exercise the 

870 option of using large tolerances (10arcmin) on both axes. Please choose 

871 a setting explicitly for runs that need to use this parameter. 

872 

873 Note : This option is available only for gridder='awproject' and usepointing=True and 

874 and has been validated primarily with VLASS on-the-fly mosaic data 

875 where POINTING subtables have been modified after the data are recorded. 

876 

877 

878 Examples of parameter usage : 

879 

880 [100.0,100.0] : Pointing offsets of 100 arcsec or less are considered 

881 small enough to be ignored. Using large values for both 

882 indicates a homogeneous array. 

883 

884 

885 [10.0, 100.0] : Based on entries in the POINTING subtable, antennas 

886 are grouped into clusters based on a 10arcsec bin size. 

887 All antennas in a bin are given a pointing offset calculated 

888 as the average of the offsets of all antennas in the bin. 

889 On the time axis, offset changes upto 100 arcsec will be ignored. 

890 

891 [10.0,10.0] : Calculate separate pointing offsets for each antenna group 

892 (with a 10 arcsec bin size). As a function of time, recalculate 

893 the antenna binning if the POINTING table entries change by 

894 more than 10 arcsec w.r.to the previously computed binning. 

895 

896 [1.0, 1.0] : Tight tolerances will imply a fully heterogenous situation where 

897 each antenna gets its own pointing offset. Also, time-dependent 

898 offset changes greater than 1 arcsec will trigger recomputes of 

899 the phase gradients. This is the most general situation and is also 

900 the most expensive option as it constructs and uses separate 

901 phase gradients for all baselines and timesteps. 

902 

903 For VLASS 1.1 data with two kinds of pointing offsets, the recommended 

904 setting is [ 30.0, 30.0 ]. 

905 

906 For VLASS 1.2 data with only the time-dependent pointing offsets, the 

907 recommended setting is [ 300.0, 30.0 ] to turn off the antenna grouping 

908 but to retain the time dependent corrections required from one timestep 

909 to the next. 

910 pblimit PB gain level at which to cut off normalizations. 

911 

912 Divisions by .pb during normalizations have a cut off at a .pb gain 

913 level given by pblimit. Outside this limit, image values are set to zero. 

914 Additionally, by default, an internal T/F mask is applied to the .pb, .image and 

915 .residual images to mask out (T) all invalid pixels outside the pblimit area. 

916 

917 Note : This internal T/F mask cannot be used as a deconvolution mask. 

918 To do so, please follow the steps listed above in the Notes for the 

919 'gridder' parameter. 

920 

921 Note : To prevent the internal T/F mask from appearing in anything other 

922 than the .pb and .image.pbcor images, 'pblimit' can be set to a 

923 negative number. 

924 The absolute value will still be used as a valid 'pblimit' for normalization 

925 purposes. So, for example, pick pblimit=-0.1 (and not pblimit=-1). 

926 A tclean restart using existing output images on disk that already 

927 have this T/F mask in the .residual and .image but only pblimit set 

928 to a negative value, will remove this mask after the next major cycle. 

929 

930 Note : An existing internal T/F mask may be removed from an image as 

931 follows (without needing to re-run tclean itself). 

932 ia.open('test.image'); 

933 ia.maskhandler(op='set', name=''); 

934 ia.done() 

935 normtype Normalization type (flatnoise, flatsky, pbsquare). 

936 

937 Gridded (and FT'd) images represent the PB-weighted sky image. 

938 Qualitatively it can be approximated as two instances of the PB 

939 applied to the sky image (one naturally present in the data 

940 and one introduced during gridding via the convolution functions). 

941 

942 xxx.weight : Weight image approximately equal to sum ( square ( pb ) ) 

943 xxx.pb : Primary beam calculated as sqrt ( xxx.weight ) 

944 

945 normtype='flatnoise' : Divide the raw image by sqrt(.weight) so that 

946 the input to the minor cycle represents the 

947 product of the sky and PB. The noise is 'flat' 

948 across the region covered by each PB. 

949 

950 normtype='flatsky' : Divide the raw image by .weight so that the input 

951 to the minor cycle represents only the sky. 

952 The noise is higher in the outer regions of the 

953 primary beam where the sensitivity is low. 

954 

955 normtype='pbsquare' : No normalization after gridding and FFT. 

956 The minor cycle sees the sky times pb square 

957 deconvolver Name of minor cycle algorithm (hogbom,clark,multiscale,mtmfs,mem,clarkstokes,asp) 

958 

959 Each of the following algorithms operate on residual images and PSFs 

960 from the gridder and produce output model and restored images. 

961 Minor cycles stop and a major cycle is triggered when cyclethreshold 

962 or cycleniter are reached. For all methods, components are picked from 

963 the entire extent of the image or (if specified) within a mask. 

964 

965 hogbom : An adapted version of Hogbom Clean [Hogbom, 1974]. 

966 - Find the location of the peak residual. 

967 - Add this delta function component to the model image. 

968 - Subtract a scaled and shifted PSF of the same size as the image 

969 from regions of the residual image where the two overlap. 

970 - Repeat. 

971 

972 clark : An adapted version of Clark Clean [Clark, 1980]. 

973 - Find the location of max(I^2+Q^2+U^2+V^2). 

974 - Add delta functions to each stokes plane of the model image. 

975 - Subtract a scaled and shifted PSF within a small patch size 

976 from regions of the residual image where the two overlap. 

977 - After several iterations trigger a Clark major cycle to subtract 

978 components from the visibility domain, but without de-gridding. 

979 - Repeat. 

980 

981 ( Note : 'clark' maps to imagermode='' in the old clean task. 

982 'clark_exp' is another implementation that maps to 

983 imagermode='mosaic' or 'csclean' in the old clean task 

984 but the behavior is not identical. For now, please 

985 use deconvolver='hogbom' if you encounter problems. ) 

986 

987 clarkstokes : Clark Clean operating separately per Stokes plane. 

988 

989 (Note : 'clarkstokes_exp' is an alternate version. See above.) 

990 

991 multiscale : MultiScale Clean [Cornwell, 2008]. 

992 - Smooth the residual image to multiple scale sizes. 

993 - Find the location and scale at which the peak occurs. 

994 - Add this multiscale component to the model image. 

995 - Subtract a scaled,smoothed,shifted PSF (within a small 

996 patch size per scale) from all residual images. 

997 - Repeat from step 2. 

998 

999 mtmfs : Multi-term (Multi Scale) Multi-Frequency Synthesis [Rau and Cornwell, 2011]. 

1000 - Smooth each Taylor residual image to multiple scale sizes. 

1001 - Solve a NTxNT system of equations per scale size to compute 

1002 Taylor coefficients for components at all locations. 

1003 - Compute gradient chi-square and pick the Taylor coefficients 

1004 and scale size at the location with maximum reduction in 

1005 chi-square. 

1006 - Add multi-scale components to each Taylor-coefficient 

1007 model image. 

1008 - Subtract scaled,smoothed,shifted PSF (within a small patch size 

1009 per scale) from all smoothed Taylor residual images. 

1010 - Repeat from step 2. 

1011 

1012 

1013 mem : Maximum Entropy Method [Cornwell and Evans, 1985]. 

1014 - Iteratively solve for values at all individual pixels via the 

1015 MEM method. It minimizes an objective function of 

1016 chi-square plus entropy (here, a measure of difference 

1017 between the current model and a flat prior model). 

1018 

1019 (Note : This MEM implementation is not very robust. 

1020 Improvements will be made in the future.) 

1021 

1022 asp : Adaptive Scale Pixel algorithm [Bhatnagar and Cornwell, 2004]. 

1023 - Define a set of initial scales defined as 0, W, 2W 4W and 8W. 

1024 where W is a 2D Gaussian fitting width to the PSF. 

1025 - Smooth the residual image by a Gaussian beam at initial scales. 

1026 - Search for the global peak (F) among these smoothed residual images. 

1027 - form an active Aspen set: amplitude(F), amplitude location(x,y). 

1028 - Optimize the Aspen set by minimizing the objective function RI-Aspen*PSF, 

1029 where RI is the residual image and * is the convulition operation. 

1030 - Compute the model image and update the residual image 

1031 - Repeat from step 2 

1032 scales List of scale sizes (in pixels) for multi-scale and mtmfs algorithms. 

1033 --> scales=[0,6,20] 

1034 This set of scale sizes should represent the sizes 

1035 (diameters in units of number of pixels) 

1036 of dominant features in the image being reconstructed. 

1037 

1038 The smallest scale size is recommended to be 0 (point source), 

1039 the second being the size of the synthesized beam and the third being 3-5 

1040 times the synthesized beam, etc. For example, if the synthesized 

1041 beam is 10" FWHM and cell=2",try scales = [0,5,15]. 

1042 

1043 For numerical stability, the largest scale must be 

1044 smaller than the image (or mask) size and smaller than or 

1045 comparable to the scale corresponding to the lowest measured 

1046 spatial frequency (as a scale size much larger than what the 

1047 instrument is sensitive to is unconstrained by the data making 

1048 it harder to recover from errors during the minor cycle). 

1049 nterms Number of Taylor coefficients in the spectral model. 

1050 

1051 - nterms=1 : Assume flat spectrum source. 

1052 - nterms=2 : Spectrum is a straight line with a slope. 

1053 - nterms=N : A polynomial of order N-1. 

1054 

1055 From a Taylor expansion of the expression of a power law, the 

1056 spectral index is derived as alpha = taylorcoeff_1 / taylorcoeff_0. 

1057 

1058 Spectral curvature is similarly derived when possible. 

1059 

1060 The optimal number of Taylor terms depends on the available 

1061 signal to noise ratio, bandwidth ratio, and spectral shape of the 

1062 source as seen by the telescope (sky spectrum x PB spectrum). 

1063 

1064 nterms=2 is a good starting point for wideband EVLA imaging 

1065 and the lower frequency bands of ALMA (when fractional bandwidth 

1066 is greater than 10%) and if there is at least one bright source for 

1067 which a dynamic range of greater than few 100 is desired. 

1068 

1069 Spectral artifacts for the VLA often look like spokes radiating out from 

1070 a bright source (i.e. in the image made with standard mfs imaging). 

1071 If increasing the number of terms does not eliminate these artifacts, 

1072 check the data for inadequate bandpass calibration. If the source is away 

1073 from the pointing center, consider including wide-field corrections too. 

1074 

1075 (Note : In addition to output Taylor coefficient images .tt0,.tt1,etc 

1076 images of spectral index (.alpha), an estimate of error on 

1077 spectral index (.alpha.error) and spectral curvature (.beta, 

1078 if nterms is greater than 2) are produced. 

1079 - These alpha, alpha.error and beta images contain 

1080 internal T/F masks based on a threshold computed 

1081 as peakresidual/10. Additional masking based on 

1082 .alpha/.alpha.error may be desirable. 

1083 - .alpha.error is a purely empirical estimate derived 

1084 from the propagation of error during the division of 

1085 two noisy numbers (alpha = xx.tt1/xx.tt0) where the 

1086 'error' on tt1 and tt0 are simply the values picked from 

1087 the corresponding residual images. The absolute value 

1088 of the error is not always accurate and it is best to interpret 

1089 the errors across the image only in a relative sense. 

1090 smallscalebias A numerical control to bias the scales when using multi-scale or mtmfs algorithms. 

1091 The peak from each scale's smoothed residual is 

1092 multiplied by ( 1 - smallscalebias \* scale/maxscale ) 

1093 to increase or decrease the amplitude relative to other scales, 

1094 before the scale with the largest peak is chosen. 

1095 Smallscalebias can be varied between -1.0 and 1.0. 

1096 A score of 0.0 gives all scales equal weight (default). 

1097 A score larger than 0.0 will bias the solution towards smaller scales. 

1098 A score smaller than 0.0 will bias the solution towards larger scales. 

1099 The effect of smallscalebias is more pronounced when using multi-scale relative to mtmfs. 

1100 fusedthreshold ring Hogbom Clean (number in units of Jy). 

1101 

1102 fusedthreshold = 0.0001 : 0.1 mJy. 

1103 

1104 This is a subparameter of the Asp Clean deconvolver. When peak residual 

1105 is lower than the threshold, Asp Clean is "switched to Hogbom Clean" (i.e. only use the 0 scale for cleaning) for 

1106 the following number of iterations until it switches back to Asp Clean. 

1107 

1108 NumberIterationsInHogbom = 50 + 2 * (exp(0.05 * NthHogbom) - 1) 

1109 

1110 , where NthHogbom is the number of times Hogbom Clean has been triggered. 

1111 

1112 When the Asp Clean detects it is approaching convergence, it uses only the 0 scale for the following number of iterations for better computational efficiency. 

1113 

1114 NumberIterationsInHogbom = 500 + 2 * (exp(0.05 * NthHogbom) - 1) 

1115 

1116 Set 'fusedthreshold = -1' to make the Asp Clean deconvolver never "switch" to Hogbom Clean. 

1117 largestscale xels) allowed for the initial guess for the Asp Clean deconvolver. 

1118 

1119 largestscale = 100 

1120 

1121 The default initial scale sizes used by Asp Clean is [0, w, 2w, 4w, 8w], 

1122 where `w` is the PSF width. The default `largestscale` is -1 which indicates 

1123 users accept these initial scales. If `largestscale` is set, the initial scales 

1124 would be [0, w, ... up to the `largestscale`]. This is only an initial guess, 

1125 and actual fitted scale sizes may evolve from these initial values. 

1126 

1127 It is recommended not to set `largestscale` unless Asp Clean picks a large 

1128 scale that has no constraints from the data (the UV hole issue). 

1129 restoration e. 

1130 

1131 Construct a restored image : imagename.image by convolving the model 

1132 image with a clean beam and adding the residual image to the result. 

1133 If a restoringbeam is specified, the residual image is also 

1134 smoothed to that target resolution before adding it in. 

1135 

1136 If a .model does not exist, it will make an empty one and create 

1137 the restored image from the residuals ( with additional smoothing if needed ). 

1138 With algorithm='mtmfs', this will construct Taylor coefficient maps from 

1139 the residuals and compute .alpha and .alpha.error. 

1140 restoringbeam ize to use. 

1141 

1142 - restoringbeam='' or ['']. 

1143 A Gaussian fitted to the PSF main lobe (separately per image plane). 

1144 

1145 - restoringbeam='10.0arcsec'. 

1146 Use a circular Gaussian of this width for all planes. 

1147 

1148 - restoringbeam=['8.0arcsec','10.0arcsec','45deg']. 

1149 Use this elliptical Gaussian for all planes. 

1150 

1151 - restoringbeam='common'. 

1152 Automatically estimate a common beam shape/size appropriate for 

1153 all planes. This option can be used when the beam shape is different as a function of frequency, and will smooth all planes to a single beam, defined by the largest beam in the cube. 

1154 

1155 Note : For any restoring beam different from the native resolution 

1156 the model image is convolved with the beam and added to 

1157 residuals that have been convolved to the same target resolution. 

1158 pbcor the output restored image. 

1159 

1160 A new image with extension .image.pbcor will be created from 

1161 the evaluation of .image / .pb for all pixels above the specified pblimit. 

1162 

1163 Note : Stand-alone PB-correction can be triggered by re-running 

1164 tclean with the appropriate imagename and with 

1165 niter=0, calcpsf=False, calcres=False, pbcor=True, vptable='vp.tab' 

1166 ( where vp.tab is the name of the vpmanager file; 

1167 see the inline help for the 'vptable' parameter ). Alternatively, task impbcor can be used for primary beam correction using the .image and .pb files. 

1168 

1169 Note : For deconvolver='mtmfs', pbcor will divide each Taylor term image by the .tt0 average PB. 

1170 For all gridders, this calculation is accurate for small fractional bandwidths. 

1171 

1172 For large fractional bandwidths, please use one of the following options. 

1173 

1174 (a) For single pointings, run the tclean task with specmode='mfs', deconvolver='mtmfs', 

1175 and gridder='standard' with pbcor=True or False. 

1176 If a PB-corrected spectral index is required, 

1177 please use the widebandpbcor task to apply multi-tern PB-correction. 

1178 

1179 (b) For mosaics, run tclean task with specmode='mfs', deconvolver='mtmfs', 

1180 and gridder='awproject' , wbawp=True, conjbeams=True, with pbcor=True. 

1181 This option applies wideband PB correction as part of the gridding step and 

1182 pbcor=True will be accurate because the spectral index map will already 

1183 be PB-corrected. 

1184 

1185 (c) For mosaics, run tclean with specmode='mvc', deconvolver='mtmfs', 

1186 and gridder='mosaic' or 'awp2' with pbcor=True. 

1187 This option applies wideband PB-correction to channelized residual images 

1188 prior to the minor cycle and pbcor=True will be accurate because the spectral 

1189 index map will already be PB-corrected. 

1190 

1191 Note : Frequency-dependent PB corrections are typically required for full-band imaging with the VLA. 

1192 Wideband PB corrections are required when the amplitude of the 

1193 brightest source is known accurately enough to be sensitive 

1194 to the difference in the PB gain between the upper and lower 

1195 end of the band at its location. As a guideline, the artificial spectral 

1196 index due to the PB is -1.4 at the 0.5 gain level and less than -0.2 

1197 at the 0.9 gain level at the middle frequency ) 

1198 outlierfile Name of outlier-field image definitions. 

1199 

1200 A text file containing sets of parameter=value pairs, 

1201 one set per outlier field. 

1202 

1203 Example : outlierfile='outs.txt' 

1204 

1205 Contents of outs.txt : 

1206 

1207 imagename=tst1 

1208 nchan=1 

1209 imsize=[80,80] 

1210 cell=[8.0arcsec,8.0arcsec] 

1211 phasecenter=J2000 19:58:40.895 +40.55.58.543 

1212 mask=circle[[40pix,40pix],10pix] 

1213 

1214 imagename=tst2 

1215 nchan=1 

1216 imsize=[100,100] 

1217 cell=[8.0arcsec,8.0arcsec] 

1218 phasecenter=J2000 19:58:40.895 +40.56.00.000 

1219 mask=circle[[60pix,60pix],20pix] 

1220 

1221 The following parameters are currently allowed to be different between 

1222 the main field and the outlier fields (i.e. they will be recognized if found 

1223 in the outlier text file). If a parameter is not listed, the value is picked from 

1224 what is defined in the main task input. 

1225 

1226 imagename, imsize, cell, phasecenter, startmodel, mask 

1227 specmode, nchan, start, width, nterms, reffreq, 

1228 gridder, deconvolver, wprojplanes. 

1229 

1230 Note : 'specmode' is an option, so combinations of mfs and cube 

1231 for different image fields, for example, are supported. 

1232 'deconvolver' and 'gridder' are also options that allow different 

1233 imaging or deconvolution algorithm per image field. 

1234 

1235 For example, multiscale with wprojection and 16 w-term planes 

1236 on the main field and mtmfs with nterms=3 and wprojection 

1237 with 64 planes on a bright outlier source for which the frequency 

1238 dependence of the primary beam produces a strong effect that 

1239 must be modeled. The traditional alternative to this approach is 

1240 to first image the outlier, subtract it out of the data (uvsub) and 

1241 then image the main field. 

1242 weighting Weighting scheme (natural,uniform,briggs,superuniform,radial, briggsabs, briggsbwtaper). 

1243 

1244 During gridding of the dirty or residual image, each visibility value is 

1245 multiplied by a weight before it is accumulated on the uv-grid. 

1246 The PSF's uv-grid is generated by gridding only the weights (weightgrid). 

1247 

1248 weighting='natural' : Gridding weights are identical to the data weights 

1249 from the MS. For visibilities with similar data weights, 

1250 the weightgrid will follow the sample density 

1251 pattern on the uv-plane. This weighting scheme 

1252 provides the maximum imaging sensitivity at the 

1253 expense of a PSF with possibly wider main lobes and high sidelobes. 

1254 It is most appropriate for detection experiments 

1255 where sensitivity is most important. 

1256 

1257 weighting='uniform' : Gridding weights per visibility data point are the 

1258 original data weights divided by the total weight of 

1259 all data points that map to the same uv grid cell : 

1260 ' data_weight / total_wt_per_cell '. 

1261 

1262 The weightgrid is as close to flat as possible resulting 

1263 in a PSF with a narrow main lobe and suppressed 

1264 sidelobes. However, since heavily sampled areas of 

1265 the uv-plane get down-weighted, the imaging 

1266 sensitivity is not as high as with natural weighting. 

1267 It is most appropriate for imaging experiments where 

1268 a well behaved PSF can help the reconstruction. 

1269 

1270 weighting='briggs' : Gridding weights per visibility data point are given by 

1271 'data_weight / ( A \* total_wt_per_cell + B ) ' where 

1272 A and B vary according to the 'robust' parameter. 

1273 

1274 robust = -2.0 maps to A=1,B=0 or uniform weighting. 

1275 robust = +2.0 maps to natural weighting. 

1276 (robust=0.5 is equivalent to robust=0.0 in AIPS IMAGR.) 

1277 

1278 Robust/Briggs weighting generates a PSF that can 

1279 vary smoothly between 'natural' and 'uniform' and 

1280 allow customized trade-offs between PSF shape and 

1281 imaging sensitivity. 

1282 weighting='briggsabs' : Experimental option. 

1283 Same as Briggs except the formula is different A= 

1284 robust\*robust and B is dependent on the 

1285 noise per visibility estimated. Giving noise='0Jy' 

1286 is a not a reasonable option. 

1287 In this mode (or formula) robust values 

1288 from -2.0 to 0.0 only make sense (2.0 and 

1289 -2.0 will get the same weighting) 

1290 

1291 weighting='superuniform' : This is similar to uniform weighting except that 

1292 the total_wt_per_cell is replaced by the 

1293 total_wt_within_NxN_cells around the uv cell of 

1294 interest. N=7 is the default (when the 

1295 parameter 'npixels' is set to 0 with 'superuniform') 

1296 

1297 This method tends to give a PSF with inner 

1298 sidelobes that are suppressed as in uniform 

1299 weighting but with far-out sidelobes closer to 

1300 natural weighting. The peak sensitivity is also 

1301 closer to natural weighting. 

1302 

1303 weighting='radial' : Gridding weights are given by ' data_weight \* uvdistance ' 

1304 This method approximately minimizes rms sidelobes 

1305 for an east-west synthesis array. 

1306 

1307 weighting='briggsbwtaper' : A modified version of Briggs weighting for cubes where an inverse uv taper, 

1308 which is proportional to the fractional bandwidth of the entire cube, 

1309 is applied per channel. The objective is to modify cube (perchanweightdensity = True) 

1310 imaging weights to have a similar density to that of the continuum imaging weights. 

1311 This is currently an experimental weighting scheme being developed for ALMA. 

1312 

1313 For more details on weighting please see Chapter3 

1314 of Dan Briggs' thesis (http://www.aoc.nrao.edu/dissertations/dbriggs) 

1315 robust Robustness parameter for Briggs weighting. 

1316 

1317 robust = -2.0 maps to uniform weighting. 

1318 robust = +2.0 maps to natural weighting. 

1319 (robust=0.5 is equivalent to robust=0.0 in AIPS IMAGR.) 

1320 noise noise parameter for briggs abs mode weighting 

1321 npixels Number of pixels to determine uv-cell size for super-uniform weighting 

1322 (0 defaults to -/+ 3 pixels). 

1323 

1324 npixels -- uv-box used for weight calculation 

1325 a box going from -npixel/2 to +npixel/2 on each side 

1326 around a point is used to calculate weight density. 

1327 

1328 npixels=2 goes from -1 to +1 and covers 3 pixels on a side. 

1329 

1330 npixels=0 implies a single pixel, which does not make sense for 

1331 superuniform weighting. Therefore, for 'superuniform' 

1332 weighting, if npixels=0 it will be forced to 6 (or a box 

1333 of -3pixels to +3pixels) to cover 7 pixels on a side. 

1334 uvtaper uv-taper on outer baselines in uv-plane. 

1335 

1336 Apply a Gaussian taper in addition to the weighting scheme specified 

1337 via the 'weighting' parameter. Higher spatial frequencies are weighted 

1338 down relative to lower spatial frequencies to suppress artifacts 

1339 arising from poorly sampled areas of the uv-plane. It is equivalent to 

1340 smoothing the PSF obtained by other weighting schemes and can be 

1341 specified either as the HWHM of a Gaussian in uv-space (eg. units of lambda) 

1342 or as the FWHM of a Gaussian in the image domain (eg. angular units like arcsec). 

1343 

1344 uvtaper = [bmaj, bmin, bpa]. 

1345 

1346 Note : FWHM_uv_lambda = (4 log2) / ( pi * FWHM_lm_radians ). 

1347 

1348 A FWHM_lm of 100.000 arcsec maps to a HWHM_uv of 910.18 lambda. 

1349 A FWHM_lm of 1 arcsec maps to a HWHM_uv of 91 klambda. 

1350 

1351 default: uvtaper=[]; no Gaussian taper applied. 

1352 example: uvtaper=['5klambda'] circular taper of HWHM=5 kilo-lambda. 

1353 uvtaper=['5klambda','3klambda','45.0deg'] uv-domain HWHM. 

1354 uvtaper=['50arcsec','30arcsec','30.0deg'] : image domain FWHM. 

1355 uvtaper=['10arcsec'] : image domain FWHM. 

1356 uvtaper=['300.0'] default units are lambda in aperture plane. 

1357 niter Maximum number of iterations. 

1358 

1359 A stopping criterion based on total iteration count. 

1360 Currently the parameter type is defined as an integer therefore the integer value 

1361 larger than 2147483647 will not be set properly as it causes an overflow. 

1362 

1363 Iterations are typically defined as the selecting one flux component 

1364 and partially subtracting it out from the residual image. 

1365 

1366 niter=0 : Do only the initial major cycle (make dirty image, psf, pb, etc). 

1367 

1368 niter larger than zero : Run major and minor cycles. 

1369 

1370 Note : Global stopping criteria vs major-cycle triggers. 

1371 

1372 In addition to global stopping criteria, the following rules are 

1373 used to determine when to terminate a set of minor cycle iterations 

1374 and trigger major cycles [derived from Cotton-Schwab Clean, 1984]. 

1375 

1376 'cycleniter' : controls the maximum number of iterations per image 

1377 plane before triggering a major cycle. 

1378 'cyclethreshold' : Automatically computed threshold related to the 

1379 max sidelobe level of the PSF and peak residual. 

1380 Divergence, detected as an increase of 10% in peak residual from the 

1381 minimum so far (during minor cycle iterations). 

1382 

1383 The first criterion to be satisfied takes precedence. 

1384 

1385 Note : Iteration counts for cubes or multi-field images : 

1386 For images with multiple planes (or image fields) on which the 

1387 deconvolver operates in sequence, iterations are counted across 

1388 all planes (or image fields). The iteration count is compared with 

1389 'niter' only after all channels/planes/fields have completed their 

1390 minor cycles and exited either due to 'cycleniter' or 'cyclethreshold'. 

1391 Therefore, the actual number of iterations reported in the logger 

1392 can sometimes be larger than the user specified value in 'niter'. 

1393 For example, with niter=100, cycleniter=20,nchan=10,threshold=0, 

1394 a total of 200 iterations will be done in the first set of minor cycles 

1395 before the total is compared with niter=100 and it exits. 

1396 

1397 Note : Additional global stopping criteria include: 

1398 - no change in peak residual across two major cycles. 

1399 - a 50% or more increase in peak residual across one major cycle. 

1400 gain Loop gain. 

1401 

1402 Fraction of the source flux to subtract out of the residual image 

1403 for the CLEAN algorithm and its variants. 

1404 

1405 A low value (0.2 or less) is recommended when the sky brightness 

1406 distribution is not well represented by the basis functions used by 

1407 the chosen deconvolution algorithm. A higher value can be tried when 

1408 there is a good match between the true sky brightness structure and 

1409 the basis function shapes. For example, for extended emission, 

1410 multiscale clean with an appropriate set of scale sizes will tolerate 

1411 a higher loop gain than Clark clean. 

1412 threshold Stopping threshold (number in units of Jy, or string). 

1413 

1414 A global stopping threshold that the peak residual (within clean mask) 

1415 across all image planes is compared to. 

1416 

1417 threshold = 0.005 : 5mJy 

1418 threshold = '5.0mJy' 

1419 

1420 Note : A 'cyclethreshold' is internally computed and used as a major cycle 

1421 trigger. It is related to what fraction of the PSF can be reliably 

1422 used during minor cycle updates of the residual image. By default 

1423 the minor cycle iterations terminate once the peak residual reaches 

1424 the first sidelobe level of the brightest source. 

1425 

1426 'cyclethreshold' is computed as follows using the settings in 

1427 parameters 'cyclefactor','minpsffraction','maxpsffraction','threshold' : 

1428 

1429 psf_fraction = max_psf_sidelobe_level \* 'cyclefactor' 

1430 psf_fraction = max(psf_fraction, 'minpsffraction'); 

1431 psf_fraction = min(psf_fraction, 'maxpsffraction'); 

1432 cyclethreshold = peak_residual \* psf_fraction 

1433 cyclethreshold = max( cyclethreshold, 'threshold' ) 

1434 

1435 If nsigma is set (>0.0), the N-sigma threshold is calculated (see 

1436 the description under nsigma), then cyclethreshold is further modified as, 

1437 

1438 cyclethreshold = max( cyclethreshold, nsgima_threshold ). 

1439 

1440 

1441 'cyclethreshold' is made visible and editable only in the 

1442 interactive GUI when tclean is run with interactive=True. 

1443 nsigma Multiplicative factor for rms-based threshold stopping. 

1444 

1445 N-sigma threshold is calculated as nsigma \* rms value per image plane determined 

1446 from a robust statistics. For nsigma > 0.0, in a minor cycle, a maximum of the two values, 

1447 the N-sigma threshold and cyclethreshold, is used to trigger a major cycle 

1448 (see also the descreption under 'threshold'). 

1449 Set nsigma=0.0 to preserve the previous tclean behavior without this feature. 

1450 The top level parameter, fastnoise is relevant for the rms noise calculation which is used 

1451 to determine the threshold. 

1452 

1453 The parameter 'nsigma' may be an int, float, or a double. 

1454 cycleniter Maximum number of minor-cycle iterations (per plane) before triggering 

1455 a major cycle. 

1456 

1457 For example, for a single plane image, if niter=100 and cycleniter=20, 

1458 there will be 5 major cycles after the initial one (assuming there is no 

1459 threshold based stopping criterion). At each major cycle boundary, if 

1460 the number of iterations left over (to reach niter) is less than cycleniter, 

1461 it is set to the difference. 

1462 

1463 Note : cycleniter applies per image plane, even if cycleniter x nplanes 

1464 gives a total number of iterations greater than 'niter'. This is to 

1465 preserve consistency across image planes within one set of minor 

1466 cycle iterations. 

1467 cyclefactor Scaling on PSF sidelobe level to compute the minor-cycle stopping threshold. 

1468 

1469 Please refer to the Note under the documentation for 'threshold' that 

1470 discussed the calculation of 'cyclethreshold'. 

1471 

1472 cyclefactor=1.0 results in a cyclethreshold at the first sidelobe level of 

1473 the brightest source in the residual image before the minor cycle starts. 

1474 

1475 cyclefactor=0.5 allows the minor cycle to go deeper. 

1476 cyclefactor=2.0 triggers a major cycle sooner. 

1477 minpsffraction PSF fraction that marks the max depth of cleaning in the minor cycle. 

1478 

1479 Please refer to the Note under the documentation for 'threshold' that 

1480 discussed the calculation of 'cyclethreshold'. 

1481 

1482 For example, minpsffraction=0.5 will stop cleaning at half the height of 

1483 the peak residual and trigger a major cycle earlier. 

1484 maxpsffraction PSF fraction that marks the minimum depth of cleaning in the minor cycle. 

1485 

1486 Please refer to the Note under the documentation for 'threshold' that 

1487 discussed the calculation of 'cyclethreshold'. 

1488 

1489 For example, maxpsffraction=0.8 will ensure that at least the top 20 

1490 percent of the source will be subtracted out in the minor cycle even if 

1491 the first PSF sidelobe is at the 0.9 level (an extreme example), or if the 

1492 cyclefactor is set too high for anything to get cleaned. 

1493 nmajor The nmajor parameter limits the number of minor and major cycle sets 

1494 that tclean executes. It is defined as the number of major cycles after the 

1495 initial set of minor cycle iterations. In other words, the count of nmajor does 

1496 not include the initial residual calculation that occurs when calcres=True. 

1497 

1498 A setting of nmajor=-1 implies no limit (default -1). 

1499 A setting of nmajor=0 implies nothing other than the initial residual calculation 

1500 A setting of nmajor>0 imples that nmajor sets of minor and major cycles will 

1501 be done in addition to the initial residual calculation. 

1502 

1503 If the major cycle limit is reached, stopcode 9 will be returned. Other stopping 

1504 criteria (such as threshold) could cause tclean to stop in fewer than this 

1505 number of major cycles. If tclean reaches another stopping criteria, first 

1506 or at the same time as nmajor, then that stopcode will be returned instead. 

1507 

1508 Note however that major cycle ids in the log messages as well as in the return 

1509 dictionary do begin with 1 for the initial residual calculation, when it exists. 

1510 

1511 Example 1 : A tclean run with 'nmajor=5' and 'calcres=True' will iterate for 

1512 5 major cycles (not counting the initial residual calculation). But, the return 

1513 dictionary will show 'nmajordone:6'. If 'calcres=False', then the return 

1514 dictionary will show 'nmajordone:5'. 

1515 

1516 Example 2 : For both the following cases, there will be a printout in the logs 

1517 "Running Major Cycle 1" and the return value will include "nmajordone: 1", 

1518 however there is a difference in the purpose of the major cycle and the 

1519 number of minor cycles executed: 

1520 Case 1; nmajor=0, calcres=True: The major cycle done is for the creation 

1521 of the residual, and no minor cycles are executed. 

1522 Case 2; nmajor=1, calcres=False: The major cycle is done as part of the 

1523 major/minor cycle loop, and 1 minor cycle will be executed. 

1524 usemask Type of mask(s) to be used for deconvolution. 

1525 

1526 user: (default) mask image(s) or user specified region file(s) or string CRTF expression(s). 

1527 subparameters: mask, pbmask. 

1528 pb: primary beam mask. 

1529 subparameter: pbmask. 

1530 

1531 Example: usemask="pb", pbmask=0.2. 

1532 Construct a mask at the 0.2 pb gain level. 

1533 (Currently, this option will work only with 

1534 

1535 gridders that produce .pb (i.e. mosaic, awp2 and awproject) 

1536 or if an externally produced .pb image exists on disk) 

1537 

1538 

1539 auto-multithresh : auto-masking by multiple thresholds for deconvolution. 

1540 subparameters : sidelobethreshold, noisethreshold, lownoisethreshold, negativethrehsold, smoothfactor, 

1541 minbeamfrac, cutthreshold, pbmask, growiterations, dogrowprune, minpercentchange, verbose. 

1542 Additional top level parameter relevant to auto-multithresh: fastnoise. 

1543 

1544 if pbmask is >0.0, the region outside the specified pb gain level is excluded from 

1545 image statistics in determination of the threshold. 

1546 

1547 

1548 

1549 

1550 Note: By default the intermediate mask generated by automask at each deconvolution cycle 

1551 is over-written in the next cycle but one can save them by setting 

1552 the environment variable, SAVE_ALL_AUTOMASKS="true". 

1553 (e.g. in the CASA prompt, os.environ['SAVE_ALL_AUTOMASKS']="true" ) 

1554 The saved CASA mask image name will be imagename.mask.autothresh#, where 

1555 # is the iteration cycle number. 

1556 mask Mask (a list of image name(s) or region file(s) or region string(s). 

1557 

1558 

1559 The name of a CASA image or region file or region string that specifies 

1560 a 1/0 mask to be used for deconvolution. Only locations with value 1 will 

1561 be considered for the centers of flux components in the minor cycle. 

1562 If regions specified fall completely outside of the image, tclean will throw an error. 

1563 

1564 Manual mask options/examples : 

1565 

1566 mask='xxx.mask' : Use this CASA image named xxx.mask and containing 

1567 ones and zeros as the mask. 

1568 If the mask is only different in spatial coordinates from what is being made 

1569 it will be resampled to the target coordinate system before being used. 

1570 The mask has to have the same shape in velocity and Stokes planes 

1571 as the output image. Exceptions are single velocity and/or single 

1572 Stokes plane masks. They will be expanded to cover all velocity and/or 

1573 Stokes planes of the output cube. 

1574 

1575 [ Note : If an error occurs during image resampling or 

1576 if the expected mask does not appear, please try 

1577 using tasks 'imregrid' or 'makemask' to resample 

1578 the mask image onto a CASA image with the target 

1579 shape and coordinates and supply it via the 'mask' 

1580 parameter. ] 

1581 

1582 

1583 mask='xxx.crtf' : A text file with region strings and the following on the first line 

1584 ( #CRTFv0 CASA Region Text Format version 0 ) 

1585 This is the format of a file created via the viewer's region 

1586 tool when saved in CASA region file format. 

1587 

1588 mask='circle[[40pix,40pix],10pix]' : A CASA region string. 

1589 

1590 mask=['xxx.mask','xxx.crtf', 'circle[[40pix,40pix],10pix]'] : a list of masks. 

1591 

1592 

1593 

1594 

1595 

1596 Note : Mask images for deconvolution must contain 1 or 0 in each pixel. 

1597 Such a mask is different from an internal T/F mask that can be 

1598 held within each CASA image. These two types of masks are not 

1599 automatically interchangeable, so please use the makemask task 

1600 to copy between them if you need to construct a 1/0 based mask 

1601 from a T/F one. 

1602 

1603 Note : Work is in progress to generate more flexible masking options and 

1604 enable more controls. 

1605 pbmask Sub-parameter for usemask: primary beam mask. 

1606 

1607 Examples : pbmask=0.0 (default, no pb mask). 

1608 pbmask=0.2 (construct a mask at the 0.2 pb gain level). 

1609 sidelobethreshold Sub-parameter for "auto-multithresh": mask threshold based on sidelobe levels: sidelobethreshold \* max_sidelobe_level \* peak residual. 

1610 noisethreshold Sub-parameter for "auto-multithresh": mask threshold based on the noise level: noisethreshold \* rms + location (=median). 

1611 

1612 The rms is calculated from the median absolute deviation (MAD), with rms = 1.4826\*MAD. 

1613 lownoisethreshold Sub-parameter for "auto-multithresh": mask threshold to grow previously masked regions via binary dilation: lownoisethreshold \* rms in residual image + location (=median). 

1614 

1615 The rms is calculated from the median absolute deviation (MAD), with rms = 1.4826\*MAD. 

1616 negativethreshold Sub-parameter for "auto-multithresh": mask threshold for negative features: -1.0* negativethreshold \* rms + location(=median). 

1617 

1618 The rms is calculated from the median absolute deviation (MAD), with rms = 1.4826\*MAD. 

1619 smoothfactor Sub-parameter for "auto-multithresh": smoothing factor in a unit of the beam. 

1620 minbeamfrac Sub-parameter for "auto-multithresh": minimum beam fraction in size to prune masks smaller than mimbeamfrac \* beam 

1621 <=0.0 : No pruning 

1622 cutthreshold Sub-parameter for "auto-multithresh": threshold to cut the smoothed mask to create a final mask: cutthreshold \* peak of the smoothed mask. 

1623 growiterations Sub-parameter for "auto-multithresh": Maximum number of iterations to perform using binary dilation for growing the mask. 

1624 dogrowprune Experimental sub-parameter for "auto-multithresh": Do pruning on the grow mask. 

1625 minpercentchange If the change in the mask size in a particular channel is less than minpercentchange, stop masking that channel in subsequent cycles. This check is only applied when noise based threshold is used and when the previous clean major cycle had a cyclethreshold value equal to the clean threshold. Values equal to -1.0 (or any value less than 0.0) will turn off this check (the default). Automask will still stop masking if the current channel mask is an empty mask and the noise threshold was used to determine the mask. 

1626 verbose he summary of automasking at the end of each automasking process 

1627 is printed in the logger. Following information per channel will be listed in the summary. 

1628 

1629 chan: channel number. 

1630 masking?: F - stop updating automask for the subsequent iteration cycles. 

1631 RMS: robust rms noise. 

1632 peak: peak in residual image. 

1633 thresh_type: type of threshold used (noise or sidelobe). 

1634 thresh_value: the value of threshold used. 

1635 N_reg: number of the automask regions. 

1636 N_pruned: number of the automask regions removed by pruning. 

1637 N_grow: number of the grow mask regions. 

1638 N_grow_pruned: number of the grow mask regions removed by pruning. 

1639 N_neg_pix: number of pixels for negative mask regions. 

1640 

1641 Note that for a large cube, extra logging may slow down the process. 

1642 fastnoise Only relevant when automask (user='multi-autothresh') and/or n-sigma stopping threshold (nsigma>0.0) are/is used. If it is set to True, a simpler but faster noise calucation is used. 

1643 In this case, the threshold values are determined based on classic statistics (using all 

1644 unmasked pixels for the calculations). 

1645 

1646 If it is set to False, the new noise calculation 

1647 method is used based on pre-existing mask. 

1648 

1649 Case 1: no exiting mask. 

1650 Calculate image statistics using Chauvenet algorithm. 

1651 

1652 Case 2: there is an existing mask. 

1653 Calculate image statistics by classical method on the region 

1654 outside the mask and inside the primary beam mask. 

1655 

1656 In all cases above RMS noise is calculated from the median absolute deviation (MAD). 

1657 restart images (and start from an existing model image) 

1658 or automatically increment the image name and make a new image set. 

1659 

1660 True : Re-use existing images. If imagename.model exists the subsequent 

1661 run will start from this model (i.e. predicting it using current gridder 

1662 settings and starting from the residual image). Care must be taken 

1663 when combining this option with startmodel. Currently, only one or 

1664 the other can be used. 

1665 

1666 startmodel='', imagename.model exists : 

1667 - Start from imagename.model. 

1668 startmodel='xxx', imagename.model does not exist : 

1669 - Start from startmodel. 

1670 startmodel='xxx', imagename.model exists : 

1671 - Exit with an error message requesting the user to pick 

1672 only one model. This situation can arise when doing one 

1673 run with startmodel='xxx' to produce an output 

1674 imagename.model that includes the content of startmodel, 

1675 and wanting to restart a second run to continue deconvolution. 

1676 Startmodel should be set to '' before continuing. 

1677 

1678 If any change in the shape or coordinate system of the image is 

1679 desired during the restart, please change the image name and 

1680 use the startmodel (and mask) parameter(s) so that the old model 

1681 (and mask) can be regridded to the new coordinate system before starting. 

1682 

1683 False : A convenience feature to increment imagename with '_1', '_2', 

1684 etc as suffixes so that all runs of tclean are fresh starts (without 

1685 having to change the imagename parameter or delete images). 

1686 

1687 This mode will search the current directory for all existing 

1688 imagename extensions, pick the maximum, and adds 1. 

1689 For imagename='try' it will make try.psf, try_2.psf, try_3.psf, etc. 

1690 

1691 This also works if you specify a directory name in the path : 

1692 imagename='outdir/try'. If './outdir' does not exist, it will create it. 

1693 Then it will search for existing filenames inside that directory. 

1694 

1695 If outlier fields are specified, the incrementing happens for each 

1696 of them (since each has its own 'imagename'). The counters are 

1697 synchronized across imagefields, to make it easier to match up sets 

1698 of output images. It adds 1 to the 'max id' from all outlier names 

1699 on disk. So, if you do two runs with only the main field 

1700 (imagename='try'), and in the third run you add an outlier with 

1701 imagename='outtry', you will get the following image names 

1702 for the third run : 'try_3' and 'outtry_3' even though 

1703 'outry' and 'outtry_2' have not been used. 

1704 savemodel Options to save model visibilities (none, virtual, modelcolumn). 

1705 

1706 Often, model visibilities must be created and saved in the MS 

1707 to be later used for self-calibration (or to just plot and view them). 

1708 

1709 none : Do not save any model visibilities in the MS. The MS is opened 

1710 in readonly mode. 

1711 

1712 Model visibilities can be predicted in a separate step by 

1713 restarting tclean with niter=0,savemodel=virtual or modelcolumn 

1714 and not changing any image names so that it finds the .model on 

1715 disk (or by changing imagename and setting startmodel to the 

1716 original imagename). 

1717 

1718 virtual : In the last major cycle, save the image model and state of the 

1719 gridder used during imaging within the SOURCE subtable of the 

1720 MS. Images required for de-gridding will also be stored internally. 

1721 All future references to model visibilities will activate the 

1722 (de)gridder to compute them on-the-fly. This mode is useful 

1723 when the dataset is large enough that an additional model data 

1724 column on disk may be too much extra disk I/O, when the 

1725 gridder is simple enough that on-the-fly recomputing of the 

1726 model visibilities is quicker than disk I/O. 

1727 For e.g. that gridder='awproject' and 'awp2' does not support virtual model. 

1728 

1729 modelcolumn : In the last major cycle, save predicted model visibilities 

1730 in the MODEL_DATA column of the MS. This mode is useful when 

1731 the de-gridding cost to produce the model visibilities is higher 

1732 than the I/O required to read the model visibilities from disk. 

1733 This mode is currently required for gridder='awproject' and 'awp2'. 

1734 This mode is also required for the ability to later pull out 

1735 model visibilities from the MS into a python array for custom 

1736 processing. 

1737 

1738 Note 1 : The imagename.model image on disk will always be constructed 

1739 if the minor cycle runs. This savemodel parameter applies only to 

1740 model visibilities created by de-gridding the model image. 

1741 

1742 Note 2 : It is possible for an MS to have both a virtual model 

1743 as well as a model_data column, but under normal operation, 

1744 the last used mode will get triggered. Use the delmod task to 

1745 clear out existing models from an MS if confusion arises. 

1746 Note 3: when parallel=True, use savemodel='none'; Other options are not yet ready 

1747 for use in parallel. If model visibilities need to be saved (virtual or modelcolumn): 

1748 please run tclean in serial mode with niter=0; after the parallel run 

1749 calcres Calculate initial residual image. 

1750 

1751 This parameter controls what the first major cycle does. 

1752 

1753 calcres=False with niter greater than 0 will assume that 

1754 a .residual image already exists and that the minor cycle can 

1755 begin without recomputing it. 

1756 

1757 calcres=False with niter=0 implies that only the PSF will be made 

1758 and no data will be gridded. 

1759 

1760 calcres=True requires that calcpsf=True or that the .psf and .sumwt 

1761 images already exist on disk (for normalization purposes). 

1762 

1763 Usage example : For large runs (or a pipeline scripts) it may be 

1764 useful to first run tclean with niter=0 to create 

1765 an initial .residual to look at and perhaps make 

1766 a custom mask for. Imaging can be resumed 

1767 without recomputing it. 

1768 calcpsf Calculate PSF 

1769 

1770 This parameter controls what the first major cycle does. 

1771 

1772 calcpsf=False will assume that a .psf image already exists 

1773 and that the minor cycle can begin without recomputing it. 

1774 psfcutoff When the .psf image is created a 2 dimensional Gaussian is fit to the main lobe of the PSF. 

1775 Which pixels in the PSF are fitted is determined by psfcutoff. 

1776 The default value of psfcutoff is 0.35 and can varied from 0.01 to 0.99. 

1777 Fitting algorithm: 

1778 - A region of 41 x 41 pixels around the peak of the PSF is compared against the psfcutoff. 

1779 Sidelobes are ignored by radially searching from the PSF peak. 

1780 - Calculate the bottom left corner (blc) and top right corner (trc) from the points. Expand blc and trc with a number of pixels (5). 

1781 - Create a new sub-matrix from blc and trc. 

1782 - Interpolate matrix to a target number of points (3001) using CUBIC spline. 

1783 - All the non-sidelobe points, in the interpolated matrix, that are above the psfcutoff are used to fit a Gaussian. 

1784 A Levenberg-Marquardt algorithm is used. 

1785 - If the fitting fails the algorithm is repeated with the psfcutoff decreased (psfcutoff=psfcutoff/1.5). 

1786 A message in the log will apear if the fitting fails along with the new value of psfcutoff. 

1787 This will be done up to 50 times if fitting fails. 

1788 This Gaussian beam is defined by a major axis, minor axis, and position angle. 

1789 During the restoration process, this Gaussian beam is used as the Clean beam. 

1790 Varying psfcutoff might be useful for producing a better fit for highly non-Gaussian PSFs, however, the resulting fits should be carefully checked. 

1791 This parameter should rarely be changed. 

1792 

1793 (This is not the support size for clark clean.) 

1794 parallel Run major cycles in parallel. 

1795 

1796 Parallel tclean will run only if casa has already been started using mpirun. 

1797 Please refer to external resources on high performance computing for details on how to start this on your system. 

1798 

1799 Example : mpirun -n 3 -xterm 0 `which casa` 

1800 

1801 Continuum Imaging : 

1802 - Data are partitioned (in time) into NProc pieces. 

1803 - Gridding/iFT is done separately per partition. 

1804 - Images (and weights) are gathered and then normalized. 

1805 - One non-parallel minor cycle is run. 

1806 - Model image is scattered to all processes. 

1807 - Major cycle is done in parallel per partition. 

1808 

1809 Cube Imaging : 

1810 - Data and Image coordinates are partitioned (in freq) into NProc pieces. 

1811 - Each partition is processed independently (major and minor cycles). 

1812 - All processes are synchronized at major cycle boundaries for convergence checks. 

1813 - At the end, cubes from all partitions are concatenated along the spectral axis. 

1814 

1815 Note 1 : Iteration control for cube imaging is independent per partition. 

1816 - There is currently no communication between them to synchronize 

1817 information such as peak residual and cyclethreshold. Therefore, 

1818 different chunks may trigger major cycles at different levels. 

1819 (Proper synchronization of iteration control is work in progress.) 

1820 RETURNS void 

1821 

1822 --------- examples ----------------------------------------------------------- 

1823 

1824 

1825 

1826 For more information, see the task pages of tclean in CASA Docs: 

1827 

1828 https://casadocs.readthedocs.io 

1829 

1830 

1831 

1832 

1833 

1834 ''' 

1835 

1836 _info_group = """imaging""" 

1837 _info_desc = """Radio Interferometric Image Reconstruction""" 

1838 

1839 def _tclean( self, *args, **kwargs ): 

1840 """ Calls tclean records the arguments in the local history of tclean calls. 

1841casatasks/src/private/imagerhelpers/_gclean.py 

1842 The full tclean history for this instance can be retrieved via the cmds() method.""" 

1843 arg_s = ', '.join( map( lambda a: self._history_filter(len(self._exe_cmds), None, repr(a)), args ) ) 

1844 kw_s = ', '.join( map( lambda kv: self._history_filter(len(self._exe_cmds), kv[0], "%s=%s" % (kv[0],repr(kv[1]))), kwargs.items()) ) 

1845 if len(arg_s) > 0 and len(kw_s) > 0: 

1846 parameters = arg_s + ", " + kw_s 

1847 else: 

1848 parameters = arg_s + kw_s 

1849 self._exe_cmds.append( "tclean( %s )" % parameters ) 

1850 self._exe_cmds_per_iter[-1] += 1 

1851 return tclean( *args, **kwargs ) 

1852 

1853 def _deconvolve( self, *args, **kwargs ): 

1854 """ Calls deconvolve records the arguments in the local history of deconvolve calls. 

1855 

1856 The full deconvolve history for this instance can be retrieved via the cmds() method.""" 

1857 arg_s = ', '.join( map( lambda a: self._history_filter(len(self._exe_cmds), None, repr(a)), args ) ) 

1858 kw_s = ', '.join( map( lambda kv: self._history_filter(len(self._exe_cmds), kv[0], "%s=%s" % (kv[0],repr(kv[1]))), kwargs.items()) ) 

1859 if len(arg_s) > 0 and len(kw_s) > 0: 

1860 parameters = arg_s + ", " + kw_s 

1861 else: 

1862 parameters = arg_s + kw_s 

1863 self._exe_cmds.append( "deconvolve( %s )" % parameters ) 

1864 self._exe_cmds_per_iter[-1] += 1 

1865 return deconvolve( *args, **kwargs ) 

1866 

1867 

1868 def _deconv_over_fields(self, niter, mask=None, threshold=None, restoration=False, hasit_per_field=None): 

1869 """ 

1870 Loop over each field, deconvolve, merge the return dicts, all that good 

1871 stuff. The only configurable option here is self._niter, and 

1872 restoreation, which is different depending on whether we want to 

1873 deconvolve (niter > 0) or update the mask (niter = 0), or restore 

1874 (niter=0, restoration=True). 

1875 

1876 The niter passed in is tracked by self._niter for when we need to do deconvolution, 

1877 and is set to 0 otherwise. 

1878 

1879 The other parameters that come in from the GUI are used directly within this function, 

1880 such as self._cyclethreshold, self._nsigma, self._gain, etc. 

1881 """ 

1882 

1883 initialize_merge_dict = False 

1884 counter = 0 

1885 

1886 # Loop over each image (outliers included) and deconvolve. 

1887 # This is not necessary for tclean, since we want a joint gridding of all the images 

1888 for fidx, fieldid in enumerate(self._paramlist.allimpars.keys()): 

1889 # Check if convergence info exists 

1890 # If it exists, skip field if it has converged 

1891 if hasit_per_field is not None and restoration == False: 

1892 if hasit_per_field[fidx]: 

1893 # If convergence is hit, skip this field 

1894 continue 

1895 elif restoration == True: 

1896 # If restoration is True, we always want to run the deconvolution 

1897 # even if convergence is hit, so we can restore the image. 

1898 # Force niter = 0 regardless of input 

1899 niter = 0 

1900 pass 

1901 

1902 if threshold is None: 

1903 # User input threshold over all fields from initial iclean call 

1904 this_threshold = self._threshold 

1905 else: 

1906 # Calculated threshold per field 

1907 this_threshold = threshold[fidx] 

1908 

1909 tmpiterpars = self._paramlist.iterpars 

1910 tmpdecpars = self._paramlist.alldecpars[fieldid] 

1911 

1912 thismask = tmpdecpars['mask'] if mask is None else mask 

1913 

1914 deconv_ret = self._deconvolve(imagename=tmpdecpars['imagename'], startmodel=tmpdecpars['startmodel'], 

1915 deconvolver=tmpdecpars['deconvolver'], scales=tmpdecpars['scales'], nterms=tmpdecpars['nterms'], 

1916 smallscalebias=tmpdecpars['scalebias'], restoration=restoration, restoringbeam=tmpdecpars['restoringbeam'], 

1917 niter = niter, gain=self._gain, threshold=this_threshold, nsigma=self._nsigma, 

1918 interactive = False, fullsummary=True, fastnoise=tmpdecpars['fastnoise'], usemask=tmpdecpars['usemask'], 

1919 mask = thismask, pbmask=tmpdecpars['pbmask'], sidelobethreshold=self._sidelobethreshold, 

1920 noisethreshold=self._noisethreshold, lownoisethreshold=self._lownoisethreshold, 

1921 negativethreshold=self._negativethreshold, smoothfactor=tmpdecpars['smoothfactor'], 

1922 minbeamfrac=self._minbeamfrac, cutthreshold=tmpdecpars['cutthreshold'], 

1923 growiterations=tmpdecpars['growiterations'], dogrowprune=self._dogrowprune, 

1924 verbose=tmpdecpars['verbose']) 

1925 

1926 

1927 # Since we are looping through field_id externally, deconvolve 

1928 # always thinks it's imaging field 0 Fix this manually so when we 

1929 # do the concat below we are not over-writing records 

1930 if fidx > 0 and self._nfields > 1: 

1931 deconv_ret['summaryminor'][fidx] = deconv_ret['summaryminor'].pop(0) 

1932 initialize_merge_dict = True 

1933 

1934 if self._nfields > 1 and counter == 0: 

1935 deconv_ret_merge = copy.deepcopy(deconv_ret) 

1936 

1937 # Only start merging after the first non-converged field has been processed 

1938 if counter > 0: 

1939 deconv_ret_merge = ImagingDict.concat_multifield_deconv(deconv_ret_merge, deconv_ret) 

1940 

1941 counter += 1 

1942 

1943 # Move the merged dict back to the original var name 

1944 if self._nfields > 1 and initialize_merge_dict: 

1945 deconv_ret = copy.deepcopy(deconv_ret_merge) 

1946 

1947 return deconv_ret 

1948 

1949 

1950 

1951 def _remove_tree( self, directory ): 

1952 if os.path.isdir(directory): 

1953 shutil.rmtree(directory) 

1954 self._exe_cmds.append( f'''shutil.rmtree( {repr(directory)} )''' ) 

1955 self._exe_cmds_per_iter[-1] += 1 

1956 

1957 def _log( self, history=False ): 

1958 """ Returns the history of all tclean calls for this instance. If ``history`` 

1959 is set to True then the full history will be returned, otherwise the commands 

1960 executed for generating the latest result are returned. 

1961 """ 

1962 

1963 if history: 

1964 return self._exe_cmds 

1965 else: 

1966 if self._exe_cmds_per_iter[-1] > 0: 

1967 # Return the last N commands 

1968 return self._exe_cmds[-self._exe_cmds_per_iter[-1]:] 

1969 else: 

1970 # If convergence is hit, no commands were run so return nothing 

1971 return [] 

1972 

1973 

1974 def update( self, msg ): 

1975 """ Interactive clean parameters update. 

1976 

1977 Args: 

1978 msg: dict with possible keys 'niter', 'cycleniter', 'nmajor', 'threshold', 'cyclefactor' 

1979 

1980 Returns: 

1981 stopcode : Stop code in case of error (-1 on error, 0 if no error), int 

1982 stopdesc : Exception error message, str 

1983 """ 

1984 if 'niter' in msg: 

1985 try: 

1986 self._niter = int(msg['niter']) 

1987 if self._niter < -1: 

1988 return -1, f"niter must be >= -1" 

1989 except ValueError as err: 

1990 return -1, "niter must be an integer" 

1991 

1992 if 'cycleniter' in msg: 

1993 try: 

1994 self._cycleniter = int(msg['cycleniter']) 

1995 if self._cycleniter < -1: 

1996 return -1, f"cycleniter must be >= -1" 

1997 except ValueError: 

1998 return -1, "cycleniter must be an integer" 

1999 

2000 if 'nmajor' in msg: 

2001 try: 

2002 self._nmajor = int(msg['nmajor']) 

2003 if self._nmajor < -1: 

2004 return -1, f"nmajor must be >= -1" 

2005 except ValueError as e: 

2006 return -1, "nmajor must be an integer" 

2007 

2008 if 'threshold' in msg: 

2009 try: 

2010 self._threshold = float(msg['threshold']) 

2011 if self._threshold < 0: 

2012 return -1, f"threshold must be >= 0" 

2013 except ValueError: 

2014 if isinstance(msg['threshold'], str) and "jy" in msg['threshold'].lower(): 

2015 self._threshold_to_float(msg['threshold']) # Convert str to float 

2016 else: 

2017 return -1, f"threshold must be a number, or a number with units (Jy/mJy/uJy)" 

2018 

2019 

2020 if 'nsigma' in msg: 

2021 try: 

2022 self._nsigma = float(msg['nsigma']) 

2023 if self._nsigma < 0: 

2024 return -1, f"nsigma must be >= 0" 

2025 except ValueError: 

2026 return -1, "nsigma must be a number" 

2027 

2028 

2029 if 'gain' in msg: 

2030 try: 

2031 self._gain = float(msg['gain']) 

2032 if self._gain <= 0: 

2033 return -1, f"gain must be > 0" 

2034 except ValueError: 

2035 return -1, "gain must be a number" 

2036 

2037 

2038 if 'cyclefactor' in msg: 

2039 try: 

2040 self._cyclefactor = float(msg['cyclefactor']) 

2041 if self._cyclefactor <= 0: 

2042 return -1, f"cyclefactor must be > 0" 

2043 except ValueError: 

2044 return -1, "cyclefactor must be a number" 

2045 

2046 ### Automasking parameters 

2047 

2048 if 'dogrowprune' in msg: 

2049 try: 

2050 self._dogrowprune = bool(msg['dogrowprune']) 

2051 except ValueError: 

2052 return -1, "dogrowprune must be a boolean" 

2053 

2054 if 'noisethreshold' in msg: 

2055 try: 

2056 self._noisethreshold = float(msg['noisethreshold']) 

2057 if self._noisethreshold < 0: 

2058 return -1, f"noisethreshold must be >= 0" 

2059 except ValueError: 

2060 return -1, "noisethreshold must be a number" 

2061 

2062 if 'sidelobethreshold' in msg: 

2063 try: 

2064 self._sidelobethreshold = float(msg['sidelobethreshold']) 

2065 if self._sidelobethreshold < 0: 

2066 return -1, f"sidelobethreshold must be >= 0" 

2067 except ValueError: 

2068 return -1, "sidelobethreshold must be a number" 

2069 

2070 if 'lownoisethreshold' in msg: 

2071 try: 

2072 self._lownoisethreshold = float(msg['lownoisethreshold']) 

2073 if self._lownoisethreshold < 0: 

2074 return -1, f"lownoisethreshold must be >= 0" 

2075 except ValueError: 

2076 return -1, "lownoisethreshold must be a number" 

2077 

2078 if 'minbeamfrac' in msg: 

2079 try: 

2080 self._minbeamfrac = float(msg['minbeamfrac']) 

2081 if self._minbeamfrac < 0: 

2082 return -1, f"minbeamfrac must be >= 0" 

2083 except ValueError: 

2084 return -1, "minbeamfrac must be a number" 

2085 

2086 if 'negativethreshold' in msg: 

2087 try: 

2088 self._negativethreshold = float(msg['negativethreshold']) 

2089 if self._negativethreshold < 0: 

2090 return -1, f"negativethreshold must be >= 0" 

2091 except ValueError: 

2092 return -1, "negativethreshold must be a number" 

2093 

2094 

2095 return 0, "" 

2096 

2097 

2098 def _threshold_to_float(self, msg=None): 

2099 # Convert threshold from string to float if necessary 

2100 if msg is not None: 

2101 if isinstance(msg, str): 

2102 if "mJy" in msg: 

2103 self._threshold = float(msg.replace("mJy", "")) / 1e3 

2104 elif "uJy" in msg: 

2105 self._threshold = float(msg.replace("uJy", "")) / 1e6 

2106 elif "Jy" in msg: 

2107 self._threshold = float(msg.replace("Jy", "")) 

2108 else: 

2109 if isinstance(self._threshold, str): 

2110 if "mJy" in self._threshold: 

2111 self._threshold = float(self._threshold.replace("mJy", "")) / 1e3 

2112 elif "uJy" in self._threshold: 

2113 self._threshold = float(self._threshold.replace("uJy", "")) / 1e6 

2114 elif "Jy" in self._threshold: 

2115 self._threshold = float(self._threshold.replace("Jy", "")) 

2116 

2117 

2118 @staticmethod 

2119 def _validate(doc, schema): 

2120 """ Validate the input parameters against the schema. 

2121 

2122 Args: 

2123 doc: dict, input parameters 

2124 schema: dict, schema for the input parameters 

2125 

2126 Returns: 

2127 bool: True if the input parameters are valid, False otherwise 

2128 """ 

2129 return _pc.validate(doc, schema) 

2130 

2131 

2132 def _initialize_convergence_result(self): 

2133 """ 

2134 Initialize the convergence result with the correct number of outlier fields specified. 

2135 The structure of the convergence result is a list-of-lists, each element of the outer 

2136 list is a field. 

2137 

2138 The inner list is structured as 

2139 

2140 self.CR.convergence_result = [None,None,None,None,None,{'field_name':{'chan': None, 'major': None},}] 

2141 ^^^^ ^^^^ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----->>> convergence info - one dict of dicts per field 

2142 | | | | +----->>> Number of global iterations remaining for current run (niterleft) 

2143 | | | +---------->>> Number of major cycles remaining for current run (nmajorleft) 

2144 | | +---------------->>> major cycles done for current run (nmajordone) 

2145 | +------------------>>> tclean stopcode 

2146 """ 

2147 

2148 #for nn in range(self._nfields): 

2149 # self.CR.convergence_result.append([None, None, None, None, None, { 'chan': None, 'major': None }]) 

2150 self.CR.convergence_result.append(None, None, None, None, None) 

2151 

2152 field_dict = {} 

2153 for nn in range(self._nfields): 

2154 field_dict[self._fieldnames[nn]] = {'chan':None, 'major':None} 

2155 

2156 self.CR.convergence_result.append(field_dict) 

2157 

2158 

2159 

2160 def __init__(self, vis='', selectdata=True, field='', spw='', timerange='', uvrange='', antenna='', scan='', observation='', intent='', datacolumn='corrected', imagename='', imsize=[ int(100) ], cell=[ ], phasecenter='', stokes='I', projection='SIN', startmodel='', specmode='mfs', reffreq='', nchan=int(-1), start='', width='', outframe='LSRK', veltype='radio', restfreq=[ ], interpolation='linear', perchanweightdensity=True, gridder='standard', facets=int(1), psfphasecenter='', wprojplanes=int(1), vptable='', mosweight=True, aterm=True, psterm=False, wbawp=True, conjbeams=False, cfcache='', usepointing=False, computepastep=float(360.0), rotatepastep=float(360.0), pointingoffsetsigdev=[ ], pblimit=float(0.2), normtype='flatnoise', deconvolver='hogbom', scales=[ ], nterms=int(2), smallscalebias=float(0.0), fusedthreshold=float(0.0), largestscale=int(-1), restoration=True, restoringbeam=[ ], pbcor=False, outlierfile='', weighting='natural', robust=float(0.5), noise='1.0Jy', npixels=int(0), uvtaper=[ '' ], niter=int(0), gain=float(0.1), threshold=float(0.0), nsigma=float(0.0), cycleniter=int(-1), cyclefactor=float(1.0), minpsffraction=float(0.05), maxpsffraction=float(0.8), nmajor=int(-1), usemask='user', mask='', pbmask=float(0.0), sidelobethreshold=float(3.0), noisethreshold=float(5.0), lownoisethreshold=float(1.5), negativethreshold=float(0.0), smoothfactor=float(1.0), minbeamfrac=float(0.3), cutthreshold=float(0.01), growiterations=int(75), dogrowprune=True, minpercentchange=float(-1.0), verbose=False, fastnoise=True, restart=True, savemodel='none', calcres=True, calcpsf=True, psfcutoff=float(0.35), parallel=False, history_filter=lambda index, arg, history_value: history_value ): 

2161 

2162 schema = { 'vis': {'anyof': [{'type': 'cReqPath', 'coerce': _coerce.expand_path}, {'type': 'cReqPathVec', 'coerce': [_coerce.to_list,_coerce.expand_pathvec]}]}, 'selectdata': {'type': 'cBool'}, 'field': {'anyof': [{'type': 'cStr', 'coerce': _coerce.to_str}, {'type': 'cStrVec', 'coerce': [_coerce.to_list,_coerce.to_strvec]}]}, 'spw': {'anyof': [{'type': 'cStr', 'coerce': _coerce.to_str}, {'type': 'cStrVec', 'coerce': [_coerce.to_list,_coerce.to_strvec]}]}, 'timerange': {'anyof': [{'type': 'cStr', 'coerce': _coerce.to_str}, {'type': 'cStrVec', 'coerce': [_coerce.to_list,_coerce.to_strvec]}]}, 'uvrange': {'anyof': [{'type': 'cStr', 'coerce': _coerce.to_str}, {'type': 'cStrVec', 'coerce': [_coerce.to_list,_coerce.to_strvec]}]}, 'antenna': {'anyof': [{'type': 'cStr', 'coerce': _coerce.to_str}, {'type': 'cStrVec', 'coerce': [_coerce.to_list,_coerce.to_strvec]}]}, 'scan': {'anyof': [{'type': 'cStr', 'coerce': _coerce.to_str}, {'type': 'cStrVec', 'coerce': [_coerce.to_list,_coerce.to_strvec]}]}, 'observation': {'anyof': [{'type': 'cStr', 'coerce': _coerce.to_str}, {'type': 'cInt'}]}, 'intent': {'anyof': [{'type': 'cStr', 'coerce': _coerce.to_str}, {'type': 'cStrVec', 'coerce': [_coerce.to_list,_coerce.to_strvec]}]}, 'datacolumn': {'type': 'cStr', 'coerce': _coerce.to_str}, 'imagename': {'anyof': [{'type': 'cInt'}, {'type': 'cStr', 'coerce': _coerce.to_str}, {'type': 'cStrVec', 'coerce': [_coerce.to_list,_coerce.to_strvec]}]}, 'imsize': {'anyof': [{'type': 'cInt'}, {'type': 'cIntVec', 'coerce': [_coerce.to_list,_coerce.to_intvec]}]}, 'cell': {'anyof': [{'type': 'cIntVec', 'coerce': [_coerce.to_list,_coerce.to_intvec]}, {'type': 'cStr', 'coerce': _coerce.to_str}, {'type': 'cFloat', 'coerce': _coerce.to_float}, {'type': 'cStrVec', 'coerce': [_coerce.to_list,_coerce.to_strvec]}, {'type': 'cInt'}, {'type': 'cFloatVec', 'coerce': [_coerce.to_list,_coerce.to_floatvec]}]}, 'phasecenter': {'anyof': [{'type': 'cInt'}, {'type': 'cStr', 'coerce': _coerce.to_str}]}, 'stokes': {'type': 'cStr', 'coerce': _coerce.to_str, 'allowed': [ 'I', 'IQUV', 'UV', 'RRLL', 'IQ', 'V', 'pseudoI', 'QU', 'YY', 'RR', 'Q', 'U', 'IV', 'XX', 'XXYY', 'LL' ]}, 'projection': {'type': 'cStr', 'coerce': _coerce.to_str}, 'startmodel': {'type': 'cVariant', 'coerce': [_coerce.to_variant]}, 'specmode': {'type': 'cStr', 'coerce': _coerce.to_str, 'allowed': [ 'cont', 'cubedata', 'cube', 'cubesource', 'mfs', 'mvc' ]}, 'reffreq': {'type': 'cVariant', 'coerce': [_coerce.to_variant]}, 'nchan': {'type': 'cInt'}, 'start': {'type': 'cVariant', 'coerce': [_coerce.to_variant]}, 'width': {'type': 'cVariant', 'coerce': [_coerce.to_variant]}, 'outframe': {'type': 'cStr', 'coerce': _coerce.to_str}, 'veltype': {'type': 'cStr', 'coerce': _coerce.to_str}, 'restfreq': {'type': 'cVariant', 'coerce': [_coerce.to_variant]}, 'interpolation': {'type': 'cStr', 'coerce': _coerce.to_str, 'allowed': [ 'nearest', 'linear', 'cubic' ]}, 'perchanweightdensity': {'type': 'cBool'}, 'gridder': {'type': 'cStr', 'coerce': _coerce.to_str, 'allowed': [ 'widefield', 'wproject', 'awphpg', 'imagemosaic', 'standard', 'awproject', 'wprojectft', 'mosaicft', 'ft', 'ftmosaic', 'mosaic', 'awprojectft', 'gridft', 'awp2' ]}, 'facets': {'type': 'cInt'}, 'psfphasecenter': {'anyof': [{'type': 'cInt'}, {'type': 'cStr', 'coerce': _coerce.to_str}]}, 'wprojplanes': {'type': 'cInt'}, 'vptable': {'type': 'cStr', 'coerce': _coerce.to_str}, 'mosweight': {'type': 'cBool'}, 'aterm': {'type': 'cBool'}, 'psterm': {'type': 'cBool'}, 'wbawp': {'type': 'cBool'}, 'conjbeams': {'type': 'cBool'}, 'cfcache': {'type': 'cStr', 'coerce': _coerce.to_str}, 'usepointing': {'type': 'cBool'}, 'computepastep': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'rotatepastep': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'pointingoffsetsigdev': {'anyof': [{'type': 'cIntVec', 'coerce': [_coerce.to_list,_coerce.to_intvec]}, {'type': 'cFloatVec', 'coerce': [_coerce.to_list,_coerce.to_floatvec]}]}, 'pblimit': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'normtype': {'type': 'cStr', 'coerce': _coerce.to_str}, 'deconvolver': {'type': 'cStr', 'coerce': _coerce.to_str, 'allowed': [ 'clarkstokes_exp', 'mtmfs', 'mem', 'clarkstokes', 'hogbom', 'clark_exp', 'clark', 'asp', 'multiscale' ]}, 'scales': {'anyof': [{'type': 'cIntVec', 'coerce': [_coerce.to_list,_coerce.to_intvec]}, {'type': 'cFloatVec', 'coerce': [_coerce.to_list,_coerce.to_floatvec]}]}, 'nterms': {'type': 'cInt'}, 'smallscalebias': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'fusedthreshold': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'largestscale': {'type': 'cInt'}, 'restoration': {'type': 'cBool'}, 'restoringbeam': {'anyof': [{'type': 'cStr', 'coerce': _coerce.to_str}, {'type': 'cStrVec', 'coerce': [_coerce.to_list,_coerce.to_strvec]}]}, 'pbcor': {'type': 'cBool'}, 'outlierfile': {'type': 'cStr', 'coerce': _coerce.to_str}, 'weighting': {'type': 'cStr', 'coerce': _coerce.to_str, 'allowed': [ 'briggsabs', 'briggs', 'briggsbwtaper', 'natural', 'radial', 'superuniform', 'uniform' ]}, 'robust': {'type': 'cFloat', 'coerce': _coerce.to_float, 'min': -2.0, 'max': 2.0}, 'noise': {'type': 'cVariant', 'coerce': [_coerce.to_variant]}, 'npixels': {'type': 'cInt'}, 'uvtaper': {'type': 'cStrVec', 'coerce': [_coerce.to_list,_coerce.to_strvec]}, 'niter': {'type': 'cInt'}, 'gain': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'threshold': {'type': 'cVariant', 'coerce': [_coerce.to_variant]}, 'nsigma': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'cycleniter': {'type': 'cInt'}, 'cyclefactor': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'minpsffraction': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'maxpsffraction': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'nmajor': {'type': 'cInt'}, 'usemask': {'type': 'cStr', 'coerce': _coerce.to_str, 'allowed': [ 'user', 'pb', 'auto-multithresh' ]}, 'mask': {'anyof': [{'type': 'cStr', 'coerce': _coerce.to_str}, {'type': 'cStrVec', 'coerce': [_coerce.to_list,_coerce.to_strvec]}]}, 'pbmask': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'sidelobethreshold': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'noisethreshold': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'lownoisethreshold': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'negativethreshold': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'smoothfactor': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'minbeamfrac': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'cutthreshold': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'growiterations': {'type': 'cInt'}, 'dogrowprune': {'type': 'cBool'}, 'minpercentchange': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'verbose': {'type': 'cBool'}, 'fastnoise': {'type': 'cBool'}, 'restart': {'type': 'cBool'}, 'savemodel': {'type': 'cStr', 'coerce': _coerce.to_str, 'allowed': [ 'none', 'virtual', 'modelcolumn' ]}, 'calcres': {'type': 'cBool'}, 'calcpsf': {'type': 'cBool'}, 'psfcutoff': {'type': 'cFloat', 'coerce': _coerce.to_float}, 'parallel': {'type': 'cBool'}, } 

2163 doc = { 'vis': vis, 'selectdata': selectdata, 'field': field, 'spw': spw, 'timerange': timerange, 'uvrange': uvrange, 'antenna': antenna, 'scan': scan, 'observation': observation, 'intent': intent, 'datacolumn': datacolumn, 'imagename': imagename, 'imsize': imsize, 'cell': cell, 'phasecenter': phasecenter, 'stokes': stokes, 'projection': projection, 'startmodel': startmodel, 'specmode': specmode, 'reffreq': reffreq, 'nchan': nchan, 'start': start, 'width': width, 'outframe': outframe, 'veltype': veltype, 'restfreq': restfreq, 'interpolation': interpolation, 'perchanweightdensity': perchanweightdensity, 'gridder': gridder, 'facets': facets, 'psfphasecenter': psfphasecenter, 'wprojplanes': wprojplanes, 'vptable': vptable, 'mosweight': mosweight, 'aterm': aterm, 'psterm': psterm, 'wbawp': wbawp, 'conjbeams': conjbeams, 'cfcache': cfcache, 'usepointing': usepointing, 'computepastep': computepastep, 'rotatepastep': rotatepastep, 'pointingoffsetsigdev': pointingoffsetsigdev, 'pblimit': pblimit, 'normtype': normtype, 'deconvolver': deconvolver, 'scales': scales, 'nterms': nterms, 'smallscalebias': smallscalebias, 'fusedthreshold': fusedthreshold, 'largestscale': largestscale, 'restoration': restoration, 'restoringbeam': restoringbeam, 'pbcor': pbcor, 'outlierfile': outlierfile, 'weighting': weighting, 'robust': robust, 'noise': noise, 'npixels': npixels, 'uvtaper': uvtaper, 'niter': niter, 'gain': gain, 'threshold': threshold, 'nsigma': nsigma, 'cycleniter': cycleniter, 'cyclefactor': cyclefactor, 'minpsffraction': minpsffraction, 'maxpsffraction': maxpsffraction, 'nmajor': nmajor, 'usemask': usemask, 'mask': mask, 'pbmask': pbmask, 'sidelobethreshold': sidelobethreshold, 'noisethreshold': noisethreshold, 'lownoisethreshold': lownoisethreshold, 'negativethreshold': negativethreshold, 'smoothfactor': smoothfactor, 'minbeamfrac': minbeamfrac, 'cutthreshold': cutthreshold, 'growiterations': growiterations, 'dogrowprune': dogrowprune, 'minpercentchange': minpercentchange, 'verbose': verbose, 'fastnoise': fastnoise, 'restart': restart, 'savemodel': savemodel, 'calcres': calcres, 'calcpsf': calcpsf, 'psfcutoff': psfcutoff, 'parallel': parallel, } 

2164 assert self._validate(doc, schema), create_error_string(_pc.errors) 

2165 

2166 if len(imagename) == 0: 

2167 raise Exception("imagename must be specified") 

2168 

2169 self._vis = vis 

2170 self._imagename = imagename 

2171 self._selectdata = selectdata 

2172 self._imsize = imsize 

2173 self._cell = cell 

2174 self._phasecenter = phasecenter 

2175 self._projection = projection 

2176 self._stokes = stokes 

2177 self._startmodel = startmodel 

2178 self._specmode = specmode 

2179 self._reffreq = reffreq 

2180 self._nchan = nchan 

2181 self._start = start 

2182 self._width = width 

2183 self._outframe = outframe 

2184 self._veltype = veltype 

2185 self._restfreq = restfreq 

2186 self._interpolation = interpolation 

2187 self._perchanweightdensity = perchanweightdensity 

2188 self._gridder = gridder 

2189 self._facets = facets 

2190 self._psfphasecenter = psfphasecenter 

2191 self._wprojplanes = wprojplanes 

2192 self._mosweight = mosweight 

2193 self._aterm = aterm 

2194 self._psterm = psterm 

2195 self._wbawp = wbawp 

2196 self._conjbeams = conjbeams 

2197 self._usepointing = usepointing 

2198 self._cfcache = cfcache 

2199 self._pointingoffsetsigdev = pointingoffsetsigdev 

2200 self._vpable = vptable 

2201 self._computepastep = computepastep 

2202 self._rotatepastep = rotatepastep 

2203 self._pblimit = pblimit 

2204 self._normtype = normtype 

2205 self._deconvolver = deconvolver 

2206 self._smallscalebias = smallscalebias 

2207 self._fusedthreshold = fusedthreshold 

2208 self._largestscale = largestscale 

2209 self._niter = niter 

2210 self._threshold = threshold 

2211 self._cycleniter = cycleniter 

2212 self._minpsffraction = minpsffraction 

2213 self._maxpsffraction = maxpsffraction 

2214 self._nsigma = nsigma 

2215 self._nmajor = nmajor 

2216 self._cyclefactor = cyclefactor 

2217 self._scales = scales 

2218 self._restoringbeam = restoringbeam 

2219 self._pbcor = pbcor 

2220 self._outlierfile = outlierfile 

2221 self._nterms = nterms 

2222 self._exe_cmds = [ ] 

2223 self._exe_cmds_per_iter = [ ] 

2224 self._history_filter = history_filter 

2225 self._finalized = False 

2226 self._field = field 

2227 self._spw = spw 

2228 self._timerange = timerange 

2229 self._uvrange = uvrange 

2230 self._antenna = antenna 

2231 self._scan = scan 

2232 self._observation = observation 

2233 self._intent = intent 

2234 self._datacolumn = datacolumn 

2235 self._weighting = weighting 

2236 self._robust = robust 

2237 self._noise = noise 

2238 self._uvtaper = uvtaper 

2239 self._npixels = npixels 

2240 self._gain = gain 

2241 self._pbmask = pbmask 

2242 self._sidelobethreshold = sidelobethreshold 

2243 self._noisethreshold = noisethreshold 

2244 self._lownoisethreshold = lownoisethreshold 

2245 self._negativethreshold = negativethreshold 

2246 self._smoothfactor = smoothfactor 

2247 self._minbeamfrac = minbeamfrac 

2248 self._cutthreshold = cutthreshold 

2249 self._growiterations = growiterations 

2250 self._dogrowprune = dogrowprune 

2251 self._minpercentchange = minpercentchange 

2252 self._verbose = verbose 

2253 self._fastnoise = fastnoise 

2254 self._savemodel = savemodel 

2255 self._parallel = parallel 

2256 self._usemask = usemask 

2257 self._mask = mask 

2258 self._restoration = restoration 

2259 self._restart = restart 

2260 self._calcres = calcres 

2261 self._calcpsf = calcpsf 

2262 self._psfcutoff = psfcutoff 

2263 self.global_imdict = ImagingDict() 

2264 self.current_imdict = ImagingDict() 

2265 self._major_done = 0 

2266 self.hasit = StopCodes(major=0,minor=0) # Convergence flag 

2267 self._has_restored = False 

2268 self._nfields = 1 

2269 self._fieldnames = ['', ] # Default is a list of len 1 

2270 

2271 self.stopdescription = '' # Convergence flag 

2272 self._all_input_params = locals() 

2273 del self._all_input_params['self'] 

2274 

2275 self._initial_mask_exists = [] 

2276 self._paramlist = None 

2277 

2278 # Convert threshold from string to float, interpreting units. 

2279 # XXX : We should ideally use quantities, but we are trying to 

2280 # stick to "public API" funtions inside _gclean 

2281 self._threshold_to_float() 

2282 

2283 # Read in params and calculate nfields 

2284 self._get_imager_parameters(locals()) 

2285 # Initialize convergence result for each field being imaged 

2286 # this has been replaced by the ConvergenceResult class 

2287 #self._initialize_convergence_result() 

2288 

2289 self.hasit_per_field = [False for _ in range(self._nfields)] 

2290 self.CR = ConvergenceResult(self._nfields, self._fieldnames) 

2291 

2292 

2293 def _get_imager_parameters(self, inpparams): 

2294 """ 

2295 Initialize ImagerParameters object and set the parameters 

2296 """ 

2297 

2298 # Drop unnecessary params 

2299 del inpparams['self'] 

2300 del inpparams['schema'] 

2301 del inpparams['history_filter'] 

2302 

2303 # deal with parameters that are not the same name 

2304 inpparams, defparm = sanitize_tclean_inputs(inpparams) 

2305 

2306 # Stolen from task_tclean.py 

2307 bparm = {k: inpparams[k] if k in inpparams else defparm[k] for k in defparm.keys()} 

2308 self._paramlist = ImagerParameters(**bparm) 

2309 

2310 self._nfields = len(self._paramlist.allimpars.keys()) 

2311 self._fieldnames = [val['imagename'] for key, val in self._paramlist.allimpars.items()] 

2312 

2313 return self._paramlist 

2314 

2315 

2316 def __update_convergence(self, field=0): 

2317 """ 

2318 Accumulates the per-channel/stokes summaryminor keys across all major cycle calls so far. 

2319 

2320 The "iterDone" key will be replaced with "iterations", and for the "iterations" key, 

2321 the value in the returned cummulative record will be a rolling sum of iterations done 

2322 for tclean calls so far, one value per minor cycle. 

2323 For example, if there have been two clean calls, and in the first call channel 0 had 

2324 [1] iteration in 1 minor cycle, and for the second call channel 0 had [6, 10, 9, 1] 

2325 iterations in 4 minor cycles), then the resultant "iterations" key for channel 0 would be: 

2326 [1, 7, 17, 26, 27] 

2327 

2328 Inputs: 

2329 field: int, field index to update convergence for. Default is 0, which is the main field. 

2330 If there are multiple fields, this will be the index of the field to update. 

2331 Returns: 

2332 outrec: dict, a nested dictionary with the following structure: 

2333 { 

2334 channel_id: { 

2335 stokes_id: { 

2336 summary_key: [values, one per minor cycle] 

2337 } 

2338 } 

2339 } 

2340 """ 

2341 

2342 keys = ['modelFlux', 'iterDone', 'peakRes', 'stopCode', 'cycleThresh'] 

2343 

2344 # Grab tuples of keys of interest 

2345 outrec = {} 

2346 for nn in range(self.global_imdict.nchan): 

2347 outrec[nn] = {} 

2348 for ss in range(self.global_imdict.nstokes): 

2349 outrec[nn][ss] = {} 

2350 for key in keys: 

2351 # Replace iterDone with iterations 

2352 if key == 'iterDone': 

2353 # Maintain cumulative sum of iterations per entry 

2354 outrec[nn][ss]['iterations'] = np.cumsum(self.global_imdict.get_key(key, field=field, stokes=ss, chan=nn)) 

2355 # Replace iterDone with iterations 

2356 #outrec[nn][ss]['iterations'] = self.global_imdict.get_key(key, stokes=ss, chan=nn) 

2357 else: 

2358 outrec[nn][ss][key] = self.global_imdict.get_key(key, field=field, stokes=ss, chan=nn) 

2359 

2360 return outrec 

2361 

2362 

2363 

2364 def __add_per_major_items( self, tclean_ret, major_ret): 

2365 '''Add meta-data about the whole major cycle, including 'cyclethreshold' 

2366 ''' 

2367 # Original if code : 

2368 #rdict = dict( major=dict( cyclethreshold=[tclean_ret['cyclethreshold']] if major_ret is None else (major_ret['cyclethreshold'] + [tclean_ret['cyclethreshold']]) ), 

2369 # chan=chan_ret ) 

2370 # --- 

2371 # original else code 

2372 #rdict = dict( major=dict( cyclethreshold=major_ret['cyclethreshold'].append(tclean_ret['cyclethreshold']) ), 

2373 # chan=chan_ret ) 

2374 

2375 rdict = {} 

2376 

2377 for fidx, fname in enumerate(self._fieldnames): 

2378 if 'cyclethreshold' in tclean_ret: 

2379 if all([mj['major'] is None for mj in major_ret.values()]): 

2380 rdict[fname] = dict(major=dict(cyclethreshold=[tclean_ret['cyclethreshold']]), chan=self.__update_convergence(field=fidx)) 

2381 else: 

2382 rdict[fname] = dict(major=dict(cyclethreshold=major_ret[fname]['major']['cyclethreshold'] + [tclean_ret['cyclethreshold']]), chan=self.__update_convergence(field=fidx)) 

2383 else: 

2384 # It really shouldn't get to this point... 

2385 rdict = dict(major=dict([mj['major']['cyclethreshold'] for mj in major_ret.values()] + [tclean_ret['cyclethreshold']]), chan=self.__update_convergence(field=fidx)) 

2386 

2387 return rdict 

2388 

2389 

2390 

2391 def _calc_deconv_controls(self, imdict, field = 0, niterleft=0, threshold=0, cycleniter=-1, hasit_per_field=None): 

2392 """ 

2393 Calculate cycleniter and cyclethreshold for deconvolution. 

2394 """ 

2395 

2396 use_cycleniter = niterleft #niter - imdict.returndict['iterdone'] 

2397 

2398 if cycleniter > -1 : # User is forcing this number 

2399 use_cycleniter = min(cycleniter, use_cycleniter) 

2400 

2401 psffrac = imdict.returndict['maxpsfsidelobe'] * self._cyclefactor 

2402 psffrac = max(psffrac, self._minpsffraction) 

2403 psffrac = min(psffrac, self._maxpsffraction) 

2404 

2405 # Each field needs it's own cyclethreshold 

2406 cyclethresh_per_field = [] 

2407 for fidx, fieldid in enumerate(self._paramlist.allimpars.keys()): 

2408 if hasit_per_field is not None: 

2409 if hasit_per_field[fidx]: 

2410 # If convergence is hit, skip this field 

2411 cyclethresh_per_field.append(None) 

2412 continue 

2413 

2414 if fidx not in imdict.returndict['summaryminor']: 

2415 # If the field is not in the summaryminor, then we cannot calculate the cyclethreshold 

2416 # So set to the default for now 

2417 # This can happen if the field has not been imaged yet. 

2418 cyclethresh_per_field.append(self._threshold) 

2419 continue 

2420 

2421 cyclethreshold = psffrac * imdict.get_peakres(field=fidx) 

2422 cyclethreshold = max(cyclethreshold, threshold) 

2423 cyclethresh_per_field.append(cyclethreshold) 

2424 

2425 return int(use_cycleniter), cyclethresh_per_field 

2426 

2427 

2428 def _check_initial_mask(self): 

2429 """ 

2430 Check if a mask from a previous run exists on disk or not. 

2431 """ 

2432 

2433 image_products = self.image_products() 

2434 

2435 for product in image_products: 

2436 if self._usemask == 'user' and self._mask == '': 

2437 maskname = product['maskname'] 

2438 

2439 if os.path.exists(maskname): 

2440 self._initial_mask_exists.append(True) 

2441 else: 

2442 self._initial_mask_exists.append(False) 

2443 

2444 

2445 def _fix_initial_mask(self): 

2446 """ 

2447 If on start up, no user mask is provided, then flip the initial mask to 

2448 be all zeros for interactive use. 

2449 """ 

2450 

2451 from casatools import image 

2452 ia = image() 

2453 

2454 image_products = self.image_products() 

2455 

2456 if self._usemask == 'user' and self._mask == '': 

2457 for idx, product in enumerate(image_products): 

2458 maskname = product['maskname'] 

2459 

2460 # This means the mask was newly created by deconvolve, so flip it 

2461 if os.path.exists(maskname) and self._initial_mask_exists[idx] is False: 

2462 ia.open(maskname) 

2463 ia.set(0.0) 

2464 ia.close() 

2465 

2466 

2467 def _update_peakres_masksum_multifield(self): 

2468 """ 

2469 Update peak residual value in the return dict for each image on disk - 

2470 main field and outliers 

2471 """ 

2472 

2473 image_products = self.image_products() 

2474 

2475 imstats = [] 

2476 

2477 for idx, product in enumerate(image_products): 

2478 residname = product['residualname'] 

2479 maskname = product['maskname'] 

2480 

2481 statsdict = {} 

2482 

2483 if not os.path.exists(maskname): 

2484 maskname = '' 

2485 

2486 peakres = imstat(imagename=residname, mask=f'''"{maskname}"''')['max'] 

2487 if len(maskname) > 0: 

2488 masksum = imstat(imagename=maskname)['sum'] 

2489 else: 

2490 masksum = [] 

2491 

2492 if len(peakres) > 0: 

2493 peakres = peakres[0] 

2494 else: 

2495 peakres = None 

2496 

2497 if len(masksum) > 0: 

2498 masksum = masksum[0] 

2499 else: 

2500 masksum = None 

2501 

2502 statsdict['idx'] = idx 

2503 statsdict['imagename'] = product['imagename'] 

2504 statsdict['peakres'] = peakres 

2505 statsdict['masksum'] = masksum 

2506 

2507 imstats.append(statsdict) 

2508 

2509 #return peakres, masksum 

2510 return imstats 

2511 

2512 

2513 def image_products(self, imageidx = None): 

2514 """ 

2515 Function that returns the image names for all fields. 

2516 

2517 Optionally if imageidx is specified, return the image names 

2518 only for that specific index. 

2519 

2520 By default it returns a list of dicts, where each element in the list is a 

2521 field. The dicts have the following keys: 

2522 

2523 - imageidx: index of the field (0 for the main field, 1 for the first outlier etc.) 

2524 - imagename: name of the image 

2525 - maskname: name of the mask 

2526 - residualname: name of the residual 

2527 - imagepath: path to the image 

2528 """ 

2529 

2530 # Use pysynthimager to get the names of the outlierfields 

2531 # Populate paths and names, generate list 

2532 # Use this function instead of self._imagename wherever possible. 

2533 

2534 allimpars = self._paramlist.allimpars 

2535 imlist = [] 

2536 

2537 for key, value in allimpars.items(): 

2538 if imageidx is not None: 

2539 if imageidx != int(key): 

2540 continue 

2541 

2542 imdict = {} 

2543 

2544 fullpath = os.path.abspath(value['imagename']) 

2545 imname = os.path.basename(fullpath) 

2546 deconvolver = value['deconvolver'] 

2547 

2548 if deconvolver == 'mtmfs': 

2549 suffix = '.tt0' 

2550 else: 

2551 suffix = '' 

2552 

2553 imdict['name'] = imname 

2554 imdict['imagename'] = imname + f'.image{suffix}' 

2555 imdict['imagepath'] = os.path.dirname(fullpath) 

2556 

2557 imdict['maskname'] = imname + '.mask' 

2558 imdict['residualname'] = imname + f'.residual{suffix}' 

2559 

2560 # Append to list 

2561 imlist.append(imdict) 

2562 

2563 return imlist 

2564 

2565 def _generate_convergence_log(self, hasit_per_field, stopcode_min_per_field, stopdesc_per_field): 

2566 """ 

2567 Generate a string that summarizes the convergence information for all fields, that 

2568 can be passed in to the logger function. 

2569 

2570 Inputs: 

2571 hasit_per_field: list of bools, whether convergence was hit for each field 

2572 stopcode_min_per_field: list of ints, the stop code for each field 

2573 stopdesc_per_field: list of str, the stop description for each field 

2574 

2575 Returns: 

2576 logstr : str, a string that summarizes the convergence information for all fields 

2577 """ 

2578 

2579 logstr = '' 

2580 logstr += f"#################################### Convergence Log ###################################<br>" 

2581 logstr += f"# {'Field Name':^20s} | {'Description':^46s} | Code (maj, min)<br>" 

2582 logstr += "#----------------------------------------------------------------------------------------<br>" 

2583 for fidx, fieldname in enumerate(self._fieldnames): 

2584 if hasit_per_field[fidx]: 

2585 logstr += f"# {fieldname:^20s} | {stopdesc_per_field[fidx]:^46s} | ({hasit_per_field[fidx]}, {stopcode_min_per_field[fidx]})<br>" 

2586 else: 

2587 logstr += f"# {fieldname:^20s} | {'Not converged':^46s} | ({hasit_per_field[fidx]}, {stopcode_min_per_field[fidx]})<br>" 

2588 logstr += "########################################################################################<br>" 

2589 logstr = logstr.replace(" ", "&nbsp;") # Replace spaces with non-breaking spaces for HTML rendering 

2590 return logstr 

2591 

2592 

2593 def __next__( self ): 

2594 """ Runs tclean and returns the (stopcode, convergence result) when executed with the python builtin next() function. 

2595 

2596 The returned convergence result is a nested dictionary: 

2597 { 

2598 channel id: { 

2599 stokes id: { 

2600 summary key: [values, one per minor cycle] 

2601 }, 

2602 }, 

2603 } 

2604 

2605 See also: gclean.__update_convergence(...) 

2606 """ 

2607 

2608 tclean_ret = {} 

2609 deconv_ret = {} 

2610 stopcode_min_per_field = [0 for _ in range(self._nfields)] 

2611 stopdesc_per_field = ['' for _ in range(self._nfields)] 

2612 

2613 # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv------------>>> is done to produce an initial dirty image 

2614 if self._niter < 1 and self.CR.convergence_result[2] is not None: 

2615 self.CR.convergence_result = ( f'nothing to run, niter == {self._niter}', 

2616 self.CR.convergence_result[1], 

2617 self._major_done, 

2618 self._nmajor, 

2619 self._niter, 

2620 self.CR.convergence_result[5] ) 

2621 return self.CR.convergence_result 

2622 else: 

2623 ### CALL SEQUENCE: 

2624 ### tclean(niter=0),deconvolve(niter=0),tclean(niter=100),deconvolve(niter=0),tclean(niter=100),tclean(niter=0,restoration=True) 

2625 self._exe_cmds_per_iter.append(0) 

2626 try: 

2627 if self.CR.convergence_result[1] is None: 

2628 # initial call to tclean(...) creates the initial dirty image with niter=0 

2629 

2630 # If calcres and calcpsf are False, no need to run initial tclean - assume image products already on disk. 

2631 if not (self._calcres == False and self._calcpsf == False): 

2632 casalog.post('Running initial major cycle to create first residual image.', 'INFO') 

2633 print('Running initial major cycle to create first residual image.') 

2634 tclean_ret = self._tclean( vis=self._vis, mask=self._mask, imagename=self._imagename, imsize=self._imsize, cell=self._cell, selectdata=self._selectdata, phasecenter=self._phasecenter, stokes=self._stokes, 

2635 startmodel=self._startmodel, specmode=self._specmode, projection=self._projection, reffreq=self._reffreq, gridder=self._gridder, wprojplanes=self._wprojplanes, facets=self._facets, 

2636 mosweight=self._mosweight, psfphasecenter = self._psfphasecenter, aterm=self._aterm, psterm=self._psterm, wbawp=self._wbawp, conjbeams=self._conjbeams, cfcache=self._cfcache, 

2637 usepointing=self._usepointing, computepastep=self._computepastep, rotatepastep=self._rotatepastep, normtype=self._normtype, fusedthreshold=self._fusedthreshold, 

2638 largestscale=self._largestscale, noise = self._noise, uvtaper=self._uvtaper, psfcutoff=self._psfcutoff, interpolation=self._interpolation, 

2639 perchanweightdensity=self._perchanweightdensity, nchan=self._nchan, start=self._start, width=self._width, veltype=self._veltype, restfreq=self._restfreq, outframe=self._outframe, 

2640 pointingoffsetsigdev=self._pointingoffsetsigdev, pblimit=self._pblimit, deconvolver=self._deconvolver, smallscalebias=self._smallscalebias, cyclefactor=self._cyclefactor, 

2641 scales=self._scales, restoringbeam=self._restoringbeam, pbcor=self._pbcor, nterms=self._nterms, field=self._field, spw=self._spw, timerange=self._timerange, uvrange=self._uvrange, 

2642 antenna=self._antenna, scan=self._scan, observation=self._observation, intent=self._intent, datacolumn=self._datacolumn, weighting=self._weighting, robust=self._robust, 

2643 npixels=self._npixels, interactive=False, niter=0, gain=self._gain, calcres=self._calcres, calcpsf=self._calcpsf, restoration=False, parallel=self._parallel, fullsummary=True, 

2644 outlierfile = self._outlierfile) 

2645 

2646 # Check if a mask from a previous run exists on disk 

2647 # This loops over all fields 

2648 self._check_initial_mask() 

2649 

2650 # deconv args are parsed correctly inside this function 

2651 deconv_ret = self._deconv_over_fields(niter=0) 

2652 # If no mask from a previous run exists, over-write the ones with zeros for the default mask 

2653 self._fix_initial_mask() 

2654 

2655 if len(tclean_ret) > 0 and len(deconv_ret) > 0: 

2656 self.current_imdict.returndict = self.current_imdict.merge(tclean_ret, deconv_ret) 

2657 elif len(tclean_ret) > 0 and len(deconv_ret) == 0: 

2658 self.current_imdict.returndict = copy.deepcopy(tclean_ret) 

2659 elif len(tclean_ret) == 0 and len(deconv_ret) > 0: 

2660 self.current_imdict.returndict = copy.deepcopy(deconv_ret) 

2661 else: # Both dicts are empty, this should never happen 

2662 raise ValueError("Both tclean and deconvolve return dicts are empty. This should never happen.") 

2663 

2664 

2665 self.global_imdict.returndict = self.current_imdict.returndict 

2666 

2667 self.current_imdict.returndict['stopcode'] = self.hasit 

2668 self.current_imdict.returndict['stopDescription'] = self.stopdescription 

2669 self._major_done = 0 

2670 else: 

2671 # Reset convergence every time, since we return control to the GUI after a single major cycle 

2672 self.current_imdict.returndict['iterdone'] = 0. 

2673 

2674 # Mask can be updated here... 

2675 # Check for mask update - peakres + masksum 

2676 # imstats is a list of dicts 

2677 imstats = self._update_peakres_masksum_multifield() 

2678 

2679 self.hasit, self.stopdescription, self.hasit_per_field, __, __ = self.global_imdict.check_convergence(self._niter, self._threshold, self._nmajor, imstats=imstats) 

2680 

2681 # Has not, i.e., not converged 

2682 if not self.hasit.major: 

2683 use_cycleniter, cyclethresh_per_field = self._calc_deconv_controls(self.current_imdict, niterleft=self._niter, threshold=self._threshold, cycleniter=self._cycleniter) 

2684 

2685 # deconv args are parsed correctly inside this function 

2686 # This will skip fields that have already converged 

2687 deconv_ret = self._deconv_over_fields(niter=use_cycleniter, mask='', threshold=cyclethresh_per_field, hasit_per_field=self.hasit_per_field) 

2688 

2689 # Joint major cycle over all fields 

2690 # Run the major cycle 

2691 tclean_ret = self._tclean( vis=self._vis, imagename=self._imagename, imsize=self._imsize, cell=self._cell, 

2692 phasecenter=self._phasecenter, stokes=self._stokes, specmode=self._specmode, reffreq=self._reffreq, 

2693 gridder=self._gridder, wprojplanes=self._wprojplanes, mosweight=self._mosweight, psterm=self._psterm, 

2694 wbawp=self._wbawp, conjbeams=self._conjbeams, usepointing=self._usepointing, interpolation=self._interpolation, 

2695 perchanweightdensity=self._perchanweightdensity, nchan=self._nchan, start=self._start, 

2696 width=self._width, veltype=self._veltype, restfreq=self._restfreq, outframe=self._outframe, 

2697 pointingoffsetsigdev=self._pointingoffsetsigdev, pblimit=self._pblimit, deconvolver=self._deconvolver, 

2698 smallscalebias=self._smallscalebias, cyclefactor=self._cyclefactor, scales=self._scales, 

2699 restoringbeam=self._restoringbeam, pbcor=self._pbcor, nterms=self._nterms, field=self._field, 

2700 spw=self._spw, timerange=self._timerange, uvrange=self._uvrange, antenna=self._antenna, 

2701 scan=self._scan, observation=self._observation, intent=self._intent, datacolumn=self._datacolumn, 

2702 weighting=self._weighting, robust=self._robust, npixels=self._npixels, interactive=False, 

2703 niter=0, restart=True, calcpsf=False, calcres=True, restoration=False, threshold=self._threshold, 

2704 nsigma=self._nsigma, cycleniter=self._cycleniter, nmajor=1, gain=self._gain, 

2705 sidelobethreshold=self._sidelobethreshold, noisethreshold=self._noisethreshold, 

2706 lownoisethreshold=self._lownoisethreshold, negativethreshold=self._negativethreshold, 

2707 minbeamfrac=self._minbeamfrac, growiterations=self._growiterations, dogrowprune=self._dogrowprune, 

2708 minpercentchange=self._minpercentchange, fastnoise=self._fastnoise, savemodel='none', 

2709 maxpsffraction=self._maxpsffraction, 

2710 minpsffraction=self._minpsffraction, parallel=self._parallel, fullsummary=True, outlierfile=self._outlierfile) 

2711 

2712 # Replace return dict with new return dict 

2713 # The order of the dicts into merge is important. 

2714 self.current_imdict.returndict = self.current_imdict.merge(tclean_ret, deconv_ret) 

2715 

2716 # Append new return dict to global return dict 

2717 self.global_imdict.returndict = self.global_imdict.concat(self.global_imdict.returndict, self.current_imdict.returndict) 

2718 self._major_done = self.current_imdict.returndict['nmajordone'] 

2719 

2720 ## Decrement count for the major cycle just done... 

2721 self.__decrement_counts() 

2722 

2723 cycleniterleft = self._cycleniter - self.current_imdict.returndict['iterdone'] 

2724 

2725 # Use global imdict for convergence check 

2726 if deconv_ret['stopcode'] == 7: ## Tell the convergence checker that the mask is zero and iterations were skipped 

2727 self.hasit, self.stopdescription, self.hasit_per_field, stopcode_min_per_field, stopdesc_per_field = self.global_imdict.check_convergence(self._niter, self._threshold, self._nmajor, cycleniter=cycleniterleft) 

2728 else: 

2729 imstats = self._update_peakres_masksum_multifield() 

2730 self.hasit, self.stopdescription, self.hasit_per_field, stopcode_min_per_field, stopdesc_per_field = self.global_imdict.check_convergence(self._niter, self._threshold, self._nmajor, cycleniter=cycleniterleft, imstats=imstats) 

2731 

2732 # XXX : This is breaking, fix this to get the logging working correctly. 

2733 logstr = self._generate_convergence_log(self.hasit_per_field, stopcode_min_per_field, stopdesc_per_field) 

2734 self._exe_cmds.append(logstr) 

2735 self._exe_cmds_per_iter[-1] += 1 

2736 

2737 self.global_imdict.returndict['stopcode'] = self.hasit 

2738 self.global_imdict.returndict['stopDescription'] = self.stopdescription 

2739 

2740 

2741 if not self.hasit.major and self._usemask == 'auto-multithresh': 

2742 # If we haven't converged, run deconvolve to update the mask 

2743 # Note : This is only necessary if using auto-multithresh. If using the interactive viewer to draw, the mask gets updated as the regions 

2744 # are added or removed in the interactive viewer. 

2745 

2746 # deconv args are parsed correctly inside this function 

2747 deconv_ret = self._deconv_over_fields(niter=0, mask='', hasit_per_field=self.hasit_per_field) 

2748 

2749 if len(self.global_imdict.returndict) > 0 and 'summaryminor' in self.global_imdict.returndict and sum(map(len,self.global_imdict.returndict['summaryminor'].values())) > 0: 

2750 self.CR.convergence_result = ( self.global_imdict.returndict['stopDescription'] if 'stopDescription' in self.global_imdict.returndict else '', 

2751 self.global_imdict.returndict['stopcode'] if 'stopcode' in self.global_imdict.returndict else 0, 

2752 self._major_done, 

2753 self._nmajor, 

2754 self._niter, 

2755 self.__add_per_major_items( self.global_imdict.returndict, 

2756 #self.CR.convergence_result[5]['major'], 

2757 self.CR.convergence_result[5])) 

2758 #self.__update_convergence( ) ) ) 

2759 else: 

2760 self.CR.convergence_result = ( f'tclean returned an empty result', 

2761 self.CR.convergence_result[1], 

2762 self._major_done, 

2763 self._nmajor, 

2764 self._niter, 

2765 self.CR.convergence_result[5] ) 

2766 except Exception as e: 

2767 self.CR.convergence_result = ( str(e), 

2768 -1, 

2769 self._major_done, 

2770 self._nmajor, 

2771 self._niter, 

2772 self.CR.convergence_result[5] ) 

2773 return self.CR.convergence_result 

2774 

2775 return self.CR.convergence_result 

2776 

2777 def __decrement_counts( self ): 

2778 ## Update niterleft and nmajorleft now. 

2779 if not any (self.hasit): ##If not yet converged. 

2780 if self._nmajor != -1: ## If -1, don't touch it. 

2781 self._nmajor = self._nmajor - 1 

2782 if self._nmajor < 0: ## Force a floor 

2783 self._nmajor = 0 

2784 self._niter = self._niter - self.current_imdict.get_key('iterdone') 

2785 if self._niter < 0: ## This can happen when we're counting niter across channels in a single minor cycle set, and it crosses the total. 

2786 self._niter = 0 ## Force a floor 

2787 else: 

2788 return ##If convergence has been reached, don't try to decrement further. 

2789 

2790 

2791 def __reflect_stop( self ): 

2792 ## if python wasn't hacky, you would be able to try/except/raise in lambda 

2793 #time.sleep(1) 

2794 try: 

2795 return self.__next__( ) 

2796 except StopIteration: 

2797 raise StopAsyncIteration 

2798 

2799 async def __anext__( self ): 

2800 ### asyncio.run cannot be used here because this is called 

2801 ### within an asyncio loop... 

2802 loop = asyncio.get_event_loop( ) 

2803 result = await loop.run_in_executor( None, self.__reflect_stop ) 

2804 return result 

2805 

2806 def __iter__( self ): 

2807 return self 

2808 

2809 def __aiter__( self ): 

2810 return self 

2811 

2812 def __split_filename( self, path ): 

2813 return os.path.splitext(os.path.basename(path)) 

2814 

2815 def __default_mask_name( self ): 

2816 imgparts = self.__split_filename( self._imagename ) 

2817 return f'{imgparts[0]}.mask' 

2818 

2819 def __del__(self): 

2820 pass 

2821 

2822 def mask(self): 

2823 #return self.__default_mask_name() if self._mask == '' else self._mask 

2824 return f'{self._imagename}.mask' if self._mask == '' else self._mask 

2825 

2826 def reset(self): 

2827 #if not self._finalized: 

2828 # raise RuntimeError('attempt to reset a gclean run that has not been finalized') 

2829 self._finalized = False 

2830 self.CR.convergence_result = ( None, 

2831 self.CR.convergence_result[1], 

2832 self._major_done, 

2833 self._nmajor, 

2834 self._niter, 

2835 self.CR.convergence_result[5] ) 

2836 

2837 

2838 def restore(self): 

2839 """ 

2840 Restores the final image, and returns a path to the restored image. 

2841 If savemodel is specified, first predict the model column with tclean, 

2842 then run restore with deconvolve. 

2843 """ 

2844 

2845 casalog.post('Restoring final image (iterating over all fields)', 'INFO') 

2846 print("Restoring the final image (iterating over all fields)") 

2847 

2848 if self._savemodel != 'none': 

2849 # Run the major cycle to predict the model column 

2850 tclean_ret = self._tclean( vis=self._vis, imagename=self._imagename, imsize=self._imsize, cell=self._cell, 

2851 phasecenter=self._phasecenter, stokes=self._stokes, specmode=self._specmode, reffreq=self._reffreq, 

2852 gridder=self._gridder, wprojplanes=self._wprojplanes, mosweight=self._mosweight, psterm=self._psterm, 

2853 wbawp=self._wbawp, conjbeams=self._conjbeams, usepointing=self._usepointing, interpolation=self._interpolation, 

2854 perchanweightdensity=self._perchanweightdensity, nchan=self._nchan, start=self._start, 

2855 width=self._width, veltype=self._veltype, restfreq=self._restfreq, outframe=self._outframe, 

2856 pointingoffsetsigdev=self._pointingoffsetsigdev, pblimit=self._pblimit, deconvolver=self._deconvolver, 

2857 smallscalebias=self._smallscalebias, cyclefactor=self._cyclefactor, scales=self._scales, 

2858 restoringbeam=self._restoringbeam, pbcor=self._pbcor, nterms=self._nterms, field=self._field, 

2859 spw=self._spw, timerange=self._timerange, uvrange=self._uvrange, antenna=self._antenna, 

2860 scan=self._scan, observation=self._observation, intent=self._intent, datacolumn=self._datacolumn, 

2861 weighting=self._weighting, robust=self._robust, npixels=self._npixels, interactive=False, 

2862 niter=0, restart=True, calcpsf=False, calcres=False, restoration=False, threshold=self._threshold, 

2863 nsigma=self._nsigma, cycleniter=self._cycleniter, nmajor=1, gain=self._gain, 

2864 sidelobethreshold=self._sidelobethreshold, noisethreshold=self._noisethreshold, 

2865 lownoisethreshold=self._lownoisethreshold, negativethreshold=self._negativethreshold, 

2866 minbeamfrac=self._minbeamfrac, growiterations=self._growiterations, dogrowprune=self._dogrowprune, 

2867 minpercentchange=self._minpercentchange, fastnoise=self._fastnoise, savemodel=self._savemodel, 

2868 maxpsffraction=self._maxpsffraction, outlierfile=self._outlierfile, 

2869 minpsffraction=self._minpsffraction, parallel=self._parallel, fullsummary=True ) 

2870 

2871 

2872 deconv_ret = self._deconv_over_fields(niter=0, mask='', restoration=True) 

2873 

2874 self._has_restored = True 

2875 

2876 # Write history into relevant images for all fields 

2877 for fidx, field in enumerate(self._fieldnames): 

2878 #params = cleanhelper.get_func_params(self.__init__, self._all_input_params) 

2879 cleanhelper.write_tclean_history(self._paramlist.allimpars[f"{fidx}"]['imagename'], "InteractiveClean", tuple(self._all_input_params['doc'].items()), casalog) 

2880 

2881 return self.global_imdict.returndict 

2882 

2883 # return { "image": f"{self._imagename}.image" } 

2884 

2885 def has_next(self): 

2886 return not self._finalized