Coverage for / home / casatest / venv / lib / python3.12 / site-packages / casatasks / private / task_plotbandpass.py: 53%
5713 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-12 07:14 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-12 07:14 +0000
1#########################################################################
2#
3# task_plotbandpass.py
4#
5# Developed at the NAASC, this is a generic task to display CASA Tsys and
6# bandpass solution tables with options to overlay them in various
7# combinations, and/or with an atmospheric transmission or sky temperature
8# model. It works with both the 'new' (casa 3.4) and 'old' calibration
9# table formats, and allows for mixed mode spws (e.g. TDM and FDM for ALMA).
10# It uses the new msmd tool to access the information about an ms.
11#
12# Todd R. Hunter February 2013
13#
14# To test: see plotbandpass_regression.py
15#
17import inspect
18import math
19import os
20import re # used for testing if a string is a float
21import time
22import copy
24import matplotlib.transforms
25import numpy as np
26import pylab as pb
27from casatasks import casalog
28from casatasks.private import sdutil, simutil
29from casatools import (atmosphere, ctsys, measures, ms, msmetadata, quanta,
30 table)
31from matplotlib.ticker import (FormatStrFormatter, MultipleLocator,
32 ScalarFormatter)
33from six.moves import input, range
35# CAS-13722, CAS-13385
36import warnings
37import matplotlib.cbook
38#warnings.filterwarnings("ignore",category=matplotlib.cbook.MatplotlibDeprecationWarning)
40##------------------------------------------------------------------------------------------------------
41##--- Increment the micro version number with each update to task_plotbandpass.py, adjust the major ---
42##--- and minor version numbers to match the analysisUtils version that is last synced with... ---
43##------------------------------------------------------------------------------------------------------
44TASK_PLOTBANDPASS_REVISION_STRING = "2.20.0" #### incremented from 2.3.0 in 2024Aug
45##------------------------------------------------------------------------------------------------------
46##--- Update this version string whenever task_plotbandpass.py is synced with plotbandpass3.py from ---
47##--- Todd's analysisUtils. This will allow for tracking efforts to keep the versions synced. ---
48##------------------------------------------------------------------------------------------------------
49PLOTBANDPASS_REVISION_STRING = "Id: plotbandpass3.py,v 2.20 2024/09/04 16:00:03 thunter Exp"
51TOP_MARGIN = 0.25 # Used if showatm=T or showtksy=T
52BOTTOM_MARGIN = 0.25 # Used if showfdm=T
53MAX_ATM_CALC_CHANNELS = 512
55markeredgewidth = 0.0
56maxAltitude = 60 # for ozone, in km, this is the default value of the parameter in the analysisUtils version
58# This is a color sequence found online which has distinguishable colors
59overlayColorsSequence = [
60 [0.00, 0.00, 0.00],
61 [0.00, 0.00, 1.00],
62 [0.00, 0.50, 0.00],
63 [1.00, 0.00, 0.00],
64 [0.00, 0.75, 0.75],
65# [0.75, 0.00, 0.75], # magenta, same as atmcolor
66 [0.25, 0.25, 0.25],
67 [0.75, 0.25, 0.25],
68 [0.95, 0.95, 0.00],
69 [0.25, 0.25, 0.75],
70# [0.75, 0.75, 0.75], this color is invisible for some reason
71 [0.00, 1.00, 0.00],
72 [0.76, 0.57, 0.17],
73 [0.54, 0.63, 0.22],
74 [0.34, 0.57, 0.92],
75 [1.00, 0.10, 0.60],
76# [0.88, 0.75, 0.73], invisible
77 [0.10, 0.49, 0.47],
78 [0.66, 0.34, 0.65],
79 [0.99, 0.41, 0.23]]
80overlayColorsList = overlayColorsSequence.copy()
81overlayColorsList += overlayColorsList + overlayColorsList # 17*3 = 34 total color entries
82overlayColorsList += overlayColorsList + overlayColorsList # try to support antenna,time 34*3 =102
83overlayColorsList += overlayColorsList + overlayColorsList # try to support antenna,time 102*3=306
84overlayColorsList += overlayColorsList + overlayColorsList # try to support antenna,time 306*3=918
85overlayColorsList += overlayColorsList + overlayColorsList # try to support antenna,time 918*3=2754 entries
87# Enumeration to keep track of plot pages
88PAGE_ANT = 0
89PAGE_SPW = 1
90PAGE_TIME = 2
91PAGE_AP = 3
93# Used to parse command line arguments
94myValidCharacterList = ['~', ',', ' ', '*',] + [str(m) for m in range(10)]
95myValidCharacterListWithBang = ['~', ',', ' ', '*', '!',] + [str(m) for m in range(10)]
96LARGE_POSITIVE = +1e20
97LARGE_NEGATIVE = -1e20
98maxAntennaNamesAcrossTheTop = 17
99maxTimesAcrossTheTop = 13 # 17 for HH:MM, reduced by 1 below for subplot=11
100antennaVerticalSpacing = 0.018 # 0.016
101antennaHorizontalSpacing = 0.05
102xstartTitle = 0.07
103ystartTitle = 0.955
104xstartPolLabel = 0.05
105ystartOverlayLegend = 0.931
106opaqueSky = 270. # Kelvin, used for scaling TebbSky
108developerEmail = "thunter@nrao.edu"
110#class Polarization:
111 # taken from Stokes.h in casa, for reference only
112# (Undefined, I,Q,U,V,RR,RL,LR,LL,XX,XY,YX,YY) = range(13)
114def version(showfile=True):
115 """
116 Returns the CVS revision number.
117 """
118 if (showfile):
119 print("Loaded from %s" % (__file__))
120 return TASK_PLOTBANDPASS_REVISION_STRING
122def refTypeToString(rtype):
123 rtypes = ['REST','LSRK','LSRD','BARY','GEO','TOPO','GALACTO','LGROUP','CMB']
124 return(rtypes[rtype])
126def corrTypeToString(ptype):
127 ptypes = ['Undefined','I','Q','U','V','RR','RL','LR','LL','XX','XY','YX','YY']
128 mystring = ptypes[ptype]
129# print("mystring = %s" % (mystring))
130 return(mystring)
132def buildAntString(antID,msFound,msAnt):
133 if (msFound):
134 antstring = msAnt[antID]
135 else:
136 antstring = '%02d' % (antID)
137 if (antstring.isdigit()):
138 Antstring = "Ant %s" % antstring
139 else:
140 Antstring = antstring
141 return(antstring, Antstring)
143def makeplot(figfile,msFound,msAnt,overlayAntennas,pages,pagectr,density,
144 interactive,antennasToPlot,spwsToPlot,overlayTimes,overlayBasebands,
145 locationCalledFrom, xant, ispw, subplot, resample='1',
146 debug=False,
147 figfileSequential=False, figfileNumber=0):
148 if (type(figfile) == str):
149 if (figfile.find('/')>=0):
150 directories = figfile.split('/')
151 directory = ''
152 for d in range(len(directories)-1):
153 directory += directories[d] + '/'
154 if (os.path.exists(directory)==False):
155 casalogPost(debug,"Making directory = %s" % (directory))
156 os.system("mkdir -p %s" % directory)
157 if (debug):
158 print(("makeplot(%d): pagectr=%d, len(pages)=%d, len(spwsToPlot)=%d, pages=" % (locationCalledFrom,
159 pagectr, len(pages),len(spwsToPlot)), pages))
160 if len(pages) == 0:
161 t = 0
162 elif (pages[pagectr][PAGE_SPW] >= len(spwsToPlot)):
163 # necessary for test86: overlay='spw' of spectral scan dataset. to avoid indexing beyond the
164 # end of the array in the the case that the final frame is of a baseband with n spw, and
165 # earlier frames had >n spws 2014-04-08
166 ispw = spwsToPlot[-1]
167 else:
168 # CAS-8285: Added 'if' to be sure to use ispw passed in for single-panel plots, but
169 # use the original behavior for multi-panel plots simply to preserve the pngfile
170 # naming scheme (i.e. including the spw name of lower right panel) to match old
171 # regressions. Should probably remove this whole 'else' block someday, if I don't
172 # mind if future multi-panel filenames contain spw name of upper left panel.
173 if (subplot != 11 or overlayBasebands): # Add only this line for CAS-8285.
174 ispw = spwsToPlot[pages[pagectr][PAGE_SPW]]
175 if debug:
176 print("setting ispw to spwsToPlot[pages[pagectr=%d]=%d[PAGE_SPW]] = %d" % (pagectr,pages[pagectr][PAGE_SPW],ispw))
177 if len(pages) > 0:
178 t = pages[pagectr][PAGE_TIME] # + 1
179 if (subplot == 11):
180 antstring, Antstring = buildAntString(xant, msFound, msAnt) # CAS-8285
181 else:
182 antstring, Antstring = buildAntString(antennasToPlot[pages[pagectr][PAGE_ANT]], msFound, msAnt)
183 figfile = figfile.split('.png')[0]
184 if (figfileSequential):
185 plotfilename = figfile + '.%03d' % (figfileNumber)
186 else:
187 if (msFound):
188 if (overlayAntennas and overlayTimes):
189 plotfilename = figfile+'.spw%02d'%(ispw)
190 elif (overlayAntennas):
191 plotfilename = figfile+'.spw%02d'%(ispw)+'.t%02d'%(t)
192 elif (overlayTimes):
193 plotfilename = figfile+'.'+antstring+'.spw%02d'%(ispw)
194 else:
195 plotfilename = figfile+'.'+antstring+'.spw%02d'%(ispw)+'.t%02d'%(t)
196 else:
197 if (overlayAntennas and overlayTimes):
198 plotfilename = figfile+'.spw%02d'%(ispw)
199 elif (overlayAntennas):
200 plotfilename = figfile+'.spw%02d'%(ispw)+'.t%02d'%(t)
201 elif (overlayTimes):
202 plotfilename = figfile+'.ant'+antstring+'.spw%02d'%(ispw)
203 else:
204 plotfilename = figfile+'.ant'+antstring+'.spw%02d'%(ispw)+'.t%02d'%(t)
205 if (int(resample) > 1):
206 plotfilename += '.resample%d.png' % (int(resample))
207 else:
208 plotfilename += '.png'
209 if (interactive == False or True):
210 casalogPost(debug,"Building %s" % (plotfilename))
211# print("Building %s" % (plotfilename))
212 pb.savefig(plotfilename, format='png', dpi=density)
213 return(plotfilename)
215def utdatestring(mjdsec):
216 (mjd, dateTimeString) = mjdSecondsToMJDandUT(mjdsec)
217 tokens = dateTimeString.split()
218 return(tokens[0])
220def mjdsecArrayToUTString(timerangeListTimes):
221 """
222 accepts [4866334935, 4866335281] etc.
223 returns '08:04:10, 09:03:00' etc.
224 """
225 timerangeListTimesString = ''
226 for t in timerangeListTimes:
227 timerangeListTimesString += utstring(t,3) + ' '
228 return(timerangeListTimesString)
230def utstring(mjdsec, xframeStart=110):
231 (mjd, dateTimeString) = mjdSecondsToMJDandUT(mjdsec)
232 tokens = dateTimeString.split()
233 hoursMinutes = tokens[1][0:len(tokens[1])-3]
234 hoursMinutesSeconds = tokens[1][0:len(tokens[1])]
235 if (xframeStart == 110): # 2011-01-01 UT 00:00
236 return(tokens[0]+' '+tokens[2]+' '+hoursMinutes)
237 elif (xframeStart == 3):
238 return(hoursMinutesSeconds)
239 else: # 00:00
240 return(hoursMinutes)
242def openBpolyFile(caltable, debug):
243 mytb = table()
244 mytb.open(caltable)
245 desc = mytb.getdesc()
246 if ('POLY_MODE' in desc):
247 polyMode = mytb.getcol('POLY_MODE')
248 casalogPost(debug,"This is a BPOLY solution = %s" % (polyMode[0]))
249 polyType = mytb.getcol('POLY_TYPE')
250 scaleFactor = mytb.getcol('SCALE_FACTOR')
251 antenna1 = mytb.getcol('ANTENNA1')
252 times = mytb.getcol('TIME')
253 cal_desc_id = mytb.getcol('CAL_DESC_ID')
254 nRows = len(polyType)
255 for pType in polyType:
256 if (pType != 'CHEBYSHEV'):
257 casalogPost(debug,"I do not recognized polynomial type = %s" % (pType))
258 return
259 # Here we assume that all spws have been solved with the same mode
260 uniqueTimesBP = np.unique(mytb.getcol('TIME'))
261 nUniqueTimesBP = len(uniqueTimesBP)
262 mystring = "There are %d unique times in the BPOLY solution: " % (nUniqueTimesBP)
263 for u in uniqueTimesBP:
264 mystring += '%.3f, ' % (u)
265 casalogPost(debug,mystring)
266 if (nUniqueTimesBP == 2):
267 casalogPost(debug,"differing by %g seconds" % (uniqueTimesBP[1]-uniqueTimesBP[0]))
268 nPolyAmp = mytb.getcol('N_POLY_AMP')
269 nPolyPhase = mytb.getcol('N_POLY_PHASE')
270 frequencyLimits = mytb.getcol('VALID_DOMAIN')
271 increments = 0.001*(frequencyLimits[1,:]-frequencyLimits[0,:])
272 frequenciesGHz = []
273 for i in range(len(increments)):
274 freqs = (1e-9)*np.arange(frequencyLimits[0,i],frequencyLimits[1,i],increments[i])
275 frequenciesGHz.append(freqs)
276 polynomialAmplitude = []
277 polynomialPhase = []
278 for i in range(len(polyMode)):
279 polynomialAmplitude.append([1])
280 polynomialPhase.append([0])
281 if (polyMode[i] == 'A&P' or polyMode[i] == 'A'):
282 polynomialAmplitude[i] = mytb.getcell('POLY_COEFF_AMP',i)[0][0][0]
283 if (polyMode[i] == 'A&P' or polyMode[i] == 'P'):
284 polynomialPhase[i] = mytb.getcell('POLY_COEFF_PHASE',i)[0][0][0]
286 mytb.close()
287 mytb.open(caltable+'/CAL_DESC')
288 nSpws = len(mytb.getcol('NUM_SPW'))
289 spws = mytb.getcol('SPECTRAL_WINDOW_ID')
290 spwBP = []
291 for c in cal_desc_id:
292 spwBP.append(spws[0][c])
293 mytb.done()
294 return([polyMode, polyType, nPolyAmp, nPolyPhase, scaleFactor, nRows, nSpws, nUniqueTimesBP,
295 uniqueTimesBP, frequencyLimits, increments, frequenciesGHz,
296 polynomialPhase, polynomialAmplitude, times, antenna1, cal_desc_id, spwBP])
297 else:
298 mytb.done()
299 return([])
300 # end of openBpolyFile()
302def displayTimesArray(uniqueTimesPerFieldPerSpw):
303 """
304 Builds a string from an array of MJD second timestamps as UT timestamps
305 """
306 legendString = ''
307 for s in uniqueTimesPerFieldPerSpw:
308 legendString += "["
309 for f in s:
310 legendString += "["
311 for t in f:
312 legendString += "%s" % utstring(t,2)
313 if (t != f[-1]):
314 legendString += ", "
315 legendString += "]"
316 if (f != s[-1]):
317 legendString += ', '
318 legendString += "], "
319 if (s != uniqueTimesPerFieldPerSpw[-1]):
320 legendString += ', '
321 return(legendString)
323def checkPolsToPlot(polsToPlot, corr_type_string, debug):
324 firstFailure = 0
325 for pol in polsToPlot:
326 if ((pol in corr_type_string) == False):
327 casalogPost(debug,"Polarization product %s is not in the ms" % (pol))
328 firstFailure += 1
329 if (pol in ['XX','YY']):
330 polsToPlot = ['RR','LL']
331 else:
332 polsToPlot = ['XX','YY']
333 break
334 if (firstFailure>0):
335 casalogPost(debug,"Looking for instead: %s" % (str(polsToPlot)))
336 for pol in polsToPlot:
337 if ((pol in corr_type_string) == False):
338 casalogPost(debug,"Polarization product %s is not in the ms" % (pol))
339 firstFailure += 1
340 if (pol in ['XX']):
341 polsToPlot = ['YY']
342 elif (pol in ['YY']):
343 polsToPlot = ['XX']
344 elif (pol in ['RR']):
345 polsToPlot = ['LL']
346 elif (pol in ['LL']):
347 polsToPlot = ['RR']
348 break
349 if (firstFailure > 1):
350 casalogPost(debug,"Looking for instead: %s" % (str(polsToPlot)))
351 for pol in polsToPlot:
352 if ((pol in corr_type_string) == False):
353 casalogPost(debug,"Polarization product %s is not in the ms" % (pol))
354 return([])
355 return(polsToPlot)
357def getCorrType(msName, spwsToPlot, mymsmd, debug=False):
358 """
359 Open the DATA_DESCRIPTION_ID table. Find the polarization_id of the first
360 spw in the list of spwsToPlot, then read the CORR_TYPE from the POLARIZATION
361 table.
362 """
363 mytb = table()
364 mytb.open(msName+'/DATA_DESCRIPTION')
365 spws = mytb.getcol('SPECTRAL_WINDOW_ID')
366 polarization_id = mytb.getcol('POLARIZATION_ID')
367 mytb.close()
368 pol_id = 0
369 telescopeName = mymsmd.observatorynames()[0]
370 mytb.open(msName+'/POLARIZATION')
371 for myspw in spwsToPlot:
372# print("looking for %d in %s" % (myspw, str(spws)))
373 row = list(spws).index(myspw)
374 if (row >= 0):
375 pol_id = polarization_id[row]
376 corr_type = mytb.getcell('CORR_TYPE',pol_id)
377 if (corr_type[0] >= 5 or (telescopeName.find('ALMA')<0 and telescopeName.find('VLA')<0)):
378 # Undefined, I, Q, U, V, which ALMA and VLA never use
379 # Need to allow non-VLA, non-ALMA to stop here
380 break
381 mytb.close()
382 corr_type_string = []
383 if (len(corr_type) == 4):
384 casalogPost(debug,"This is a 4-polarization dataset.")
385 if (corr_type[0] in [5,6,7,8]):
386 corr_type = [5,8]
387 elif (corr_type[0] in [9,10,11,12]):
388 corr_type = [9,12]
389 else:
390 print(("Unsupported polarization types = ", corr_type))
391 return(corr_type, corr_type_string)
392 # This overrides the len(gain_table) because it can have length=2 even when only 1 pol present
393 nPolarizations = len(corr_type)
394 for ct in corr_type:
395 corr_type_string.append(corrTypeToString(ct))
396 if (debug):
397 print(("corr_types = ", corr_type, " = ", corr_type_string))
398 return(corr_type, corr_type_string, nPolarizations)
400def writeArgument(f,name,arg):
401 if (type(arg) == str):
402 s = "%-18s = '%s'" % (name,arg)
403 t = "%s='%s'" % (name,arg)
404 else:
405 s = "%-18s = %s" % (name,str(arg))
406 t = "%s=%s" % (name,arg)
407 f.write(s+'\n')
408 return(t)
410def channelDifferences(y, x, resample=1):
411 """
412 Takes a vector, and computes the channel-to-channel derivative.
413 Optionally, it will also resample the data and compute the
414 derivative.
415 - Todd Hunter
416 """
417 x = np.array(x)
418 y = np.array(y)
419 if (len(x) > 1):
420 channelWidth = x[1]-x[0]
421 d = (np.diff(y)/np.diff(x))
422 newy = d*channelWidth
423 newx = (x[1:]+x[:-1])/2. # midpoints of input x-axis
424 else:
425 newx = x
426 newy = y
427 if (resample > 1):
428 x,y = resampleSolution(x,y,resample)
429 if (len(x) > 1):
430 channelWidth = x[1]-x[0]
431 d = (np.diff(y)/np.diff(x))
432 resy = d*channelWidth
433 resx = (x[1:]+x[:-1])/2. # midpoints of input x-axis
434 else:
435 resx = x
436 resy = y
437 else:
438 resy = newy
439 resx = newx
440 return(newy, newx, resy, resx)
442def getDataColumnName(inputMs, debug):
443 mytb = table()
444 mytb.open(inputMs)
445 colnames = mytb.colnames()
446 correctedDataColumnName = ''
447 modelDataColumnName = ''
448 if 'FLOAT_DATA' in colnames:
449 dataColumnName = 'FLOAT_DATA'
450 correctedDataColumnName = 'FLOAT_DATA'
451 elif 'DATA' in colnames:
452 dataColumnName = 'DATA'
453 if 'CORRECTED_DATA' in colnames:
454 correctedDataColumnName = 'CORRECTED_DATA'
455 if 'MODEL_DATA' in colnames:
456 modelDataColumnName = 'MODEL_DATA'
457 mytb.done()
458 return(dataColumnName)
460def doPolarizations(mymsmd, inputMs, debug=False) :
461 # This function is obsolete. There may be no OBSERVE_TARGET intents in a dataset!
462 # Determine the number of polarizations for the first OBSERVE_TARGET intent.
463 # Used by plotbandpass for BPOLY plots since the number of pols cannot be inferred
464 # correctly from the caltable alone. You cannot not simply use the first row, because
465 # it may be a pointing scan which may have different number of polarizations than what
466 # the TARGET and BANDPASS calibrator will have.
467 # -- T. Hunter
468 if (debug): print("doPolarizations()")
469 myscan = -1
470 starttime = time.time()
471 for s in range(1,mymsmd.nscans()+1):
472 if (debug): print("s = %s" % (str(s)))
473 intents = mymsmd.intentsforscan(s)
474 for i in intents:
475 if (i.find('OBSERVE_TARGET')>=0):
476 myscan = s
477# print("First OBSERVE_TARGET scan = %s" % (str(myscan)))
478 break
479 if (myscan >= 0):
480 break
481 if (myscan == -1):
482 # if there is no OBSERVE_TARGET, then just use the first scan
483 myscan = 0
484 dataColumnName = getDataColumnName(inputMs,debug)
485 if (debug): print("dataColumnName = %s" % (dataColumnName))
486 mytb = table()
487 mytb.open("%s" % inputMs)
488 if (myscan == 0):
489 # assume the first row in the table is for the first scan, to save time
490 nPolarizations = np.shape(mytb.getcell(dataColumnName,0))[0]
491 else:
492 scans = mytb.getcol('SCAN_NUMBER')
493 nPolarizations = 0
494 for s in range(len(scans)):
495 if (scans[s]==myscan):
496 nPolarizations = np.shape(mytb.getcell(dataColumnName,s))[0]
497 break
498 mytb.close()
499 donetime = time.time()
500 return(nPolarizations)
502def getnspw(mymsmd):
503# if (casadef.subversion_revision > '22653'):
504 return(mymsmd.nspw(False))
505# else:
506# return(mymsmd.nspw())
508def drawOverlayTimeLegends(xframe, firstFrame, xstartTitle, ystartTitle, caltable, titlesize,
509 fieldIndicesToPlot, ispwInCalTable, uniqueTimesPerFieldPerSpw,
510 timerangeListTimes, solutionTimeThresholdSeconds, debugSloppyMatch,
511 ystartOverlayLegend, debug, mysize, fieldsToPlot, myUniqueColor,
512 timeHorizontalSpacing, fieldIndex, overlayColors,
513 antennaVerticalSpacing, overlayAntennas,
514 timerangeList, caltableTitle, mytime, scansToPlot,
515 scansForUniqueTimes, uniqueSpwsInCalTable, uniqueTimes):
516 """
517 Draws the legend at the top of the page, if it is the correct time to do so,
518 including the overlayTimes, the 'UT' label, and the caltable name.
519 xframe: an integer as a subplot specifier, like 223 for the third panel of a 2x2 plot
520 firstFrame: an integer as a subplot specifier, like 221 for the first panel of a 2x2 plot
521 caltable: name of caltable on disk
522 titlesize: font size as an integer string, e.g. '7'
523 fieldIndicesToPlot: a list of integer indexes to the parent list fieldsToPlot, e.g. [0]
524 fieldsToPlot: list of measurement set field IDs to plot, this can be different (shorter) than parent list fieldsToPlot
525 scansToPlot: a list of measurement set scan numbers from which solutions should be plotted
526 scansForUniqueTimes: a list of scans corresponding to the parent list of uniqueTimes
527 ispwInCalTable: an integer index for the single desired spw in the spw list uniqueSpwsInCalTable, e.g. 0
528 uniqueTimesPerFieldPerSpw: a list of list of lists corresponding to [spwIndex][fieldIndex][floating-point times...]
529 uniqueTimes: a list of all unique floating-point times in the caltable
530 timerangeListTimes: a list of unique values of floating point MJD seconds that were requested to be plotted
531 timerangeList: a list of timerange indices that were requested to be plotted
532 uniqueSpwsInCalTable: a list of spw IDs, but only used for print statements
533 mytime: the index of the timerange in the list of uniqueTimes in the caltable that was
534 being examined when this function was called in the parent 'while loop' over uniqueTimes
535 """
536 # debugSloppyMatch=True
537 myspw = uniqueSpwsInCalTable[ispwInCalTable]
538 if debug:
539 print("len(timerangeList)=%d, len(timerangeListTimes)=%d" % (len(timerangeList), len(timerangeListTimes)))
540 print("timerangeListTimes: %s" % (['%.3f'%(i) for i in timerangeListTimes]))
541 print("xframe=%d, firstFrame=%d, ispwInCalTable=%d, spw=%d, fieldIndicesToPlot=%s, fieldsToPlot=%s" % (xframe,firstFrame,ispwInCalTable,myspw,fieldIndicesToPlot,fieldsToPlot))
542 print("uniqueTimesPerFieldPerSpw[%d][%d] = %s" % (ispwInCalTable,fieldIndicesToPlot[0],uniqueTimesPerFieldPerSpw[ispwInCalTable][fieldIndicesToPlot[0]]))
543 if (xframe == firstFrame):
544 # draw title including caltable name
545 pb.text(xstartTitle, ystartTitle, caltableTitle, size=titlesize, color='k', transform=pb.gcf().transFigure)
546 # support multi-fields with overlay='time'
547 uTPFPS = []
548 uTPFPStimerange = []
550 # Find all timerange indices for all fields, not just the ones that were plotted
551 allTimeranges = []
552 for f in range(len(uniqueTimesPerFieldPerSpw[ispwInCalTable])):
553 for t in uniqueTimesPerFieldPerSpw[ispwInCalTable][f]:
554 if (np.min(np.abs(timerangeListTimes-t)) < solutionTimeThresholdSeconds): ### added 2024Aug
555 closestIndex = np.argmin(np.abs(timerangeListTimes-t)) ### added 2024Aug
556 allTimeranges.append(closestIndex) ### added 2024Aug
558 allTimeranges = list(np.sort(np.unique(allTimeranges)))
559 # allTimeranges is a list of integers.
560 # The length of allTimeranges will generally be shorter than timerangeListTimes.
562 for f in fieldIndicesToPlot:
563 found = 0
564 for timestamp in uniqueTimesPerFieldPerSpw[ispwInCalTable][f]:
565 if timestamp in uniqueTimes: # 2024Aug28
566 myUniqueTimeIndex = uniqueTimes.index(timestamp) # 2024Aug28
567 matched, mymatch = sloppyMatch(timestamp, timerangeListTimes, solutionTimeThresholdSeconds, myUniqueTimeIndex, scansToPlot, # 2024Aug28
568 scansForUniqueTimes, myprint=debugSloppyMatch, whichone=True)
569 # when there are multiple solutions per scan (as in SDSKY_PS tables), the value of mymatch will always be the first one, so cannot use it
570 mymatch = myUniqueTimeIndex # 2024Aug28
571 else:
572 # Not including the mytime, scansToPlot and scansForUniqueTimes in the following call will lead to the legend
573 # showing all timestamps, not merely the subset that was selected by the (optional) scans parameter. That is
574 # why we need to compare each myUniqueTimeIndex. You cannot simply use mytime as it will always be the final
575 # time in the parent loop when you are in the overlay='time' scenario. But we fail over to this method.
576 if debug:
577 print("%.3f not in uniqueTimes, failing over to simpler method" % (timestamp))
578 matched, mymatch = sloppyMatch(timestamp, timerangeListTimes, solutionTimeThresholdSeconds, myprint=debugSloppyMatch, whichone=True) # 2024Aug27 regression
579 if (matched and mymatch in timerangeList):
580 uTPFPS.append(timestamp)
581 uTPFPStimerange.append(mymatch)
582 expected = len(uniqueTimesPerFieldPerSpw[ispwInCalTable][f])
583 if found < expected:
584 statement = "plotbandpass drawOverlayTimeLegends() found %d/%d time matches for spw%d field%d" % (found,expected,myspw,f)
585 casalogPost(debug,statement)
586 # sort the timeranges so the text labels will be increasing
587 idx = np.argsort(uTPFPS)
588 uTPFPStimerange = np.array(uTPFPStimerange)[idx]
589 uTPFPS = np.sort(uTPFPS)
590 timeFormat = 3 # HH:MM:SS
591 maxTimesAcross = maxTimesAcrossTheTop
592 if (firstFrame == 111):
593 maxTimesAcross -= 2
595 for a in range(len(uTPFPS)):
596 legendString = utstring(uTPFPS[a],timeFormat)
597 if (debug): print("----> Defined legendString: %s" % (legendString))
598 if (a==0):
599 pb.text(xstartTitle-0.03, ystartOverlayLegend, 'UT',color='k',fontsize=mysize,
600 transform=pb.gcf().transFigure)
601 if (a < maxTimesAcross):
602 x0 = xstartTitle + (a*timeHorizontalSpacing)
603 y0 = ystartOverlayLegend
604 else:
605 # start going down the righthand side
606 x0 = xstartTitle + (maxTimesAcross*timeHorizontalSpacing)
607 y0 = ystartOverlayLegend-(a-maxTimesAcross)*antennaVerticalSpacing
608 if (True):
609 if (debug):
610 print("3)checking time %d, len(uTPFPS)=%d" % (a,len(uTPFPS)))
611 if (sloppyMatch(uTPFPS[a],timerangeListTimes,
612 solutionTimeThresholdSeconds,
613 mytime, scansToPlot, scansForUniqueTimes,
614 myprint=debugSloppyMatch)):
615 myUniqueTime = uTPFPS[a]
616 if (debug):
617 print("3)setting myUniqueTime to %d" % (myUniqueTime))
619 if (debug): print("----> Drawing legendString: %s" % (legendString))
620 if ((len(fieldsToPlot) > 1 or len(timerangeList) > 1) and overlayAntennas==False):
621 # having overlayAntennas==False here will force all time labels to be black (as desired)
622 if (debug):
623 print("len(uTPFPS)=%d, a=%d, len(myUniqueColor)=%d, overlayColors[%d]=%s" % (len(uTPFPS),a,len(myUniqueColor),timerangeList[allTimeranges.index(uTPFPStimerange[a])],str(overlayColors[timerangeList[allTimeranges.index(uTPFPStimerange[a])]])))
624 print("len(uTPFPS)=%d, a=%d, len(myUniqueColor)=%d" % (len(uTPFPS),a,len(myUniqueColor)))
626 mycolor = overlayColors[uTPFPStimerange[a]] # color based on the subset of timeranges to be plotted
627 pb.text(x0, y0, legendString, color=mycolor, fontsize=mysize, transform=pb.gcf().transFigure)
628 else: # only 1 spectrum, or overlayAntennas==True means use all black labels
629 pb.text(x0, y0, legendString, fontsize=mysize, transform=pb.gcf().transFigure)
631def lineNumber():
632 """Returns the current line number in our program."""
633 return inspect.currentframe().f_back.f_lineno
635def drawAtmosphereAndFDM(showatm, showtsky, atmString, subplotRows, mysize, TebbSky,
636 TebbSkyImage,plotrange, xaxis, atmchan, atmfreq, transmission,
637 subplotCols, showatmPoints,xframe, channels,LO1,atmchanImage,
638 atmfreqImage,transmissionImage, firstFrame,showfdm,nChannels,tableFormat,
639 originalSpw_casa33, chanFreqGHz_casa33,originalSpw,chanFreqGHz,
640 overlayTimes, overlayAntennas, xant, antennasToPlot, overlaySpws,
641 baseband, showBasebandNumber, basebandDict, overlayBasebands, overlayColors,
642 drewAtmosphere, showtsys=False, Trx=None):
643 """
644 If requested by the user at the command line, draw the atmospheric curve
645 and the FDM window locations.
646 """
647 mylineno = lineNumber()
648 ylim = pb.ylim() # CAS-8655
649 if ((showatm or showtsky) and len(atmString) > 0):
650 ylim = DrawAtmosphere(showatm, showtsky, subplotRows, atmString,
651 mysize, TebbSky, plotrange, xaxis, atmchan,
652 atmfreq, transmission, subplotCols,
653 showatmPoints=showatmPoints, xframe=xframe,
654 channels=channels,
655 mylineno=mylineno,xant=xant,
656 overlaySpws=overlaySpws, overlayBasebands=overlayBasebands,
657 drewAtmosphere=drewAtmosphere,
658 loc=201, showtsys=showtsys, Trx=Trx)
659 if (LO1):
660 # Now draw the image band
661 ylim = DrawAtmosphere(showatm,showtsky, subplotRows, atmString,
662 mysize, TebbSkyImage, plotrange, xaxis,
663 atmchanImage, atmfreqImage, transmissionImage,
664 subplotCols, LO1, xframe, firstFrame, showatmPoints,
665 channels=channels, mylineno=mylineno,xant=xant,
666 overlaySpws=overlaySpws, overlayBasebands=overlayBasebands,
667 drewAtmosphere=drewAtmosphere,
668 loc=202, showtsys=showtsys, Trx=Trx)
669 # The following case is needed for the case that overlay='antenna,time' and
670 # the final timerange is flagged on the final antenna.
671# if (overlayTimes==False or overlayAntennas==False or xant==antennasToPlot[-1]):
672 # Because this function is now only called from one place, setting this to
673 # True is what we want. - 18-Jun-2013
674 if (True):
675 if (xaxis.find('freq')>=0 and showfdm and nChannels <= 256):
676 if (tableFormat == 33):
677 showFDM(originalSpw_casa33, chanFreqGHz_casa33,
678 baseband, showBasebandNumber, basebandDict, overlayColors)
679 else:
680 showFDM(originalSpw, chanFreqGHz,
681 baseband, showBasebandNumber, basebandDict, overlayColors)
682 ylim = pb.ylim() # CAS-11062 need to pass the new wider limits back up to calling function
683 return ylim # CAS-8655
685def DrawPolarizationLabelsForOverlayTime(xstartPolLabel,ystartPolLabel,corr_type,polsToPlot,
686 channeldiff,ystartMadLabel,subplotRows,gamp_mad,mysize,
687 ampmarkstyle,markersize,ampmarkstyle2, gamp_std):
688 """
689 Currently this is only called for amp vs. X plots. The corresponding code for phase
690 vs. X plots is still inside plotbandpass(). But this is okay because overlay='time'
691 is mainly intended for Tsys plots.
692 """
693 x0 = xstartPolLabel
694 y0 = ystartPolLabel
695 if (corrTypeToString(corr_type[0]) in polsToPlot):
696 if (channeldiff > 0):
697 pb.text(x0, ystartMadLabel-0.03*subplotRows*0,
698 corrTypeToString(corr_type[0])+' MAD = %.4f, St.Dev = %.4f'%(gamp_mad[0]['mad'], gamp_std[0]['std']),
699 color='k',size=mysize, transform=pb.gca().transAxes)
700 if (ampmarkstyle.find('-')>=0):
701 pb.text(x0, y0, corrTypeToString(corr_type[0])+' solid', color='k',
702 size=mysize, transform=pb.gca().transAxes)
703 else:
704 pb.text(x0+0.02, y0, corrTypeToString(corr_type[0]), color='k',
705 size=mysize, transform=pb.gca().transAxes)
706 pdesc = pb.plot([x0-0.1], [y0], '%sk'%ampmarkstyle, markersize=markersize,
707 scalex=False,scaley=False, transform=pb.gca().transAxes,markeredgewidth=markeredgewidth)
708 if (len(corr_type) > 1):
709 if (corrTypeToString(corr_type[1]) in polsToPlot):
710 if (channeldiff > 0):
711 pb.text(x0, ystartMadLabel-0.03*subplotRows*1,
712 corrTypeToString(corr_type[1])+' MAD = %.4f, St.Dev = %.4f'%(gamp_mad[1]['mad'], gamp_std[1]['std']),
713 color='k',size=mysize, transform=pb.gca().transAxes)
714 if (ampmarkstyle2.find('--')>=0):
715 pb.text(x0, y0-0.03*subplotRows, corrTypeToString(corr_type[1])+' dashed',
716 color='k', size=mysize, transform=pb.gca().transAxes)
717 else:
718 pb.text(x0, y0-0.03*subplotRows, corrTypeToString(corr_type[1]), # removed +0.02*xrange on 11-Mar-2014
719 color='k', size=mysize, transform=pb.gca().transAxes)
720 pdesc = pb.plot([x0-0.1], [y0-0.03*subplotRows], '%sk'%ampmarkstyle2,
721 markersize=markersize, scalex=False,scaley=False, transform=pb.gca().transAxes,markeredgewidth=markeredgewidth)
723def plural(u):
724 """
725 If the length of the array passed is > 1, return 's', otherwise return ''.
726 """
727 if (len(u) > 1):
728 return('s')
729 else:
730 return('')
732def casalogPost(debug, mystring):
733 casalog.post(mystring)
734 if (debug): print(mystring)
736def computeHighestSpwIndexInSpwsToPlotThatHasCurrentScan(spwsToPlot, scansToPlotPerSpw, scan):
737 highestSpwIndex = -1
738 for i,spw in enumerate(spwsToPlot):
739 if (scan in scansToPlotPerSpw[spw]):
740 highestSpwIndex = i
741 return(highestSpwIndex)
743def madOfDiff(solution):
744 """
745 This function is used to decide which of two curves has more scatter, and hence should
746 be plotted first (i.e. shown in the background) when overlaying two solutions.
747 Added as part of CAS-9474 to do a better job of the selection
748 """
749 if (len(solution) < 4):
750 return MAD(np.diff(solution))
751 else:
752 start = int(len(solution)/4)
753 stop = int(len(solution)*3/4)
754 ydata = np.array(solution[start:stop+1])
755 return MAD(np.diff(ydata))
757def run_with_old_pyplot_style(func):
758 """
759 CAS-12786: this decorator is introduced here to have a single entry point before/after
760 which the style sheet of matplotlib/pylab can be tuned and restored before returning.
762 The motivation is that plotbandpass plots are heavily dependent on default image size,
763 grid style, ticks frequency, etc., as it used to be in matplotlib 1.1.0 (used in
764 CASA 5.x). In more recent matplotlib (3.1.1 is currently used in CASA 6.x) that style
765 can be reproduced using the style sheet 'classic'. This is the quickest and simplest way
766 to produce plotbandpass plots that look like those of CASA 5
767 # https://matplotlib.org/3.1.1/users/dflt_style_changes.html
768 """
769 def func_old_style(*args, **kwargs):
770 with pb.style.context('classic'):
771 pb.rc('axes.formatter', useoffset=False)
772 pb.rc('axes', grid=True)
773 pb.rc('axes.grid', axis='both', which='major')
774 return func(*args, **kwargs)
776 return func_old_style
778DEFAULT_PLATFORMING_THRESHOLD = 10.0 # unused if platformingSigma != 0
779@run_with_old_pyplot_style
780def plotbandpass(caltable='', antenna='', field='', spw='', yaxis='amp',
781 xaxis='chan', figfile='', plotrange=[0,0,0,0],
782 caltable2='', overlay='', showflagged=False, timeranges='',
783 buildpdf=False, caltable3='', markersize=3, density=108,
784 interactive=True, showpoints='auto', showlines='auto',
785 subplot='22', zoom='', poln='', showatm=False, pwv='auto',
786 gs='gs', convert='convert', chanrange='',
787 solutionTimeThresholdSeconds=30.0, debug=False,
788 phase='', vis='',showtsky=False, showfdm=False,showatmfield='',
789 lo1='', showimage=False, showatmPoints=False, parentms='',
790 pdftk='pdftk', channeldiff=False, edge=8, resample=1,
791 platformingThreshold=DEFAULT_PLATFORMING_THRESHOLD,
792 platformingSigma=5.0, basebands=[], showBasebandNumber=False,
793 scans='', figfileSequential=False, chanrangeSetXrange=False,
794 Trx='auto', showtsys=False):
795 """
796 This is a task to plot bandpass and Tsys calibration tables faster and more
797 flexibly than plotcal, including the ability to overlay the atmospheric
798 transmission, and to create multi-page plots as pngs and combine them
799 into single PDF documents.
800 It works with both the old style and new style cal tables. The source code
801 is in task_plotbandpass.py. For more detailed help, see examples at:
802 http://casaguides.nrao.edu/index.php?title=Plotbandpass
803 -- Todd Hunter
804 """
805 def safe_pb_subplot(xframe):
806 """
807 CAS-12786: old pyplots (up to CASA 5.6.1 used to accept "220" in the pos parameter
808 Newer pyplots won't. Assume the index effectively used was 1 ("221")
809 """
810 xf = (xframe + 1) if str(xframe).endswith('0') else xframe
811 return pb.subplot(xf)
813 def safe_pb_clf():
814 pb.clf()
816 casalog.origin('plotbandpass')
817 casalogPost(debug,"task plotbandpass version number:\t%s" % (TASK_PLOTBANDPASS_REVISION_STRING))
818 casalogPost(debug,"tracking au version:\t\t\t%s" % (PLOTBANDPASS_REVISION_STRING))
819 DEBUG = debug
820 help = False
821 vm = '' # unused variable, now that msmd is available in casa
822 if (help):
823 print("Usage: plotbandpass(caltable='', antenna='', field='', spw='', yaxis='amp',")
824 print(" xaxis='chan', figfile='', plotrange=[0,0,0,0], caltable2='',")
825 print(" overlay='', showflagged=False, timeranges='', buildpdf=False, caltable3='',")
826 print(" markersize=3, density=108, interactive=True, showpoints='auto',")
827 print(" showlines='auto', subplot='22', zoom='', poln='', showatm=False, pwv='auto',")
828 print(" gs='gs', convert='convert', chanrange='', debug=False,")
829 print(" solutionTimeThresholdSeconds=30.0, phase='', vis='', showtsky=False,")
830 print(" showfdm=False, showatmfield='', lo1='', showimage=False,")
831 print(" showatmPoints=False, parentms='', pdftk='pdftk', channeldiff=False,")
832 print(" edge=8, resample=1, vis='',platformingThreshold=%f," % (DEFAULT_PLATFORMING_THRESHOLD))
833 print(" platformingSigma=%.1f, basebands=[], showBasebandNumber=False," % (5.0))
834 print(" scans='')")
835 print(" antenna: must be either an ID (int or string or list), or a single antenna name or list")
836 print(" basebands: show only spws from the specified baseband or list of basebands (default:None=all)")
837 print(" buildpdf: True/False, if True and figfile is set, assemble pngs into a pdf")
838 print(" caltable: a bandpass table, of type B or BPOLY")
839 print(" caltable2: a second cal table, of type BPOLY or B, to overlay on a B table")
840 print(" caltable3: a third cal table, of type BPOLY, to overlay on the first two")
841 print(" chanrange: set xrange ('5~100') over which to autoscale y-axis for xaxis='freq'")
842 print(" channeldiff: set to value > 0 (sigma) to plot derivatives of amplitude")
843 print(" convert: full path for convert command (in case it's not found)")
844 print(" density: dpi to use in creating PNGs and PDFs (default=108)")
845 print(" edge: the number of edge channels to ignore in finding outliers (for channeldiff>0)")
846 print(" field: must be an ID, source name, or list thereof; can use trailing *: 'J*'")
847 print(" figfile: the base_name of the png files to save: base_name.antX.spwY.png")
848 print(" figfileSequential: naming scheme, False: name by spw/antenna (default)")
849 print(" True: figfile.1.png, figfile.2.png, etc.")
850 print(" gs: full path for ghostscript command (in case it's not found)")
851 print(" interactive: if False, then figfile will run to completion automatically and no gui")
852 print(" lo1: specify the LO1 setting (in GHz) for the observation")
853 print(" overlay: 'antenna','time','antenna,time','spw', or 'baseband'")
854 print(" makes 1 plot with different items in colors")
855 print(" markersize: size of points (default=3)")
856 print(" vis: name of the ms for this table, in case it does not match the string in the caltable")
857 print(" parentms: name of the parent ms, in case the ms has been previously split")
858 print(" pdftk: full path for pdftk command (in case it's not found)")
859 print(" phase: the y-axis limits to use for phase plots when yaxis='both'")
860 print(" platformingSigma: declare platforming if the amplitude derivative exceeds this many times the MAD")
861 print(" platformingThreshold: if platformingSigma=0, then declare platforming if the amplitude")
862 print(" derivative exceeds this percentage of the median")
863 print(" plotrange: define axis limits: [x0,x1,y0,y1] where 0,0 means auto")
864 print(" poln: polarizations to plot (e.g. 'XX','YY','RR','LL' or '' for both)")
865 print(" pwv: define the pwv to use for the showatm option: 'auto' or value in mm")
866 print(" resample: channel expansion factor to use when computing MAD of derivative (for channeldiff>0)")
867 print(" scans: show only solutions for the specified scans (int, list, or string)")
868 print(" showatm: compute and overlay the atmospheric transmission curve")
869 print(" showatmfield: for overlay='time', use first observation of this fieldID or name")
870 print(" showatmPoints: draw atmospheric curve with points instead of a line")
871 print(" showBasebandNumber: put the BBC_NO in the title of each plot")
872 print(" showfdm: when showing TDM spws with xaxis='freq', draw locations of FDM spws")
873 print(" showflagged: show the values of data, even if flagged")
874 print(" showimage: also show the atmospheric curve for the image sideband (in black)")
875 print(" showtsky: compute and overlay the sky temperature curve instead of transmission")
876 print(" showlines: draw lines connecting the data (default=T for amp, F for phase)")
877 print(" showpoints: draw points for the data (default=F for amp, T for phase)")
878 print(" solutionTimeThresholdSeconds: consider 2 solutions simultaneous if within this interval (default=30)")
879 print(" spw: must be single ID or list or range (e.g. 0~4, not the original ID)")
880 print(" subplot: 11..81,22,32 or 42 for RowsxColumns (default=22), any 3rd digit is ignored")
881 print(" timeranges: show only these timeranges, the first timerange being 0")
882 print(" xaxis: 'chan' or 'freq'")
883 print(" yaxis: 'amp', 'tsys', 'phase', or 'both' amp&phase == 'ap'; append 'db' for dB")
884 print(" zoom: 'intersect' will zoom to overlap region of caltable with caltable2")
885 return()
886 mytimestamp = time.time()
887 debugSloppyMatch = debug
888 doneOverlayTime = False # changed from True on 08-nov-2012
889 missingCalWVRErrorPrinted = False
890 adesc = None
891 # initialize the arguments to DrawAtmosphereAndFDM()
892 TebbSky = None
893 TebbSkyImage = None
894 atmchan = None
895 atmfreq = None
896 transmission = None
897 atmchanImage = None
898 atmfreqImage = None
899 transmissionImage = None
900 originalSpw_casa33 = None
901 originalSpw = None
902 chanFreqGHz_casa33 = None
903 chanFreqGHz = None
904 # initialize arguments to DrawPolarizationLabelsForOverlayTime()
905 gamp_mad = None
906 gamp_std = None
907 figfileNumber = 0 # only used if figfileSequential == True
909 if (False):
910 # Write a .last file
911 if (os.access('plotbandpass.last',os.W_OK)):
912 cmd = 'plotbandpass'
913 lastfile = open('%s.last'%cmd,'w')
914 lastfile.write('taskname = "%s"\n'%cmd)
915 cmd += '(' + writeArgument(lastfile, "caltable", caltable)
916 cmd += ',' + writeArgument(lastfile, "antenna" , antenna)
917 cmd += ',' + writeArgument(lastfile, "field" , field)
918 cmd += ',' + writeArgument(lastfile, "spw" , spw)
919 cmd += ',' + writeArgument(lastfile, "yaxis", yaxis)
920 cmd += ',' + writeArgument(lastfile, "xaxis", xaxis)
921 cmd += ',' + writeArgument(lastfile, "figfile", figfile)
922 cmd += ',' + writeArgument(lastfile, "plotrange" , plotrange)
923 cmd += ',' + writeArgument(lastfile, "caltable2", caltable2)
924 cmd += ',' + writeArgument(lastfile, "overlay", overlay)
925 cmd += ',' + writeArgument(lastfile, "showflagged", showflagged)
926 cmd += ',' + writeArgument(lastfile, "timeranges", timeranges)
927 cmd += ',' + writeArgument(lastfile, "buildpdf", buildpdf)
928 cmd += ',' + writeArgument(lastfile, "caltable3", caltable3)
929 cmd += ',' + writeArgument(lastfile, "markersize", markersize)
930 cmd += ',' + writeArgument(lastfile, "density", density)
931 cmd += ',' + writeArgument(lastfile, "interactive", interactive)
932 cmd += ',' + writeArgument(lastfile, "showpoints", showpoints)
933 cmd += ',' + writeArgument(lastfile, "showlines", showlines)
934 cmd += ',' + writeArgument(lastfile, "subplot", subplot)
935 cmd += ',' + writeArgument(lastfile, "zoom", zoom)
936 cmd += ',' + writeArgument(lastfile, "poln", poln)
937 cmd += ',' + writeArgument(lastfile, "showatm", showatm)
938 cmd += ',' + writeArgument(lastfile, "showatmfield", showatmfield)
939 cmd += ',' + writeArgument(lastfile, "pwv", pwv)
940 cmd += ',' + writeArgument(lastfile, "gs", gs)
941 cmd += ',' + writeArgument(lastfile, "convert", convert)
942 cmd += ',' + writeArgument(lastfile, "chanrange", chanrange)
943 cmd += ',' + writeArgument(lastfile, "solutionTimeThresholdSeconds", solutionTimeThresholdSeconds)
944 cmd += ',' + writeArgument(lastfile, "debug", debug)
945 # cmd += ',' + writeArgument(lastfile, "vm", vm)
946 cmd += ',' + writeArgument(lastfile, "phase", phase)
947 cmd += ',' + writeArgument(lastfile, "vis", vis)
948 cmd += ',' + writeArgument(lastfile, "parentms", parentms)
949 cmd += ',' + writeArgument(lastfile, "lo1", lo1)
950 cmd += ',' + writeArgument(lastfile, "showimage", showimage)
951 cmd += ',' + writeArgument(lastfile, "showtsky", showtsky)
952 cmd += ',' + writeArgument(lastfile, "showatmPoints", showatmPoints)
953 cmd += ',' + writeArgument(lastfile, "showfdm", showfdm)
954 cmd += ',' + writeArgument(lastfile, "pdftk", pdftk) + ')'
955 lastfile.write('#%s\n'%(cmd))
956 lastfile.close()
958 LO1 = None # Fix for SCOPS-4877
959 lo1s = None # Fix for SCOPS-4877
960 if (showimage == False):
961 LO1 = lo1 = ''
962 elif (lo1 != ''):
963 if re.match("^\d+?\.\d+?$", lo1) is None:
964 print("lo1 must be a float (entered as a string or number)")
965 return
966 lo1 = float(lo1)
967 if (lo1 > 1e6):
968 # convert from Hz to GHz
969 lo1 *= 1e-9
970 if (showatm and showtsky):
971 print("You have selected both showatm and showtsky! Defaulting to showatm=True only.")
972 showtsky = False
973 if (showatm==False and showtsky==False and showatmfield!=''):
974 print("Defaulting to showatm=True because showatmfield was specified.")
975 showatm = True
976 if (showatm==False and showtsky==False and showimage==True):
977 print("Defaulting to showatm=True because showimage was True.")
978 showatm = True
979 if showtsys:
980 showtsky = True
981 if (overlay.find('time') < 0 and showatmfield != ''):
982 print("The showatmfield only has meaning for overlay='time'.")
983 return()
985 if (plotrange=='' or plotrange==[]):
986 plotrange = [0,0,0,0]
987 if (type(plotrange) != list):
988 print("plotrange must be an array: e.g. [0,1,-180,180]")
989 return()
990 if (len(plotrange) < 4):
991 print("plotrange must be an array: e.g. [0,1,-180,180]")
992 return()
993 if (phase != ''):
994 if (type(phase) != list):
995 print("phase must be either '' or 2 values: [x,y]")
996 return()
997 if (len(phase) != 2):
998 print("phase must be either '' or 2 values: [x,y]")
999 return()
1001 if (edge < 0):
1002 print("edge must be >= 0")
1003 return(vm)
1005 if (resample < 1):
1006 print("resample must be an integer >= 1")
1007 return(vm)
1008 resample = int(resample)
1010 if (buildpdf and figfile==''):
1011 print("With buildPDF=True, you must specify figfile='yourFileName' (.png will be appended if necessary).")
1012 return()
1014 if (interactive==False and figfile=='' and channeldiff == False):
1015 print("With interactive=False and channeldiff=False, you must specify figfile='yourFileName' (.png will be appended if necessary).")
1016 return()
1018 pxl = 0 # polarization number to use for setting xlimits if plotrange=[0,0...]
1019 chanrangePercent = None
1020 if (type(chanrange) != str):
1021 if (type(chanrange) != list):
1022 print("Chanrange must be a string or list: '8~120' or [8,120]")
1023 return()
1024 elif (len(chanrange) != 2):
1025 print("Chanrange must be a string or list: '8~120' or [8,120]")
1026 return()
1027 elif ((type(chanrange[0]) != int) or (type(chanrange[1]) != int)):
1028 print("Chanrange list members must be integers, not %s, %s" % (type(chanrange[0]), type(chanrange[1])))
1029 return
1030 elif (len(chanrange) < 1):
1031 chanrange = [0,0]
1032 else:
1033 if (chanrange.find('%')>0):
1034 chanrangePercent = float(chanrange.split('%')[0])
1035 if (chanrangePercent >= 100 or chanrangePercent <= 0):
1036 chanrangePercent = None
1037 chanrange = [0,0]
1038 elif (chanrange.find('~')>=0):
1039 tokens = chanrange.split('~')
1040 if (len(tokens) < 2):
1041 print("Invalid chanrange string, too few tokens")
1042 return()
1043 try:
1044 chanrange = [int(tokens[0]),int(tokens[1])]
1045 if (DEBUG):
1046 print("Using chanrange = %s" % (str(chanrange)))
1047 except:
1048 print("Invalid chanrange, not integers")
1049 return()
1050 else:
1051 print("Invalid chanrange, no tilde or percent sign found")
1052 return()
1053 if (xaxis.find('chan')>=0):
1054 print("The chanrange parameter is only valid for xaxis='freq', and only if the plotrange is [0,0,0,0].")
1055 return()
1056 if (chanrange[0] < 0):
1057 print("Invalid chanrange, cannot be negative")
1058 return()
1059 if ((chanrange[0] != 0 or chanrange[1] != 0 or chanrangePercent != None) and
1060 (plotrange[0] != 0 or plotrange[1] != 0 or plotrange[2] != 0 or plotrange[3] != 0)):
1061 print("If chanrange is specified, then plotrange must be all zeros.")
1062 return()
1064 if (pwv==''):
1065 pwv = 1.0
1067 # CAS-12786: from a command that sets poln='' we'll get poln as ['']
1068 if isinstance(poln, list) and 1 == len(poln):
1069 poln = poln[0]
1071 if (type(poln) != list):
1072 poln = poln.upper()
1073 if (poln == 'X'):
1074 poln = 'XX'
1075 if (poln == 'Y'):
1076 poln = 'YY'
1077 if (poln == 'X,Y' or poln=='Y,X'):
1078 poln = 'XX,YY'
1079 if (poln == 'R'):
1080 poln = 'RR'
1081 if (poln == 'L'):
1082 poln = 'LL'
1083 if (poln == 'R,L' or poln=='L,R'):
1084 poln = 'RR,LL'
1086 # Parse the polarizations to plot from the command line
1087 # Prior to opening the .ms (later), we cannot tell which products are actually present
1088 useAllPols = False
1089 if (poln == ''):
1090 useAllPols = True
1091 polsToPlot = ['XX','YY'] # assume ALMA initially
1092 elif (type(poln) == list):
1093 polsToPlot = poln
1094 else:
1095 if ((poln in ['','RR','RL','LR','LL','XX','XY','YX','YY','RR,LL','XX,YY']) == False):
1096 print("Unrecognized polarization option = %s" % (poln))
1097 return()
1098 if (poln.find(',')>0):
1099 polsToPlot = poln.split(',')
1100 else:
1101 polsToPlot = [poln]
1104 if ((overlay in ['antenna', 'spw', 'time', 'baseband', '',
1105 'antenna,time', 'time,antenna']) == False):
1106 print("Unrecognized option for overlay: only 'antenna', 'spw', 'baseband', 'time' and 'antenna,time' are supported.")
1107 return()
1109 allowedFrames = [11,21,31,41,51,61,71,81,22,32,42] # [11,22,32,42]
1110 if (int(subplot) > 100):
1111 # This will accept 111, 221, 321, 421, etc.
1112 subplot //= 10
1113 if ((int(subplot) in allowedFrames)==False):
1114 print("Subplot choice (rows x columns) must be one of %s" % (str(allowedFrames)))
1115 print("(with an optional trailing digit that is ignored).")
1116 return()
1118 if ((int(subplot) % 2) == 1):
1119 timeHorizontalSpacing = 0.06*1.3 # *1.3 is for HH:MM:SS (timeFormat=3 in drawOverlayTimeLegends)
1120 else:
1121 timeHorizontalSpacing = 0.05*1.3 # *1.3 is for HH:MM:SS
1123 if (yaxis.find('both')<0 and yaxis.find('ap')<0 and yaxis.find('tsys')<0 and
1124 yaxis.find('amp')<0 and yaxis.find('phase')<0):
1125 print("Invalid yaxis. Must be 'amp', 'tsys', 'phase' or 'both'.")
1126 return()
1128 if (yaxis.find('tsys')>=0):
1129 yaxis = 'amp'
1131 if (xaxis.find('chan')<0 and xaxis.find('freq')<0):
1132 print("Invalid xaxis. Must be 'chan' or 'freq'.")
1133 return()
1135 if (showatm and showtsky):
1136 print("showatm=True and showtsky=True are mutually exclusive options")
1137 return()
1139 if (showfdm and xaxis.find('freq')<0):
1140 print("The option showfdm=True requires xaxis='freq'.")
1141 return()
1143 # Plotting settings
1144 minPhaseRange = 0.2
1145 plotfiles = []
1146 if (int(subplot) % 2 == 1):
1147 mysize = '10'
1148 titlesize = 10
1149 elif (int(subplot) == 22 or int(subplot) == 32):
1150 mysize = '8'
1151 titlesize = 8
1152 else:
1153 mysize = '7'
1154 titlesize = 8
1155 maxCharsBeforeReducingTitleFontSize = 72
1156 if (type(subplot) == str):
1157 subplot = int(subplot)
1158 if (subplot in allowedFrames == False):
1159 print("Invalid subplot = %d. Valid options are: %s" % (subplot,str(allowedFrames)))
1160 return()
1161 xframeStart = int(subplot)*10 # i.e. 110 or 220 or 420
1162 firstFrame = xframeStart + 1
1163 lastFrame = xframeStart + (subplot//10)*(subplot%10)
1164 bottomRowFrames = [111,212,313,414,515,616,717,818,223,224,325,326,427,428] # try to make this more general
1165 leftColumnFrames = [111,211,212,311,312,313,411,412,413,414,511,512,513,514,515,611,612,613,614,615,616,
1166 711,712,713,714,715,716,717,811,812,813,814,815,816,817,818,221,223,321,323,325,421,423,425,427]
1167 rightColumnFrames = [111,211,212,311,312,313,411,412,413,414,511,512,513,514,515,611,612,613,614,615,616,
1168 711,712,713,714,715,716,717,811,812,813,814,815,816,817,818,222,224,322,324,326,422,424,426,428]
1169 subplotCols = subplot % 10
1170 subplotRows = subplot//10
1171 ystartPolLabel = 1.0-0.04*subplotRows
1172 ystartMadLabel = 0.04*subplotRows
1173 if (subplotCols == 1):
1174 fstringLimit = 40 # character length of multi-field overlay title string
1175 elif (subplotCols == 2):
1176 fstringLimit = 12 # character length of multi-field overlay title string
1178 xframe = xframeStart
1179 previousSubplot = xframe
1180 xcolor = 'b'
1181 ycolor = 'g'
1182 pcolor = ['b','g']
1183 x2color = 'k'
1184 y2color = 'c'
1185 p2color = ['k','c']
1186 x3color = 'm'
1187 y3color = 'r'
1188 p3color = ['m','r']
1189 if (showpoints == 'auto'):
1190 if (showlines == 'auto'):
1191 ampmarkstyle = '-'
1192 phasemarkstyle = '.'
1193 if (len(polsToPlot) == 1):
1194 ampmarkstyle2 = '-'
1195 else:
1196 ampmarkstyle2 = '--'
1197 phasemarkstyle2 = 'o'
1198 elif (showlines == False):
1199 ampmarkstyle = '.'
1200 ampmarkstyle2 = 'o'
1201 phasemarkstyle = '.'
1202 phasemarkstyle2 = 'o'
1203 else:
1204 ampmarkstyle = '-'
1205 phasemarkstyle = '-'
1206 if (len(polsToPlot) == 1):
1207 ampmarkstyle2 = '-'
1208 phasemarkstyle2 = '-'
1209 else:
1210 ampmarkstyle2 = '--'
1211 phasemarkstyle2 = '--'
1212 elif (showpoints == True):
1213 if (showlines == 'auto'):
1214 ampmarkstyle = '.-'
1215 phasemarkstyle = '.'
1216 if (len(polsToPlot) == 1):
1217 ampmarkstyle2 = 'o-'
1218 else:
1219 ampmarkstyle2 = 'o--'
1220 phasemarkstyle2 = 'o'
1221 elif (showlines == False):
1222 ampmarkstyle = '.'
1223 ampmarkstyle2 = 'o'
1224 phasemarkstyle = '.'
1225 phasemarkstyle2 = 'o'
1226 else:
1227 ampmarkstyle = '.-'
1228 phasemarkstyle = '.-'
1229 if (len(polsToPlot) == 1):
1230 ampmarkstyle2 = 'o-'
1231 phasemarkstyle2 = 'o-'
1232 else:
1233 ampmarkstyle2 = 'o--'
1234 phasemarkstyle2 = 'o--'
1235 else: # showpoints == False
1236 if (showlines == False):
1237 print('You must have either showpoints or showlines set True or auto, assuming showlines=T')
1238 ampmarkstyle = '-'
1239 phasemarkstyle = '-'
1240 if (len(polsToPlot) == 1):
1241 ampmarkstyle2 = '-'
1242 phasemarkstyle2 = '-'
1243 else:
1244 ampmarkstyle2 = '--'
1245 phasemarkstyle2 = '--'
1247 ampmarkstyles = [ampmarkstyle,ampmarkstyle2]
1248 phasemarkstyles = [phasemarkstyle,phasemarkstyle2]
1249 # bpoly solutions should always be shown as lines, not dots or dots+lines
1250 bpolymarkstyle = '-'
1252 amplitudeWithPhase = (yaxis.find('both')>=0 or yaxis.find('ap')>=0)
1253 if (amplitudeWithPhase):
1254 myhspace = 0.30
1255 if (overlay.find('antenna')>=0 or overlay.find('time')>=0 or overlay.find('spw')>=0):
1256 print("Option 'overlay' is incompatible with yaxis='both'. Pick either amp or phase.")
1257 return()
1258 else:
1259 myhspace = 0.30
1260 if (subplot//10 > 2):
1261 myhspace = 0.4
1262 if (subplot//10 > 3):
1263 myhspace = 0.6
1264 mywspace = 0.25
1266 # Now open the Bandpass solution table
1267 if (len(caltable) < 1):
1268 print("You need to specify a caltable.")
1269 return(vm)
1270 if (caltable[-1] == '/'):
1271 print("Stripping off the trailing '/' from the caltable name.")
1272 caltable = caltable[:-1]
1273 mytb = table()
1274 try:
1275 if (DEBUG): print("Trying to open: %s." % (caltable))
1276 mytb.open(caltable)
1277 except:
1278 print("Could not open the caltable = %s" % (caltable))
1279 return()
1280 if (caltable[0] != '/'):
1281 # print(this so when someone sends me a bug report I can find their data!)
1282 try:
1283 print("caltable = %s:%s/%s" % (os.uname()[1], os.getcwd(), caltable))
1284 except:
1285 print("caltable = localhost:%s/%s" % (os.getcwd(), caltable))
1286 else:
1287 try:
1288 print("caltable = %s:%s" % (os.uname()[1], caltable))
1289 except:
1290 print("caltable = localhost:%s" % (caltable))
1292 if (len(caltable) > 90):
1293 caltableTitle = '...' + caltable[-90:]
1294 else:
1295 caltableTitle = caltable
1296 names = mytb.colnames()
1297 ant = mytb.getcol('ANTENNA1')
1298 fields = mytb.getcol('FIELD_ID')
1299 if (DEBUG):
1300 print("FIELD_ID column = %s" % (str(fields)))
1301 validFields = False
1302 for f in fields:
1303 if (f != -1):
1304 validFields = True
1305 if (validFields == False):
1306 print("The field_id is -1 (invalid) for all rows of this caltable.")
1307 print("Did you remember to run assignFieldAndScanToSolution()?")
1308 return()
1309 try:
1310 flags = {}
1311 for f in range(len(fields)):
1312 flags[f] = mytb.getcell('FLAG',f)
1313 except:
1314 print("No Flag column found. Are you sure this is a bandpass solution file, or is it the .ms?")
1315 print("If it is a solution file, does it contain solutions for both TDM and FDM spws?")
1316 return()
1318 times = mytb.getcol('TIME')
1319 intervals = mytb.getcol('INTERVAL')
1320 if ('SPECTRAL_WINDOW_ID' not in names):
1321 tableFormat = 33
1322 cal_desc_id = mytb.getcol('CAL_DESC_ID')
1323 VisCal = (mytb.info())['subType']
1324 if (VisCal == "BPOLY"):
1325 casalogPost(debug,"This appears to be a BPOLY cal table written in the casa 3.3/3.4 style.")
1326 else:
1327 casalogPost(debug,"This appears to be an old-format cal table from casa 3.3 or earlier.")
1328 if (debug): print("VisCal = %s" % (VisCal))
1329 mytb.close()
1330 ParType = "unknown" # i.e. not Complex
1331 calDesc = mytb.open(caltable+'/CAL_DESC')
1332 originalSpws = mytb.getcol('SPECTRAL_WINDOW_ID') # [[0,1,2,3]]
1333 if debug: print("originalSpws = %s" % (str(originalSpws)))
1334 originalSpw = originalSpws[0] # [0,1,2,3]
1335 if debug: print("originalSpw = %s" % (str(originalSpw)))
1336 msName = mytb.getcol('MS_NAME')[0]
1337 if debug: print("msName in table = %s" % (msName))
1338 if (vis != ''):
1339 msName = vis
1340 # This appears to be the channel range extracted from the original spw, but is
1341 # only present in B solutions.
1342 if (VisCal == "BPOLY"):
1343 originalChannelStart = np.zeros(len(originalSpw))
1344 else:
1345 originalChannelRange = mytb.getcol('CHAN_RANGE')
1346 originalChannelStart = originalChannelRange[0][0][:][0]
1347 mytb.close()
1348 try:
1349 mytb.open(msName+'/SPECTRAL_WINDOW')
1350 refFreq = mytb.getcol('REF_FREQUENCY')
1351 net_sideband = mytb.getcol('NET_SIDEBAND')
1352 measFreqRef = mytb.getcol('MEAS_FREQ_REF')
1353 originalSpw_casa33 = list(range(len(measFreqRef)))
1354 chanFreqGHz_casa33 = [] # used by showFDM
1355 for i in originalSpw_casa33:
1356 # They array shapes can vary.
1357 chanFreqGHz_casa33.append(1e-9 * mytb.getcell('CHAN_FREQ',i))
1358 mytb.close()
1359 except:
1360 print("2) Could not open the associated measurement set tables (%s). Will not translate antenna names." % (msName))
1361 cal_scans = None #### added 2024Aug
1362 else: # 3.4
1363 tableFormat = 34
1364 cal_desc_id = mytb.getcol('SPECTRAL_WINDOW_ID')
1365 cal_scans = mytb.getcol('SCAN_NUMBER')
1366 unique_cal_scans = np.unique(cal_scans)
1367 cal_scans_per_spw = {}
1368 for myspw in np.unique(cal_desc_id):
1369 cal_scans_per_spw[myspw] = np.unique(cal_scans[np.where(myspw == cal_desc_id)[0]])
1370 if (debug):
1371 print("spw %d: scans %s" % (myspw,str(cal_scans_per_spw[myspw])))
1372 ParType = mytb.getkeyword('ParType') # string = 'Complex'
1373 msName = mytb.getkeyword('MSName')
1374 VisCal = mytb.getkeyword('VisCal') # string = 'B TSYS'
1375 PolBasis = mytb.getkeyword('PolBasis') # string = 'LINEAR'
1376 spectralWindowTable = mytb.getkeyword('SPECTRAL_WINDOW').split()[1]
1377 antennaTable = mytb.getkeyword('ANTENNA').split()[1]
1378 fieldTable = mytb.getkeyword('FIELD').split()[1]
1379 mytb.close()
1380 mytb.open(spectralWindowTable)
1381 chanFreqGHz = []
1382 originalSpws = list(range(len(mytb.getcol('MEAS_FREQ_REF'))))
1383 originalSpw = originalSpws # may need to do a global replace of this
1384 originalSpwNames = mytb.getcol('NAME')
1385 for i in originalSpws:
1386 # They array shapes can vary.
1387 chanFreqGHz.append(1e-9 * mytb.getcell('CHAN_FREQ',i))
1388 mytb.close()
1389 # CAS-6801 changes
1390 mytb.open(antennaTable)
1391 msAnt = mytb.getcol('NAME')
1392 mytb.close()
1393 mytb.open(fieldTable)
1394 msFields = mytb.getcol('NAME')
1395 mytb.close()
1397 if (VisCal == 'K Jones'):
1398 delay = True
1399 showpoints = True
1400 ampmarkstyle = '.'
1401 ampmarkstyle2 = 'o'
1402 if (markersize < 8): markersize = 8
1403 else:
1404 delay = False
1405 # Now open the associated ms tables via msmd tool
1406# msAnt = [] # comment this out when CAS-6801 changes are in place
1407 if (debug): print( "creating msmd tool")
1408 if (ctsys.compare_version('<',[4,1,0])):
1409 print("This version of casa is too old to use the msmd tool. Use au.plotbandpass instead.")
1410 return
1411 mymsmd = ''
1412 observatoryName = ''
1413 if (debug): print( "msName = %s." % (msName))
1414 if (os.path.exists(msName) or os.path.exists(os.path.dirname(caltable)+'/'+msName)):
1415 if (os.path.exists(msName) == False):
1416 msName = os.path.dirname(caltable)+'/'+msName
1417 if (debug): print( "found msName = %s." % (msName))
1418 if (ctsys.compare_version('<',[4,1,0])):
1419 print("This version of casa is too old to use the msmd tool. Use au.plotbandpass instead.")
1420 return
1421 try:
1422 if (debug): print("Running mymsmd on %s..." % (msName))
1423 mymsmd = msmetadata()
1424 mymsmd.open(msName) # this is the only open (vis not specified, but it exists)
1425 donetime = time.time()
1426 if (debug): print("%.1f sec elapsed" % (donetime-mytimestamp))
1427 mytimestamp = time.time()
1428 if (debug): print("time = %s" % (str(mytimestamp)))
1429 msAnt = mymsmd.antennanames(list(range(mymsmd.nantennas())))
1430 if (debug): print("msAnt = %s" % (str(msAnt)))
1431# msFields = mymsmd.namesforfields(range(mymsmd.nfields())) # bombs if split has been run on subset of fields
1432 msFields = mymsmd.namesforfields()
1433 observatoryName = mymsmd.observatorynames()[0]
1434 casalogPost(debug,"Available antennas = %s" % (str(msAnt)))
1435 except:
1436 print("1)Could not open the associated measurement set tables (%s). Will not translate antenna names or frequencies." % (msName))
1437 return
1438 else:
1439 if (vis=='' and tableFormat < 34):
1440 print("Could not find the associated measurement set (%s). Will not translate antenna names or frequencies." % (msName))
1441 elif (vis != ''):
1442 # Use the ms name passed in from the command line
1443 msName = vis
1444# # print("************* 2) Set msName to %s" % (msName))
1445 try:
1446 mymsmd = msmetadata()
1447 if (debug): print("Running msmd.open on %s" % (msName))
1448 mymsmd.open(msName) # this is the only open (vis specified)
1449 donetime = time.time()
1450 if (debug): print("%.1f sec elapsed" % (donetime-mytimestamp))
1451 mytimestamp = time.time()
1452 msAnt = mymsmd.antennanames(list(range(mymsmd.nantennas())))
1453# msFields = mymsmd.namesforfields(range(mymsmd.nfields())) # bombs if split has been run on subset of fields
1454 msFields = mymsmd.namesforfields()
1455 observatoryName = mymsmd.observatorynames()[0]
1456 casalogPost(debug,"Available antennas = %s" % (str(msAnt)))
1457 except:
1458 print("1b) Could not open the associated measurement set tables (%s). Will not translate antenna names or channels to frequencies." % (msName))
1459 msFound = False
1460 if (len(msAnt) > 0):
1461 msFound = True
1462 casalogPost(debug,"Fields in ms = %s" % (str(msFields)))
1463 else:
1464 msFields = []
1465 if (tableFormat == 33 and msFound): # casa 3.3
1466 # Now open the associated ms tables via ValueMapping to figure out channel freqs
1467 chanFreqGHz = []
1468 for ictr in range(len(originalSpw)):
1469 if debug: print("ictr = %d" % (ictr))
1470 if debug: print("nspw = %d, np.max(originalSpw) = %d" % (getnspw(mymsmd),np.max(originalSpw)))
1471 if (getnspw(mymsmd) < np.max(originalSpw)): # waiting on CAS-4285
1472 # Then there was an extra split
1473 i = ictr
1474 else:
1475 i = originalSpw[ictr]
1476 nchan = mymsmd.nchan(i)
1477 if (nchan > 1):
1478 missingFrequencyWidth = originalChannelStart[ictr]*(mymsmd.chanfreqs(i)[-1]-mymsmd.chanfreqs(i)[0])/(nchan-1)
1479 else:
1480 missingFrequencyWidth = 0
1481 if (missingFrequencyWidth > 0):
1482 if (DEBUG):
1483 print("Correcting for channels flagged prior to running bandpass by %f GHz" % (missingFrequencyWidth*1e-9))
1484 newfreqs = 1e-9*(mymsmd.chanfreqs(i)) + missingFrequencyWidth*1e-9
1485 if debug: print("Appending onto chanFreqGHz: %s" % (str(newfreqs)))
1486 chanFreqGHz.append(newfreqs)
1488 # the sort order of this variable is based on tb.getcol('SPECTRAL_WINDOW_ID') which is usually (always?) in increasing order
1489 uniqueSpwsInCalTable = np.unique(cal_desc_id)
1491 # initial calculation for final message if not all spws appear with overlay='antenna'
1492 uniqueTimes = sloppyUnique(np.unique(times), 1.0)
1493 nUniqueTimes = len(uniqueTimes)
1494 if (nUniqueTimes == 1):
1495 solutionTimeSpread = 0
1496 else:
1497 solutionTimeSpread = np.max(uniqueTimes)-np.min(uniqueTimes)
1498 casalogPost(debug,"Found solutions with %d unique times across all spws and fields (within a threshold of 1.0 second)." % (nUniqueTimes))
1500 casalogPost(True,"Median difference between solution times = %f sec" % (np.median(np.diff(uniqueTimes))))
1501 if cal_scans is None or VisCal == 'SDSKY_PS': ### added 2024Aug
1502 # this will show the spectrum for every solution / integration (appropriate for old Tsys tables and SDsky spectra)
1503 uniqueTimes = sloppyUnique(np.unique(times), solutionTimeThresholdSeconds) ### indented 2024Aug
1504 else: ### added 2024Aug
1505 # this will show one spectrum per scan (appropriate for Tsys tables in CASA 3.4 onward)
1506 uniqueTimes = sloppyUnique(times, solutionTimeThresholdSeconds, cal_scans) ### added 2024Aug
1507 nUniqueTimes = len(uniqueTimes)
1508 if (nUniqueTimes == 1):
1509 casalogPost(debug,"Found solutions with %d unique time (within a threshold of %d seconds)." % (nUniqueTimes,solutionTimeThresholdSeconds))
1510 else:
1511 casalogPost(debug,"Found solutions with %d unique times (within a threshold of %d seconds)." % (nUniqueTimes,solutionTimeThresholdSeconds))
1513 scansForUniqueTimes = []
1514 if (tableFormat >= 34):
1515 if (len(unique_cal_scans) == 1):
1516 casalogPost(debug,"Found solutions with %d unique scan number %s" % (len(unique_cal_scans), str(unique_cal_scans)))
1517 else:
1518 casalogPost(debug,"Found solutions with %d unique scan numbers %s" % (len(unique_cal_scans), str(unique_cal_scans)))
1520 scansForUniqueTimes, nUniqueTimes = computeScansForUniqueTimes(uniqueTimes, cal_scans, times, unique_cal_scans)
1521 elif (scans != ''):
1522 print("Selection by scan is not support for old-style tables that do not have the scan number filled.")
1523 return
1524 uniqueTimesCopy = uniqueTimes[:]
1526 mystring = ''
1527 if (debug):
1528 for u in uniqueTimes:
1529 mystring += '%.6f, ' % (u)
1530 print(mystring)
1531 uniqueAntennaIds = np.unique(ant)
1532 uniqueFields = np.unique(fields)
1533 if (debug): print("uniqueFields = %s" % (str(uniqueFields)))
1534 nFields = len(uniqueFields)
1535 spwlist = []
1536 uniqueTimesPerFieldPerSpw = []
1537 for s in uniqueSpwsInCalTable:
1538 uniqueTimesPerField = []
1539 for f in uniqueFields:
1540 timelist = []
1541 for row in range(len(fields)):
1542 if (fields[row] == f and cal_desc_id[row] == s):
1543 if (sloppyMatch(times[row], timelist, solutionTimeThresholdSeconds) == False):
1544 # if this time is not already in the list for this spw/field combination, then append it
1545 timelist.append(times[row])
1546 spwlist.append(cal_desc_id)
1547 uniqueTimesPerField.append(timelist)
1548 uniqueTimesPerFieldPerSpw.append(uniqueTimesPerField)
1550 if (debug): print("about to call casalogPost")
1551 casalogPost(debug,displayTimesArray([[uniqueTimes]]))
1553 # Parse the spws to plot from the command line
1554 if (spw==''):
1555 spwsToPlot = uniqueSpwsInCalTable
1556 else:
1557 if (type(spw) == str):
1558 if (spw.find('!')>=0):
1559 print("The ! modifier is not (yet) supported")
1560 return()
1561 tokens = spw.split(',')
1562 spwsToPlot = []
1563 for token in tokens:
1564 if (len(token) > 0):
1565 if (token.find('*')>=0):
1566 spwsToPlot = uniqueSpwsInCalTable
1567 break
1568 elif (token.find('~')>0):
1569 (start,finish) = token.split('~')
1570 spwsToPlot += list(range(int(start),int(finish)+1))
1571 else:
1572 spwsToPlot.append(int(token))
1573 elif (type(spw) == list):
1574 spwsToPlot = np.sort(spw)
1575 else:
1576 spwsToPlot = [spw]
1577 # note that spwsToPlot will not necessarily be in increasing order, e.g. if the user specified them out-of-order
1579 casalogPost(debug,"%d spw%s in the solution = %s" % (len(uniqueSpwsInCalTable), plural(uniqueSpwsInCalTable), str(uniqueSpwsInCalTable)))
1580 keepSpwsToPlot = spwsToPlot[:]
1581 for myspw in spwsToPlot:
1582 if (myspw not in uniqueSpwsInCalTable):
1583 print("WARNING: spw %d is not in the solution. Removing it from the list to plot." % (myspw))
1584 print("Available spws = ", uniqueSpwsInCalTable)
1585 keepSpwsToPlot.remove(myspw)
1586 if (ctsys.compare_version('>=',[4,1,0]) and mymsmd != ''):
1587# # nonwvrspws = list(set(range(mymsmd.nspw())).difference(set(mymsmd.wvrspws())))
1588 if (myspw not in list(range(mymsmd.nspw()))):
1589 print("FATAL: spw %d is not even in the ms. There might be a bug in your script." % (myspw))
1590 return
1591 elif (myspw in mymsmd.wvrspws()):
1592 print("WARNING: spw %d is a WVR spw." % (myspw))
1593 return
1594 spwsToPlot = keepSpwsToPlot[:]
1595 if (len(spwsToPlot) == 0):
1596 print("FATAL: no spws to plot")
1597 return
1598 originalSpwsToPlot = computeOriginalSpwsToPlot(spwsToPlot, originalSpw, tableFormat, debug)
1600 # Now generate the list of minimal basebands that contain the spws to be plotted
1601 if (ctsys.compare_version('>=',[4,1,0]) and msFound):
1602 allBasebands = []
1603 if (mymsmd != ''):
1604 try:
1605 for spw in originalSpwsToPlot:
1606 mybaseband = mymsmd.baseband(spw)
1607 if (debug): print("appending: spw=%d -> bb=%d" % (spw,mybaseband))
1608 allBasebands.append(mybaseband)
1609 allBasebands = np.unique(allBasebands)
1610 basebandDict = getBasebandDict(msName,caltable=caltable,mymsmd=mymsmd) # needed later by showFDM()
1611 except:
1612 basebandDict = {}
1613 print("This dataset (%s) does not have a BBC_NO column in the SPECTRAL_WINDOW_TABLE." % (msName))
1614 else:
1615 basebandDict = {}
1616 telescopeName = getTelescopeNameFromCaltable(caltable)
1617 print("Measurement set not found.")
1618 if (basebandDict == {}):
1619 if (overlay.find('spw') >= 0):
1620 print("As such, since the ms cannot be found, overlay='spw' is not supported, but overlay='baseband' should work.")
1621 return
1622 elif (showfdm):
1623 print("As such, since the ms cannot be found, showfdm=True is not supported.")
1624 return
1625 elif (showBasebandNumber):
1626 print("As such, since the ms cannot be found, showBasebandNumber=True is not supported.")
1627 return
1628 elif (msFound==False):
1629 allBasebands = [1,2,3,4]
1630 else:
1631 basebandDict = getBasebandDict(msName,caltable=caltable,mymsmd=mymsmd) # needed later by showFDM()
1632 allBasebands = []
1633 for spw in originalSpwsToPlot:
1634 mybaseband = [key for key in basebandDict if spw in basebandDict[key]]
1635 if (len(mybaseband)>0): allBasebands.append(mybaseband[0])
1636 allBasebands = np.unique(allBasebands)
1637 if (allBasebands == []):
1638 allBasebands = [1,2,3,4]
1639 if (debug):
1640 print("================ allBasebands = ", allBasebands)
1642 if (basebands == None or basebands == [] or basebands == ''):
1643 basebands = allBasebands
1644 elif (type(basebands) == str):
1645 basebands = [int(s) for s in basebands.split(',')]
1646 elif (type(basebands) != list):
1647 # it is a single integer
1648 basebands = [basebands]
1649 for baseband in basebands:
1650 if (baseband not in allBasebands):
1651 print("Baseband %d is not in the dataset (only %s)" % (baseband,str(allBasebands)))
1652 return
1654 if (msFound):
1655 msFieldsList = str(np.array(msFields)[uniqueFields])
1656 else:
1657 msFieldsList = 'unknown'
1658 casalogPost(debug,"%d field(s) in the solution = %s = %s" % (len(uniqueFields), uniqueFields,msFieldsList))
1660 # Figure out which kind of Bandpass solution this is.
1661 bOverlay = False # Am I trying to overlay a second B-type solution?
1662 if (os.path.exists(caltable) == False):
1663 print("Caltable does not exist = %s" % (caltable))
1664 return()
1665 try:
1666 ([polyMode, polyType, nPolyAmp, nPolyPhase, scaleFactor, nRows, nSpws, nUniqueTimesBP, uniqueTimesBP,
1667# # nPolarizations,
1668 frequencyLimits, increments, frequenciesGHz, polynomialPhase,
1669 polynomialAmplitude, timesBP, antennasBP, cal_desc_idBP, spwBP]) = openBpolyFile(caltable,debug)
1670 bpoly = True
1671 bpolyOverlay = bpolyOverlay2 = False
1672 if (xaxis.find('chan') >= 0):
1673 print("Sorry, but BPOLY solutions cannot be plotted with xaxis='chan'. Proceeding with xaxis='freq'.")
1674 xaxis = 'freq'
1675 if (chanrange[0] != 0 or chanrange[1] != 0 or chanrangePercent != None):
1676 print("The chanrange parameter only applies if the first caltable is a B solution, not a BPOLY.")
1677 return()
1678 if (len(caltable2) > 0):
1679 try:
1680 # figure out if the next file is a BPOLY or another B solution to pick the proper error message.
1681 ([polyMode, polyType, nPolyAmp, nPolyPhase, scaleFactor, nRows, nSpws, nUniqueTimesBP, uniqueTimesBP,
1682# # nPolarizations,
1683 frequencyLimits, increments, frequenciesGHz, polynomialPhase,
1684 polynomialAmplitude, timesBP, antennasBP, cal_desc_idBP, spwBP]) = openBpolyFile(caltable2,debug)
1685 print("Sorry, but you cannot overlay two BPOLY solutions (unless caltable is a B solution and caltable2 and 3 are BPOLYs).")
1686 except:
1687 print("Sorry, but for overlays, caltable must be a B solution, whlie caltable2 and 3 can be either type.")
1688 return()
1689 except:
1690 casalogPost(debug,"This is a %s solution." % (VisCal))
1691 bpoly = bpolyOverlay = bpolyOverlay2 = False
1693 # Now check if there is a second file to overlay
1694 if (len(caltable2) > 0):
1695 if (os.path.exists(caltable2) == False):
1696 print("Caltable2 does not exist = %s" % (caltable2))
1697 return()
1698 try:
1699 # figure out if the next file is a BPOLY or another B solution
1700 ([polyMode, polyType, nPolyAmp, nPolyPhase, scaleFactor, nRows, nSpws, nUniqueTimesBP, uniqueTimesBP,
1701# # nPolarizations,
1702 frequencyLimits, increments, frequenciesGHz, polynomialPhase,
1703 polynomialAmplitude, timesBP, antennasBP, cal_desc_idBP, spwBP]) = openBpolyFile(caltable2,debug)
1704 bpolyOverlay = True
1705 casalogPost(debug,"Overlay the BPOLY solution")
1706 if (xaxis.find('chan')>=0):
1707 print("Sorry, but overlap of BPOLY is currently possible only with xaxis='freq'")
1708 return()
1709 if (len(caltable3) > 0):
1710 if (os.path.exists(caltable3) == False):
1711 print("Caltable3 does not exist = %s" % (caltable3))
1712 return()
1713 bpolyOverlay2 = True
1714 casalogPost(debug,"Overlay the second BPOLY solution")
1715 ([polyMode2, polyType2, nPolyAmp2, nPolyPhase2, scaleFactor2, nRows2, nSpws2,
1716 nUniqueTimesBP2, uniqueTimesBP2,
1717# # nPolarizations2,
1718 frequencyLimits2, increments2, frequenciesGHz2, polynomialPhase2,
1719 polynomialAmplitude2, timesBP2, antennasBP2, cal_desc_idBP2, spwBP2]) = openBpolyFile(caltable3,debug)
1720 except:
1721 # this is another B solution
1722 casalogPost(debug,"Overlay another %s solution" % (VisCal))
1723 bOverlay = True
1724 if (xaxis.find('freq')<0):
1725 print("Currently, you must use xaxis='freq' to overlay two B solutions.")
1726 return()
1727 if (len(caltable3) > 0):
1728 print("You cannot overlay caltable3 because caltable2 is a B solution.")
1729 return()
1730 elif (len(caltable3) > 0):
1731 print("You cannot have a caltable3 argument without a caltable2 argument.")
1732 return()
1734 if (overlay.find('antenna')>=0):
1735 overlayAntennas = True
1736 if (bpoly == True):
1737 print("The overlay of times or antennas is not supported with BPOLY solutions")
1738 return()
1739 if (len(caltable2)>0):
1740 print("The overlay of times or antennas not supported when overlaying a B or BPOLY solution")
1741 return()
1742 casalogPost(debug,"Will overlay solutions from different antennas")
1743 else:
1744 overlayAntennas = False
1746 if (overlay.find('time')>=0):
1747 overlayTimes = True
1748 if (bpoly == True):
1749 print("The overlay of times or antennas is not supported with BPOLY solutions")
1750 return()
1751 if (len(caltable2)>0):
1752 print("The overlay of times or antennas not supported when overlaying a B or BPOLY solution")
1753 return()
1754 casalogPost(debug,"Will overlay solutions from different times")
1755 else:
1756 overlayTimes = False
1758 if (overlay.find('spw')>=0):
1759 if (tableFormat < 34):
1760 print("Overlay spw may not work reliably for old cal tables")
1761 overlaySpws = True
1762 if (bpoly == True):
1763 print("The overlay of times, antennas, or spws is not supported with BPOLY solutions")
1764 return(vm)
1765 if (len(caltable2)>0):
1766 print("The overlay of times, antennas, or spws not supported when overlaying a B or BPOLY solution")
1767 return(vm)
1768 casalogPost(debug,"Will overlay solutions from different spws within a baseband")
1769 else:
1770 overlaySpws = False
1772 if (overlay.find('baseband')>=0):
1773 if (tableFormat < 34):
1774 print("Overlay baseband may not work reliably for old cal tables")
1775 overlayBasebands = True
1776 if (bpoly == True):
1777 print("The overlay of times, antennas, spws, or basebands is not supported with BPOLY solutions")
1778 return(vm)
1779 if (len(caltable2)>0):
1780 print("The overlay of times, antennas, spws, or basebands not supported when overlaying a B or BPOLY solution")
1781 return(vm)
1782 casalogPost(debug,"Will overlay solutions from all spws regardless of baseband")
1783 else:
1784 overlayBasebands = False
1786 if (bOverlay):
1787 # Now open the Bandpass solution table
1788 try:
1789 mytb.open(caltable2)
1790 except:
1791 print("Could not open the second caltable = %s" % (caltable2))
1792 return()
1793 names = mytb.colnames()
1794 ant2 = mytb.getcol('ANTENNA1')
1795 fields2 = mytb.getcol('FIELD_ID')
1796 times2 = mytb.getcol('TIME')
1797 if ('SPECTRAL_WINDOW_ID' not in names):
1798 if ('SNR' not in names):
1799 print("This does not appear to be a cal table.")
1800 return()
1801 else:
1802 tableFormat2 = 33
1803 casalogPost(debug,"This appears to be an old-format cal table from casa 3.3 or earlier.")
1804 cal_desc_id2 = mytb.getcol('CAL_DESC_ID')
1805 VisCal2 = (mytb.info())['subType']
1806 mytb.close()
1807 ParType = "unknown" # i.e. not Complex
1808 calDesc2 = mytb.open(caltable2+'/CAL_DESC')
1809 originalSpws2 = mytb.getcol('SPECTRAL_WINDOW_ID') # [[0,1,2,3]]
1810 originalSpw2 = originalSpws2[0] # [0,1,2,3]
1811 msName2 = mytb.getcol('MS_NAME')[0]
1812 mytb.close()
1813 # Now open the associated ms tables via ValueMapping to figure out channel freqs
1814 chanFreqGHz2 = []
1815 for ictr in range(len(originalSpw2)):
1816 if debug: print("ictr = %d" % (ictr))
1817 if debug: print("nspw = %d, np.max(originalSpw) = %d" % (getnspw(mymsmd),np.max(originalSpw2)))
1818 if (getnspw(mymsmd) < np.max(originalSpw2)):
1819 # Then there was an extra split
1820 i = ictr
1821 else:
1822 i = originalSpw2[ictr]
1823 nchan = mymsmd.nchan(i)
1824 if (nchan > 1):
1825 missingFrequencyWidth = originalChannelStart[ictr]*(mymsmd.chanfreqs(i)[-1]-mymsmd.chanfreqs(i)[0])/(nchan-1)
1826 else:
1827 missingFrequencyWidth = 0
1828 if (missingFrequencyWidth > 0):
1829 if (DEBUG):
1830 print("Correcting for channels flagged prior to running bandpass by %f GHz" % (missingFrequencyWidth*1e-9))
1831 newfreqs = 1e-9*(mymsmd.chanfreqs(i)) + missingFrequencyWidth*1e-9
1832 if debug: print("Appending onto chanFreqGHz2: %s" % (str(newfreqs)))
1833 chanFreqGHz2.append(newfreqs)
1834 else:
1835 tableFormat2 = 34
1836 cal_desc_id2 = mytb.getcol('SPECTRAL_WINDOW_ID')
1837 msName2 = mytb.getkeyword('MSName')
1838 ParType2 = mytb.getkeyword('ParType') # string = 'Complex'
1839 VisCal2 = mytb.getkeyword('VisCal') # string = 'B TSYS'
1840 PolBasis2 = mytb.getkeyword('PolBasis') # string = 'LINEAR'
1841 spectralWindowTable2 = mytb.getkeyword('SPECTRAL_WINDOW').split()[1]
1842 mytb.close()
1843 mytb.open(spectralWindowTable2)
1844 chanFreqGHz2 = []
1845 originalSpws2 = list(range(len(mytb.getcol('MEAS_FREQ_REF'))))
1846 for i in originalSpws2:
1847 # The array shapes can vary.
1848 chanFreqGHz2.append(1e-9 * mytb.getcell('CHAN_FREQ',i))
1849 originalSpws2 = list(range(len(mytb.getcol('MEAS_FREQ_REF'))))
1850 originalSpw2 = originalSpws2 # may want to do a global replace of this <----------------------------------
1852 uniqueSpwsInCalTable2 = np.unique(cal_desc_id2)
1853 mytb.open(caltable2)
1854 try:
1855 flags2 = {}
1856 for f in range(len(fields2)):
1857 flags2[f] = mytb.getcell('FLAG',f)
1858 except:
1859 print("bOverlay: No Flag column found. Are you sure this is a bandpass solution file, or is it the .ms?")
1860 print("If it is a solution file, does it contain solutions for both TDM and FDM spws?")
1861 return()
1862 uniqueTimes2 = sloppyUnique(np.unique(times2), solutionTimeThresholdSeconds)
1863 nUniqueTimes2 = len(uniqueTimes2)
1864# # print("Found %d solutions in time: MJD seconds = " % (nUniqueTimes2), uniqueTimes2)
1865 spacing = ''
1866 for i in range(1,nUniqueTimes2):
1867 spacing += '%.0f, ' % (np.abs(uniqueTimes2[i]-uniqueTimes2[i-1]))
1868 casalogPost(debug,"Found %d solutions in time, spaced by seconds: %s" % (nUniqueTimes2, str(spacing)))
1869 casalogPost(debug,displayTimesArray([[uniqueTimes2]]))
1870 uniqueAntennaIds2 = np.unique(ant2)
1871 uniqueFields2 = np.unique(fields2)
1872 nFields2 = len(uniqueFields2)
1874 casalogPost(debug,"(boverlay) original unique spws in the second dataset = %s" % (str(np.unique(originalSpw2))))
1876 uniqueTimesPerFieldPerSpw2 = []
1877 for s in uniqueSpwsInCalTable2:
1878 uniqueTimesPerField2 = []
1879 for f in uniqueFields2:
1880 timelist2 = []
1881 for row in range(len(fields2)):
1882 if (fields2[row] == f and cal_desc_id2[row] == s):
1883 if (sloppyMatch(times2[row], timelist2, solutionTimeThresholdSeconds) == False):
1884 timelist2.append(times2[row])
1885 uniqueTimesPerField2.append(timelist2)
1886 uniqueTimesPerFieldPerSpw2.append(uniqueTimesPerField2)
1887 casalogPost(debug,"uniqueTimesPerFieldPerSpw2 = %s" % (displayTimesArray(uniqueTimesPerFieldPerSpw2)))
1888 casalogPost(debug,"%d spw%s in the second solution = %s" % (len(uniqueSpwsInCalTable2), plural(uniqueSpwsInCalTable2), str(uniqueSpwsInCalTable2)))
1889 if (msFound):
1890 msFieldsList = str(np.array(msFields)[uniqueFields2])
1891 else:
1892 msFieldsList = 'unknown'
1893 casalogPost(debug,"%d field(s) in the solution = %s = %s" % (len(uniqueFields2), uniqueFields2, msFieldsList))
1895 # Parse the timeranges field from the command line
1896 if timeranges != '': # CAS-8439
1897 timerangesWasSpecified = True
1898 else:
1899 timerangesWasSpecified = False
1900 if (type(timeranges) == str):
1901 # a list of antenna numbers was given
1902 tokens = timeranges.split(',')
1903 timerangeList = []
1904 removeTime = []
1905 for token in tokens:
1906 if (len(token) > 0):
1907 if (token.find('!')==0):
1908 timerangeList = list(range(len(uniqueTimes)))
1909 removeTime.append(int(token[1:]))
1910 elif (token.find('~')>0):
1911 (start,finish) = token.split('~')
1912 timerangeList += list(range(int(start),int(finish)+1))
1913 else:
1914 timerangeList.append(int(token))
1915 timerangeList = np.array(timerangeList)
1916 for rt in removeTime:
1917 timerangeList = timerangeList[np.where(timerangeList != rt)[0]]
1918 timerangeList = list(timerangeList)
1919 if (len(timerangeList) < 1):
1920 if (len(removeTime) > 0):
1921 print("Too many negated timeranges -- there are none left to plot.")
1922 return
1923 else:
1924 # then a blank list was specified
1925 timerangeList = range(len(uniqueTimes))
1926 elif (type(timeranges) == list):
1927 # it's already a list of integers
1928 timerangeList = timeranges
1929 else:
1930 # It's a single, integer entry
1931 timerangeList = [timeranges]
1932 if (timerangesWasSpecified and scans != ''): # CAS-8489
1933 if (type(scans) == list or type(scans) == np.ndarray):
1934 myscan = int(scans[0])
1935 else:
1936 myscan = int(str(scans).split(',')[0])
1937 if (myscan not in scansForUniqueTimes):
1938 print(("No rows for scan %d, only " % (myscan), np.unique(scansForUniqueTimes)))
1939 return
1940 timerangeOffset = scansForUniqueTimes.index(myscan)
1941 timerangeList = np.array(timerangeList) + timerangeOffset
1942 if (debug): print(("Since both timeranges and scans was specified, generated new effective timerangeList: ", timerangeList))
1943 if (max(timerangeList) >= len(uniqueTimes)):
1944 print("Invalid timerange. Solution has %d times (%d~%d)" % (len(uniqueTimes),0,len(uniqueTimes)-1))
1945 return
1946 timerangeListTimes = np.array(uniqueTimes)[timerangeList]
1947 if debug:
1948 print("%d timerangeListTimes to be plotted" % (len(timerangeListTimes)))
1949 timerangeListTimesString = mjdsecArrayToUTString(timerangeListTimes)
1950 if (tableFormat == 33 or scansForUniqueTimes == []):
1951 # SMA data with scan numbers of -1 has empty list for scansForUniqueTimes
1952 scansToPlot = []
1953 if (scans != ''):
1954 print("Selection by scan is not possible for this dataset.")
1955 return
1956 else:
1957 if (debug): print("A)scansForUniqueTimes = %s" % (str(scansForUniqueTimes)))
1958 scansToPlot = np.array(scansForUniqueTimes)[timerangeList]
1959 if (np.unique(scansToPlot)[0] == -1):
1960 # scan numbers are not correct in this new-style cal table
1961 scansToPlot = []
1962 if (scans != ''):
1963 print("Selection by scan number is not possible with this dataset.")
1964 return
1965 if (scans != '' and scans != []):
1966 if (type(scans) == list):
1967 scansToPlot = scans
1968 elif (type(scans) == str):
1969 scansToPlot = [int(a) for a in scans.split(',')]
1970 else:
1971 scansToPlot = [scans]
1972 for scan in scansToPlot:
1973 if (scan not in scansForUniqueTimes):
1974 print("Scan %d is not in any solution" % (scan))
1975 return
1976 if debug: print("scans to plot: %s" % (str(scansToPlot)))
1977 scansToPlotPerSpw = {}
1978 casalogPost(debug,"originalSpwsToPlot: %s" % (originalSpwsToPlot))
1979# for myspw in np.unique(cal_desc_id): ### removed 2024Aug
1980 for myspw in originalSpwsToPlot: ### added 2024Aug
1981 scansToPlotPerSpw[myspw] = []
1982 if tableFormat == 34 and scansForUniqueTimes != []: ### added 2024Aug
1983 scansToPlotRevised = [] ### added 2024Aug
1984 timerangeListTimesRevised = [] ### added 2024Aug
1985 for scan in scansToPlot: ### indented 2024Aug
1986# for myspw in np.unique(cal_desc_id): ### removed 2024Aug
1987 for myspw in originalSpwsToPlot: ### added 2024Aug
1988 if (scan in cal_scans_per_spw[myspw]): ### indented 2024Aug
1989 scansToPlotPerSpw[myspw].append(scan) ### indented 2024Aug
1990 scansToPlotRevised.append(scan) #### added 2024Aug
1991 idx = np.where(cal_scans == scan) #### added 2024Aug
1992 timerangeListTimesRevised += list(np.unique(times[idx])) #### added 2024Aug
1993 scansToPlot = np.unique(scansToPlotRevised) #### added 2024Aug
1994# timerangeListTimes = np.unique(timerangeListTimesRevised) #### added 2024Aug
1995 timerangeListTimes = np.array(uniqueTimes)[timerangeList] #### added 2024Aug after the Aug22 benchmark
1996 casalogPost(debug, "%d timerangeListTimes (after filtering for spw) = %s" % (len(timerangeListTimes), timerangeListTimes)) #### add 2024Aug08
1997 casalogPost(debug, "scansToPlot (after filtering for spw) = %s" % (scansToPlot)) #### added 2024Aug
1999 # remove spws that do not have any scans to be plotted
2000 # but only for tables that have a scan number column, and not filled with all -1
2001 if (tableFormat > 33 and scansForUniqueTimes != []):
2002 for myspw in np.unique(cal_desc_id):
2003 if myspw in scansToPlotPerSpw: #### added 2024Aug
2004 if (scansToPlotPerSpw[myspw] == []): #### indented 2024Aug
2005 indexDelete = np.where(spwsToPlot==myspw)[0] #### indented 2024Aug
2006 if (len(indexDelete) > 0): #### indented 2024Aug
2007 spwsToPlot = np.delete(spwsToPlot, indexDelete[0]) #### indented 2024Aug
2008 elif (debug):
2009 print("scans to plot for spw %d: %s" % (myspw, scansToPlotPerSpw[myspw]))
2010 print("spws to plot (sorted) = ", sorted(spwsToPlot))
2011 casalogPost(debug,"scans to plot: %s" % (str(scansToPlot)))
2012 casalogPost(debug,"UT times to plot: %s" % (timerangeListTimesString))
2013 casalogPost(debug,"Corresponding time IDs (0-based): %s" % (str(timerangeList)))
2014 if (len(timerangeListTimes) > len(np.unique(scansToPlot))):
2015 # fix for CAS-9474
2016 uniqueScansToPlot, idx = np.unique(scansToPlot, return_index=True)
2017 if (len(uniqueScansToPlot) < len(scansToPlot)):
2018 # If the solution time for one spw differs by more than solutionTimeThresholdSeconds from
2019 # another spw, then we will get 2 identical entries for the same scan, and thus duplicate
2020 # plots. So, remove one.
2021 if debug: print("Engaging fix for CAS-9474")
2022 scansToPlot = uniqueScansToPlot
2023 timerangeListTimes = list(np.array(timerangeListTimes)[idx])
2024 timerangeList = list(np.array(timerangeList)[idx])
2025 timerangeListTimesString = mjdsecArrayToUTString(timerangeListTimes)
2026 casalogPost(debug,"Revised scans to plot: %s" % (str(scansToPlot)))
2027 casalogPost(debug,"Revised UT times to plot: %s" % (timerangeListTimesString))
2028 casalogPost(debug,"Corresponding time IDs (0-based): %s" % (str(timerangeList)))
2030 # Reassign overlay colors list if time overlays use a single color
2031 overlayColors = overlayColorsList
2032 if (overlayTimes and not overlayAntennas and len(timerangeList) > 1):
2033 timeOverlayColors = [overlayColors[idx] for idx in timerangeList]
2034 uniqueTimeColors = np.unique(timeOverlayColors)
2035 if (len(uniqueTimeColors) == 1):
2036 # Redo overlay colors list with shift
2037 if debug: print("Shifting overlay colors list to avoid repeats")
2038 shiftOverlayColors = overlayColorsSequence
2039 while len(shiftOverlayColors) <= timerangeList[-1]:
2040 shiftOverlayColors += shiftOverlayColors[1:]
2041 overlayColors = shiftOverlayColors
2043 # Check for mismatch
2044 if (bpolyOverlay):
2045 if (len(timerangeListTimes) > nUniqueTimesBP):
2046 print("There are more timeranges (%d) to plot from %s than exist in the caltable2=%s (%d)" % (len(timerangeListTimes), caltable,caltable2, nUniqueTimesBP))
2047 for i in timerangeList:
2048 if (sloppyMatch(timerangeListTimes[i],uniqueTimesBP[0],
2049 solutionTimeThresholdSeconds, mytime,
2050 scansToPlot, scansForUniqueTimes, myprint=False)):
2051 print("Try adding 'timeranges=%d'" % (i+1))
2052 return()
2053 if (bpolyOverlay2):
2054 if (len(timerangeListTimes) > nUniqueTimesBP2):
2055 print("There are more timeranges to plot (%d) from %s than exist in the caltable3=%s (%d)" % (len(timerangeListTimes), caltable, caltable3, nUniqueTimesBP2))
2056 return()
2058 # Parse the antenna string to emulate plotms
2059 if (type(antenna) == str):
2060 if (len(antenna) == sum([m in myValidCharacterListWithBang for m in antenna])):
2061 # a simple list of antenna numbers was given
2062 tokens = antenna.split(',')
2063 antlist = []
2064 removeAntenna = []
2065 for token in tokens:
2066 if (len(token) > 0):
2067 if (token.find('*')==0 and len(token)==1):
2068 antlist = uniqueAntennaIds
2069 break
2070 elif (token.find('!')==0):
2071 antlist = uniqueAntennaIds
2072 removeAntenna.append(int(token[1:]))
2073 elif (token.find('~')>0):
2074 (start,finish) = token.split('~')
2075 antlist += list(range(int(start),int(finish)+1))
2076 else:
2077 antlist.append(int(token))
2078 antlist = np.array(antlist)
2079 for rm in removeAntenna:
2080 antlist = antlist[np.where(antlist != rm)[0]]
2081 antlist = list(antlist)
2082 if (len(antlist) < 1 and len(removeAntenna)>0):
2083 print("Too many negated antennas -- there are no antennas left to plot.")
2084 return()
2085 else:
2086 # The antenna name (or list of names) was specified
2087 tokens = antenna.split(',')
2088 if (msFound):
2089 antlist = []
2090 removeAntenna = []
2091 for token in tokens:
2092# if (token in mymsmd.antennanames(range(mymsmd.nantennas()))):
2093 if (token in msAnt):
2094 antlist = list(antlist) # needed in case preceding antenna had ! modifier
2095# antlist.append(mymsmd.antennaids(token)[0])
2096 antlist.append(list(msAnt).index(token))
2097 elif (token[0] == '!'):
2098# if (token[1:] in mymsmd.antennanames(range(mymsmd.nantennas()))):
2099 if (token[1:] in msAnt):
2100 antlist = uniqueAntennaIds # range(mymsmd.nantennas())
2101# removeAntenna.append(mymsmd.antennaids(token[1:])[0])
2102 removeAntenna.append(list(msAnt).index(token[1:]))
2103 else:
2104 print("Antenna %s is not in the ms. It contains: " % (token), mymsmd.antennanames(list(range(mymsmd.nantennas()))))
2105 return()
2106 else:
2107 print("Antenna %s is not in the ms. It contains: " % (token), mymsmd.antennanames(list(range(mymsmd.nantennas()))))
2108 return()
2109 antlist = np.array(antlist)
2110 for rm in removeAntenna:
2111 antlist = antlist[np.where(antlist != rm)[0]]
2112 antlist = list(antlist)
2113 if (len(antlist) < 1 and len(removeAntenna)>0):
2114 print("Too many negated antennas -- there are no antennas left to plot.")
2115 return()
2116 else:
2117 print("Antennas cannot be specified my name if the ms is not found.")
2118 return()
2119 elif (type(antenna) == list):
2120 # it's a list of integers
2121 antlist = antenna
2122 else:
2123 # It's a single, integer entry
2124 antlist = [antenna]
2125 casalogPost(debug,"antlist = %s" % (str(antlist)))
2126 if (len(antlist) > 0):
2127 antennasToPlot = np.intersect1d(uniqueAntennaIds,antlist)
2128 else:
2129 antennasToPlot = uniqueAntennaIds
2130 casalogPost(debug,"antennasToPlot = %s" % (str(antennasToPlot)))
2132 # Parse the field string to emulate plotms
2133 removeField = []
2134 if (type(field) == str):
2135 if (len(field) == sum([m in myValidCharacterListWithBang for m in field])):
2136 casalogPost(debug,"a list of field numbers was given")
2137 # a list of field numbers was given
2138 tokens = field.split(',')
2139 fieldlist = []
2140 for token in tokens:
2141 if (token.find('*')>=0):
2142 fieldlist = uniqueFields
2143 break
2144 elif (token.find('!')==0):
2145 fieldlist = uniqueFields
2146 removeField.append(int(token[1:]))
2147 elif (len(token) > 0):
2148 if (token.find('~')>0):
2149 (start,finish) = token.split('~')
2150 fieldlist += list(range(int(start),int(finish)+1))
2151 else:
2152 fieldlist.append(int(token))
2153 fieldlist = np.array(fieldlist)
2154 for rm in removeField:
2155 fieldlist = fieldlist[np.where(fieldlist != rm)[0]]
2156 fieldlist = list(fieldlist)
2157 if (len(fieldlist) < 1 and len(removeField)>0):
2158 print("Too many negated fields -- there are no fields left to plot.")
2159 return()
2160 else:
2161 casalogPost(debug,"The field name, or list of names was given")
2162 # The field name (or list of names, or wildcard) was specified
2163 tokens = field.split(',')
2164 if (msFound):
2165 fieldlist = []
2166 removeField = []
2167 for token in tokens:
2168 myloc = token.find('*')
2169 casalogPost(debug,"token=%s, myloc=%d" % (token,myloc))
2170 if (myloc > 0):
2171 casalogPost(debug,"Saw wildcard in the name")
2172 for u in uniqueFields:
2173 myFieldName = GetFieldNamesForFieldId(u, mymsmd, msFields)
2174 if (token[0:myloc]==myFieldName[0:myloc]):
2175 if (DEBUG):
2176 print("Found wildcard match = %s" % mymsmd.namesforfields(u))
2177 fieldlist.append(u)
2178 else:
2179 if (DEBUG):
2180 print("No wildcard match with = %s" % mymsmd.namesforfields(u))
2181 elif (myloc==0):
2182 casalogPost(debug,"Saw wildcard at start of name")
2183 for u in uniqueFields:
2184 fieldlist.append(u)
2185 elif (token in msFields):
2186 fieldlist = list(fieldlist) # needed in case preceding field had ! modifier
2187 fieldlist.append(GetFieldIdsForFieldName(token, mymsmd, msFields))
2188 elif (token[0] == '!'):
2189 if (fieldlist == []):
2190 for u in uniqueFields:
2191 fieldlist.append(u)
2192 if (token[1:] in msFields):
2193 removeField.append(GetFieldIdsForFieldName(token[1:], mymsmd, msFields))
2194 else:
2195 print("Field %s is not in the ms. It contains: %s, %s" % (token, str(uniqueFields), str(np.unique(msFields))))
2196 return()
2197 else:
2198 casalogPost(debug,"Field not in ms")
2199 fieldlist = []
2200 for f in mymsmd.namesforfields():
2201 fieldlist.append(mymsmd.fieldsforname(f))
2202 print("Field %s is not in the ms. It contains: %s, %s" % (token, str(uniqueFields), str(np.unique(msFields))))
2203 return()
2204 fieldlist = np.array(fieldlist)
2205 for rm in removeField:
2206 fieldlist = fieldlist[np.where(fieldlist != rm)[0]]
2207 fieldlist = list(fieldlist)
2208 if (len(fieldlist) < 1 and len(removeField)>0):
2209 print("Too many negated fields -- there are no fields left to plot.")
2210 return()
2211 else:
2212 print("Fields cannot be specified my name if the ms is not found.")
2213 return()
2214 elif (type(field) == list):
2215 # it's a list of integers
2216 fieldlist = field
2217 else:
2218 # It's a single, integer entry
2219 fieldlist = [field]
2221 casalogPost(debug,"fieldlist = %s" % (str(fieldlist)))
2223 if (len(fieldlist) > 0):
2224 if (DEBUG):
2225 print("Finding intersection of %s with %s" % (str(uniqueFields), str(fieldlist)))
2226 fieldsToPlot = np.intersect1d(uniqueFields,np.array(fieldlist))
2227 if (bOverlay):
2228 fieldsToPlot = np.intersect1d(np.union1d(uniqueFields,uniqueFields2),np.array(fieldlist))
2229 if (len(fieldsToPlot) < 1):
2230 print("Requested field not found in solution")
2231 return()
2232 else:
2233 fieldsToPlot = uniqueFields # use all fields if none are specified
2234 if (bOverlay):
2235 fieldsToPlot = np.union1d(uniqueFields,uniqueFields2)
2236 if (DEBUG):
2237 print("bOverlay = %s" % (bOverlay))
2238 print("set fieldsToPlot to uniqueFields = %s" % (str(fieldsToPlot)))
2239 fieldIndicesToPlot = []
2240 casalogPost(debug,"fieldsToPlot = %s" % (str(fieldsToPlot)))
2242 if (showatmfield == ''):
2243 showatmfield = fieldsToPlot[0]
2244 else:
2245 if (str.isdigit(str(showatmfield))):
2246 showatmfield = int(str(showatmfield))
2247 if (showatmfield not in fieldsToPlot):
2248 print("The showatmfield (%d) is not in the list of fields to plot: %s" % (showatmfield, str(fieldsToPlot)))
2249 return()
2250 else:
2251 showatmfieldName = showatmfield
2252 showatmfield = mymsmd.fieldsforname(showatmfield)
2253 if (list(showatmfield) == []):
2254 print("The showatmfield (%s) is not in the ms." %(showatmfieldName))
2255 return()
2256 if (type(showatmfield) == type(np.ndarray(0))):
2257 # more than one field IDs exist for this source name, so pick the first
2258 showatmfield = showatmfield[0]
2259 if (showatmfield not in fieldsToPlot):
2260 print("The showatmfield (%d=%s) is not in the list of fields to plot: %s" % (showatmfield, showatmfieldName, str(fieldsToPlot)))
2261 return()
2263 for i in fieldsToPlot:
2264 match = np.where(i==uniqueFields)[0]
2265 if (len(match) < 1 and bOverlay):
2266 match = np.where(i==uniqueFields2)[0]
2267 fieldIndicesToPlot.append(match[0])
2269 casalogPost(debug,"spws to plot (sorted) = %s" % (str(sorted(spwsToPlot))))
2270 casalogPost(debug,"Field IDs to plot: %s" % (str(fieldsToPlot)))
2272 redisplay = False
2273 myap = 0 # this variable is necessary to make the 'b' option work for
2274 # subplot=11, yaxis=both. It keeps track of whether 'amp' or
2275 # 'phase' was the first plot on the page.
2277 # I added pb.ion() because Remy suggested it.
2278 if (interactive):
2279 pb.ion() # This will open a new window if not present.
2280 else:
2281 pb.ioff() # This will not destroy an existing window or prevent new plots from appearing there.
2282# # The call to pb.figure() causes an additional new window everytime.
2283# # pb.figure()
2285 newylimits = [LARGE_POSITIVE, LARGE_NEGATIVE]
2287 safe_pb_clf() # pb.clf()
2288 if (bpoly):
2289 # The number of polarizations cannot be reliably inferred from the shape of
2290 # the GAIN column in the caltable. Must use the shape of the DATA column
2291 # in the ms.
2292 if (debug): print("in bpoly")
2293 if (msFound):
2294 (corr_type, corr_type_string, nPolarizations) = getCorrType(msName, spwsToPlot, mymsmd, debug)
2295 casalogPost(debug,"nPolarizations in first spw to plot = %s" % (str(nPolarizations)))
2296 else:
2297 print("With no ms available, I will assume ALMA data: XX, YY, and refFreq=first channel.")
2298 chanFreqGHz = []
2299 corr_type_string = ['XX','YY']
2300 corr_type = [9,12]
2301 nPolarizations = 2
2302 nPolarizations2 = nPolarizations
2303 if (corr_type_string == []):
2304 return()
2305 polsToPlot = checkPolsToPlot(polsToPlot, corr_type_string, debug)
2306 if (polsToPlot == []):
2307 return()
2308 # Here we are only plotting one BPOLY solution, no overlays implemented.
2309 overlayAntennas = False
2310 # rows in the table are: antennas 0..nAnt for first spw, antennas 0..nAnt
2311 # for 2nd spw...
2312 pagectr = 0
2313 if debug:
2314 print("Setting pages to blank list")
2315 pages = []
2316 xctr = 0
2317 newpage = 1
2318 while (xctr < len(antennasToPlot)):
2319 xant = antennasToPlot[xctr]
2320 antstring, Antstring = buildAntString(xant,msFound,msAnt)
2321 spwctr = 0
2322 spwctrFirstToPlot = spwctr
2323 while (spwctr < len(spwsToPlot)):
2324 ispw = spwsToPlot[spwctr]
2325 mytime = 0
2326 while (mytime < nUniqueTimes):
2327 if (len(uniqueTimes) > 0 and (mytime not in timerangeList)):
2328 if (debug):
2329 print("@@@@@@@@@@@@@@@ Skipping mytime=%d" % (mytime))
2330 mytime += 1
2331 continue
2332 if (newpage == 1):
2333 pages.append([xctr,spwctr,mytime,0])
2334 if debug:
2335 print("top: appending [%d,%d,%d,%d]" % (xctr,spwctr,mytime,0))
2336 newpage = 0
2337 antennaString = 'Ant%2d: %s, ' % (xant,antstring)
2338 for index in range(nRows):
2339 # Find this antenna, spw, and timerange combination in the table
2340 if tableFormat >= 34: ### added 2024Aug
2341 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
2342 else: ### added 2024Aug
2343 scansToPlotHere = scansToPlot ### added 2024Aug
2344 if (xant==ant[index] and sloppyMatch(uniqueTimes[mytime],times[index],solutionTimeThresholdSeconds,
2345 mytime, scansToPlotHere, scansForUniqueTimes, ### modified 2024Aug
2346 myprint=debugSloppyMatch) and
2347 (ispw == cal_desc_id[index]) and (fields[index] in fieldsToPlot)):
2348 fieldIndex = np.where(fields[index] == uniqueFields)[0]
2349 if (type(fieldIndex) == list or type(fieldIndex) == np.ndarray):
2350 fieldIndex = fieldIndex[0]
2351 validDomain = [frequencyLimits[0,index], frequencyLimits[1,index]]
2352 if (msFound):
2353 fieldString = msFields[uniqueFields[fieldIndex]]
2354 else:
2355 fieldString = str(field)
2356 timeString = ', t%d/%d %s' % (mytime,nUniqueTimes-1,utstring(uniqueTimes[mytime],3))
2357 if (scansForUniqueTimes != []):
2358 if (scansForUniqueTimes[mytime]>=0):
2359 timeString = ', scan%d %s' % (scansForUniqueTimes[mytime],utstring(uniqueTimes[mytime],3))
2360 if ((yaxis.find('amp')>=0 or amplitudeWithPhase) and myap==0):
2361 xframe += 1
2362 myUniqueColor = []
2363 if (debug):
2364 print("v) incrementing xframe to %d" % xframe)
2365 adesc = safe_pb_subplot(xframe)
2366 previousSubplot = xframe
2367 if (ispw==originalSpw[ispw]):
2368 # all this was added mistakenly here. If it causes a bug, remove it.
2369 if (overlayTimes and len(fieldsToPlot) > 1):
2370 indices = fstring = ''
2371 for f in fieldIndicesToPlot:
2372 if (f != fieldIndicesToPlot[0]):
2373 indices += ','
2374 fstring += ','
2375 indices += str(uniqueFields[f])
2376 if (msFound):
2377 fstring += msFields[uniqueFields[f]]
2378 if (len(fstring) > fstringLimit):
2379 fstring = fstring[0:fstringLimit] + '...'
2380 pb.title("%sspw%2d, fields %s: %s%s" % (antennaString,ispw,
2381 indices, fstring, timeString), size=titlesize)
2382 else:
2383 pb.title("%sspw%2d, field %d: %s%s" % (antennaString,ispw,
2384 uniqueFields[fieldIndex],fieldString,timeString), size=titlesize)
2385 else:
2386 if (overlayTimes and len(fieldsToPlot) > 1):
2387 indices = fstring = ''
2388 for f in fieldIndicesToPlot:
2389 if (f != fieldIndicesToPlot[0]):
2390 indices += ','
2391 fstring += ','
2392 indices += str(uniqueFields[f])
2393 if (msFound):
2394 fstring += msFields[uniqueFields[f]]
2395 if (len(fstring) > fstringLimit):
2396 fstring = fstring[0:fstringLimit] + '...'
2397 pb.title("%sspw%2d (%d), fields %s: %s%s" % (antennaString,ispw,originalSpw[ispw],
2398 indices, fstring, timeString), size=titlesize)
2399 else:
2400 pb.title("%sspw%2d (%d), field %d: %s%s" % (antennaString,ispw,originalSpw[ispw],
2401 uniqueFields[fieldIndex],fieldString,timeString), size=titlesize)
2402 amplitudeSolutionX = np.real(scaleFactor[index])+calcChebyshev(polynomialAmplitude[index][0:nPolyAmp[index]], validDomain, frequenciesGHz[index]*1e+9)
2403 amplitudeSolutionY = np.real(scaleFactor[index])+calcChebyshev(polynomialAmplitude[index][nPolyAmp[index]:2*nPolyAmp[index]], validDomain, frequenciesGHz[index]*1e+9)
2404 amplitudeSolutionX += 1 - np.mean(amplitudeSolutionX)
2405 amplitudeSolutionY += 1 - np.mean(amplitudeSolutionY)
2406 if (yaxis.lower().find('db') >= 0):
2407 amplitudeSolutionX = 10*np.log10(amplitudeSolutionX)
2408 amplitudeSolutionY = 10*np.log10(amplitudeSolutionY)
2409 if (nPolarizations == 1):
2410 pb.plot(frequenciesGHz[index], amplitudeSolutionX, '%s%s'%(xcolor,bpolymarkstyle),markeredgewidth=markeredgewidth)
2411 else:
2412 pb.plot(frequenciesGHz[index], amplitudeSolutionX, '%s%s'%(xcolor,bpolymarkstyle), frequenciesGHz[index], amplitudeSolutionY, '%s%s'%(ycolor,bpolymarkstyle),markeredgewidth=markeredgewidth)
2413 if (plotrange[0] != 0 or plotrange[1] != 0):
2414 SetNewXLimits([plotrange[0],plotrange[1]])
2415 if (plotrange[2] != 0 or plotrange[3] != 0):
2416 SetNewYLimits([plotrange[2],plotrange[3]])
2417 xlim=pb.xlim()
2418 ylim=pb.ylim()
2419 ResizeFontsSetGrid(adesc,mysize)
2420 if (yaxis.lower().find('db')>=0):
2421 pb.ylabel('Amplitude (dB)', size=mysize)
2422 else:
2423 pb.ylabel('Amplitude', size=mysize)
2424# pb.xlabel('Frequency (GHz)', size=mysize)
2425 pb.xlabel('Frequency (GHz) (%d channels)'%(len(frequenciesGHz[index])), size=mysize) # 2024Aug
2426 if (xframe == firstFrame):
2427 DrawBottomLegendPageCoords(msName, uniqueTimes[mytime], mysize, figfile)
2428 pb.text(xstartTitle, ystartTitle,
2429 '%s (degamp=%d, degphase=%d)'%(caltableTitle,nPolyAmp[index]-1,
2430 nPolyPhase[index]-1),size=mysize,
2431 transform=pb.gcf().transFigure)
2432 # draw polarization labels
2433 x0 = xstartPolLabel
2434 y0 = ystartPolLabel
2435 for p in range(nPolarizations):
2436 if (corrTypeToString(corr_type[p]) in polsToPlot):
2437 pb.text(x0, y0-0.03*subplotRows*p, corrTypeToString(corr_type[p])+'',
2438 color=pcolor[p],size=mysize, transform=pb.gca().transAxes)
2439 if (xframe == 111 and amplitudeWithPhase):
2440 if (len(figfile) > 0):
2441 # We need to make a new figure page
2442 plotfiles.append(makeplot(figfile,msFound,msAnt,
2443 overlayAntennas,pages,pagectr,
2444 density,interactive,antennasToPlot,
2445 spwsToPlot,overlayTimes,overlayBasebands,
2446 0,xant,ispw,subplot,resample,
2447 debug,figfileSequential,figfileNumber))
2448 figfileNumber += 1
2449 donetime = time.time()
2450 if (interactive):
2451 pb.draw()
2452# # myinput = raw_input("(%.1f sec) Press return for next page (b for backwards, q to quit): "%(donetime-mytimestamp))
2453 myinput = input("Press return for next page (b for backwards, q to quit): ")
2454 else:
2455 myinput = ''
2456 skippingSpwMessageSent = 0
2457 mytimestamp = time.time()
2458 if (myinput.find('q') >= 0):
2459 showFinalMessage(overlayAntennas, solutionTimeSpread, nUniqueTimes)
2460 return()
2461 if (myinput.find('b') >= 0):
2462 if (pagectr > 0):
2463 pagectr -= 1
2464 #redisplay the current page by setting ctrs back to the value they had at start of that page
2465 xctr = pages[pagectr][PAGE_ANT]
2466 spwctr = pages[pagectr][PAGE_SPW]
2467 mytime = pages[pagectr][PAGE_TIME]
2468 myap = pages[pagectr][PAGE_AP]
2469 xant = antennasToPlot[xctr]
2470 antstring, Antstring = buildAntString(xant,msFound,msAnt)
2471 ispw = spwsToPlot[spwctr]
2472 redisplay = True
2473 else:
2474 pagectr += 1
2475 if (pagectr >= len(pages)):
2476 pages.append([xctr,spwctr,mytime,1])
2477 print("appending [%d,%d,%d,%d]" % (xctr,spwctr,mytime,1))
2478 newpage = 0
2479 safe_pb_clf()
2481 if (yaxis.find('phase')>=0 or amplitudeWithPhase):
2482 xframe += 1
2483 myUniqueColor = []
2484# # print("w) incrementing xframe to %d" % xframe)
2485 adesc = safe_pb_subplot(xframe)
2486 previousSubplot = xframe
2487 if (ispw==originalSpw[ispw]):
2488 pb.title("%sspw%2d, field %d: %s%s" % (antennaString,ispw,
2489 uniqueFields[fieldIndex],fieldString,timeString), size=titlesize)
2490 else:
2491 pb.title("%sspw%2d (%d), field %d: %s%s" % (antennaString,ispw,originalSpw[ispw],
2492 uniqueFields[fieldIndex],fieldString,timeString), size=titlesize)
2493 phaseSolutionX = calcChebyshev(polynomialPhase[index][0:nPolyPhase[index]], validDomain, frequenciesGHz[index]*1e+9) * 180/math.pi
2494 phaseSolutionY = calcChebyshev(polynomialPhase[index][nPolyPhase[index]:2*nPolyPhase[index]], validDomain, frequenciesGHz[index]*1e+9) * 180/math.pi
2495 if (nPolarizations == 1):
2496 pb.plot(frequenciesGHz[index], phaseSolutionX, '%s%s'%(xcolor,bpolymarkstyle),markeredgewidth=markeredgewidth)
2497 else:
2498 pb.plot(frequenciesGHz[index], phaseSolutionX, '%s%s'%(xcolor,bpolymarkstyle), frequenciesGHz[index], phaseSolutionY, '%s%s'%(ycolor,bpolymarkstyle),markeredgewidth=markeredgewidth)
2499 ResizeFontsSetGrid(adesc,mysize)
2500 pb.ylabel('Phase (deg)', size=mysize)
2501# pb.xlabel('Frequency (GHz)', size=mysize)
2502 pb.xlabel('Frequency (GHz) (%d channels)'%(len(frequenciesGHz[index])), size=mysize) ### 2024Aug
2503 if (plotrange[0] != 0 or plotrange[1] != 0):
2504 SetNewXLimits([plotrange[0],plotrange[1]])
2505 if (plotrange[2] != 0 or plotrange[3] != 0):
2506 SetNewYLimits([plotrange[2],plotrange[3]])
2507 if (amplitudeWithPhase and phase != ''):
2508 if (phase[0] != 0 or phase[1] != 0):
2509 SetNewYLimits(phase)
2510 if (xframe == firstFrame):
2511 pb.text(xstartTitle, ystartTitle,
2512 '%s (degamp=%d, degphase=%d)'%(caltable,
2513 nPolyAmp[index]-1,nPolyPhase[index]-1),
2514 size=mysize, transform=pb.gcf().transFigure)
2515 # draw polarization labels
2516 x0 = xstartPolLabel
2517 y0 = ystartPolLabel
2518 for p in range(nPolarizations):
2519 if (corrTypeToString(corr_type[p]) in polsToPlot):
2520 pb.text(x0, y0-0.03*p*subplotRows, corrTypeToString(corr_type[p])+'',
2521 color=pcolor[p],size=mysize, transform=pb.gca().transAxes)
2523 # end of 'for' loop over rows
2524 redisplay = False
2525 pb.subplots_adjust(hspace=myhspace, wspace=mywspace)
2526 if (xframe == lastFrame):
2527 if (len(figfile) > 0):
2528 plotfiles.append(makeplot(figfile,msFound,msAnt,
2529 overlayAntennas,pages,pagectr,
2530 density,interactive,antennasToPlot,
2531 spwsToPlot,overlayTimes,overlayBasebands,
2532 1,xant,ispw,
2533 subplot,resample,debug,
2534 figfileSequential,figfileNumber))
2535 figfileNumber += 1
2536 donetime = time.time()
2537 if (interactive):
2538 pb.draw()
2539# # myinput = raw_input("(%.1f sec) Press return for next page (b for backwards, q to quit): "%(donetime-mytimestamp))
2540 myinput = input("Press return for next page (b for backwards, q to quit): ")
2541 else:
2542 myinput = ''
2543 skippingSpwMessageSent = 0
2544 mytimestamp = time.time()
2545 if (myinput.find('q') >= 0):
2546 return()
2547 if (myinput.find('b') >= 0):
2548 if (pagectr > 0):
2549 pagectr -= 1
2550 #redisplay the current page by setting ctrs back to the value they had at start of that page
2551 xctr = pages[pagectr][PAGE_ANT]
2552 spwctr = pages[pagectr][PAGE_SPW]
2553 mytime = pages[pagectr][PAGE_TIME]
2554 myap = pages[pagectr][PAGE_AP]
2555 xant = antennasToPlot[xctr]
2556 antstring, Antstring = buildAntString(xant,msFound,msAnt)
2557 ispw = spwsToPlot[spwctr]
2558 redisplay = True
2559 else:
2560 pagectr += 1
2561 if (pagectr >= len(pages)):
2562 newpage = 1
2563 else:
2564 newpage = 0
2565 if (debug):
2566 print("1)Setting xframe to %d" % xframeStart)
2567 xframe = xframeStart
2568 if (xctr+1 < len(antennasToPlot)):
2569 # don't clear the final plot when finished
2570 safe_pb_clf()
2571 if (spwctr+1<len(spwsToPlot) or mytime+1<nUniqueTimes):
2572 # don't clear the final plot when finished
2573 safe_pb_clf()
2574 pb.subplots_adjust(hspace=myhspace, wspace=mywspace)
2575 if (redisplay == False):
2576 mytime += 1
2577 if (debug):
2578 print("Incrementing mytime to %d" % (mytime))
2579 # end while(mytime)
2580 if (redisplay == False):
2581 spwctr +=1
2582 if (debug):
2583 print("Incrementing spwctr to %d" % (spwctr))
2584 # end while(spwctr)
2585 if (redisplay == False):
2586 xctr += 1
2587 # end while(xctr) for BPOLY
2588 if (len(figfile) > 0 and pagectr<len(pages)):
2589 plotfiles.append(makeplot(figfile,msFound,msAnt,overlayAntennas,pages,
2590 pagectr,density,interactive,antennasToPlot,
2591 spwsToPlot,overlayTimes,overlayBasebands,
2592 2,xant,ispw,subplot,resample,debug,
2593 figfileSequential,figfileNumber))
2594 figfileNumber += 1
2595 if (len(plotfiles) > 0 and buildpdf):
2596 pdfname = figfile+'.pdf'
2597 filelist = ''
2598 plotfiles = np.unique(plotfiles)
2599 for i in range(len(plotfiles)):
2600 cmd = '%s -density %d %s %s.pdf' % (convert,density,plotfiles[i],plotfiles[i].split('.png')[0])
2601 casalogPost(debug,"Running command = %s" % (cmd))
2602 mystatus = os.system(cmd)
2603 if (mystatus != 0):
2604 break
2605 filelist += plotfiles[i].split('.png')[0] + '.pdf '
2606 if (mystatus != 0):
2607 print("ImageMagick is missing, no PDF created")
2608 buildpdf = False
2609 if (buildpdf):
2610 cmd = '%s %s cat output %s' % (pdftk, filelist, pdfname)
2611 casalogPost(debug,"Running command = %s" % (cmd))
2612 mystatus = os.system(cmd)
2613 if (mystatus != 0):
2614 cmd = '%s -q -sPAPERSIZE=letter -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=%s %s' % (gs,pdfname,filelist)
2615 casalogPost(debug,"Running command = %s" % (cmd))
2616 mystatus = os.system(cmd)
2617 if (mystatus == 0):
2618 print("PDF left in %s" % (pdfname))
2619 os.system("rm -f %s" % filelist)
2620 else:
2621 print("Both pdftk and ghostscript are missing, no PDF created")
2622 return()
2624####################################################################################
2625# # bpoly == false,
2626#################
2627 msFound = False
2628 mytb.open(caltable)
2629 uniqueScanNumbers = sorted(np.unique(mytb.getcol('SCAN_NUMBER')))
2630 if (ParType == 'Complex'): # casa >= 3.4
2631 gain = {}
2632 for f in range(len(fields)):
2633 gain[f] = mytb.getcell('CPARAM',f)
2634 else: # casa 3.3
2635 gain = {}
2636# # gain = mytb.getcol('FPARAM') # 2,128,576
2637 if ('FPARAM' in mytb.colnames()):
2638 for f in range(len(fields)):
2639 gain[f] = mytb.getcell('FPARAM',f)
2640 else:
2641 for f in range(len(fields)):
2642 gain[f] = mytb.getcell('GAIN',f)
2643 nPolarizations = len(gain[0])
2644 if (debug):
2645 print("(1)Set nPolarizations = %d" % nPolarizations)
2646 ggx = {}
2647 for g in range(len(gain)):
2648 ggx[g] = gain[g][0]
2649 if (nPolarizations == 2):
2650 ggy = {}
2651 for g in range(len(gain)):
2652 ggy[g] = gain[g][1]
2653 mytb.close()
2655 if (debug):
2656 print("nPolarizations = %s" % (str(nPolarizations)))
2657 nRows = len(gain)
2658 if (bOverlay):
2659 mytb.open(caltable2)
2660 gain2 = {}
2661 if (ParType == 'Complex'):
2662# # gain2 = mytb.getcol('CPARAM')
2663 for f in range(len(fields2)):
2664 gain2[f] = mytb.getcell('CPARAM',f)
2665 else:
2666# # gain2 = mytb.getcol('FPARAM')
2667 for f in range(len(fields2)):
2668 if (tableFormat2 == 34):
2669 gain2[f] = mytb.getcell('FPARAM',f)
2670 else:
2671 gain2[f] = mytb.getcell('GAIN',f)
2672 mytb.close()
2673 ggx2 = {}
2674 for g in range(len(gain2)):
2675# # print("Appending to ggx: ", gain2[g][0])
2676 ggx2[g] = gain2[g][0]
2677 nPolarizations2 = len(gain2[0])
2678 if (nPolarizations == 2):
2679 ggy2 = {}
2680 for g in range(len(gain2)):
2681 ggy2[g] = gain2[g][1]
2682 nRows2 = len(gain2)
2683 if (debug): print("nRows2 = %s" % (str(nRows2)))
2685 if (tableFormat == 34):
2686 # CAS-6801, unfortunately corr_type is not available in the caltable
2687 mytb.open(caltable)
2688 spectralWindowTable = mytb.getkeyword('SPECTRAL_WINDOW').split()[1]
2689 if ('OBSERVATION' in mytb.getkeywords()):
2690 observationTable = mytb.getkeyword('OBSERVATION').split()[1]
2691 else:
2692 observationTable = None
2693 mytb.open(spectralWindowTable)
2694 refFreq = mytb.getcol('REF_FREQUENCY')
2695 net_sideband = mytb.getcol('NET_SIDEBAND')
2696 measFreqRef = mytb.getcol('MEAS_FREQ_REF')
2697 mytb.close()
2698 corr_type = None
2699 if (os.path.exists(msName)):
2700 try:
2701 (corr_type, corr_type_string, nPolarizations) = getCorrType(msName,originalSpwsToPlot,mymsmd,debug)
2702 except:
2703 print("4) Could not getCorrType")
2704 if (corr_type is None):
2705 if (observationTable is None):
2706 corr_type, corr_type_string, nPolarizations = getCorrTypeByAntennaName(msAnt[0].lower())
2707 else:
2708 telescope = getTelescopeNameFromCaltableObservationTable(observationTable)
2709 if (telescope.find('ALMA') >= 0):
2710 print("Using telescope name (%s) to set the polarization type." % (telescope))
2711 corr_type_string = ['XX','YY']
2712 corr_type = [9,12]
2713 elif (telescope.find('VLA') >= 0):
2714 print("Using telescope name (%s) to set the polarization type." % (telescope))
2715 corr_type_string = ['RR','LL']
2716 corr_type = [5,8]
2717 else:
2718 corr_type, corr_type_string, noPolarizations = getCorrTypeByAntennaName(msAnt[0].lower())
2719 else:
2720 try:
2721 if (DEBUG):
2722 print("Trying to open %s" % (msName+'/SPECTRAL_WINDOW'))
2723 mytb.open(msName+'/SPECTRAL_WINDOW')
2724 refFreq = mytb.getcol('REF_FREQUENCY')
2725 net_sideband = mytb.getcol('NET_SIDEBAND')
2726 measFreqRef = mytb.getcol('MEAS_FREQ_REF')
2727 mytb.close()
2729# (corr_type, corr_type_string, nPolarizations) = getCorrType(msName, spwsToPlot, mymsmd, debug)
2730 (corr_type, corr_type_string, nPolarizations) = getCorrType(msName, originalSpwsToPlot, mymsmd, debug)
2731 if (corr_type_string == []):
2732 return()
2733 except:
2734 print("4) Could not open the associated measurement set tables (%s). Will not translate antenna names." % (msName))
2735 mymsmd = ''
2736 print("I will assume ALMA data: XX, YY, and refFreq=first channel.")
2737# chanFreqGHz = [] # comment out on 2014-04-08
2738 corr_type_string = ['XX','YY']
2739 corr_type = [9,12]
2741 if (len(polsToPlot) > len(corr_type)):
2742 # Necessary for SMA (single-pol) data
2743 polsToPlot = corr_type_string
2744 casalogPost(debug,"Polarizations to plot = %s" % (str(polsToPlot)))
2745 polsToPlot = checkPolsToPlot(polsToPlot, corr_type_string, debug)
2746 if (polsToPlot == []):
2747 return()
2749 if (len(msAnt) > 0):
2750 msFound = True
2751 else:
2752 if (xaxis.find('freq')>=0 and tableFormat==33):
2753 print("Because I could not open the .ms, you cannot use xaxis='freq'.")
2754 return()
2755 if (showatm == True or showtsky==True):
2756 print("Because I could not open the .ms, you cannot use showatm or showtsky.")
2757 return()
2759 if (bpoly == False):
2760 if (debug):
2761 print("nPolarizations = %s" % (nPolarizations))
2762 print("nFields = %d = %s" % (nFields, str(uniqueFields)))
2764 if (bOverlay and debug):
2765 print("nPolarizations2 = %s" % (str(nPolarizations2)))
2766 print("nFields2 = %d = %s" % (nFields2, str(uniqueFields2)))
2767 print("nRows2 = %s" % (str(nRows2)))
2768 uniqueAntennaIds = np.sort(np.unique(ant))
2770 yPhaseLabel = 'Phase (deg)'
2771 tsysPercent = True
2772 ampPercent = True
2773 if (VisCal.lower().find('tsys') >= 0):
2774 if (channeldiff > 0):
2775 if (tsysPercent):
2776 yAmplitudeLabel = "Tsys derivative (%_of_median/channel)"
2777 else:
2778 yAmplitudeLabel = "Tsys derivative (K/channel)"
2779 else:
2780 yAmplitudeLabel = "Tsys (K)"
2781 else:
2782 if (yaxis.lower().find('db')>=0):
2783 yAmplitudeLabel = "Amplitude (dB)"
2784 else:
2785 if (channeldiff > 0):
2786 if (ampPercent):
2787 yAmplitudeLabel = "Amp derivative (%_of_median/channel)"
2788 else:
2789 yAmplitudeLabel = "Amplitude derivative"
2790 yPhaseLabel = 'Phase derivative (deg/channel)'
2791 else:
2792 yAmplitudeLabel = "Amplitude"
2794 madsigma = channeldiff # for option channeldiff>0, sets threshold for finding outliers
2795 ampMin = LARGE_POSITIVE
2796 ampMax = LARGE_NEGATIVE
2797 PHASE_ABS_SUM_THRESHOLD = 2e-3 # in degrees, used to avoid printing MAD statistics for refant
2799 TDMisSecond = False
2800 pagectr = 0
2801 drewAtmosphere = False
2802 newpage = 1
2803 if debug:
2804 print("Setting pages to blank list")
2805 pages = []
2806 xctr = 0
2807 myap = 0 # determines whether an amp or phase plot starts the page (in the case of 'both')
2808 # zero means amplitude, 1 means phase
2809 redisplay = False
2810 matchctr = 0
2811 myUniqueColor = []
2812 # for the overlay=antenna case, start by assuming the first antenna is not flagged
2813 firstUnflaggedAntennaToPlot = 0
2814 lastUnflaggedAntennaToPlot = len(antennasToPlot)
2815 computedAtmSpw = -1
2816 computedAtmTime = -1
2817 computedAtmField = -1
2818 skippingSpwMessageSent = 0
2819 atmString = ''
2820 if (showimage and lo1==''):
2821 # We only need to run this once per execution.
2822 if (debug):
2823 print("Calling getLOs")
2824 getLOsReturnValue = getLOs(msName, verbose=debug)
2825 if (getLOsReturnValue != []):
2826 if (debug):
2827 print("Calling interpret LOs")
2828 lo1s = interpretLOs(msName,parentms,verbose=debug,mymsmd=mymsmd)
2829 if (debug):
2830 print("Done interpretLOs")
2831 foundLO1Message = [] # Initialize so that message is only displayed once per spw
2833 if (channeldiff>0):
2834 # build blank dictionary: madstats['DV01']['spw']['time']['pol']['amp' or 'phase' or both]
2835 # where spw, time, pol are each integers
2836 if (len(msAnt) > 0):
2837 madstats = dict.fromkeys(mymsmd.antennanames(antennasToPlot))
2838 else:
2839 madstats = dict.fromkeys(['Ant '+str(i) for i in range(len(uniqueAntennaIds))])
2841 for i in range(len(madstats)):
2842 madstats[list(madstats.keys())[i]] = dict.fromkeys(spwsToPlot)
2843 for j in range(len(spwsToPlot)):
2844 madstats[list(madstats.keys())[i]][spwsToPlot[j]] = dict.fromkeys(timerangeList) # dict.fromkeys(range(len(uniqueTimes)))
2845 for k in timerangeList: # range(len(uniqueTimes)):
2846 madstats[list(madstats.keys())[i]][spwsToPlot[j]][k] = dict.fromkeys(list(range(nPolarizations)))
2847 for l in range(nPolarizations):
2848 if (yaxis == 'both'):
2849 madstats[list(madstats.keys())[i]][spwsToPlot[j]][k][l] = {'amp': None, 'phase': None}
2850 elif (yaxis == 'phase'):
2851 madstats[list(madstats.keys())[i]][spwsToPlot[j]][k][l] = {'phase': None}
2852 else:
2853 # this includes tsys and amp
2854 madstats[list(madstats.keys())[i]][spwsToPlot[j]][k][l] = {'amp': None}
2855 madstats['platforming'] = {}
2856# # print("madstats = ", madstats)
2857 myinput = ''
2858 atmEverBeenShown = False
2859 spwsToPlotInBaseband = []
2860 frequencyRangeToPlotInBaseband = []
2861 if (debug): print("up to basebands")
2862 if (len(basebands) == 0):
2863 # MS is too old to have BBC_NO
2864 if (debug): print("MS is too old to have BBC_NO")
2865 spwsToPlotInBaseband = [spwsToPlot]
2866 frequencyRangeToPlotInBaseband = [callFrequencyRangeForSpws(mymsmd, spwsToPlot, vm, caltable)]
2867 basebands = [0]
2868 elif (overlayBasebands):
2869 if (debug): print("overlayBaseband")
2870 if (list(spwsToPlot) != list(uniqueSpwsInCalTable)):
2871 # then spws were requested, so treat them all as if in the same baseband, and
2872 # ignore the basebands parameter
2873 print("Ignoring the basebands parameter because spws were specified = %s" % (str(spwsToPlot)))
2874 elif (np.array_equal(np.sort(basebands), np.sort(allBasebands)) == False):
2875 # Allow the basebands parameter to select the spws
2876 if (debug): print("Allow the basebands parameter to select the spws")
2877 basebandSpwsToPlot = []
2878 for baseband in basebands:
2879 myspws = list(getSpwsForBaseband(vis=msName, mymsmd=mymsmd, bb=baseband))
2880 basebandSpwsToPlot += myspws
2881 spwsToPlot = np.intersect1d(basebandSpwsToPlot, spwsToPlot)
2882 print("selected basebands %s have spwsToPlot = %s" % (str(basebands),str(spwsToPlot)))
2883 spwsToPlotInBaseband = [spwsToPlot] # treat all spws as if in the same baseband
2884 frequencyRangeToPlotInBaseband = [callFrequencyRangeForSpws(mymsmd, spwsToPlot, vm, caltable)]
2885 basebands = [0]
2886 else:
2887 print("basebands = %s, spwsToPlot=%s" % (basebands,spwsToPlot))
2888 for baseband in basebands:
2889 myspwlist = []
2890 for spw in spwsToPlot:
2891 if (ctsys.compare_version('>=',[4,1,0]) and msFound):
2892 if (mymsmd.baseband(originalSpwsToPlot[list(spwsToPlot).index(spw)]) == baseband):
2893 myspwlist.append(spw)
2894 else:
2895 # need to write a function to retrieve baseband
2896 # if (spw != 0):
2897 myspwlist.append(spw)
2898 spwsToPlotInBaseband.append(myspwlist)
2899 frequencyRangeToPlotInBaseband.append(callFrequencyRangeForSpws(mymsmd, myspwlist,vm,caltable))
2901 firstTimeMatch = -1 # Aug 5, 2013
2902 finalTimeMatch = -1 # for CAS-7820
2903 groupByBaseband = False # don't activate this parameter yet
2904 if (overlaySpws or overlayBasebands):
2905 groupByBaseband = True
2906 if (groupByBaseband and overlaySpws==False and overlayBasebands==False):
2907 showBasebandNumber = True
2908 # Basic nested 'while' loop structure is:
2909 # - antennas
2910 # - baseband (if necessary)
2911 # - spw
2912 # - time
2913 # - for i in rows
2914 maxChannels = {}; maxChannels2 = {}
2915 while (xctr < len(antennasToPlot)):
2916 if (debug): print("at top of xctr loop: %d" % (xctr))
2917 xant = antennasToPlot[xctr]
2918 bbctr = 0
2919 spwctr = 0
2920 spwctrFirstToPlot = 0
2921 antstring, Antstring = buildAntString(xant,msFound,msAnt)
2922 alreadyPlottedAmp = False # needed for (overlay='baseband', yaxis='both') CAS-6477
2923 finalSpwWasFlagged = False # inserted on 22-Apr-2014 for g25.27
2924 if debug:
2925 print("if (bbctr=%d <? %d and groupByBaseband=%s) or (spwctr=%d < %d and not groupByBaseband=%s)" % (bbctr,len(spwsToPlotInBaseband), groupByBaseband, spwctr, len(spwsToPlot), groupByBaseband))
2926 while ((bbctr < len(spwsToPlotInBaseband) and groupByBaseband) or
2927 (spwctr < len(spwsToPlot) and groupByBaseband==False)
2928 ):
2929 if (debug): print("at top of bbctr/spwctr loop with bbctr=%d, spwctr=%d" % (bbctr,spwctr))
2930 if (groupByBaseband):
2931 baseband = basebands[bbctr]
2932 spwsToPlot = spwsToPlotInBaseband[bbctr]
2933 if (debug): print("setting spwsToPlot for baseband %d (bbctr=%d) to %s" % (baseband, bbctr, str(spwsToPlot)))
2934 else:
2935 baseband = 0 # add from here to "ispw=" on 2014-04-05
2936 if (ctsys.compare_version('>=',[4,1,0])):
2937 if (debug): print("TASK> msName=%s, vis=%s" % (msName,vis))
2938 if (getBasebandDict(vis=msName,caltable=caltable,mymsmd=mymsmd) != {}):
2939 try:
2940 baseband = mymsmd.baseband(originalSpwsToPlot[spwctr])
2941 if (baseband not in basebands):
2942 spwctr += 1
2943 if (debug): print("A)incrementing spwctr")
2944 continue
2945 except:
2946 pass
2947 if (debug):
2948 if (overlayBasebands):
2949 print("Regardless of baseband (%s), plotting all spws: %s" % (basebands,str(spwsToPlot)))
2950 else:
2951 print("Showing baseband %d containing spws: %s" % (baseband,str(spwsToPlot)))
2952 if (bbctr < len(spwsToPlotInBaseband)):
2953 if (debug):
2954 print("A) spwctr=%d, bbctr=%d < len(spwsToPlotInBaseband)=%d" % (spwctr,bbctr,len(spwsToPlotInBaseband)))
2955 spwctr = 0
2956 spwctrFirstToPlot = spwctr
2957 firstSpwMatch = -1
2958 while (spwctr < len(spwsToPlot)):
2959 if (debug): print("at top of spwctr loop, spwctr=%d" % (spwctr))
2960 allTimesFlaggedOnThisSpw = True # used only by overlay='time'
2961 if (groupByBaseband == False):
2962 baseband = 0
2963 if (ctsys.compare_version('>=',[4,1,0])):
2964 if (getBasebandDict(vis=msName,caltable=caltable,mymsmd=mymsmd) != {}):
2965 try:
2966 baseband = mymsmd.baseband(originalSpwsToPlot[spwctr])
2967 if (baseband not in basebands):
2968 # print("spw %d=%d: baseband %d is not in %s" % (spwsToPlot[spwctr],originalSpwsToPlot[spwctr], baseband, basebands))
2969 if (debug): print("Bb)incrementing spwctr")
2970 spwctr += 1
2971 continue
2972 except:
2973 pass
2974 ispw = spwsToPlot[spwctr]
2975 ispwInCalTable = list(uniqueSpwsInCalTable).index(ispw)
2976 mytime = 0
2977 if (debug):
2978 print("+++++++ set mytime=0 for ispw=%d, len(chanFreqGHz) = %d" % (ispw, len(chanFreqGHz)))
2979 if (overlayAntennas):
2980 xctr = -1
2981 if (overlayTimes):
2982 # since the times/scans can vary between spws, redefine nUniqueTimes for each spw
2983 nUniqueTimes = len(uniqueTimesCopy)
2984 uniqueTimes = uniqueTimesCopy[:]
2985 uniqueTimesForSpw = []
2986 testtime = 0
2987 while (testtime < nUniqueTimes):
2988 if (ispw in cal_desc_id[np.where(uniqueTimes[testtime] == times)[0]]):
2989 uniqueTimesForSpw.append(uniqueTimes[testtime])
2990 testtime += 1
2991 uniqueTimes = uniqueTimesForSpw[:]
2992 if (tableFormat >= 34):
2993 scansForUniqueTimes, nUniqueTimes = computeScansForUniqueTimes(uniqueTimes, cal_scans, times, unique_cal_scans)
2994 else:
2995 nUniqueTimes = len(uniqueTimes)
2996# currentSpwctr = spwctr # commented out on 2014-04-04 to match task for task01 regression
2997 if (overlaySpws or overlayBasebands):
2998 if (xctr >= firstUnflaggedAntennaToPlot):
2999 if (debug):
3000 print("xctr=%d >= firstUnflaggedAntennaToPlot=%d, decrementing spwctr to %d" % (xctr, firstUnflaggedAntennaToPlot,spwctr-1))
3001 spwctr -= 1
3003 firstTimeMatch = -1
3004 finalTimeMatch = -1 # for CAS-7820
3005 while (mytime < nUniqueTimes): # start of enormous 2470-line while loop
3006 finalTimerangeFlagged = False # 04-Aug-2014
3007 if (debug):
3008 print("at top of mytime loop: mytime = %d < %d" % (mytime,nUniqueTimes))
3009 print("%d timerangeListTimes" % (len(timerangeListTimes)))
3010 print("timerangeList = %s" % (str(timerangeList)))
3011 print("timerangeListTimes = %s" % (str(timerangeListTimes)))
3012 print("debugSloppyMatch = %s" % (str(debugSloppyMatch)))
3013 print(("solutionTimeThresholdSeconds = %s" % (str(solutionTimeThresholdSeconds))))
3014# if ((scansToPlot == scansToPlotPerSpw[ispw]).all() == False and False):
3015# print " scansToPlot = ", scansToPlot
3016# print "scansToPlotPerSpw[%2d] = " % (ispw), scansToPlotPerSpw[ispw]
3017 if (len(timerangeList) > 0 and
3018 (sloppyMatch(uniqueTimes[mytime],timerangeListTimes,solutionTimeThresholdSeconds,
3019 mytime, scansToPlot, scansForUniqueTimes, myprint=debugSloppyMatch)==False)): # task version
3020# mytime, scansToPlotPerSpw[ispw], scansForUniqueTimes, myprint=debugSloppyMatch)==False)): # causes infinite loop on test 85
3021 if (debug):
3022 print("Skipping time %d because it is not in the list: %s" % (mytime, str(timerangeList)))
3023 mytime += 1
3024 if (debug): print(" 0006 incrementing mytime to ", mytime)
3025 if (mytime == nUniqueTimes and overlayTimes and overlayAntennas):
3026 # added March 14, 2013 to support the case when final timerange is flagged
3027 doneOverlayTime = False
3028 if (debug):
3029 print("$$$$$$$$$$$$$$$$$$$$$$ Setting doneOverlayTime=False" % (xframe))
3030 else:
3031 if (debug):
3032 print("Not setting doneOverlayTime=False because either mytime(%d) != nUniqueTimes(%d) or we are not overlaying time and antenna" % (mytime,nUniqueTimes))
3033 continue
3034 if (overlayAntennas):
3035 xctr += 1
3036 if (xctr >= len(antennasToPlot)):
3037 xctr = 0
3038# if (mytime == 0):
3039# if (debug): print "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ setting firstTimeMatch = -1"
3040# firstTimeMatch = -1 # Aug 5, 2013
3041 xant = antennasToPlot[xctr]
3042 if (debug):
3043 print("mytime=%d, Set xant to %d" % (mytime,xant))
3044 antennaString = ''
3045 else:
3046 antennaString = 'Ant%2d: %s, ' % (xant,antstring)
3047 if (overlaySpws or overlayBasebands):
3048 if (debug): print("C)incrementing spwctr to %d" % (spwctr+1))
3049 spwctr += 1
3050 if (spwctr >= len(spwsToPlot)):
3051 if (debug): print("---------------------- C) Setting spwctr=0")
3052 spwctr = 0
3053 if (xctr < firstUnflaggedAntennaToPlot):
3054 xctr += 1
3055 if (xctr == len(antennasToPlot)):
3056 break
3057 xant = antennasToPlot[xctr]
3058 antstring = buildAntString(xant,msFound,msAnt)
3059 if (debug):
3060 print("mytime=%d, Set xant to %d" % (mytime,xant))
3061 antennaString = 'Ant%2d: %s, ' % (xant,antstring)
3062 if (overlayBasebands):
3063 # Added on 7/29/2014 to fix infinite loop in uid___A002_X652932_X20fb bandpass
3064 if (mytime == nUniqueTimes):
3065 spwctr = len(spwsToPlot)
3066 break
3067 ispw = spwsToPlot[spwctr]
3068 ispwInCalTable = list(uniqueSpwsInCalTable).index(ispw)
3069 if (debug):
3070 print("----------------------------- spwctr=%d, ispw set to %d, xctr=%d" % (spwctr,ispw,xctr))
3071 # endif overlaySpws or overlayBasebands
3072 if (newpage==1):
3073 # add the current page (being created here) to the list
3074 if (debug):
3075 print("pages = ", pages)
3076 pages.append([xctr,spwctr,mytime,0])
3077 if (debug):
3078 print("next: appending [%d,%d,%d,%d]" % (xctr,spwctr,mytime,0))
3079 newpage = 0
3080 if (ispw not in uniqueSpwsInCalTable): ##### added 2024Aug
3081 print("spw %d is not in caltable=%s" % (ispw,uniqueSpwsInCalTable)) ##### added 2024Aug
3082 return ##### added 2024Aug
3083 if tableFormat > 33: ##### added 2024Aug
3084 if ispw not in list(scansToPlotPerSpw.keys()): ##### added 2024Aug
3085 print("ispw=%d not in %s" % (ispw,scansToPlotPerSpw)) ##### added 2024Aug
3086 break ##### added 2024Aug
3087 gplotx = []
3088 gploty = []
3089 channels = []
3090 xchannels = []
3091 ychannels = []
3092 frequencies = []
3093 xfrequencies = []
3094 yfrequencies = []
3095 channels2 = []
3096 xchannels2 = []
3097 ychannels2 = []
3098 frequencies2 = []
3099 xfrequencies2 = []
3100 yfrequencies2 = []
3101 gplotx2 = []
3102 gploty2 = []
3103 xflag = []
3104 yflag = []
3105 xflag2 = []
3106 yflag2 = []
3107 matchFound = False
3108 matchField = -1
3109 matchRow = -1
3110 matchTime = -1
3111 if (debug): print("looping over all nRows = %d" % (nRows))
3112 for i in range(nRows):
3113 if (overlayTimes or overlayAntennas or len(fieldsToPlot)>1 or
3114 (nFields>1 and len(fieldlist)<nFields)):
3115 # When there are multiple fields, then matching by scan causes the first
3116 # matching solution to be displayed every time. So use the original method
3117 # of matching by time until I think of something better.
3118 sm = sloppyMatch(uniqueTimes[mytime],times[i],solutionTimeThresholdSeconds,myprint=False)
3119 else:
3120 if (overlayBasebands):
3121 sTP = scansToPlot
3122 else:
3123 if tableFormat > 33: ### added 2024Aug
3124 sTP = scansToPlotPerSpw[ispw] ### indented 2024Aug
3125 else: ### added 2024Aug
3126 sTP = [] ### added 2024Aug
3127 sm = sloppyMatch(uniqueTimes[mytime],times[i],solutionTimeThresholdSeconds,
3128 mytime, sTP, scansForUniqueTimes, myprint=False) # au version
3129 if ((ant[i]==xant) and (cal_desc_id[i]==ispw) and sm
3130 and (mytime in timerangeList) # this test was added to support multiFieldInTimeOverlay
3131 ):
3132 if (debug): print("len(chanFreqGHz)=%d, ispw=%d" % (len(chanFreqGHz),ispw))
3133 if (msFound or tableFormat==34):
3134 if (len(chanFreqGHz[ispw]) == 1):
3135 if ((skippingSpwMessageSent & (1<<ispw)) == 0):
3136 casalogPost(debug,"Skipping spw=%d because it has only 1 channel." % (ispw))
3137 skippingSpwMessageSent |= (1<<ispw)
3138 break
3139 if (fields[i] in fieldsToPlot):
3140 interval = intervals[i] # used for CalcAtmTransmission
3141 myFieldIndex = np.where(fields[i] == uniqueFields)[0]
3142 if (type(myFieldIndex) == list or type(myFieldIndex) == np.ndarray):
3143 myFieldIndex = myFieldIndex[0]
3144 if (debug):
3145 print("%d Found match at field,ant,spw,mytime,time = %d(index=%d),%d,%d,%d,%f=%s" % (matchctr,fields[i],myFieldIndex,xant,ispw,mytime,uniqueTimes[mytime],utstring(uniqueTimes[mytime],4)))
3146 if (matchFound):
3147 if (myFieldIndex == matchField and matchTime==times[i]):
3148 print("WARNING: multiple rows for field=%d,ant=%d,spw=%d,scan=%d,time=%d=%.0f=%s,row=%d. Only showing the first one." % (fields[i],xant,ispw,scansForUniqueTimes[mytime],mytime,uniqueTimes[mytime],utstring(uniqueTimes[mytime],3),i))
3149 else:
3150 matchFound = True
3151 fieldIndex = myFieldIndex
3152 matchField = myFieldIndex
3153 matchTime = times[i]
3154 matchRow = i
3155 if (msFound or tableFormat==34):
3156 nChannels = len(chanFreqGHz[ispw])
3157 else:
3158 nChannels = len(ggx[0])
3159 xflag.append(flags[i][0][:])
3160 yflag.append(flags[i][1][:])
3161 BRowNumber = i
3162 for j in range(nChannels): # len(chanFreqGHz[ispw])):
3163 channels.append(j) # both flagged and unflagged
3164 if (msFound or tableFormat==34):
3165 frequencies.append(chanFreqGHz[ispw][j])
3166 if (j==0 and debug):
3167 print("found match: ispw=%d, j=%d, len(chanFreqGHz)=%d, chanFreqGHz[0]=%f" % (ispw,j, len(chanFreqGHz),chanFreqGHz[ispw][0]))
3168 if (showflagged or (showflagged == False and flags[i][0][j]==0)):
3169 gplotx.append(ggx[i][j])
3170 xchannels.append(j)
3171 if (msFound or tableFormat==34):
3172 xfrequencies.append(chanFreqGHz[ispw][j])
3173 if (nPolarizations == 2):
3174 if (showflagged or (showflagged == False and flags[i][1][j]==0)):
3175 gploty.append(ggy[i][j])
3176 ychannels.append(j)
3177 if (msFound or tableFormat==34):
3178 yfrequencies.append(chanFreqGHz[ispw][j])
3179 # end 'for i' over rows
3181# if (not matchFound and newpage==0 and firstTimeMatch==-1):
3182 if (not matchFound and newpage==0):
3183 # the first test below is the first of two fixes for CAS-13568 (prevent crash)
3184 if (len(pages) > 1) and (subplot==11 or (subplot!=11 and firstSpwMatch==-1 and firstTimeMatch==-1)):
3185 # Fix for CAS-7753
3186 # the firstTimeMatch part was needed for regression 65: different antennas having different solution times
3187 newpage = 1
3188 if debug: print("setting pages to length=%d" % (len(pages)-1))
3189 pages = pages[:len(pages)-1]
3190 myspw = originalSpw[ispw]
3191 if myspw not in list(maxChannels.keys()):
3192 maxChannels[myspw] = 0 # keep track to set x-axis label correctly
3193 maxChannels2[myspw] = 0 # keep track to set x-axis label correctly
3195 if len(xchannels) > maxChannels[myspw]:
3196 maxChannels[myspw] = len(xchannels) # keep track to set x-axis label correctly
3197 if len(xchannels2) > maxChannels[myspw]:
3198 maxChannels2[myspw] = len(xchannels2) # keep track to set x-axis label correctly
3199 if (msFound):
3200 if debug:
3201 print("A) xchannels = ", xchannels)
3202 print("myspw=%s" % (str(myspw)))
3203 print("len(refFreq)=%d" % (len(refFreq)))
3204 if (myspw >= len(refFreq)):
3205 myspw = ispw
3206 if (msFound and refFreq[myspw]*1e-9 > 60):
3207 # Then this cannot be Band 1 or EVLA data. TODO: But I should really check the telescope name!
3208# if (refFreq[myspw]*1e-9 > np.mean(frequencies)):
3209 if (refFreq[myspw]*1e-9 > np.mean(chanFreqGHz[ispw])): # this is safer (since frequencies might be an empty list)
3210 sideband = -1
3211# xlabelString = "%s LSB Frequency (GHz)" % refTypeToString(measFreqRef[myspw])
3212 xlabelString = "%s LSB Frequency (GHz) (%d channels)" % (refTypeToString(measFreqRef[myspw]),maxChannels[myspw]) ### 2024Aug
3213 else:
3214 sideband = +1
3215# xlabelString = "%s USB Frequency (GHz)" % refTypeToString(measFreqRef[myspw])
3216 xlabelString = "%s USB Frequency (GHz) (%d channels)" % (refTypeToString(measFreqRef[myspw]),maxChannels[myspw]) ### 2024Aug
3217 else:
3218 sideband = -1
3219# xlabelString = "Frequency (GHz)"
3220 xlabelString = "Frequency (GHz) (%d channels)" % (maxChannels[myspw]) ### 2024Aug
3221 if ((len(frequencies)>0) and (chanrange[1] > len(frequencies))):
3222 print("Invalid chanrange (%d-%d) for spw%d in caltable1. Valid range = 0-%d" % (chanrange[0],chanrange[1],ispw,len(frequencies)-1))
3223 return()
3224 pchannels = [xchannels,ychannels]
3225 pfrequencies = [xfrequencies,yfrequencies]
3226 gplot = [gplotx,gploty]
3227 # We only need to compute the atmospheric transmission if:
3228 # * we have been asked to show it,
3229 # * there is a non-trivial number of channels,
3230 # * the current field is the one for which we should calculate it (if times are being overlaied)
3231 # But this will cause no atmcurve to appear if that field is flagged on the first
3232 # antenna; so, I added the atmEverBeenShown flag to deal with this.
3233 # * the previous calculation is not identical to what this one will be
3234 #
3235 if ((showatm or showtsky) and (len(xchannels)>1 or len(ychannels)>1) and
3236 ((uniqueFields[fieldIndex]==showatmfield or
3237 (uniqueFields[fieldIndex] in fieldsToPlot and overlayTimes)) or # this insures a plot if first fieldsToPlot is missing
3238 overlayTimes==False or atmEverBeenShown==False) and
3239 ((overlayTimes==False and computedAtmField!=fieldIndex) or (computedAtmSpw!=ispw) or
3240 (overlayTimes==False and computedAtmTime!=mytime))):
3241 atmEverBeenShown = True
3242 # The following 'if' is used to avoid wasting time since atm is not shown for
3243 # overlay='antenna,time'.
3244 if (overlayTimes==False or overlayAntennas==False or True): # support showatm for overlay='antenna,time'
3245# # if (overlayTimes==False or overlayAntennas==False):
3246# # # # print("CAF, CAS, CAT = ", computedAtmField, computedAtmSpw, computedAtmTime)
3247 if (type(fieldIndex) == list or type(fieldIndex) == np.ndarray):
3248 computedAtmField = fieldIndex[0]
3249 else:
3250 computedAtmField = fieldIndex
3251 computedAtmSpw = ispw
3252 computedAtmTime = mytime
3253 atmtime = time.time()
3254 asdm = ''
3255# # # # print("A) uniqueFields[%d] = " % (fieldIndex), uniqueFields[fieldIndex])
3256 uFFI = uniqueFields[fieldIndex]
3257 if (type(uFFI) == type(np.ndarray(0))):
3258 uFFI = uFFI[0]
3259 if (debug): print("converting uFFI from array to %s" % (str(type(uFFI))))
3260 (atmfreq,atmchan,transmission,pwvmean,atmairmass,TebbSky,missingCalWVRErrorPrinted) = \
3261 CalcAtmTransmission(channels, frequencies, xaxis, pwv,
3262 vm, mymsmd, msName, asdm, xant, uniqueTimes[mytime],
3263 interval, uFFI, refFreq[originalSpw[ispw]],
3264 net_sideband[originalSpw[ispw]], mytime,
3265 missingCalWVRErrorPrinted, caltable,
3266 Trx=Trx, showtsys=showtsys, verbose=DEBUG)
3267 if showtsys:
3268 TebbSky = Tsys
3269 if (showimage):
3270# print("len(lo1s)=%d = " % (len(lo1s)), lo1s)
3271 if (lo1 != ''):
3272 # lo1 was specified on the command line
3273 LO1 = lo1
3274 else:
3275 if (getLOsReturnValue == []):
3276 if (lo1 == ''):
3277 print("Because you do not have the ASDM_RECEIVER table, if you want the showimage")
3278 print("option to work, then you must specify the LO1 frequency with lo1=.")
3279# # # # return()
3280 LO1 = lo1
3281 else:
3282 if (lo1s is None or lo1s == {}):
3283 print("Failed to get LO1, disabling showimage. Alternatively, you can use printLOsFromASDM and supply the lo1 parameter to plotbandpass.")
3284 showimage = False
3285 LO1 = ''
3286 else:
3287 if (originalSpw[ispw] not in list(lo1s.keys())):
3288 print("There is a problem in reading the LO1 values, cannot showimage for this dataset.")
3289 showimage = False
3290 LO1 = ''
3291 else:
3292 LO1 = lo1s[originalSpw[ispw]]*1e-9
3293 if (ispw not in foundLO1Message):
3294 casalogPost(debug,"For spw %d (%d), found LO1 = %.6f GHz" % (ispw,originalSpw[ispw],LO1))
3295 foundLO1Message.append(ispw)
3296 if (LO1):
3297 frequenciesImage = list(2*LO1 - np.array(frequencies))
3298 xfrequenciesImage = list(2*LO1 - np.array(pfrequencies[0]))
3299 yfrequenciesImage = list(2*LO1 - np.array(pfrequencies[1]))
3300 pfrequenciesImage = [xfrequenciesImage, yfrequenciesImage]
3301 if (debug):
3302 print("B) uniqueFields[%d] = %s" % (fieldIndex, str(uniqueFields[fieldIndex])))
3303 uFFI = uniqueFields[fieldIndex]
3304 if (debug):
3305 print("type(uFFI) = %s" % (str(type(uFFI))))
3306 if (type(uFFI) == list or type(uFFI) == type(np.ndarray(0))):
3307 uFFI = uFFI[0]
3308 if (debug):
3309 print("uFFI = %s" % (str(uFFI)))
3310 (atmfreqImage,atmchanImage,transmissionImage,pwvmean,atmairmass,TebbSkyImage,missingCalWVRErrorPrinted) = \
3311 CalcAtmTransmission(channels, frequenciesImage, xaxis,
3312 pwv, vm, mymsmd, msName, asdm, xant, uniqueTimes[mytime],
3313 interval, uFFI, refFreq[originalSpw[ispw]],
3314 net_sideband[originalSpw[ispw]], mytime,
3315 missingCalWVRErrorPrinted, caltable,
3316 Trx=Trx, showtsys=showtsys, verbose=DEBUG)
3317 # difference between the requested Atm freq and actual Atm calcuation CAS-7715. No longer necessary after CAS-10228.
3318 #chanDifference = atmfreq[0]-frequencies[0]
3319 #chanImageDifference = atmfreqImage[0]-frequenciesImage[-1]
3320 #print("signal SB difference = %f, image SB difference = %f" % (chanDifference, chanImageDifference))
3321 if showtsys:
3322 TebbSkyImage = TsysImage
3323 atmfreqImage = list(2*LO1 - np.array(atmfreqImage)) # + 2*chanDifference + chanImageDifference) # CAS-7715 adds final 2 terms
3324 atmchanImage.reverse()
3326 if (overlayTimes):
3327 atmString = 'PWV %.2fmm, airmass %.2f, maxAlt %.0fkm (field %d)' % (pwvmean,atmairmass,maxAltitude,showatmfield)
3328 else:
3329 atmString = 'PWV %.2fmm, airmass %.3f, maxAlt %.0fkm' % (pwvmean,atmairmass,maxAltitude)
3330 if (bOverlay):
3331 for i in range(nRows2):
3332 if (overlayTimes or overlayAntennas or len(fieldsToPlot)>1 or
3333 (nFields>1 and len(fieldlist)<nFields)):
3334 # Not having this path causes Tsys table overlays to behave like overlay='antenna,time'
3335 # for caltable2.
3336 sm = sloppyMatch(uniqueTimes2[mytime],times2[i],solutionTimeThresholdSeconds,myprint=False)
3337 else:
3338 if (mytime >= len(uniqueTimes2)):
3339 # Fix for CAS-9474: avoid calling sloppyMatch because it will crash.
3340 # Setting sm=False will result in an abort: "no amp data found in second solution."
3341 sm = False
3342 else:
3343 if tableFormat >= 34: ### added 2024Aug
3344 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
3345 else: ### added 2024Aug
3346 scansToPlotHere = scansToPlot ### added 2024Aug
3347 sm = sloppyMatch(uniqueTimes2[mytime],times2[i],solutionTimeThresholdSeconds,
3348 mytime, scansToPlotHere, scansForUniqueTimes, # au version ### modified 2024Aug
3349 myprint=debugSloppyMatch)
3350 if ((ant2[i]==xant) and (cal_desc_id2[i]==ispw) and sm
3351 and (mytime in timerangeList) # added to match first caltable logic on 2014-04-09
3352 ):
3353 if (fields2[i] in fieldsToPlot):
3354 xflag2.append(flags2[i][0][:])
3355 yflag2.append(flags2[i][1][:])
3356 # With solint='2ch' or more, the following loop should not be over
3357 # chanFreqGHz2 but over the channels in the solution.
3358 for j in range(len(chanFreqGHz2[ispw])):
3359 channels2.append(j)
3360 frequencies2.append(chanFreqGHz2[ispw][j])
3361# # # # print("len(chanFreqGHz2[%d])=%d, i=%d,j=%d, len(ggx2)=%d, len(ggx2[0])=%d, shape(ggx2) = " % (ispw,len(chanFreqGHz2[ispw]),i,j,len(ggx2),len(ggx2[0])), np.shape(np.array(ggx2)))
3362 if (showflagged or (showflagged == False and flags2[i][0][j]==0)):
3363 gplotx2.append(ggx2[i][j])
3364 xchannels2.append(j)
3365 xfrequencies2.append(chanFreqGHz2[ispw][j])
3366 if (nPolarizations2 == 2):
3367 if (showflagged or (showflagged == False and flags2[i][1][j]==0)):
3368 gploty2.append(ggy2[i][j])
3369 ychannels2.append(j)
3370 yfrequencies2.append(chanFreqGHz2[ispw][j])
3371 # end 'for i'
3372 pchannels2 = [xchannels2,ychannels2]
3373 pfrequencies2 = [xfrequencies2,yfrequencies2]
3374 gplot2 = [gplotx2,gploty2]
3375 # Need to rewrite the xlabel to show the total channel numbers from both caltables. Note that xaxis must be 'freq' for bOverlay
3376 if (msFound and refFreq[myspw]*1e-9 > 60):
3377 # Then this cannot be Band 1 or EVLA data. But I should really check the telescope name!
3378 if (refFreq[myspw]*1e-9 > np.mean(chanFreqGHz2[ispw])): # this is safer (since frequencies might be [])
3379 sideband = -1
3380 xlabelString = "%s LSB Frequency (GHz) (%d, %d channels)" % (refTypeToString(measFreqRef[myspw]),maxChannels[myspw],maxChannels2[myspw])
3381 else:
3382 sideband = +1
3383 xlabelString = "%s USB Frequency (GHz) (%d, %d channels)" % (refTypeToString(measFreqRef[myspw]),maxChannels[myspw],maxChannels2[myspw])
3384 else:
3385 sideband = -1
3386 xlabelString = "Frequency (GHz) (%d, %d channels)" % (maxChannels[myspw],maxChannels2[myspw])
3387 # endif bOverlay
3389 if (matchFound==False):
3390 if ((overlayAntennas==False and overlaySpws==False and overlayBasebands==False) or
3391 (overlayAntennas and xctr+1 >= len(antennasToPlot)) or
3392 ((overlaySpws or overlayBasebands) and spwctr+1 >= len(spwsToPlot))):
3393 mytime += 1
3394 if (debug):
3395 print("a) xctr=%d, Incrementing mytime to %d" % (xctr, mytime))
3396 if overlayAntennas and xctr+1 == len(antennasToPlot): # second fix for CAS-13568
3397 DrawAntennaNamesForOverlayAntennas(xstartPolLabel, ystartPolLabel, polsToPlot, corr_type, channeldiff, ystartMadLabel, subplotRows, gamp_mad, gamp_std, overlayColors, mysize, ampmarkstyle, markersize, markeredgewidth, msAnt, msFound, antennasToPlot, ampmarkstyle2, xframe, firstFrame, caltableTitle, titlesize, debug=debug)
3398 if ((showatm or showtsky) and len(atmString) > 0):
3399 DrawAtmosphere(showatm, showtsky, subplotRows, atmString,
3400 mysize, TebbSky, plotrange, xaxis, atmchan,
3401 atmfreq, transmission, subplotCols,
3402 showatmPoints=showatmPoints, xframe=xframe,
3403 channels=channels,mylineno=lineNumber(),
3404 overlaySpws=overlaySpws,
3405 overlayBasebands=overlayBasebands,
3406 drewAtmosphere=drewAtmosphere,loc=203,
3407 showtsys=showtsys, Trx=Trx)
3408 if (LO1):
3409 # Now draw the image band
3410 DrawAtmosphere(showatm,showtsky, subplotRows, atmString,
3411 mysize, TebbSkyImage, plotrange, xaxis,
3412 atmchanImage, atmfreqImage, transmissionImage,
3413 subplotCols, LO1, xframe, firstFrame, showatmPoints,
3414 channels=channels,mylineno=lineNumber(),
3415 overlaySpws=overlaySpws,
3416 overlayBasebands=overlayBasebands,
3417 drewAtmosphere=drewAtmosphere,loc=204,
3418 showtsys=showtsys, Trx=Trx)
3419 drewAtmosphere = True
3421 continue
3422 # The following variable allows color legend of UT times to match line plot
3423 myUniqueTime = []
3424 if (True): # multiFieldsWithOverlayTime):
3425 # support multi-fields with overlay='time'
3426 uTPFPS = []
3427 for f in fieldIndicesToPlot:
3428 for t in uniqueTimesPerFieldPerSpw[ispwInCalTable][f]:
3429 if tableFormat >= 34: ### added 2024Aug
3430 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
3431 else: ### added 2024Aug
3432 scansToPlotHere = scansToPlot ### added 2024Aug
3433 if (sloppyMatch(t, timerangeListTimes, solutionTimeThresholdSeconds,
3434 mytime, scansToPlotHere, scansForUniqueTimes, # au version ### modified 2024Aug
3435 myprint=debugSloppyMatch
3436 )):
3437 uTPFPS.append(t)
3438 uTPFPS = np.sort(uTPFPS)
3439 ctr = 0
3440 for t in uTPFPS:
3441 if (debug and False):
3442 print("1)checking time %d" % (t))
3443 if (overlayTimes or overlayAntennas):
3444 sm = sloppyMatch(uniqueTimes[mytime],times[i],solutionTimeThresholdSeconds,myprint=False)
3445 else:
3446 if tableFormat >= 34: ### added 2024Aug
3447 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
3448 else: ### added 2024Aug
3449 scansToPlotHere = scansToPlot ### added 2024Aug
3450 sm = sloppyMatch(t, uniqueTimes[mytime], solutionTimeThresholdSeconds,
3451 mytime, scansToPlotHere, scansForUniqueTimes, # au version ### modified 2024Aug
3452 myprint=debugSloppyMatch
3453 )
3454 if (sm):
3455 if (debug):
3456 print("1)setting myUniqueTime to %d" % (mytime))
3457 myUniqueTime = mytime
3458 ctr += 1
3459 if (ctr > len(fieldIndicesToPlot) and bOverlay==False):
3460 if (debug): print("multi-field time overlay *************** why are there 2 matches?")
3461# # # # if (ctr == 0):
3462# # # # print("No match for %.1f in "%(t), uTPFPS)
3464# # # # print("Overlay antenna %d, myUniqueTime=%d" % (xctr, myUniqueTime))
3465 if (xframe == xframeStart):
3466 safe_pb_clf()
3467 xflag = [item for sublist in xflag for item in sublist]
3468 yflag = [item for sublist in yflag for item in sublist]
3469# # pflag = [xflag, yflag]
3470# # flagfrequencies = [frequencies, frequencies2]
3471 antstring, Antstring = buildAntString(xant,msFound,msAnt)
3472 if (msFound):
3473 fieldString = msFields[uniqueFields[fieldIndex]]
3474 else:
3475 fieldString = str(field)
3476 if (overlayTimes):
3477 timeString =''
3478 else:
3479 timeString = ', t%d/%d %s' % (mytime,nUniqueTimes-1,utstring(uniqueTimes[mytime],3))
3480 if (scansForUniqueTimes != []):
3481 if (scansForUniqueTimes[mytime]>=0):
3482 timeString = ', scan%d %s' % (scansForUniqueTimes[mytime],utstring(uniqueTimes[mytime],3))
3483 spwString = buildSpwString(overlaySpws, overlayBasebands, spwsToPlot,
3484 ispw, originalSpw[ispw], observatoryName,
3485 baseband, showBasebandNumber)
3486 titleString = "%sspw%s, field %d: %s%s" % (antennaString,spwString,uniqueFields[fieldIndex],fieldString,timeString)
3487 if (sum(xflag)==nChannels and sum(yflag)==nChannels and showflagged==False):
3488 if (overlayTimes):
3489 msg = "Skip %s (%s) for time%d=%s all data flagged" % (antstring, titleString,mytime,utstring(uniqueTimes[mytime],3))
3490 casalogPost(True, msg)
3491 # need to set doneOverlayTime = True if this is the final time,
3492 # otherwise, we get "subplot number exceeds total subplots" at line 2427
3493 # but we need to draw the labels at the top of the page, else they will not get done
3494 if (debug):
3495 print("########## uniqueTimes[%d]=%d, timerangeListTimes[-1]=%d" % (mytime,uniqueTimes[mytime],timerangeListTimes[-1]))
3496 if (len(scansToPlotPerSpw[ispw]) < 1):
3497 sTPPS = []
3498 else:
3499# sTPPS = [scansToPlot[-1]]# added [[-1]] on 2014-04-04 for CAS-6394 task version
3500 sTPPS = [scansToPlotPerSpw[ispw][-1]]# added [[-1]] on 2014-04-04 for CAS-6394 au version
3501 if (sloppyMatch(timerangeListTimes[-1], uniqueTimes[mytime],
3502 solutionTimeThresholdSeconds,
3503 mytime, sTPPS, scansForUniqueTimes,
3504 myprint=debugSloppyMatch
3505 )):
3506 if (overlayAntennas == False or xant==antennasToPlot[-1]): # 11-Mar-2014
3507 doneOverlayTime = True # 08-Nov-2012
3508 finalTimerangeFlagged = True # 04-Aug-2014
3509 if (debug):
3510 print("###### set doneOverlayTime = %s" % (str(doneOverlayTime)))
3512 # draw labels
3513 # try adding the following 'if' statement on Jun 18, 2013; it works.
3514# if (drewAtmosphere==False or overlayAntennas==False):
3515 # Add the 'and not' case to prevent extra atm/fdms shown if one spw's solutions are all flagged
3516 if (drewAtmosphere==False or (not overlayAntennas and not allTimesFlaggedOnThisSpw)):
3517 if (debug): print("drawOverlayTimeLegends loc 1")
3518 drawOverlayTimeLegends(xframe, firstFrame, xstartTitle, ystartTitle,
3519 caltable, titlesize, fieldIndicesToPlot,
3520 ispwInCalTable, uniqueTimesPerFieldPerSpw,
3521 timerangeListTimes,
3522 solutionTimeThresholdSeconds,
3523 debugSloppyMatch,
3524 ystartOverlayLegend, debug, mysize,
3525 fieldsToPlot, myUniqueColor,
3526 timeHorizontalSpacing, fieldIndex,
3527 overlayColors,
3528 antennaVerticalSpacing, overlayAntennas,
3529 timerangeList, caltableTitle, mytime,
3530 scansToPlotPerSpw[ispw], scansForUniqueTimes,
3531 uniqueSpwsInCalTable, uniqueTimes)
3532 if not LO1 and type(lo1s) == dict: # Fix for SCOPS-4877
3533 LO1 = lo1s[myspw] # Fix for SCOPS-4877
3534 # CAS-8655
3535 newylimits = drawAtmosphereAndFDM(showatm,showtsky,atmString,subplotRows,mysize,
3536 TebbSky,TebbSkyImage,plotrange, xaxis,atmchan,
3537 atmfreq,transmission,subplotCols,showatmPoints,
3538 xframe, channels,LO1,atmchanImage,atmfreqImage,
3539 transmissionImage, firstFrame,showfdm,nChannels,
3540 tableFormat,originalSpw_casa33,
3541 chanFreqGHz_casa33,originalSpw,chanFreqGHz,
3542 overlayTimes, overlayAntennas, xant,
3543 antennasToPlot, overlaySpws, baseband,
3544 showBasebandNumber, basebandDict,
3545 overlayBasebands, overlayColors, drewAtmosphere, showtsys)
3546 drewAtmosphere = True
3547 if (xctr == firstUnflaggedAntennaToPlot or overlayAntennas==False): # changed xant->xctr on 11-mar-2014
3548 DrawPolarizationLabelsForOverlayTime(xstartPolLabel,ystartPolLabel,corr_type,polsToPlot,
3549 channeldiff,ystartMadLabel,subplotRows,gamp_mad,mysize,
3550 ampmarkstyle,markersize,ampmarkstyle2,gamp_std)
3551 else: # not overlaying times
3552 msg = "Skip %s spw%d (%s) all data flagged" % (antstring, ispw, titleString)
3553 casalogPost(True, msg)
3554 if ((overlaySpws or overlayBasebands) and spwctr==spwctrFirstToPlot):
3555 spwctrFirstToPlot += 1
3556 if ((overlaySpws or overlayBasebands) and ispw==spwsToPlotInBaseband[bbctr][-1]):
3557 if (debug): print("The final spw was flagged!!!!!!!!!!!!!!")
3558 finalSpwWasFlagged = True # inserted on 22-Apr-2014 for g25.27
3559 if (myinput == 'b'):
3560 redisplay = False # This prevents infinite loop when htting 'b' on first screen when ant0 flagged. 2013-03-08
3561 if (overlayAntennas==False and overlayBasebands==False): # 07/30/2014 added overlayBasebands==False
3562 if (doneOverlayTime==False or overlayTimes==False): # added on 08-Nov-2012
3563 finalSpwWasFlagged = False # Added on 23-Apr-2014 for regression61
3564 mytime += 1
3565 if (debug):
3566 print("F) all solutions flagged --> incrementing mytime to %d" % mytime)
3567 if (overlayAntennas):
3568 if (xctr == firstUnflaggedAntennaToPlot):
3569 firstUnflaggedAntennaToPlot += 1
3570 if (firstUnflaggedAntennaToPlot >= len(antennasToPlot)):
3571 firstUnflaggedAntennaToPlot = 0
3572 if not finalSpwWasFlagged: # Added on 23-Apr-2014 for regression61
3573 mytime += 1
3574 if (debug):
3575 print("----- Resetting firstUnflaggedAntennaToPlot from %d to %d = %d" % (firstUnflaggedAntennaToPlot-1, firstUnflaggedAntennaToPlot, antennasToPlot[firstUnflaggedAntennaToPlot]))
3576 if (mytime < nUniqueTimes): # Add this 'if' conditional on 9-22-2015 for CAS-7839
3577 continue # Try adding this statement on Apr 2, 2012 to fix bug.
3578 mytime -= 1 # Add this on 9-22-2015 for CAS-7839
3579 if (overlaySpws or overlayBasebands):
3580 if (xctr == firstUnflaggedAntennaToPlot):
3581 firstUnflaggedAntennaToPlot += 1
3582 if (firstUnflaggedAntennaToPlot >= len(antennasToPlot)):
3583 firstUnflaggedAntennaToPlot = 0
3584 if not finalSpwWasFlagged: # Added on 22-Apr-2014 for g25.27 dataset antenna='4'
3585 if (overlayBasebands == False or spwctr>len(spwsToPlot)): # Added on 7/30/2014 for regression 96
3586 mytime += 1
3587 if (debug):
3588 print("----- Resetting firstUnflaggedAntennaToPlot from %d to %d" % (firstUnflaggedAntennaToPlot-1, firstUnflaggedAntennaToPlot))
3589 print("----- = antenna %d" % (antennasToPlot[firstUnflaggedAntennaToPlot]))
3590 if (not finalSpwWasFlagged): # add this test on Apr 22, 2014 to prevent crash on g25.27 dataset with antenna='4,5'
3591 continue # Try this 'continue' on Apr 2, 2012 to fix bug -- works.
3592 if (overlayAntennas==False and subplot==11
3593 and not finalSpwWasFlagged # inserted on 22-Apr-2014 for g25.27
3594 and not finalTimerangeFlagged): # inserted on 04-Aug-2014 for CAS-6812
3595 # added the case (subplot==11) on April 22, 2012 to prevent crash on multi-antenna subplot=421
3596 if (debug):
3597 print("####### removing [%d,%d,%d,%d]" % (pages[len(pages)-1][PAGE_ANT],
3598 pages[len(pages)-1][PAGE_SPW],
3599 pages[len(pages)-1][PAGE_TIME],
3600 pages[len(pages)-1][PAGE_AP]))
3601 pages = pages[0:len(pages)-1]
3602 newpage = 1
3603 if (overlayAntennas==False):
3604 if (doneOverlayTime==False # inserted on 08-Nov-2012
3605 and not finalSpwWasFlagged): # inserted on 22-Apr-2014 for g25.27
3606 continue
3607 elif (debug):
3608 print("=========== Not continuing because doneOverlayTime=%s" % (str(doneOverlayTime)))
3609 else:
3610 allTimesFlaggedOnThisSpw = False
3611 if (debug):
3612 print("Not all the data are flagged. doneOverlayTime=%s" % (str(doneOverlayTime)))
3614 if (firstSpwMatch == -1):
3615 firstSpwMatch = spwctr
3616 if (firstTimeMatch == -1):
3617 firstTimeMatch = mytime
3618 if (debug):
3619 print("Setting firstTimeMatch from -1 to %s" % (str(firstTimeMatch)))
3620 # The following was needed to support overlay='antenna,time' for showatm for QA2 report (CAS-7820)
3621 if (finalTimeMatch == -1 or finalTimeMatch < mytime):
3622 if (debug):
3623 print("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Setting finalTimeMatch from %d to %d" % (finalTimeMatch, mytime))
3624 finalTimeMatch = mytime
3626################### Here is the amplitude plotting ############
3627 if (yaxis.find('amp')>=0 or yaxis.find('both')>=0 or yaxis.find('ap')>=0) and doneOverlayTime==False:
3628 if (overlayBasebands and amplitudeWithPhase): # CAS-6477
3629 if (float(xframe/10) != xframe*0.1 and alreadyPlottedAmp):
3630 xframe -= 2
3632 if (debug):
3633 print("amp: xctr=%d, xant=%d, myap=%d, mytime=%d(%s), firstTimeMatch=%d, bOverlay=" % (xctr, xant, myap, mytime, utstring(uniqueTimes[mytime],3), firstTimeMatch), bOverlay)
3634 if (myap==1):
3635 if (overlayTimes == False or mytime==firstTimeMatch):
3636 if ((overlaySpws == False and overlayBasebands==False) or spwctr==spwctrFirstToPlot or spwctr>len(spwsToPlot)):
3637 if (overlayAntennas==False or xctr==firstUnflaggedAntennaToPlot
3638 or xctr==antennasToPlot[-1]): # 2012-05-24, to fix the case where all ants flagged on one timerange
3639 xframe += 1
3640 if (debug):
3641 print("y) incrementing xframe to %d" % xframe)
3642 print("mytime=%d == firstTimeMatch=%d" % (mytime, firstTimeMatch))
3643 print("xctr=%d == firstUnflaggedAntennaToPlot=%d, antennastoPlot[-1]=%d" % (xctr, firstUnflaggedAntennaToPlot,antennasToPlot[-1]))
3644 myUniqueColor = []
3645 newylimits = [LARGE_POSITIVE, LARGE_NEGATIVE]
3646 else: # (myap == 0)
3647 if (overlayTimes == False or mytime==firstTimeMatch):
3648 if ((overlaySpws == False and overlayBasebands==False) or
3649 spwctr==spwctrFirstToPlot or
3650 (overlayBasebands and amplitudeWithPhase) or # CAS-6477
3651 spwctr>len(spwsToPlot)):
3652 if (overlayAntennas==False or xctr==firstUnflaggedAntennaToPlot
3653 or xctr>antennasToPlot[-1]): # 2012-05-24, to fix the case where all ants flagged on one timerange
3654 xframe += 1
3655 if (debug):
3656 print("Y) incrementing xframe to %d" % xframe)
3657 print("mytime=%d == firstTimeMatch=%d" % (mytime, firstTimeMatch))
3658 print("xctr=%d == firstUnflaggedAntennaToPlot=%d, antennasToPlot[-1]=%d" % (xctr, firstUnflaggedAntennaToPlot,antennasToPlot[-1]))
3659 print("spwctr=%d >? len(spwsToPlot)=%d" % (spwctr, len(spwsToPlot)))
3660 myUniqueColor = []
3661 newylimits = [LARGE_POSITIVE, LARGE_NEGATIVE]
3662 if (debug):
3663 print("myap=%d, mytime == firstTimeMatch=%d" % (myap, firstTimeMatch))
3664 else:
3665 if (debug): print("4)Not incrementing xframe from %d" % (xframe))
3666 else:
3667 if (debug): print("2)Not incrementing xframe from %d (spwctr=%d >? len(spwsToPlot)=%d) or (spwctr=%d == spwctrFirstToPlot=%d)" % (xframe,spwctr,len(spwsToPlot),spwctr,spwctrFirstToPlot))
3668 else:
3669 if (debug): print("1)Not incrementing xframe from %d" % (xframe))
3670 if (debug):
3671 print("$$$$$$$$$$$$$$$$$$$$$$$ ready to plot amp on xframe %d" % (xframe))
3672# # # # print(",,,,,,,,,,,,,,,, Starting with newylimits = ", newylimits)
3673 if (previousSubplot != xframe):
3674 adesc = safe_pb_subplot(xframe) # avoid deprecation warning in CASA6 when xframe already was opened
3675 drewAtmosphere = False
3676 previousSubplot = xframe
3677 alreadyPlottedAmp = True # needed for (overlay='baseband', yaxis='both') CAS-6477
3678 if (delay):
3679 gampx = gplotx
3680 else:
3681 gampx = np.abs(gplotx)
3682 if (nPolarizations == 2):
3683 if (delay):
3684 gampy = gploty
3685 else:
3686 gampy = np.abs(gploty)
3687 if (yaxis.lower().find('db') >= 0):
3688 gamp = [10*np.log10(gampx), 10*np.log10(gampy)]
3689 else:
3690 if (channeldiff>0):
3691 if (debug): print("Computing derivatives")
3692 if (xaxis == 'chan'):
3693 gamp0, newx0, gamp0res, newx0res = channelDifferences(gampx, pchannels[0], resample)
3694 gamp1, newx1, gamp1res, newx1res = channelDifferences(gampy, pchannels[1], resample)
3695 pchannels = [newx0, newx1]
3696 else:
3697 gamp0, newx0, gamp0res, newx0res = channelDifferences(gampx, pfrequencies[0], resample)
3698 gamp1, newx1, gamp1res, newx1res = channelDifferences(gampy, pfrequencies[1], resample)
3699 pfrequencies = [newx0, newx1]
3700 gamp = [gamp0, gamp1]
3701 gampres = [gamp0res, gamp1res]
3702 if (VisCal.lower().find('tsys') >= 0 and tsysPercent):
3703 gamp = [100*gamp0/np.median(gampx), 100*gamp1/np.median(gampy)]
3704 gampres = [100*gamp0res/np.median(gampx), 100*gamp1res/np.median(gampy)]
3705 elif (VisCal.lower().find('tsys') < 0 and ampPercent):
3706 gamp = [100*gamp0/np.median(gampx), 100*gamp1/np.median(gampy)]
3707 gampres = [100*gamp0res/np.median(gampx), 100*gamp1res/np.median(gampy)]
3708 gamp_mad = [madInfo(gamp[0],madsigma,edge), madInfo(gamp[1],madsigma,edge)]
3709 gamp_std = [stdInfo(gampres[0],madsigma,edge,ispw,xant,0), stdInfo(gampres[1],madsigma,edge,ispw,xant,1)]
3710 if (debug): print("gamp_mad done")
3711 if (platformingSigma > 0):
3712 platformingThresholdX = gamp_mad[0]['mad']*platformingSigma
3713 platformingThresholdY = gamp_mad[1]['mad']*platformingSigma
3714 else:
3715 platformingThresholdX = platformingThreshold
3716 platformingThresholdY = platformingThreshold
3717 gamp_platforming = [platformingCheck(gamp[0],platformingThresholdX),
3718 platformingCheck(gamp[1],platformingThresholdY)]
3719 for p in [0,1]:
3720 if (debug):
3721 print("gamp_mad[%d] = %s" % (p, str(gamp_mad[p])))
3722 print("madstats[%s][%d] = %s" % (Antstring,ispw, str(madstats[Antstring][ispw])))
3723 madstats[Antstring][ispw][mytime][p]['amp'] = gamp_mad[p]['mad']
3724 madstats[Antstring][ispw][mytime][p]['ampstd'] = gamp_std[p]['std']
3725 if (gamp_platforming[p]):
3726 if (Antstring not in list(madstats['platforming'].keys())):
3727 madstats['platforming'][Antstring] = {}
3728 if (ispw not in list(madstats['platforming'][Antstring].keys())):
3729 madstats['platforming'][Antstring][ispw] = {}
3730 if (p not in list(madstats['platforming'][Antstring][ispw].keys())):
3731 madstats['platforming'][Antstring][ispw][p] = []
3732 madstats['platforming'][Antstring][ispw][p].append(uniqueTimes[mytime])
3733 if (gamp_mad[p]['nchan'] > 0):
3734 casalogPost(debug, "%s, Pol %d, spw %2d, %s, amp: %4d points exceed %.1f sigma (worst=%.2f at chan %d)" % (Antstring, p, ispw, utstring(uniqueTimes[mytime],0), gamp_mad[p]['nchan'], madsigma, gamp_mad[p]['outlierValue'], gamp_mad[p]['outlierChannel']+pchannels[p][0]))
3735 if (debug): print("madstats done")
3736 else:
3737 gamp = [gampx,gampy]
3738 else:
3739 if (yaxis.lower().find('db') >= 0):
3740 gamp = [10*np.log10(gampx)]
3741 else:
3742 if (channeldiff>0):
3743 if (xaxis == 'chan'):
3744 gamp0, newx0, gamp0res, newx0res = channelDifferences(gampx, pchannels[0], resample)
3745 pchannels = [newx0]
3746 else:
3747 gamp0, newx0, gamp0res, newx0res = channelDifferences(gampx, pfrequencies[0], resample)
3748 pfrequencies = [newx0]
3749 gamp = [gamp0]
3750 gampres = [gamp0res]
3751 if (VisCal.lower().find('tsys') >= 0 and tsysPercent):
3752 gamp = [100*gamp0/np.median(gampx)]
3753 gampres = [100*gamp0res/np.median(gampx)]
3754 elif (VisCal.lower().find('tsys') < 0 and ampPercent):
3755 gamp = [100*gamp0/np.median(gampx)]
3756 gampres = [100*gamp0res/np.median(gampx)]
3757 p = 0
3758 gamp_mad = [madInfo(gamp[p], madsigma,edge)]
3759 gamp_std = [stdInfo(gampres[p], madsigma,edge,ispw,xant,p)]
3760 if (platformingSigma > 0):
3761 platformingThresholdX = gamp_mad[0]['mad']*platformingSigma
3762 else:
3763 platformingThresholdX = platformingThreshold
3764 gamp_platforming = [platformingCheck(gamp[p], platformingThresholdX)]
3765 madstats[Antstring][ispw][mytime][p]['amp'] = gamp_mad[p]['mad']
3766 madstats[Antstring][ispw][mytime][p]['ampstd'] = gamp_std[p]['std']
3767 if (gamp_platforming[p]):
3768 if (Antstring not in list(madstats['platforming'].keys())):
3769 madstats['platforming'][Antstring] = {}
3770 if (ispw not in list(madstats['platforming'][Antstring].keys())):
3771 madstats['platforming'][Antstring][ispw] = {}
3772 if (p not in list(madstats['platforming'][Antstring][ispw].keys())):
3773 madstats['platforming'][Antstring][ispw][p] = []
3774 madstats['platforming'][Antstring][ispw][p].append(mytime)
3775 if (gamp_mad[p]['nchan'] > 0):
3776 casalogPost(debug, "%s, Pol %d, spw %2d, %s, amp: %4d points exceed %.1f sigma (worst=%.2f at chan %d)" % (Antstring, p, ispw, utstring(uniqueTimes[mytime],0), gamp_mad[p]['nchan'], madsigma, gamp_mad[p]['outlierValue'], gamp_mad[p]['outlierChannel']+pchannels[p][0]))
3777 else:
3778 gamp = [gampx]
3779 if (bOverlay):
3780 gampx2 = np.abs(gplotx2)
3781 if (nPolarizations2 == 2):
3782 gampy2 = np.abs(gploty2)
3783 if (yaxis.lower().find('db') >= 0):
3784 gamp2 = [10*np.log10(gampx2), 10*np.log10(gampy2)]
3785 else:
3786 if (channeldiff>0):
3787 if (xaxis == 'chan'):
3788 gamp2_0, newx0, gamp2_0res, newx0res = channelDifferences(gampx2, pchannels2[0], resample)
3789 gamp2_1, newx1, gamp2_1res, newx1res = channelDifferences(gampy2, pchannels2[1], resample)
3790 pchannels2 = [newx0, newx1]
3791 else:
3792 gamp2_0, newx0, gamp2_0res, newx0res = channelDifferences(gampx2, pfrequencies2[0], resample)
3793 gamp2_1, newx1, gamp2_1res, newx1res = channelDifferences(gampy2, pfrequencies2[1], resample)
3794 pfrequencies2 = [newx0, newx1]
3795 gamp2 = [gamp2_0, gamp2_1]
3796 gamp2res = [gamp2_0res, gamp2_1res]
3797 if (VisCal.lower().find('tsys') >= 0 and tsysPercent):
3798 gamp2 = [100*gamp2_0/np.median(gampx2), 100*gamp2_1/np.median(gampy2)]
3799 gamp2res = [100*gamp2_0res/np.median(gampx2), 100*gamp2_1res/np.median(gampy2)]
3800 elif (VisCal.lower().find('tsys') < 0 and ampPercent):
3801 gamp2 = [100*gamp2_0/np.median(gampx2), 100*gamp2_1/np.median(gampy2)]
3802 gamp2res = [100*gamp2_0res/np.median(gampx2), 100*gamp2_1res/np.median(gampy2)]
3803 else:
3804 gamp2 = [gampx2, gampy2]
3805 else:
3806 if (yaxis.lower().find('db') >= 0):
3807 gamp2 = [10*np.log10(gampx2)]
3808 else:
3809 if (channeldiff>0):
3810 if (xaxis == 'chan'):
3811 gamp2_0, newx0, gamp2_0res, newx0res = channelDifferences(gampx2, pchannels[0], resample)
3812 pchannels2 = [newx0]
3813 else:
3814 gamp2_0, newx0, gamp2_0res, newx0res = channelDifferences(gampx2, pfrequencies[0], resample)
3815 pfrequencies2 = [newx0]
3816 gamp2 = [gamp2_0]
3817 gamp2res = [gamp2_0res]
3818 if (VisCal.lower().find('tsys') >= 0 and tsysPercent):
3819 gamp2 = [100*gamp2_0/np.median(gampx2)]
3820 gamp2res = [100*gamp2_0res/np.median(gampx2)]
3821 elif (VisCal.lower().find('tsys') < 0 and ampPercent):
3822 gamp2 = [100*gamp2_0/np.median(gampx2)]
3823 gamp2res = [100*gamp2_0res/np.median(gampx2)]
3824 else:
3825 gamp2 = [gampx2]
3826 if (xaxis.find('chan')>=0 or (msFound==False and tableFormat==33)): # 'amp'
3827 if (debug):
3828 print("amp: plot vs. channel **********************")
3829 for p in range(nPolarizations):
3830 if (overlayAntennas or overlayTimes):
3831 if (corr_type_string[p] in polsToPlot):
3832 pdesc = pb.plot(pchannels[p],gamp[p],'%s'%ampmarkstyles[p],
3833 markersize=markersize,
3834 markerfacecolor=overlayColors[xctr],markeredgewidth=markeredgewidth)
3835 newylimits = recalcYlimits(plotrange,newylimits,gamp[p])
3836 if (overlayAntennas and overlayTimes==False):
3837 pb.setp(pdesc, color=overlayColors[xctr])
3838 elif (overlayTimes and overlayAntennas==False):
3839 pb.setp(pdesc, color=overlayColors[mytime])
3840 elif (overlayTimes and overlayAntennas): # try to support time,antenna
3841 if (debug):
3842 print("p=%d, len(fieldsToPlot)=%d, len(timerangeList)=%d" % (p,len(fieldsToPlot),len(timerangeList)))
3843 if (len(fieldsToPlot) > 1 or len(timerangeList)>1):
3844 # The third 'or' below is needed if pol='0' is flagged on antenna 0. -- 2012/10/12
3845 if (p==0 or len(polsToPlot)==1 or myUniqueColor==[]):
3846 myUniqueColor.append(overlayColors[len(myUniqueColor)])
3847 pb.setp(pdesc, color=myUniqueColor[-1])
3848 else:
3849 if (corr_type_string[p] in polsToPlot):
3850# # # # print("pcolor[%d]=%s" % (p,pcolor))
3851 pb.plot(pchannels[p],gamp[p],'%s%s'%(pcolor[p],ampmarkstyle), markersize=markersize,markeredgewidth=markeredgewidth)
3852 newylimits = recalcYlimits(plotrange,newylimits,gamp[p])
3853 if (sum(xflag)>0):
3854 myxrange = np.max(channels)-np.min(channels)
3855 SetNewXLimits([np.min(channels)-myxrange/20, np.max(channels)+myxrange/20],1)
3856# # # # print("amp: Resetting xaxis channel range to counteract flagged data")
3857 if (xframe in bottomRowFrames or (xctr+1==len(antennasToPlot) and ispw==spwsToPlot[-1])):
3858 pb.xlabel("Channels (%d)" % (len(pchannels[p])), size=mysize) ### changed 2024Aug24
3859 elif (xaxis.find('freq')>=0): # amp
3860 if (bOverlay):
3861 myxrange = np.abs(xfrequencies[0]-xfrequencies[-1])
3862 try:
3863 xrange2 = np.abs(xfrequencies2[0]-xfrequencies2[-1])
3864 except:
3865 print("No amp data found in second solution. Try increasing the solutionTimeThresholdSeconds above %.0f." % (solutionTimeThresholdSeconds))
3866 print("If this doesn't work, email the developer (%s)." % (developerEmail))
3867 return()
3869 if (np.abs(myxrange/xrange2 - 1) > 0.05 + len(xflag)//len(xchannels)): # 0.0666 is 2000/1875-1
3870 # These line widths are optimal for visualizing FDM over TDM
3871 width1 = 1
3872 width2 = 4
3873 # solutions differ in frequency width
3874 if (myxrange < xrange2):
3875 for p in range(nPolarizations):
3876 if (corrTypeToString(corr_type[p]) in polsToPlot):
3877 pb.plot(pfrequencies[p], gamp[p], '%s%s'%(pcolor[p],ampmarkstyle), linewidth=width2, markersize=markersize,markeredgewidth=markeredgewidth)
3878 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
3879 for p in range(nPolarizations):
3880 if (corrTypeToString(corr_type[p]) in polsToPlot):
3881 pb.plot(pfrequencies2[p], gamp2[p], '%s%s'%(p2color[p],ampmarkstyle), linewidth=width1, markersize=markersize,markeredgewidth=markeredgewidth)
3882 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp2[p], sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
3883 else:
3884 for p in range(nPolarizations):
3885 if (corrTypeToString(corr_type[p]) in polsToPlot):
3886 pb.plot(pfrequencies2[p], gamp2[p], '%s%s'%(p2color[p],ampmarkstyle), linewidth=width2, markersize=markersize,markeredgewidth=markeredgewidth)
3887 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp2[p], sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
3888 for p in range(nPolarizations):
3889 if (corrTypeToString(corr_type[p]) in polsToPlot):
3890 pb.plot(pfrequencies[p], gamp[p], '%s%s'%(pcolor[p],ampmarkstyle), linewidth=width1, markersize=markersize,markeredgewidth=markeredgewidth)
3891 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
3892 else:
3893 width1 = 1
3894 width2 = 2 # Just enough to distinguish one line from the other.
3895 # solutions may be different level of smoothing, so plot highest rms first
3896 if madOfDiff(gamp[0]) < madOfDiff(gamp2[0]): # and firstPlot != 1): # only au version has this parameter
3897# if (MAD(gamp[0]) < MAD(gamp2[0])):
3898 for p in range(nPolarizations):
3899 if (corrTypeToString(corr_type[p]) in polsToPlot):
3900 pb.plot(pfrequencies2[p], gamp2[p], '%s%s'%(p2color[p],ampmarkstyle), linewidth=width1, markersize=markersize,markeredgewidth=markeredgewidth)
3901 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp2[p], sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
3902 for p in range(nPolarizations):
3903 if (corrTypeToString(corr_type[p]) in polsToPlot):
3904 pb.plot(pfrequencies[p], gamp[p], '%s%s'%(pcolor[p],ampmarkstyle), linewidth=width2, markersize=markersize,markeredgewidth=markeredgewidth)
3905 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
3906 else:
3907 # plot first solution first
3908 for p in range(nPolarizations):
3909 if (corrTypeToString(corr_type[p]) in polsToPlot):
3910 pb.plot(pfrequencies[p], gamp[p], '%s%s'%(pcolor[p],ampmarkstyle), linewidth=width2, markersize=markersize,markeredgewidth=markeredgewidth)
3911 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
3912 for p in range(nPolarizations):
3913 if (corrTypeToString(corr_type[p]) in polsToPlot):
3914 pb.plot(pfrequencies2[p], gamp2[p], '%s%s'%(p2color[p],ampmarkstyle), linewidth=width1, markersize=markersize,markeredgewidth=markeredgewidth)
3915 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp2[p], sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
3916 # must set new limits after plotting 'amp'
3917 if (zoom=='intersect'):
3918 if (myxrange < xrange2):
3919 SetNewXLimits([min(xfrequencies[0],xfrequencies[-1])-myxrange*0.1, max(xfrequencies[0],xfrequencies[-1])+myxrange*0.1],2)
3920 SetLimits(plotrange, chanrange, newylimits, channels, frequencies,
3921 pfrequencies, ampMin, ampMax, xaxis, pxl, chanrangeSetXrange,
3922 chanrangePercent)
3923 else:
3924# # # # print("len(xfrequencies2) = ", len(xfrequencies2))
3925 SetNewXLimits([min(xfrequencies2[0],xfrequencies2[-1])-xrange2*0.1, max(xfrequencies2[0],xfrequencies2[-1])+xrange2*0.1],3)
3926 slstatus = SetLimits(plotrange, chanrange, newylimits, channels, frequencies2,
3927 pfrequencies2, ampMin, ampMax, xaxis, pxl, chanrangeSetXrange,
3928 chanrangePercent)
3929 else:
3930 if (myxrange < xrange2):
3931 SetLimits(plotrange, chanrange, newylimits, channels, frequencies,
3932 pfrequencies, ampMin, ampMax, xaxis, pxl, chanrangeSetXrange,
3933 chanrangePercent)
3934 else:
3935 SetLimits(plotrange, chanrange, newylimits, channels, frequencies2,
3936 pfrequencies2, ampMin, ampMax, xaxis, pxl, chanrangeSetXrange,
3937 chanrangePercent)
3938 # draw polarization and spw labels
3939 if (xframe == firstFrame):
3940 # draw title including caltable name
3941 caltableList = 'c1=' + caltable + ', c2=' + caltable2 # + ' (%s)'%(utstring(uniqueTimes2[mytime],3))
3942 pb.text(xstartTitle, ystartTitle, caltableList, size=titlesize,
3943 color='k', transform=pb.gcf().transFigure)
3944 elif (bpolyOverlay):
3945 if (debug):
3946 print("in bpolyOverlay **********************************")
3947 matches1 = []
3948 if tableFormat >= 34: ### added 2024Aug
3949 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
3950 else: ### added 2024Aug
3951 scansToPlotHere = scansToPlot ### added 2024Aug
3952 for tbp in range(len(timesBP)):
3953 if (sloppyMatch(uniqueTimes[mytime], timesBP[tbp], solutionTimeThresholdSeconds,
3954 mytime, scansToPlotHere, scansForUniqueTimes, # au version ### modified 2024Aug
3955 myprint=debugSloppyMatch
3956 )):
3957 matches1.append(tbp)
3958 matches1 = np.array(matches1)
3959 if (len(matches1) < 1):
3960 print("No time match found between %.1f and %s" % (uniqueTimes[mytime], str(timesBP)))
3961 print("If you are sure the solutions correspond to the same data, you can set solutionTimeThresholdSeconds>=%.0f" % (1+np.ceil(np.abs(timesBP[0]-uniqueTimes[mytime]))))
3962 return()
3963 matches2 = np.where(xant == np.array(antennasBP))[0]
3964 if (len(matches2) < 1):
3965 print("No antenna match found: %s" % (str(xant), str(antennasBP)))
3966 if (tableFormat == 33):
3967 matches3 = np.where(ispw == np.array(cal_desc_idBP))[0]
3968 if (len(matches3) < 1):
3969 print("No spw match found: %d not in %s" % (ispw, str(cal_desc_idBP)))
3970 else:
3971 matches3 = np.where(ispw == np.array(spwBP))[0]
3972 if (len(matches3) < 1):
3973 print("No spw match found: %d not in %s" % (ispw, str(spwBP)))
3974 matches12 = np.intersect1d(matches1,matches2)
3975 if (len(matches12) < 1):
3976 print("No time+antenna match between: %s and %s" % (str(matches1), str(matches2)))
3977 matches = np.intersect1d(matches12, matches3)
3978 if (len(matches) < 1):
3979 print("No time+antenna+spw match between: %s and %s" % (str(matches12), str(matches3)))
3980 try:
3981 index = matches[0]
3982 if (debug):
3983 print("Match = %d ***********************************" % (index))
3984 except:
3985 print("No match found for time=%.6f, xant=%d, ispw=%d" % (uniqueTimes[mytime],xant,ispw))
3986 print("antennasBP = %s" % (str(antennasBP)))
3987 print("cal_desc_idBP = %s" % (str(cal_desc_idBP)))
3988 timesBPstring = 'timesBP = '
3989 for i in timesBP:
3990 timesBPstring += "%.6f, " % i
3991 print(timesBPstring)
3992 return()
3993 validDomain = [frequencyLimits[0,index], frequencyLimits[1,index]]
3994 cc = calcChebyshev(polynomialAmplitude[index][0:nPolyAmp[index]], validDomain, frequenciesGHz[index]*1e+9)
3995 if (debug): print("Done calcChebyshev 1")
3996 fa = np.array(frequenciesGHz[index])
3997 if (xfrequencies[0] < xfrequencies[-1]):
3998 matches = np.where(fa>xfrequencies[0])[0]
3999 matches2 = np.where(fa<xfrequencies[-1])[0]
4000 else:
4001 matches = np.where(fa>xfrequencies[-1])[0]
4002 matches2 = np.where(fa<xfrequencies[0])[0]
4003 if (len(matches) < 1):
4004 print("looking for %f-%f GHz inside %f-%f" % (xfrequencies[0],xfrequencies[-1],fa[0],fa[-1]))
4005 amplitudeSolutionX = np.mean(gampx)*(cc-np.mean(cc)+1)
4007 cc = calcChebyshev(polynomialAmplitude[index][nPolyAmp[index]:2*nPolyAmp[index]], validDomain, frequenciesGHz[index]*1e+9)
4008 if (debug): print("Done calcChebyshev 2")
4009 if (nPolarizations > 1):
4010 if (yfrequencies[0] < yfrequencies[-1]):
4011 matches = np.where(fa>yfrequencies[0])[0]
4012 matches2 = np.where(fa<yfrequencies[-1])[0]
4013 else:
4014 matches = np.where(fa>yfrequencies[-1])[0]
4015 matches2 = np.where(fa<yfrequencies[0])[0]
4016 amplitudeSolutionY = np.mean(gampy)*(cc-np.mean(cc)+1)
4017 if (bpolyOverlay2):
4018 validDomain = [frequencyLimits2[0,index], frequencyLimits2[1,index]]
4019 cc = calcChebyshev(polynomialAmplitude2[index][0:nPolyAmp2[index]],
4020 validDomain, frequenciesGHz2[index]*1e+9)
4021 if (debug): print("Done calcChebyshev 3")
4022 fa = np.array(frequenciesGHz2[index])
4023 if (xfrequencies[0] < xfrequencies[-1]):
4024 matches = np.where(fa>xfrequencies[0])[0]
4025 matches2 = np.where(fa<xfrequencies[-1])[0]
4026 else:
4027 matches = np.where(fa>xfrequencies[-1])[0]
4028 matches2 = np.where(fa<xfrequencies[0])[0]
4029 amplitudeSolution2X = np.mean(gampx)*(cc-np.mean(cc)+1)
4031 cc = calcChebyshev(polynomialAmplitude2[index][nPolyAmp2[index]:2*nPolyAmp2[index]],
4032 validDomain, frequenciesGHz2[index]*1e+9)
4033 if (debug): print("Done calcChebyshev 4")
4034 fa = np.array(frequenciesGHz2[index])
4035 if (yfrequencies[0] < yfrequencies[-1]):
4036 matches = np.where(fa>yfrequencies[0])[0]
4037 matches2 = np.where(fa<yfrequencies[-1])[0]
4038 else:
4039 matches = np.where(fa>yfrequencies[-1])[0]
4040 matches2 = np.where(fa<yfrequencies[0])[0]
4041 amplitudeSolution2Y = np.mean(gampy)*(cc-np.mean(cc)+1)
4042 if (debug):
4043 print("Done mean(gampy)")
4044 for p in range(nPolarizations):
4045 if (corrTypeToString(corr_type[p]) in polsToPlot):
4046 pb.plot(pfrequencies[p], gamp[p],'%s%s'%(pcolor[p],ampmarkstyle), markersize=markersize,markeredgewidth=markeredgewidth)
4047 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4048 if (debug): print("Done newylimits")
4049 if (corrTypeToString(corr_type[0]) in polsToPlot):
4050 pb.plot(frequenciesGHz[index], amplitudeSolutionX,'%s%s'%(p2color[0],bpolymarkstyle),markeredgewidth=markeredgewidth)
4051 newylimits = recalcYlimitsFreq(chanrange, newylimits, amplitudeSolutionX, sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4052 pb.plot(frequenciesGHz2[index], amplitudeSolution2X, '%s%s'%(p3color[0],bpolymarkstyle),markeredgewidth=markeredgewidth)
4053 newylimits = recalcYlimitsFreq(chanrange, newylimits, amplitudeSolution2X, sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
4054 if (debug): print("Done newylimits2,3")
4055 if (nPolarizations == 2):
4056 if (debug): print("dualpol")
4057 if (corrTypeToString(corr_type[1]) in polsToPlot):
4058 pb.plot(frequenciesGHz[index], amplitudeSolutionY,'%s%s'%(p2color[1],bpolymarkstyle),markeredgewidth=markeredgewidth)
4059 if (debug): print("A")
4060 newylimits = recalcYlimitsFreq(chanrange, newylimits, amplitudeSolutionY, sideband,plotrange,ychannels,debug,12,chanrangePercent=chanrangePercent)
4061 if (debug): print("B")
4062 pb.plot(frequenciesGHz2[index], amplitudeSolution2Y, '%s%s'%(p3color[1],bpolymarkstyle),markeredgewidth=markeredgewidth)
4063 if (debug): print("C")
4064 newylimits = recalcYlimitsFreq(chanrange, newylimits, amplitudeSolution2Y, sideband,plotrange,ychannels2,debug,13,chanrangePercent=chanrangePercent)
4065 if (debug): print("Done this block")
4066 else:
4067 for p in range(nPolarizations):
4068 if (corrTypeToString(corr_type[p]) in polsToPlot):
4069 pb.plot(pfrequencies[p], gamp[p],'%s%s'%(pcolor[p],ampmarkstyle), markersize=markersize,markeredgewidth=markeredgewidth)
4070 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4071 if (corrTypeToString(corr_type[0]) in polsToPlot):
4072 pb.plot(frequenciesGHz[index], amplitudeSolutionX,'%s%s'%(p2color[0],bpolymarkstyle),markeredgewidth=markeredgewidth)
4073 newylimits = recalcYlimitsFreq(chanrange, newylimits, amplitudeSolutionX, sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4074 if (nPolarizations == 2):
4075 if (corrTypeToString(corr_type[1]) in polsToPlot):
4076 pb.plot(frequenciesGHz[index], amplitudeSolutionY,'%s%s'%(p2color[1],bpolymarkstyle),markeredgewidth=markeredgewidth)
4077 newylimits = recalcYlimitsFreq(chanrange, newylimits, amplitudeSolutionY, sideband,plotrange,ychannels,chanrangePercent=chanrangePercent)
4078 # endif (bpolyOverlay2)
4079 else:
4080 # we are not overlaying any B or polynomial solutions 'amp vs. freq'
4081 if (showflagged):
4082 # Also show the flagged data to see where the flags are
4083 for p in range(nPolarizations):
4084 if (corrTypeToString(corr_type[p]) in polsToPlot):
4085 if (overlayAntennas or overlayTimes):
4086 pdesc1 = pb.plot(pfrequencies[p], gamp[p], '%s'%ampmarkstyles[p], markersize=markersize,markeredgewidth=markeredgewidth)
4087 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4088 if (overlayAntennas and overlayTimes==False):
4089 pb.setp(pdesc1, color=overlayColors[xctr])
4090 elif (overlayTimes and overlayAntennas==False):
4091 pb.setp(pdesc1, color=overlayColors[mytime])
4092 elif (overlayTimes and overlayAntennas): # try to support antenna,time
4093 if (myUniqueTime != []):
4094 pb.setp(pdesc1, color=overlayColors[myUniqueTime])
4095 # The third 'or' below is needed if pol='0' is flagged on antenna 0. -- 2012/10/12 (original spot)
4096 if (p==0 or len(polsToPlot)==1 or myUniqueColor==[]):
4097 myUniqueColor.append(overlayColors[len(myUniqueColor)])
4098 pb.setp(pdesc1, color=myUniqueColor[-1])
4099 else:
4100 pb.plot(pfrequencies[p], gamp[p], '%s%s'%(pcolor[p],ampmarkstyles[p]), markersize=markersize,markeredgewidth=markeredgewidth)
4101 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4102 else: # showing only unflagged data 'amp vs. freq'
4103 for p in range(nPolarizations):
4104 if (debug):
4105 print("*p=%d, polsToPlot=%s, len(fieldsToPlot)=%d, len(timerangeList)=%d, myUniqueTime=%s" % (p,str(polsToPlot),len(fieldsToPlot),len(timerangeList), str(myUniqueTime)))
4106 if (corrTypeToString(corr_type[p]) in polsToPlot):
4107 if (len(gamp[p]) == 0): # Try this on Apr 2, 2012
4108# # # # print("=============== Skipping flagged data on antenna %d = %s" % (xant,antstring))
4109 continue
4110 if (overlayAntennas or overlayTimes):
4111 pdesc = pb.plot(pfrequencies[p], gamp[p], '%s'%ampmarkstyles[p], markersize=markersize,markeredgewidth=markeredgewidth)
4112 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4113 if (overlayAntennas and overlayTimes==False):
4114 pb.setp(pdesc, color=overlayColors[xctr])
4115 elif (overlayTimes and overlayAntennas==False):
4116 pb.setp(pdesc, color=overlayColors[mytime])
4117 elif (overlayTimes and overlayAntennas): # try to support antenna,time
4118 if (myUniqueTime != []):
4119 pb.setp(pdesc, color=overlayColors[myUniqueTime])
4120 # The third 'or' below is needed if pol='0' is flagged on antenna 0. -- 2012/10/12 (original spot)
4121 if (p==0 or len(polsToPlot)==1 or myUniqueColor==[]):
4122 myUniqueColor.append(overlayColors[len(myUniqueColor)])
4123 if (debug):
4124 print("myUniqueColor = %s" % (str(myUniqueColor)))
4125 pb.setp(pdesc, color=myUniqueColor[-1])
4126 elif (overlaySpws): # this elif block was missing prior to 2024Aug28
4127 mycolor = [xcolor,ycolor][p]
4128 linewidth = 1
4129 pdesc = pb.plot(pfrequencies[p], gamp[p], '%s'%(ampmarkstyles[0]), lw=linewidth, color=mycolor,
4130 markersize=markersize,markeredgewidth=markeredgewidth)
4131 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,
4132 plotrange,xchannels,debug,-18,chanrangePercent)
4133 else: # show unflagged solutions, no overlay
4134 if (corrTypeToString(corr_type[p]) in polsToPlot):
4135 # since there is no overlay, don't use dashed line, so zero ------v
4136 pdesc = pb.plot(pfrequencies[p], gamp[p], '%s%s'%(pcolor[p],ampmarkstyles[0]),markersize=markersize,markeredgewidth=markeredgewidth)
4137 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4138 # print("newylimits for amp = ", newylimits)
4139# if (debug): print("finished 'for' loop")
4140 if (sum(xflag)>0):
4141 # print("amp: Resetting xaxis frequency range to counteract flagged data")
4142 myxrange = np.max(frequencies)-np.min(frequencies)
4143 SetNewXLimits([np.min(frequencies)-0.15*myxrange, np.max(frequencies)+0.15*myxrange],4)
4145 if (1==1 or (xframe in bottomRowFrames) or (xctr+1==len(antennasToPlot) and ispw==spwsToPlot[-1])):
4146 # use 1==1 because spw might change between top row and bottom row of frames
4147 pb.xlabel(xlabelString, size=mysize)
4148 # endif (xaxis=='chan' elif xaxis=='freq' for 'amp')
4149 if (debug): print("finished 'if' block")
4150 if (overlayTimes):
4151 timeString =''
4152 else:
4153 if (len(uniqueTimes) > mytime):
4154 timeString = ', t%d/%d %s' % (mytime,nUniqueTimes-1,utstring(uniqueTimes[mytime],3))
4155 if (scansForUniqueTimes != []):
4156 if (scansForUniqueTimes[mytime]>=0):
4157 timeString = ', scan%d %s' % (scansForUniqueTimes[mytime],utstring(uniqueTimes[mytime],3))
4158 spwString = buildSpwString(overlaySpws, overlayBasebands,
4159 spwsToPlot, ispw, originalSpw[ispw],
4160 observatoryName, baseband,
4161 showBasebandNumber)
4162 if (overlayTimes and len(fieldsToPlot) > 1):
4163 indices = fstring = ''
4164 for f in fieldIndicesToPlot:
4165 if (f != fieldIndicesToPlot[0]):
4166 indices += ','
4167 fstring += ','
4168 indices += str(uniqueFields[f])
4169 if (msFound):
4170 fstring += msFields[uniqueFields[f]]
4171 if (len(fstring) > fstringLimit):
4172 fstring = fstring[0:fstringLimit] + '...'
4173 titleString = "%sspw%s, fields %s: %s%s" % (antennaString,spwString,
4174 indices, fstring, timeString)
4175 else:
4176 titleString = "%sspw%s, field %d: %s%s" % (antennaString,spwString,uniqueFields[fieldIndex],
4177 fieldString,timeString)
4178 tsize = titlesize-int(len(titleString)//(maxCharsBeforeReducingTitleFontSize//subplotCols))
4179 pb.title(titleString, size=tsize)
4180 if (abs(plotrange[0]) > 0 or abs(plotrange[1]) > 0):
4181 SetNewXLimits([plotrange[0],plotrange[1]],5)
4182 else:
4183 # Here is 1st place where we eliminate white space on right and left edge of the plots: 'amp'
4184 if (xaxis.find('chan')>=0):
4185 SetNewXLimits([channels[0],channels[-1]],6)
4186 else:
4187 if (zoom != 'intersect'):
4188 if (overlaySpws or overlayBasebands):
4189 SetNewXLimits(frequencyRangeToPlotInBaseband[bbctr],7)
4190 else:
4191 SetNewXLimits([frequencies[0], frequencies[-1]],8)
4192 if (bOverlay):
4193 if (xrange2 > myxrange+0.1 and zoom != 'intersect'):
4194 TDMisSecond = True
4195 if (abs(plotrange[2]) > 0 or abs(plotrange[3]) > 0):
4196 SetNewYLimits([plotrange[2],plotrange[3]])
4198 xlim = pb.xlim()
4199 ylim = pb.ylim()
4200 ResizeFontsSetGrid(adesc,mysize)
4201 pb.ylabel(yAmplitudeLabel, size=mysize)
4202 pb.subplots_adjust(hspace=myhspace, wspace=mywspace)
4203 myxrange = xlim[1]-xlim[0]
4204 yrange = ylim[1]-ylim[0]
4205 if (debug): print(("amp: ylim, yrange = ", ylim, yrange))
4206 if (overlayAntennas == False and overlayTimes == False and bOverlay == False and
4207 ((overlaySpws == False and overlayBasebands == False) or spwctr==spwctrFirstToPlot)):
4208 # draw polarization labels for no overlay, or overlaySpws/overlayBasebands
4209 x0 = xstartPolLabel
4210 y0 = ystartPolLabel
4211 for p in range(nPolarizations):
4212 if (corrTypeToString(corr_type[p]) in polsToPlot):
4213 if spwctr==spwctrFirstToPlot or (not overlaySpws and not overlayBasebands):
4214 # no need to plot it more than once in the same position
4215 pb.text(x0, y0-subplotRows*p*0.03, corrTypeToString(corr_type[p]),
4216 color=pcolor[p],size=mysize, transform=pb.gca().transAxes)
4217 if (channeldiff > 0):
4218 pb.text(x0, ystartMadLabel-0.03*subplotRows*p,
4219 corrTypeToString(corr_type[p])+' MAD = %.4f, St.Dev = %.4f'%(gamp_mad[p]['mad'],gamp_std[p]['std']),
4220 color=pcolor[p],size=mysize, transform=pb.gca().transAxes)
4221 if (xframe == firstFrame):
4222 # draw title including caltable name
4223 caltableList = caltableTitle
4224 if (bpolyOverlay):
4225 caltableList += ', ' + caltable2 + ' (degamp=%d, degphase=%d)'%(nPolyAmp[index]-1,nPolyPhase[index]-1)
4226 if (bpolyOverlay2):
4227 caltableList += ', ' + caltable3 + ' (degamp=%d, degphase=%d)'%(nPolyAmp2[index]-1,nPolyPhase2[index]-1)
4228 pb.text(xstartTitle, ystartTitle, caltableList, size=titlesize,
4229 color='k', transform=pb.gcf().transFigure)
4231 elif (overlayAntennas==True and xant==antennasToPlot[-1] and bOverlay == False # ):
4232 and overlayTimes==False): # try to support antenna,time avoid antenna labels 'amp'
4233 # We do this last, because by then, the limits will be stable.
4234 if (debug): print("overlayAntennas=True")
4235 DrawAntennaNamesForOverlayAntennas(xstartPolLabel, ystartPolLabel, polsToPlot, corr_type, channeldiff, ystartMadLabel, subplotRows, gamp_mad, gamp_std, overlayColors, mysize, ampmarkstyle, markersize, markeredgewidth, msAnt, msFound, antennasToPlot, ampmarkstyle2, xframe, firstFrame, caltableTitle, titlesize)
4236 elif (overlayTimes==True and bOverlay == False
4237 and overlayAntennas==False): # try to support antenna,time
4238 doneOverlayTime = True # assumed until proven otherwise in the 'for' loop
4239 for f in fieldIndicesToPlot:
4240 if (len(uniqueTimesPerFieldPerSpw[ispwInCalTable][f]) > 0):
4241 # this spw/field combination had some entries plotted
4242 if ((uniqueTimes[mytime] < uniqueTimesPerFieldPerSpw[ispwInCalTable][f][-1]-solutionTimeThresholdSeconds) and
4243 (uniqueTimes[mytime] < timerangeListTimes[-1])):
4244 if tableFormat >= 34: #### added 2024Aug
4245 if scansForUniqueTimes[mytime] not in [scansForUniqueTimes[-1],scansToPlot[-1]] and mytime != timerangeList[-1]: # fix for CAS-14096: if we are on the final time then we are done; and add support for specifying a limited set of timeranges via the timeranges parameter ### added 2024Aug
4246 if (debug):
4247 print("-----------Not done because %.0f < %.0f-%d for fieldIndex=%d and <%.0f and scan%d not in scan[%d,%d] and t%d != t%d" % (uniqueTimes[mytime], uniqueTimesPerFieldPerSpw[ispwInCalTable][f][-1], solutionTimeThresholdSeconds, f, timerangeListTimes[-1],scansForUniqueTimes[mytime],scansForUniqueTimes[-1],scansToPlot[-1],mytime,timerangeList[-1]))
4248 print("-----------ispwInCalTable=%d, mytime=%d, len(uniqueTimes) = %d" % (ispwInCalTable, mytime, len(uniqueTimes)))
4249 doneOverlayTime = False
4250 else: #### added 2024Aug
4251 doneOverlayTime = False #### added 2024Aug
4252 if (debug):
4253 print("------doneOverlayTime = %s on mytime %d" % (str(doneOverlayTime),mytime))
4254 if (doneOverlayTime):
4255 # either it is the last time of any times in solution, or the last time in the list of times to plot
4256 if (debug):
4257 print("*** on last time = %d for last fieldIndex %d or %d>=%d" % (mytime,fieldIndex,mytime,timerangeList[-1]))
4258 mytime = nUniqueTimes-1
4259 # We do this last, because by then, the limits will be broad enought and stable.
4260 # draw polarization labels
4261 DrawPolarizationLabelsForOverlayTime(xstartPolLabel,ystartPolLabel,corr_type,polsToPlot,
4262 channeldiff,ystartMadLabel,subplotRows,gamp_mad,mysize,
4263 ampmarkstyle,markersize,ampmarkstyle2, gamp_std)
4264 if (xframe == firstFrame):
4265 # draw title including caltable name
4266 pb.text(xstartTitle, ystartTitle, caltableTitle, size=titlesize,
4267 color='k', transform=pb.gcf().transFigure)
4268 if tableFormat >= 34: ### added 2024Aug
4269 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
4270 else: ### added 2024Aug
4271 scansToPlotHere = scansToPlot ### added 2024Aug
4272 if (debug): print("drawOverlayTimeLegends loc 2")
4273 drawOverlayTimeLegends(xframe, firstFrame, xstartTitle, ystartTitle,
4274 caltable, titlesize, fieldIndicesToPlot,
4275 ispwInCalTable, uniqueTimesPerFieldPerSpw,
4276 timerangeListTimes, solutionTimeThresholdSeconds,
4277 debugSloppyMatch, ystartOverlayLegend, debug, mysize,
4278 fieldsToPlot, myUniqueColor,timeHorizontalSpacing,
4279 fieldIndex, overlayColors, antennaVerticalSpacing,
4280 overlayAntennas, timerangeList, caltableTitle,
4281 mytime, scansToPlotHere, scansForUniqueTimes,
4282 uniqueSpwsInCalTable, uniqueTimes) ### modified 2024Aug
4283 elif (overlayAntennas and overlayTimes): # Oct 23, 2012
4284 # This will only happen for overlay='antenna,time'
4285 if (xframe == firstFrame and mytime == firstTimeMatch and xctr==firstUnflaggedAntennaToPlot and bOverlay==False): # bug fix on 2015-08-19 for CAS-7820
4286 # draw title including caltable name
4287 pb.text(xstartTitle, ystartTitle, caltableTitle, size=titlesize, color='k',
4288 transform=pb.gcf().transFigure)
4289 DrawBottomLegendPageCoords(msName, uniqueTimes[mytime], mysize, figfile)
4290 # Adding the following 'for' loop on Mar 13, 2013 to support the case of
4291 # single time range with overlay='antenna,time'
4292 if (xant==antennasToPlot[-1]):
4293 doneOverlayTime = True # assumed until proven otherwise in the 'for' loop
4294 for f in fieldIndicesToPlot:
4295 if (len(uniqueTimesPerFieldPerSpw[ispwInCalTable][f]) > 0):
4296 if ((uniqueTimes[mytime] < uniqueTimesPerFieldPerSpw[ispwInCalTable][f][-1]-solutionTimeThresholdSeconds) and
4297 (uniqueTimes[mytime] < timerangeListTimes[-1])):
4298 if tableFormat >= 34: #### added 2024Aug
4299# if (scansForUniqueTimes[mytime] != scansForUniqueTimes[-1]) #### added 2024Aug (fix for CAS-14096): if we are on the final time then we are done
4300 if scansForUniqueTimes[mytime] != scansForUniqueTimes[-1] and mytime != timerangeList[-1]: # fix for CAS-14096: if we are on the final time then we are done; and add support for specifying a limited set of timeranges via the timeranges parameter ### added 2024Aug
4301 if (debug):
4302 print("-----------Not done because %.0f < %.0f-%d for fieldIndex=%d and <%.0f" % (uniqueTimes[mytime], uniqueTimesPerFieldPerSpw[ispwInCalTable][f][-1], solutionTimeThresholdSeconds, f, timerangeListTimes[-1]))
4303 print("-----------ispwInCalTable=%d, mytime=%d, len(uniqueTimes) = %d" % (ispwInCalTable, mytime, len(uniqueTimes)))
4304 doneOverlayTime = False
4305 else: #### added 2024Aug
4306 doneOverlayTime = False #### added 2024Aug
4307 if (doneOverlayTime):
4308 # This is necessary for the case that no antennas were flagged for the single timerange selected
4309 if (debug): print("drawOverlayTimeLegends loc 3")
4310 drawOverlayTimeLegends(xframe,firstFrame,xstartTitle,ystartTitle,caltable,titlesize,
4311 fieldIndicesToPlot,ispwInCalTable,uniqueTimesPerFieldPerSpw,
4312 timerangeListTimes, solutionTimeThresholdSeconds,
4313 debugSloppyMatch,ystartOverlayLegend,debug,mysize,
4314 fieldsToPlot,myUniqueColor,timeHorizontalSpacing,
4315 fieldIndex, overlayColors, antennaVerticalSpacing,
4316 overlayAntennas, timerangeList, caltableTitle,
4317 mytime, scansToPlotPerSpw[ispw], scansForUniqueTimes,
4318 uniqueSpwsInCalTable, uniqueTimes)
4320 # endif / elif / elif / elif
4322 if (debug): print("####### 2nd place")
4323 # Here is 2nd place where we eliminate any white space on the right and left edge of the plots: 'amp'
4324 #
4325 if (abs(plotrange[2]) > 0 or abs(plotrange[3]) > 0):
4326 SetNewYLimits([plotrange[2],plotrange[3]])
4327 if (plotrange[0]==0 and plotrange[1]==0):
4328 if (xaxis.find('chan')>=0):
4329 SetNewXLimits([channels[0],channels[-1]],9)
4330 else:
4331 if (zoom != 'intersect'):
4332 if (overlaySpws or overlayBasebands):
4333 SetNewXLimits(frequencyRangeToPlotInBaseband[bbctr],10)
4334 else:
4335 SetNewXLimits([frequencies[0], frequencies[-1]],11)
4336 if (bOverlay):
4337# # # # print("Checking if %f >= %f" % (xrange2, myxrange))
4338 if (xrange2 >= myxrange and zoom != 'intersect'):
4339 # This is necessary if caltable2=TDM and caltable=FDM
4340 SetNewXLimits([frequencies2[0], frequencies2[-1]],12)
4341 if (xrange2 > myxrange+0.1 and zoom != 'intersect'):
4342 TDMisSecond = True
4343 else:
4344 SetNewXLimits([plotrange[0], plotrange[1]],13)
4345 if (debug): print("done SetNewXLimits")
4347 # I need the following line for chanrange to work
4348 if (chanrange[0] != 0 or chanrange[1] != 0 or chanrangePercent != None):
4349 SetLimits(plotrange, chanrange, newylimits, channels, frequencies, pfrequencies,
4350 ampMin, ampMax, xaxis,pxl, chanrangeSetXrange,
4351 chanrangePercent)
4353 # Finally, draw the atmosphere and FDM windows, if requested. 'amp'
4354 if ((overlayAntennas==False and overlayTimes==False) or
4355 (overlayAntennas==True and overlayTimes==False and xant==antennasToPlot[-1]) or
4356 (overlayTimes==True and overlayAntennas==False and doneOverlayTime) or
4357 (overlayTimes and overlayAntennas and # Aug 5, 2013
4358 xant==antennasToPlot[-1] and doneOverlayTime and mytime==finalTimeMatch # 2015-08-19 for CAS-7820
4359 and not drewAtmosphere) # added on 2014-12-04 to support case of a flagged antenna CAS-7187
4360 ):
4361 if ((showatm or showtsky) and len(atmString) > 0):
4362 DrawAtmosphere(showatm, showtsky, subplotRows, atmString,
4363 mysize, TebbSky, plotrange, xaxis, atmchan,
4364 atmfreq, transmission, subplotCols,
4365 showatmPoints=showatmPoints, xframe=xframe,
4366 channels=channels,mylineno=lineNumber(),
4367 overlaySpws=overlaySpws,
4368 overlayBasebands=overlayBasebands,
4369 drewAtmosphere=drewAtmosphere,loc=203,
4370 showtsys=showtsys, Trx=Trx)
4371 if (LO1):
4372 # Now draw the image band
4373 DrawAtmosphere(showatm,showtsky, subplotRows, atmString,
4374 mysize, TebbSkyImage, plotrange, xaxis,
4375 atmchanImage, atmfreqImage, transmissionImage,
4376 subplotCols, LO1, xframe, firstFrame,
4377 showatmPoints,
4378 channels=channels,mylineno=lineNumber(),
4379 overlaySpws=overlaySpws,
4380 overlayBasebands=overlayBasebands,
4381 drewAtmosphere=drewAtmosphere,loc=204,
4382 showtsys=showtsys, Trx=Trx)
4383 drewAtmosphere = True
4384 if (xaxis.find('freq')>=0 and showfdm and nChannels <= 256):
4385 if (tableFormat == 33):
4386 showFDM(originalSpw_casa33, chanFreqGHz_casa33, baseband, showBasebandNumber, basebandDict, overlayColors)
4387 else:
4388 showFDM(originalSpw, chanFreqGHz, baseband, showBasebandNumber, basebandDict, overlayColors)
4389 if (debug): print("done drawAtmosphere/FDM check")
4391 if (bOverlay):
4392 # draw polarization labels
4393 x0 = xstartPolLabel
4394 y0 = ystartPolLabel
4395 for p in range(nPolarizations):
4396 if (corrTypeToString(corr_type[p]) in polsToPlot):
4397 pb.text(x0, y0-p*0.03*subplotRows, corrTypeToString(corr_type[p])+'-c1',
4398 color=pcolor[p],size=mysize,transform=pb.gca().transAxes)
4399 pb.text(x0, y0-p*0.03*subplotRows-0.06*subplotRows, corrTypeToString(corr_type[p])+'-c2',
4400 color=p2color[p],size=mysize,transform=pb.gca().transAxes)
4401 if (debug): print("done pol labels")
4402 if (bpolyOverlay and xaxis.find('freq')>=0):
4403 # draw polarization labels
4404 x0 = xstartPolLabel
4405 y0 = ystartPolLabel
4406 if (x2color != xcolor):
4407 for p in range(nPolarizations):
4408 if (corrTypeToString(corr_type[0]) in polsToPlot):
4409 pb.text(x0+0.1, y0-p*0.03*subplotRows, corrTypeToString(corr_type[p]), color=p2color[p],
4410 size=mysize,transform=pb.gca().transAxes)
4411 if (bpolyOverlay2):
4412 for p in range(nPolarizations):
4413 if (corrTypeToString(corr_type[0]) in polsToPlot):
4414 pb.text(x0+0.2, y0-p*0.03*subplotRows, corrTypeToString(corr_type[p]),
4415 color=p3color[p], size=mysize,transform=pb.gca().transAxes)
4417 myIndexTime = uniqueTimesPerFieldPerSpw[ispwInCalTable][fieldIndex][-1]
4418 if (debug): print("running sloppyMatch")
4419 if tableFormat >= 34: ### added 2024Aug
4420 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
4421 else: ### added 2024Aug
4422 scansToPlotHere = scansToPlot ### added 2024Aug
4423 matched,mymatch = sloppyMatch(myIndexTime,uniqueTimes,solutionTimeThresholdSeconds,
4424 mytime, scansToPlotHere, ### modified 2024Aug
4425 scansForUniqueTimes,
4426 whichone=True,myprint=debug)
4427 if (debug):
4428 print("1)done sloppyMatch, mytime=%d, scansForUniqueTimes=%s" % (mytime,str(scansForUniqueTimes)))
4429 print("ispw=%d" % (ispw))
4430 print("len(scansToPlotPerSpw)=%d" % (len(scansToPlotPerSpw)))
4431 if (matched == False and scansForUniqueTimes[mytime] in scansToPlotPerSpw[ispw]):
4432 print("---------- 1) Did not find %f in %s" % (myIndexTime,str(uniqueTimes)))
4433 print("Try re-running with a smaller solutionTimeThresholdSeconds (currently %f)" % (solutionTimeThresholdSeconds))
4434 return
4435 else:
4436 # we are on the final time to be plotted
4437 if (debug): print("on the final time")
4438 mytimeTest = mytime==nUniqueTimes-1 # mytime==myIndexTime # mytime==mymatch
4439 if ((xframe == 111 and amplitudeWithPhase) or
4440 # Following case is needed to make subplot=11 to work for: try to support overlay='antenna,time'
4441 (xframe == lastFrame and overlayTimes and overlayAntennas and
4442 xctr+1==len(antennasToPlot) and
4443 mytimeTest and
4444 spwctr<len(spwsToPlot))): # removed +1 from spwctr+1 on 2014-04-05 to match au
4445 if (debug):
4446 print("xframe=%d == lastFrame=%d, amplitudeWithPhase=%s" % (xframe, lastFrame, str(amplitudeWithPhase)))
4447 print("xctr+1=%d == len(antennasToPlot)=%d" % (xctr+1,len(antennasToPlot)))
4448 print("mytime+1=%d == len(uniqueTimes)=%d" % (mytime+1,len(uniqueTimes)))
4449 print("spwctr+1=%d < len(spwsToPlot)=%d" % (spwctr+1,len(spwsToPlot)))
4450 if (len(figfile) > 0):
4451 plotfiles.append(makeplot(figfile,msFound,msAnt,
4452 overlayAntennas,pages,pagectr,
4453 density,interactive,antennasToPlot,
4454 spwsToPlot,overlayTimes,overlayBasebands,
4455 3,xant,ispw,subplot,resample,
4456 debug,figfileSequential,figfileNumber))
4457 figfileNumber += 1
4459 donetime = time.time()
4460 drewAtmosphere = False # needed for CAS-7187 (subplot=11)
4461 if (interactive):
4462 pb.draw()
4463 myinput = input("Press return for next page (b for backwards, q to quit): ")
4464 else:
4465 myinput = ''
4466 skippingSpwMessageSent = 0
4467 mytimestamp = time.time()
4468 if (myinput.find('q') >= 0):
4469 showFinalMessage(overlayAntennas, solutionTimeSpread, nUniqueTimes)
4470 return()
4471 if (myinput.find('b') >= 0):
4472 if (pagectr > 0):
4473 if (debug):
4474 print("Decrementing pagectr from %d to %d" % (pagectr, pagectr-1))
4475 pagectr -= 1
4476 else:
4477 if (debug):
4478 print("Not decrementing pagectr=%d" % (pagectr))
4480 redisplay = True
4481 #redisplay the current page by setting ctrs back to the value they had at start of that page
4482 xctr = pages[pagectr][PAGE_ANT]
4483 spwctr = pages[pagectr][PAGE_SPW]
4484 mytime = pages[pagectr][PAGE_TIME]
4485 myap = pages[pagectr][PAGE_AP]
4486 xant = antennasToPlot[xctr]
4487 antstring, Antstring = buildAntString(xant,msFound,msAnt)
4488 ispw = spwsToPlot[spwctr]
4489# # # # print("Returning to [%d,%d,%d,%d]" % (xctr,spwctr,mytime,myap))
4490 if (xctr==pages[0][PAGE_ANT] and spwctr==pages[0][PAGE_SPW] and mytime==pages[0][PAGE_TIME] and pages[0][PAGE_AP]==myap):
4491 safe_pb_clf()
4492 if (debug):
4493 print("2)Setting xframe to %d" % xframeStart)
4494 xframe = xframeStart
4495 myUniqueColor = []
4496 continue
4497 else:
4498 pagectr += 1
4499 if (pagectr >= len(pages)):
4500 if (xframe == lastFrame and overlayTimes and overlayAntennas and xctr+1==len(antennasToPlot) and
4501 yaxis=='amp'):
4502 # I'm not sure why this works, but is needed to fix CAS-7154
4503 myspwctr = spwctr+1
4504 else:
4505 myspwctr = spwctr
4506 pages.append([xctr,myspwctr,mytime,1])
4507 if (debug):
4508 print("amp: appending [%d,%d,%d,%d]" % (xctr,myspwctr,mytime,1))
4509 newpage = 0
4510 safe_pb_clf()
4511 if (debug):
4512 print("3)Setting xframe to %d" % xframeStart)
4513 xframe = xframeStart
4514 myUniqueColor = []
4515 else:
4516 if (debug):
4517 print("::: Not done page: Not checking whether we need to set xframe=xframeStart")
4518 print("::: xframe=%d ?= lastFrame=%d, amplitudeWithPhase=" % (xframe, lastFrame), amplitudeWithPhase)
4519 print("::: xctr+1=%d ?= len(antennasToPlot)=%d" % (xctr+1,len(antennasToPlot)))
4520 print(":::: mytimeTest = %s" % (mytimeTest))
4521 print("::: spwctr=%d ?< len(spwsToPlot)=%d" % (spwctr,len(spwsToPlot)))
4522###########################################################
4523################### Here is the phase plotting ############
4524###########################################################
4525 if (yaxis.find('phase')>=0 or amplitudeWithPhase) and doneOverlayTime==False:
4526 if (channeldiff > 0):
4527 pchannels = [xchannels,ychannels] # this is necessary because np.diff reduces nchan by 1
4528 pfrequencies = [xfrequencies,yfrequencies] # this is necessary because np.diff reduces nchan by 1
4529 if (bOverlay):
4530 pchannels2 = [xchannels2,ychannels2] # this is necessary because np.diff reduces nchan by 1
4531 pfrequencies2 = [xfrequencies2,yfrequencies2] # this is necessary because np.diff reduces nchan by 1
4532 if (overlayTimes == False or mytime==firstTimeMatch):
4533 if ((overlaySpws == False and overlayBasebands==False) or spwctr==spwctrFirstToPlot or
4534 spwctr>spwsToPlot[-1] or
4535 (overlayBasebands and amplitudeWithPhase)): # CAS-6477
4536 if (overlayAntennas==False or xctr==firstUnflaggedAntennaToPlot
4537 or xctr>antennasToPlot[-1]): # 2012-05-24, to fix the case where all ants flagged on one timerange
4538 xframe += 1
4539 if debug:
4540 print("u) incrementing xframe to %d" % xframe)
4541 myUniqueColor = []
4542 newylimits = [LARGE_POSITIVE, LARGE_NEGATIVE]
4543 if (phase != ''):
4544 if ((phase[0] != 0 or phase[1] != 0) and amplitudeWithPhase):
4545 newylimits = phase
4546 if (debug):
4547 print("$$$$$$$$$$$$$$$$$$$$$$$ ready to plot phase on xframe %d" % (xframe))
4550 if (previousSubplot != xframe):
4551 adesc = safe_pb_subplot(xframe) # avoid deprecation warning in CASA6 when xframe already was opened
4552 drewAtmosphere = False
4553 previousSubplot = xframe
4554 gphsx = np.arctan2(np.imag(gplotx),np.real(gplotx))*180.0/math.pi
4555 if (nPolarizations == 2):
4556 gphsy = np.arctan2(np.imag(gploty),np.real(gploty))*180.0/math.pi
4557 if (channeldiff>0):
4558 if (xaxis == 'chan'):
4559 gphs0, newx0, gphs0res, newx0res = channelDifferences(gphsx, pchannels[0], resample)
4560 gphs1, newx1, gphs1res, newx1res = channelDifferences(gphsy, pchannels[1], resample)
4561 pchannels = [newx0,newx1]
4562 else:
4563 gphs0, newx0, gphs0res, newx0res = channelDifferences(gphsx, pfrequencies[0], resample)
4564 gphs1, newx1, gphs1res, newx1res = channelDifferences(gphsy, pfrequencies[1], resample)
4565 pfrequencies = [newx0,newx1]
4566 gphs = [gphs0, gphs1]
4567 gphsres = [gphs0res, gphs1res]
4568 gphs_mad = [madInfo(gphs[0],madsigma,edge), madInfo(gphs[1],madsigma,edge)]
4569 gphs_std = [stdInfo(gphsres[0],madsigma,edge,ispw,xant,0), stdInfo(gphsres[1],madsigma,edge,ispw,xant,1)]
4570 for p in [0,1]:
4571 madstats[Antstring][ispw][mytime][p]['phase'] = gphs_mad[p]['mad']
4572 madstats[Antstring][ispw][mytime][p]['phasestd'] = gphs_std[p]['std']
4573 if (gphs_mad[p]['nchan'] > 0):
4574 checkAbsSum = np.sum(np.abs(gphs[p]))
4575 if (checkAbsSum < PHASE_ABS_SUM_THRESHOLD):
4576 if (debug): print("%s, Pol %d, spw %d, %s, phs: not printing because abs sum of all values near zero (%f)" % (Antstring, p, ispw, utstring(uniqueTimes[mytime],0), checkAbsSum))
4577 else:
4578 casalogPost(debug, "%s, Pol %d, spw %2d, %s, phs: %4d points exceed %.1f sigma (worst=%.2f at chan %d)" % (Antstring, p, ispw, utstring(uniqueTimes[mytime],0), gphs_mad[p]['nchan'], madsigma, gphs_mad[p]['outlierValue'], gphs_mad[p]['outlierChannel']+pchannels[p][0]))
4579 else:
4580 gphs = [gphsx,gphsy]
4581 else: # 1-pol
4582 if (channeldiff>0):
4583 if (xaxis == 'chan'):
4584 gphs0, newx0, gphs0res, newx0res = channelDifferences(gphsx, pchannels[0], resample)
4585 pchannels = [newx0]
4586 else:
4587 gphs0, newx0, gphs0res, newx0res = channelDifferences(gphsx, pfrequencies[0], resample)
4588 pfrequencies = [newx0]
4589 gphs = [gphs0]
4590 gphsres = [gphs0res]
4591 p = 0
4592 gphs_mad = [madInfo(gphs[p], madsigma, edge)]
4593 gphs_std = [stdInfo(gphsres[p], madsigma, edge, ispw,xant,p)]
4594 madstats[Antstring][ispw][mytime][p]['phase'] = gphs_mad[p]['mad']
4595 madstats[Antstring][ispw][mytime][p]['phasestd'] = gphs_mad[p]['std']
4596 if (gphs_mad[p]['nchan'] > 0):
4597 checkAbsSum = np.sum(np.abs(gphs[p]))
4598 if (checkAbsSum < PHASE_ABS_SUM_THRESHOLD):
4599 if (debug): print("%s, Pol %d, spw %d, %s, phs: not printing because all values near zero (%f)" % (Antstring, p, ispw, utstring(uniqueTimes[mytime],0), checkAbsSum))
4600 else:
4601 casalogPost(debug, "%s, Pol %d, spw %2d, %s, phs: %4d points exceed %.1f sigma (worst=%.2f at chan %d)" % (Antstring, p, ispw, utstring(uniqueTimes[mytime],0), gphs_mad[p]['nchan'], madsigma, gphs_mad[p]['outlierValue'], gphs_mad[p]['outlierChannel']+pchannels[p][0]))
4602 else:
4603 gphs = [gphsx]
4604 if (bOverlay):
4605 if (debug):
4606 print("computing phase for second table")
4607 gphsx2 = np.arctan2(np.imag(gplotx2),np.real(gplotx2))*180.0/math.pi
4608 if (nPolarizations == 2):
4609 gphsy2 = np.arctan2(np.imag(gploty2),np.real(gploty2))*180.0/math.pi
4610 if (channeldiff>0):
4611 if (xaxis == 'chan'):
4612 gphs2_0, newx0, gphs2_0res, newx0res = channelDifferences(gphsx2, pchannels2[0], resample)
4613 gphs2_1, newx1, gphs2_1res, newx1res = channelDifferences(gphsy2, pchannels2[1], resample)
4614 pchannels2 = [newx0, newx1]
4615 else:
4616 gphs2_0, newx0, gphs2_0res, newx0res = channelDifferences(gphsx2, pfrequencies2[0], resample)
4617 gphs2_1, newx1, gphs2_1res, newx1res = channelDifferences(gphsy2, pfrequencies2[1], resample)
4618 pfrequencies2 = [newx0, newx1]
4619 gphs2 = [gphs2_0, gphs2_1]
4620 gphs2res = [gphs2_0res, gphs2_1res]
4621 else:
4622 gphs2 = [gphsx2, gphsy2]
4623 else:
4624 if (channeldiff>0):
4625 if (xaxis == 'chan'):
4626 gphs2_0, newx0, gphs2_0res, newx0res = channelDifferences(gphsx2, pchannels2[0], resample)
4627 pchannels2 = [newx0]
4628 else:
4629 gphs2_0, newx0, gphs2_0res, newx0res = channelDifferences(gphsx2, pfrequencies2[0], resample)
4630 pfrequencies2 = [newx0]
4631 gphs2 = [gphs2_0]
4632 gphs2res = [gphs2_0res]
4633 else:
4634 gphs2 = [gphsx2]
4635 else:
4636 if (debug):
4637 print("bOverlay is FALSE ===========================")
4639 if (xaxis.find('chan')>=0 or len(xfrequencies) < 1): # 'phase'
4640 for p in range(nPolarizations):
4641 if (corrTypeToString(corr_type[p]) in polsToPlot):
4642 if (overlayAntennas or overlayTimes):
4643 pdesc = pb.plot(pchannels[p],gphs[p],'%s'%(phasemarkstyles[p]),markersize=markersize,markeredgewidth=markeredgewidth)
4644 newylimits = recalcYlimits(plotrange,newylimits,gphs[p]) # 10/27/2011
4645 if (newylimits[1]-newylimits[0] < minPhaseRange):
4646 newylimits = [-minPhaseRange,minPhaseRange]
4647 if (phase != ''):
4648 if ((phase[0] != 0 or phase[1] != 0) and amplitudeWithPhase):
4649 newylimits = phase
4651 if (overlayAntennas and overlayTimes==False):
4652 pb.setp(pdesc, color=overlayColors[xctr])
4653 elif (overlayTimes and overlayAntennas==False):
4654 pb.setp(pdesc, color=overlayColors[mytime])
4655 elif (overlayTimes): # try to support antenna,time
4656 if (myUniqueTime != []):
4657 pb.setp(pdesc, color=overlayColors[myUniqueTime])
4658 # The third 'or' below is needed if pol='0' is flagged on antenna 0. -- 2012/10/12 (original spot)
4659 if (p==0 or len(polsToPlot)==1 or myUniqueColor==[]):
4660 myUniqueColor.append(overlayColors[len(myUniqueColor)])
4661 pb.setp(pdesc, color=myUniqueColor[-1])
4662 else:
4663 pb.plot(pchannels[p],gphs[p],'%s%s'%(pcolor[p],phasemarkstyles[0]), markersize=markersize,markeredgewidth=markeredgewidth)
4664 newylimits = recalcYlimits(plotrange,newylimits,gphs[p]) # 10/27/2011
4665 if (newylimits[1]-newylimits[0] < minPhaseRange):
4666 newylimits = [-minPhaseRange,minPhaseRange]
4667 if (phase != ''):
4668 if ((phase[0] != 0 or phase[1] != 0) and amplitudeWithPhase):
4669 newylimits = phase
4670 if (sum(xflag)>0):
4671# # # # print("phase: Resetting xaxis channel range to counteract flagged data")
4672 myxrange = np.max(channels)-np.min(channels)
4673 SetNewXLimits([np.min(channels)-myxrange/20,
4674 np.max(channels)+myxrange/20],14)
4675 if (xframe in bottomRowFrames or (xctr+1==len(antennasToPlot) and ispw==spwsToPlot[-1])):
4676 pb.xlabel("Channels (%d)"%(len(pchannels[p])), size=mysize) ### changed 2024Aug24
4677 elif (xaxis.find('freq')>=0): # 'phase'
4678 if (bOverlay):
4679 if (debug):
4680 p = 0 ### added 2024Aug to prevent crash due to undefined variable
4681 print("Preparing to plot phase from %f-%f for pols: %s" % (xfrequencies[0],xfrequencies[-1],str(polsToPlot)))
4682 print("Preparing to plot phase from %f-%f for pols: %s" % (pfrequencies[p][0],pfrequencies[p][-1],str(polsToPlot)))
4683 print("Preparing to plot phase from %f-%f for pols: %s" % (pfrequencies2[p][0],pfrequencies2[p][-1],str(polsToPlot)))
4684 myxrange = np.abs(xfrequencies[0]-xfrequencies[-1])
4685 try:
4686 xrange2 = np.abs(xfrequencies2[0]-xfrequencies2[-1])
4687 except:
4688 print("No phase data found in second solution. Try increasing the solutionTimeThresholdSeconds above %.0f." % (solutionTimeThresholdSeconds))
4689 print("If this doesn't work, email the developer (%s)." % (developerEmail))
4690 return()
4691 if (np.abs(myxrange/xrange2 - 1) > 0.05 + len(xflag)//len(xchannels)): # 0.0666 is 2000/1875-1
4692 # These line widths are optimal for visualizing FDM over TDM
4693 width1 = 1
4694 width2 = 4
4695 # solutions differ in frequency width, so show the narrower one first
4696 if (myxrange < xrange2):
4697 for p in range(nPolarizations):
4698 if (corrTypeToString(corr_type[p]) in polsToPlot):
4699 if (debug): print("pb.plot 1")
4700 pb.plot(pfrequencies[p], gphs[p], '%s%s'%(pcolor[p],phasemarkstyle), linewidth=width2, markersize=markersize,markeredgewidth=markeredgewidth)
4701 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4702 for p in range(nPolarizations):
4703 if (corrTypeToString(corr_type[p]) in polsToPlot):
4704 if (debug): print("pb.plot 2")
4705 pb.plot(pfrequencies2[p], gphs2[p], '%s%s'%(p2color[p],phasemarkstyle), linewidth=width1, markersize=markersize,markeredgewidth=markeredgewidth)
4706 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs2[p], sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
4707 else:
4708 for p in range(nPolarizations):
4709 if (corrTypeToString(corr_type[p]) in polsToPlot):
4710 if (debug): print("pb.plot 3")
4711 pb.plot(pfrequencies2[p], gphs2[p], '%s%s'%(p2color[p],phasemarkstyle), linewidth=width2, markersize=markersize,markeredgewidth=markeredgewidth)
4712 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs2[p], sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
4713 for p in range(nPolarizations):
4714 if (corrTypeToString(corr_type[p]) in polsToPlot):
4715 if (debug): print("pb.plot 4")
4716 pb.plot(pfrequencies[p], gphs[p], '%s%s'%(pcolor[p],phasemarkstyle), linewidth=width1, markersize=markersize,markeredgewidth=markeredgewidth)
4717 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4718 else:
4719 width1 = 1
4720 width2 = 1
4721 # solutions may be different level of smoothing, so plot highest rms first
4722 if (MAD(gphsx) < MAD(gphsx2)):
4723 for p in range(nPolarizations):
4724 if (corrTypeToString(corr_type[p]) in polsToPlot):
4725 if (debug): print("pb.plot 5")
4726 pb.plot(pfrequencies2[p], gphs2[p], '%s%s'%(p2color[p],phasemarkstyle), linewidth=width1, markersize=markersize,markeredgewidth=markeredgewidth)
4727 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs2[p], sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
4728 for p in range(nPolarizations):
4729 if (corrTypeToString(corr_type[p]) in polsToPlot):
4730 if (debug): print("pb.plot 6")
4731 pb.plot(pfrequencies[p], gphs[p], '%s%s'%(pcolor[p],phasemarkstyle), linewidth=width2, markersize=markersize,markeredgewidth=markeredgewidth)
4732 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4733 else:
4734 for p in range(nPolarizations):
4735 if (corrTypeToString(corr_type[p]) in polsToPlot):
4736 if (debug): print("pb.plot 7")
4737 pb.plot(pfrequencies[p], gphs[p], '%s%s'%(pcolor[p],phasemarkstyle), linewidth=width2, markersize=markersize,markeredgewidth=markeredgewidth)
4738 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4739 for p in range(nPolarizations):
4740 if (corrTypeToString(corr_type[p]) in polsToPlot):
4741 if (debug): print("pb.plot 9")
4742 pb.plot(pfrequencies2[p], gphs2[p], '%s%s'%(p2color[p],phasemarkstyle), linewidth=width1, markersize=markersize,markeredgewidth=markeredgewidth)
4743 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs2[p], sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
4744 # must set new limits after plotting 'phase'
4745 (y0,y1) = pb.ylim()
4746 if (y1-y0 < minPhaseRange):
4747 # this must come before defining ticks
4748 SetNewYLimits([-minPhaseRange,minPhaseRange])
4749 if (zoom=='intersect'):
4750 if (myxrange < xrange2):
4751 SetNewXLimits([min(xfrequencies[0],xfrequencies[-1])-myxrange*0.1, max(xfrequencies[0],xfrequencies[-1])+myxrange*0.1],15)
4752 SetLimits(plotrange, chanrange, newylimits, channels, frequencies,
4753 pfrequencies, ampMin, ampMax, xaxis,pxl, chanrangeSetXrange,
4754 chanrangePercent)
4755 else:
4756 SetNewXLimits([min(xfrequencies2[0],xfrequencies2[-1])-xrange2*0.1, max(xfrequencies2[0],xfrequencies2[-1])+xrange2*0.1],16)
4757 SetLimits(plotrange, chanrange, newylimits, channels, frequencies2,
4758 pfrequencies2, ampMin, ampMax, xaxis,pxl, chanrangeSetXrange,
4759 chanrangePercent)
4760 else:
4761 if (myxrange < xrange2):
4762 SetLimits(plotrange, chanrange, newylimits, channels, frequencies,
4763 pfrequencies, ampMin, ampMax, xaxis,pxl, chanrangeSetXrange,
4764 chanrangePercent)
4765 else:
4766 SetLimits(plotrange, chanrange, newylimits, channels, frequencies2,
4767 pfrequencies2, ampMin, ampMax, xaxis,pxl, chanrangeSetXrange,
4768 chanrangePercent)
4769 # draw polarization and spw labels
4770 if (xframe == firstFrame):
4771 # draw title including caltable name
4772 caltableList = 'c1=' + caltable + ', c2=' + caltable2 # + ' (%s)'%(utstring(uniqueTimes2[mytime],3))
4773 pb.text(xstartTitle, ystartTitle, caltableList, size=titlesize,
4774 color='k', transform=pb.gcf().transFigure)
4775 elif (bpolyOverlay):
4776 matches1 = []
4777 if tableFormat >= 34: ### added 2024Aug
4778 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
4779 else: ### added 2024Aug
4780 scansToPlotHere = scansToPlot ### added 2024Aug
4781 for tbp in range(len(timesBP)):
4782 if (sloppyMatch(uniqueTimes[mytime], timesBP[tbp], solutionTimeThresholdSeconds,
4783 mytime, scansToPlotHere, scansForUniqueTimes, ### modified 2024Aug
4784 myprint=debugSloppyMatch)):
4785 matches1.append(tbp)
4786 matches1 = np.array(matches1)
4787# # # # print("time matches: matches1 = ", matches1)
4788 if (len(matches1) < 1):
4789 print("No time match found")
4790 print("If you are sure the solutions correspond to the same data, you can set solutionTimeThresholdSeconds=%.0f" % (1+np.ceil(np.abs(timesBP[0]-uniqueTimes[mytime]))))
4791 return()
4792 matches2 = np.where(xant == np.array(antennasBP))[0]
4793 if (len(matches2) < 1):
4794 print("No antenna match found between %s and %s" % (str(xant), str(antennasBP)))
4795# # # # print("antenna matches: matches2 = ", matches2)
4797 if (tableFormat == 33):
4798 matches3 = np.where(ispw == np.array(cal_desc_idBP))[0]
4799 if (len(matches3) < 1):
4800 print("No spw match found: %d not in %s" % (ispw, str(cal_desc_idBP)))
4801 else:
4802 matches3 = np.where(ispw == np.array(spwBP))[0]
4803 if (len(matches3) < 1):
4804 print("No spw match found: %d not in %s" % (ispw, str(spwBP)))
4805# # # # print("spw matches: matches3 = ", matches3)
4807 matches12 = np.intersect1d(matches1,matches2)
4808 if (len(matches12) < 1):
4809 print("No match between: %s and %s" % (str(matches1), str(matches2)))
4810# # # # print("antenna&time matches: matches12 = ", matches12)
4812 matches = np.intersect1d(matches12, matches3)
4813 if (len(matches) < 1):
4814 print("No match between: %s and %s" % (str(matches12), str(matches3)))
4815# # # # print("antenna&time&spw matches: matches = ", matches)
4817 try:
4818 index = matches[0] # holds the row number of the matching solution in the BPOLY table
4819 except:
4820 print("No match found for time=%.6f, xant=%d, ispw=%d" % (uniqueTimes[mytime],xant,ispw))
4821 print("antennasBP = %s" % (str(antennasBP)))
4822 print("cal_desc_idBP = %s" % (str(cal_desc_idBP)))
4823 timesBPstring = "timesBP = "
4824 for i in timesBP:
4825 timesBPstring += "%.6f, " % i
4826 print(timesBPstring)
4827 return()
4828# # # # print("phase: Using index = %d/%d (mytime=%d), domain=%.3f,%.3f" % (index,len(polynomialPhase),mytime,frequencyLimits[0,index]*1e-9,frequencyLimits[1,index]*1e-9))
4829 if (debug): print("BRowNumber = %d, BPolyRowNumber = %d" % (BRowNumber, index))
4830 validDomain = [frequencyLimits[0,index], frequencyLimits[1,index]]
4831 cc = calcChebyshev(polynomialPhase[index][0:nPolyPhase[index]], validDomain, frequenciesGHz[index]*1e+9) * 180/math.pi
4832 fa = np.array(frequenciesGHz[index])
4833 if (xfrequencies[0] < xfrequencies[-1]):
4834 matches = np.where(fa>xfrequencies[0])[0]
4835 matches2 = np.where(fa<xfrequencies[-1])[0]
4836 else:
4837 matches = np.where(fa>xfrequencies[-1])[0]
4838 matches2 = np.where(fa<xfrequencies[0])[0]
4839# # # # print("xfrequencies[0] = %f, xfrequencies[-1] = %f" % (xfrequencies[0], xfrequencies[-1]))
4840# # # # print("len(matches)=%d, len(matches2)=%d" % (len(matches), len(matches2)))
4841# # # # print("fa = ", fa)
4842 mymean = complexMeanDeg(np.array(cc)[matches[0]:matches2[-1]+1])
4843 phaseSolutionX = np.mean(gphsx) - mymean + cc
4845 cc = calcChebyshev(polynomialPhase[index][nPolyPhase[index]:2*nPolyPhase[index]], validDomain, frequenciesGHz[index]*1e+9) * 180/math.pi
4846 if (nPolarizations > 1):
4847 if (yfrequencies[0] < yfrequencies[-1]):
4848 matches = np.where(fa>yfrequencies[0])[0]
4849 matches2 = np.where(fa<yfrequencies[-1])[0]
4850 else:
4851 matches = np.where(fa>yfrequencies[-1])[0]
4852 matches2 = np.where(fa<yfrequencies[0])[0]
4853 mymean = complexMeanDeg(np.array(cc)[matches[0]:matches2[-1]+1])
4854 phaseSolutionY = np.mean(gphsy) - mymean + cc
4855 if (bpolyOverlay2):
4856 validDomain = [frequencyLimits2[0,index], frequencyLimits2[1,index]]
4857 cc = calcChebyshev(polynomialPhase2[index][0:nPolyPhase2[index]], validDomain, frequenciesGHz2[index]*1e+9) * 180/math.pi
4858 fa = np.array(frequenciesGHz2[index])
4859 if (xfrequencies[0] < xfrequencies[-1]):
4860 matches = np.where(fa>xfrequencies[0])[0]
4861 matches2 = np.where(fa<xfrequencies[-1])[0]
4862 else:
4863 matches = np.where(fa>xfrequencies[-1])[0]
4864 matches2 = np.where(fa<xfrequencies[0])[0]
4865 mymean = complexMeanDeg(np.array(cc)[matches[0]:matches2[-1]+1])
4866 phaseSolution2X = np.mean(gphsx) + cc - mymean
4868 cc = calcChebyshev(polynomialPhase2[index][nPolyPhase2[index]:2*nPolyPhase2[index]], validDomain, frequenciesGHz2[index]*1e+9) * 180/math.pi
4869 if (yfrequencies[0] < yfrequencies[-1]):
4870 matches = np.where(fa>yfrequencies[0])[0]
4871 matches2 = np.where(fa<yfrequencies[-1])[0]
4872 else:
4873 matches = np.where(fa>yfrequencies[-1])[0]
4874 matches2 = np.where(fa<yfrequencies[0])[0]
4875 mymean = complexMeanDeg(np.array(cc)[matches[0]:matches2[-1]+1])
4876 phaseSolution2Y = np.mean(gphsy) + cc - mymean
4877 for p in range(nPolarizations):
4878 if (corrTypeToString(corr_type[p]) in polsToPlot):
4879 pb.plot(pfrequencies[p], gphs[p],'%s%s' % (pcolor[p],phasemarkstyle), markersize=markersize,markeredgewidth=markeredgewidth)
4880 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4881 if (corrTypeToString(corr_type[0]) in polsToPlot):
4882 pb.plot(frequenciesGHz[index],phaseSolutionX,'%s%s'%(x2color,bpolymarkstyle),markeredgewidth=markeredgewidth)
4883 newylimits = recalcYlimitsFreq(chanrange, newylimits, phaseSolutionX, sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4884 pb.plot(frequenciesGHz2[index],phaseSolution2X,'%s%s'%(x3color,bpolymarkstyle),markeredgewidth=markeredgewidth)
4885 newylimits = recalcYlimitsFreq(chanrange, newylimits, phaseSolution2X, sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
4886 if (nPolarizations == 2):
4887 if (corrTypeToString(corr_type[1]) in polsToPlot):
4888 pb.plot(frequenciesGHz[index],phaseSolutionY,'%s%s'%(y2color,bpolymarkstyle),markeredgewidth=markeredgewidth)
4889 newylimits = recalcYlimitsFreq(chanrange, newylimits, phaseSolutionY, sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4890 pb.plot(frequenciesGHz2[index],phaseSolution2Y,'%s%s'%(y3color,bpolymarkstyle),markeredgewidth=markeredgewidth)
4891 newylimits = recalcYlimitsFreq(chanrange, newylimits, phaseSolution2Y, sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
4892 else:
4893 for p in range(nPolarizations):
4894 if (corrTypeToString(corr_type[p]) in polsToPlot):
4895 pb.plot(pfrequencies[p], gphs[p],'%s%s'%(pcolor[p],phasemarkstyle), markersize=markersize,markeredgewidth=markeredgewidth)
4896 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4897 if (corrTypeToString(corr_type[0]) in polsToPlot):
4898 pb.plot(frequenciesGHz[index],phaseSolutionX,'%s%s'%(x2color,bpolymarkstyle),markeredgewidth=markeredgewidth)
4899 newylimits = recalcYlimitsFreq(chanrange, newylimits, phaseSolutionX, sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4900 if (nPolarizations == 2):
4901 if (corrTypeToString(corr_type[1]) in polsToPlot):
4902 pb.plot(frequenciesGHz[index],phaseSolutionY,'%s%s'%(y2color,bpolymarkstyle),markeredgewidth=markeredgewidth)
4903 newylimits = recalcYlimitsFreq(chanrange, newylimits, phaseSolutionY, sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4904 # endif (bpolyOverlay2)
4905 # Adding the following 4 lines on March 14, 2013
4906 (y0,y1) = pb.ylim()
4907 if (y1-y0 < minPhaseRange):
4908 # this must come before defining ticks
4909 SetNewYLimits([-minPhaseRange,minPhaseRange])
4910 else:
4911 # we are not overlaying any B or polynomial solutions 'phase vs. freq'
4912 for p in range(nPolarizations):
4913 if (corrTypeToString(corr_type[p]) in polsToPlot):
4914 if (overlayAntennas or overlayTimes):
4915 pdesc = pb.plot(pfrequencies[p], gphs[p],'%s'%(phasemarkstyles[p]), markersize=markersize,markeredgewidth=markeredgewidth)
4916 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent) # Apr 2, 2012
4917 if (overlayAntennas and overlayTimes==False):
4918 pb.setp(pdesc, color=overlayColors[xctr])
4919 elif (overlayTimes and overlayAntennas==False):
4920 pb.setp(pdesc, color=overlayColors[mytime])
4921 elif (overlayTimes): # try to support antenna,time
4922 if (myUniqueTime != []):
4923 pb.setp(pdesc, color=overlayColors[myUniqueTime])
4924 # The third 'or' below is needed if pol='0' is flagged on antenna 0. -- 2012/10/12 (original spot)
4925 if (p==0 or len(polsToPlot)==1 or myUniqueColor==[]):
4926 myUniqueColor.append(overlayColors[len(myUniqueColor)])
4927 pb.setp(pdesc, color=myUniqueColor[-1])
4928 else:
4929 pb.plot(pfrequencies[p], gphs[p],'%s%s'%(pcolor[p],phasemarkstyles[0]), markersize=markersize,markeredgewidth=markeredgewidth)
4930 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs[p], sideband, plotrange,xchannels,chanrangePercent=chanrangePercent)
4931 if (sum(xflag)>0):
4932# # # # print("phase frame %d: Resetting xaxis frequency range to counteract flagged data" % (xframe))
4933 myxrange = np.max(frequencies)-np.min(frequencies)
4934 SetNewXLimits([np.min(frequencies)-0.15*myxrange, np.max(frequencies)+0.15*myxrange],17)
4935 if (len(gphs[p]) > 0):
4936 if (np.max(gphs[p]) < minPhaseRange and np.min(gphs[p]) > -minPhaseRange):
4937 SetNewYLimits([-minPhaseRange,minPhaseRange])
4938 #endif bOverlay
4940 if (1==1):
4941 pb.xlabel(xlabelString, size=mysize)
4942 #endif xaxis='chan'/freq for 'phase'
4943 if (overlayTimes):
4944 timeString =''
4945 else:
4946 timeString = ', t%d/%d %s' % (mytime,nUniqueTimes-1,utstring(uniqueTimes[mytime],3))
4947 if (scansForUniqueTimes != []):
4948 if (scansForUniqueTimes[mytime]>=0):
4949 timeString = ', scan%d %s' % (scansForUniqueTimes[mytime],utstring(uniqueTimes[mytime],3))
4950 spwString = buildSpwString(overlaySpws, overlayBasebands,
4951 spwsToPlot, ispw, originalSpw[ispw],
4952 observatoryName, baseband,
4953 showBasebandNumber)
4954 titleString = "%sspw%s, field %d: %s%s" % (antennaString,
4955 spwString,uniqueFields[fieldIndex],fieldString,timeString)
4956 pb.title(titleString,size=titlesize-int(len(titleString)//(maxCharsBeforeReducingTitleFontSize//subplotCols)))
4957 if (abs(plotrange[0]) > 0 or abs(plotrange[1]) > 0):
4958 SetNewXLimits([plotrange[0],plotrange[1]],18)
4960 # Here is 1st place where we eliminate any white space on the right and left edge of the plots: 'phase'
4961 else:
4962 if (xaxis.find('chan')>=0):
4963 SetNewXLimits([channels[0],channels[-1]])
4964 else:
4965 if (zoom != 'intersect'):
4966 if (overlaySpws or overlayBasebands):
4967 SetNewXLimits(frequencyRangeToPlotInBaseband[bbctr])
4968 else:
4969 SetNewXLimits([frequencies[0], frequencies[-1]])
4970 if (bOverlay):
4971 if (xrange2 > myxrange+0.1 and zoom != 'intersect'):
4972 TDMisSecond = True
4974 if (abs(plotrange[2]) > 0 or abs(plotrange[3]) > 0):
4975 if (amplitudeWithPhase == False or phase == ''):
4976 SetNewYLimits([plotrange[2],plotrange[3]])
4977 if (amplitudeWithPhase and phase != ''):
4978 if (phase[0] != 0 or phase[1] != 0):
4979 SetNewYLimits(phase)
4982 (y0,y1) = pb.ylim()
4983 if (y1-y0 < minPhaseRange):
4984 # this must come before defining ticks
4985 SetNewYLimits([-minPhaseRange,minPhaseRange])
4986 SetNewYLimits(newylimits) # added 10/2/2012 for the case of only 1 data point
4987 if (amplitudeWithPhase and phase != ''):
4988 if (phase[0] != 0 or phase[1] != 0):
4989 SetNewYLimits(phase)
4990 (y0,y1) = pb.ylim()
4991 ResizeFontsSetGrid(adesc,mysize)
4992 pb.ylabel(yPhaseLabel, size=mysize)
4993 pb.subplots_adjust(hspace=myhspace, wspace=mywspace)
4994 ylim = pb.ylim()
4995 xlim = pb.xlim()
4996 myxrange = xlim[1]-xlim[0]
4997 yrange = ylim[1]-ylim[0]
4998# # # # print("phase: ylim, yrange = ", ylim, yrange)
4999 myap = 0
5000 if (overlayAntennas == False and overlayTimes == False and bOverlay == False and
5001 ((overlaySpws == False and overlayBasebands == False) or spwctr==spwctrFirstToPlot)):
5002 # draw polarization labels
5003 x0 = xstartPolLabel
5004 y0 = ystartPolLabel
5005 for p in range(nPolarizations):
5006 if (corrTypeToString(corr_type[p]) in polsToPlot):
5007 pb.text(x0, y0-0.03*subplotRows*p, corrTypeToString(corr_type[p]), color=pcolor[p],
5008 size=mysize, transform=pb.gca().transAxes)
5009 if (channeldiff > 0):
5010 pb.text(x0, ystartMadLabel-0.03*subplotRows*p,
5011 corrTypeToString(corr_type[p])+' MAD = %.4f, St.Dev = %.4f'%(gphs_mad[p]['mad'],gphs_std[p]['std']),
5012 color=pcolor[p],size=mysize, transform=pb.gca().transAxes)
5013 if (xframe == firstFrame):
5014 # draw title including caltable name
5015 caltableList = caltableTitle
5016 if (bpolyOverlay):
5017 caltableList += ', ' + caltable2 + ' (degamp=%d, degphase=%d)'%(nPolyAmp[index]-1,nPolyPhase[index]-1)
5018 if (bpolyOverlay2):
5019 caltableList += ', ' + caltable3 + ' (degamp=%d, degphase=%d)'%(nPolyAmp2[index]-1,nPolyPhase2[index]-1)
5020 pb.text(xstartTitle, ystartTitle, caltableList, size=titlesize,
5021 color='k', transform=pb.gcf().transFigure)
5022 elif (overlayAntennas==True and xant==antennasToPlot[-1] and bOverlay==False # ):
5023 and overlayTimes==False): # try to support antenna,time avoid antenna labels 'phase'
5024 # We do this last, because by then, the limits will be stable.
5025 # draw polarization labels for overlayAntennas
5026 x0 = xstartPolLabel
5027 y0 = ystartPolLabel
5028 if (corrTypeToString(corr_type[0]) in polsToPlot):
5029 if (channeldiff > 0):
5030 pb.text(x0, ystartMadLabel-0.03*subplotRows*p,
5031 corrTypeToString(corr_type[p])+' MAD = %.4f, St.Dev = %.4f'%(gphs_mad[p]['mad'],gphs_std[p]['std']),
5032 color=overlayColors[0], size=mysize, transform=pb.gca().transAxes)
5033 if (phasemarkstyle.find('-')>=0):
5034 pb.text(x0, y0-0.03*subplotRows*0, corrTypeToString(corr_type[0])+' solid', color=overlayColors[0],
5035 fontsize=mysize, transform=pb.gca().transAxes)
5036 else:
5037 pb.text(x0+0.02, y0-0.03*subplotRows*0, corrTypeToString(corr_type[0]), color=overlayColors[0],
5038 fontsize=mysize, transform=pb.gca().transAxes)
5039 pdesc = pb.plot([x0], [y0+0.015-0*0.03*subplotRows], '%sk'%phasemarkstyle, markersize=markersize,
5040 scalex=False,scaley=False, transform=pb.gca().transAxes,markeredgewidth=markeredgewidth)
5041 if (len(corr_type) > 1):
5042 if (corrTypeToString(corr_type[1]) in polsToPlot):
5043 if (channeldiff > 0):
5044 pb.text(x0, ystartMadLabel-0.03*subplotRows*p,
5045 corrTypeToString(corr_type[p])+' MAD = %.4f, St.Dev = %.4f'%(gphs_mad[p]['mad'],gphs_std[p]['std']),
5046 color=overlayColors[0], size=mysize, transform=pb.gca().transAxes)
5047 if (phasemarkstyle2.find('--')>=0):
5048 pb.text(x0, y0-0.03*subplotRows*1, corrTypeToString(corr_type[1])+' dashed', color=overlayColors[0],
5049 fontsize=mysize, transform=pb.gca().transAxes)
5050 else:
5051 pb.text(x0+0.02, y0-0.03*subplotRows*1, corrTypeToString(corr_type[1]), color=overlayColors[0],
5052 fontsize=mysize, transform=pb.gca().transAxes)
5053 pdesc = pb.plot([x0], [y0+0.015*subplotRows-0.03*subplotRows*1],'%sk'%phasemarkstyle2, markersize=markersize,
5054 scalex=False,scaley=False, transform=pb.gca().transAxes,markeredgewidth=markeredgewidth)
5055 if (xframe == firstFrame):
5056 # draw title including caltable name
5057 pb.text(xstartTitle, ystartTitle, caltableTitle, size=titlesize, color='k',
5058 transform=pb.gcf().transFigure)
5059 DrawAntennaNames(msAnt, antennasToPlot, msFound, mysize, overlayColors)
5060 elif (overlayTimes==True and bOverlay == False
5061 and overlayAntennas==False): # try to support antenna,time
5062 doneOverlayTime = True # assumed until proven otherwise in the 'for' loop
5063 for f in fieldIndicesToPlot:
5064 if (uniqueTimes[mytime] < uniqueTimesPerFieldPerSpw[ispwInCalTable][f][-1]-solutionTimeThresholdSeconds and
5065 uniqueTimes[mytime] < timerangeListTimes[-1]):
5066 if tableFormat >= 34: # added 2024Aug
5067 if scansForUniqueTimes[mytime] != scansForUniqueTimes[-1]: # fix for CAS-14096
5068 doneOverlayTime = False
5069 else: # added 2024Aug
5070 doneOverlayTime = False # added 2024Aug
5071 if (doneOverlayTime):
5072 # either it is the last time of any times in solution, or the last time in the list of times to plot
5073 mytime = nUniqueTimes-1
5074 # draw polarization labels for overlayTimes
5075 # We do this last, because by then, the limits will be broad enough and stable.
5076 x0 = xstartPolLabel
5077 y0 = ystartPolLabel
5078 if (corrTypeToString(corr_type[0]) in polsToPlot):
5079 if (channeldiff > 0):
5080 p = 0
5081 pb.text(x0, ystartMadLabel-0.03*subplotRows*p,
5082 corrTypeToString(corr_type[p])+' MAD = %.4f'%(gphs_mad[p]['mad']),
5083 color='k', size=mysize, transform=pb.gca().transAxes)
5084 if (phasemarkstyle.find('-')>=0):
5085 pb.text(x0, y0, corrTypeToString(corr_type[0])+' solid', color='k',
5086 fontsize=mysize, transform=pb.gca().transAxes)
5087 else:
5088 pb.text(x0+0.02, y0, corrTypeToString(corr_type[0]), color='k',
5089 fontsize=mysize, transform=pb.gca().transAxes)
5090 pdesc = pb.plot([x0], [y0+0.015*subplotRows], '%sk'%phasemarkstyle, markersize=markersize,
5091 scalex=False,scaley=False, transform=pb.gca().transAxes,markeredgewidth=markeredgewidth)
5092 if (len(corr_type) > 1):
5093 if (corrTypeToString(corr_type[1]) in polsToPlot):
5094 if (channeldiff > 0):
5095 p = 1
5096 pb.text(x0, ystartMadLabel-0.03*subplotRows*p,
5097 corrTypeToString(corr_type[p])+' MAD = %.4f'%(gphs_mad[p]['mad']),
5098 color='k', size=mysize, transform=pb.gca().transAxes)
5099 if (phasemarkstyle2.find('--')>=0):
5100 pb.text(x0, y0-0.03*subplotRows, corrTypeToString(corr_type[1])+' dashed',
5101 color='k',fontsize=mysize, transform=pb.gca().transAxes)
5102 else:
5103 pb.text(x0+0.02, y0-0.03*subplotRows, corrTypeToString(corr_type[1]),
5104 color='k', fontsize=mysize, transform=pb.gca().transAxes)
5105 pdesc = pb.plot([x0], [y0+0.015*subplotRows-0.03*subplotRows], '%sk'%phasemarkstyle2,
5106 markersize=markersize, scalex=False,scaley=False, transform=pb.gca().transAxes,markeredgewidth=markeredgewidth)
5107 if (xframe == firstFrame):
5108 # draw title including caltable name
5109 pb.text(xstartTitle, ystartTitle, caltableTitle, size=titlesize, color='k',
5110 transform=pb.gcf().transFigure)
5111 if (debug): print("drawOverlayTimeLegends loc 4")
5112 drawOverlayTimeLegends(xframe,firstFrame,xstartTitle,ystartTitle,
5113 caltable,titlesize,fieldIndicesToPlot,
5114 ispwInCalTable,uniqueTimesPerFieldPerSpw,
5115 timerangeListTimes, solutionTimeThresholdSeconds,
5116 debugSloppyMatch,ystartOverlayLegend,debug,mysize,
5117 fieldsToPlot,myUniqueColor,timeHorizontalSpacing,
5118 fieldIndex, overlayColors, antennaVerticalSpacing,
5119 overlayAntennas, timerangeList, caltableTitle,
5120 mytime, scansToPlotPerSpw[ispw], scansForUniqueTimes,
5121 uniqueSpwsInCalTable, uniqueTimes)
5123 elif (overlayAntennas and overlayTimes): # Oct 23, 2012
5124 # This will only happen for: try to support overlay='antenna,time'
5125 if (xframe == firstFrame and mytime==0 and xctr==firstUnflaggedAntennaToPlot and bOverlay==False):
5126 # draw title including caltable name
5127 pb.text(xstartTitle, ystartTitle, caltableTitle, size=titlesize, color='k',
5128 transform=pb.gcf().transFigure)
5129 DrawBottomLegendPageCoords(msName, uniqueTimes[mytime], mysize, figfile)
5131 #endif (overlayAntennas == False and overlayTimes == False and bOverlay == False)
5133 # Here is 2nd place where we eliminate any white space on the right and left edge of the plots: 'phase'
5134 if (abs(plotrange[2]) > 0 or abs(plotrange[3]) > 0):
5135 if (amplitudeWithPhase == False or phase == ''):
5136 SetNewYLimits([plotrange[2],plotrange[3]])
5137 if (phase != '' and amplitudeWithPhase):
5138 if (phase[0] != 0 or phase[1] != 0):
5139 SetNewYLimits(phase)
5140 if (plotrange[0]==0 and plotrange[1]==0):
5141 if (xaxis.find('chan')>=0):
5142 SetNewXLimits([channels[0],channels[-1]])
5143 else:
5144 if (zoom != 'intersect'):
5145 if (overlaySpws or overlayBasebands):
5146 SetNewXLimits(frequencyRangeToPlotInBaseband[bbctr])
5147 else:
5148 SetNewXLimits([frequencies[0], frequencies[-1]])
5149 if (bOverlay):
5150 if (xrange2 >= myxrange and zoom != 'intersect'):
5151 # This is necessary if caltable2=TDM and caltable=FDM
5152 SetNewXLimits([frequencies2[0], frequencies2[-1]])
5153 if (xrange2 > myxrange+0.1 and zoom != 'intersect'):
5154 TDMisSecond = True
5155 else:
5156 SetNewXLimits([plotrange[0], plotrange[1]])
5158 # I need the following line for chanrange to work
5159 if (chanrange[0] != 0 or chanrange[1] != 0):
5160 SetLimits(plotrange, chanrange, newylimits, channels, frequencies, pfrequencies,
5161 ampMin, ampMax, xaxis,pxl, chanrangeSetXrange,
5162 chanrangePercent)
5164 # Finally, draw the atmosphere and FDM windows, if requested. 'phase'
5165 if ((overlayAntennas==False and overlayTimes==False) or
5166 (overlayAntennas==True and overlayTimes==False and xant==antennasToPlot[-1]) or
5167 (overlayTimes==True and overlayAntennas==False and doneOverlayTime) or
5168 (xant==antennasToPlot[-1] and doneOverlayTime)
5169 ):
5170 if ((showatm or showtsky) and len(atmString)>0):
5171 DrawAtmosphere(showatm, showtsky, subplotRows, atmString,
5172 mysize, TebbSky, plotrange, xaxis, atmchan,
5173 atmfreq, transmission, subplotCols,
5174 showatmPoints=showatmPoints, xframe=xframe,
5175 channels=channels, mylineno=lineNumber(),
5176 overlaySpws=overlaySpws,
5177 overlayBasebands=overlayBasebands,
5178 drewAtmosphere=drewAtmosphere,loc=205,
5179 showtsys=showtsys, Trx=Trx)
5180 if (LO1):
5181 DrawAtmosphere(showatm,showtsky, subplotRows, atmString,
5182 mysize, TebbSky, plotrange, xaxis, atmchanImage,
5183 atmfreqImage, transmissionImage, subplotCols,
5184 LO1, xframe, firstFrame, showatmPoints,
5185 channels=channels, mylineno=lineNumber(),
5186 overlaySpws=overlaySpws,
5187 overlayBasebands=overlayBasebands,
5188 drewAtmosphere=drewAtmosphere, loc=206,
5189 showtsys=showtsys, Trx=Trx)
5190 drewAtmosphere = True
5192 if (xaxis.find('freq')>=0 and showfdm and nChannels <= 256):
5193 if (tableFormat == 33):
5194 showFDM(originalSpw_casa33, chanFreqGHz_casa33, baseband, showBasebandNumber, basebandDict, overlayColors)
5195 else:
5196 showFDM(originalSpw, chanFreqGHz, baseband, showBasebandNumber, basebandDict, overlayColors)
5198 if (bOverlay):
5199 # draw polarization labels for bOverlay
5200 x0 = xstartPolLabel
5201 y0 = ystartPolLabel
5202 for p in range(nPolarizations):
5203 if (corrTypeToString(corr_type[p]) in polsToPlot):
5204 pb.text(x0, y0-p*0.03*subplotRows, corrTypeToString(corr_type[p])+'-c1',
5205 color=pcolor[p],size=mysize,transform=pb.gca().transAxes)
5206 pb.text(x0, y0-(p*0.03+0.06)*subplotRows, corrTypeToString(corr_type[p])+'-c2',
5207 color=p2color[p],size=mysize, transform=pb.gca().transAxes)
5208 if (bpolyOverlay and xaxis.find('freq')>=0):
5209 # draw polarization labels for bpolyOverlay
5210 x0 = xstartPolLabel
5211 y0 = ystartPolLabel
5212 if (xcolor != x2color):
5213 for p in range(nPolarizations):
5214 if (corrTypeToString(corr_type[p]) in polsToPlot):
5215 pb.text(x0+0.1, y0-p*0.03*subplotRows, corrTypeToString(corr_type[p]), color=p2color[p],
5216 size=mysize, transform=pb.gca().transAxes)
5217 if (bpolyOverlay2):
5218 for p in range(nPolarizations):
5219 if (corrTypeToString(corr_type[p]) in polsToPlot):
5220 pb.text(x0+0.2, y0-p*0.03*subplotRows, corrTypeToString(corr_type[p]), color=p3color[p],
5221 size=mysize, transform=pb.gca().transAxes)
5223 # endif (yaxis='phase')
5225 redisplay = False
5227 if (xframe == lastFrame):
5228 if (debug):
5229 print("*** mytime+1=%d, nUniqueTimes=%d, timerangeList[-1]=%d, doneOverlayTime=%s" % (mytime+1, nUniqueTimes,timerangeList[-1],doneOverlayTime))
5230 print("*** xant=%d, antennasToPlot[-1]=%d, overlayAntennas=%s, overlayTimes=%s" % (xant,antennasToPlot[-1],overlayAntennas,overlayTimes))
5231 print("*** xframe=%d, lastFrame=%d, xctr=%d, spwctr=%d, len(antennasToPlot)=%d, len(spwsToPlot)=%d" % (xframe,lastFrame,xctr,spwctr,len(antennasToPlot), len(spwsToPlot)))
5232 myIndexTime = uniqueTimesPerFieldPerSpw[ispwInCalTable][fieldIndex][-1]
5233 if (debug):
5234 print("myIndexTime = ", myIndexTime)
5235 if tableFormat >= 34: ### added 2024Aug
5236 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
5237 else: ### added 2024Aug
5238 scansToPlotHere = scansToPlot ### added 2024Aug
5239 matched,mymatch = sloppyMatch(myIndexTime,uniqueTimes,solutionTimeThresholdSeconds,
5240 mytime, scansToPlotHere, scansForUniqueTimes,
5241 whichone=True, myprint=False)
5242 if (matched==False and scansForUniqueTimes[mytime] in scansToPlotPerSpw[ispw]):
5243 print("---------- 2) Did not find %f within %.1f seconds of anything in %s" % (myIndexTime,solutionTimeThresholdSeconds,str(uniqueTimes)))
5244 print("Try re-running with a smaller solutionTimeThresholdSeconds (currently %f)" % (solutionTimeThresholdSeconds))
5245 return
5246 else:
5247 # we are on the final time to be plotted
5248 if (debug): print("on the final time")
5249 mytimeTest = mytime==nUniqueTimes-1
5250 if (debug):
5251 print("mytimeTest = %s" % (mytimeTest))
5252 if (scansForUniqueTimes == []):
5253 # old 3.3 cal tables will land here
5254 scanTest = False
5255 scanTest2 = False
5256 else:
5257 if (debug):
5258 print("ispw=%d len(scansToPlotPerSpw[ispw])=%d mytime=%d, len(scansForUniqueTimes)=%d" % (ispw,len(scansToPlotPerSpw[ispw]),mytime,len(scansForUniqueTimes)))
5259 print("scansToPlotPerSpw = ", scansToPlotPerSpw)
5260 if (len(scansToPlotPerSpw[ispw]) == 0):
5261 scanTest = False
5262 else:
5263 scanTest = scansToPlotPerSpw[ispw][-1]==scansForUniqueTimes[mytime] and (VisCal != 'SDSKY_PS' or mytime == timerangeList[-1]) ### added second expression 2024Aug27
5264 highestSpwIndexInSpwsToPlotThatHasCurrentScan = \
5265 computeHighestSpwIndexInSpwsToPlotThatHasCurrentScan(spwsToPlot, scansToPlotPerSpw, scansForUniqueTimes[mytime])
5266 if (highestSpwIndexInSpwsToPlotThatHasCurrentScan == -1):
5267 scanTest2 = False
5268 else:
5269 scanTest2 = (spwctr == highestSpwIndexInSpwsToPlotThatHasCurrentScan)
5270 if ((overlayAntennas==False and overlayTimes==False and overlaySpws==False and overlayBasebands==False)
5271 # either it is the last time of any, or the last time in the list of times to plot
5272 or (overlayAntennas==False and overlaySpws==False and overlayBasebands==False and (mytime+1==nUniqueTimes or mytime == timerangeList[-1])) # or mytimeTest)) # removed on July 25,2013
5273 or (xant==antennasToPlot[-1] and overlayAntennas==True and overlayTimes==False and overlaySpws==False and overlayBasebands==False)
5274 # The following case is needed to prevent frame=225 in test86 (spectral scan dataset with overlay='spw')
5275 # and the lack of showing of 7 of 8 of the spws in final frame of test61. scanTest2 matches both cases.
5276 or (scanTest and scanTest2 and overlaySpws and overlayAntennas==False and overlayTimes==False)
5277 or ((spwctr==len(spwsToPlot)-1) and (overlayBasebands or overlaySpws) and overlayAntennas==False and overlayTimes==False)
5278 # following case is needed for scans parameter with overlay='time'
5279 or (overlayTimes and scanTest and overlayAntennas==False)
5280 # Following case is needed to make subplot=11 to work for: try to support overlay='antenna,time' : 'phase'
5281 or (xframe == lastFrame and overlayTimes and overlayAntennas and
5282 xctr+1==len(antennasToPlot) and
5283 mytimeTest and
5284 spwctr<len(spwsToPlot))
5285 or (doneOverlayTime and overlayTimes==True
5286 and overlayAntennas==False
5287 )):
5288 if (debug):
5289 print("entered 'if' block")
5290 DrawBottomLegendPageCoords(msName, uniqueTimes[mytime], mysize, figfile)
5292 # added len(pages)>0 on July 30, 2013 to prevent crash when called with single
5293 # antenna and subplot=11 and all solutions flagged.
5294 if (len(figfile) > 0 and len(pages)>0):
5295 if (debug):
5296 print("calling makeplot")
5297 plotfiles.append(makeplot(figfile,msFound,msAnt,
5298 overlayAntennas,pages,pagectr,
5299 density,interactive,antennasToPlot,
5300 spwsToPlot,overlayTimes,overlayBasebands,
5301 4,xant,ispw,subplot,resample,debug,
5302 figfileSequential, figfileNumber))
5303 if (debug):
5304 print("done makeplot")
5305 figfileNumber += 1
5306 myinput = ''
5307 donetime = time.time()
5308 drewAtmosphere = False # needed for CAS-7187 (subplot=11)
5309 if (interactive):
5310 pb.draw()
5311# # # # myinput = raw_input("(%.1f sec) Press return for next screen (b for backwards, q to quit): "%(donetime-mytimestamp))
5312 myinput = input("Press return for next page (b for backwards, q to quit): ")
5313 else:
5314 myinput = ''
5315 skippingSpwMessageSent = 0
5316 mytimestamp = time.time()
5317 if (myinput.find('q') >= 0):
5318 mytime = len(uniqueTimes)
5319 spwctr = len(spwsToPlot)
5320 xctr = len(antennasToPlot)
5321 bbctr = len(spwsToPlotInBaseband)
5322 break
5323 if (debug):
5324 print("4)Setting xframe to %d" % (xframeStart))
5325 xframe = xframeStart
5326 myUniqueColor = []
5327 pb.subplots_adjust(hspace=myhspace, wspace=mywspace)
5328 if (myinput.find('b') >= 0):
5329 if (pagectr > 0):
5330 if (debug):
5331 print("Decrementing pagectr from %d to %d" % (pagectr, pagectr-1))
5332 pagectr -= 1
5333 else:
5334 if (debug):
5335 print("Not decrementing pagectr=%d" % (pagectr))
5336 redisplay = True
5337 #redisplay the current page by setting ctrs back to the value they had at start of that page
5338 xctr = pages[pagectr][PAGE_ANT]
5339 spwctr = pages[pagectr][PAGE_SPW]
5340 mytime = pages[pagectr][PAGE_TIME]
5341 myap = pages[pagectr][PAGE_AP]
5342 xant = antennasToPlot[xctr]
5343 antstring, Antstring = buildAntString(xant,msFound,msAnt)
5344 ispw = spwsToPlot[spwctr]
5345# # # # print("Returning to [%d,%d,%d,%d]" % (xctr,spwctr,mytime,myap))
5346 else:
5347 pagectr += 1
5348 if (pagectr >= len(pages)):
5349 newpage = 1
5350 else:
5351 newpage = 0
5352 if tableFormat >= 34: ### added 2024Aug
5353 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
5354 else: ### added 2024Aug
5355 scansToPlotHere = scansToPlot ### added 2024Aug
5356 if (overlayTimes==True and
5357 sloppyMatch(uniqueTimesPerFieldPerSpw[ispwInCalTable][fieldIndex][-1],
5358 uniqueTimes[mytime],solutionTimeThresholdSeconds,
5359 mytime, scansToPlotHere, scansForUniqueTimes, # au version ### modified 2024Aug
5360 myprint=debugSloppyMatch)):
5361 # be sure to avoid any more loops through mytime which will cause 'b' button to fail
5362 if VisCal != 'SDSKY_PS':
5363 mytime = nUniqueTimes
5364 else:
5365 if (debug):
5366 print(">>>>>>>>>>> Not going to new page, uniqueTimes[mytime]=%.8f, uniqueTimesPerFieldPerSpw[ispwInCalTable=%d][fieldIndex=%d][-1]=%.8f" % (uniqueTimes[mytime], ispwInCalTable, fieldIndex, uniqueTimesPerFieldPerSpw[ispwInCalTable][fieldIndex][-1]))
5367 print("spwctr=%d ?== (len(spwsToPlot)-1)=%d, spwsToPlot=" % (spwctr,len(spwsToPlot)-1),spwsToPlot)
5368 print("test1: %s" % (overlayAntennas==False and overlayTimes==False and overlaySpws==False and overlayBasebands==False))
5369 print("test2: %s" % (overlayAntennas==False and overlaySpws==False and overlayBasebands==False and (mytime+1==nUniqueTimes or mytime == timerangeList[-1])))
5370 print("test3: %s" % (xant==antennasToPlot[-1] and overlayAntennas==True and overlayTimes==False and overlaySpws==False and overlayBasebands==False))
5371 print("*test4: %s" % ((spwctr==len(spwsToPlot)-1) and (overlaySpws or overlayBasebands) and overlayAntennas==False and overlayTimes==False) )
5372 print(" * = overlaySpws==True" )
5373 print("test5: %s" % (overlayTimes and scanTest))
5374 print("test6: %s" % (xframe == lastFrame and overlayTimes and overlayAntennas and xctr+1==len(antennasToPlot) and mytimeTest and spwctr<len(spwsToPlot)))
5375 print("test7: %s" % (doneOverlayTime and overlayTimes==True and overlayAntennas==False))
5377 if (redisplay == False):
5378 if ((overlayAntennas and xctr+1 >= len(antennasToPlot)) or
5379 ((overlaySpws or overlayBasebands) and spwctr+1 >= len(spwsToPlot)) or
5380 (overlayAntennas==False and overlaySpws==False and overlayBasebands==False)):
5381 mytime += 1
5382 if (debug):
5383 print("AT BOTTOM OF LOOP: Incrementing mytime to %d, setting firstUnflaggedAntennaToPlot to 0" % (mytime))
5384 firstUnflaggedAntennaToPlot = 0 # try this
5385 doneOverlayTime = False # added on 08-nov-2012
5386 if (overlayBasebands and (uniqueScanNumbers == sorted(scansToPlot))):
5387 if (debug): print("Breaking because scans not specified")
5388 break
5389 # end of enormous while(mytime) loop endwhile mytime
5390 if (redisplay == False):
5391 spwctr += 1
5392 if (debug):
5393 print( "---------------------------------------- Incrementing spwctr to %d, spwsToPlot=" % (spwctr), spwsToPlot)
5394 if (spwctr < len(spwsToPlot)):
5395 print("---------------------------------------- ispw = %d" % (spwsToPlot[spwctr]))
5396 else:
5397 print("---------------------------------------- done the spws in this baseband (%d)" % (baseband))
5398 else:
5399 if (debug):
5400 print("redisplay = True")
5401 # end of while(spwctr) loop
5402 if (debug): print("at bottom of spwctr loop, spwctr=%d, incrementing bbctr from %d to %d" % (spwctr,bbctr,bbctr+1))
5403 bbctr += 1
5404 # end of while(bbctr) loop
5405 if (debug): print("at bottom of bbctr loop")
5406 if (xant >= antennasToPlot[-1] and xframe != xframeStart):
5407 # this is the last antenna, so make a final plot
5408 if (len(figfile) > 0):
5409 plotfiles.append(makeplot(figfile,msFound,msAnt,overlayAntennas,
5410 pages,pagectr,density,interactive,
5411 antennasToPlot,spwsToPlot,overlayTimes,overlayBasebands,
5412 5,xant,ispw,subplot,resample,debug,
5413 figfileSequential,figfileNumber))
5414 figfileNumber += 1
5415 if (redisplay == False):
5416 xctr += 1
5417 if (debug):
5418 print("Incrementing xctr to %d" % (xctr))
5419 if (overlayAntennas):
5420 if (debug):
5421 print("Breaking out of antenna loop because we are done -------------------")
5422 break
5423 # end of while(xant) loop
5424 if (debug): print("Finished while(xant) loop----------------")
5425 pb.draw()
5426 if (len(plotfiles) == 1 and figfileSequential):
5427 # rename the single file to remove ".000"
5428 newplotfiles = [plotfiles[0].split('.000.png')[0]+'.png']
5429 print("renaming %s to %s" % (plotfiles[0],newplotfiles[0]))
5430 os.system('mv %s %s' % (plotfiles[0],newplotfiles[0]))
5431 plotfiles = newplotfiles
5432 if (len(plotfiles) > 0 and buildpdf):
5433 pdfname = figfile+'.pdf'
5434 filelist = ''
5435 plotfiles = np.unique(plotfiles)
5436 for i in range(len(plotfiles)):
5437 cmd = '%s -density %d %s %s.pdf' % (convert,density,plotfiles[i],plotfiles[i].split('.png')[0])
5438 casalogPost(debug,"Running command = %s" % (cmd))
5439 mystatus = os.system(cmd)
5440 if (mystatus != 0):
5441 print("ImageMagick's convert command not found, no PDF built")
5442 buildpdf = False
5443 break
5444 filelist += plotfiles[i].split('.png')[0] + '.pdf '
5445 if (buildpdf and (len(plotfiles)>1 or not figfileSequential)):
5446 # The following 2 lines reduce the total number of characters on the command line, which
5447 # was apparently a problem at JAO for Liza.
5448 filelist = ' '.join(pruneFilelist(filelist.split()))
5449 pdfname = pruneFilelist([pdfname])[0]
5450 cmd = '%s %s cat output %s' % (pdftk, filelist, pdfname)
5451 casalogPost(debug,"Running command = %s" % (cmd))
5452 mystatus = os.system(cmd)
5453 if (mystatus != 0):
5454 cmd = '%s -q -sPAPERSIZE=letter -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=%s %s' % (gs,pdfname,filelist)
5455 casalogPost(debug,"Running command = %s" % (cmd))
5456 mystatus = os.system(cmd)
5457 if (mystatus == 0):
5458 casalogPost(debug,"PDF left in %s" % (pdfname))
5459 print("PDF left in %s" % (pdfname))
5460 os.system("rm -f %s" % filelist)
5461 else:
5462 print("Both pdftk and ghostscript are missing, so no PDF built.")
5464 showFinalMessage(overlayAntennas, solutionTimeSpread, nUniqueTimes)
5466 if (channeldiff>0):
5467 # Compute median over all antennas, or at least those completed before 'q' was hit
5468 madstats['median'] = dict.fromkeys(spwsToPlot)
5469 spwvalue = {}
5470 spwvalue['amp'] = []
5471 spwvalue['phase'] = []
5472 for j in spwsToPlot:
5473 madstats['median'][j] = dict.fromkeys(timerangeList) # dict.fromkeys(range(len(uniqueTimes)))
5474 for k in timerangeList: # range(len(uniqueTimes)):
5475 madstats['median'][j][k] = dict.fromkeys(list(range(nPolarizations)))
5476 for l in range(nPolarizations):
5477 if (yaxis == 'both'):
5478 madstats['median'][j][k][l] = {'amp': None, 'phase': None}
5479 elif (yaxis == 'phase'):
5480 madstats['median'][j][k][l] = {'phase': None}
5481 else:
5482 # this includes tsys and amp
5483 madstats['median'][j][k][l] = {'amp': None}
5484 for m in madstats['median'][j][k][l].keys():
5485 value = []
5486 for i in madstats.keys(): # loop over antennas
5487 if (i != 'median' and i != 'platforming'):
5488 if (madstats[i][j][k][l][m] != None):
5489 if (debug): print(("madstats[%s][%d][%d][%d][%s] = " % (i,j,k,l,m), madstats[i][j][k][l][m]))
5490 value.append(madstats[i][j][k][l][m])
5491 spwvalue[m].append(madstats[i][j][k][l][m])
5492 madstats['median'][j][k][l][m] = np.median(value)
5493 # now add another spw which is the median over spw,time,polarization
5494 if (yaxis == 'both'):
5495 madstats['median']['median']={'amp': np.median(spwvalue['amp']),
5496 'phase': np.median(spwvalue['phase'])}
5497 elif (yaxis == 'phase'):
5498 madstats['median'][j][k][l] = {'phase': np.median(spwvalue['phase'])}
5499 else:
5500 madstats['median']['median'] = {'amp': np.median(spwvalue['amp'])}
5502 mymsmd.close()
5503 return(madstats)
5504 else:
5505 if (msFound and mymsmd != ''):
5506 mymsmd.close()
5507 return()
5508 # end of plotbandpass
5510def GetFieldIdsForFieldName(token, mymsmd, msFields):
5511 if (mymsmd != '' and mymsmd != None):
5512 return(mymsmd.fieldsforname(token)[0])
5513 else:
5514 return(list(msFields).index(token))
5516def GetFieldNamesForFieldId(u, mymsmd, msFields):
5517 if (mymsmd != '' and mymsmd != None):
5518 return(mymsmd.namesforfields(u)[0])
5519 else:
5520 print("B")
5521 return(msFields[u])
5523def DrawAntennaNamesForOverlayAntennas(xstartPolLabel, ystartPolLabel, polsToPlot, corr_type, channeldiff, ystartMadLabel, subplotRows, gamp_mad, gamp_std, overlayColors, mysize, ampmarkstyle, markersize, markeredgewidth, msAnt, msFound, antennasToPlot, ampmarkstyle2, xframe, firstFrame, caltableTitle, titlesize, debug=False):
5524 if (debug): print("overlayAntennas=True")
5525 x0 = xstartPolLabel
5526 y0 = ystartPolLabel
5527 # draw polarization labels
5528 if (debug): print("1) overlayAntennas=True")
5529 if (corrTypeToString(corr_type[0]) in polsToPlot):
5530 if (channeldiff > 0):
5531 pb.text(x0, ystartMadLabel-0.03*subplotRows*0,
5532 corrTypeToString(corr_type[0])+' MAD = %.4f, St.Dev = %.4f'%(gamp_mad[0]['mad'],gamp_std[0]['std']),
5533 color=overlayColors[0],size=mysize, transform=pb.gca().transAxes)
5534 if (ampmarkstyle.find('-')>=0):
5535 pb.text(x0, y0, corrTypeToString(corr_type[0])+' solid', color=overlayColors[0],size=mysize,
5536 transform=pb.gca().transAxes)
5537 else:
5538 pb.text(x0+0.02, y0, corrTypeToString(corr_type[0]), color=overlayColors[0],size=mysize,
5539 transform=pb.gca().transAxes)
5540 pdesc = pb.plot([x0-0.01], [y0], '%sk'%ampmarkstyle, markersize=markersize,
5541 scalex=False,scaley=False, transform=pb.gca().transAxes,markeredgewidth=markeredgewidth)
5542 if (debug): print("2) overlayAntennas=True")
5543 if (len(corr_type) > 1):
5544 if (corrTypeToString(corr_type[1]) in polsToPlot):
5545 if (channeldiff > 0):
5546 pb.text(x0, ystartMadLabel-0.03*subplotRows*1,
5547 corrTypeToString(corr_type[1])+' MAD = %.4f, St.Dev = %.4f'%(gamp_mad[1]['mad'],gamp_std[1]['std']),
5548 color=overlayColors[0],size=mysize, transform=pb.gca().transAxes)
5549 if (ampmarkstyle2.find('--')>=0):
5550 pb.text(x0, y0-0.03*subplotRows, corrTypeToString(corr_type[1])+' dashed',
5551 color=overlayColors[0],size=mysize, transform=pb.gca().transAxes)
5552 else:
5553 pb.text(x0+0.02, y0-0.03*subplotRows, corrTypeToString(corr_type[1]),
5554 color=overlayColors[0],size=mysize, transform=pb.gca().transAxes)
5555 pdesc = pb.plot([x0-0.01], [y0-0.03*subplotRows], '%sk'%ampmarkstyle2,
5556 markersize=markersize, scalex=False,scaley=False,markeredgewidth=markeredgewidth)
5557 if (debug): print("3) overlayAntennas=True")
5558 if (xframe == firstFrame):
5559 # draw title including caltable name
5560 if (debug): print("4) overlayAntennas=True")
5561 pb.text(xstartTitle, ystartTitle, caltableTitle, size=titlesize, color='k',
5562 transform=pb.gcf().transFigure)
5563 if (debug): print("5) overlayAntennas=True")
5564 DrawAntennaNames(msAnt, antennasToPlot, msFound, mysize, overlayColors)
5565 if (debug): print("6) overlayAntennas=True")
5567def getTelescopeNameFromCaltable(caltable):
5568 mytb = table()
5569 mytb.open(caltable)
5570 if ('OBSERVATION' in mytb.getkeywords()):
5571 observationTable = mytb.getkeyword('OBSERVATION').split()[1]
5572 else:
5573 observationTable = None
5574 mytb.close()
5575 if (observationTable == None):
5576 return('')
5577 else:
5578 return(getTelescopeNameFromCaltableObservationTable(observationTable))
5581def getTelescopeNameFromCaltableObservationTable(observationTable):
5582 mytb = table()
5583 mytb.open(observationTable)
5584 telescope = mytb.getcell('TELESCOPE_NAME')
5585 mytb.close()
5586 return(telescope)
5588def getCorrTypeByAntennaName(firstAntenna):
5589 """
5590 This function is used only if the OBSERVATION table of the caltable is blank and the MS is unavailable.
5591 """
5592 print("Using antenna name (%s) to set the polarization type." % (firstAntenna))
5593 if (firstAntenna.find('ea') >= 0):
5594 corr_type_string = ['RR','LL']
5595 corr_type = [5,8]
5596 elif (firstAntenna.find('dv') >= 0 or firstAntenna.find('da') >= 0 or
5597 firstAntenna.find('pm') >= 0 or firstAntenna.find('da') >= 0):
5598 corr_type_string = ['XX','YY']
5599 corr_type = [9,12]
5600 else: # SMA
5601 corr_type_string = ['XX']
5602 corr_type = [9]
5603 return(corr_type, corr_type_string, len(corr_type))
5605def MAD(a, c=0.6745, axis=0):
5606 """
5607 Median Absolute Deviation along given axis of an array:
5609 median(abs(a - median(a))) / c
5611 c = 0.6745 is the constant to convert from MAD to std; it is used by
5612 default
5613 """
5614 a = np.array(a)
5615 good = (a==a)
5616 a = np.asarray(a, np.float64)
5617 if a.ndim == 1:
5618 d = np.median(a[good])
5619 m = np.median(np.fabs(a[good] - d) / c)
5620 else:
5621 d = np.median(a[good], axis=axis)
5622 # I don't want the array to change so I have to copy it?
5623 if axis > 0:
5624 aswp = swapaxes(a[good],0,axis)
5625 else:
5626 aswp = a[good]
5627 m = np.median(np.fabs(aswp - d) / c, axis=0)
5629 return m
5631def showFinalMessage(overlayAntennas, solutionTimeSpread, nUniqueTimes):
5632 if (overlayAntennas and solutionTimeSpread > 0 and nUniqueTimes==1):
5633 print("If not all spws were shown, then try setting solutionTimeThreshold=%.0f seconds" % (solutionTimeSpread+1))
5635def computeOriginalSpwsToPlot(spwsToPlot, originalSpws, tableFormat, debug):
5636 if (tableFormat > 33):
5637 # New caltables use the same numbering as the original ms
5638 return(spwsToPlot)
5639 else:
5640 originalSpwsToPlot = []
5641 for spw in spwsToPlot:
5642 originalSpwsToPlot.append(originalSpws[spw])
5643 return(list(originalSpwsToPlot))
5645def computeScansForUniqueTimes(uniqueTimes, cal_scans, times, unique_cal_scans,
5646 debug=False):
5647 scansForUniqueTimes = []
5648 nUniqueTimes = len(uniqueTimes)
5649 for uT in uniqueTimes:
5650 if (debug): print("Checking uniqueTime = %s" % (str(uT)))
5651 scansForUniqueTimes.append(cal_scans[list(times).index(uT)])
5652 if (len(unique_cal_scans) == 1):
5653 if (unique_cal_scans[0] != -1):
5654 if (len(scansForUniqueTimes) != len(np.unique(scansForUniqueTimes))):
5655 if debug:
5656 print("Because there are multiple timestamps per scan, I will not assume there is a one-to-one match.")
5657 else:
5658 nUniqueTimes = len(np.unique(scansForUniqueTimes))
5659 else:
5660 # This 3.4 table does not have the scan numbers populated
5661 scansForUniqueTimes = []
5662 if debug:
5663 print("Because the scan numbers are either not filled in this table, or the solutions span multiple scans, I will use timestamps instead.")
5664 else:
5665 if (len(scansForUniqueTimes) != len(np.unique(scansForUniqueTimes))):
5666 if debug:
5667 print("Because there are multiple timestamps per scan, I will not assume there is a one-to-one match.")
5668 else:
5669 nUniqueTimes = len(np.unique(scansForUniqueTimes))
5670 return(scansForUniqueTimes, nUniqueTimes)
5673def calcChebyshev(coeff, validDomain, x):
5674 """
5675 Given a set of coefficients,
5676 this method evaluates a Chebyshev approximation.
5677 """
5678 if (type(x) == float or type(x) == int):
5679 x = [x]
5680 myxrange = validDomain[1] - validDomain[0]
5681 x = -1 + 2*(x-validDomain[0])/myxrange
5682 coeff[0] = 0
5683 if (True):
5684 try:
5685 # python 2.7
5686 v = np.polynomial.chebyshev.chebval(x,coeff)
5687 except:
5688 # python 2.6
5689 v = np.polynomial.chebval(x,coeff)
5690 else:
5691 # manual approach, before I found chebval()
5692 v = np.zeros(len(x))
5693 if (len(coeff) > 0):
5694 v += coeff[0] * 1
5695 if (len(coeff) > 1):
5696 v += coeff[1] * (x)
5697 if (len(coeff) > 2):
5698 v += coeff[2] * (2*x**2 - 1)
5699 if (len(coeff) > 3):
5700 v += coeff[3] * (4*x**3 - 3*x)
5701 if (len(coeff) > 4):
5702 v += coeff[4] * (8*x**4 - 8*x**2 + 1)
5703 if (len(coeff) > 5):
5704 v += coeff[5] * (16*x**5 - 20*x**3 + 5*x)
5705 if (len(coeff) > 6):
5706 v += coeff[6] * (32*x**6 - 48*x**4 + 18*x**2 - 1)
5707 if (len(coeff) > 7):
5708 v += coeff[7] * (64*x**7 -112*x**5 + 56*x**3 - 7*x)
5709 if (len(coeff) > 8):
5710 v += coeff[8] * (128*x**8 -256*x**6 +160*x**5 - 32*x**2 + 1)
5711 if (len(coeff) > 9):
5712 v += coeff[9] * (256*x**9 -576*x**7 +432*x**5 - 120*x**3 + 9*x)
5713 if (len(coeff) > 10):
5714 print("Chebyshev polynomials with degree > 10 are not implemented")
5716 return(v)
5718def ResizeFontsSetGrid(adesc,fontsize):
5719# print("Called ResizeFontsSetGrid()")
5720 yFormat = ScalarFormatter(useOffset=False)
5721 if adesc:
5722 adesc.yaxis.set_major_formatter(yFormat)
5723 adesc.xaxis.set_major_formatter(yFormat)
5724 pb.setp(adesc.get_xticklabels(), fontsize=fontsize)
5725 pb.setp(adesc.get_yticklabels(), fontsize=fontsize)
5726 adesc.xaxis.grid(True,which='major')
5727 adesc.yaxis.grid(True,which='major')
5729def complexMeanRad(phases):
5730 # convert back to real and imaginary, take mean, then convert back to phase
5731 meanSin = np.mean(np.sin(phases))
5732 meanCos = np.mean(np.cos(phases))
5733 return(180*np.arctan2(meanSin, meanCos)/math.pi)
5735def complexMeanDeg(phases):
5736 # convert back to real and imaginary, take mean, then convert back to phase
5737 phases *= math.pi/180
5738 meanSin = np.mean(np.sin(phases))
5739 meanCos = np.mean(np.cos(phases))
5740 return(180*np.arctan2(meanSin, meanCos)/math.pi)
5742def CalcAtmTransmission(chans,freqs,xaxis,pwv,vm, mymsmd,vis,asdm,antenna,timestamp,
5743 interval,field,refFreqInTable, net_sideband=0,
5744 mytime=0, missingCalWVRErrorPrinted=False, caltable='',
5745 Trx=None, showtsys=False, verbose=False):
5746 """
5747 chans: all channels, regardless of whether they are flagged
5748 freqs: frequencies corresponding to chans
5749 xaxis: what we are plotting on the xaxis: 'chan' or 'freq'
5750 """
5751# print("CalcAtm, field = ", field)
5752# print("interval = ", interval)
5753# print("refFreqInTable = ", refFreqInTable)
5754 if (type(mymsmd) == str):
5755 telescopeName = getTelescopeNameFromCaltable(caltable)
5756 else:
5757 telescopeName = mymsmd.observatorynames()[0]
5758 if (telescopeName.find('ALMA') >= 0):
5759 defaultPWV = 1.0 # a reasonable value for ALMA in case it cannot be found
5760 elif (telescopeName.find('VLA') >= 0):
5761 defaultPWV = 5.0
5762 else:
5763 defaultPWV = 5.0
5764 if (type(pwv) == str):
5765 if (pwv.find('auto')>=0):
5766 if (os.path.exists(vis+'/ASDM_CALWVR') or os.path.exists(vis+'/ASDM_CALATMOSPHERE') or
5767 os.path.exists('CalWVR.xml')):
5768 if (verbose):
5769 print("*** Computing atmospheric transmission using measured PWV, field %d, time %d (%f). ***" % (field,mytime,timestamp))
5770 timerange = [timestamp-interval/2, timestamp+interval/2]
5771 if (os.path.exists(vis+'/ASDM_CALWVR') or os.path.exists(vis+'/ASDM_CALATMOSPHERE')):
5772 [pwvmean, pwvstd] = getMedianPWV(vis,timerange,asdm,verbose=False)
5773 else:
5774 [pwvmean, pwvstd] = getMedianPWV('.',timerange,asdm='',verbose=False)
5775 if (verbose):
5776 print("retrieved pwvmean = %f" % pwvmean)
5777 retrievedPWV = pwvmean
5778 if (pwvmean < 0.00001):
5779 pwvmean = defaultPWV
5780 else:
5781 pwvmean = defaultPWV
5782 if (missingCalWVRErrorPrinted == False):
5783 missingCalWVRErrorPrinted = True
5784 if (telescopeName.find('ALMA')>=0):
5785 print("No ASDM_CALWVR, ASDM_CALATMOSPHERE, or CalWVR.xml table found. Using PWV %.1fmm." % pwvmean)
5786 else:
5787 print("This telescope has no WVR to provide a PWV measurement. Using PWV %.1fmm." % pwvmean)
5788 else:
5789 try:
5790 pwvmean = float(pwv)
5791 except:
5792 pwvmean = defaultPWV
5793 else:
5794 try:
5795 pwvmean = float(pwv)
5796 except:
5797 pwvmean = defaultPWV
5799 if (verbose):
5800 print("Using PWV = %.2f mm" % pwvmean)
5802 # default values in case we can't find them below
5803 myqa = quanta()
5804 airmass = 1.5
5805 P = 563.0
5806 H = 20.0
5807 T = 273.0
5808 roundedScanTimes = []
5809 if (type(mymsmd) != str):
5810 if (verbose):
5811 print("Looking for scans for field integer = %d" % (field))
5812 scans = mymsmd.scansforfield(field)
5813 if (verbose):
5814 print(("For field %s, Got scans = " % str(field),scans))
5815 for myscan in scans:
5816 roundedScanTimes.append(np.unique(np.round(mymsmd.timesforscan(myscan))))
5817# This method was much slower and not necessary. Removed for CAS-8065
5818# scantimes = mymsmd.timesforscans(scans) # is often longer than the scans array
5819# roundedScanTimes = np.unique(np.round(scantimes,0))
5820# scans, roundedScanTimes = getScansForTimes(mymsmd,roundedScanTimes) # be sure that each scantime has a scan associated, round to nearest second to save time (esp. for single dish data)
5821# if (verbose): print("scantimes = %s" % (str(scantimes)))
5822# if (verbose): print("scans = %s" % (str(scans)))
5823 mindiff = 1e20
5824 bestscan = 1
5825 for i in range(len(roundedScanTimes)):
5826 stime = roundedScanTimes[i]
5827 meantime = np.mean(stime)
5828 tdiff = np.abs(meantime-timestamp)
5829 # if (verbose): print("tdiff = %s" % (str(tdiff)))
5830 if (tdiff < mindiff):
5831 bestscan = scans[i]
5832 if (verbose): print("bestscan = %s" % (str(bestscan)))
5833 mindiff = tdiff
5834 if (verbose):
5835 print("For timestamp=%.1f, got closest scan = %d, %.0f sec away" %(timestamp, bestscan,mindiff))
5836 if (verbose): print("Calling getWeather()")
5837 [conditions,myTimes] = getWeather(vis,bestscan,antenna,verbose,mymsmd)
5838 if (verbose): print("Done getWeather()")
5840 # convert pressure with unit to the value in mbar
5841 if (verbose): print("conditions = ", conditions)
5842 P = myqa.convert(myqa.quantity(conditions['pressure'], conditions['pressure_unit']), 'mbar')['value']
5843 if P < 100: ### added 2024Aug
5844 # then the units are wrong, as in early ALMA data had units="Pa" but value was in mbar
5845 P = conditions['pressure'] ### added 2024Aug
5846 casalogPost(verbose,"Ignoring pressure units '%s' because the value implied would be less than 100 mbar."%(conditions['pressure_unit'])) ### added 2024Aug
5847 H = conditions['humidity']
5848 T = conditions['temperature']+273.15
5849 if (P <= 0.0):
5850 P = 563
5851 if (H <= 0.0):
5852 H = 20
5853 else:
5854 conditions = {}
5855 if (type(mymsmd) != str):
5856 if ('elevation' not in list(conditions.keys())):
5857 # Someone cleared the POINTING table, so calculate elevation from Ra/Dec/MJD
5858# myfieldId = mymsmd.fieldsforname(mymsmd.fieldsforscan(bestscan))
5859 myfieldId = mymsmd.fieldsforscan(bestscan)[0]
5860 myscantime = np.mean(mymsmd.timesforscan(bestscan))
5861 mydirection = getRADecForField(vis, myfieldId, verbose)
5862 if (verbose):
5863 print("myfieldId = %s" % (str(myfieldId)))
5864 print("mydirection = %s" % (str(mydirection)))
5865 print("Scan = %d, time = %.1f, Field = %d, direction = %s" % (bestscan, myscantime, myfieldId, str(mydirection)))
5866 telescopeName = mymsmd.observatorynames()[0]
5867 if (len(telescopeName) < 1):
5868 telescopeName = 'ALMA'
5869 if verbose: ### added 2024Aug to prevent lots of spam to the terminal
5870 print("telescope = %s" % (telescopeName))
5871 myazel = computeAzElFromRADecMJD(mydirection, myscantime/86400., telescopeName)
5872 conditions['elevation'] = myazel[1] * 180/math.pi
5873 conditions['azimuth'] = myazel[0] * 180/math.pi
5874 if (verbose):
5875 print("Computed elevation = %.1f deg" % (conditions['elevation']))
5876 else:
5877 conditions['elevation'] = 45
5878 casalogPost(verbose,"Using 45 deg elevation since the actual value is unavailable.")
5879 bestscan = -1
5880 if (verbose):
5881 print("CalcAtm: found elevation=%f (airmass=%.3f) for scan: %s" % (conditions['elevation'],1/np.sin(conditions['elevation']*np.pi/180.), str(bestscan)))
5882 print("P,H,T = %f,%f,%f" % (P,H,T))
5883 if (conditions['elevation'] <= 3):
5884 print("Using 45 deg elevation instead")
5885 airmass = 1.0/math.cos(45*math.pi/180.)
5886 else:
5887 airmass = 1.0/math.cos((90-conditions['elevation'])*math.pi/180.)
5889 # get the elevation of the antenna
5890 geodetic_elevation = 5059
5891 if os.path.exists(os.path.join(vis, 'ANTENNA')):
5892 with sdutil.table_manager(os.path.join(vis, 'ANTENNA')) as tb:
5893 _X, _Y, _Z = (float(i) for i in tb.getcell('POSITION', antenna))
5894 geodetic_elevation = simutil.simutil().xyz2long(_X, _Y, _Z, 'WGS84')[2]
5895 if verbose:
5896 casalogPost(True,"computed geodetic_elevation from ANTENNA table as %s" % str(geodetic_elevation))
5898 tropical = 1
5899 midLatitudeSummer = 2
5900 midLatitudeWinter = 3
5901 numchan = len(freqs)
5902 # Set the reference freq to be the middle of the middle two channels
5903 reffreq=0.5*(freqs[numchan//2-1]+freqs[numchan//2])
5904 originalnumchan = numchan
5905 while (numchan > MAX_ATM_CALC_CHANNELS):
5906 numchan //= 2
5907# print("Reducing numchan to ", numchan)
5908 chans = list(range(0,originalnumchan,(originalnumchan//numchan)))
5910 chansep = (freqs[-1]-freqs[0])/(numchan-1)
5911 nbands = 1
5912 if (verbose): print("Opening casac.atmosphere()")
5913 myat = atmosphere()
5914 if (verbose): print("Opened")
5915 fCenter = myqa.quantity(reffreq,'GHz')
5916 fResolution = myqa.quantity(chansep,'GHz')
5917 fWidth = myqa.quantity(numchan*chansep,'GHz')
5918 h0 = 1.0 # km
5919 dP = 5.0 # mbar
5920 dPm = 1.1 # unitless ratio
5921# print(H, T, geodetic_elevation,P, midLatitudeWinter, maxAltitude, h0, dP, dPm)
5922 myat.initAtmProfile(humidity=H, temperature=myqa.quantity(T, "K"),
5923 altitude=myqa.quantity(geodetic_elevation, "m"),
5924 pressure=myqa.quantity(P, 'mbar'),
5925 atmType=midLatitudeWinter,
5926 h0=myqa.quantity(h0,"km"),
5927 maxAltitude=myqa.quantity(maxAltitude,"km"),
5928 dP=myqa.quantity(dP,"mbar"),
5929 dPm=dPm)
5930 myat.initSpectralWindow(nbands,fCenter,fWidth,fResolution)
5931 myat.setUserWH2O(myqa.quantity(pwvmean,'mm'))
5933# myat.setAirMass() # This does not affect the opacity, but it does effect TebbSky, so do it manually.
5935 n = myat.getNumChan()
5936 if (verbose): print("numchan = %s" % (str(n)))
5937 if ctsys.compare_version('<',[4,0,0]):
5938 dry = np.array(myat.getDryOpacitySpec(0)['dryOpacity'])
5939 wet = np.array(myat.getWetOpacitySpec(0)['wetOpacity'].value)
5940 TebbSky = []
5941 for chan in range(n): # do NOT use numchan here, use n
5942 TebbSky.append(myat.getTebbSky(nc=chan, spwid=0).value)
5943 TebbSky = np.array(TebbSky)
5944 # readback the values to be sure they got set
5945 #rf = myat.getRefFreq().value
5946 #cs = myat.getChanSep().value
5947 else: # casa >=4.0
5948 dry = np.array(myat.getDryOpacitySpec(0)[1])
5949 wet = np.array(myat.getWetOpacitySpec(0)[1]['value'])
5950 TebbSky = myat.getTebbSkySpec(spwid=0)[1]['value']
5951 # readback the values to be sure they got set
5952 #rf = myqa.convert(myat.getRefFreq(),'GHz')['value']
5953 #cs = myqa.convert(myat.getChanSep(),'GHz')['value']
5955 transmission = np.exp(-airmass*(wet+dry))
5956 TebbSky *= (1-np.exp(-airmass*(wet+dry)))/(1-np.exp(-wet-dry))
5958 if (refFreqInTable*1e-9>np.mean(freqs)):
5959 if ((net_sideband % 2) == 0):
5960 sense = 1
5961 else:
5962 sense = 2
5963 else:
5964 if ((net_sideband % 2) == 0):
5965 sense = 2
5966 else:
5967 sense = 1
5969 if (sense == 1):
5970 # The following looks right for LSB sense=1
5971 if (xaxis.find('chan')>=0):
5972 trans = np.zeros(len(transmission))
5973 Tebb = np.zeros(len(TebbSky))
5974 for i in range(len(transmission)):
5975 trans[i] = transmission[len(transmission)-1-i]
5976 Tebb[i] = TebbSky[len(TebbSky)-1-i]
5977 transmission = trans
5978 TebbSky = Tebb
5979 if showtsys:
5980 if Trx is None or Trx == 'auto':
5981 Trx = au.receiverTrxSpec(au.getBand(freqs[0]*1e9))
5982 Tsys = (Feff*TebbSky + (1.0-Feff)*Tamb + Trx) * ((1.0 + (1.0-SBGain)) / (Feff*np.exp(-airmass*(wet+dry))))
5983 else:
5984 Tsys = None
5986 # Be sure that number of frequencies matched number of transmission values - CAS-10123
5987 numchan = len(transmission)
5988 chans = list(range(len(transmission)))
5989 # Note that getChanFreq returns units of GHz, but use convert to be sure.
5990 startFreq = myqa.convert(myat.getChanFreq(0),'GHz')['value']
5991 endFreq = myqa.convert(myat.getChanFreq(numchan-1),'GHz')['value']
5992 # print("startFreq=%f endFreq=%f " % (startFreq, endFreq))
5993 freq = np.linspace(startFreq, endFreq, numchan)
5994# old method that fails on spws with an even number of channels, i.e. when the integer refchan
5995# is half a channel from the center of the span
5996# if sense == 2:
5997# freq = np.linspace(rf-((numchan-1)/2.)*chansepGHz, rf+((numchan-1)/2.)*chansepGHz, numchan)
5998# else:
5999# freq = np.linspace(rf+((numchan-1)/2.)*chansepGHz,
6000# rf-((numchan-1)/2.)*chansepGHz, numchan)
6001 # Therewas a 1-channel offset in CASA 5.0.x (CAS-10228), but it was fixed.
6002# if (ctsys.compare_version('<',[5,1,0])):
6003# freq += chansepGHz
6005 if (verbose): print("Done CalcAtmTransmission")
6006 return(freq, chans, transmission, pwvmean, airmass, TebbSky, missingCalWVRErrorPrinted)
6008def RescaleTrans(trans, lim, subplotRows, lo1='', xframe=0):
6009 # Input: the array of transmission or TebbSky values and current limits
6010 # Returns: arrays of the rescaled transmission values and the zero point
6011 # values in units of the frame, and in amplitude.
6012 debug = False
6013 yrange = lim[1]-lim[0]
6014 if (lo1 == ''):
6015 labelgap = 0.6 # Use this fraction of the margin for the PWV ATM label
6016 else:
6017 labelgap = 0.5 # Use this fraction of the margin to separate the top
6018 # curve from the upper y-axis
6019 y2 = lim[1] - labelgap*yrange*TOP_MARGIN/(1.0+TOP_MARGIN)
6020 y1 = lim[1] - yrange*TOP_MARGIN/(1.0+TOP_MARGIN)
6021 transmissionRange = np.max(trans)-np.min(trans)
6022 if (transmissionRange < 0.05):
6023 # force there to be a minimum range of transmission display
6024 # overemphasize tiny ozone lines
6025 transmissionRange = 0.05
6027 if (transmissionRange > 1 and transmissionRange < 10):
6028 # force there to be a minimum range of Tebbsky (10K) to display
6029 transmissionRange = 10
6031 # convert transmission to amplitude
6032 newtrans = y2 - (y2-y1)*(np.max(trans)-trans)/transmissionRange
6034 # Use edge values
6035 edgeValueTransmission = trans[-1]
6036 otherEdgeValueTransmission = trans[0]
6038 # Now convert the edge channels' transmission values into amplitude
6039 edgeValueAmplitude = y2 - (y2-y1)*(np.max(trans)-trans[-1])/transmissionRange
6040 otherEdgeValueAmplitude = y2 - (y2-y1)*(np.max(trans)-trans[0])/transmissionRange
6042 # Now convert amplitude to frame units, offsetting downward by half
6043 # the font size
6044 fontoffset = 0.01*subplotRows
6045 edgeValueFrame = (edgeValueAmplitude - lim[0])/yrange - fontoffset
6046 otherEdgeValueFrame = (otherEdgeValueAmplitude - lim[0])/yrange - fontoffset
6048 # scaleFactor is how large the plot is from the bottom x-axis
6049 # up to the labelgap, in units of the transmissionRange
6050 scaleFactor = (1+TOP_MARGIN*(1-labelgap)) / (TOP_MARGIN*(1-labelgap))
6052 # compute the transmission at the bottom of the plot, and label it
6053 y0transmission = np.max(trans) - transmissionRange*scaleFactor
6054 y0transmissionFrame = 0
6055 y0transmissionAmplitude = lim[0]
6057 if (y0transmission <= 0):
6058 # If the bottom of the plot is below zero transmission, then label
6059 # the location of zero transmission instead.
6060 if (debug):
6061 print("--------- y0transmission original = %f, (y1,y2)=(%f,%f)" % (y0transmission,y1,y2))
6062 y0transmissionAmplitude = y1-(y2-y1)*(np.min(trans)/transmissionRange)
6063 y0transmissionFrame = (y0transmissionAmplitude-lim[0]) / (lim[1]-lim[0])
6064 y0transmission = 0
6065 if (debug):
6066 print("-------- xframe=%d, scaleFactor = %s" % (xframe, str(scaleFactor)))
6067 print("edgeValueFrame, other = %s, %s" % (str(edgeValueFrame), str(otherEdgeValueFrame)))
6068 print("edgeValueTransmission, other = %s, %s" % (str(edgeValueTransmission), str(otherEdgeValueTransmission)))
6069 print("edgeValueAmplitude, otherEdgeValueAmplitude = %s, %s" % (str(edgeValueAmplitude), str(otherEdgeValueAmplitude)))
6070 print("y0transmission = %f, y0transmissionFrame = %f" % (y0transmission,y0transmissionFrame))
6071 print("y0transmissionAmplitude = %s" % (str(y0transmissionAmplitude)))
6072 print("transmissionRange = %s" % (str(transmissionRange)))
6073 return(newtrans, edgeValueFrame, y0transmission, y0transmissionFrame,
6074 otherEdgeValueFrame, edgeValueTransmission,
6075 otherEdgeValueTransmission, edgeValueAmplitude,
6076 otherEdgeValueAmplitude, y0transmissionAmplitude)
6078def RescaleX(chans, lim, plotrange, channels):
6079 # This function is now only used by DrawAtmosphere when xaxis='chan'.
6080 # It is only really necessary when len(chans)>MAX_ATM_CALC_CHANNELS.
6081 # - September 2012
6082 # If the user specified a plotrange, then rescale to this range,
6083 # otherwise rescale to the automatically-determined range.
6085 # chans = 0..N where N=number of channels in the ATM_CALC
6086 # channels = 0..X where X=number of channels in the spw, regardless of flagging
6088 if (len(chans) != len(channels)):
6089 if (chans[1] > chans[0]):
6090 atmchanrange = chans[-1]-chans[0]
6091 else:
6092 atmchanrange = chans[0]-chans[-1]
6093 if len(channels) == 0: ### added 2024Aug to prevent crash
6094 return(chans) ### added 2024Aug to prevent crash
6095 if (channels[1] > channels[0]):
6096 chanrange = channels[-1]-channels[0]
6097 else:
6098 chanrange = channels[0]-channels[-1]
6100 newchans = np.array(chans)*chanrange/atmchanrange
6101 return(newchans)
6102 else:
6103 return(chans)
6105def recalcYlimitsFreq(chanrange, ylimits, amp, sideband,plotrange,xchannels,
6106 debug=False,location=0,chanrangePercent=None):
6107 # Used by plots with xaxis='freq'
6108 # xchannels are the actual channel numbers of unflagged data, i.e. displayed points
6109 # amp is actual data plotted
6110 ylim_debug = False
6111 if (len(amp) < 1):
6112 return(pb.ylim()) # ylimits)
6113 if (chanrange[0]==0 and chanrange[1] == 0 and plotrange[2] == 0 and plotrange[3]==0
6114 and chanrangePercent == None):
6115 if (len(amp) == 1):
6116 if (ylim_debug):
6117 print("amp = %s" % (str(amp)))
6118 ylimits = [amp[0]-0.2, amp[0]+0.2]
6119 else:
6120 newmin = np.min(amp)
6121 newmax = np.max(amp)
6122 newmin = np.min([ylimits[0],newmin])
6123 newmax = np.max([ylimits[1],newmax])
6124 ylimits = [newmin, newmax]
6125 elif ((abs(chanrange[0]) > 0 or abs(chanrange[1]) > 0)):
6126 plottedChannels = np.intersect1d(xchannels, list(range(chanrange[0],chanrange[1]+1)))
6127 if (len(plottedChannels) < 1):
6128 return(ylimits)
6129 mylist = np.arange(xchannels.index(plottedChannels[0]), 1+xchannels.index(plottedChannels[-1]))
6130 if (mylist[-1] >= len(amp)):
6131 # prevent crash if many channels are flagged
6132 return(ylimits)
6133 if (ylim_debug):
6134 print("Starting with limits = %s" % (str(ylimits)))
6135 print("Examining channels: %s" % (str(mylist)))
6136 print("len(amp): %d" % (len(amp)))
6137 print("Examining values: amp[mylist] = %s" % (str(amp[mylist])))
6138 newmin = np.min(amp[mylist])
6139 newmax = np.max(amp[mylist])
6140 newmin = np.min([ylimits[0],newmin])
6141 newmax = np.max([ylimits[1],newmax])
6142 # The following presents a problem with overlays, as it keeps widening forever
6143# # newmin -= 0.05*(newmax-newmin)
6144# # newmax += 0.05*(newmax-newmin)
6145 ylimits = [newmin, newmax]
6146 elif (chanrangePercent != None):
6147 startFraction = (100-chanrangePercent)*0.5*0.01
6148 stopFraction = 1-(100-chanrangePercent)*0.5*0.01
6149 if (xchannels == []):
6150 # prevent crash if many channels are flagged: 2015-04-13
6151 return(ylimits)
6152 cr0 = int(np.round(np.max(xchannels)*startFraction))
6153 cr1 = int(np.round(np.max(xchannels)*stopFraction))
6154 plottedChannels = np.intersect1d(xchannels, list(range(cr0, cr1+1)))
6155 if (len(plottedChannels) < 1):
6156 return(ylimits)
6157 mylist = np.arange(xchannels.index(plottedChannels[0]), 1+xchannels.index(plottedChannels[-1]))
6158 if (mylist[-1] >= len(amp)):
6159 # prevent crash if many channels are flagged
6160 return(ylimits)
6161 if (ylim_debug):
6162 print("Starting with limits = ", ylimits)
6163 print("Examining channels: ", mylist)
6164 print("len(amp): %d" % (len(amp)))
6165 print("type(amp) = %s" % (str(type(amp))))
6166 print("Examining values: amp[mylist] = %s" % (str(amp[mylist])))
6167 newmin = np.min(amp[mylist])
6168 newmax = np.max(amp[mylist])
6169 newmin = np.min([ylimits[0],newmin])
6170 newmax = np.max([ylimits[1],newmax])
6171 ylimits = [newmin, newmax]
6172 if (ylim_debug):
6173 print("Returning with limits = %s" % (str(ylimits)))
6174 return ylimits
6176def recalcYlimits(plotrange, ylimits, amp):
6177 # Used by plots with xaxis='chan'
6178 if (len(amp) < 1):
6179 return(pb.ylim())
6180 if ((abs(plotrange[0]) > 0 or abs(plotrange[1]) > 0) and (plotrange[2] == 0 and plotrange[3] == 0)):
6181 x0 = int(plotrange[0])
6182 x1 = int(plotrange[1])
6183 if (x0 < 0):
6184 x0 = 0
6185 if (x1 > len(amp)-1):
6186 x1 = len(amp)-1
6187 if (len(amp) > x1 and x0 < x1):
6188 newmin = np.min(amp[x0:x1])
6189 newmax = np.max(amp[x0:x1])
6190 newmin = np.min([ylimits[0],newmin])
6191 newmax = np.max([ylimits[1],newmax])
6192 ylimits = [newmin, newmax]
6193 else:
6194 ylimits = pb.ylim() # added on 10/27/2011
6195# # print("current ylimits = ", ylimits)
6196 return(ylimits)
6198def SetNewYLimits(newylimits):
6199# print("Entered SetNewYLimits with ", newylimits )
6200 newrange = newylimits[1]-newylimits[0]
6201 if (newrange > 0):
6202 pb.ylim([newylimits[0]-0.0*newrange, newylimits[1]+0.0*newrange])
6204def SetNewXLimits(newxlimits, loc=0):
6205# print("loc=%d: Entered SetNewXLimits with range = %.3f (%f-%f)" % (loc,np.max(newxlimits)-np.min(newxlimits), newxlimits[0], newxlimits[1]))
6206 myxrange = np.abs(newxlimits[1]-newxlimits[0])
6207 if (myxrange == 0):
6208 myxrange = 0.001
6209 mybuffer = 0.01
6210 if (newxlimits[0] < newxlimits[1]):
6211 pb.xlim([newxlimits[0]-myxrange*mybuffer,newxlimits[1]+myxrange*mybuffer] )
6212 else:
6213# print("Swapping xlimits order")
6214 pb.xlim(newxlimits[1]-myxrange*mybuffer, newxlimits[0]+myxrange*mybuffer)
6216def sloppyMatch(newvalue, mylist, threshold, mytime=None, scansToPlot=[],
6217 scansForUniqueTimes=[], myprint=False, whichone=False):
6218 """
6219 If scan numbers are present, perform an exact match, otherwise compare the
6220 time stamps of the solutions.
6221 """
6222 debug = myprint
6223 if (debug):
6224 print("sloppyMatch: scansToPlot = %s" % (str(scansToPlot)))
6225 mymatch = None
6226 if (len(scansToPlot) > 0):
6227 if (mytime >= len(scansForUniqueTimes)):
6228 print("sloppyMatch() mytime is too large: mytime=%d >= len(scansForUniqueTimes)=%d: " % (mytime, len(scansForUniqueTimes)), scansForUniqueTimes)
6229 matched = scansForUniqueTimes[mytime] in scansToPlot
6230 if (whichone or myprint):
6231 myscan = scansForUniqueTimes[mytime]
6232 if (myscan in scansToPlot):
6233 mymatch = list(scansToPlot).index(myscan)
6234 if (matched == False and myprint==True):
6235 print("sloppyMatch: %d is not in %s" % (myscan, list(scansToPlot)))
6236 elif (myprint==True):
6237 print("sloppyMatch: %d is in %s" % (myscan, list(scansToPlot)))
6238 else:
6239 matched = False
6240 if (type(mylist) != list and type(mylist)!=np.ndarray):
6241 mylist = [mylist]
6242 mymatch = -1
6243 for i in range(len(mylist)):
6244 v = mylist[i]
6245 if (abs(newvalue-v) < threshold):
6246 matched = True
6247 mymatch = i
6248 if (matched == False and myprint==True):
6249 print("sloppyMatch: %.0f is not within %.0f of anything in %s" % (newvalue,threshold, str([int(round(b)) for b in mylist])))
6250 elif (myprint==True):
6251 print("sloppyMatch: %.0f is within %.0f of something in %s" % (newvalue,threshold, str([int(round(b)) for b in mylist])))
6252 if (whichone == False):
6253 return(matched)
6254 else:
6255 return(matched,mymatch)
6257# replacement function with extra optional parameter added on 2024Aug
6258def sloppyUnique(t, thresholdSeconds, cal_scans=None):
6259 """
6260 Takes a list of numbers and returns a list of unique values, subject
6261 to a threshold difference.
6262 cal_scans: if specified, then perform the analysis per scan number
6263 """
6264 # start with the first entry (t[0]), and only add a new entry if it is more than the threshold from prior
6265 if cal_scans is None:
6266 sloppyList = [t[0]]
6267 for i in range(1,len(t)):
6268 keepit = True
6269 # for j in range(0,i): # prior to PIPE-1519
6270 # if (abs(t[i]-t[j]) < thresholdSeconds):
6271 for j in range(len(sloppyList)):
6272 if (abs(t[i]-sloppyList[j]) < thresholdSeconds):
6273 keepit = False
6274 if (keepit):
6275 sloppyList.append(t[i])
6276 else:
6277 # build a list of one time per calibration scan
6278 uniqueCalScans = np.unique(cal_scans)
6279 t = np.array(t)
6280 sloppyList = []
6281# print("len(t) = %d, len(cal_scans) = %d" % (len(t),len(cal_scans)))
6282 for k,calscan in enumerate(uniqueCalScans):
6283 times = t[np.where(calscan == cal_scans)]
6284 sloppyList.append(times[0])
6285# print "sloppyUnique returns %d values from the original %d" % (len(sloppyList), len(t))
6286 return(sloppyList)
6288# commented out 2024Aug
6289#def sloppyUnique(t, thresholdSeconds):
6290# """
6291# Takes a list of numbers and returns a list of unique values, subject to a threshold difference.
6292# """
6293# # start with the first entry, and only add a new entry if it is more than the threshold from prior
6294# sloppyList = [t[0]]
6295# for i in range(1,len(t)):
6296# keepit = True
6297# for j in range(0,i):
6298# if (abs(t[i]-t[j]) < thresholdSeconds):
6299# keepit = False
6300# if (keepit):
6301# sloppyList.append(t[i])
6302## print("sloppyUnique returns %d values from the original %d" % (len(sloppyList), len(t)))
6303# return(sloppyList)
6305def SetLimits(plotrange, chanrange, newylimits, channels, frequencies, pfrequencies,
6306 ampMin, ampMax, xaxis, pxl, chanrangeSetXrange, chanrangePercent=None):
6307 """
6308 This is the place where chanrange actually takes effect.
6309 """
6310 if (abs(plotrange[0]) > 0 or abs(plotrange[1]) > 0):
6311 SetNewXLimits([plotrange[0],plotrange[1]])
6312 if (plotrange[2] == 0 and plotrange[3] == 0):
6313 # reset the ylimits based on the channel range shown (selected via plotrange)
6314 SetNewYLimits(newylimits)
6315 else: # set xlimits to full range
6316 if (xaxis.find('chan')>=0):
6317 SetNewXLimits([channels[0],channels[-1]])
6318 else:
6319 if (chanrangeSetXrange or (chanrange[0]==0 and chanrange[1]==0 and chanrangePercent==None)): # CAS-7965
6320 # print("SetLimits(): Setting x limits to full range (%f-%f)" % (frequencies[0], frequencies[-1]))
6321 SetNewXLimits([frequencies[0], frequencies[-1]])
6322 if (chanrange[0] != 0 or chanrange[1] != 0 or chanrangePercent != None):
6323 # reset the ylimits based on the channel range specified (selected via chanrange)
6324 if (newylimits != [LARGE_POSITIVE, LARGE_NEGATIVE]):
6325 SetNewYLimits(newylimits)
6326# print("pxl=%d, chanrange[0]=%d, chanrange[1]=%d, shape(pfreq), shape(freq)=" % (pxl, chanrange[0], chanrange[1]), np.shape(pfrequencies),np.shape(frequencies))
6327 # Use frequencies instead of pfrequencies, because frequencies are not flagged and
6328 # will continue to work if chanranze is specified and data are flagged.
6329 if chanrangeSetXrange:
6330 if (chanrangePercent == None):
6331 try:
6332 SetNewXLimits([frequencies[chanrange[0]], frequencies[chanrange[1]]]) # Apr 3, 2012
6333 except:
6334 print("a)Invalid chanrange (%d-%d). Valid range = 0-%d" % (chanrange[0],chanrange[1],len(frequencies)-1))
6335 return(-1)
6336 else:
6337 startFraction = (100-chanrangePercent)*0.5*0.01
6338 stopFraction = 1-(100-chanrangePercent)*0.5*0.01
6339 cr0 = int(np.round(np.max(channels)*startFraction))
6340 cr1 = int(np.round(np.max(channels)*stopFraction))
6341 try:
6342 SetNewXLimits([frequencies[cr0], frequencies[cr1]])
6343 except:
6344 print("b)Invalid chanrange (%d-%d). Valid range = 0-%d" % (cr0,cr1,len(frequencies)-1))
6345 return(-1)
6346 if (abs(plotrange[2]) > 0 or abs(plotrange[3]) > 0):
6347 SetNewYLimits([plotrange[2],plotrange[3]])
6348 return(0)
6350def showFDM(originalSpw, chanFreqGHz, baseband, showBasebandNumber, basebandDict, overlayColors):
6351 """
6352 Draws a horizontal bar indicating the location of FDM spws in the dataset.
6354 Still need to limit based on the baseband -- need dictionary passed in.
6355 originalSpw: should contain all spws in the dataset, not just the ones
6356 in the caltable
6357 baseband: the baseband of the current spw
6358 showBasebandNumber: force the display of all FDM spws, and their baseband number
6359 basebandDict: {1:[17,19], 2:[21,23], etc.} or {} for really old datasets
6360 """
6362 # add some space at the bottom -- Apr 25, 2012
6363 ylim = pb.ylim()
6364 yrange = ylim[1]-ylim[0]
6365 pb.ylim([ylim[0]-BOTTOM_MARGIN*yrange, ylim[1]])
6367 sdebug = False
6368 if (sdebug):
6369 print(("Showing FDM (%d)" % (len(originalSpw)), originalSpw))
6370 print("baseband = %d, basebandDict = %s" % (baseband, str(basebandDict)))
6371 fdmctr = -1
6372 x0,x1 = pb.xlim()
6373 y0,y1 = pb.ylim()
6374 yrange = y1 - y0
6375 myxrange = x1 - x0
6376 labelAbove = False # False means label to the right
6377 for i in range(len(originalSpw)):
6378 nchan = len(chanFreqGHz[i])
6379 # latter 3 values are for ACA with FPS enabled
6380 if (nchan >= 15 and nchan not in [256,128,64,32,16,248,124,62]):
6381 if (originalSpw[i] in basebandDict[baseband] or showBasebandNumber):
6382 fdmctr += 1
6383 verticalOffset = fdmctr*0.04*yrange
6384 y1a = y0 + 0.03*yrange + verticalOffset
6385 if (labelAbove):
6386 y2 = y1a + 0.01*yrange
6387 else:
6388 y2 = y1a - 0.016*yrange
6389# print("chan=%d: Drawing line at y=%f (y0=%f) from x=%f to %f" % (len(chanFreqGHz[i]),
6390# y1a,y0,chanFreqGHz[i][0], chanFreqGHz[i][-1]))
6391 f0 = chanFreqGHz[i][0]
6392 f1 = chanFreqGHz[i][-1]
6393 if (f1 < f0):
6394 swap = f1
6395 f1 = f0
6396 f0 = swap
6397 v0 = np.max([f0,x0])
6398 v1 = np.min([f1,x1])
6399 if (v1 > v0):
6400 if (labelAbove):
6401 xlabel = 0.5*(v0+v1)
6402 if (xlabel < x0):
6403 xlabel = x0
6404 if (xlabel > x1):
6405 xlabel = x1
6406 else:
6407 xlabel = v1+0.02*myxrange
6408 pb.plot([v0,v1], [y1a,y1a], '-',
6409 linewidth=4, color=overlayColors[fdmctr],markeredgewidth=markeredgewidth)
6410 if (showBasebandNumber):
6411 mybaseband = [key for key in basebandDict if i in basebandDict[key]]
6412 if (len(mybaseband) > 0):
6413 pb.text(xlabel, y2, "spw%d(bb%d)"%(i,mybaseband[0]), size=7)
6414 else:
6415 pb.text(xlabel, y2, "spw%d(bb?)"%(i), size=7)
6416 else:
6417 pb.text(xlabel, y2, "spw%d"%(i), size=7)
6418 if (sdebug): print("Plotting spw %d (%d)" % (i, originalSpw[i]))
6419 else:
6420 if (sdebug): print("Not plotting spw %d (%d) because %f < %f" % (i,originalSpw[i],v0,v1))
6421 else:
6422 if (sdebug): print("Not plotting spw %d (%d) because it is not in baseband %d (%s)" % (i,originalSpw[i],baseband,basebandDict[baseband]))
6423 else:
6424 if (sdebug): print("Not plotting spw %d (%d) because fewer than 256 channels (%d)" % (i,originalSpw[i],nchan))
6425 if (fdmctr > -1):
6426 pb.ylim([y0,y1])
6427 pb.xlim([x0,x1])
6429def DrawAtmosphere(showatm, showtsky, subplotRows, atmString, mysize,
6430 TebbSky, plotrange, xaxis, atmchan, atmfreq, transmission,
6431 subplotCols, lo1='', xframe=0, firstFrame=0,
6432 showatmPoints=False, channels=[0], mylineno=-1,xant=-1,
6433 overlaySpws=False, overlayBasebands=False, drewAtmosphere=False,
6434 loc=-1, showtsys=False, Trx=None):
6435 """
6436 Draws atmospheric transmission or Tsky on an amplitude vs. chan or freq plot.
6437 """
6438 xlim = pb.xlim()
6439 ylim = pb.ylim()
6440 myxrange = xlim[1]-xlim[0]
6441 yrange = ylim[1]-ylim[0]
6443 if (not drewAtmosphere and not overlayBasebands): # CAS-8489 final
6444 if (lo1 == ''):
6445 # add some space at the top -- Apr 16, 2012
6446 pb.ylim([ylim[0], ylim[1]+TOP_MARGIN*yrange])
6447 else:
6448 pb.ylim([ylim[0], ylim[1]+TOP_MARGIN*yrange*0.5])
6449 ylim = pb.ylim()
6450 yrange = ylim[1]-ylim[0]
6451 #
6452 ystartPolLabel = 1.0-0.04*subplotRows
6453 if (lo1 == ''):
6454 transmissionColor = 'm'
6455 tskyColor = 'm'
6456 else:
6457 transmissionColor = 'k'
6458 tskyColor = 'k'
6459 if (showatmPoints):
6460 atmline = '.'
6461 else:
6462 atmline = '-'
6463 if (showatm or showtsky):
6464 if (showatm):
6465 atmcolor = transmissionColor
6466 else:
6467 atmcolor = tskyColor
6468 if (lo1 == '' and not drewAtmosphere):
6469 pb.text(0.25, ystartPolLabel, atmString, color=atmcolor, size=mysize, transform=pb.gca().transAxes)
6471 if (showtsky):
6472 if showtsys:
6473 rescaledY = TebbSky
6474 if Trx == 'auto':
6475 scaleFactor = np.mean([ylim[1]-np.max(TebbSky), ylim[0]-np.min(TebbSky)])
6476 scaleFactor = 0.5*(ylim[1]+ylim[0]) - np.mean(TebbSky)
6477 rescaledY += scaleFactor
6478 else:
6479 rescaledY, edgeYvalue, zeroValue, zeroYValue, otherEdgeYvalue, edgeT, otherEdgeT, edgeValueAmplitude, otherEdgeValueAmplitude, zeroValueAmplitude = RescaleTrans(TebbSky, ylim, subplotRows, lo1, xframe)
6481 else:
6482 rescaledY, edgeYvalue, zeroValue, zeroYValue, otherEdgeYvalue, edgeT, otherEdgeT, edgeValueAmplitude, otherEdgeValueAmplitude, zeroValueAmplitude = RescaleTrans(transmission, ylim, subplotRows, lo1, xframe)
6483 if (overlayBasebands and xaxis.find('freq')>=0):
6484 # use axis coordinates for y-axis only so that transmission can be on common scale
6485 trans = matplotlib.transforms.blended_transform_factory(pb.gca().transData, pb.gca().transAxes)
6486 if showtsky:
6487 pb.plot(atmfreq, TebbSky/300., '%s%s'%(atmcolor,atmline),
6488 markeredgewidth=markeredgewidth, transform=trans)
6489 else:
6490 pb.plot(atmfreq, transmission, '%s%s'%(atmcolor,atmline),
6491 markeredgewidth=markeredgewidth, transform=trans)
6492 if (atmfreq[0]<atmfreq[1]):
6493 tindex = -1
6494 else:
6495 tindex = 0
6496 else:
6497 # use user coordinates
6498 if (xaxis.find('chan')>=0):
6499 rescaledX = RescaleX(atmchan, xlim, plotrange, channels)
6500 # rescaledX = atmchan
6501 pb.plot(rescaledX, rescaledY,'%s%s'%(atmcolor,atmline),markeredgewidth=markeredgewidth)
6502 tindex = -1
6503 elif (xaxis.find('freq')>=0):
6504 pb.plot(atmfreq, rescaledY, '%s%s'%(atmcolor,atmline),markeredgewidth=markeredgewidth)
6505 if (atmfreq[0]<atmfreq[1]):
6506 tindex = -1
6507 else:
6508 tindex = 0
6509 if (lo1 == ''):
6510 xEdgeLabel = 1.01
6511 else:
6512 if (xframe == firstFrame):
6513 xEdgeLabel = -0.10*subplotCols # avoids overwriting y-axis label
6514 else:
6515 xEdgeLabel = -0.10*subplotCols
6516 SetNewXLimits(xlim) # necessary for zoom='intersect'
6517 if (not overlayBasebands): # CAS-8489 final
6518 SetNewYLimits(ylim)
6519 # Now draw the percentage on right edge of plot
6520 if (not drewAtmosphere):
6521 if (overlayBasebands and xaxis.find('freq')>=0): # CAS-8489 final
6522 trans = matplotlib.transforms.blended_transform_factory(pb.gca().transData, pb.gca().transAxes)
6523 zeroValue = 0
6524 zeroValueAmplitude = 0
6525 edgeValueAmplitude = 1
6526 if (showtsky):
6527 edgeT = 300
6528 if (lo1 == ''):
6529 pb.text(xlim[1]+0.06*myxrange/subplotCols, edgeValueAmplitude,
6530 '%.0fK'%(edgeT), color=atmcolor, size=mysize, transform=trans)
6531 pb.text(xlim[1]+0.06*myxrange/subplotCols, zeroValueAmplitude,
6532 '%.0fK'%(zeroValue), color=atmcolor, transform=trans,
6533 size=mysize)
6534 else:
6535 pb.text(xEdgeLabel, edgeValueAmplitude,'%.0fK'%(edgeT),
6536 color=atmcolor,
6537 size=mysize, transform=pb.gca().transAxes)
6538 pb.text(xEdgeLabel, zeroValueAmplitude,'%.0fK'%(zeroValue),
6539 color=atmcolor,
6540 size=mysize, transform=pb.gca().transAxes)
6541 else:
6542 # showatm=True
6543 edgeT = 1
6544 if (lo1 == ''):
6545 pb.text(xlim[1]+0.05*myxrange/subplotCols, edgeValueAmplitude,
6546 '%.0f%%'%(edgeT*100), color=atmcolor, size=mysize,
6547 transform=trans, va='center')
6548 pb.text(xlim[1]+0.05*myxrange/subplotCols, zeroValueAmplitude,
6549 '%.0f%%'%(zeroValue*100), color=atmcolor, transform=trans,
6550 size=mysize, va='center')
6551 else:
6552 pb.text(xEdgeLabel, edgeValueAmplitude,'%.0f%%'%(edgeT*100),
6553 color=atmcolor, va='center',
6554 size=mysize, transform=pb.gca().transAxes)
6555 pb.text(xEdgeLabel, zeroValueAmplitude,'%.0f%%'%(zeroValue*100),
6556 color=atmcolor, va='center',
6557 size=mysize, transform=pb.gca().transAxes)
6558 elif not showtsys:
6559 if (showtsky):
6560 if (lo1 == ''):
6561 # This must be done in user coordinates since another curve
6562 # is plotted following this one.
6563 pb.text(xlim[1]+0.06*myxrange/subplotCols, edgeValueAmplitude,
6564 '%.0fK'%(edgeT), color=atmcolor, size=mysize)
6565 pb.text(xlim[1]+0.06*myxrange/subplotCols, zeroValueAmplitude,
6566 '%.0fK'%(zeroValue), color=atmcolor,
6567 size=mysize)
6568 else:
6569 # This can remain in axes units since it is the final plot.
6570 pb.text(xEdgeLabel, otherEdgeYvalue,'%.0fK'%(otherEdgeT),
6571 color=atmcolor,
6572 size=mysize, transform=pb.gca().transAxes)
6573 pb.text(xEdgeLabel, zeroYValue,'%.0fK'%(zeroValue),
6574 color=atmcolor,
6575 size=mysize, transform=pb.gca().transAxes)
6576 else:
6577 # showatm=True
6578 if (lo1 == ''):
6579 # This must be done in user coordinates since another curve
6580 # is plotted following this one.
6581 pb.text(xlim[1]+0.05*myxrange/subplotCols, edgeValueAmplitude,
6582 '%.0f%%'%(edgeT*100), color=atmcolor, size=mysize)
6583 pb.text(xlim[1]+0.05*myxrange/subplotCols, zeroValueAmplitude,
6584 '%.0f%%'%(zeroValue*100), color=atmcolor,
6585 size=mysize)
6586 else:
6587 # This can remain in axes units since it is the final plot.
6588 pb.text(xEdgeLabel, otherEdgeYvalue,'%.0f%%'%(otherEdgeT*100),
6589 color=atmcolor,
6590 size=mysize, transform=pb.gca().transAxes)
6591 pb.text(xEdgeLabel, zeroYValue,'%.0f%%'%(zeroValue*100),
6592 color=atmcolor,
6593 size=mysize, transform=pb.gca().transAxes)
6594 if (lo1 != ''):
6595 if (xframe == firstFrame):
6596 pb.text(+1.04-0.04*subplotCols, -0.07*subplotRows,
6597 'Signal SB', color='m', size=mysize,
6598 transform=pb.gca().transAxes)
6599 pb.text(-0.03-0.08*subplotCols, -0.07*subplotRows,
6600 'Image SB', color='k', size=mysize,
6601 transform=pb.gca().transAxes)
6602# pb.text(+0.96-0.08*subplotCols, -0.07*subplotRows,
6603# 'Signal Sideband', color='m', size=mysize,
6604# transform=pb.gca().transAxes)
6605# pb.text(-0.08*subplotCols, -0.07*subplotRows,
6606# 'Image Sideband', color='k', size=mysize,
6607# transform=pb.gca().transAxes)
6608 return ylim # CAS-8655
6610def DrawBottomLegendPageCoords(msName, uniqueTimesMytime, mysize, figfile):
6611 msName = msName.split('/')[-1]
6612 bottomLegend = msName + ' ObsDate=' + utdatestring(uniqueTimesMytime)
6613 if (os.path.basename(figfile).find('regression') == 0):
6614 regression = True
6615 else:
6616 regression = False
6617 if (regression == False):
6618 bottomLegend += ' plotbandpass v' \
6619 + PLOTBANDPASS_REVISION_STRING.split()[2] + ' = ' \
6620 + PLOTBANDPASS_REVISION_STRING.split()[3] + ' ' \
6621 + PLOTBANDPASS_REVISION_STRING.split()[4]
6622# The following should be used going forward, as it is better for long VLA names
6623 pb.text(0.04, 0.02, bottomLegend, size=mysize, transform=pb.gcf().transFigure)
6624# pb.text(0.1, 0.02, bottomLegend, size=mysize, transform=pb.gcf().transFigure)
6626def DrawAntennaNames(msAnt, antennasToPlot, msFound, mysize, overlayColors):
6627 for a in range(len(antennasToPlot)):
6628 if (msFound):
6629 legendString = msAnt[antennasToPlot[a]]
6630 else:
6631 legendString = str(antennasToPlot[a])
6632 if (a<maxAntennaNamesAcrossTheTop):
6633 x0 = xstartTitle+(a*antennaHorizontalSpacing)
6634 y0 = ystartOverlayLegend
6635 else:
6636 # start going down the righthand side
6637 x0 = xstartTitle+(maxAntennaNamesAcrossTheTop*antennaHorizontalSpacing)
6638 y0 = ystartOverlayLegend-(a-maxAntennaNamesAcrossTheTop)*antennaVerticalSpacing
6639 pb.text(x0, y0, legendString,color=overlayColors[a],fontsize=mysize,
6640 transform=pb.gcf().transFigure)
6642def stdInfo(a, sigma=3, edge=0, spw=-1, xant=-1, pol=-1):
6643 """
6644 Computes the standard deviation of a list, then returns the value, plus the
6645 number and list of channels that exceed sigma*std, and the worst outlier.
6646 """
6647 info = {}
6648 if (edge >= len(a)//2): # protect against too large of an edge value
6649 originalEdge = edge
6650 if (len(a) == 2*(len(a)//2)):
6651 edge = len(a)//2 - 1 # use middle 2 points
6652 else:
6653 edge = len(a)//2 # use central point
6654 if (edge < 0):
6655 edge = 0
6656 print("stdInfo: WARNING edge value is too large for spw%d xant%d pol%d, reducing it from %d to %d." % (spw, xant, pol, originalEdge, edge))
6657 info['std'] = np.std(a[edge:len(a)-edge])
6658 chan = []
6659 outlierValue = 0
6660 outlierChannel = None
6661 for i in range(edge,len(a)-edge):
6662 if (np.abs(a[i]) > sigma*info['std']):
6663 chan.append(i)
6664 if (np.abs(a[i]) > np.abs(outlierValue)):
6665 outlierValue = a[i]
6666 outlierChannel = i
6667 info['nchan'] = len(chan)
6668 info['chan'] = chan
6669 info['outlierValue'] = outlierValue/info['std']
6670 info['outlierChannel'] = outlierChannel
6671 return(info)
6673def madInfo(a, madsigma=3, edge=0):
6674 """
6675 Computes the MAD of a list, then returns the value, plus the number and list
6676 of channels that exceed madsigma*MAD, and the worst outlier.
6677 """
6678 info = {}
6679 if (edge >= len(a)//2): # protect against too large of an edge value
6680 originalEdge = edge
6681 if (len(a) == 2*(len(a)//2)):
6682 edge = len(a)//2 - 1 # use middle 2 points
6683 else:
6684 edge = len(a)//2 # use central point
6685 print("WARNING edge value is too large, reducing it from %d to %d." % (originalEdge, edge))
6686 info['mad'] = mad(a[edge:len(a)-edge])
6687 chan = []
6688 outlierValue = 0
6689 outlierChannel = None
6690 for i in range(edge,len(a)-edge):
6691 if (np.abs(a[i]) > madsigma*info['mad']):
6692 chan.append(i)
6693 if (np.abs(a[i]) > np.abs(outlierValue)):
6694 outlierValue = a[i]
6695 outlierChannel = i
6696 info['nchan'] = len(chan)
6697 info['chan'] = chan
6698 info['outlierValue'] = outlierValue/info['mad']
6699 info['outlierChannel'] = outlierChannel
6700 return(info)
6702def platformingCheck(a, threshold=DEFAULT_PLATFORMING_THRESHOLD):
6703 """
6704 Checks for values outside the range of +-threshold.
6705 Meant to be passed an amplitude spectrum.
6706 """
6707 info = {}
6708 startChan = len(a)/32. - 1
6709 endChan = len(a)*31/32. + 1
6710# print("Checking channels %d-%d for platforming" % (startChan,endChan))
6711 if (startChan <= 0 or endChan >= len(a)):
6712 return
6713 middleChan = (startChan+endChan)//2
6714 channelRange1 = list(range(startChan,middleChan+1))
6715 channelRange2 = list(range(endChan,middleChan,-1))
6716 platforming = False
6717 awayFromEdge = False
6718 for i in channelRange1:
6719 if (np.abs(a[i]) > threshold):
6720 if (awayFromEdge):
6721# print("a[%d]=%f" % (i,a[i]))
6722 platforming = True
6723 return(platforming)
6724 else:
6725 awayFromEdge = True
6726 awayFromEdge = False
6727 for i in channelRange2:
6728 if (np.abs(a[i]) > threshold):
6729 if (awayFromEdge):
6730 platforming = True
6731 return(platforming)
6732 else:
6733 awayFromEdge = True
6734 return(platforming)
6736def mad(a, c=0.6745, axis=0):
6737 """
6738 Median Absolute Deviation along given axis of an array:
6740 median(abs(a - median(a))) / c
6742 c = 0.6745 is the constant to convert from MAD to std; it is used by
6743 default
6745 """
6746 a = np.array(a)
6747 good = (a==a)
6748 a = np.asarray(a, np.float64)
6749 if a.ndim == 1:
6750 d = np.median(a[good])
6751 m = np.median(np.fabs(a[good] - d) / c)
6752# print( "mad = %f" % (m))
6753 else:
6754 d = np.median(a[good], axis=axis)
6755 # I don't want the array to change so I have to copy it?
6756 if axis > 0:
6757 aswp = swapaxes(a[good],0,axis)
6758 else:
6759 aswp = a[good]
6760 m = np.median(np.fabs(aswp - d) / c, axis=0)
6762 return m
6764def callFrequencyRangeForSpws(mymsmd, spwlist, vm, caltable=None):
6765 """
6766 Returns the min and max frequency of a list of spws.
6767 Uses msmd, unless the ms is not found, in which case it uses
6768 the spw information inside the (new-style) cal-table.
6769 """
6770 if (mymsmd != '' and ctsys.compare_version('>=',[4,1,0])):
6771 return(frequencyRangeForSpws(mymsmd,spwlist))
6772 else:
6773 freqs = []
6774 if (type(vm) != str):
6775 for spw in spwlist:
6776 freqs += list(vm.spwInfo[spw]["chanFreqs"])
6777 else:
6778 mytb = table()
6779 try:
6780 mytb.open(caltable+'/SPECTRAL_WINDOW')
6781 chanfreq = []
6782 if (len(spwlist) == 0): # CAS-8489b
6783 originalSpws = list(range(len(mytb.getcol('MEAS_FREQ_REF'))))
6784 spwlist = originalSpws
6785 for i in spwlist: # CAS-8489b
6786 # The array shapes can vary.
6787 chanfreq.append(mytb.getcell('CHAN_FREQ',i))
6788 for cf in chanfreq:
6789 freqs += list(cf)
6790 mytb.close()
6791 except:
6792 mytb.done()
6793 if (freqs == []):
6794 return(0,0)
6795 else:
6796 return(np.min(freqs)*1e-9, np.max(freqs)*1e-9)
6798def frequencyRangeForSpws(mymsmd, spwlist):
6799 """
6800 Returns the min and max frequency of a list of spws.
6801 """
6802 allfreqs = []
6803 for spw in spwlist:
6804 allfreqs += list(mymsmd.chanfreqs(spw))
6805 if (len(allfreqs) == 0):
6806 return(0,0)
6807 return(np.min(allfreqs)*1e-9, np.max(allfreqs)*1e-9)
6809def buildSpwString(overlaySpws, overlayBasebands, spwsToPlot, ispw, originalSpw,
6810 observatoryName, baseband, showBasebandNumber):
6811 if (overlayBasebands):
6812 spwString = ' all'
6813 elif (overlaySpws and len(spwsToPlot)>1):
6814 if (observatoryName.find('ALMA') >= 0 or observatoryName.find('ACA') >= 0):
6815 # show a list of all spws
6816 spwString = str(spwsToPlot).replace(' ','').strip('[').strip(']')
6817 else:
6818 # show the range of spw numbers
6819 spwString = '%2d-%2d' % (np.min(spwsToPlot),np.max(spwsToPlot))
6820 elif (ispw==originalSpw):
6821 spwString = '%2d' % (ispw)
6822 else:
6823 spwString = '%2d (%d)' % (ispw,originalSpw)
6824 if (overlayBasebands==False):
6825 spwString = appendBasebandNumber(spwString, baseband, showBasebandNumber)
6826 return(spwString)
6828def appendBasebandNumber(spwString, baseband, showBasebandNumber):
6829 if (showBasebandNumber):
6830 spwString += ', bb%d' % (baseband)
6831 return(spwString)
6833def getSpwsForBaseband(vis, bb, mymsmd=None):
6834 needToClose = False
6835# if (casadef.subversion_revision >= 25753):
6836 if (mymsmd is None or mymsmd == ''):
6837 needToClose = True
6838 mymsmd = msmetadata()
6839 mymsmd.open(vis)
6840 s = mymsmd.spwsforbaseband(bb)
6841 if needToClose:
6842 mymsmd.close()
6843 return(s)
6844# else:
6845# return(getBasebandDict(vis,caltable=caltable,mymsmd=mymsmd))
6847def getBasebandDict(vis=None, spwlist=[], caltable=None, mymsmd=None):
6848 """
6849 Builds a dictionary with baseband numbers as the keys and the
6850 associated spws as the values. The optional parameter spwlist can
6851 be used to restrict the contents of the dictionary.
6852 Note: This is obsoleted by msmd.spwsforbaseband(-1)
6853 """
6854 bbdict = {}
6855 if (vis != None):
6856 if (os.path.exists(vis)):
6857 bbs = getBasebandNumbers(vis)
6858 elif (caltable != None):
6859 bbs = getBasebandNumbersFromCaltable(caltable)
6860 else:
6861 print("Must specify either vis or caltable")
6862 return
6863 elif (caltable != None):
6864 bbs = getBasebandNumbersFromCaltable(caltable)
6865 else:
6866 print("Must specify either vis or caltable")
6867 return
6868 if (type(bbs) == int): # old datasets will bomb on msmd.baseband()
6869 return(bbdict)
6870 if (ctsys.compare_version('>=',[4,1,0]) and vis != None):
6871 if (os.path.exists(vis)):
6872 needToClose = False
6873 if mymsmd is None or mymsmd == '':
6874 needToClose = True
6875 mymsmd = msmetadata()
6876 mymsmd.open(vis)
6877 if (spwlist == []):
6878 nspws = mymsmd.nspw()
6879 spwlist = list(range(nspws))
6880 for spw in spwlist:
6881 bbc_no = mymsmd.baseband(spw)
6882 if (bbc_no not in list(bbdict.keys())):
6883 bbdict[bbc_no] = [spw]
6884 else:
6885 bbdict[bbc_no].append(spw)
6886 if needToClose:
6887 mymsmd.close()
6888 if (bbdict == {}):
6889 # read from spw table
6890 ubbs = np.unique(bbs)
6891 for bb in ubbs:
6892 bbdict[bb] = []
6893 for i in range(len(bbs)):
6894 bbdict[bbs[i]].append(i)
6895 return(bbdict)
6897def getBasebandNumbersFromCaltable(caltable) :
6898 """
6899 Returns the baseband numbers associated with each spw in
6900 the specified caltable.
6901 Todd Hunter
6902 """
6903 if (os.path.exists(caltable) == False):
6904 print("getBasebandNumbersFromCaltable(): caltable set not found")
6905 return -1
6906 mytb = table()
6907 mytb.open(caltable)
6908 spectralWindowTable = mytb.getkeyword('SPECTRAL_WINDOW').split()[1]
6909 mytb.close()
6910 mytb.open(spectralWindowTable)
6911 if ("BBC_NO" in mytb.colnames()):
6912 bbNums = mytb.getcol("BBC_NO")
6913 else:
6914 # until CAS-6853 is solved, need to get it from the name
6915# print("BBC_NO not in colnames (CAS-6853). Using NAME column.")
6916 names = mytb.getcol('NAME')
6917 bbNums = []
6918 trivial = True
6919 for name in names:
6920 if (name.find('#BB_') > 0):
6921 bbNums.append(int(name.split('#BB_')[1].split('#')[0]))
6922 trivial = False
6923 else:
6924 bbNums.append(-1)
6925 if (trivial): bbNums = -1
6926 mytb.close()
6927 return bbNums
6930def getLOs(inputMs, verbose=True):
6931 """
6932 Reads the LO information from an ms's ASDM_RECEIVER table. It returns
6933 a list of 7 lists: [freqLO,band,spws,names,sidebands,receiverIDs,spwnames]
6934 The logic for converting this raw list into sensible association with
6935 spw numbers is in printLOs(). These lists are longer than the true number
6936 of spws by Nantennas-1 due to the extra WVR spws.
6937 -Todd Hunter
6938 """
6939 if (os.path.exists(inputMs)):
6940 mytb = table()
6941 if (os.path.exists("%s/ASDM_RECEIVER" % inputMs)):
6942 try:
6943 mytb.open("%s/ASDM_RECEIVER" % inputMs)
6944 except:
6945 print("Could not open the existing ASDM_RECEIVER table")
6946 mytb.close()
6947 return([])
6948 else:
6949 if (os.path.exists(inputMs+'/ASDMBinary')):
6950 print("This is an ASDM, not an ms! Use printLOsFromASDM.")
6951 else:
6952 if (verbose):
6953 print("The ASDM_RECEIVER table for this ms does not exist.")
6954 mytb.close()
6955 return([])
6956 else:
6957 print("This ms does not exist = %s." % (inputMs))
6958 return([])
6960 numLO = mytb.getcol('numLO')
6961 freqLO = []
6962 band = []
6963 spws = []
6964 names = []
6965 sidebands = []
6966 receiverIds = []
6967 for i in range(len(numLO)):
6968 spw = int((mytb.getcell('spectralWindowId',i).split('_')[1]))
6969 if (spw not in spws):
6970 spws.append(spw)
6971 freqLO.append(mytb.getcell('freqLO',i))
6972 band.append(mytb.getcell('frequencyBand',i))
6973 names.append(mytb.getcell('name',i))
6974 sidebands.append(mytb.getcell('sidebandLO',i))
6975 receiverIds.append(int(mytb.getcell('receiverId',i)))
6976 mytb.close()
6977 mytb.open("%s/SPECTRAL_WINDOW" % inputMs)
6978 spwNames = mytb.getcol("NAME")
6979 mytb.close()
6980 mytb.close()
6981 return([freqLO,band,spws,names,sidebands,receiverIds,spwNames])
6983def readPWVFromASDM_CALATMOSPHERE(vis):
6984 """
6985 Reads the PWV via the water column of the ASDM_CALATMOSPHERE table.
6986 - Todd Hunter
6987 """
6988 mytb = table()
6989 mytb.open("%s/ASDM_CALATMOSPHERE" % vis)
6990 pwvtime = mytb.getcol('startValidTime') # mjdsec
6991 antenna = mytb.getcol('antennaName')
6992 pwv = mytb.getcol('water')[0] # There seem to be 2 identical entries per row, so take first one.
6993 mytb.close()
6994 return(pwvtime, antenna, pwv)
6996def getMedianPWV(vis='.', myTimes=[0,999999999999], asdm='', verbose=False):
6997 """
6998 Extracts the PWV measurements from the WVR on all antennas for the
6999 specified time range. The time range is input as a two-element list of
7000 MJD seconds (default = all times). First, it tries to find the ASDM_CALWVR
7001 table in the ms. If that fails, it then tries to find CalWVR.xml in the
7002 specified ASDM, or failing that, an ASDM of the same name (-.ms). If neither of
7003 these exist, then it tries to find CalWVR.xml in the present working directory.
7004 If it still fails, it looks for CalWVR.xml in the .ms directory. Thus,
7005 you only need to copy this xml file from the ASDM into your ms, rather
7006 than the entire ASDM. Returns the median and standard deviation in millimeters.
7007 For further help and examples, see https://safe.nrao.edu/wiki/bin/view/ALMA/GetMedianPWV
7008 -- Todd Hunter
7009 """
7010 pwvmean = 0
7011 success = False
7012 mytb = table()
7013 if (verbose):
7014 print("in getMedianPWV with myTimes = %s" % (str(myTimes)))
7015 try:
7016 if (os.path.exists("%s/ASDM_CALWVR"%vis)):
7017 mytb.open("%s/ASDM_CALWVR" % vis)
7018 pwvtime = mytb.getcol('startValidTime') # mjdsec
7019 antenna = mytb.getcol('antennaName')
7020 pwv = mytb.getcol('water')
7021 mytb.close()
7022 success = True
7023 if (len(pwv) < 1):
7024 if (os.path.exists("%s/ASDM_CALATMOSPHERE" % vis)):
7025 pwvtime, antenna, pwv = readPWVFromASDM_CALATMOSPHERE(vis)
7026 success = True
7027 if (len(pwv) < 1):
7028 print("Found no data in ASDM_CALWVR nor ASDM_CALATMOSPHERE table")
7029 return(0,-1)
7030 else:
7031 if (verbose):
7032 print("Did not find ASDM_CALATMOSPHERE in the ms")
7033 return(0,-1)
7034 if (verbose):
7035 print("Opened ASDM_CALWVR table, len(pwvtime)=%s" % (str(len(pwvtime))))
7036 else:
7037 if (verbose):
7038 print("Did not find ASDM_CALWVR table in the ms. Will look for ASDM_CALATMOSPHERE next.")
7039 if (os.path.exists("%s/ASDM_CALATMOSPHERE" % vis)):
7040 pwvtime, antenna, pwv = readPWVFromASDM_CALATMOSPHERE(vis)
7041 success = True
7042 if (len(pwv) < 1):
7043 print("Found no data in ASDM_CALATMOSPHERE table")
7044 return(0,-1)
7045 else:
7046 if (verbose):
7047 print("Did not find ASDM_CALATMOSPHERE in the ms")
7048 except:
7049 if (verbose):
7050 print("Could not open ASDM_CALWVR table in the ms")
7051 finally:
7052 # try to find the ASDM table
7053 if (success == False):
7054 if (len(asdm) > 0):
7055 if (os.path.exists(asdm) == False):
7056 print("Could not open ASDM = %s" % (asdm))
7057 mytb.done()
7058 return(0,-1)
7059 try:
7060 [pwvtime,pwv,antenna] = readpwv(asdm)
7061 except:
7062 if (verbose):
7063 print("Could not open ASDM = %s" % (asdm))
7064 mytb.done()
7065 return(pwvmean,-1)
7066 else:
7067 try:
7068 tryasdm = vis.split('.ms')[0]
7069 if (verbose):
7070 print("No ASDM name provided, so I will try this name = %s" % (tryasdm))
7071 [pwvtime,pwv,antenna] = readpwv(tryasdm)
7072 except:
7073 try:
7074 if (verbose):
7075 print("Still did not find it. Will look for CalWVR.xml in current directory.")
7076 [pwvtime, pwv, antenna] = readpwv('.')
7077 except:
7078 try:
7079 if (verbose):
7080 print("Still did not find it. Will look for CalWVR.xml in the .ms directory.")
7081 [pwvtime, pwv, antenna] = readpwv('%s/'%vis)
7082 except:
7083 if (verbose):
7084 print("No CalWVR.xml file found, so no PWV retrieved. Copy it to this directory and try again.")
7085 mytb.done()
7086 return(pwvmean,-1)
7087 try:
7088 matches = np.where(np.array(pwvtime)>myTimes[0])[0]
7089 except:
7090 print("Found no times > %d" % (myTimes[0]))
7091 mytb.done()
7092 return(0,-1)
7093 if (len(pwv) < 1):
7094 print("Found no PWV data")
7095 return(0,-1)
7096 ptime = np.array(pwvtime)[matches]
7097 matchedpwv = np.array(pwv)[matches]
7098 matches2 = np.where(ptime<myTimes[-1])[0]
7099 if (len(matches2) < 1):
7100 # look for the value with the closest start time
7101 mindiff = 1e12
7102 for i in range(len(pwvtime)):
7103 if (abs(myTimes[0]-pwvtime[i]) < mindiff):
7104 mindiff = abs(myTimes[0]-pwvtime[i])
7105 pwvmean = pwv[i]*1000
7106 matchedpwv = []
7107 for i in range(len(pwvtime)):
7108 if (abs(abs(myTimes[0]-pwvtime[i]) - mindiff) < 1.0):
7109 matchedpwv.append(pwv[i])
7110 pwvmean = 1000*np.median(matchedpwv)
7111 if (verbose):
7112 print("Taking the median of %d pwv measurements from all antennas = %.3f mm" % (len(matchedpwv),pwvmean))
7113 pwvstd = np.std(matchedpwv)
7114 else:
7115 pwvmean = 1000*np.median(matchedpwv[matches2])
7116 pwvstd = np.std(matchedpwv[matches2])
7117 if (verbose):
7118 print("Taking the median of %d pwv measurements from all antennas = %.3f mm" % (len(matches2),pwvmean))
7119# mytb.done()
7120 return(pwvmean,pwvstd)
7121# end of getMedianPWV
7123def computeAzElFromRADecMJD(raDec, mjd, observatory='ALMA'):
7124 """
7125 Computes the az/el for a specified J2000 RA/Dec, MJD and observatory.
7127 raDec must be in radians: [ra,dec]
7128 mjd must be in days
7129 returns the [az,el] in radians
7130 - Todd Hunter
7131 """
7132 myme = measures()
7133 myqa = quanta()
7134 mydir = myme.direction('J2000', myqa.quantity(raDec[0],'rad'), myqa.quantity(raDec[1],'rad'))
7135 myme.doframe(myme.epoch('mjd', myqa.quantity(mjd, 'd')))
7136 myme.doframe(myme.observatory(observatory))
7137 myazel = myme.measure(mydir,'azel')
7138 myqa.done()
7139 myme.done()
7140 return([myazel['m0']['value'], myazel['m1']['value']])
7142def getRADecForField(msName, myfieldId, debug):
7143 """
7144 Returns RA,Dec in radians for the specified field in the specified ms.
7145 -- Todd Hunter
7146 """
7147 myms = ms()
7148 myms.open(msName)
7149 myd = myms.getfielddirmeas('DELAY_DIR', fieldid=myfieldId) # dircolname defaults to 'PHASE_DIR'
7150 myms.close()
7151 mydir = np.array([[myd['m0']['value']], [myd['m1']['value']]]) # simulates tb.getcell
7152 return(mydir)
7154def findClosestTime(mytimes, mytime):
7155 myindex = 0
7156 mysep = np.abs(mytimes[0]-mytime)
7157 for m in range(1,len(mytimes)):
7158 if (np.abs(mytimes[m] - mytime) < mysep):
7159 mysep = np.abs(mytimes[m] - mytime)
7160 myindex = m
7161 return(myindex)
7163def getWeather(vis='', scan='', antenna='0',verbose=False, mymsmd=None):
7164 """
7165 Queries the WEATHER and ANTENNA tables of an .ms by scan number or
7166 list of scan numbers in order to return median values of: angleToSun,
7167 pressure, temperature, humidity, dew point, wind speed, wind direction,
7168 azimuth, elevation, solarangle, solarelev, solarazim.
7169 If the sun is below the horizon, the solarangle returned is negated.
7170 -- Todd Hunter
7171 """
7172 if (verbose):
7173 print("Entered getWeather with vis,scan,antenna = %s,%s,%s" % (str(vis), str(scan), str(antenna)))
7174 try:
7175 if str(antenna).isdigit():
7176 antennaName = mymsmd.antennanames(antenna)[0]
7177 else:
7178 antennaName = antenna
7179 try:
7180 antenna = mymsmd.antennaids(antennaName)[0]
7181 except:
7182 antennaName = string.upper(antenna)
7183 antenna = mymsmd.antennaids(antennaName)[0]
7184 except:
7185 print("Either the ANTENNA table does not exist or antenna %s does not exist" % (antenna))
7186 return([0,[]])
7187 mytb = table()
7188 try:
7189 mytb.open("%s/POINTING" % vis)
7190 except:
7191 print("POINTING table does not exist")
7192 mytb.done()
7193 return([0,0])
7194 subtable = mytb.query("ANTENNA_ID == %s" % antenna)
7195 mytb.close()
7196 try:
7197 mytb.open("%s/OBSERVATION" % vis)
7198 observatory = mytb.getcell("TELESCOPE_NAME",0)
7199 mytb.close()
7200 except:
7201 print("OBSERVATION table does not exist, assuming observatory == ALMA")
7202 observatory = "ALMA"
7203 if (scan == ''):
7204 scan = mymsmd.scannumbers()
7205 conditions = {}
7206 conditions['pressure']=conditions['temperature']=conditions['humidity']=conditions['dewpoint']=conditions['windspeed']=conditions['winddirection'] = 0
7207 conditions['scan'] = scan
7208 if (type(scan) == str):
7209 if (scan.find('~')>0):
7210 tokens = scan.split('~')
7211 scan = [int(k) for k in range(int(tokens[0]),int(tokens[1])+1)]
7212 else:
7213 scan = [int(k) for k in scan.split(',')]
7214 if (type(scan) == type(np.ndarray(0))):
7215 scan = list(scan)
7216 if (type(scan) == list):
7217 myTimes = np.array([])
7218 for sc in scan:
7219 try:
7220 print("calling timesforscan")
7221 newTimes = mymsmd.timesforscan(sc)
7222 print("times = %s" % (str(newTimes)))
7223 except:
7224 print("Error reading scan %d, is it in the data?" % (sc))
7225 mytb.done()
7226 return([conditions,[]])
7227 myTimes = np.concatenate((myTimes,newTimes))
7228 elif (scan != None):
7229 try:
7230 myTimes = mymsmd.timesforscan(scan)
7231 except:
7232 print("Error reading scan %d, is it in the data?" % (scan))
7233 mytb.done()
7234 return([conditions,[]])
7235 else:
7236 mytb.done()
7237 return([conditions,[]])
7238 if (type(scan) == str):
7239 scan = [int(k) for k in scan.split(',')]
7240 if (type(scan) == list):
7241 listscan = ""
7242 listfield = []
7243 for sc in scan:
7244# print("Processing scan ", sc)
7245 listfield.append(mymsmd.fieldsforscan(sc))
7246 listscan += "%d" % sc
7247 if (sc != scan[-1]):
7248 listscan += ","
7249# print("listfield = ", listfield)
7250 listfields = np.unique(listfield[0])
7251 listfield = ""
7252 for field in listfields:
7253 listfield += "%s" % field
7254 if (field != listfields[-1]):
7255 listfield += ","
7256 else:
7257 listscan = str(scan)
7258 listfield = mymsmd.fieldsforscan(scan)
7259 [az,el] = ComputeSolarAzElForObservatory(myTimes[0], mymsmd)
7260 [az2,el2] = ComputeSolarAzElForObservatory(myTimes[-1], mymsmd)
7261 azsun = np.median([az,az2])
7262 elsun = np.median([el,el2])
7263 direction = subtable.getcol("DIRECTION")
7264 azeltime = subtable.getcol("TIME")
7265 subtable.close()
7266 telescopeName = mymsmd.observatorynames()[0]
7267 if (len(direction) > 0 and telescopeName.find('VLA') < 0 and telescopeName.find('NRO') < 0):
7268 azimuth = direction[0][0]*180.0/math.pi # a list of values
7269 elevation = direction[1][0]*180.0/math.pi # a list of values
7270 npat = np.array(azeltime)
7271 matches = np.where(npat>myTimes[0])[0]
7272 matches2 = np.where(npat<myTimes[-1])[0]
7273 if (len(matches2) > 0 and len(matches) > 0):
7274 if verbose: print("matches[0]=%d, matches2[-1]=%d" % (matches[0],matches[-1]))
7275 matchingIndices = list(range(matches[0],matches2[-1]+1))
7276 else:
7277 matchingIndices = []
7278 if (len(matchingIndices) > 0): # CAS-8440
7279 conditions['azimuth'] = np.median(azimuth[matches[0]:matches2[-1]+1])
7280 conditions['elevation'] = np.median(elevation[matches[0]:matches2[-1]+1])
7281 elif (len(matches) > 0): # CAS-8440
7282 if verbose: print("using median of all az/el values after time 0")
7283 conditions['azimuth'] = np.median(azimuth[matches[0]])
7284 conditions['elevation'] = np.median(elevation[matches[0]])
7285 else: # CAS-8440
7286 if verbose: print("using median of all az/el values")
7287 conditions['azimuth'] = np.median(azimuth)
7288 conditions['elevation'] = np.median(elevation)
7289 conditions['solarangle'] = angularSeparation(azsun,elsun,conditions['azimuth'],conditions['elevation'])
7290 conditions['solarelev'] = elsun
7291 conditions['solarazim'] = azsun
7292 if (verbose):
7293 print("Using antenna = %s to retrieve median azimuth and elevation" % (antennaName))
7294 print("Separation from sun = %f deg" % (abs(conditions['solarangle'])))
7295 if (elsun<0):
7296 conditions['solarangle'] = -conditions['solarangle']
7297 if (verbose):
7298 print("Sun is below horizon (elev=%.1f deg)" % (elsun))
7299 else:
7300 if (verbose):
7301 print("Sun is above horizon (elev=%.1f deg)" % (elsun))
7302 if (verbose):
7303 print("Average azimuth = %.2f, elevation = %.2f degrees" % (conditions['azimuth'],conditions['elevation']))
7304 else:
7305 if (verbose): print("The POINTING table is either blank or does not contain Azim/Elev.")
7306 if (type(scan) == int or type(scan)==np.int32):
7307 # compute Az/El for this scan
7308 myfieldId = mymsmd.fieldsforscan(scan)
7309 if (type(myfieldId) == list or type(myfieldId) == type(np.ndarray(0))):
7310 myfieldId = myfieldId[0]
7311 fieldName = mymsmd.namesforfields(myfieldId)
7312 if (type(fieldName) == list or type(fieldName) == type(np.ndarray(0))):
7313 fieldName = fieldName[0]
7314# print("A) fieldname = ", fieldName)
7315# print("myfieldId = ", myfieldId)
7316 myscantime = np.median(mymsmd.timesforscan(scan))
7317# print("Calling getRADecForField")
7318 mydirection = getRADecForField(vis, myfieldId, verbose)
7319 if (verbose): print("mydirection= %s" % (str(mydirection)))
7320 if (len(telescopeName) < 1):
7321 telescopeName = 'ALMA'
7322 myazel = computeAzElFromRADecMJD(mydirection, myscantime/86400., telescopeName)
7323 conditions['elevation'] = myazel[1] * 180/math.pi
7324 conditions['azimuth'] = myazel[0] * 180/math.pi
7325 conditions['solarangle'] = angularSeparation(azsun,elsun,conditions['azimuth'],conditions['elevation'])
7326 conditions['solarelev'] = elsun
7327 conditions['solarazim'] = azsun
7328 if (verbose):
7329 print("Separation from sun = %f deg" % (abs(conditions['solarangle'])))
7330 if (elsun<0):
7331 conditions['solarangle'] = -conditions['solarangle']
7332 if (verbose):
7333 print("Sun is below horizon (elev=%.1f deg)" % (elsun))
7334 else:
7335 if (verbose):
7336 print("Sun is above horizon (elev=%.1f deg)" % (elsun))
7337 if (verbose):
7338 print("Average azimuth = %.2f, elevation = %.2f degrees" % (conditions['azimuth'],conditions['elevation']))
7339 elif (type(scan) == list):
7340 myaz = []
7341 myel = []
7342 if (verbose):
7343 print("Scans to loop over = %s" % (str(scan)))
7344 for s in scan:
7345 fieldName = mymsmd.fieldsforscan(s)
7346 if (type(fieldName) == list):
7347 # take only the first pointing in the mosaic
7348 fieldName = fieldName[0]
7349 myfieldId = mymsmd.fieldsforname(fieldName)
7350 if (type(myfieldId) == list or type(myfieldId)==type(np.ndarray(0))):
7351 # If the same field name has two IDs (this happens in EVLA data)
7352 myfieldId = myfieldId[0]
7353 myscantime = np.median(mymsmd.timesforscan(s))
7354 mydirection = getRADecForField(vis, myfieldId, verbose)
7355 telescopeName = mymsmd.observatorynames()[0]
7356 if (len(telescopeName) < 1):
7357 telescopeName = 'ALMA'
7358 myazel = computeAzElFromRADecMJD(mydirection, myscantime/86400., telescopeName)
7359 myaz.append(myazel[0]*180/math.pi)
7360 myel.append(myazel[1]*180/math.pi)
7361 conditions['azimuth'] = np.median(myaz)
7362 conditions['elevation'] = np.median(myel)
7363 conditions['solarangle'] = angularSeparation(azsun,elsun,conditions['azimuth'],conditions['elevation'])
7364 conditions['solarelev'] = elsun
7365 conditions['solarazim'] = azsun
7366 if (verbose):
7367 print("Using antenna = %s to retrieve median azimuth and elevation" % (antennaName))
7368 print("Separation from sun = %f deg" % (abs(conditions['solarangle'])))
7369 if (elsun<0):
7370 conditions['solarangle'] = -conditions['solarangle']
7371 if (verbose):
7372 print("Sun is below horizon (elev=%.1f deg)" % (elsun))
7373 else:
7374 if (verbose):
7375 print("Sun is above horizon (elev=%.1f deg)" % (elsun))
7376 if (verbose):
7377 print("Average azimuth = %.2f, elevation = %.2f degrees" % (conditions['azimuth'],conditions['elevation']))
7380 # now, get the weather
7381 if not os.path.exists('%s/WEATHER' % vis):
7382 print("There is no WEATHER table for this ms.")
7383 if (needToClose_mymsmd): mymsmd.close()
7384 return([conditions,myTimes])
7385 try:
7386 mytb.open("%s/WEATHER" % vis)
7387 except:
7388 print("Could not open the WEATHER table for this ms.")
7389 mytb.done()
7390 return([conditions,myTimes])
7391 if (True):
7392 mjdsec = mytb.getcol('TIME')
7393 indices = np.argsort(mjdsec)
7394 mjd = mjdsec/86400.
7395 pressure = mytb.getcol('PRESSURE')
7396 conditions['pressure_unit'] = mytb.getcolkeywords('PRESSURE').get('QuantumUnits', ['mbar'])[0]
7397 relativeHumidity = mytb.getcol('REL_HUMIDITY')
7398 temperature = mytb.getcol('TEMPERATURE')
7399 if (np.median(temperature) > 100):
7400 # must be in units of Kelvin, so convert to C
7401 temperature -= 273.15
7402 if 'DEW_POINT' in mytb.colnames():
7403 dewPoint = mytb.getcol('DEW_POINT')
7404 if (np.median(dewPoint) > 100):
7405 # must be in units of Kelvin, so convert to C
7406 dewPoint -= 273.15
7407 if (np.median(dewPoint) == 0):
7408 # assume it is not measured and use NOAA formula to compute from humidity:
7409 dewPoint = ComputeDewPointCFromRHAndTempC(relativeHumidity, temperature)
7410 else:
7411 dewPoint = None # Nobeyama measurement sets do not have a dewpoint column
7412 sinWindDirection = np.sin(mytb.getcol('WIND_DIRECTION'))
7413 cosWindDirection = np.cos(mytb.getcol('WIND_DIRECTION'))
7414 windSpeed = mytb.getcol('WIND_SPEED')
7415 mytb.done()
7417 # put values into time order (they mostly are, but there can be small differences)
7418 mjdsec = np.array(mjdsec)[indices]
7419 pressure = np.array(pressure)[indices]
7420 relativeHumidity = np.array(relativeHumidity)[indices]
7421 temperature = np.array(temperature)[indices]
7422 if dewPoint is not None:
7423 dewPoint = np.array(dewPoint)[indices]
7424 windSpeed = np.array(windSpeed)[indices]
7425 sinWindDirection = np.array(sinWindDirection)[indices]
7426 cosWindDirection = np.array(cosWindDirection)[indices]
7428 # find the overlap of weather measurement times and scan times
7429 matches = np.where(mjdsec>=np.min(myTimes))[0]
7430 matches2 = np.where(mjdsec<=np.max(myTimes))[0]
7431# print("len(matches)=%d, len(matches2)=%d" % (len(matches), len(matches2)))
7432 noWeatherData = False
7433 if (len(matches)>0 and len(matches2) > 0):
7434 # average the weather points enclosed by the scan time range
7435 selectedValues = list(range(matches[0], matches2[-1]+1))
7436 if (selectedValues == []):
7437 # there was a either gap in the weather data, or an incredibly short scan duration
7438 if (verbose):
7439 print("---- Finding the nearest weather value --------------------------- ")
7440 selectedValues = findClosestTime(mjdsec, myTimes[0])
7441 elif (len(matches)>0):
7442 # all points are greater than myTime, so take the first one
7443 selectedValues = matches[0]
7444 elif (len(matches2)>0):
7445 # all points are less than myTime, so take the last one
7446 selectedValues = matches2[-1]
7447 else:
7448 # table has no weather data!
7449 noWeatherData = True
7450 if (noWeatherData):
7451 conditions['pressure'] = 563.0
7452 conditions['temperature'] = 0 # Celsius is expected
7453 conditions['humidity'] = 20.0
7454 conditions['dewpoint'] = -20.0
7455 conditions['windspeed'] = 0
7456 conditions['winddirection'] = 0
7457 print("WARNING: No weather data found in the WEATHER table!")
7458 else:
7459 if (type(selectedValues) == np.int64 or type(selectedValues) == np.int32 or
7460 type(selectedValues) == int):
7461 conditions['readings'] = 1
7462 if (verbose):
7463 print("selectedValues=%d, myTimes[0]=%.0f, len(matches)=%d, len(matches2)=%d" % (selectedValues,
7464 myTimes[0], len(matches), len(matches2)))
7465 if (len(matches) > 0):
7466 print("matches[0]=%f, matches[-1]=%f" % (matches[0], matches[-1]))
7467 if (len(matches2) > 0):
7468 print("matches2[0]=%f, matches2[-1]=%d" % (matches2[0], matches2[-1]))
7469 else:
7470 conditions['readings'] = len(selectedValues)
7471 conditions['pressure'] = np.median(pressure[selectedValues])
7472 if (conditions['pressure'] != conditions['pressure']):
7473 # A nan value got through, due to no selected values (should be impossible)"
7474 if (verbose):
7475 print(">>>>>>>>>>>>>>>>>>>>>>>> selectedValues = %s" % (str(selectedValues)))
7476 print("len(matches)=%d, len(matches2)=%d" % (len(matches), len(matches2)))
7477 print("matches[0]=%f, matches[-1]=%f, matches2[0]=%f, matches2[-1]=%d" % (matches[0], matches[-1], matches2[0], matches2[-1]))
7478 conditions['temperature'] = np.median(temperature[selectedValues])
7479 conditions['humidity'] = np.median(relativeHumidity[selectedValues])
7480 if dewPoint is not None:
7481 conditions['dewpoint'] = np.nanmedian(dewPoint[selectedValues])
7482 conditions['windspeed'] = np.median(windSpeed[selectedValues])
7483 conditions['winddirection'] = (180./math.pi)*np.arctan2(np.median(sinWindDirection[selectedValues]),np.median(cosWindDirection[selectedValues]))
7484 if (conditions['winddirection'] < 0):
7485 conditions['winddirection'] += 360
7486 if (verbose):
7487 print("Median weather values for scan %s (field %s)" % (listscan,listfield))
7488 print(" Pressure = %.2f mb" % (conditions['pressure']))
7489 print(" Temperature = %.2f C" % (conditions['temperature']))
7490 if dewPoint is not None:
7491 print(" Dew point = %.2f C" % (conditions['dewpoint']))
7492 print(" Relative Humidity = %.2f %%" % (conditions['humidity']))
7493 print(" Wind speed = %.2f m/s" % (conditions['windspeed']))
7494 print(" Wind direction = %.2f deg" % (conditions['winddirection']))
7496 return([conditions,myTimes])
7497 # end of getWeather
7499def getBasebandNumbers(inputMs) :
7500 """
7501 Returns the baseband numbers associated with each spw in the specified ms.
7502 Todd Hunter
7503 """
7504 if (os.path.exists(inputMs) == False):
7505 print("measurement set not found")
7506 return -1
7507 mytb = table()
7508 mytb.open("%s/SPECTRAL_WINDOW" % inputMs)
7509 if ("BBC_NO" in mytb.colnames()):
7510 bbNums = mytb.getcol("BBC_NO")
7511 else:
7512 return(-1)
7513 mytb.close()
7514 return bbNums
7516def yigHarmonic(bandString):
7517 """
7518 Returns the YIG harmonic for the specified ALMA band, given as a string
7519 used in casa tables.
7520 For example: yigHarmonic('ALMA_RB_03') returns the integer 6.
7521 Todd Hunter
7522 """
7523 # remove any leading spaces
7524 #bandString = bandString[bandString.find('ALMA_RB'):]
7525 harmonics = {'ALMA_RB_03':6, 'ALMA_RB_04':6, 'ALMA_RB_06': 18,
7526 'ALMA_RB_07': 18, 'ALMA_RB_08':18, 'ALMA_RB_09':27}
7527 try:
7528 harmonic = harmonics[bandString]
7529 except:
7530 harmonic = -1
7531 return(harmonic)
7533def interpretLOs(vis, parentms='', showWVR=False,
7534 showCentralFreq=False, verbose=False, show=False,
7535 alsoReturnLO2=False, showChannelAverageSpws=False,
7536 showOnlyScienceSpws=False, birdieFreq=None, birdieSpw=None,
7537 intent='OBSERVE_TARGET#ON_SOURCE', spwsForIntent=None,
7538 showEffective=False, showWindowFactors=False, mymsmd=None):
7539 """
7540 Copied from analysisUtils on May 16, 2017, to replace old version, in order
7541 to fix SCOPS-4877.
7542 Interpret (and optionally print) the LO settings for an MS from the
7543 ASDM_RECEIVER table.
7544 Options:
7545 showCentralFreq: if True, then show the mean frequency of each spw,
7546 otherwise show the frequency of the first channel
7547 showWVR: include the WVR spw in the list
7548 parentms: if the dataset has been split from a parent dataset, then
7549 you may also need to specify the name of the parent ms.
7550 alsoReturnLO2: if True, return a second dictionary of the LO2 values
7551 birdieFreq: if specified, compute the IF of this RF feature
7552 birdieSpw: only necessary if more than one LO1 in the science spws
7553 intent: which intent to use in spwsforintent (to find science spws)
7554 spwsForIntent: if specified, then avoid the call to spwsforintent
7556 Returns: a dictionary of the LO1 values (in Hz) for each spw, keyed by
7557 integer.
7559 A typical band 7 TDM dataset (prior to splitting) looks like this:
7560 SPECTRAL_WINDOW table has 39 rows: row
7561 WVR 0
7562 8 band 3 windows (pointing) 1-8
7563 8 band 7 windows 9-16
7564 22 WVR windows 17-38
7565 The corresponding ASDM_RECEIVER table has only 18 rows:
7566 WVR 0
7567 8 band 3 windows 1-8
7568 WVR 9
7569 8 band 7 windows 10-17
7570 After splitting, the ASDM_RECEIVER table remains the same, but the
7571 SPECTRAL WINDOW table then has only 4 rows, as the pointing spws and
7572 the channel-averaged data are dropped:
7573 4 band 7 windows
7575 Todd Hunter
7576 """
7577 lo1s = {} # initialize dictionary to be returned
7578 lo2s = {}
7579 try:
7580 retval = getLOs(vis)
7581 [LOs,bands,spws,names,sidebands,receiverIds,spwNames] = retval
7582 except:
7583 print("getLOs failed")
7584 return(retval)
7585 if (verbose): print("len(spws) = %d: %s" % (len(spws), str(spws)))
7586 maxSpw = np.max(spws)
7587 sawWVR = False
7588 indices = [] # will exclude the extraneous WVR spws
7589 for i in range(len(spws)):
7590 if (names[i].find('WVR') >= 0):
7591 if (not sawWVR):
7592 indices.append(i)
7593 sawWVR = True
7594 else:
7595 indices.append(i)
7596 LOs = np.array(LOs, dtype=object)[indices]
7597 bands = np.array(bands, dtype=object)[indices]
7598 spws = list(np.array(spws, dtype=object)[indices])
7599 names = np.array(names, dtype=object)[indices]
7600 sidebands = np.array(sidebands, dtype=object)[indices]
7601 receiverIds = np.array(receiverIds, dtype=object)[indices]
7602 index = list(range(len(spws)))
7603 mytb = table()
7604 mytb.open(vis+'/SPECTRAL_WINDOW')
7605 # If the data have been split into an ms with fewer spws, then this
7606 # table will be smaller (in rows) than the parent MS's table.
7607 spwNames = mytb.getcol('NAME')
7608 mytb.close()
7609 splitted = False
7610 if (maxSpw != len(spwNames)-1):
7611 splitted = True
7612 if (verbose):
7613 print("maxSpw=%d != len(spwNames)=%d)" % (maxSpw, len(spwNames)))
7614 if (parentms == '' or parentms == None):
7615 print("You appear to have split these data. Please provide the parentms as an argument.")
7616 return
7617 mytb.open(parentms+'/SPECTRAL_WINDOW')
7618 parentSpwNames = mytb.getcol('NAME')
7619 mytb.close()
7620 extractedRows = []
7621 index = []
7622 for s in range(len(spwNames)):
7623 if (len(spwNames[s]) == 0):
7624 print("This is an old dataset lacking values in the NAME column of the SPECTRAL_WINDOW table.")
7625 return
7626 if (verbose):
7627 print("Checking for %s in " % (spwNames[s]), parentSpwNames)
7628 extractedRows.append(np.where(parentSpwNames == spwNames[s])[0][0])
7629 index.append(spws.index(extractedRows[-1]))
7630 if (verbose):
7631 print("spw %d came from spw %d" % (s, extractedRows[-1]))
7632# extractedRows = the row of the parent SPECTRAL_WINDOW table that matches
7633# the split-out spw
7634# index = the row of the ASDM_RECEIVER table that matches the split-out spw
7635 vis = parentms
7636 if (verbose):
7637 print("spwNames = ", spwNames)
7638 print("spws = ", spws)
7639 print("bands = ", bands)
7640 output = "LOs = "
7641 for LO in LOs:
7642 output += "%.3f, " % (LO[0]*1e-9)
7643 print(output)
7644 print("names = ", names)
7645 print("index = ", index)
7647 bbc = getBasebandNumbers(vis) # does not use msmd
7648 if (show):
7649 print('Row refers to the row number in the ASDM_RECEIVER table (starting at 0).')
7650 if (showCentralFreq):
7651 myline = 'Row spw BB RxBand CenFreq Nchan LO1(GHz) LO2(GHz) Sampler YIG(GHz) TFBoffset(MHz)'
7652 else:
7653 myline = 'Row spw BB RxBand Ch1Freq Nchan LO1(GHz) LO2(GHz) Sampler YIG(GHz) TFBoffset(MHz)'
7654 if (showEffective):
7655 myline += ' Eff.BW(MHz) Res(MHz) Width(MHz)'
7656 if (showWindowFactors):
7657 myline += ' windowFactors'
7658 print(myline)
7660 # Loop over all rows in the ASDM_RECEIVER table, unless we've split, in
7661 # which case this will loop over the N spws in the table.
7662 needToClose = False
7663 if mymsmd is None or mymsmd == '':
7664 mymsmd = msmetadata()
7665 mymsmd.open(vis)
7666 needToClose = True
7667 if (spwsForIntent == None):
7668 if intent in mymsmd.intents(): # prevent a warning of OBSERVE_TARGET does not exist
7669 scienceSpws = np.setdiff1d(mymsmd.spwsforintent(intent),mymsmd.wvrspws())
7670 else:
7671 scienceSpws = []
7672 else:
7673 scienceSpws = spwsForIntent
7674 birdieIF = 0
7675 if (birdieFreq is not None):
7676 birdieFreq = parseFrequencyArgumentToHz(birdieFreq)
7677 birdieFreqGHz = parseFrequencyArgumentToGHz(birdieFreq)
7678 fdmSpws = mymsmd.almaspws(fdm=True)
7679 for i in range(len(index)):
7680 if (verbose):
7681 print("index[%d]=%d" % (i,index[i]))
7682 print("spws[%d] = %d" % (index[i], spws[index[i]]))
7683 myspw = i
7684 if (birdieFreq is not None and birdieIF == 0):
7685 if (myspw == birdieSpw):
7686 if verbose:
7687 print("spw=%d, Computing IF = %f - %f" % (myspw, birdieFreq, LOs[index[i]][0]))
7688 birdieIF = np.fabs(birdieFreq - LOs[index[i]][0])
7689 elif (myspw in scienceSpws and birdieSpw==None):
7690 if verbose:
7691 print("spw=%d (in %s), Computing IF = %f - %f" % (myspw, str(scienceSpws), birdieFreq, LOs[index[i]][0]))
7692 birdieIF = np.fabs(birdieFreq - LOs[index[i]][0])
7693 freqs = mymsmd.chanfreqs(myspw)
7694 meanFreqGHz = mymsmd.meanfreq(myspw) * (1e-9)
7695 if (myspw not in scienceSpws and showOnlyScienceSpws): continue
7696 if (len(freqs) < 2 and showChannelAverageSpws==False):
7697 continue
7698 if (bands[index[i]].split('_')[-1].isdigit()):
7699 rxband = bands[index[i]].split('_')[-1]
7700 elif (showWVR):
7701 rxband = 'WVR'
7702 else:
7703 continue
7704 line = "%2d %2d %d %3s " % (spws[index[i]], myspw, bbc[myspw], rxband)
7705 if (showCentralFreq):
7706 line += "%10.6f %4d " % (meanFreqGHz,len(freqs))
7707 else:
7708 line += "%10.6f %4d " % (freqs[0],len(freqs))
7710 if (LOs[index[i]][0] < 0):
7711 print(line)
7712 continue
7713 if (bbc[myspw] > 0):
7714 if (splitted):
7715 lo1s[i] = LOs[index[i]][0]
7716 lo2s[i] = LOs[index[i]][1]
7717 else:
7718 lo1s[myspw] = LOs[index[i]][0]
7719 lo2s[myspw] = LOs[index[i]][1]
7720 for j in range(len(LOs[index[i]])):
7721 if (j != 2):
7722 line = line + '%10.6f' % (LOs[index[i]][j]*1e-9)
7723 else:
7724 line = line + '%5.2f' % (LOs[index[i]][j]*1e-9)
7725 yig = LOs[index[i]][0] / yigHarmonic(bands[index[i]])
7726 if (yig > 0):
7727 line = line + ' %.6f' % (yig*1e-9)
7728 if (myspw in fdmSpws):
7729 # work out what LO4 must have been
7730 LO1 = LOs[index[i]][0]
7731 LO2 = LOs[index[i]][1]
7732 LO3 = LOs[index[i]][2]
7733 if (sidebands[index[i]][0] == 'USB'):
7734 IFlocation = LO3 - (LO2 - (meanFreqGHz*1e9 - LO1))
7735 else:
7736 IFlocation = LO3 - (LO2 - (LO1 - meanFreqGHz*1e9))
7737 LO4 = 2e9 + IFlocation
7738 TFBLOoffset = LO4-3e9
7739 line += '%9.3f %+8.3f ' % (LO4 * 1e-6, TFBLOoffset * 1e-6)
7740 else:
7741 line += 19*' '
7742 if (showEffective):
7743 line += '%9.4f %9.4f %9.4f' % (effectiveBandwidth(vis, myspw)*1e-6,
7744 effectiveResolution(vis, myspw)*1e-6,
7745 getChanWidths(mymsmd, myspw)*1e-6)
7746 if (showWindowFactors):
7747 chanwidth = abs(getChanWidths(mymsmd,myspw))
7748 line += ' %.4f %.4f' % (effectiveBandwidth(vis, myspw)/chanwidth,
7749 effectiveResolution(vis, myspw)/chanwidth)
7750 if (bands[index[i]].find('ALMA_RB_06')>=0 or bands[index[i]].find('ALMA_RB_09')>=0):
7751 if (len(LOs[index[i]]) > 1):
7752 if (LOs[index[i]][1] < 11.3e9 and LOs[index[i]][1] > 10.5e9):
7753 line = line + ' leakage of LO2 undesired sideband may degrade dynamic range'
7754 if (bands[index[i]].find('ALMA_RB_06')>=0):
7755 line += ' (and YIG may leak in)'
7756 yigLeakage = LOs[index[i]][0] + (LOs[index[i]][1] - LOs[index[i]][2]) + (yig - LOs[index[i]][1])
7757 if (yigLeakage > 0):
7758 line = line + ' at %.6f' % (yigLeakage*1e-9)
7759 if (show): print(line)
7760 if needToClose:
7761 mymsmd.done()
7762 if (birdieIF != 0):
7763 print("The feature at %f GHz is at IF = %f GHz." % (birdieFreqGHz, birdieIF*1e-9))
7764 if (alsoReturnLO2):
7765 return(lo1s, lo2s)
7766 else:
7767 return(lo1s)
7769def mjdSecondsToMJDandUT(mjdsec):
7770 """
7771 Converts a value of MJD seconds into MJD, and into a UT date/time string.
7772 example: (56000.0, '2012-03-14 00:00:00 UT')
7773 Caveat: only works for a scalar input value
7774 Todd Hunter
7775 """
7776 myme = measures()
7777 today = myme.epoch('utc','today')
7778 mjd = np.array(mjdsec) / 86400.
7779 today['m0']['value'] = mjd
7780 myqa = quanta()
7781 hhmmss = myqa.time(today['m0'], form='', prec=0, showform=False)[0]
7782# print("hhmmss = ", hhmmss)
7783 date = myqa.splitdate(today['m0'])
7784 myqa.done()
7785 utstring = "%s-%02d-%02d %s UT" % (date['year'],date['month'],date['monthday'],hhmmss)
7786 myme.done()
7787 return(mjd, utstring)
7789def ComputeSolarAzElForObservatory(mjdsec, mymsmd):
7790 pos = mymsmd.observatoryposition()
7791 longitude = pos['m0']['value'] * 180/np.pi
7792 latitude = pos['m1']['value'] * 180/np.pi
7793 return(ComputeSolarAzElLatLong(mjdsec,latitude,longitude))
7795def ComputeSolarAzElLatLong(mjdsec,latitude,longitude):
7796 """
7797 Computes the apparent Az,El of the Sun for a specified time and location
7798 on Earth. Latitude and longitude must arrive in degrees, with positive
7799 longitude meaning east of Greenwich.
7800 -- Todd Hunter
7801 """
7802 DEG_TO_RAD = math.pi/180.
7803 RAD_TO_DEG = 180/math.pi
7804 HRS_TO_RAD = math.pi/12.
7805 [RA,Dec] = ComputeSolarRADec(mjdsec)
7806 LST = ComputeLST(mjdsec, longitude)
7808 phi = latitude*DEG_TO_RAD
7809 hourAngle = HRS_TO_RAD*(LST - RA)
7810 azimuth = RAD_TO_DEG*math.atan2(math.sin(hourAngle), (math.cos(hourAngle)*math.sin(phi) - math.tan(Dec*DEG_TO_RAD)*math.cos(phi)))
7812 # the following is to convert from South=0 (which the French formula uses)
7813 # to North=0, which is what the rest of the world uses */
7814 azimuth += 180.0;
7816 if (azimuth > 360.0):
7817 azimuth -= 360.0
7818 if (azimuth < 0.0):
7819 azimuth += 360.0
7821 argument = math.sin(phi)*math.sin(Dec*DEG_TO_RAD) + math.cos(phi)*math.cos(Dec*DEG_TO_RAD) * math.cos(hourAngle);
7822 elevation = RAD_TO_DEG*math.asin(argument);
7823 return([azimuth,elevation])
7825def ComputeSolarRADec(mjdsec):
7826 """
7827 Computes the RA,Dec of the Sun for a specified time. -- Todd Hunter
7828 """
7829 jd = mjdToJD(mjdsec/86400.)
7830 RAD_TO_DEG = 180/math.pi
7831 RAD_TO_HRS = (1.0/0.2617993877991509)
7832 DEG_TO_RAD = math.pi/180.
7833 T = (jd - 2451545.0) / 36525.0
7834 Lo = 280.46646 + 36000.76983*T + 0.0003032*T*T
7835 M = 357.52911 + 35999.05029*T - 0.0001537*T*T
7836 Mrad = M * DEG_TO_RAD
7837 e = 0.016708634 - 0.000042037*T - 0.0000001267*T*T
7838 C = (1.914602 - 0.004817*T - 0.000014*T*T) * math.sin(Mrad) + (0.019993 - 0.000101*T) * math.sin(2*Mrad) + 0.000289*math.sin(3*Mrad)
7839 L = Lo + C
7840 nu = DEG_TO_RAD*(M + C)
7841 R = 1.000001018 * (1-e*e) / (1 + e*math.cos(nu))
7842 Omega = DEG_TO_RAD*(125.04 - 1934.136*T)
7843 mylambda = DEG_TO_RAD*(L - 0.00569 - 0.00478 * math.sin(Omega))
7844 epsilon0 = (84381.448 - 46.8150*T - 0.00059*T*T + 0.001813*T*T*T) / 3600.
7845 epsilon = (epsilon0 + 0.00256 * math.cos(Omega)) * DEG_TO_RAD
7846 rightAscension = RAD_TO_HRS*math.atan2(math.cos(epsilon)*math.sin(mylambda), math.cos(mylambda))
7847 if (rightAscension < 0):
7848 rightAscension += 24.0
7849 argument = math.sin(epsilon) * math.sin(mylambda)
7850 declination = RAD_TO_DEG*math.asin(argument)
7851 return([rightAscension, declination])
7853def angularSeparation(ra0,dec0,ra1,dec1, returnComponents=False):
7854 """
7855 Usage: angularSeparation(ra0,dec0,ra1,dec1)
7856 Computes the great circle angle between two celestial coordinates.
7857 using the Vincenty formula (from wikipedia) which is correct for all
7858 angles, as long as you use atan2() to handle a zero denominator.
7859 See http://en.wikipedia.org/wiki/Great_circle_distance
7860 ra,dec must be given in degrees, as is the output.
7861 It also works for the az,el coordinate system.
7862 Comopnent separations are field_0 minus field_1.
7863 See also angularSeparationRadians()
7864 -- Todd Hunter
7865 """
7866 ra0 *= math.pi/180.
7867 dec0 *= math.pi/180.
7868 ra1 *= math.pi/180.
7869 dec1 *= math.pi/180.
7870 deltaLong = ra0-ra1
7871 argument1 = (((math.cos(dec1)*math.sin(deltaLong))**2) +
7872 ((math.cos(dec0)*math.sin(dec1)-math.sin(dec0)*math.cos(dec1)*math.cos(deltaLong))**2))**0.5
7873 argument2 = math.sin(dec0)*math.sin(dec1) + math.cos(dec0)*math.cos(dec1)*math.cos(deltaLong)
7874 angle = math.atan2(argument1, argument2) / (math.pi/180.)
7875 if (returnComponents):
7876 radegrees = (ra0-ra1)*180/math.pi
7877 decdegrees = (dec0-dec1)*180/math.pi
7878 retval = angle,radegrees,decdegrees
7879 else:
7880 retval = angle
7881 return(retval)
7883def ComputeDewPointCFromRHAndTempC(relativeHumidity, temperature):
7884 """
7885 inputs: relativeHumidity in percentage, temperature in C
7886 output: in degrees C
7887 Uses formula from http://en.wikipedia.org/wiki/Dew_point#Calculating_the_dew_point
7888 Todd Hunter
7889 """
7890 temperature = np.array(temperature) # protect against it being a list
7891 relativeHumidity = np.array(relativeHumidity) # protect against it being a list
7892 es = 6.112 * np.exp(17.67 * temperature / (temperature + 243.5))
7893 E = relativeHumidity * 0.01 * es
7894 # patch problematic cases where relativy humiditiy is -1
7895 # requires changing numpy.mean to numpy.nanmean downstream the code to avoid bad averages of the dewpoint
7896 dewPoint = np.zeros(len(E))
7897 for i in range(len(E)):
7898 if E[i] <= 0:
7899 dewPoint[i] = None
7900 else:
7901 dewPoint[i] = 243.5 * np.log(E[i] / 6.112) / (17.67 - np.log(E[i] / 6.112))
7903 return dewPoint
7905def ComputeLST(mjdsec, longitude):
7906 """
7907 Computes the LST (in hours) for a specified time and longitude.
7908 The input longitude is in degrees, where east of Greenwich is positive.
7909 -- Todd Hunter
7910 """
7911 JD = mjdToJD(mjdsec/86400.)
7912 T = (JD - 2451545.0) / 36525.0
7913 sidereal = 280.46061837 + 360.98564736629*(JD - 2451545.0) + 0.000387933*T*T - T*T*T/38710000.
7914 # now we have LST in Greenwich, need to scale back to site
7915 sidereal += longitude
7916 sidereal /= 360.
7917 sidereal -= np.floor(sidereal)
7918 sidereal *= 24.0
7919 if (sidereal < 0):
7920 sidereal += 24
7921 if (sidereal >= 24):
7922 sidereal -= 24
7923 return(sidereal)
7925def mjdToJD(MJD):
7926 """
7927 Converts an MJD value to JD
7928 """
7929 JD = MJD + 2400000.5
7930 return(JD)
7932def splitListIntoContiguousLists(mylist):
7933 """
7934 Converts [1,2,3,5,6,7] into [[1,2,3],[5,6,7]], etc.
7935 -Todd Hunter
7936 """
7937 mylists = []
7938 newlist = [mylist[0]]
7939 for i in range(1,len(mylist)):
7940 if (mylist[i-1] != mylist[i]-1):
7941 mylists.append(newlist)
7942 newlist = [mylist[i]]
7943 else:
7944 newlist.append(mylist[i])
7945 mylists.append(newlist)
7946 return(mylists)
7948# Removed for CAS-8065
7949#def getScansForTimes(mymsmd, scantimes):
7950# myscans = []
7951# myscantimes = []
7952## print("len(scantimes) = ", len(scantimes))
7953# scantimes = splitListIntoContiguousLists(scantimes)
7954# for t in scantimes:
7955# mean_t = np.mean(t)
7956# range_t = (1+np.max(t)-np.min(t))*0.5
7957# scans_t = mymsmd.scansfortimes(mean_t, range_t)
7958# if (len(scans_t) > 0):
7959# scan = scans_t[0]
7960# # print("scansfortime(%f) = " % (t), scan)
7961# myscans.append(scan)
7962# myscantimes.append(t)
7963# return(myscans, myscantimes)
7965def pruneFilelist(filelist):
7966 """
7967 Reduce size of filenames in filelist to the extent that current working directory
7968 agrees with the path.
7969 """
7970 mypwd = os.getcwd() + '/'
7971 newfilelist = []
7972 for f in filelist:
7973 fstart = 0
7974 if (f.find(mypwd) == 0):
7975 fstart = len(mypwd)
7976 newfilelist.append(f[fstart:])
7977 return(newfilelist)