Coverage for /wheeldirectory/casa-6.7.0-12-py3.10.el8/lib/py/lib/python3.10/site-packages/casatasks/private/task_plotbandpass.py: 2%
5716 statements
« prev ^ index » next coverage.py v7.6.4, created at 2024-10-31 18:48 +0000
« prev ^ index » next coverage.py v7.6.4, created at 2024-10-31 18:48 +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 if (len(antennasToPlot) < 2 and overlayAntennas):
2131 print("More than 1 antenna is required for overlay='antenna'.")
2132 return()
2133 casalogPost(debug,"antennasToPlot = %s" % (str(antennasToPlot)))
2135 # Parse the field string to emulate plotms
2136 removeField = []
2137 if (type(field) == str):
2138 if (len(field) == sum([m in myValidCharacterListWithBang for m in field])):
2139 casalogPost(debug,"a list of field numbers was given")
2140 # a list of field numbers was given
2141 tokens = field.split(',')
2142 fieldlist = []
2143 for token in tokens:
2144 if (token.find('*')>=0):
2145 fieldlist = uniqueFields
2146 break
2147 elif (token.find('!')==0):
2148 fieldlist = uniqueFields
2149 removeField.append(int(token[1:]))
2150 elif (len(token) > 0):
2151 if (token.find('~')>0):
2152 (start,finish) = token.split('~')
2153 fieldlist += list(range(int(start),int(finish)+1))
2154 else:
2155 fieldlist.append(int(token))
2156 fieldlist = np.array(fieldlist)
2157 for rm in removeField:
2158 fieldlist = fieldlist[np.where(fieldlist != rm)[0]]
2159 fieldlist = list(fieldlist)
2160 if (len(fieldlist) < 1 and len(removeField)>0):
2161 print("Too many negated fields -- there are no fields left to plot.")
2162 return()
2163 else:
2164 casalogPost(debug,"The field name, or list of names was given")
2165 # The field name (or list of names, or wildcard) was specified
2166 tokens = field.split(',')
2167 if (msFound):
2168 fieldlist = []
2169 removeField = []
2170 for token in tokens:
2171 myloc = token.find('*')
2172 casalogPost(debug,"token=%s, myloc=%d" % (token,myloc))
2173 if (myloc > 0):
2174 casalogPost(debug,"Saw wildcard in the name")
2175 for u in uniqueFields:
2176 myFieldName = GetFieldNamesForFieldId(u, mymsmd, msFields)
2177 if (token[0:myloc]==myFieldName[0:myloc]):
2178 if (DEBUG):
2179 print("Found wildcard match = %s" % mymsmd.namesforfields(u))
2180 fieldlist.append(u)
2181 else:
2182 if (DEBUG):
2183 print("No wildcard match with = %s" % mymsmd.namesforfields(u))
2184 elif (myloc==0):
2185 casalogPost(debug,"Saw wildcard at start of name")
2186 for u in uniqueFields:
2187 fieldlist.append(u)
2188 elif (token in msFields):
2189 fieldlist = list(fieldlist) # needed in case preceding field had ! modifier
2190 fieldlist.append(GetFieldIdsForFieldName(token, mymsmd, msFields))
2191 elif (token[0] == '!'):
2192 if (fieldlist == []):
2193 for u in uniqueFields:
2194 fieldlist.append(u)
2195 if (token[1:] in msFields):
2196 removeField.append(GetFieldIdsForFieldName(token[1:], mymsmd, msFields))
2197 else:
2198 print("Field %s is not in the ms. It contains: %s, %s" % (token, str(uniqueFields), str(np.unique(msFields))))
2199 return()
2200 else:
2201 casalogPost(debug,"Field not in ms")
2202 fieldlist = []
2203 for f in mymsmd.namesforfields():
2204 fieldlist.append(mymsmd.fieldsforname(f))
2205 print("Field %s is not in the ms. It contains: %s, %s" % (token, str(uniqueFields), str(np.unique(msFields))))
2206 return()
2207 fieldlist = np.array(fieldlist)
2208 for rm in removeField:
2209 fieldlist = fieldlist[np.where(fieldlist != rm)[0]]
2210 fieldlist = list(fieldlist)
2211 if (len(fieldlist) < 1 and len(removeField)>0):
2212 print("Too many negated fields -- there are no fields left to plot.")
2213 return()
2214 else:
2215 print("Fields cannot be specified my name if the ms is not found.")
2216 return()
2217 elif (type(field) == list):
2218 # it's a list of integers
2219 fieldlist = field
2220 else:
2221 # It's a single, integer entry
2222 fieldlist = [field]
2224 casalogPost(debug,"fieldlist = %s" % (str(fieldlist)))
2226 if (len(fieldlist) > 0):
2227 if (DEBUG):
2228 print("Finding intersection of %s with %s" % (str(uniqueFields), str(fieldlist)))
2229 fieldsToPlot = np.intersect1d(uniqueFields,np.array(fieldlist))
2230 if (bOverlay):
2231 fieldsToPlot = np.intersect1d(np.union1d(uniqueFields,uniqueFields2),np.array(fieldlist))
2232 if (len(fieldsToPlot) < 1):
2233 print("Requested field not found in solution")
2234 return()
2235 else:
2236 fieldsToPlot = uniqueFields # use all fields if none are specified
2237 if (bOverlay):
2238 fieldsToPlot = np.union1d(uniqueFields,uniqueFields2)
2239 if (DEBUG):
2240 print("bOverlay = %s" % (bOverlay))
2241 print("set fieldsToPlot to uniqueFields = %s" % (str(fieldsToPlot)))
2242 fieldIndicesToPlot = []
2243 casalogPost(debug,"fieldsToPlot = %s" % (str(fieldsToPlot)))
2245 if (showatmfield == ''):
2246 showatmfield = fieldsToPlot[0]
2247 else:
2248 if (str.isdigit(str(showatmfield))):
2249 showatmfield = int(str(showatmfield))
2250 if (showatmfield not in fieldsToPlot):
2251 print("The showatmfield (%d) is not in the list of fields to plot: %s" % (showatmfield, str(fieldsToPlot)))
2252 return()
2253 else:
2254 showatmfieldName = showatmfield
2255 showatmfield = mymsmd.fieldsforname(showatmfield)
2256 if (list(showatmfield) == []):
2257 print("The showatmfield (%s) is not in the ms." %(showatmfieldName))
2258 return()
2259 if (type(showatmfield) == type(np.ndarray(0))):
2260 # more than one field IDs exist for this source name, so pick the first
2261 showatmfield = showatmfield[0]
2262 if (showatmfield not in fieldsToPlot):
2263 print("The showatmfield (%d=%s) is not in the list of fields to plot: %s" % (showatmfield, showatmfieldName, str(fieldsToPlot)))
2264 return()
2266 for i in fieldsToPlot:
2267 match = np.where(i==uniqueFields)[0]
2268 if (len(match) < 1 and bOverlay):
2269 match = np.where(i==uniqueFields2)[0]
2270 fieldIndicesToPlot.append(match[0])
2272 casalogPost(debug,"spws to plot (sorted) = %s" % (str(sorted(spwsToPlot))))
2273 casalogPost(debug,"Field IDs to plot: %s" % (str(fieldsToPlot)))
2275 redisplay = False
2276 myap = 0 # this variable is necessary to make the 'b' option work for
2277 # subplot=11, yaxis=both. It keeps track of whether 'amp' or
2278 # 'phase' was the first plot on the page.
2280 # I added pb.ion() because Remy suggested it.
2281 if (interactive):
2282 pb.ion() # This will open a new window if not present.
2283 else:
2284 pb.ioff() # This will not destroy an existing window or prevent new plots from appearing there.
2285# # The call to pb.figure() causes an additional new window everytime.
2286# # pb.figure()
2288 newylimits = [LARGE_POSITIVE, LARGE_NEGATIVE]
2290 safe_pb_clf() # pb.clf()
2291 if (bpoly):
2292 # The number of polarizations cannot be reliably inferred from the shape of
2293 # the GAIN column in the caltable. Must use the shape of the DATA column
2294 # in the ms.
2295 if (debug): print("in bpoly")
2296 if (msFound):
2297 (corr_type, corr_type_string, nPolarizations) = getCorrType(msName, spwsToPlot, mymsmd, debug)
2298 casalogPost(debug,"nPolarizations in first spw to plot = %s" % (str(nPolarizations)))
2299 else:
2300 print("With no ms available, I will assume ALMA data: XX, YY, and refFreq=first channel.")
2301 chanFreqGHz = []
2302 corr_type_string = ['XX','YY']
2303 corr_type = [9,12]
2304 nPolarizations = 2
2305 nPolarizations2 = nPolarizations
2306 if (corr_type_string == []):
2307 return()
2308 polsToPlot = checkPolsToPlot(polsToPlot, corr_type_string, debug)
2309 if (polsToPlot == []):
2310 return()
2311 # Here we are only plotting one BPOLY solution, no overlays implemented.
2312 overlayAntennas = False
2313 # rows in the table are: antennas 0..nAnt for first spw, antennas 0..nAnt
2314 # for 2nd spw...
2315 pagectr = 0
2316 if debug:
2317 print("Setting pages to blank list")
2318 pages = []
2319 xctr = 0
2320 newpage = 1
2321 while (xctr < len(antennasToPlot)):
2322 xant = antennasToPlot[xctr]
2323 antstring, Antstring = buildAntString(xant,msFound,msAnt)
2324 spwctr = 0
2325 spwctrFirstToPlot = spwctr
2326 while (spwctr < len(spwsToPlot)):
2327 ispw = spwsToPlot[spwctr]
2328 mytime = 0
2329 while (mytime < nUniqueTimes):
2330 if (len(uniqueTimes) > 0 and (mytime not in timerangeList)):
2331 if (debug):
2332 print("@@@@@@@@@@@@@@@ Skipping mytime=%d" % (mytime))
2333 mytime += 1
2334 continue
2335 if (newpage == 1):
2336 pages.append([xctr,spwctr,mytime,0])
2337 if debug:
2338 print("top: appending [%d,%d,%d,%d]" % (xctr,spwctr,mytime,0))
2339 newpage = 0
2340 antennaString = 'Ant%2d: %s, ' % (xant,antstring)
2341 for index in range(nRows):
2342 # Find this antenna, spw, and timerange combination in the table
2343 if tableFormat >= 34: ### added 2024Aug
2344 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
2345 else: ### added 2024Aug
2346 scansToPlotHere = scansToPlot ### added 2024Aug
2347 if (xant==ant[index] and sloppyMatch(uniqueTimes[mytime],times[index],solutionTimeThresholdSeconds,
2348 mytime, scansToPlotHere, scansForUniqueTimes, ### modified 2024Aug
2349 myprint=debugSloppyMatch) and
2350 (ispw == cal_desc_id[index]) and (fields[index] in fieldsToPlot)):
2351 fieldIndex = np.where(fields[index] == uniqueFields)[0]
2352 if (type(fieldIndex) == list or type(fieldIndex) == np.ndarray):
2353 fieldIndex = fieldIndex[0]
2354 validDomain = [frequencyLimits[0,index], frequencyLimits[1,index]]
2355 if (msFound):
2356 fieldString = msFields[uniqueFields[fieldIndex]]
2357 else:
2358 fieldString = str(field)
2359 timeString = ', t%d/%d %s' % (mytime,nUniqueTimes-1,utstring(uniqueTimes[mytime],3))
2360 if (scansForUniqueTimes != []):
2361 if (scansForUniqueTimes[mytime]>=0):
2362 timeString = ', scan%d %s' % (scansForUniqueTimes[mytime],utstring(uniqueTimes[mytime],3))
2363 if ((yaxis.find('amp')>=0 or amplitudeWithPhase) and myap==0):
2364 xframe += 1
2365 myUniqueColor = []
2366 if (debug):
2367 print("v) incrementing xframe to %d" % xframe)
2368 adesc = safe_pb_subplot(xframe)
2369 previousSubplot = xframe
2370 if (ispw==originalSpw[ispw]):
2371 # all this was added mistakenly here. If it causes a bug, remove it.
2372 if (overlayTimes and len(fieldsToPlot) > 1):
2373 indices = fstring = ''
2374 for f in fieldIndicesToPlot:
2375 if (f != fieldIndicesToPlot[0]):
2376 indices += ','
2377 fstring += ','
2378 indices += str(uniqueFields[f])
2379 if (msFound):
2380 fstring += msFields[uniqueFields[f]]
2381 if (len(fstring) > fstringLimit):
2382 fstring = fstring[0:fstringLimit] + '...'
2383 pb.title("%sspw%2d, fields %s: %s%s" % (antennaString,ispw,
2384 indices, fstring, timeString), size=titlesize)
2385 else:
2386 pb.title("%sspw%2d, field %d: %s%s" % (antennaString,ispw,
2387 uniqueFields[fieldIndex],fieldString,timeString), size=titlesize)
2388 else:
2389 if (overlayTimes and len(fieldsToPlot) > 1):
2390 indices = fstring = ''
2391 for f in fieldIndicesToPlot:
2392 if (f != fieldIndicesToPlot[0]):
2393 indices += ','
2394 fstring += ','
2395 indices += str(uniqueFields[f])
2396 if (msFound):
2397 fstring += msFields[uniqueFields[f]]
2398 if (len(fstring) > fstringLimit):
2399 fstring = fstring[0:fstringLimit] + '...'
2400 pb.title("%sspw%2d (%d), fields %s: %s%s" % (antennaString,ispw,originalSpw[ispw],
2401 indices, fstring, timeString), size=titlesize)
2402 else:
2403 pb.title("%sspw%2d (%d), field %d: %s%s" % (antennaString,ispw,originalSpw[ispw],
2404 uniqueFields[fieldIndex],fieldString,timeString), size=titlesize)
2405 amplitudeSolutionX = np.real(scaleFactor[index])+calcChebyshev(polynomialAmplitude[index][0:nPolyAmp[index]], validDomain, frequenciesGHz[index]*1e+9)
2406 amplitudeSolutionY = np.real(scaleFactor[index])+calcChebyshev(polynomialAmplitude[index][nPolyAmp[index]:2*nPolyAmp[index]], validDomain, frequenciesGHz[index]*1e+9)
2407 amplitudeSolutionX += 1 - np.mean(amplitudeSolutionX)
2408 amplitudeSolutionY += 1 - np.mean(amplitudeSolutionY)
2409 if (yaxis.lower().find('db') >= 0):
2410 amplitudeSolutionX = 10*np.log10(amplitudeSolutionX)
2411 amplitudeSolutionY = 10*np.log10(amplitudeSolutionY)
2412 if (nPolarizations == 1):
2413 pb.plot(frequenciesGHz[index], amplitudeSolutionX, '%s%s'%(xcolor,bpolymarkstyle),markeredgewidth=markeredgewidth)
2414 else:
2415 pb.plot(frequenciesGHz[index], amplitudeSolutionX, '%s%s'%(xcolor,bpolymarkstyle), frequenciesGHz[index], amplitudeSolutionY, '%s%s'%(ycolor,bpolymarkstyle),markeredgewidth=markeredgewidth)
2416 if (plotrange[0] != 0 or plotrange[1] != 0):
2417 SetNewXLimits([plotrange[0],plotrange[1]])
2418 if (plotrange[2] != 0 or plotrange[3] != 0):
2419 SetNewYLimits([plotrange[2],plotrange[3]])
2420 xlim=pb.xlim()
2421 ylim=pb.ylim()
2422 ResizeFontsSetGrid(adesc,mysize)
2423 if (yaxis.lower().find('db')>=0):
2424 pb.ylabel('Amplitude (dB)', size=mysize)
2425 else:
2426 pb.ylabel('Amplitude', size=mysize)
2427# pb.xlabel('Frequency (GHz)', size=mysize)
2428 pb.xlabel('Frequency (GHz) (%d channels)'%(len(frequenciesGHz[index])), size=mysize) # 2024Aug
2429 if (xframe == firstFrame):
2430 DrawBottomLegendPageCoords(msName, uniqueTimes[mytime], mysize, figfile)
2431 pb.text(xstartTitle, ystartTitle,
2432 '%s (degamp=%d, degphase=%d)'%(caltableTitle,nPolyAmp[index]-1,
2433 nPolyPhase[index]-1),size=mysize,
2434 transform=pb.gcf().transFigure)
2435 # draw polarization labels
2436 x0 = xstartPolLabel
2437 y0 = ystartPolLabel
2438 for p in range(nPolarizations):
2439 if (corrTypeToString(corr_type[p]) in polsToPlot):
2440 pb.text(x0, y0-0.03*subplotRows*p, corrTypeToString(corr_type[p])+'',
2441 color=pcolor[p],size=mysize, transform=pb.gca().transAxes)
2442 if (xframe == 111 and amplitudeWithPhase):
2443 if (len(figfile) > 0):
2444 # We need to make a new figure page
2445 plotfiles.append(makeplot(figfile,msFound,msAnt,
2446 overlayAntennas,pages,pagectr,
2447 density,interactive,antennasToPlot,
2448 spwsToPlot,overlayTimes,overlayBasebands,
2449 0,xant,ispw,subplot,resample,
2450 debug,figfileSequential,figfileNumber))
2451 figfileNumber += 1
2452 donetime = time.time()
2453 if (interactive):
2454 pb.draw()
2455# # myinput = raw_input("(%.1f sec) Press return for next page (b for backwards, q to quit): "%(donetime-mytimestamp))
2456 myinput = input("Press return for next page (b for backwards, q to quit): ")
2457 else:
2458 myinput = ''
2459 skippingSpwMessageSent = 0
2460 mytimestamp = time.time()
2461 if (myinput.find('q') >= 0):
2462 showFinalMessage(overlayAntennas, solutionTimeSpread, nUniqueTimes)
2463 return()
2464 if (myinput.find('b') >= 0):
2465 if (pagectr > 0):
2466 pagectr -= 1
2467 #redisplay the current page by setting ctrs back to the value they had at start of that page
2468 xctr = pages[pagectr][PAGE_ANT]
2469 spwctr = pages[pagectr][PAGE_SPW]
2470 mytime = pages[pagectr][PAGE_TIME]
2471 myap = pages[pagectr][PAGE_AP]
2472 xant = antennasToPlot[xctr]
2473 antstring, Antstring = buildAntString(xant,msFound,msAnt)
2474 ispw = spwsToPlot[spwctr]
2475 redisplay = True
2476 else:
2477 pagectr += 1
2478 if (pagectr >= len(pages)):
2479 pages.append([xctr,spwctr,mytime,1])
2480 print("appending [%d,%d,%d,%d]" % (xctr,spwctr,mytime,1))
2481 newpage = 0
2482 safe_pb_clf()
2484 if (yaxis.find('phase')>=0 or amplitudeWithPhase):
2485 xframe += 1
2486 myUniqueColor = []
2487# # print("w) incrementing xframe to %d" % xframe)
2488 adesc = safe_pb_subplot(xframe)
2489 previousSubplot = xframe
2490 if (ispw==originalSpw[ispw]):
2491 pb.title("%sspw%2d, field %d: %s%s" % (antennaString,ispw,
2492 uniqueFields[fieldIndex],fieldString,timeString), size=titlesize)
2493 else:
2494 pb.title("%sspw%2d (%d), field %d: %s%s" % (antennaString,ispw,originalSpw[ispw],
2495 uniqueFields[fieldIndex],fieldString,timeString), size=titlesize)
2496 phaseSolutionX = calcChebyshev(polynomialPhase[index][0:nPolyPhase[index]], validDomain, frequenciesGHz[index]*1e+9) * 180/math.pi
2497 phaseSolutionY = calcChebyshev(polynomialPhase[index][nPolyPhase[index]:2*nPolyPhase[index]], validDomain, frequenciesGHz[index]*1e+9) * 180/math.pi
2498 if (nPolarizations == 1):
2499 pb.plot(frequenciesGHz[index], phaseSolutionX, '%s%s'%(xcolor,bpolymarkstyle),markeredgewidth=markeredgewidth)
2500 else:
2501 pb.plot(frequenciesGHz[index], phaseSolutionX, '%s%s'%(xcolor,bpolymarkstyle), frequenciesGHz[index], phaseSolutionY, '%s%s'%(ycolor,bpolymarkstyle),markeredgewidth=markeredgewidth)
2502 ResizeFontsSetGrid(adesc,mysize)
2503 pb.ylabel('Phase (deg)', size=mysize)
2504# pb.xlabel('Frequency (GHz)', size=mysize)
2505 pb.xlabel('Frequency (GHz) (%d channels)'%(len(frequenciesGHz[index])), size=mysize) ### 2024Aug
2506 if (plotrange[0] != 0 or plotrange[1] != 0):
2507 SetNewXLimits([plotrange[0],plotrange[1]])
2508 if (plotrange[2] != 0 or plotrange[3] != 0):
2509 SetNewYLimits([plotrange[2],plotrange[3]])
2510 if (amplitudeWithPhase and phase != ''):
2511 if (phase[0] != 0 or phase[1] != 0):
2512 SetNewYLimits(phase)
2513 if (xframe == firstFrame):
2514 pb.text(xstartTitle, ystartTitle,
2515 '%s (degamp=%d, degphase=%d)'%(caltable,
2516 nPolyAmp[index]-1,nPolyPhase[index]-1),
2517 size=mysize, transform=pb.gcf().transFigure)
2518 # draw polarization labels
2519 x0 = xstartPolLabel
2520 y0 = ystartPolLabel
2521 for p in range(nPolarizations):
2522 if (corrTypeToString(corr_type[p]) in polsToPlot):
2523 pb.text(x0, y0-0.03*p*subplotRows, corrTypeToString(corr_type[p])+'',
2524 color=pcolor[p],size=mysize, transform=pb.gca().transAxes)
2526 # end of 'for' loop over rows
2527 redisplay = False
2528 pb.subplots_adjust(hspace=myhspace, wspace=mywspace)
2529 if (xframe == lastFrame):
2530 if (len(figfile) > 0):
2531 plotfiles.append(makeplot(figfile,msFound,msAnt,
2532 overlayAntennas,pages,pagectr,
2533 density,interactive,antennasToPlot,
2534 spwsToPlot,overlayTimes,overlayBasebands,
2535 1,xant,ispw,
2536 subplot,resample,debug,
2537 figfileSequential,figfileNumber))
2538 figfileNumber += 1
2539 donetime = time.time()
2540 if (interactive):
2541 pb.draw()
2542# # myinput = raw_input("(%.1f sec) Press return for next page (b for backwards, q to quit): "%(donetime-mytimestamp))
2543 myinput = input("Press return for next page (b for backwards, q to quit): ")
2544 else:
2545 myinput = ''
2546 skippingSpwMessageSent = 0
2547 mytimestamp = time.time()
2548 if (myinput.find('q') >= 0):
2549 return()
2550 if (myinput.find('b') >= 0):
2551 if (pagectr > 0):
2552 pagectr -= 1
2553 #redisplay the current page by setting ctrs back to the value they had at start of that page
2554 xctr = pages[pagectr][PAGE_ANT]
2555 spwctr = pages[pagectr][PAGE_SPW]
2556 mytime = pages[pagectr][PAGE_TIME]
2557 myap = pages[pagectr][PAGE_AP]
2558 xant = antennasToPlot[xctr]
2559 antstring, Antstring = buildAntString(xant,msFound,msAnt)
2560 ispw = spwsToPlot[spwctr]
2561 redisplay = True
2562 else:
2563 pagectr += 1
2564 if (pagectr >= len(pages)):
2565 newpage = 1
2566 else:
2567 newpage = 0
2568 if (debug):
2569 print("1)Setting xframe to %d" % xframeStart)
2570 xframe = xframeStart
2571 if (xctr+1 < len(antennasToPlot)):
2572 # don't clear the final plot when finished
2573 safe_pb_clf()
2574 if (spwctr+1<len(spwsToPlot) or mytime+1<nUniqueTimes):
2575 # don't clear the final plot when finished
2576 safe_pb_clf()
2577 pb.subplots_adjust(hspace=myhspace, wspace=mywspace)
2578 if (redisplay == False):
2579 mytime += 1
2580 if (debug):
2581 print("Incrementing mytime to %d" % (mytime))
2582 # end while(mytime)
2583 if (redisplay == False):
2584 spwctr +=1
2585 if (debug):
2586 print("Incrementing spwctr to %d" % (spwctr))
2587 # end while(spwctr)
2588 if (redisplay == False):
2589 xctr += 1
2590 # end while(xctr) for BPOLY
2591 if (len(figfile) > 0 and pagectr<len(pages)):
2592 plotfiles.append(makeplot(figfile,msFound,msAnt,overlayAntennas,pages,
2593 pagectr,density,interactive,antennasToPlot,
2594 spwsToPlot,overlayTimes,overlayBasebands,
2595 2,xant,ispw,subplot,resample,debug,
2596 figfileSequential,figfileNumber))
2597 figfileNumber += 1
2598 if (len(plotfiles) > 0 and buildpdf):
2599 pdfname = figfile+'.pdf'
2600 filelist = ''
2601 plotfiles = np.unique(plotfiles)
2602 for i in range(len(plotfiles)):
2603 cmd = '%s -density %d %s %s.pdf' % (convert,density,plotfiles[i],plotfiles[i].split('.png')[0])
2604 casalogPost(debug,"Running command = %s" % (cmd))
2605 mystatus = os.system(cmd)
2606 if (mystatus != 0):
2607 break
2608 filelist += plotfiles[i].split('.png')[0] + '.pdf '
2609 if (mystatus != 0):
2610 print("ImageMagick is missing, no PDF created")
2611 buildpdf = False
2612 if (buildpdf):
2613 cmd = '%s %s cat output %s' % (pdftk, filelist, pdfname)
2614 casalogPost(debug,"Running command = %s" % (cmd))
2615 mystatus = os.system(cmd)
2616 if (mystatus != 0):
2617 cmd = '%s -q -sPAPERSIZE=letter -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=%s %s' % (gs,pdfname,filelist)
2618 casalogPost(debug,"Running command = %s" % (cmd))
2619 mystatus = os.system(cmd)
2620 if (mystatus == 0):
2621 print("PDF left in %s" % (pdfname))
2622 os.system("rm -f %s" % filelist)
2623 else:
2624 print("Both pdftk and ghostscript are missing, no PDF created")
2625 return()
2627####################################################################################
2628# # bpoly == false,
2629#################
2630 msFound = False
2631 mytb.open(caltable)
2632 uniqueScanNumbers = sorted(np.unique(mytb.getcol('SCAN_NUMBER')))
2633 if (ParType == 'Complex'): # casa >= 3.4
2634 gain = {}
2635 for f in range(len(fields)):
2636 gain[f] = mytb.getcell('CPARAM',f)
2637 else: # casa 3.3
2638 gain = {}
2639# # gain = mytb.getcol('FPARAM') # 2,128,576
2640 if ('FPARAM' in mytb.colnames()):
2641 for f in range(len(fields)):
2642 gain[f] = mytb.getcell('FPARAM',f)
2643 else:
2644 for f in range(len(fields)):
2645 gain[f] = mytb.getcell('GAIN',f)
2646 nPolarizations = len(gain[0])
2647 if (debug):
2648 print("(1)Set nPolarizations = %d" % nPolarizations)
2649 ggx = {}
2650 for g in range(len(gain)):
2651 ggx[g] = gain[g][0]
2652 if (nPolarizations == 2):
2653 ggy = {}
2654 for g in range(len(gain)):
2655 ggy[g] = gain[g][1]
2656 mytb.close()
2658 if (debug):
2659 print("nPolarizations = %s" % (str(nPolarizations)))
2660 nRows = len(gain)
2661 if (bOverlay):
2662 mytb.open(caltable2)
2663 gain2 = {}
2664 if (ParType == 'Complex'):
2665# # gain2 = mytb.getcol('CPARAM')
2666 for f in range(len(fields2)):
2667 gain2[f] = mytb.getcell('CPARAM',f)
2668 else:
2669# # gain2 = mytb.getcol('FPARAM')
2670 for f in range(len(fields2)):
2671 if (tableFormat2 == 34):
2672 gain2[f] = mytb.getcell('FPARAM',f)
2673 else:
2674 gain2[f] = mytb.getcell('GAIN',f)
2675 mytb.close()
2676 ggx2 = {}
2677 for g in range(len(gain2)):
2678# # print("Appending to ggx: ", gain2[g][0])
2679 ggx2[g] = gain2[g][0]
2680 nPolarizations2 = len(gain2[0])
2681 if (nPolarizations == 2):
2682 ggy2 = {}
2683 for g in range(len(gain2)):
2684 ggy2[g] = gain2[g][1]
2685 nRows2 = len(gain2)
2686 if (debug): print("nRows2 = %s" % (str(nRows2)))
2688 if (tableFormat == 34):
2689 # CAS-6801, unfortunately corr_type is not available in the caltable
2690 mytb.open(caltable)
2691 spectralWindowTable = mytb.getkeyword('SPECTRAL_WINDOW').split()[1]
2692 if ('OBSERVATION' in mytb.getkeywords()):
2693 observationTable = mytb.getkeyword('OBSERVATION').split()[1]
2694 else:
2695 observationTable = None
2696 mytb.open(spectralWindowTable)
2697 refFreq = mytb.getcol('REF_FREQUENCY')
2698 net_sideband = mytb.getcol('NET_SIDEBAND')
2699 measFreqRef = mytb.getcol('MEAS_FREQ_REF')
2700 mytb.close()
2701 corr_type = None
2702 if (os.path.exists(msName)):
2703 try:
2704 (corr_type, corr_type_string, nPolarizations) = getCorrType(msName,originalSpwsToPlot,mymsmd,debug)
2705 except:
2706 print("4) Could not getCorrType")
2707 if (corr_type is None):
2708 if (observationTable is None):
2709 corr_type, corr_type_string, nPolarizations = getCorrTypeByAntennaName(msAnt[0].lower())
2710 else:
2711 telescope = getTelescopeNameFromCaltableObservationTable(observationTable)
2712 if (telescope.find('ALMA') >= 0):
2713 print("Using telescope name (%s) to set the polarization type." % (telescope))
2714 corr_type_string = ['XX','YY']
2715 corr_type = [9,12]
2716 elif (telescope.find('VLA') >= 0):
2717 print("Using telescope name (%s) to set the polarization type." % (telescope))
2718 corr_type_string = ['RR','LL']
2719 corr_type = [5,8]
2720 else:
2721 corr_type, corr_type_string, noPolarizations = getCorrTypeByAntennaName(msAnt[0].lower())
2722 else:
2723 try:
2724 if (DEBUG):
2725 print("Trying to open %s" % (msName+'/SPECTRAL_WINDOW'))
2726 mytb.open(msName+'/SPECTRAL_WINDOW')
2727 refFreq = mytb.getcol('REF_FREQUENCY')
2728 net_sideband = mytb.getcol('NET_SIDEBAND')
2729 measFreqRef = mytb.getcol('MEAS_FREQ_REF')
2730 mytb.close()
2732# (corr_type, corr_type_string, nPolarizations) = getCorrType(msName, spwsToPlot, mymsmd, debug)
2733 (corr_type, corr_type_string, nPolarizations) = getCorrType(msName, originalSpwsToPlot, mymsmd, debug)
2734 if (corr_type_string == []):
2735 return()
2736 except:
2737 print("4) Could not open the associated measurement set tables (%s). Will not translate antenna names." % (msName))
2738 mymsmd = ''
2739 print("I will assume ALMA data: XX, YY, and refFreq=first channel.")
2740# chanFreqGHz = [] # comment out on 2014-04-08
2741 corr_type_string = ['XX','YY']
2742 corr_type = [9,12]
2744 if (len(polsToPlot) > len(corr_type)):
2745 # Necessary for SMA (single-pol) data
2746 polsToPlot = corr_type_string
2747 casalogPost(debug,"Polarizations to plot = %s" % (str(polsToPlot)))
2748 polsToPlot = checkPolsToPlot(polsToPlot, corr_type_string, debug)
2749 if (polsToPlot == []):
2750 return()
2752 if (len(msAnt) > 0):
2753 msFound = True
2754 else:
2755 if (xaxis.find('freq')>=0 and tableFormat==33):
2756 print("Because I could not open the .ms, you cannot use xaxis='freq'.")
2757 return()
2758 if (showatm == True or showtsky==True):
2759 print("Because I could not open the .ms, you cannot use showatm or showtsky.")
2760 return()
2762 if (bpoly == False):
2763 if (debug):
2764 print("nPolarizations = %s" % (nPolarizations))
2765 print("nFields = %d = %s" % (nFields, str(uniqueFields)))
2767 if (bOverlay and debug):
2768 print("nPolarizations2 = %s" % (str(nPolarizations2)))
2769 print("nFields2 = %d = %s" % (nFields2, str(uniqueFields2)))
2770 print("nRows2 = %s" % (str(nRows2)))
2771 uniqueAntennaIds = np.sort(np.unique(ant))
2773 yPhaseLabel = 'Phase (deg)'
2774 tsysPercent = True
2775 ampPercent = True
2776 if (VisCal.lower().find('tsys') >= 0):
2777 if (channeldiff > 0):
2778 if (tsysPercent):
2779 yAmplitudeLabel = "Tsys derivative (%_of_median/channel)"
2780 else:
2781 yAmplitudeLabel = "Tsys derivative (K/channel)"
2782 else:
2783 yAmplitudeLabel = "Tsys (K)"
2784 else:
2785 if (yaxis.lower().find('db')>=0):
2786 yAmplitudeLabel = "Amplitude (dB)"
2787 else:
2788 if (channeldiff > 0):
2789 if (ampPercent):
2790 yAmplitudeLabel = "Amp derivative (%_of_median/channel)"
2791 else:
2792 yAmplitudeLabel = "Amplitude derivative"
2793 yPhaseLabel = 'Phase derivative (deg/channel)'
2794 else:
2795 yAmplitudeLabel = "Amplitude"
2797 madsigma = channeldiff # for option channeldiff>0, sets threshold for finding outliers
2798 ampMin = LARGE_POSITIVE
2799 ampMax = LARGE_NEGATIVE
2800 PHASE_ABS_SUM_THRESHOLD = 2e-3 # in degrees, used to avoid printing MAD statistics for refant
2802 TDMisSecond = False
2803 pagectr = 0
2804 drewAtmosphere = False
2805 newpage = 1
2806 if debug:
2807 print("Setting pages to blank list")
2808 pages = []
2809 xctr = 0
2810 myap = 0 # determines whether an amp or phase plot starts the page (in the case of 'both')
2811 # zero means amplitude, 1 means phase
2812 redisplay = False
2813 matchctr = 0
2814 myUniqueColor = []
2815 # for the overlay=antenna case, start by assuming the first antenna is not flagged
2816 firstUnflaggedAntennaToPlot = 0
2817 lastUnflaggedAntennaToPlot = len(antennasToPlot)
2818 computedAtmSpw = -1
2819 computedAtmTime = -1
2820 computedAtmField = -1
2821 skippingSpwMessageSent = 0
2822 atmString = ''
2823 if (showimage and lo1==''):
2824 # We only need to run this once per execution.
2825 if (debug):
2826 print("Calling getLOs")
2827 getLOsReturnValue = getLOs(msName, verbose=debug)
2828 if (getLOsReturnValue != []):
2829 if (debug):
2830 print("Calling interpret LOs")
2831 lo1s = interpretLOs(msName,parentms,verbose=debug,mymsmd=mymsmd)
2832 if (debug):
2833 print("Done interpretLOs")
2834 foundLO1Message = [] # Initialize so that message is only displayed once per spw
2836 if (channeldiff>0):
2837 # build blank dictionary: madstats['DV01']['spw']['time']['pol']['amp' or 'phase' or both]
2838 # where spw, time, pol are each integers
2839 if (len(msAnt) > 0):
2840 madstats = dict.fromkeys(mymsmd.antennanames(antennasToPlot))
2841 else:
2842 madstats = dict.fromkeys(['Ant '+str(i) for i in range(len(uniqueAntennaIds))])
2844 for i in range(len(madstats)):
2845 madstats[list(madstats.keys())[i]] = dict.fromkeys(spwsToPlot)
2846 for j in range(len(spwsToPlot)):
2847 madstats[list(madstats.keys())[i]][spwsToPlot[j]] = dict.fromkeys(timerangeList) # dict.fromkeys(range(len(uniqueTimes)))
2848 for k in timerangeList: # range(len(uniqueTimes)):
2849 madstats[list(madstats.keys())[i]][spwsToPlot[j]][k] = dict.fromkeys(list(range(nPolarizations)))
2850 for l in range(nPolarizations):
2851 if (yaxis == 'both'):
2852 madstats[list(madstats.keys())[i]][spwsToPlot[j]][k][l] = {'amp': None, 'phase': None}
2853 elif (yaxis == 'phase'):
2854 madstats[list(madstats.keys())[i]][spwsToPlot[j]][k][l] = {'phase': None}
2855 else:
2856 # this includes tsys and amp
2857 madstats[list(madstats.keys())[i]][spwsToPlot[j]][k][l] = {'amp': None}
2858 madstats['platforming'] = {}
2859# # print("madstats = ", madstats)
2860 myinput = ''
2861 atmEverBeenShown = False
2862 spwsToPlotInBaseband = []
2863 frequencyRangeToPlotInBaseband = []
2864 if (debug): print("up to basebands")
2865 if (len(basebands) == 0):
2866 # MS is too old to have BBC_NO
2867 if (debug): print("MS is too old to have BBC_NO")
2868 spwsToPlotInBaseband = [spwsToPlot]
2869 frequencyRangeToPlotInBaseband = [callFrequencyRangeForSpws(mymsmd, spwsToPlot, vm, caltable)]
2870 basebands = [0]
2871 elif (overlayBasebands):
2872 if (debug): print("overlayBaseband")
2873 if (list(spwsToPlot) != list(uniqueSpwsInCalTable)):
2874 # then spws were requested, so treat them all as if in the same baseband, and
2875 # ignore the basebands parameter
2876 print("Ignoring the basebands parameter because spws were specified = %s" % (str(spwsToPlot)))
2877 elif (np.array_equal(np.sort(basebands), np.sort(allBasebands)) == False):
2878 # Allow the basebands parameter to select the spws
2879 if (debug): print("Allow the basebands parameter to select the spws")
2880 basebandSpwsToPlot = []
2881 for baseband in basebands:
2882 myspws = list(getSpwsForBaseband(vis=msName, mymsmd=mymsmd, bb=baseband))
2883 basebandSpwsToPlot += myspws
2884 spwsToPlot = np.intersect1d(basebandSpwsToPlot, spwsToPlot)
2885 print("selected basebands %s have spwsToPlot = %s" % (str(basebands),str(spwsToPlot)))
2886 spwsToPlotInBaseband = [spwsToPlot] # treat all spws as if in the same baseband
2887 frequencyRangeToPlotInBaseband = [callFrequencyRangeForSpws(mymsmd, spwsToPlot, vm, caltable)]
2888 basebands = [0]
2889 else:
2890 print("basebands = %s, spwsToPlot=%s" % (basebands,spwsToPlot))
2891 for baseband in basebands:
2892 myspwlist = []
2893 for spw in spwsToPlot:
2894 if (ctsys.compare_version('>=',[4,1,0]) and msFound):
2895 if (mymsmd.baseband(originalSpwsToPlot[list(spwsToPlot).index(spw)]) == baseband):
2896 myspwlist.append(spw)
2897 else:
2898 # need to write a function to retrieve baseband
2899 # if (spw != 0):
2900 myspwlist.append(spw)
2901 spwsToPlotInBaseband.append(myspwlist)
2902 frequencyRangeToPlotInBaseband.append(callFrequencyRangeForSpws(mymsmd, myspwlist,vm,caltable))
2904 firstTimeMatch = -1 # Aug 5, 2013
2905 finalTimeMatch = -1 # for CAS-7820
2906 groupByBaseband = False # don't activate this parameter yet
2907 if (overlaySpws or overlayBasebands):
2908 groupByBaseband = True
2909 if (groupByBaseband and overlaySpws==False and overlayBasebands==False):
2910 showBasebandNumber = True
2911 # Basic nested 'while' loop structure is:
2912 # - antennas
2913 # - baseband (if necessary)
2914 # - spw
2915 # - time
2916 # - for i in rows
2917 maxChannels = {}; maxChannels2 = {}
2918 while (xctr < len(antennasToPlot)):
2919 if (debug): print("at top of xctr loop: %d" % (xctr))
2920 xant = antennasToPlot[xctr]
2921 bbctr = 0
2922 spwctr = 0
2923 spwctrFirstToPlot = 0
2924 antstring, Antstring = buildAntString(xant,msFound,msAnt)
2925 alreadyPlottedAmp = False # needed for (overlay='baseband', yaxis='both') CAS-6477
2926 finalSpwWasFlagged = False # inserted on 22-Apr-2014 for g25.27
2927 if debug:
2928 print("if (bbctr=%d <? %d and groupByBaseband=%s) or (spwctr=%d < %d and not groupByBaseband=%s)" % (bbctr,len(spwsToPlotInBaseband), groupByBaseband, spwctr, len(spwsToPlot), groupByBaseband))
2929 while ((bbctr < len(spwsToPlotInBaseband) and groupByBaseband) or
2930 (spwctr < len(spwsToPlot) and groupByBaseband==False)
2931 ):
2932 if (debug): print("at top of bbctr/spwctr loop with bbctr=%d, spwctr=%d" % (bbctr,spwctr))
2933 if (groupByBaseband):
2934 baseband = basebands[bbctr]
2935 spwsToPlot = spwsToPlotInBaseband[bbctr]
2936 if (debug): print("setting spwsToPlot for baseband %d (bbctr=%d) to %s" % (baseband, bbctr, str(spwsToPlot)))
2937 else:
2938 baseband = 0 # add from here to "ispw=" on 2014-04-05
2939 if (ctsys.compare_version('>=',[4,1,0])):
2940 if (debug): print("TASK> msName=%s, vis=%s" % (msName,vis))
2941 if (getBasebandDict(vis=msName,caltable=caltable,mymsmd=mymsmd) != {}):
2942 try:
2943 baseband = mymsmd.baseband(originalSpwsToPlot[spwctr])
2944 if (baseband not in basebands):
2945 spwctr += 1
2946 if (debug): print("A)incrementing spwctr")
2947 continue
2948 except:
2949 pass
2950 if (debug):
2951 if (overlayBasebands):
2952 print("Regardless of baseband (%s), plotting all spws: %s" % (basebands,str(spwsToPlot)))
2953 else:
2954 print("Showing baseband %d containing spws: %s" % (baseband,str(spwsToPlot)))
2955 if (bbctr < len(spwsToPlotInBaseband)):
2956 if (debug):
2957 print("A) spwctr=%d, bbctr=%d < len(spwsToPlotInBaseband)=%d" % (spwctr,bbctr,len(spwsToPlotInBaseband)))
2958 spwctr = 0
2959 spwctrFirstToPlot = spwctr
2960 firstSpwMatch = -1
2961 while (spwctr < len(spwsToPlot)):
2962 if (debug): print("at top of spwctr loop, spwctr=%d" % (spwctr))
2963 allTimesFlaggedOnThisSpw = True # used only by overlay='time'
2964 if (groupByBaseband == False):
2965 baseband = 0
2966 if (ctsys.compare_version('>=',[4,1,0])):
2967 if (getBasebandDict(vis=msName,caltable=caltable,mymsmd=mymsmd) != {}):
2968 try:
2969 baseband = mymsmd.baseband(originalSpwsToPlot[spwctr])
2970 if (baseband not in basebands):
2971 # print("spw %d=%d: baseband %d is not in %s" % (spwsToPlot[spwctr],originalSpwsToPlot[spwctr], baseband, basebands))
2972 if (debug): print("Bb)incrementing spwctr")
2973 spwctr += 1
2974 continue
2975 except:
2976 pass
2977 ispw = spwsToPlot[spwctr]
2978 ispwInCalTable = list(uniqueSpwsInCalTable).index(ispw)
2979 mytime = 0
2980 if (debug):
2981 print("+++++++ set mytime=0 for ispw=%d, len(chanFreqGHz) = %d" % (ispw, len(chanFreqGHz)))
2982 if (overlayAntennas):
2983 xctr = -1
2984 if (overlayTimes):
2985 # since the times/scans can vary between spws, redefine nUniqueTimes for each spw
2986 nUniqueTimes = len(uniqueTimesCopy)
2987 uniqueTimes = uniqueTimesCopy[:]
2988 uniqueTimesForSpw = []
2989 testtime = 0
2990 while (testtime < nUniqueTimes):
2991 if (ispw in cal_desc_id[np.where(uniqueTimes[testtime] == times)[0]]):
2992 uniqueTimesForSpw.append(uniqueTimes[testtime])
2993 testtime += 1
2994 uniqueTimes = uniqueTimesForSpw[:]
2995 if (tableFormat >= 34):
2996 scansForUniqueTimes, nUniqueTimes = computeScansForUniqueTimes(uniqueTimes, cal_scans, times, unique_cal_scans)
2997 else:
2998 nUniqueTimes = len(uniqueTimes)
2999# currentSpwctr = spwctr # commented out on 2014-04-04 to match task for task01 regression
3000 if (overlaySpws or overlayBasebands):
3001 if (xctr >= firstUnflaggedAntennaToPlot):
3002 if (debug):
3003 print("xctr=%d >= firstUnflaggedAntennaToPlot=%d, decrementing spwctr to %d" % (xctr, firstUnflaggedAntennaToPlot,spwctr-1))
3004 spwctr -= 1
3006 firstTimeMatch = -1
3007 finalTimeMatch = -1 # for CAS-7820
3008 while (mytime < nUniqueTimes): # start of enormous 2470-line while loop
3009 finalTimerangeFlagged = False # 04-Aug-2014
3010 if (debug):
3011 print("at top of mytime loop: mytime = %d < %d" % (mytime,nUniqueTimes))
3012 print("%d timerangeListTimes" % (len(timerangeListTimes)))
3013 print("timerangeList = %s" % (str(timerangeList)))
3014 print("timerangeListTimes = %s" % (str(timerangeListTimes)))
3015 print("debugSloppyMatch = %s" % (str(debugSloppyMatch)))
3016 print(("solutionTimeThresholdSeconds = %s" % (str(solutionTimeThresholdSeconds))))
3017# if ((scansToPlot == scansToPlotPerSpw[ispw]).all() == False and False):
3018# print " scansToPlot = ", scansToPlot
3019# print "scansToPlotPerSpw[%2d] = " % (ispw), scansToPlotPerSpw[ispw]
3020 if (len(timerangeList) > 0 and
3021 (sloppyMatch(uniqueTimes[mytime],timerangeListTimes,solutionTimeThresholdSeconds,
3022 mytime, scansToPlot, scansForUniqueTimes, myprint=debugSloppyMatch)==False)): # task version
3023# mytime, scansToPlotPerSpw[ispw], scansForUniqueTimes, myprint=debugSloppyMatch)==False)): # causes infinite loop on test 85
3024 if (debug):
3025 print("Skipping time %d because it is not in the list: %s" % (mytime, str(timerangeList)))
3026 mytime += 1
3027 if (debug): print(" 0006 incrementing mytime to ", mytime)
3028 if (mytime == nUniqueTimes and overlayTimes and overlayAntennas):
3029 # added March 14, 2013 to support the case when final timerange is flagged
3030 doneOverlayTime = False
3031 if (debug):
3032 print("$$$$$$$$$$$$$$$$$$$$$$ Setting doneOverlayTime=False" % (xframe))
3033 else:
3034 if (debug):
3035 print("Not setting doneOverlayTime=False because either mytime(%d) != nUniqueTimes(%d) or we are not overlaying time and antenna" % (mytime,nUniqueTimes))
3036 continue
3037 if (overlayAntennas):
3038 xctr += 1
3039 if (xctr >= len(antennasToPlot)):
3040 xctr = 0
3041# if (mytime == 0):
3042# if (debug): print "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ setting firstTimeMatch = -1"
3043# firstTimeMatch = -1 # Aug 5, 2013
3044 xant = antennasToPlot[xctr]
3045 if (debug):
3046 print("mytime=%d, Set xant to %d" % (mytime,xant))
3047 antennaString = ''
3048 else:
3049 antennaString = 'Ant%2d: %s, ' % (xant,antstring)
3050 if (overlaySpws or overlayBasebands):
3051 if (debug): print("C)incrementing spwctr to %d" % (spwctr+1))
3052 spwctr += 1
3053 if (spwctr >= len(spwsToPlot)):
3054 if (debug): print("---------------------- C) Setting spwctr=0")
3055 spwctr = 0
3056 if (xctr < firstUnflaggedAntennaToPlot):
3057 xctr += 1
3058 if (xctr == len(antennasToPlot)):
3059 break
3060 xant = antennasToPlot[xctr]
3061 antstring = buildAntString(xant,msFound,msAnt)
3062 if (debug):
3063 print("mytime=%d, Set xant to %d" % (mytime,xant))
3064 antennaString = 'Ant%2d: %s, ' % (xant,antstring)
3065 if (overlayBasebands):
3066 # Added on 7/29/2014 to fix infinite loop in uid___A002_X652932_X20fb bandpass
3067 if (mytime == nUniqueTimes):
3068 spwctr = len(spwsToPlot)
3069 break
3070 ispw = spwsToPlot[spwctr]
3071 ispwInCalTable = list(uniqueSpwsInCalTable).index(ispw)
3072 if (debug):
3073 print("----------------------------- spwctr=%d, ispw set to %d, xctr=%d" % (spwctr,ispw,xctr))
3074 # endif overlaySpws or overlayBasebands
3075 if (newpage==1):
3076 # add the current page (being created here) to the list
3077 if (debug):
3078 print("pages = ", pages)
3079 pages.append([xctr,spwctr,mytime,0])
3080 if (debug):
3081 print("next: appending [%d,%d,%d,%d]" % (xctr,spwctr,mytime,0))
3082 newpage = 0
3083 if (ispw not in uniqueSpwsInCalTable): ##### added 2024Aug
3084 print("spw %d is not in caltable=%s" % (ispw,uniqueSpwsInCalTable)) ##### added 2024Aug
3085 return ##### added 2024Aug
3086 if tableFormat > 33: ##### added 2024Aug
3087 if ispw not in list(scansToPlotPerSpw.keys()): ##### added 2024Aug
3088 print("ispw=%d not in %s" % (ispw,scansToPlotPerSpw)) ##### added 2024Aug
3089 break ##### added 2024Aug
3090 gplotx = []
3091 gploty = []
3092 channels = []
3093 xchannels = []
3094 ychannels = []
3095 frequencies = []
3096 xfrequencies = []
3097 yfrequencies = []
3098 channels2 = []
3099 xchannels2 = []
3100 ychannels2 = []
3101 frequencies2 = []
3102 xfrequencies2 = []
3103 yfrequencies2 = []
3104 gplotx2 = []
3105 gploty2 = []
3106 xflag = []
3107 yflag = []
3108 xflag2 = []
3109 yflag2 = []
3110 matchFound = False
3111 matchField = -1
3112 matchRow = -1
3113 matchTime = -1
3114 if (debug): print("looping over all nRows = %d" % (nRows))
3115 for i in range(nRows):
3116 if (overlayTimes or overlayAntennas or len(fieldsToPlot)>1 or
3117 (nFields>1 and len(fieldlist)<nFields)):
3118 # When there are multiple fields, then matching by scan causes the first
3119 # matching solution to be displayed every time. So use the original method
3120 # of matching by time until I think of something better.
3121 sm = sloppyMatch(uniqueTimes[mytime],times[i],solutionTimeThresholdSeconds,myprint=False)
3122 else:
3123 if (overlayBasebands):
3124 sTP = scansToPlot
3125 else:
3126 if tableFormat > 33: ### added 2024Aug
3127 sTP = scansToPlotPerSpw[ispw] ### indented 2024Aug
3128 else: ### added 2024Aug
3129 sTP = [] ### added 2024Aug
3130 sm = sloppyMatch(uniqueTimes[mytime],times[i],solutionTimeThresholdSeconds,
3131 mytime, sTP, scansForUniqueTimes, myprint=False) # au version
3132 if ((ant[i]==xant) and (cal_desc_id[i]==ispw) and sm
3133 and (mytime in timerangeList) # this test was added to support multiFieldInTimeOverlay
3134 ):
3135 if (debug): print("len(chanFreqGHz)=%d, ispw=%d" % (len(chanFreqGHz),ispw))
3136 if (msFound or tableFormat==34):
3137 if (len(chanFreqGHz[ispw]) == 1):
3138 if ((skippingSpwMessageSent & (1<<ispw)) == 0):
3139 casalogPost(debug,"Skipping spw=%d because it has only 1 channel." % (ispw))
3140 skippingSpwMessageSent |= (1<<ispw)
3141 break
3142 if (fields[i] in fieldsToPlot):
3143 interval = intervals[i] # used for CalcAtmTransmission
3144 myFieldIndex = np.where(fields[i] == uniqueFields)[0]
3145 if (type(myFieldIndex) == list or type(myFieldIndex) == np.ndarray):
3146 myFieldIndex = myFieldIndex[0]
3147 if (debug):
3148 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)))
3149 if (matchFound):
3150 if (myFieldIndex == matchField and matchTime==times[i]):
3151 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))
3152 else:
3153 matchFound = True
3154 fieldIndex = myFieldIndex
3155 matchField = myFieldIndex
3156 matchTime = times[i]
3157 matchRow = i
3158 if (msFound or tableFormat==34):
3159 nChannels = len(chanFreqGHz[ispw])
3160 else:
3161 nChannels = len(ggx[0])
3162 xflag.append(flags[i][0][:])
3163 yflag.append(flags[i][1][:])
3164 BRowNumber = i
3165 for j in range(nChannels): # len(chanFreqGHz[ispw])):
3166 channels.append(j) # both flagged and unflagged
3167 if (msFound or tableFormat==34):
3168 frequencies.append(chanFreqGHz[ispw][j])
3169 if (j==0 and debug):
3170 print("found match: ispw=%d, j=%d, len(chanFreqGHz)=%d, chanFreqGHz[0]=%f" % (ispw,j, len(chanFreqGHz),chanFreqGHz[ispw][0]))
3171 if (showflagged or (showflagged == False and flags[i][0][j]==0)):
3172 gplotx.append(ggx[i][j])
3173 xchannels.append(j)
3174 if (msFound or tableFormat==34):
3175 xfrequencies.append(chanFreqGHz[ispw][j])
3176 if (nPolarizations == 2):
3177 if (showflagged or (showflagged == False and flags[i][1][j]==0)):
3178 gploty.append(ggy[i][j])
3179 ychannels.append(j)
3180 if (msFound or tableFormat==34):
3181 yfrequencies.append(chanFreqGHz[ispw][j])
3182 # end 'for i' over rows
3184# if (not matchFound and newpage==0 and firstTimeMatch==-1):
3185 if (not matchFound and newpage==0):
3186 # the first test below is the first of two fixes for CAS-13568 (prevent crash)
3187 if (len(pages) > 1) and (subplot==11 or (subplot!=11 and firstSpwMatch==-1 and firstTimeMatch==-1)):
3188 # Fix for CAS-7753
3189 # the firstTimeMatch part was needed for regression 65: different antennas having different solution times
3190 newpage = 1
3191 if debug: print("setting pages to length=%d" % (len(pages)-1))
3192 pages = pages[:len(pages)-1]
3193 myspw = originalSpw[ispw]
3194 if myspw not in list(maxChannels.keys()):
3195 maxChannels[myspw] = 0 # keep track to set x-axis label correctly
3196 maxChannels2[myspw] = 0 # keep track to set x-axis label correctly
3198 if len(xchannels) > maxChannels[myspw]:
3199 maxChannels[myspw] = len(xchannels) # keep track to set x-axis label correctly
3200 if len(xchannels2) > maxChannels[myspw]:
3201 maxChannels2[myspw] = len(xchannels2) # keep track to set x-axis label correctly
3202 if (msFound):
3203 if debug:
3204 print("A) xchannels = ", xchannels)
3205 print("myspw=%s" % (str(myspw)))
3206 print("len(refFreq)=%d" % (len(refFreq)))
3207 if (myspw >= len(refFreq)):
3208 myspw = ispw
3209 if (msFound and refFreq[myspw]*1e-9 > 60):
3210 # Then this cannot be Band 1 or EVLA data. TODO: But I should really check the telescope name!
3211# if (refFreq[myspw]*1e-9 > np.mean(frequencies)):
3212 if (refFreq[myspw]*1e-9 > np.mean(chanFreqGHz[ispw])): # this is safer (since frequencies might be an empty list)
3213 sideband = -1
3214# xlabelString = "%s LSB Frequency (GHz)" % refTypeToString(measFreqRef[myspw])
3215 xlabelString = "%s LSB Frequency (GHz) (%d channels)" % (refTypeToString(measFreqRef[myspw]),maxChannels[myspw]) ### 2024Aug
3216 else:
3217 sideband = +1
3218# xlabelString = "%s USB Frequency (GHz)" % refTypeToString(measFreqRef[myspw])
3219 xlabelString = "%s USB Frequency (GHz) (%d channels)" % (refTypeToString(measFreqRef[myspw]),maxChannels[myspw]) ### 2024Aug
3220 else:
3221 sideband = -1
3222# xlabelString = "Frequency (GHz)"
3223 xlabelString = "Frequency (GHz) (%d channels)" % (maxChannels[myspw]) ### 2024Aug
3224 if ((len(frequencies)>0) and (chanrange[1] > len(frequencies))):
3225 print("Invalid chanrange (%d-%d) for spw%d in caltable1. Valid range = 0-%d" % (chanrange[0],chanrange[1],ispw,len(frequencies)-1))
3226 return()
3227 pchannels = [xchannels,ychannels]
3228 pfrequencies = [xfrequencies,yfrequencies]
3229 gplot = [gplotx,gploty]
3230 # We only need to compute the atmospheric transmission if:
3231 # * we have been asked to show it,
3232 # * there is a non-trivial number of channels,
3233 # * the current field is the one for which we should calculate it (if times are being overlaied)
3234 # But this will cause no atmcurve to appear if that field is flagged on the first
3235 # antenna; so, I added the atmEverBeenShown flag to deal with this.
3236 # * the previous calculation is not identical to what this one will be
3237 #
3238 if ((showatm or showtsky) and (len(xchannels)>1 or len(ychannels)>1) and
3239 ((uniqueFields[fieldIndex]==showatmfield or
3240 (uniqueFields[fieldIndex] in fieldsToPlot and overlayTimes)) or # this insures a plot if first fieldsToPlot is missing
3241 overlayTimes==False or atmEverBeenShown==False) and
3242 ((overlayTimes==False and computedAtmField!=fieldIndex) or (computedAtmSpw!=ispw) or
3243 (overlayTimes==False and computedAtmTime!=mytime))):
3244 atmEverBeenShown = True
3245 # The following 'if' is used to avoid wasting time since atm is not shown for
3246 # overlay='antenna,time'.
3247 if (overlayTimes==False or overlayAntennas==False or True): # support showatm for overlay='antenna,time'
3248# # if (overlayTimes==False or overlayAntennas==False):
3249# # # # print("CAF, CAS, CAT = ", computedAtmField, computedAtmSpw, computedAtmTime)
3250 if (type(fieldIndex) == list or type(fieldIndex) == np.ndarray):
3251 computedAtmField = fieldIndex[0]
3252 else:
3253 computedAtmField = fieldIndex
3254 computedAtmSpw = ispw
3255 computedAtmTime = mytime
3256 atmtime = time.time()
3257 asdm = ''
3258# # # # print("A) uniqueFields[%d] = " % (fieldIndex), uniqueFields[fieldIndex])
3259 uFFI = uniqueFields[fieldIndex]
3260 if (type(uFFI) == type(np.ndarray(0))):
3261 uFFI = uFFI[0]
3262 if (debug): print("converting uFFI from array to %s" % (str(type(uFFI))))
3263 (atmfreq,atmchan,transmission,pwvmean,atmairmass,TebbSky,missingCalWVRErrorPrinted) = \
3264 CalcAtmTransmission(channels, frequencies, xaxis, pwv,
3265 vm, mymsmd, msName, asdm, xant, uniqueTimes[mytime],
3266 interval, uFFI, refFreq[originalSpw[ispw]],
3267 net_sideband[originalSpw[ispw]], mytime,
3268 missingCalWVRErrorPrinted, caltable,
3269 Trx=Trx, showtsys=showtsys, verbose=DEBUG)
3270 if showtsys:
3271 TebbSky = Tsys
3272 if (showimage):
3273# print("len(lo1s)=%d = " % (len(lo1s)), lo1s)
3274 if (lo1 != ''):
3275 # lo1 was specified on the command line
3276 LO1 = lo1
3277 else:
3278 if (getLOsReturnValue == []):
3279 if (lo1 == ''):
3280 print("Because you do not have the ASDM_RECEIVER table, if you want the showimage")
3281 print("option to work, then you must specify the LO1 frequency with lo1=.")
3282# # # # return()
3283 LO1 = lo1
3284 else:
3285 if (lo1s is None or lo1s == {}):
3286 print("Failed to get LO1, disabling showimage. Alternatively, you can use printLOsFromASDM and supply the lo1 parameter to plotbandpass.")
3287 showimage = False
3288 LO1 = ''
3289 else:
3290 if (originalSpw[ispw] not in list(lo1s.keys())):
3291 print("There is a problem in reading the LO1 values, cannot showimage for this dataset.")
3292 showimage = False
3293 LO1 = ''
3294 else:
3295 LO1 = lo1s[originalSpw[ispw]]*1e-9
3296 if (ispw not in foundLO1Message):
3297 casalogPost(debug,"For spw %d (%d), found LO1 = %.6f GHz" % (ispw,originalSpw[ispw],LO1))
3298 foundLO1Message.append(ispw)
3299 if (LO1):
3300 frequenciesImage = list(2*LO1 - np.array(frequencies))
3301 xfrequenciesImage = list(2*LO1 - np.array(pfrequencies[0]))
3302 yfrequenciesImage = list(2*LO1 - np.array(pfrequencies[1]))
3303 pfrequenciesImage = [xfrequenciesImage, yfrequenciesImage]
3304 if (debug):
3305 print("B) uniqueFields[%d] = %s" % (fieldIndex, str(uniqueFields[fieldIndex])))
3306 uFFI = uniqueFields[fieldIndex]
3307 if (debug):
3308 print("type(uFFI) = %s" % (str(type(uFFI))))
3309 if (type(uFFI) == list or type(uFFI) == type(np.ndarray(0))):
3310 uFFI = uFFI[0]
3311 if (debug):
3312 print("uFFI = %s" % (str(uFFI)))
3313 (atmfreqImage,atmchanImage,transmissionImage,pwvmean,atmairmass,TebbSkyImage,missingCalWVRErrorPrinted) = \
3314 CalcAtmTransmission(channels, frequenciesImage, xaxis,
3315 pwv, vm, mymsmd, msName, asdm, xant, uniqueTimes[mytime],
3316 interval, uFFI, refFreq[originalSpw[ispw]],
3317 net_sideband[originalSpw[ispw]], mytime,
3318 missingCalWVRErrorPrinted, caltable,
3319 Trx=Trx, showtsys=showtsys, verbose=DEBUG)
3320 # difference between the requested Atm freq and actual Atm calcuation CAS-7715. No longer necessary after CAS-10228.
3321 #chanDifference = atmfreq[0]-frequencies[0]
3322 #chanImageDifference = atmfreqImage[0]-frequenciesImage[-1]
3323 #print("signal SB difference = %f, image SB difference = %f" % (chanDifference, chanImageDifference))
3324 if showtsys:
3325 TebbSkyImage = TsysImage
3326 atmfreqImage = list(2*LO1 - np.array(atmfreqImage)) # + 2*chanDifference + chanImageDifference) # CAS-7715 adds final 2 terms
3327 atmchanImage.reverse()
3329 if (overlayTimes):
3330 atmString = 'PWV %.2fmm, airmass %.2f, maxAlt %.0fkm (field %d)' % (pwvmean,atmairmass,maxAltitude,showatmfield)
3331 else:
3332 atmString = 'PWV %.2fmm, airmass %.3f, maxAlt %.0fkm' % (pwvmean,atmairmass,maxAltitude)
3333 if (bOverlay):
3334 for i in range(nRows2):
3335 if (overlayTimes or overlayAntennas or len(fieldsToPlot)>1 or
3336 (nFields>1 and len(fieldlist)<nFields)):
3337 # Not having this path causes Tsys table overlays to behave like overlay='antenna,time'
3338 # for caltable2.
3339 sm = sloppyMatch(uniqueTimes2[mytime],times2[i],solutionTimeThresholdSeconds,myprint=False)
3340 else:
3341 if (mytime >= len(uniqueTimes2)):
3342 # Fix for CAS-9474: avoid calling sloppyMatch because it will crash.
3343 # Setting sm=False will result in an abort: "no amp data found in second solution."
3344 sm = False
3345 else:
3346 if tableFormat >= 34: ### added 2024Aug
3347 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
3348 else: ### added 2024Aug
3349 scansToPlotHere = scansToPlot ### added 2024Aug
3350 sm = sloppyMatch(uniqueTimes2[mytime],times2[i],solutionTimeThresholdSeconds,
3351 mytime, scansToPlotHere, scansForUniqueTimes, # au version ### modified 2024Aug
3352 myprint=debugSloppyMatch)
3353 if ((ant2[i]==xant) and (cal_desc_id2[i]==ispw) and sm
3354 and (mytime in timerangeList) # added to match first caltable logic on 2014-04-09
3355 ):
3356 if (fields2[i] in fieldsToPlot):
3357 xflag2.append(flags2[i][0][:])
3358 yflag2.append(flags2[i][1][:])
3359 # With solint='2ch' or more, the following loop should not be over
3360 # chanFreqGHz2 but over the channels in the solution.
3361 for j in range(len(chanFreqGHz2[ispw])):
3362 channels2.append(j)
3363 frequencies2.append(chanFreqGHz2[ispw][j])
3364# # # # 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)))
3365 if (showflagged or (showflagged == False and flags2[i][0][j]==0)):
3366 gplotx2.append(ggx2[i][j])
3367 xchannels2.append(j)
3368 xfrequencies2.append(chanFreqGHz2[ispw][j])
3369 if (nPolarizations2 == 2):
3370 if (showflagged or (showflagged == False and flags2[i][1][j]==0)):
3371 gploty2.append(ggy2[i][j])
3372 ychannels2.append(j)
3373 yfrequencies2.append(chanFreqGHz2[ispw][j])
3374 # end 'for i'
3375 pchannels2 = [xchannels2,ychannels2]
3376 pfrequencies2 = [xfrequencies2,yfrequencies2]
3377 gplot2 = [gplotx2,gploty2]
3378 # Need to rewrite the xlabel to show the total channel numbers from both caltables. Note that xaxis must be 'freq' for bOverlay
3379 if (msFound and refFreq[myspw]*1e-9 > 60):
3380 # Then this cannot be Band 1 or EVLA data. But I should really check the telescope name!
3381 if (refFreq[myspw]*1e-9 > np.mean(chanFreqGHz2[ispw])): # this is safer (since frequencies might be [])
3382 sideband = -1
3383 xlabelString = "%s LSB Frequency (GHz) (%d, %d channels)" % (refTypeToString(measFreqRef[myspw]),maxChannels[myspw],maxChannels2[myspw])
3384 else:
3385 sideband = +1
3386 xlabelString = "%s USB Frequency (GHz) (%d, %d channels)" % (refTypeToString(measFreqRef[myspw]),maxChannels[myspw],maxChannels2[myspw])
3387 else:
3388 sideband = -1
3389 xlabelString = "Frequency (GHz) (%d, %d channels)" % (maxChannels[myspw],maxChannels2[myspw])
3390 # endif bOverlay
3392 if (matchFound==False):
3393 if ((overlayAntennas==False and overlaySpws==False and overlayBasebands==False) or
3394 (overlayAntennas and xctr+1 >= len(antennasToPlot)) or
3395 ((overlaySpws or overlayBasebands) and spwctr+1 >= len(spwsToPlot))):
3396 mytime += 1
3397 if (debug):
3398 print("a) xctr=%d, Incrementing mytime to %d" % (xctr, mytime))
3399 if overlayAntennas and xctr+1 == len(antennasToPlot): # second fix for CAS-13568
3400 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)
3401 if ((showatm or showtsky) and len(atmString) > 0):
3402 DrawAtmosphere(showatm, showtsky, subplotRows, atmString,
3403 mysize, TebbSky, plotrange, xaxis, atmchan,
3404 atmfreq, transmission, subplotCols,
3405 showatmPoints=showatmPoints, xframe=xframe,
3406 channels=channels,mylineno=lineNumber(),
3407 overlaySpws=overlaySpws,
3408 overlayBasebands=overlayBasebands,
3409 drewAtmosphere=drewAtmosphere,loc=203,
3410 showtsys=showtsys, Trx=Trx)
3411 if (LO1):
3412 # Now draw the image band
3413 DrawAtmosphere(showatm,showtsky, subplotRows, atmString,
3414 mysize, TebbSkyImage, plotrange, xaxis,
3415 atmchanImage, atmfreqImage, transmissionImage,
3416 subplotCols, LO1, xframe, firstFrame, showatmPoints,
3417 channels=channels,mylineno=lineNumber(),
3418 overlaySpws=overlaySpws,
3419 overlayBasebands=overlayBasebands,
3420 drewAtmosphere=drewAtmosphere,loc=204,
3421 showtsys=showtsys, Trx=Trx)
3422 drewAtmosphere = True
3424 continue
3425 # The following variable allows color legend of UT times to match line plot
3426 myUniqueTime = []
3427 if (True): # multiFieldsWithOverlayTime):
3428 # support multi-fields with overlay='time'
3429 uTPFPS = []
3430 for f in fieldIndicesToPlot:
3431 for t in uniqueTimesPerFieldPerSpw[ispwInCalTable][f]:
3432 if tableFormat >= 34: ### added 2024Aug
3433 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
3434 else: ### added 2024Aug
3435 scansToPlotHere = scansToPlot ### added 2024Aug
3436 if (sloppyMatch(t, timerangeListTimes, solutionTimeThresholdSeconds,
3437 mytime, scansToPlotHere, scansForUniqueTimes, # au version ### modified 2024Aug
3438 myprint=debugSloppyMatch
3439 )):
3440 uTPFPS.append(t)
3441 uTPFPS = np.sort(uTPFPS)
3442 ctr = 0
3443 for t in uTPFPS:
3444 if (debug and False):
3445 print("1)checking time %d" % (t))
3446 if (overlayTimes or overlayAntennas):
3447 sm = sloppyMatch(uniqueTimes[mytime],times[i],solutionTimeThresholdSeconds,myprint=False)
3448 else:
3449 if tableFormat >= 34: ### added 2024Aug
3450 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
3451 else: ### added 2024Aug
3452 scansToPlotHere = scansToPlot ### added 2024Aug
3453 sm = sloppyMatch(t, uniqueTimes[mytime], solutionTimeThresholdSeconds,
3454 mytime, scansToPlotHere, scansForUniqueTimes, # au version ### modified 2024Aug
3455 myprint=debugSloppyMatch
3456 )
3457 if (sm):
3458 if (debug):
3459 print("1)setting myUniqueTime to %d" % (mytime))
3460 myUniqueTime = mytime
3461 ctr += 1
3462 if (ctr > len(fieldIndicesToPlot) and bOverlay==False):
3463 if (debug): print("multi-field time overlay *************** why are there 2 matches?")
3464# # # # if (ctr == 0):
3465# # # # print("No match for %.1f in "%(t), uTPFPS)
3467# # # # print("Overlay antenna %d, myUniqueTime=%d" % (xctr, myUniqueTime))
3468 if (xframe == xframeStart):
3469 safe_pb_clf()
3470 xflag = [item for sublist in xflag for item in sublist]
3471 yflag = [item for sublist in yflag for item in sublist]
3472# # pflag = [xflag, yflag]
3473# # flagfrequencies = [frequencies, frequencies2]
3474 antstring, Antstring = buildAntString(xant,msFound,msAnt)
3475 if (msFound):
3476 fieldString = msFields[uniqueFields[fieldIndex]]
3477 else:
3478 fieldString = str(field)
3479 if (overlayTimes):
3480 timeString =''
3481 else:
3482 timeString = ', t%d/%d %s' % (mytime,nUniqueTimes-1,utstring(uniqueTimes[mytime],3))
3483 if (scansForUniqueTimes != []):
3484 if (scansForUniqueTimes[mytime]>=0):
3485 timeString = ', scan%d %s' % (scansForUniqueTimes[mytime],utstring(uniqueTimes[mytime],3))
3486 spwString = buildSpwString(overlaySpws, overlayBasebands, spwsToPlot,
3487 ispw, originalSpw[ispw], observatoryName,
3488 baseband, showBasebandNumber)
3489 titleString = "%sspw%s, field %d: %s%s" % (antennaString,spwString,uniqueFields[fieldIndex],fieldString,timeString)
3490 if (sum(xflag)==nChannels and sum(yflag)==nChannels and showflagged==False):
3491 if (overlayTimes):
3492 msg = "Skip %s (%s) for time%d=%s all data flagged" % (antstring, titleString,mytime,utstring(uniqueTimes[mytime],3))
3493 casalogPost(True, msg)
3494 # need to set doneOverlayTime = True if this is the final time,
3495 # otherwise, we get "subplot number exceeds total subplots" at line 2427
3496 # but we need to draw the labels at the top of the page, else they will not get done
3497 if (debug):
3498 print("########## uniqueTimes[%d]=%d, timerangeListTimes[-1]=%d" % (mytime,uniqueTimes[mytime],timerangeListTimes[-1]))
3499 if (len(scansToPlotPerSpw[ispw]) < 1):
3500 sTPPS = []
3501 else:
3502# sTPPS = [scansToPlot[-1]]# added [[-1]] on 2014-04-04 for CAS-6394 task version
3503 sTPPS = [scansToPlotPerSpw[ispw][-1]]# added [[-1]] on 2014-04-04 for CAS-6394 au version
3504 if (sloppyMatch(timerangeListTimes[-1], uniqueTimes[mytime],
3505 solutionTimeThresholdSeconds,
3506 mytime, sTPPS, scansForUniqueTimes,
3507 myprint=debugSloppyMatch
3508 )):
3509 if (overlayAntennas == False or xant==antennasToPlot[-1]): # 11-Mar-2014
3510 doneOverlayTime = True # 08-Nov-2012
3511 finalTimerangeFlagged = True # 04-Aug-2014
3512 if (debug):
3513 print("###### set doneOverlayTime = %s" % (str(doneOverlayTime)))
3515 # draw labels
3516 # try adding the following 'if' statement on Jun 18, 2013; it works.
3517# if (drewAtmosphere==False or overlayAntennas==False):
3518 # Add the 'and not' case to prevent extra atm/fdms shown if one spw's solutions are all flagged
3519 if (drewAtmosphere==False or (not overlayAntennas and not allTimesFlaggedOnThisSpw)):
3520 if (debug): print("drawOverlayTimeLegends loc 1")
3521 drawOverlayTimeLegends(xframe, firstFrame, xstartTitle, ystartTitle,
3522 caltable, titlesize, fieldIndicesToPlot,
3523 ispwInCalTable, uniqueTimesPerFieldPerSpw,
3524 timerangeListTimes,
3525 solutionTimeThresholdSeconds,
3526 debugSloppyMatch,
3527 ystartOverlayLegend, debug, mysize,
3528 fieldsToPlot, myUniqueColor,
3529 timeHorizontalSpacing, fieldIndex,
3530 overlayColors,
3531 antennaVerticalSpacing, overlayAntennas,
3532 timerangeList, caltableTitle, mytime,
3533 scansToPlotPerSpw[ispw], scansForUniqueTimes,
3534 uniqueSpwsInCalTable, uniqueTimes)
3535 if not LO1 and type(lo1s) == dict: # Fix for SCOPS-4877
3536 LO1 = lo1s[myspw] # Fix for SCOPS-4877
3537 # CAS-8655
3538 newylimits = drawAtmosphereAndFDM(showatm,showtsky,atmString,subplotRows,mysize,
3539 TebbSky,TebbSkyImage,plotrange, xaxis,atmchan,
3540 atmfreq,transmission,subplotCols,showatmPoints,
3541 xframe, channels,LO1,atmchanImage,atmfreqImage,
3542 transmissionImage, firstFrame,showfdm,nChannels,
3543 tableFormat,originalSpw_casa33,
3544 chanFreqGHz_casa33,originalSpw,chanFreqGHz,
3545 overlayTimes, overlayAntennas, xant,
3546 antennasToPlot, overlaySpws, baseband,
3547 showBasebandNumber, basebandDict,
3548 overlayBasebands, overlayColors, drewAtmosphere, showtsys)
3549 drewAtmosphere = True
3550 if (xctr == firstUnflaggedAntennaToPlot or overlayAntennas==False): # changed xant->xctr on 11-mar-2014
3551 DrawPolarizationLabelsForOverlayTime(xstartPolLabel,ystartPolLabel,corr_type,polsToPlot,
3552 channeldiff,ystartMadLabel,subplotRows,gamp_mad,mysize,
3553 ampmarkstyle,markersize,ampmarkstyle2,gamp_std)
3554 else: # not overlaying times
3555 msg = "Skip %s spw%d (%s) all data flagged" % (antstring, ispw, titleString)
3556 casalogPost(True, msg)
3557 if ((overlaySpws or overlayBasebands) and spwctr==spwctrFirstToPlot):
3558 spwctrFirstToPlot += 1
3559 if ((overlaySpws or overlayBasebands) and ispw==spwsToPlotInBaseband[bbctr][-1]):
3560 if (debug): print("The final spw was flagged!!!!!!!!!!!!!!")
3561 finalSpwWasFlagged = True # inserted on 22-Apr-2014 for g25.27
3562 if (myinput == 'b'):
3563 redisplay = False # This prevents infinite loop when htting 'b' on first screen when ant0 flagged. 2013-03-08
3564 if (overlayAntennas==False and overlayBasebands==False): # 07/30/2014 added overlayBasebands==False
3565 if (doneOverlayTime==False or overlayTimes==False): # added on 08-Nov-2012
3566 finalSpwWasFlagged = False # Added on 23-Apr-2014 for regression61
3567 mytime += 1
3568 if (debug):
3569 print("F) all solutions flagged --> incrementing mytime to %d" % mytime)
3570 if (overlayAntennas):
3571 if (xctr == firstUnflaggedAntennaToPlot):
3572 firstUnflaggedAntennaToPlot += 1
3573 if (firstUnflaggedAntennaToPlot >= len(antennasToPlot)):
3574 firstUnflaggedAntennaToPlot = 0
3575 if not finalSpwWasFlagged: # Added on 23-Apr-2014 for regression61
3576 mytime += 1
3577 if (debug):
3578 print("----- Resetting firstUnflaggedAntennaToPlot from %d to %d = %d" % (firstUnflaggedAntennaToPlot-1, firstUnflaggedAntennaToPlot, antennasToPlot[firstUnflaggedAntennaToPlot]))
3579 if (mytime < nUniqueTimes): # Add this 'if' conditional on 9-22-2015 for CAS-7839
3580 continue # Try adding this statement on Apr 2, 2012 to fix bug.
3581 mytime -= 1 # Add this on 9-22-2015 for CAS-7839
3582 if (overlaySpws or overlayBasebands):
3583 if (xctr == firstUnflaggedAntennaToPlot):
3584 firstUnflaggedAntennaToPlot += 1
3585 if (firstUnflaggedAntennaToPlot >= len(antennasToPlot)):
3586 firstUnflaggedAntennaToPlot = 0
3587 if not finalSpwWasFlagged: # Added on 22-Apr-2014 for g25.27 dataset antenna='4'
3588 if (overlayBasebands == False or spwctr>len(spwsToPlot)): # Added on 7/30/2014 for regression 96
3589 mytime += 1
3590 if (debug):
3591 print("----- Resetting firstUnflaggedAntennaToPlot from %d to %d" % (firstUnflaggedAntennaToPlot-1, firstUnflaggedAntennaToPlot))
3592 print("----- = antenna %d" % (antennasToPlot[firstUnflaggedAntennaToPlot]))
3593 if (not finalSpwWasFlagged): # add this test on Apr 22, 2014 to prevent crash on g25.27 dataset with antenna='4,5'
3594 continue # Try this 'continue' on Apr 2, 2012 to fix bug -- works.
3595 if (overlayAntennas==False and subplot==11
3596 and not finalSpwWasFlagged # inserted on 22-Apr-2014 for g25.27
3597 and not finalTimerangeFlagged): # inserted on 04-Aug-2014 for CAS-6812
3598 # added the case (subplot==11) on April 22, 2012 to prevent crash on multi-antenna subplot=421
3599 if (debug):
3600 print("####### removing [%d,%d,%d,%d]" % (pages[len(pages)-1][PAGE_ANT],
3601 pages[len(pages)-1][PAGE_SPW],
3602 pages[len(pages)-1][PAGE_TIME],
3603 pages[len(pages)-1][PAGE_AP]))
3604 pages = pages[0:len(pages)-1]
3605 newpage = 1
3606 if (overlayAntennas==False):
3607 if (doneOverlayTime==False # inserted on 08-Nov-2012
3608 and not finalSpwWasFlagged): # inserted on 22-Apr-2014 for g25.27
3609 continue
3610 elif (debug):
3611 print("=========== Not continuing because doneOverlayTime=%s" % (str(doneOverlayTime)))
3612 else:
3613 allTimesFlaggedOnThisSpw = False
3614 if (debug):
3615 print("Not all the data are flagged. doneOverlayTime=%s" % (str(doneOverlayTime)))
3617 if (firstSpwMatch == -1):
3618 firstSpwMatch = spwctr
3619 if (firstTimeMatch == -1):
3620 firstTimeMatch = mytime
3621 if (debug):
3622 print("Setting firstTimeMatch from -1 to %s" % (str(firstTimeMatch)))
3623 # The following was needed to support overlay='antenna,time' for showatm for QA2 report (CAS-7820)
3624 if (finalTimeMatch == -1 or finalTimeMatch < mytime):
3625 if (debug):
3626 print("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Setting finalTimeMatch from %d to %d" % (finalTimeMatch, mytime))
3627 finalTimeMatch = mytime
3629################### Here is the amplitude plotting ############
3630 if (yaxis.find('amp')>=0 or yaxis.find('both')>=0 or yaxis.find('ap')>=0) and doneOverlayTime==False:
3631 if (overlayBasebands and amplitudeWithPhase): # CAS-6477
3632 if (float(xframe/10) != xframe*0.1 and alreadyPlottedAmp):
3633 xframe -= 2
3635 if (debug):
3636 print("amp: xctr=%d, xant=%d, myap=%d, mytime=%d(%s), firstTimeMatch=%d, bOverlay=" % (xctr, xant, myap, mytime, utstring(uniqueTimes[mytime],3), firstTimeMatch), bOverlay)
3637 if (myap==1):
3638 if (overlayTimes == False or mytime==firstTimeMatch):
3639 if ((overlaySpws == False and overlayBasebands==False) or spwctr==spwctrFirstToPlot or spwctr>len(spwsToPlot)):
3640 if (overlayAntennas==False or xctr==firstUnflaggedAntennaToPlot
3641 or xctr==antennasToPlot[-1]): # 2012-05-24, to fix the case where all ants flagged on one timerange
3642 xframe += 1
3643 if (debug):
3644 print("y) incrementing xframe to %d" % xframe)
3645 print("mytime=%d == firstTimeMatch=%d" % (mytime, firstTimeMatch))
3646 print("xctr=%d == firstUnflaggedAntennaToPlot=%d, antennastoPlot[-1]=%d" % (xctr, firstUnflaggedAntennaToPlot,antennasToPlot[-1]))
3647 myUniqueColor = []
3648 newylimits = [LARGE_POSITIVE, LARGE_NEGATIVE]
3649 else: # (myap == 0)
3650 if (overlayTimes == False or mytime==firstTimeMatch):
3651 if ((overlaySpws == False and overlayBasebands==False) or
3652 spwctr==spwctrFirstToPlot or
3653 (overlayBasebands and amplitudeWithPhase) or # CAS-6477
3654 spwctr>len(spwsToPlot)):
3655 if (overlayAntennas==False or xctr==firstUnflaggedAntennaToPlot
3656 or xctr>antennasToPlot[-1]): # 2012-05-24, to fix the case where all ants flagged on one timerange
3657 xframe += 1
3658 if (debug):
3659 print("Y) incrementing xframe to %d" % xframe)
3660 print("mytime=%d == firstTimeMatch=%d" % (mytime, firstTimeMatch))
3661 print("xctr=%d == firstUnflaggedAntennaToPlot=%d, antennasToPlot[-1]=%d" % (xctr, firstUnflaggedAntennaToPlot,antennasToPlot[-1]))
3662 print("spwctr=%d >? len(spwsToPlot)=%d" % (spwctr, len(spwsToPlot)))
3663 myUniqueColor = []
3664 newylimits = [LARGE_POSITIVE, LARGE_NEGATIVE]
3665 if (debug):
3666 print("myap=%d, mytime == firstTimeMatch=%d" % (myap, firstTimeMatch))
3667 else:
3668 if (debug): print("4)Not incrementing xframe from %d" % (xframe))
3669 else:
3670 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))
3671 else:
3672 if (debug): print("1)Not incrementing xframe from %d" % (xframe))
3673 if (debug):
3674 print("$$$$$$$$$$$$$$$$$$$$$$$ ready to plot amp on xframe %d" % (xframe))
3675# # # # print(",,,,,,,,,,,,,,,, Starting with newylimits = ", newylimits)
3676 if (previousSubplot != xframe):
3677 adesc = safe_pb_subplot(xframe) # avoid deprecation warning in CASA6 when xframe already was opened
3678 drewAtmosphere = False
3679 previousSubplot = xframe
3680 alreadyPlottedAmp = True # needed for (overlay='baseband', yaxis='both') CAS-6477
3681 if (delay):
3682 gampx = gplotx
3683 else:
3684 gampx = np.abs(gplotx)
3685 if (nPolarizations == 2):
3686 if (delay):
3687 gampy = gploty
3688 else:
3689 gampy = np.abs(gploty)
3690 if (yaxis.lower().find('db') >= 0):
3691 gamp = [10*np.log10(gampx), 10*np.log10(gampy)]
3692 else:
3693 if (channeldiff>0):
3694 if (debug): print("Computing derivatives")
3695 if (xaxis == 'chan'):
3696 gamp0, newx0, gamp0res, newx0res = channelDifferences(gampx, pchannels[0], resample)
3697 gamp1, newx1, gamp1res, newx1res = channelDifferences(gampy, pchannels[1], resample)
3698 pchannels = [newx0, newx1]
3699 else:
3700 gamp0, newx0, gamp0res, newx0res = channelDifferences(gampx, pfrequencies[0], resample)
3701 gamp1, newx1, gamp1res, newx1res = channelDifferences(gampy, pfrequencies[1], resample)
3702 pfrequencies = [newx0, newx1]
3703 gamp = [gamp0, gamp1]
3704 gampres = [gamp0res, gamp1res]
3705 if (VisCal.lower().find('tsys') >= 0 and tsysPercent):
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 elif (VisCal.lower().find('tsys') < 0 and ampPercent):
3709 gamp = [100*gamp0/np.median(gampx), 100*gamp1/np.median(gampy)]
3710 gampres = [100*gamp0res/np.median(gampx), 100*gamp1res/np.median(gampy)]
3711 gamp_mad = [madInfo(gamp[0],madsigma,edge), madInfo(gamp[1],madsigma,edge)]
3712 gamp_std = [stdInfo(gampres[0],madsigma,edge,ispw,xant,0), stdInfo(gampres[1],madsigma,edge,ispw,xant,1)]
3713 if (debug): print("gamp_mad done")
3714 if (platformingSigma > 0):
3715 platformingThresholdX = gamp_mad[0]['mad']*platformingSigma
3716 platformingThresholdY = gamp_mad[1]['mad']*platformingSigma
3717 else:
3718 platformingThresholdX = platformingThreshold
3719 platformingThresholdY = platformingThreshold
3720 gamp_platforming = [platformingCheck(gamp[0],platformingThresholdX),
3721 platformingCheck(gamp[1],platformingThresholdY)]
3722 for p in [0,1]:
3723 if (debug):
3724 print("gamp_mad[%d] = %s" % (p, str(gamp_mad[p])))
3725 print("madstats[%s][%d] = %s" % (Antstring,ispw, str(madstats[Antstring][ispw])))
3726 madstats[Antstring][ispw][mytime][p]['amp'] = gamp_mad[p]['mad']
3727 madstats[Antstring][ispw][mytime][p]['ampstd'] = gamp_std[p]['std']
3728 if (gamp_platforming[p]):
3729 if (Antstring not in list(madstats['platforming'].keys())):
3730 madstats['platforming'][Antstring] = {}
3731 if (ispw not in list(madstats['platforming'][Antstring].keys())):
3732 madstats['platforming'][Antstring][ispw] = {}
3733 if (p not in list(madstats['platforming'][Antstring][ispw].keys())):
3734 madstats['platforming'][Antstring][ispw][p] = []
3735 madstats['platforming'][Antstring][ispw][p].append(uniqueTimes[mytime])
3736 if (gamp_mad[p]['nchan'] > 0):
3737 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]))
3738 if (debug): print("madstats done")
3739 else:
3740 gamp = [gampx,gampy]
3741 else:
3742 if (yaxis.lower().find('db') >= 0):
3743 gamp = [10*np.log10(gampx)]
3744 else:
3745 if (channeldiff>0):
3746 if (xaxis == 'chan'):
3747 gamp0, newx0, gamp0res, newx0res = channelDifferences(gampx, pchannels[0], resample)
3748 pchannels = [newx0]
3749 else:
3750 gamp0, newx0, gamp0res, newx0res = channelDifferences(gampx, pfrequencies[0], resample)
3751 pfrequencies = [newx0]
3752 gamp = [gamp0]
3753 gampres = [gamp0res]
3754 if (VisCal.lower().find('tsys') >= 0 and tsysPercent):
3755 gamp = [100*gamp0/np.median(gampx)]
3756 gampres = [100*gamp0res/np.median(gampx)]
3757 elif (VisCal.lower().find('tsys') < 0 and ampPercent):
3758 gamp = [100*gamp0/np.median(gampx)]
3759 gampres = [100*gamp0res/np.median(gampx)]
3760 p = 0
3761 gamp_mad = [madInfo(gamp[p], madsigma,edge)]
3762 gamp_std = [stdInfo(gampres[p], madsigma,edge,ispw,xant,p)]
3763 if (platformingSigma > 0):
3764 platformingThresholdX = gamp_mad[0]['mad']*platformingSigma
3765 else:
3766 platformingThresholdX = platformingThreshold
3767 gamp_platforming = [platformingCheck(gamp[p], platformingThresholdX)]
3768 madstats[Antstring][ispw][mytime][p]['amp'] = gamp_mad[p]['mad']
3769 madstats[Antstring][ispw][mytime][p]['ampstd'] = gamp_std[p]['std']
3770 if (gamp_platforming[p]):
3771 if (Antstring not in list(madstats['platforming'].keys())):
3772 madstats['platforming'][Antstring] = {}
3773 if (ispw not in list(madstats['platforming'][Antstring].keys())):
3774 madstats['platforming'][Antstring][ispw] = {}
3775 if (p not in list(madstats['platforming'][Antstring][ispw].keys())):
3776 madstats['platforming'][Antstring][ispw][p] = []
3777 madstats['platforming'][Antstring][ispw][p].append(mytime)
3778 if (gamp_mad[p]['nchan'] > 0):
3779 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]))
3780 else:
3781 gamp = [gampx]
3782 if (bOverlay):
3783 gampx2 = np.abs(gplotx2)
3784 if (nPolarizations2 == 2):
3785 gampy2 = np.abs(gploty2)
3786 if (yaxis.lower().find('db') >= 0):
3787 gamp2 = [10*np.log10(gampx2), 10*np.log10(gampy2)]
3788 else:
3789 if (channeldiff>0):
3790 if (xaxis == 'chan'):
3791 gamp2_0, newx0, gamp2_0res, newx0res = channelDifferences(gampx2, pchannels2[0], resample)
3792 gamp2_1, newx1, gamp2_1res, newx1res = channelDifferences(gampy2, pchannels2[1], resample)
3793 pchannels2 = [newx0, newx1]
3794 else:
3795 gamp2_0, newx0, gamp2_0res, newx0res = channelDifferences(gampx2, pfrequencies2[0], resample)
3796 gamp2_1, newx1, gamp2_1res, newx1res = channelDifferences(gampy2, pfrequencies2[1], resample)
3797 pfrequencies2 = [newx0, newx1]
3798 gamp2 = [gamp2_0, gamp2_1]
3799 gamp2res = [gamp2_0res, gamp2_1res]
3800 if (VisCal.lower().find('tsys') >= 0 and tsysPercent):
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 elif (VisCal.lower().find('tsys') < 0 and ampPercent):
3804 gamp2 = [100*gamp2_0/np.median(gampx2), 100*gamp2_1/np.median(gampy2)]
3805 gamp2res = [100*gamp2_0res/np.median(gampx2), 100*gamp2_1res/np.median(gampy2)]
3806 else:
3807 gamp2 = [gampx2, gampy2]
3808 else:
3809 if (yaxis.lower().find('db') >= 0):
3810 gamp2 = [10*np.log10(gampx2)]
3811 else:
3812 if (channeldiff>0):
3813 if (xaxis == 'chan'):
3814 gamp2_0, newx0, gamp2_0res, newx0res = channelDifferences(gampx2, pchannels[0], resample)
3815 pchannels2 = [newx0]
3816 else:
3817 gamp2_0, newx0, gamp2_0res, newx0res = channelDifferences(gampx2, pfrequencies[0], resample)
3818 pfrequencies2 = [newx0]
3819 gamp2 = [gamp2_0]
3820 gamp2res = [gamp2_0res]
3821 if (VisCal.lower().find('tsys') >= 0 and tsysPercent):
3822 gamp2 = [100*gamp2_0/np.median(gampx2)]
3823 gamp2res = [100*gamp2_0res/np.median(gampx2)]
3824 elif (VisCal.lower().find('tsys') < 0 and ampPercent):
3825 gamp2 = [100*gamp2_0/np.median(gampx2)]
3826 gamp2res = [100*gamp2_0res/np.median(gampx2)]
3827 else:
3828 gamp2 = [gampx2]
3829 if (xaxis.find('chan')>=0 or (msFound==False and tableFormat==33)): # 'amp'
3830 if (debug):
3831 print("amp: plot vs. channel **********************")
3832 for p in range(nPolarizations):
3833 if (overlayAntennas or overlayTimes):
3834 if (corr_type_string[p] in polsToPlot):
3835 pdesc = pb.plot(pchannels[p],gamp[p],'%s'%ampmarkstyles[p],
3836 markersize=markersize,
3837 markerfacecolor=overlayColors[xctr],markeredgewidth=markeredgewidth)
3838 newylimits = recalcYlimits(plotrange,newylimits,gamp[p])
3839 if (overlayAntennas and overlayTimes==False):
3840 pb.setp(pdesc, color=overlayColors[xctr])
3841 elif (overlayTimes and overlayAntennas==False):
3842 pb.setp(pdesc, color=overlayColors[mytime])
3843 elif (overlayTimes and overlayAntennas): # try to support time,antenna
3844 if (debug):
3845 print("p=%d, len(fieldsToPlot)=%d, len(timerangeList)=%d" % (p,len(fieldsToPlot),len(timerangeList)))
3846 if (len(fieldsToPlot) > 1 or len(timerangeList)>1):
3847 # The third 'or' below is needed if pol='0' is flagged on antenna 0. -- 2012/10/12
3848 if (p==0 or len(polsToPlot)==1 or myUniqueColor==[]):
3849 myUniqueColor.append(overlayColors[len(myUniqueColor)])
3850 pb.setp(pdesc, color=myUniqueColor[-1])
3851 else:
3852 if (corr_type_string[p] in polsToPlot):
3853# # # # print("pcolor[%d]=%s" % (p,pcolor))
3854 pb.plot(pchannels[p],gamp[p],'%s%s'%(pcolor[p],ampmarkstyle), markersize=markersize,markeredgewidth=markeredgewidth)
3855 newylimits = recalcYlimits(plotrange,newylimits,gamp[p])
3856 if (sum(xflag)>0):
3857 myxrange = np.max(channels)-np.min(channels)
3858 SetNewXLimits([np.min(channels)-myxrange/20, np.max(channels)+myxrange/20],1)
3859# # # # print("amp: Resetting xaxis channel range to counteract flagged data")
3860 if (xframe in bottomRowFrames or (xctr+1==len(antennasToPlot) and ispw==spwsToPlot[-1])):
3861 pb.xlabel("Channels (%d)" % (len(pchannels[p])), size=mysize) ### changed 2024Aug24
3862 elif (xaxis.find('freq')>=0): # amp
3863 if (bOverlay):
3864 myxrange = np.abs(xfrequencies[0]-xfrequencies[-1])
3865 try:
3866 xrange2 = np.abs(xfrequencies2[0]-xfrequencies2[-1])
3867 except:
3868 print("No amp data found in second solution. Try increasing the solutionTimeThresholdSeconds above %.0f." % (solutionTimeThresholdSeconds))
3869 print("If this doesn't work, email the developer (%s)." % (developerEmail))
3870 return()
3872 if (np.abs(myxrange/xrange2 - 1) > 0.05 + len(xflag)//len(xchannels)): # 0.0666 is 2000/1875-1
3873 # These line widths are optimal for visualizing FDM over TDM
3874 width1 = 1
3875 width2 = 4
3876 # solutions differ in frequency width
3877 if (myxrange < xrange2):
3878 for p in range(nPolarizations):
3879 if (corrTypeToString(corr_type[p]) in polsToPlot):
3880 pb.plot(pfrequencies[p], gamp[p], '%s%s'%(pcolor[p],ampmarkstyle), linewidth=width2, markersize=markersize,markeredgewidth=markeredgewidth)
3881 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
3882 for p in range(nPolarizations):
3883 if (corrTypeToString(corr_type[p]) in polsToPlot):
3884 pb.plot(pfrequencies2[p], gamp2[p], '%s%s'%(p2color[p],ampmarkstyle), linewidth=width1, markersize=markersize,markeredgewidth=markeredgewidth)
3885 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp2[p], sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
3886 else:
3887 for p in range(nPolarizations):
3888 if (corrTypeToString(corr_type[p]) in polsToPlot):
3889 pb.plot(pfrequencies2[p], gamp2[p], '%s%s'%(p2color[p],ampmarkstyle), linewidth=width2, markersize=markersize,markeredgewidth=markeredgewidth)
3890 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp2[p], sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
3891 for p in range(nPolarizations):
3892 if (corrTypeToString(corr_type[p]) in polsToPlot):
3893 pb.plot(pfrequencies[p], gamp[p], '%s%s'%(pcolor[p],ampmarkstyle), linewidth=width1, markersize=markersize,markeredgewidth=markeredgewidth)
3894 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
3895 else:
3896 width1 = 1
3897 width2 = 2 # Just enough to distinguish one line from the other.
3898 # solutions may be different level of smoothing, so plot highest rms first
3899 if madOfDiff(gamp[0]) < madOfDiff(gamp2[0]): # and firstPlot != 1): # only au version has this parameter
3900# if (MAD(gamp[0]) < MAD(gamp2[0])):
3901 for p in range(nPolarizations):
3902 if (corrTypeToString(corr_type[p]) in polsToPlot):
3903 pb.plot(pfrequencies2[p], gamp2[p], '%s%s'%(p2color[p],ampmarkstyle), linewidth=width1, markersize=markersize,markeredgewidth=markeredgewidth)
3904 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp2[p], sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
3905 for p in range(nPolarizations):
3906 if (corrTypeToString(corr_type[p]) in polsToPlot):
3907 pb.plot(pfrequencies[p], gamp[p], '%s%s'%(pcolor[p],ampmarkstyle), linewidth=width2, markersize=markersize,markeredgewidth=markeredgewidth)
3908 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
3909 else:
3910 # plot first solution first
3911 for p in range(nPolarizations):
3912 if (corrTypeToString(corr_type[p]) in polsToPlot):
3913 pb.plot(pfrequencies[p], gamp[p], '%s%s'%(pcolor[p],ampmarkstyle), linewidth=width2, markersize=markersize,markeredgewidth=markeredgewidth)
3914 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
3915 for p in range(nPolarizations):
3916 if (corrTypeToString(corr_type[p]) in polsToPlot):
3917 pb.plot(pfrequencies2[p], gamp2[p], '%s%s'%(p2color[p],ampmarkstyle), linewidth=width1, markersize=markersize,markeredgewidth=markeredgewidth)
3918 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp2[p], sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
3919 # must set new limits after plotting 'amp'
3920 if (zoom=='intersect'):
3921 if (myxrange < xrange2):
3922 SetNewXLimits([min(xfrequencies[0],xfrequencies[-1])-myxrange*0.1, max(xfrequencies[0],xfrequencies[-1])+myxrange*0.1],2)
3923 SetLimits(plotrange, chanrange, newylimits, channels, frequencies,
3924 pfrequencies, ampMin, ampMax, xaxis, pxl, chanrangeSetXrange,
3925 chanrangePercent)
3926 else:
3927# # # # print("len(xfrequencies2) = ", len(xfrequencies2))
3928 SetNewXLimits([min(xfrequencies2[0],xfrequencies2[-1])-xrange2*0.1, max(xfrequencies2[0],xfrequencies2[-1])+xrange2*0.1],3)
3929 slstatus = SetLimits(plotrange, chanrange, newylimits, channels, frequencies2,
3930 pfrequencies2, ampMin, ampMax, xaxis, pxl, chanrangeSetXrange,
3931 chanrangePercent)
3932 else:
3933 if (myxrange < xrange2):
3934 SetLimits(plotrange, chanrange, newylimits, channels, frequencies,
3935 pfrequencies, ampMin, ampMax, xaxis, pxl, chanrangeSetXrange,
3936 chanrangePercent)
3937 else:
3938 SetLimits(plotrange, chanrange, newylimits, channels, frequencies2,
3939 pfrequencies2, ampMin, ampMax, xaxis, pxl, chanrangeSetXrange,
3940 chanrangePercent)
3941 # draw polarization and spw labels
3942 if (xframe == firstFrame):
3943 # draw title including caltable name
3944 caltableList = 'c1=' + caltable + ', c2=' + caltable2 # + ' (%s)'%(utstring(uniqueTimes2[mytime],3))
3945 pb.text(xstartTitle, ystartTitle, caltableList, size=titlesize,
3946 color='k', transform=pb.gcf().transFigure)
3947 elif (bpolyOverlay):
3948 if (debug):
3949 print("in bpolyOverlay **********************************")
3950 matches1 = []
3951 if tableFormat >= 34: ### added 2024Aug
3952 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
3953 else: ### added 2024Aug
3954 scansToPlotHere = scansToPlot ### added 2024Aug
3955 for tbp in range(len(timesBP)):
3956 if (sloppyMatch(uniqueTimes[mytime], timesBP[tbp], solutionTimeThresholdSeconds,
3957 mytime, scansToPlotHere, scansForUniqueTimes, # au version ### modified 2024Aug
3958 myprint=debugSloppyMatch
3959 )):
3960 matches1.append(tbp)
3961 matches1 = np.array(matches1)
3962 if (len(matches1) < 1):
3963 print("No time match found between %.1f and %s" % (uniqueTimes[mytime], str(timesBP)))
3964 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]))))
3965 return()
3966 matches2 = np.where(xant == np.array(antennasBP))[0]
3967 if (len(matches2) < 1):
3968 print("No antenna match found: %s" % (str(xant), str(antennasBP)))
3969 if (tableFormat == 33):
3970 matches3 = np.where(ispw == np.array(cal_desc_idBP))[0]
3971 if (len(matches3) < 1):
3972 print("No spw match found: %d not in %s" % (ispw, str(cal_desc_idBP)))
3973 else:
3974 matches3 = np.where(ispw == np.array(spwBP))[0]
3975 if (len(matches3) < 1):
3976 print("No spw match found: %d not in %s" % (ispw, str(spwBP)))
3977 matches12 = np.intersect1d(matches1,matches2)
3978 if (len(matches12) < 1):
3979 print("No time+antenna match between: %s and %s" % (str(matches1), str(matches2)))
3980 matches = np.intersect1d(matches12, matches3)
3981 if (len(matches) < 1):
3982 print("No time+antenna+spw match between: %s and %s" % (str(matches12), str(matches3)))
3983 try:
3984 index = matches[0]
3985 if (debug):
3986 print("Match = %d ***********************************" % (index))
3987 except:
3988 print("No match found for time=%.6f, xant=%d, ispw=%d" % (uniqueTimes[mytime],xant,ispw))
3989 print("antennasBP = %s" % (str(antennasBP)))
3990 print("cal_desc_idBP = %s" % (str(cal_desc_idBP)))
3991 timesBPstring = 'timesBP = '
3992 for i in timesBP:
3993 timesBPstring += "%.6f, " % i
3994 print(timesBPstring)
3995 return()
3996 validDomain = [frequencyLimits[0,index], frequencyLimits[1,index]]
3997 cc = calcChebyshev(polynomialAmplitude[index][0:nPolyAmp[index]], validDomain, frequenciesGHz[index]*1e+9)
3998 if (debug): print("Done calcChebyshev 1")
3999 fa = np.array(frequenciesGHz[index])
4000 if (xfrequencies[0] < xfrequencies[-1]):
4001 matches = np.where(fa>xfrequencies[0])[0]
4002 matches2 = np.where(fa<xfrequencies[-1])[0]
4003 else:
4004 matches = np.where(fa>xfrequencies[-1])[0]
4005 matches2 = np.where(fa<xfrequencies[0])[0]
4006 if (len(matches) < 1):
4007 print("looking for %f-%f GHz inside %f-%f" % (xfrequencies[0],xfrequencies[-1],fa[0],fa[-1]))
4008 amplitudeSolutionX = np.mean(gampx)*(cc-np.mean(cc)+1)
4010 cc = calcChebyshev(polynomialAmplitude[index][nPolyAmp[index]:2*nPolyAmp[index]], validDomain, frequenciesGHz[index]*1e+9)
4011 if (debug): print("Done calcChebyshev 2")
4012 if (nPolarizations > 1):
4013 if (yfrequencies[0] < yfrequencies[-1]):
4014 matches = np.where(fa>yfrequencies[0])[0]
4015 matches2 = np.where(fa<yfrequencies[-1])[0]
4016 else:
4017 matches = np.where(fa>yfrequencies[-1])[0]
4018 matches2 = np.where(fa<yfrequencies[0])[0]
4019 amplitudeSolutionY = np.mean(gampy)*(cc-np.mean(cc)+1)
4020 if (bpolyOverlay2):
4021 validDomain = [frequencyLimits2[0,index], frequencyLimits2[1,index]]
4022 cc = calcChebyshev(polynomialAmplitude2[index][0:nPolyAmp2[index]],
4023 validDomain, frequenciesGHz2[index]*1e+9)
4024 if (debug): print("Done calcChebyshev 3")
4025 fa = np.array(frequenciesGHz2[index])
4026 if (xfrequencies[0] < xfrequencies[-1]):
4027 matches = np.where(fa>xfrequencies[0])[0]
4028 matches2 = np.where(fa<xfrequencies[-1])[0]
4029 else:
4030 matches = np.where(fa>xfrequencies[-1])[0]
4031 matches2 = np.where(fa<xfrequencies[0])[0]
4032 amplitudeSolution2X = np.mean(gampx)*(cc-np.mean(cc)+1)
4034 cc = calcChebyshev(polynomialAmplitude2[index][nPolyAmp2[index]:2*nPolyAmp2[index]],
4035 validDomain, frequenciesGHz2[index]*1e+9)
4036 if (debug): print("Done calcChebyshev 4")
4037 fa = np.array(frequenciesGHz2[index])
4038 if (yfrequencies[0] < yfrequencies[-1]):
4039 matches = np.where(fa>yfrequencies[0])[0]
4040 matches2 = np.where(fa<yfrequencies[-1])[0]
4041 else:
4042 matches = np.where(fa>yfrequencies[-1])[0]
4043 matches2 = np.where(fa<yfrequencies[0])[0]
4044 amplitudeSolution2Y = np.mean(gampy)*(cc-np.mean(cc)+1)
4045 if (debug):
4046 print("Done mean(gampy)")
4047 for p in range(nPolarizations):
4048 if (corrTypeToString(corr_type[p]) in polsToPlot):
4049 pb.plot(pfrequencies[p], gamp[p],'%s%s'%(pcolor[p],ampmarkstyle), markersize=markersize,markeredgewidth=markeredgewidth)
4050 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4051 if (debug): print("Done newylimits")
4052 if (corrTypeToString(corr_type[0]) in polsToPlot):
4053 pb.plot(frequenciesGHz[index], amplitudeSolutionX,'%s%s'%(p2color[0],bpolymarkstyle),markeredgewidth=markeredgewidth)
4054 newylimits = recalcYlimitsFreq(chanrange, newylimits, amplitudeSolutionX, sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4055 pb.plot(frequenciesGHz2[index], amplitudeSolution2X, '%s%s'%(p3color[0],bpolymarkstyle),markeredgewidth=markeredgewidth)
4056 newylimits = recalcYlimitsFreq(chanrange, newylimits, amplitudeSolution2X, sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
4057 if (debug): print("Done newylimits2,3")
4058 if (nPolarizations == 2):
4059 if (debug): print("dualpol")
4060 if (corrTypeToString(corr_type[1]) in polsToPlot):
4061 pb.plot(frequenciesGHz[index], amplitudeSolutionY,'%s%s'%(p2color[1],bpolymarkstyle),markeredgewidth=markeredgewidth)
4062 if (debug): print("A")
4063 newylimits = recalcYlimitsFreq(chanrange, newylimits, amplitudeSolutionY, sideband,plotrange,ychannels,debug,12,chanrangePercent=chanrangePercent)
4064 if (debug): print("B")
4065 pb.plot(frequenciesGHz2[index], amplitudeSolution2Y, '%s%s'%(p3color[1],bpolymarkstyle),markeredgewidth=markeredgewidth)
4066 if (debug): print("C")
4067 newylimits = recalcYlimitsFreq(chanrange, newylimits, amplitudeSolution2Y, sideband,plotrange,ychannels2,debug,13,chanrangePercent=chanrangePercent)
4068 if (debug): print("Done this block")
4069 else:
4070 for p in range(nPolarizations):
4071 if (corrTypeToString(corr_type[p]) in polsToPlot):
4072 pb.plot(pfrequencies[p], gamp[p],'%s%s'%(pcolor[p],ampmarkstyle), markersize=markersize,markeredgewidth=markeredgewidth)
4073 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4074 if (corrTypeToString(corr_type[0]) in polsToPlot):
4075 pb.plot(frequenciesGHz[index], amplitudeSolutionX,'%s%s'%(p2color[0],bpolymarkstyle),markeredgewidth=markeredgewidth)
4076 newylimits = recalcYlimitsFreq(chanrange, newylimits, amplitudeSolutionX, sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4077 if (nPolarizations == 2):
4078 if (corrTypeToString(corr_type[1]) in polsToPlot):
4079 pb.plot(frequenciesGHz[index], amplitudeSolutionY,'%s%s'%(p2color[1],bpolymarkstyle),markeredgewidth=markeredgewidth)
4080 newylimits = recalcYlimitsFreq(chanrange, newylimits, amplitudeSolutionY, sideband,plotrange,ychannels,chanrangePercent=chanrangePercent)
4081 # endif (bpolyOverlay2)
4082 else:
4083 # we are not overlaying any B or polynomial solutions 'amp vs. freq'
4084 if (showflagged):
4085 # Also show the flagged data to see where the flags are
4086 for p in range(nPolarizations):
4087 if (corrTypeToString(corr_type[p]) in polsToPlot):
4088 if (overlayAntennas or overlayTimes):
4089 pdesc1 = pb.plot(pfrequencies[p], gamp[p], '%s'%ampmarkstyles[p], markersize=markersize,markeredgewidth=markeredgewidth)
4090 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4091 if (overlayAntennas and overlayTimes==False):
4092 pb.setp(pdesc1, color=overlayColors[xctr])
4093 elif (overlayTimes and overlayAntennas==False):
4094 pb.setp(pdesc1, color=overlayColors[mytime])
4095 elif (overlayTimes and overlayAntennas): # try to support antenna,time
4096 if (myUniqueTime != []):
4097 pb.setp(pdesc1, color=overlayColors[myUniqueTime])
4098 # The third 'or' below is needed if pol='0' is flagged on antenna 0. -- 2012/10/12 (original spot)
4099 if (p==0 or len(polsToPlot)==1 or myUniqueColor==[]):
4100 myUniqueColor.append(overlayColors[len(myUniqueColor)])
4101 pb.setp(pdesc1, color=myUniqueColor[-1])
4102 else:
4103 pb.plot(pfrequencies[p], gamp[p], '%s%s'%(pcolor[p],ampmarkstyles[p]), markersize=markersize,markeredgewidth=markeredgewidth)
4104 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4105 else: # showing only unflagged data 'amp vs. freq'
4106 for p in range(nPolarizations):
4107 if (debug):
4108 print("*p=%d, polsToPlot=%s, len(fieldsToPlot)=%d, len(timerangeList)=%d, myUniqueTime=%s" % (p,str(polsToPlot),len(fieldsToPlot),len(timerangeList), str(myUniqueTime)))
4109 if (corrTypeToString(corr_type[p]) in polsToPlot):
4110 if (len(gamp[p]) == 0): # Try this on Apr 2, 2012
4111# # # # print("=============== Skipping flagged data on antenna %d = %s" % (xant,antstring))
4112 continue
4113 if (overlayAntennas or overlayTimes):
4114 pdesc = pb.plot(pfrequencies[p], gamp[p], '%s'%ampmarkstyles[p], markersize=markersize,markeredgewidth=markeredgewidth)
4115 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4116 if (overlayAntennas and overlayTimes==False):
4117 pb.setp(pdesc, color=overlayColors[xctr])
4118 elif (overlayTimes and overlayAntennas==False):
4119 pb.setp(pdesc, color=overlayColors[mytime])
4120 elif (overlayTimes and overlayAntennas): # try to support antenna,time
4121 if (myUniqueTime != []):
4122 pb.setp(pdesc, color=overlayColors[myUniqueTime])
4123 # The third 'or' below is needed if pol='0' is flagged on antenna 0. -- 2012/10/12 (original spot)
4124 if (p==0 or len(polsToPlot)==1 or myUniqueColor==[]):
4125 myUniqueColor.append(overlayColors[len(myUniqueColor)])
4126 if (debug):
4127 print("myUniqueColor = %s" % (str(myUniqueColor)))
4128 pb.setp(pdesc, color=myUniqueColor[-1])
4129 elif (overlaySpws): # this elif block was missing prior to 2024Aug28
4130 mycolor = [xcolor,ycolor][p]
4131 linewidth = 1
4132 pdesc = pb.plot(pfrequencies[p], gamp[p], '%s'%(ampmarkstyles[0]), lw=linewidth, color=mycolor,
4133 markersize=markersize,markeredgewidth=markeredgewidth)
4134 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,
4135 plotrange,xchannels,debug,-18,chanrangePercent)
4136 else: # show unflagged solutions, no overlay
4137 if (corrTypeToString(corr_type[p]) in polsToPlot):
4138 # since there is no overlay, don't use dashed line, so zero ------v
4139 pdesc = pb.plot(pfrequencies[p], gamp[p], '%s%s'%(pcolor[p],ampmarkstyles[0]),markersize=markersize,markeredgewidth=markeredgewidth)
4140 newylimits = recalcYlimitsFreq(chanrange, newylimits, gamp[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4141 # print("newylimits for amp = ", newylimits)
4142# if (debug): print("finished 'for' loop")
4143 if (sum(xflag)>0):
4144 # print("amp: Resetting xaxis frequency range to counteract flagged data")
4145 myxrange = np.max(frequencies)-np.min(frequencies)
4146 SetNewXLimits([np.min(frequencies)-0.15*myxrange, np.max(frequencies)+0.15*myxrange],4)
4148 if (1==1 or (xframe in bottomRowFrames) or (xctr+1==len(antennasToPlot) and ispw==spwsToPlot[-1])):
4149 # use 1==1 because spw might change between top row and bottom row of frames
4150 pb.xlabel(xlabelString, size=mysize)
4151 # endif (xaxis=='chan' elif xaxis=='freq' for 'amp')
4152 if (debug): print("finished 'if' block")
4153 if (overlayTimes):
4154 timeString =''
4155 else:
4156 if (len(uniqueTimes) > mytime):
4157 timeString = ', t%d/%d %s' % (mytime,nUniqueTimes-1,utstring(uniqueTimes[mytime],3))
4158 if (scansForUniqueTimes != []):
4159 if (scansForUniqueTimes[mytime]>=0):
4160 timeString = ', scan%d %s' % (scansForUniqueTimes[mytime],utstring(uniqueTimes[mytime],3))
4161 spwString = buildSpwString(overlaySpws, overlayBasebands,
4162 spwsToPlot, ispw, originalSpw[ispw],
4163 observatoryName, baseband,
4164 showBasebandNumber)
4165 if (overlayTimes and len(fieldsToPlot) > 1):
4166 indices = fstring = ''
4167 for f in fieldIndicesToPlot:
4168 if (f != fieldIndicesToPlot[0]):
4169 indices += ','
4170 fstring += ','
4171 indices += str(uniqueFields[f])
4172 if (msFound):
4173 fstring += msFields[uniqueFields[f]]
4174 if (len(fstring) > fstringLimit):
4175 fstring = fstring[0:fstringLimit] + '...'
4176 titleString = "%sspw%s, fields %s: %s%s" % (antennaString,spwString,
4177 indices, fstring, timeString)
4178 else:
4179 titleString = "%sspw%s, field %d: %s%s" % (antennaString,spwString,uniqueFields[fieldIndex],
4180 fieldString,timeString)
4181 tsize = titlesize-int(len(titleString)//(maxCharsBeforeReducingTitleFontSize//subplotCols))
4182 pb.title(titleString, size=tsize)
4183 if (abs(plotrange[0]) > 0 or abs(plotrange[1]) > 0):
4184 SetNewXLimits([plotrange[0],plotrange[1]],5)
4185 else:
4186 # Here is 1st place where we eliminate white space on right and left edge of the plots: 'amp'
4187 if (xaxis.find('chan')>=0):
4188 SetNewXLimits([channels[0],channels[-1]],6)
4189 else:
4190 if (zoom != 'intersect'):
4191 if (overlaySpws or overlayBasebands):
4192 SetNewXLimits(frequencyRangeToPlotInBaseband[bbctr],7)
4193 else:
4194 SetNewXLimits([frequencies[0], frequencies[-1]],8)
4195 if (bOverlay):
4196 if (xrange2 > myxrange+0.1 and zoom != 'intersect'):
4197 TDMisSecond = True
4198 if (abs(plotrange[2]) > 0 or abs(plotrange[3]) > 0):
4199 SetNewYLimits([plotrange[2],plotrange[3]])
4201 xlim = pb.xlim()
4202 ylim = pb.ylim()
4203 ResizeFontsSetGrid(adesc,mysize)
4204 pb.ylabel(yAmplitudeLabel, size=mysize)
4205 pb.subplots_adjust(hspace=myhspace, wspace=mywspace)
4206 myxrange = xlim[1]-xlim[0]
4207 yrange = ylim[1]-ylim[0]
4208 if (debug): print(("amp: ylim, yrange = ", ylim, yrange))
4209 if (overlayAntennas == False and overlayTimes == False and bOverlay == False and
4210 ((overlaySpws == False and overlayBasebands == False) or spwctr==spwctrFirstToPlot)):
4211 # draw polarization labels for no overlay, or overlaySpws/overlayBasebands
4212 x0 = xstartPolLabel
4213 y0 = ystartPolLabel
4214 for p in range(nPolarizations):
4215 if (corrTypeToString(corr_type[p]) in polsToPlot):
4216 if spwctr==spwctrFirstToPlot or (not overlaySpws and not overlayBasebands):
4217 # no need to plot it more than once in the same position
4218 pb.text(x0, y0-subplotRows*p*0.03, corrTypeToString(corr_type[p]),
4219 color=pcolor[p],size=mysize, transform=pb.gca().transAxes)
4220 if (channeldiff > 0):
4221 pb.text(x0, ystartMadLabel-0.03*subplotRows*p,
4222 corrTypeToString(corr_type[p])+' MAD = %.4f, St.Dev = %.4f'%(gamp_mad[p]['mad'],gamp_std[p]['std']),
4223 color=pcolor[p],size=mysize, transform=pb.gca().transAxes)
4224 if (xframe == firstFrame):
4225 # draw title including caltable name
4226 caltableList = caltableTitle
4227 if (bpolyOverlay):
4228 caltableList += ', ' + caltable2 + ' (degamp=%d, degphase=%d)'%(nPolyAmp[index]-1,nPolyPhase[index]-1)
4229 if (bpolyOverlay2):
4230 caltableList += ', ' + caltable3 + ' (degamp=%d, degphase=%d)'%(nPolyAmp2[index]-1,nPolyPhase2[index]-1)
4231 pb.text(xstartTitle, ystartTitle, caltableList, size=titlesize,
4232 color='k', transform=pb.gcf().transFigure)
4234 elif (overlayAntennas==True and xant==antennasToPlot[-1] and bOverlay == False # ):
4235 and overlayTimes==False): # try to support antenna,time avoid antenna labels 'amp'
4236 # We do this last, because by then, the limits will be stable.
4237 if (debug): print("overlayAntennas=True")
4238 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)
4239 elif (overlayTimes==True and bOverlay == False
4240 and overlayAntennas==False): # try to support antenna,time
4241 doneOverlayTime = True # assumed until proven otherwise in the 'for' loop
4242 for f in fieldIndicesToPlot:
4243 if (len(uniqueTimesPerFieldPerSpw[ispwInCalTable][f]) > 0):
4244 # this spw/field combination had some entries plotted
4245 if ((uniqueTimes[mytime] < uniqueTimesPerFieldPerSpw[ispwInCalTable][f][-1]-solutionTimeThresholdSeconds) and
4246 (uniqueTimes[mytime] < timerangeListTimes[-1])):
4247 if tableFormat >= 34: #### added 2024Aug
4248 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
4249 if (debug):
4250 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]))
4251 print("-----------ispwInCalTable=%d, mytime=%d, len(uniqueTimes) = %d" % (ispwInCalTable, mytime, len(uniqueTimes)))
4252 doneOverlayTime = False
4253 else: #### added 2024Aug
4254 doneOverlayTime = False #### added 2024Aug
4255 if (debug):
4256 print("------doneOverlayTime = %s on mytime %d" % (str(doneOverlayTime),mytime))
4257 if (doneOverlayTime):
4258 # either it is the last time of any times in solution, or the last time in the list of times to plot
4259 if (debug):
4260 print("*** on last time = %d for last fieldIndex %d or %d>=%d" % (mytime,fieldIndex,mytime,timerangeList[-1]))
4261 mytime = nUniqueTimes-1
4262 # We do this last, because by then, the limits will be broad enought and stable.
4263 # draw polarization labels
4264 DrawPolarizationLabelsForOverlayTime(xstartPolLabel,ystartPolLabel,corr_type,polsToPlot,
4265 channeldiff,ystartMadLabel,subplotRows,gamp_mad,mysize,
4266 ampmarkstyle,markersize,ampmarkstyle2, gamp_std)
4267 if (xframe == firstFrame):
4268 # draw title including caltable name
4269 pb.text(xstartTitle, ystartTitle, caltableTitle, size=titlesize,
4270 color='k', transform=pb.gcf().transFigure)
4271 if tableFormat >= 34: ### added 2024Aug
4272 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
4273 else: ### added 2024Aug
4274 scansToPlotHere = scansToPlot ### added 2024Aug
4275 if (debug): print("drawOverlayTimeLegends loc 2")
4276 drawOverlayTimeLegends(xframe, firstFrame, xstartTitle, ystartTitle,
4277 caltable, titlesize, fieldIndicesToPlot,
4278 ispwInCalTable, uniqueTimesPerFieldPerSpw,
4279 timerangeListTimes, solutionTimeThresholdSeconds,
4280 debugSloppyMatch, ystartOverlayLegend, debug, mysize,
4281 fieldsToPlot, myUniqueColor,timeHorizontalSpacing,
4282 fieldIndex, overlayColors, antennaVerticalSpacing,
4283 overlayAntennas, timerangeList, caltableTitle,
4284 mytime, scansToPlotHere, scansForUniqueTimes,
4285 uniqueSpwsInCalTable, uniqueTimes) ### modified 2024Aug
4286 elif (overlayAntennas and overlayTimes): # Oct 23, 2012
4287 # This will only happen for overlay='antenna,time'
4288 if (xframe == firstFrame and mytime == firstTimeMatch and xctr==firstUnflaggedAntennaToPlot and bOverlay==False): # bug fix on 2015-08-19 for CAS-7820
4289 # draw title including caltable name
4290 pb.text(xstartTitle, ystartTitle, caltableTitle, size=titlesize, color='k',
4291 transform=pb.gcf().transFigure)
4292 DrawBottomLegendPageCoords(msName, uniqueTimes[mytime], mysize, figfile)
4293 # Adding the following 'for' loop on Mar 13, 2013 to support the case of
4294 # single time range with overlay='antenna,time'
4295 if (xant==antennasToPlot[-1]):
4296 doneOverlayTime = True # assumed until proven otherwise in the 'for' loop
4297 for f in fieldIndicesToPlot:
4298 if (len(uniqueTimesPerFieldPerSpw[ispwInCalTable][f]) > 0):
4299 if ((uniqueTimes[mytime] < uniqueTimesPerFieldPerSpw[ispwInCalTable][f][-1]-solutionTimeThresholdSeconds) and
4300 (uniqueTimes[mytime] < timerangeListTimes[-1])):
4301 if tableFormat >= 34: #### added 2024Aug
4302# if (scansForUniqueTimes[mytime] != scansForUniqueTimes[-1]) #### added 2024Aug (fix for CAS-14096): if we are on the final time then we are done
4303 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
4304 if (debug):
4305 print("-----------Not done because %.0f < %.0f-%d for fieldIndex=%d and <%.0f" % (uniqueTimes[mytime], uniqueTimesPerFieldPerSpw[ispwInCalTable][f][-1], solutionTimeThresholdSeconds, f, timerangeListTimes[-1]))
4306 print("-----------ispwInCalTable=%d, mytime=%d, len(uniqueTimes) = %d" % (ispwInCalTable, mytime, len(uniqueTimes)))
4307 doneOverlayTime = False
4308 else: #### added 2024Aug
4309 doneOverlayTime = False #### added 2024Aug
4310 if (doneOverlayTime):
4311 # This is necessary for the case that no antennas were flagged for the single timerange selected
4312 if (debug): print("drawOverlayTimeLegends loc 3")
4313 drawOverlayTimeLegends(xframe,firstFrame,xstartTitle,ystartTitle,caltable,titlesize,
4314 fieldIndicesToPlot,ispwInCalTable,uniqueTimesPerFieldPerSpw,
4315 timerangeListTimes, solutionTimeThresholdSeconds,
4316 debugSloppyMatch,ystartOverlayLegend,debug,mysize,
4317 fieldsToPlot,myUniqueColor,timeHorizontalSpacing,
4318 fieldIndex, overlayColors, antennaVerticalSpacing,
4319 overlayAntennas, timerangeList, caltableTitle,
4320 mytime, scansToPlotPerSpw[ispw], scansForUniqueTimes,
4321 uniqueSpwsInCalTable, uniqueTimes)
4323 # endif / elif / elif / elif
4325 if (debug): print("####### 2nd place")
4326 # Here is 2nd place where we eliminate any white space on the right and left edge of the plots: 'amp'
4327 #
4328 if (abs(plotrange[2]) > 0 or abs(plotrange[3]) > 0):
4329 SetNewYLimits([plotrange[2],plotrange[3]])
4330 if (plotrange[0]==0 and plotrange[1]==0):
4331 if (xaxis.find('chan')>=0):
4332 SetNewXLimits([channels[0],channels[-1]],9)
4333 else:
4334 if (zoom != 'intersect'):
4335 if (overlaySpws or overlayBasebands):
4336 SetNewXLimits(frequencyRangeToPlotInBaseband[bbctr],10)
4337 else:
4338 SetNewXLimits([frequencies[0], frequencies[-1]],11)
4339 if (bOverlay):
4340# # # # print("Checking if %f >= %f" % (xrange2, myxrange))
4341 if (xrange2 >= myxrange and zoom != 'intersect'):
4342 # This is necessary if caltable2=TDM and caltable=FDM
4343 SetNewXLimits([frequencies2[0], frequencies2[-1]],12)
4344 if (xrange2 > myxrange+0.1 and zoom != 'intersect'):
4345 TDMisSecond = True
4346 else:
4347 SetNewXLimits([plotrange[0], plotrange[1]],13)
4348 if (debug): print("done SetNewXLimits")
4350 # I need the following line for chanrange to work
4351 if (chanrange[0] != 0 or chanrange[1] != 0 or chanrangePercent != None):
4352 SetLimits(plotrange, chanrange, newylimits, channels, frequencies, pfrequencies,
4353 ampMin, ampMax, xaxis,pxl, chanrangeSetXrange,
4354 chanrangePercent)
4356 # Finally, draw the atmosphere and FDM windows, if requested. 'amp'
4357 if ((overlayAntennas==False and overlayTimes==False) or
4358 (overlayAntennas==True and overlayTimes==False and xant==antennasToPlot[-1]) or
4359 (overlayTimes==True and overlayAntennas==False and doneOverlayTime) or
4360 (overlayTimes and overlayAntennas and # Aug 5, 2013
4361 xant==antennasToPlot[-1] and doneOverlayTime and mytime==finalTimeMatch # 2015-08-19 for CAS-7820
4362 and not drewAtmosphere) # added on 2014-12-04 to support case of a flagged antenna CAS-7187
4363 ):
4364 if ((showatm or showtsky) and len(atmString) > 0):
4365 DrawAtmosphere(showatm, showtsky, subplotRows, atmString,
4366 mysize, TebbSky, plotrange, xaxis, atmchan,
4367 atmfreq, transmission, subplotCols,
4368 showatmPoints=showatmPoints, xframe=xframe,
4369 channels=channels,mylineno=lineNumber(),
4370 overlaySpws=overlaySpws,
4371 overlayBasebands=overlayBasebands,
4372 drewAtmosphere=drewAtmosphere,loc=203,
4373 showtsys=showtsys, Trx=Trx)
4374 if (LO1):
4375 # Now draw the image band
4376 DrawAtmosphere(showatm,showtsky, subplotRows, atmString,
4377 mysize, TebbSkyImage, plotrange, xaxis,
4378 atmchanImage, atmfreqImage, transmissionImage,
4379 subplotCols, LO1, xframe, firstFrame,
4380 showatmPoints,
4381 channels=channels,mylineno=lineNumber(),
4382 overlaySpws=overlaySpws,
4383 overlayBasebands=overlayBasebands,
4384 drewAtmosphere=drewAtmosphere,loc=204,
4385 showtsys=showtsys, Trx=Trx)
4386 drewAtmosphere = True
4387 if (xaxis.find('freq')>=0 and showfdm and nChannels <= 256):
4388 if (tableFormat == 33):
4389 showFDM(originalSpw_casa33, chanFreqGHz_casa33, baseband, showBasebandNumber, basebandDict, overlayColors)
4390 else:
4391 showFDM(originalSpw, chanFreqGHz, baseband, showBasebandNumber, basebandDict, overlayColors)
4392 if (debug): print("done drawAtmosphere/FDM check")
4394 if (bOverlay):
4395 # draw polarization labels
4396 x0 = xstartPolLabel
4397 y0 = ystartPolLabel
4398 for p in range(nPolarizations):
4399 if (corrTypeToString(corr_type[p]) in polsToPlot):
4400 pb.text(x0, y0-p*0.03*subplotRows, corrTypeToString(corr_type[p])+'-c1',
4401 color=pcolor[p],size=mysize,transform=pb.gca().transAxes)
4402 pb.text(x0, y0-p*0.03*subplotRows-0.06*subplotRows, corrTypeToString(corr_type[p])+'-c2',
4403 color=p2color[p],size=mysize,transform=pb.gca().transAxes)
4404 if (debug): print("done pol labels")
4405 if (bpolyOverlay and xaxis.find('freq')>=0):
4406 # draw polarization labels
4407 x0 = xstartPolLabel
4408 y0 = ystartPolLabel
4409 if (x2color != xcolor):
4410 for p in range(nPolarizations):
4411 if (corrTypeToString(corr_type[0]) in polsToPlot):
4412 pb.text(x0+0.1, y0-p*0.03*subplotRows, corrTypeToString(corr_type[p]), color=p2color[p],
4413 size=mysize,transform=pb.gca().transAxes)
4414 if (bpolyOverlay2):
4415 for p in range(nPolarizations):
4416 if (corrTypeToString(corr_type[0]) in polsToPlot):
4417 pb.text(x0+0.2, y0-p*0.03*subplotRows, corrTypeToString(corr_type[p]),
4418 color=p3color[p], size=mysize,transform=pb.gca().transAxes)
4420 myIndexTime = uniqueTimesPerFieldPerSpw[ispwInCalTable][fieldIndex][-1]
4421 if (debug): print("running sloppyMatch")
4422 if tableFormat >= 34: ### added 2024Aug
4423 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
4424 else: ### added 2024Aug
4425 scansToPlotHere = scansToPlot ### added 2024Aug
4426 matched,mymatch = sloppyMatch(myIndexTime,uniqueTimes,solutionTimeThresholdSeconds,
4427 mytime, scansToPlotHere, ### modified 2024Aug
4428 scansForUniqueTimes,
4429 whichone=True,myprint=debug)
4430 if (debug):
4431 print("1)done sloppyMatch, mytime=%d, scansForUniqueTimes=%s" % (mytime,str(scansForUniqueTimes)))
4432 print("ispw=%d" % (ispw))
4433 print("len(scansToPlotPerSpw)=%d" % (len(scansToPlotPerSpw)))
4434 if (matched == False and scansForUniqueTimes[mytime] in scansToPlotPerSpw[ispw]):
4435 print("---------- 1) Did not find %f in %s" % (myIndexTime,str(uniqueTimes)))
4436 print("Try re-running with a smaller solutionTimeThresholdSeconds (currently %f)" % (solutionTimeThresholdSeconds))
4437 return
4438 else:
4439 # we are on the final time to be plotted
4440 if (debug): print("on the final time")
4441 mytimeTest = mytime==nUniqueTimes-1 # mytime==myIndexTime # mytime==mymatch
4442 if ((xframe == 111 and amplitudeWithPhase) or
4443 # Following case is needed to make subplot=11 to work for: try to support overlay='antenna,time'
4444 (xframe == lastFrame and overlayTimes and overlayAntennas and
4445 xctr+1==len(antennasToPlot) and
4446 mytimeTest and
4447 spwctr<len(spwsToPlot))): # removed +1 from spwctr+1 on 2014-04-05 to match au
4448 if (debug):
4449 print("xframe=%d == lastFrame=%d, amplitudeWithPhase=%s" % (xframe, lastFrame, str(amplitudeWithPhase)))
4450 print("xctr+1=%d == len(antennasToPlot)=%d" % (xctr+1,len(antennasToPlot)))
4451 print("mytime+1=%d == len(uniqueTimes)=%d" % (mytime+1,len(uniqueTimes)))
4452 print("spwctr+1=%d < len(spwsToPlot)=%d" % (spwctr+1,len(spwsToPlot)))
4453 if (len(figfile) > 0):
4454 plotfiles.append(makeplot(figfile,msFound,msAnt,
4455 overlayAntennas,pages,pagectr,
4456 density,interactive,antennasToPlot,
4457 spwsToPlot,overlayTimes,overlayBasebands,
4458 3,xant,ispw,subplot,resample,
4459 debug,figfileSequential,figfileNumber))
4460 figfileNumber += 1
4462 donetime = time.time()
4463 drewAtmosphere = False # needed for CAS-7187 (subplot=11)
4464 if (interactive):
4465 pb.draw()
4466 myinput = input("Press return for next page (b for backwards, q to quit): ")
4467 else:
4468 myinput = ''
4469 skippingSpwMessageSent = 0
4470 mytimestamp = time.time()
4471 if (myinput.find('q') >= 0):
4472 showFinalMessage(overlayAntennas, solutionTimeSpread, nUniqueTimes)
4473 return()
4474 if (myinput.find('b') >= 0):
4475 if (pagectr > 0):
4476 if (debug):
4477 print("Decrementing pagectr from %d to %d" % (pagectr, pagectr-1))
4478 pagectr -= 1
4479 else:
4480 if (debug):
4481 print("Not decrementing pagectr=%d" % (pagectr))
4483 redisplay = True
4484 #redisplay the current page by setting ctrs back to the value they had at start of that page
4485 xctr = pages[pagectr][PAGE_ANT]
4486 spwctr = pages[pagectr][PAGE_SPW]
4487 mytime = pages[pagectr][PAGE_TIME]
4488 myap = pages[pagectr][PAGE_AP]
4489 xant = antennasToPlot[xctr]
4490 antstring, Antstring = buildAntString(xant,msFound,msAnt)
4491 ispw = spwsToPlot[spwctr]
4492# # # # print("Returning to [%d,%d,%d,%d]" % (xctr,spwctr,mytime,myap))
4493 if (xctr==pages[0][PAGE_ANT] and spwctr==pages[0][PAGE_SPW] and mytime==pages[0][PAGE_TIME] and pages[0][PAGE_AP]==myap):
4494 safe_pb_clf()
4495 if (debug):
4496 print("2)Setting xframe to %d" % xframeStart)
4497 xframe = xframeStart
4498 myUniqueColor = []
4499 continue
4500 else:
4501 pagectr += 1
4502 if (pagectr >= len(pages)):
4503 if (xframe == lastFrame and overlayTimes and overlayAntennas and xctr+1==len(antennasToPlot) and
4504 yaxis=='amp'):
4505 # I'm not sure why this works, but is needed to fix CAS-7154
4506 myspwctr = spwctr+1
4507 else:
4508 myspwctr = spwctr
4509 pages.append([xctr,myspwctr,mytime,1])
4510 if (debug):
4511 print("amp: appending [%d,%d,%d,%d]" % (xctr,myspwctr,mytime,1))
4512 newpage = 0
4513 safe_pb_clf()
4514 if (debug):
4515 print("3)Setting xframe to %d" % xframeStart)
4516 xframe = xframeStart
4517 myUniqueColor = []
4518 else:
4519 if (debug):
4520 print("::: Not done page: Not checking whether we need to set xframe=xframeStart")
4521 print("::: xframe=%d ?= lastFrame=%d, amplitudeWithPhase=" % (xframe, lastFrame), amplitudeWithPhase)
4522 print("::: xctr+1=%d ?= len(antennasToPlot)=%d" % (xctr+1,len(antennasToPlot)))
4523 print(":::: mytimeTest = %s" % (mytimeTest))
4524 print("::: spwctr=%d ?< len(spwsToPlot)=%d" % (spwctr,len(spwsToPlot)))
4525###########################################################
4526################### Here is the phase plotting ############
4527###########################################################
4528 if (yaxis.find('phase')>=0 or amplitudeWithPhase) and doneOverlayTime==False:
4529 if (channeldiff > 0):
4530 pchannels = [xchannels,ychannels] # this is necessary because np.diff reduces nchan by 1
4531 pfrequencies = [xfrequencies,yfrequencies] # this is necessary because np.diff reduces nchan by 1
4532 if (bOverlay):
4533 pchannels2 = [xchannels2,ychannels2] # this is necessary because np.diff reduces nchan by 1
4534 pfrequencies2 = [xfrequencies2,yfrequencies2] # this is necessary because np.diff reduces nchan by 1
4535 if (overlayTimes == False or mytime==firstTimeMatch):
4536 if ((overlaySpws == False and overlayBasebands==False) or spwctr==spwctrFirstToPlot or
4537 spwctr>spwsToPlot[-1] or
4538 (overlayBasebands and amplitudeWithPhase)): # CAS-6477
4539 if (overlayAntennas==False or xctr==firstUnflaggedAntennaToPlot
4540 or xctr>antennasToPlot[-1]): # 2012-05-24, to fix the case where all ants flagged on one timerange
4541 xframe += 1
4542 if debug:
4543 print("u) incrementing xframe to %d" % xframe)
4544 myUniqueColor = []
4545 newylimits = [LARGE_POSITIVE, LARGE_NEGATIVE]
4546 if (phase != ''):
4547 if ((phase[0] != 0 or phase[1] != 0) and amplitudeWithPhase):
4548 newylimits = phase
4549 if (debug):
4550 print("$$$$$$$$$$$$$$$$$$$$$$$ ready to plot phase on xframe %d" % (xframe))
4553 if (previousSubplot != xframe):
4554 adesc = safe_pb_subplot(xframe) # avoid deprecation warning in CASA6 when xframe already was opened
4555 drewAtmosphere = False
4556 previousSubplot = xframe
4557 gphsx = np.arctan2(np.imag(gplotx),np.real(gplotx))*180.0/math.pi
4558 if (nPolarizations == 2):
4559 gphsy = np.arctan2(np.imag(gploty),np.real(gploty))*180.0/math.pi
4560 if (channeldiff>0):
4561 if (xaxis == 'chan'):
4562 gphs0, newx0, gphs0res, newx0res = channelDifferences(gphsx, pchannels[0], resample)
4563 gphs1, newx1, gphs1res, newx1res = channelDifferences(gphsy, pchannels[1], resample)
4564 pchannels = [newx0,newx1]
4565 else:
4566 gphs0, newx0, gphs0res, newx0res = channelDifferences(gphsx, pfrequencies[0], resample)
4567 gphs1, newx1, gphs1res, newx1res = channelDifferences(gphsy, pfrequencies[1], resample)
4568 pfrequencies = [newx0,newx1]
4569 gphs = [gphs0, gphs1]
4570 gphsres = [gphs0res, gphs1res]
4571 gphs_mad = [madInfo(gphs[0],madsigma,edge), madInfo(gphs[1],madsigma,edge)]
4572 gphs_std = [stdInfo(gphsres[0],madsigma,edge,ispw,xant,0), stdInfo(gphsres[1],madsigma,edge,ispw,xant,1)]
4573 for p in [0,1]:
4574 madstats[Antstring][ispw][mytime][p]['phase'] = gphs_mad[p]['mad']
4575 madstats[Antstring][ispw][mytime][p]['phasestd'] = gphs_std[p]['std']
4576 if (gphs_mad[p]['nchan'] > 0):
4577 checkAbsSum = np.sum(np.abs(gphs[p]))
4578 if (checkAbsSum < PHASE_ABS_SUM_THRESHOLD):
4579 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))
4580 else:
4581 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]))
4582 else:
4583 gphs = [gphsx,gphsy]
4584 else: # 1-pol
4585 if (channeldiff>0):
4586 if (xaxis == 'chan'):
4587 gphs0, newx0, gphs0res, newx0res = channelDifferences(gphsx, pchannels[0], resample)
4588 pchannels = [newx0]
4589 else:
4590 gphs0, newx0, gphs0res, newx0res = channelDifferences(gphsx, pfrequencies[0], resample)
4591 pfrequencies = [newx0]
4592 gphs = [gphs0]
4593 gphsres = [gphs0res]
4594 p = 0
4595 gphs_mad = [madInfo(gphs[p], madsigma, edge)]
4596 gphs_std = [stdInfo(gphsres[p], madsigma, edge, ispw,xant,p)]
4597 madstats[Antstring][ispw][mytime][p]['phase'] = gphs_mad[p]['mad']
4598 madstats[Antstring][ispw][mytime][p]['phasestd'] = gphs_mad[p]['std']
4599 if (gphs_mad[p]['nchan'] > 0):
4600 checkAbsSum = np.sum(np.abs(gphs[p]))
4601 if (checkAbsSum < PHASE_ABS_SUM_THRESHOLD):
4602 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))
4603 else:
4604 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]))
4605 else:
4606 gphs = [gphsx]
4607 if (bOverlay):
4608 if (debug):
4609 print("computing phase for second table")
4610 gphsx2 = np.arctan2(np.imag(gplotx2),np.real(gplotx2))*180.0/math.pi
4611 if (nPolarizations == 2):
4612 gphsy2 = np.arctan2(np.imag(gploty2),np.real(gploty2))*180.0/math.pi
4613 if (channeldiff>0):
4614 if (xaxis == 'chan'):
4615 gphs2_0, newx0, gphs2_0res, newx0res = channelDifferences(gphsx2, pchannels2[0], resample)
4616 gphs2_1, newx1, gphs2_1res, newx1res = channelDifferences(gphsy2, pchannels2[1], resample)
4617 pchannels2 = [newx0, newx1]
4618 else:
4619 gphs2_0, newx0, gphs2_0res, newx0res = channelDifferences(gphsx2, pfrequencies2[0], resample)
4620 gphs2_1, newx1, gphs2_1res, newx1res = channelDifferences(gphsy2, pfrequencies2[1], resample)
4621 pfrequencies2 = [newx0, newx1]
4622 gphs2 = [gphs2_0, gphs2_1]
4623 gphs2res = [gphs2_0res, gphs2_1res]
4624 else:
4625 gphs2 = [gphsx2, gphsy2]
4626 else:
4627 if (channeldiff>0):
4628 if (xaxis == 'chan'):
4629 gphs2_0, newx0, gphs2_0res, newx0res = channelDifferences(gphsx2, pchannels2[0], resample)
4630 pchannels2 = [newx0]
4631 else:
4632 gphs2_0, newx0, gphs2_0res, newx0res = channelDifferences(gphsx2, pfrequencies2[0], resample)
4633 pfrequencies2 = [newx0]
4634 gphs2 = [gphs2_0]
4635 gphs2res = [gphs2_0res]
4636 else:
4637 gphs2 = [gphsx2]
4638 else:
4639 if (debug):
4640 print("bOverlay is FALSE ===========================")
4642 if (xaxis.find('chan')>=0 or len(xfrequencies) < 1): # 'phase'
4643 for p in range(nPolarizations):
4644 if (corrTypeToString(corr_type[p]) in polsToPlot):
4645 if (overlayAntennas or overlayTimes):
4646 pdesc = pb.plot(pchannels[p],gphs[p],'%s'%(phasemarkstyles[p]),markersize=markersize,markeredgewidth=markeredgewidth)
4647 newylimits = recalcYlimits(plotrange,newylimits,gphs[p]) # 10/27/2011
4648 if (newylimits[1]-newylimits[0] < minPhaseRange):
4649 newylimits = [-minPhaseRange,minPhaseRange]
4650 if (phase != ''):
4651 if ((phase[0] != 0 or phase[1] != 0) and amplitudeWithPhase):
4652 newylimits = phase
4654 if (overlayAntennas and overlayTimes==False):
4655 pb.setp(pdesc, color=overlayColors[xctr])
4656 elif (overlayTimes and overlayAntennas==False):
4657 pb.setp(pdesc, color=overlayColors[mytime])
4658 elif (overlayTimes): # try to support antenna,time
4659 if (myUniqueTime != []):
4660 pb.setp(pdesc, color=overlayColors[myUniqueTime])
4661 # The third 'or' below is needed if pol='0' is flagged on antenna 0. -- 2012/10/12 (original spot)
4662 if (p==0 or len(polsToPlot)==1 or myUniqueColor==[]):
4663 myUniqueColor.append(overlayColors[len(myUniqueColor)])
4664 pb.setp(pdesc, color=myUniqueColor[-1])
4665 else:
4666 pb.plot(pchannels[p],gphs[p],'%s%s'%(pcolor[p],phasemarkstyles[0]), markersize=markersize,markeredgewidth=markeredgewidth)
4667 newylimits = recalcYlimits(plotrange,newylimits,gphs[p]) # 10/27/2011
4668 if (newylimits[1]-newylimits[0] < minPhaseRange):
4669 newylimits = [-minPhaseRange,minPhaseRange]
4670 if (phase != ''):
4671 if ((phase[0] != 0 or phase[1] != 0) and amplitudeWithPhase):
4672 newylimits = phase
4673 if (sum(xflag)>0):
4674# # # # print("phase: Resetting xaxis channel range to counteract flagged data")
4675 myxrange = np.max(channels)-np.min(channels)
4676 SetNewXLimits([np.min(channels)-myxrange/20,
4677 np.max(channels)+myxrange/20],14)
4678 if (xframe in bottomRowFrames or (xctr+1==len(antennasToPlot) and ispw==spwsToPlot[-1])):
4679 pb.xlabel("Channels (%d)"%(len(pchannels[p])), size=mysize) ### changed 2024Aug24
4680 elif (xaxis.find('freq')>=0): # 'phase'
4681 if (bOverlay):
4682 if (debug):
4683 p = 0 ### added 2024Aug to prevent crash due to undefined variable
4684 print("Preparing to plot phase from %f-%f for pols: %s" % (xfrequencies[0],xfrequencies[-1],str(polsToPlot)))
4685 print("Preparing to plot phase from %f-%f for pols: %s" % (pfrequencies[p][0],pfrequencies[p][-1],str(polsToPlot)))
4686 print("Preparing to plot phase from %f-%f for pols: %s" % (pfrequencies2[p][0],pfrequencies2[p][-1],str(polsToPlot)))
4687 myxrange = np.abs(xfrequencies[0]-xfrequencies[-1])
4688 try:
4689 xrange2 = np.abs(xfrequencies2[0]-xfrequencies2[-1])
4690 except:
4691 print("No phase data found in second solution. Try increasing the solutionTimeThresholdSeconds above %.0f." % (solutionTimeThresholdSeconds))
4692 print("If this doesn't work, email the developer (%s)." % (developerEmail))
4693 return()
4694 if (np.abs(myxrange/xrange2 - 1) > 0.05 + len(xflag)//len(xchannels)): # 0.0666 is 2000/1875-1
4695 # These line widths are optimal for visualizing FDM over TDM
4696 width1 = 1
4697 width2 = 4
4698 # solutions differ in frequency width, so show the narrower one first
4699 if (myxrange < xrange2):
4700 for p in range(nPolarizations):
4701 if (corrTypeToString(corr_type[p]) in polsToPlot):
4702 if (debug): print("pb.plot 1")
4703 pb.plot(pfrequencies[p], gphs[p], '%s%s'%(pcolor[p],phasemarkstyle), linewidth=width2, markersize=markersize,markeredgewidth=markeredgewidth)
4704 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4705 for p in range(nPolarizations):
4706 if (corrTypeToString(corr_type[p]) in polsToPlot):
4707 if (debug): print("pb.plot 2")
4708 pb.plot(pfrequencies2[p], gphs2[p], '%s%s'%(p2color[p],phasemarkstyle), linewidth=width1, markersize=markersize,markeredgewidth=markeredgewidth)
4709 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs2[p], sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
4710 else:
4711 for p in range(nPolarizations):
4712 if (corrTypeToString(corr_type[p]) in polsToPlot):
4713 if (debug): print("pb.plot 3")
4714 pb.plot(pfrequencies2[p], gphs2[p], '%s%s'%(p2color[p],phasemarkstyle), linewidth=width2, markersize=markersize,markeredgewidth=markeredgewidth)
4715 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs2[p], sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
4716 for p in range(nPolarizations):
4717 if (corrTypeToString(corr_type[p]) in polsToPlot):
4718 if (debug): print("pb.plot 4")
4719 pb.plot(pfrequencies[p], gphs[p], '%s%s'%(pcolor[p],phasemarkstyle), linewidth=width1, markersize=markersize,markeredgewidth=markeredgewidth)
4720 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4721 else:
4722 width1 = 1
4723 width2 = 1
4724 # solutions may be different level of smoothing, so plot highest rms first
4725 if (MAD(gphsx) < MAD(gphsx2)):
4726 for p in range(nPolarizations):
4727 if (corrTypeToString(corr_type[p]) in polsToPlot):
4728 if (debug): print("pb.plot 5")
4729 pb.plot(pfrequencies2[p], gphs2[p], '%s%s'%(p2color[p],phasemarkstyle), linewidth=width1, markersize=markersize,markeredgewidth=markeredgewidth)
4730 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs2[p], sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
4731 for p in range(nPolarizations):
4732 if (corrTypeToString(corr_type[p]) in polsToPlot):
4733 if (debug): print("pb.plot 6")
4734 pb.plot(pfrequencies[p], gphs[p], '%s%s'%(pcolor[p],phasemarkstyle), linewidth=width2, markersize=markersize,markeredgewidth=markeredgewidth)
4735 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4736 else:
4737 for p in range(nPolarizations):
4738 if (corrTypeToString(corr_type[p]) in polsToPlot):
4739 if (debug): print("pb.plot 7")
4740 pb.plot(pfrequencies[p], gphs[p], '%s%s'%(pcolor[p],phasemarkstyle), linewidth=width2, markersize=markersize,markeredgewidth=markeredgewidth)
4741 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4742 for p in range(nPolarizations):
4743 if (corrTypeToString(corr_type[p]) in polsToPlot):
4744 if (debug): print("pb.plot 9")
4745 pb.plot(pfrequencies2[p], gphs2[p], '%s%s'%(p2color[p],phasemarkstyle), linewidth=width1, markersize=markersize,markeredgewidth=markeredgewidth)
4746 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs2[p], sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
4747 # must set new limits after plotting 'phase'
4748 (y0,y1) = pb.ylim()
4749 if (y1-y0 < minPhaseRange):
4750 # this must come before defining ticks
4751 SetNewYLimits([-minPhaseRange,minPhaseRange])
4752 if (zoom=='intersect'):
4753 if (myxrange < xrange2):
4754 SetNewXLimits([min(xfrequencies[0],xfrequencies[-1])-myxrange*0.1, max(xfrequencies[0],xfrequencies[-1])+myxrange*0.1],15)
4755 SetLimits(plotrange, chanrange, newylimits, channels, frequencies,
4756 pfrequencies, ampMin, ampMax, xaxis,pxl, chanrangeSetXrange,
4757 chanrangePercent)
4758 else:
4759 SetNewXLimits([min(xfrequencies2[0],xfrequencies2[-1])-xrange2*0.1, max(xfrequencies2[0],xfrequencies2[-1])+xrange2*0.1],16)
4760 SetLimits(plotrange, chanrange, newylimits, channels, frequencies2,
4761 pfrequencies2, ampMin, ampMax, xaxis,pxl, chanrangeSetXrange,
4762 chanrangePercent)
4763 else:
4764 if (myxrange < xrange2):
4765 SetLimits(plotrange, chanrange, newylimits, channels, frequencies,
4766 pfrequencies, ampMin, ampMax, xaxis,pxl, chanrangeSetXrange,
4767 chanrangePercent)
4768 else:
4769 SetLimits(plotrange, chanrange, newylimits, channels, frequencies2,
4770 pfrequencies2, ampMin, ampMax, xaxis,pxl, chanrangeSetXrange,
4771 chanrangePercent)
4772 # draw polarization and spw labels
4773 if (xframe == firstFrame):
4774 # draw title including caltable name
4775 caltableList = 'c1=' + caltable + ', c2=' + caltable2 # + ' (%s)'%(utstring(uniqueTimes2[mytime],3))
4776 pb.text(xstartTitle, ystartTitle, caltableList, size=titlesize,
4777 color='k', transform=pb.gcf().transFigure)
4778 elif (bpolyOverlay):
4779 matches1 = []
4780 if tableFormat >= 34: ### added 2024Aug
4781 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
4782 else: ### added 2024Aug
4783 scansToPlotHere = scansToPlot ### added 2024Aug
4784 for tbp in range(len(timesBP)):
4785 if (sloppyMatch(uniqueTimes[mytime], timesBP[tbp], solutionTimeThresholdSeconds,
4786 mytime, scansToPlotHere, scansForUniqueTimes, ### modified 2024Aug
4787 myprint=debugSloppyMatch)):
4788 matches1.append(tbp)
4789 matches1 = np.array(matches1)
4790# # # # print("time matches: matches1 = ", matches1)
4791 if (len(matches1) < 1):
4792 print("No time match found")
4793 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]))))
4794 return()
4795 matches2 = np.where(xant == np.array(antennasBP))[0]
4796 if (len(matches2) < 1):
4797 print("No antenna match found between %s and %s" % (str(xant), str(antennasBP)))
4798# # # # print("antenna matches: matches2 = ", matches2)
4800 if (tableFormat == 33):
4801 matches3 = np.where(ispw == np.array(cal_desc_idBP))[0]
4802 if (len(matches3) < 1):
4803 print("No spw match found: %d not in %s" % (ispw, str(cal_desc_idBP)))
4804 else:
4805 matches3 = np.where(ispw == np.array(spwBP))[0]
4806 if (len(matches3) < 1):
4807 print("No spw match found: %d not in %s" % (ispw, str(spwBP)))
4808# # # # print("spw matches: matches3 = ", matches3)
4810 matches12 = np.intersect1d(matches1,matches2)
4811 if (len(matches12) < 1):
4812 print("No match between: %s and %s" % (str(matches1), str(matches2)))
4813# # # # print("antenna&time matches: matches12 = ", matches12)
4815 matches = np.intersect1d(matches12, matches3)
4816 if (len(matches) < 1):
4817 print("No match between: %s and %s" % (str(matches12), str(matches3)))
4818# # # # print("antenna&time&spw matches: matches = ", matches)
4820 try:
4821 index = matches[0] # holds the row number of the matching solution in the BPOLY table
4822 except:
4823 print("No match found for time=%.6f, xant=%d, ispw=%d" % (uniqueTimes[mytime],xant,ispw))
4824 print("antennasBP = %s" % (str(antennasBP)))
4825 print("cal_desc_idBP = %s" % (str(cal_desc_idBP)))
4826 timesBPstring = "timesBP = "
4827 for i in timesBP:
4828 timesBPstring += "%.6f, " % i
4829 print(timesBPstring)
4830 return()
4831# # # # 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))
4832 if (debug): print("BRowNumber = %d, BPolyRowNumber = %d" % (BRowNumber, index))
4833 validDomain = [frequencyLimits[0,index], frequencyLimits[1,index]]
4834 cc = calcChebyshev(polynomialPhase[index][0:nPolyPhase[index]], validDomain, frequenciesGHz[index]*1e+9) * 180/math.pi
4835 fa = np.array(frequenciesGHz[index])
4836 if (xfrequencies[0] < xfrequencies[-1]):
4837 matches = np.where(fa>xfrequencies[0])[0]
4838 matches2 = np.where(fa<xfrequencies[-1])[0]
4839 else:
4840 matches = np.where(fa>xfrequencies[-1])[0]
4841 matches2 = np.where(fa<xfrequencies[0])[0]
4842# # # # print("xfrequencies[0] = %f, xfrequencies[-1] = %f" % (xfrequencies[0], xfrequencies[-1]))
4843# # # # print("len(matches)=%d, len(matches2)=%d" % (len(matches), len(matches2)))
4844# # # # print("fa = ", fa)
4845 mymean = complexMeanDeg(np.array(cc)[matches[0]:matches2[-1]+1])
4846 phaseSolutionX = np.mean(gphsx) - mymean + cc
4848 cc = calcChebyshev(polynomialPhase[index][nPolyPhase[index]:2*nPolyPhase[index]], validDomain, frequenciesGHz[index]*1e+9) * 180/math.pi
4849 if (nPolarizations > 1):
4850 if (yfrequencies[0] < yfrequencies[-1]):
4851 matches = np.where(fa>yfrequencies[0])[0]
4852 matches2 = np.where(fa<yfrequencies[-1])[0]
4853 else:
4854 matches = np.where(fa>yfrequencies[-1])[0]
4855 matches2 = np.where(fa<yfrequencies[0])[0]
4856 mymean = complexMeanDeg(np.array(cc)[matches[0]:matches2[-1]+1])
4857 phaseSolutionY = np.mean(gphsy) - mymean + cc
4858 if (bpolyOverlay2):
4859 validDomain = [frequencyLimits2[0,index], frequencyLimits2[1,index]]
4860 cc = calcChebyshev(polynomialPhase2[index][0:nPolyPhase2[index]], validDomain, frequenciesGHz2[index]*1e+9) * 180/math.pi
4861 fa = np.array(frequenciesGHz2[index])
4862 if (xfrequencies[0] < xfrequencies[-1]):
4863 matches = np.where(fa>xfrequencies[0])[0]
4864 matches2 = np.where(fa<xfrequencies[-1])[0]
4865 else:
4866 matches = np.where(fa>xfrequencies[-1])[0]
4867 matches2 = np.where(fa<xfrequencies[0])[0]
4868 mymean = complexMeanDeg(np.array(cc)[matches[0]:matches2[-1]+1])
4869 phaseSolution2X = np.mean(gphsx) + cc - mymean
4871 cc = calcChebyshev(polynomialPhase2[index][nPolyPhase2[index]:2*nPolyPhase2[index]], validDomain, frequenciesGHz2[index]*1e+9) * 180/math.pi
4872 if (yfrequencies[0] < yfrequencies[-1]):
4873 matches = np.where(fa>yfrequencies[0])[0]
4874 matches2 = np.where(fa<yfrequencies[-1])[0]
4875 else:
4876 matches = np.where(fa>yfrequencies[-1])[0]
4877 matches2 = np.where(fa<yfrequencies[0])[0]
4878 mymean = complexMeanDeg(np.array(cc)[matches[0]:matches2[-1]+1])
4879 phaseSolution2Y = np.mean(gphsy) + cc - mymean
4880 for p in range(nPolarizations):
4881 if (corrTypeToString(corr_type[p]) in polsToPlot):
4882 pb.plot(pfrequencies[p], gphs[p],'%s%s' % (pcolor[p],phasemarkstyle), markersize=markersize,markeredgewidth=markeredgewidth)
4883 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4884 if (corrTypeToString(corr_type[0]) in polsToPlot):
4885 pb.plot(frequenciesGHz[index],phaseSolutionX,'%s%s'%(x2color,bpolymarkstyle),markeredgewidth=markeredgewidth)
4886 newylimits = recalcYlimitsFreq(chanrange, newylimits, phaseSolutionX, sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4887 pb.plot(frequenciesGHz2[index],phaseSolution2X,'%s%s'%(x3color,bpolymarkstyle),markeredgewidth=markeredgewidth)
4888 newylimits = recalcYlimitsFreq(chanrange, newylimits, phaseSolution2X, sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
4889 if (nPolarizations == 2):
4890 if (corrTypeToString(corr_type[1]) in polsToPlot):
4891 pb.plot(frequenciesGHz[index],phaseSolutionY,'%s%s'%(y2color,bpolymarkstyle),markeredgewidth=markeredgewidth)
4892 newylimits = recalcYlimitsFreq(chanrange, newylimits, phaseSolutionY, sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4893 pb.plot(frequenciesGHz2[index],phaseSolution2Y,'%s%s'%(y3color,bpolymarkstyle),markeredgewidth=markeredgewidth)
4894 newylimits = recalcYlimitsFreq(chanrange, newylimits, phaseSolution2Y, sideband,plotrange,xchannels2,chanrangePercent=chanrangePercent)
4895 else:
4896 for p in range(nPolarizations):
4897 if (corrTypeToString(corr_type[p]) in polsToPlot):
4898 pb.plot(pfrequencies[p], gphs[p],'%s%s'%(pcolor[p],phasemarkstyle), markersize=markersize,markeredgewidth=markeredgewidth)
4899 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4900 if (corrTypeToString(corr_type[0]) in polsToPlot):
4901 pb.plot(frequenciesGHz[index],phaseSolutionX,'%s%s'%(x2color,bpolymarkstyle),markeredgewidth=markeredgewidth)
4902 newylimits = recalcYlimitsFreq(chanrange, newylimits, phaseSolutionX, sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4903 if (nPolarizations == 2):
4904 if (corrTypeToString(corr_type[1]) in polsToPlot):
4905 pb.plot(frequenciesGHz[index],phaseSolutionY,'%s%s'%(y2color,bpolymarkstyle),markeredgewidth=markeredgewidth)
4906 newylimits = recalcYlimitsFreq(chanrange, newylimits, phaseSolutionY, sideband,plotrange,xchannels,chanrangePercent=chanrangePercent)
4907 # endif (bpolyOverlay2)
4908 # Adding the following 4 lines on March 14, 2013
4909 (y0,y1) = pb.ylim()
4910 if (y1-y0 < minPhaseRange):
4911 # this must come before defining ticks
4912 SetNewYLimits([-minPhaseRange,minPhaseRange])
4913 else:
4914 # we are not overlaying any B or polynomial solutions 'phase vs. freq'
4915 for p in range(nPolarizations):
4916 if (corrTypeToString(corr_type[p]) in polsToPlot):
4917 if (overlayAntennas or overlayTimes):
4918 pdesc = pb.plot(pfrequencies[p], gphs[p],'%s'%(phasemarkstyles[p]), markersize=markersize,markeredgewidth=markeredgewidth)
4919 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs[p], sideband,plotrange,xchannels,chanrangePercent=chanrangePercent) # Apr 2, 2012
4920 if (overlayAntennas and overlayTimes==False):
4921 pb.setp(pdesc, color=overlayColors[xctr])
4922 elif (overlayTimes and overlayAntennas==False):
4923 pb.setp(pdesc, color=overlayColors[mytime])
4924 elif (overlayTimes): # try to support antenna,time
4925 if (myUniqueTime != []):
4926 pb.setp(pdesc, color=overlayColors[myUniqueTime])
4927 # The third 'or' below is needed if pol='0' is flagged on antenna 0. -- 2012/10/12 (original spot)
4928 if (p==0 or len(polsToPlot)==1 or myUniqueColor==[]):
4929 myUniqueColor.append(overlayColors[len(myUniqueColor)])
4930 pb.setp(pdesc, color=myUniqueColor[-1])
4931 else:
4932 pb.plot(pfrequencies[p], gphs[p],'%s%s'%(pcolor[p],phasemarkstyles[0]), markersize=markersize,markeredgewidth=markeredgewidth)
4933 newylimits = recalcYlimitsFreq(chanrange, newylimits, gphs[p], sideband, plotrange,xchannels,chanrangePercent=chanrangePercent)
4934 if (sum(xflag)>0):
4935# # # # print("phase frame %d: Resetting xaxis frequency range to counteract flagged data" % (xframe))
4936 myxrange = np.max(frequencies)-np.min(frequencies)
4937 SetNewXLimits([np.min(frequencies)-0.15*myxrange, np.max(frequencies)+0.15*myxrange],17)
4938 if (len(gphs[p]) > 0):
4939 if (np.max(gphs[p]) < minPhaseRange and np.min(gphs[p]) > -minPhaseRange):
4940 SetNewYLimits([-minPhaseRange,minPhaseRange])
4941 #endif bOverlay
4943 if (1==1):
4944 pb.xlabel(xlabelString, size=mysize)
4945 #endif xaxis='chan'/freq for 'phase'
4946 if (overlayTimes):
4947 timeString =''
4948 else:
4949 timeString = ', t%d/%d %s' % (mytime,nUniqueTimes-1,utstring(uniqueTimes[mytime],3))
4950 if (scansForUniqueTimes != []):
4951 if (scansForUniqueTimes[mytime]>=0):
4952 timeString = ', scan%d %s' % (scansForUniqueTimes[mytime],utstring(uniqueTimes[mytime],3))
4953 spwString = buildSpwString(overlaySpws, overlayBasebands,
4954 spwsToPlot, ispw, originalSpw[ispw],
4955 observatoryName, baseband,
4956 showBasebandNumber)
4957 titleString = "%sspw%s, field %d: %s%s" % (antennaString,
4958 spwString,uniqueFields[fieldIndex],fieldString,timeString)
4959 pb.title(titleString,size=titlesize-int(len(titleString)//(maxCharsBeforeReducingTitleFontSize//subplotCols)))
4960 if (abs(plotrange[0]) > 0 or abs(plotrange[1]) > 0):
4961 SetNewXLimits([plotrange[0],plotrange[1]],18)
4963 # Here is 1st place where we eliminate any white space on the right and left edge of the plots: 'phase'
4964 else:
4965 if (xaxis.find('chan')>=0):
4966 SetNewXLimits([channels[0],channels[-1]])
4967 else:
4968 if (zoom != 'intersect'):
4969 if (overlaySpws or overlayBasebands):
4970 SetNewXLimits(frequencyRangeToPlotInBaseband[bbctr])
4971 else:
4972 SetNewXLimits([frequencies[0], frequencies[-1]])
4973 if (bOverlay):
4974 if (xrange2 > myxrange+0.1 and zoom != 'intersect'):
4975 TDMisSecond = True
4977 if (abs(plotrange[2]) > 0 or abs(plotrange[3]) > 0):
4978 if (amplitudeWithPhase == False or phase == ''):
4979 SetNewYLimits([plotrange[2],plotrange[3]])
4980 if (amplitudeWithPhase and phase != ''):
4981 if (phase[0] != 0 or phase[1] != 0):
4982 SetNewYLimits(phase)
4985 (y0,y1) = pb.ylim()
4986 if (y1-y0 < minPhaseRange):
4987 # this must come before defining ticks
4988 SetNewYLimits([-minPhaseRange,minPhaseRange])
4989 SetNewYLimits(newylimits) # added 10/2/2012 for the case of only 1 data point
4990 if (amplitudeWithPhase and phase != ''):
4991 if (phase[0] != 0 or phase[1] != 0):
4992 SetNewYLimits(phase)
4993 (y0,y1) = pb.ylim()
4994 ResizeFontsSetGrid(adesc,mysize)
4995 pb.ylabel(yPhaseLabel, size=mysize)
4996 pb.subplots_adjust(hspace=myhspace, wspace=mywspace)
4997 ylim = pb.ylim()
4998 xlim = pb.xlim()
4999 myxrange = xlim[1]-xlim[0]
5000 yrange = ylim[1]-ylim[0]
5001# # # # print("phase: ylim, yrange = ", ylim, yrange)
5002 myap = 0
5003 if (overlayAntennas == False and overlayTimes == False and bOverlay == False and
5004 ((overlaySpws == False and overlayBasebands == False) or spwctr==spwctrFirstToPlot)):
5005 # draw polarization labels
5006 x0 = xstartPolLabel
5007 y0 = ystartPolLabel
5008 for p in range(nPolarizations):
5009 if (corrTypeToString(corr_type[p]) in polsToPlot):
5010 pb.text(x0, y0-0.03*subplotRows*p, corrTypeToString(corr_type[p]), color=pcolor[p],
5011 size=mysize, transform=pb.gca().transAxes)
5012 if (channeldiff > 0):
5013 pb.text(x0, ystartMadLabel-0.03*subplotRows*p,
5014 corrTypeToString(corr_type[p])+' MAD = %.4f, St.Dev = %.4f'%(gphs_mad[p]['mad'],gphs_std[p]['std']),
5015 color=pcolor[p],size=mysize, transform=pb.gca().transAxes)
5016 if (xframe == firstFrame):
5017 # draw title including caltable name
5018 caltableList = caltableTitle
5019 if (bpolyOverlay):
5020 caltableList += ', ' + caltable2 + ' (degamp=%d, degphase=%d)'%(nPolyAmp[index]-1,nPolyPhase[index]-1)
5021 if (bpolyOverlay2):
5022 caltableList += ', ' + caltable3 + ' (degamp=%d, degphase=%d)'%(nPolyAmp2[index]-1,nPolyPhase2[index]-1)
5023 pb.text(xstartTitle, ystartTitle, caltableList, size=titlesize,
5024 color='k', transform=pb.gcf().transFigure)
5025 elif (overlayAntennas==True and xant==antennasToPlot[-1] and bOverlay==False # ):
5026 and overlayTimes==False): # try to support antenna,time avoid antenna labels 'phase'
5027 # We do this last, because by then, the limits will be stable.
5028 # draw polarization labels for overlayAntennas
5029 x0 = xstartPolLabel
5030 y0 = ystartPolLabel
5031 if (corrTypeToString(corr_type[0]) in polsToPlot):
5032 if (channeldiff > 0):
5033 pb.text(x0, ystartMadLabel-0.03*subplotRows*p,
5034 corrTypeToString(corr_type[p])+' MAD = %.4f, St.Dev = %.4f'%(gphs_mad[p]['mad'],gphs_std[p]['std']),
5035 color=overlayColors[0], size=mysize, transform=pb.gca().transAxes)
5036 if (phasemarkstyle.find('-')>=0):
5037 pb.text(x0, y0-0.03*subplotRows*0, corrTypeToString(corr_type[0])+' solid', color=overlayColors[0],
5038 fontsize=mysize, transform=pb.gca().transAxes)
5039 else:
5040 pb.text(x0+0.02, y0-0.03*subplotRows*0, corrTypeToString(corr_type[0]), color=overlayColors[0],
5041 fontsize=mysize, transform=pb.gca().transAxes)
5042 pdesc = pb.plot([x0], [y0+0.015-0*0.03*subplotRows], '%sk'%phasemarkstyle, markersize=markersize,
5043 scalex=False,scaley=False, transform=pb.gca().transAxes,markeredgewidth=markeredgewidth)
5044 if (len(corr_type) > 1):
5045 if (corrTypeToString(corr_type[1]) in polsToPlot):
5046 if (channeldiff > 0):
5047 pb.text(x0, ystartMadLabel-0.03*subplotRows*p,
5048 corrTypeToString(corr_type[p])+' MAD = %.4f, St.Dev = %.4f'%(gphs_mad[p]['mad'],gphs_std[p]['std']),
5049 color=overlayColors[0], size=mysize, transform=pb.gca().transAxes)
5050 if (phasemarkstyle2.find('--')>=0):
5051 pb.text(x0, y0-0.03*subplotRows*1, corrTypeToString(corr_type[1])+' dashed', color=overlayColors[0],
5052 fontsize=mysize, transform=pb.gca().transAxes)
5053 else:
5054 pb.text(x0+0.02, y0-0.03*subplotRows*1, corrTypeToString(corr_type[1]), color=overlayColors[0],
5055 fontsize=mysize, transform=pb.gca().transAxes)
5056 pdesc = pb.plot([x0], [y0+0.015*subplotRows-0.03*subplotRows*1],'%sk'%phasemarkstyle2, markersize=markersize,
5057 scalex=False,scaley=False, transform=pb.gca().transAxes,markeredgewidth=markeredgewidth)
5058 if (xframe == firstFrame):
5059 # draw title including caltable name
5060 pb.text(xstartTitle, ystartTitle, caltableTitle, size=titlesize, color='k',
5061 transform=pb.gcf().transFigure)
5062 DrawAntennaNames(msAnt, antennasToPlot, msFound, mysize, overlayColors)
5063 elif (overlayTimes==True and bOverlay == False
5064 and overlayAntennas==False): # try to support antenna,time
5065 doneOverlayTime = True # assumed until proven otherwise in the 'for' loop
5066 for f in fieldIndicesToPlot:
5067 if (uniqueTimes[mytime] < uniqueTimesPerFieldPerSpw[ispwInCalTable][f][-1]-solutionTimeThresholdSeconds and
5068 uniqueTimes[mytime] < timerangeListTimes[-1]):
5069 if tableFormat >= 34: # added 2024Aug
5070 if scansForUniqueTimes[mytime] != scansForUniqueTimes[-1]: # fix for CAS-14096
5071 doneOverlayTime = False
5072 else: # added 2024Aug
5073 doneOverlayTime = False # added 2024Aug
5074 if (doneOverlayTime):
5075 # either it is the last time of any times in solution, or the last time in the list of times to plot
5076 mytime = nUniqueTimes-1
5077 # draw polarization labels for overlayTimes
5078 # We do this last, because by then, the limits will be broad enough and stable.
5079 x0 = xstartPolLabel
5080 y0 = ystartPolLabel
5081 if (corrTypeToString(corr_type[0]) in polsToPlot):
5082 if (channeldiff > 0):
5083 p = 0
5084 pb.text(x0, ystartMadLabel-0.03*subplotRows*p,
5085 corrTypeToString(corr_type[p])+' MAD = %.4f'%(gphs_mad[p]['mad']),
5086 color='k', size=mysize, transform=pb.gca().transAxes)
5087 if (phasemarkstyle.find('-')>=0):
5088 pb.text(x0, y0, corrTypeToString(corr_type[0])+' solid', color='k',
5089 fontsize=mysize, transform=pb.gca().transAxes)
5090 else:
5091 pb.text(x0+0.02, y0, corrTypeToString(corr_type[0]), color='k',
5092 fontsize=mysize, transform=pb.gca().transAxes)
5093 pdesc = pb.plot([x0], [y0+0.015*subplotRows], '%sk'%phasemarkstyle, markersize=markersize,
5094 scalex=False,scaley=False, transform=pb.gca().transAxes,markeredgewidth=markeredgewidth)
5095 if (len(corr_type) > 1):
5096 if (corrTypeToString(corr_type[1]) in polsToPlot):
5097 if (channeldiff > 0):
5098 p = 1
5099 pb.text(x0, ystartMadLabel-0.03*subplotRows*p,
5100 corrTypeToString(corr_type[p])+' MAD = %.4f'%(gphs_mad[p]['mad']),
5101 color='k', size=mysize, transform=pb.gca().transAxes)
5102 if (phasemarkstyle2.find('--')>=0):
5103 pb.text(x0, y0-0.03*subplotRows, corrTypeToString(corr_type[1])+' dashed',
5104 color='k',fontsize=mysize, transform=pb.gca().transAxes)
5105 else:
5106 pb.text(x0+0.02, y0-0.03*subplotRows, corrTypeToString(corr_type[1]),
5107 color='k', fontsize=mysize, transform=pb.gca().transAxes)
5108 pdesc = pb.plot([x0], [y0+0.015*subplotRows-0.03*subplotRows], '%sk'%phasemarkstyle2,
5109 markersize=markersize, scalex=False,scaley=False, transform=pb.gca().transAxes,markeredgewidth=markeredgewidth)
5110 if (xframe == firstFrame):
5111 # draw title including caltable name
5112 pb.text(xstartTitle, ystartTitle, caltableTitle, size=titlesize, color='k',
5113 transform=pb.gcf().transFigure)
5114 if (debug): print("drawOverlayTimeLegends loc 4")
5115 drawOverlayTimeLegends(xframe,firstFrame,xstartTitle,ystartTitle,
5116 caltable,titlesize,fieldIndicesToPlot,
5117 ispwInCalTable,uniqueTimesPerFieldPerSpw,
5118 timerangeListTimes, solutionTimeThresholdSeconds,
5119 debugSloppyMatch,ystartOverlayLegend,debug,mysize,
5120 fieldsToPlot,myUniqueColor,timeHorizontalSpacing,
5121 fieldIndex, overlayColors, antennaVerticalSpacing,
5122 overlayAntennas, timerangeList, caltableTitle,
5123 mytime, scansToPlotPerSpw[ispw], scansForUniqueTimes,
5124 uniqueSpwsInCalTable, uniqueTimes)
5126 elif (overlayAntennas and overlayTimes): # Oct 23, 2012
5127 # This will only happen for: try to support overlay='antenna,time'
5128 if (xframe == firstFrame and mytime==0 and xctr==firstUnflaggedAntennaToPlot and bOverlay==False):
5129 # draw title including caltable name
5130 pb.text(xstartTitle, ystartTitle, caltableTitle, size=titlesize, color='k',
5131 transform=pb.gcf().transFigure)
5132 DrawBottomLegendPageCoords(msName, uniqueTimes[mytime], mysize, figfile)
5134 #endif (overlayAntennas == False and overlayTimes == False and bOverlay == False)
5136 # Here is 2nd place where we eliminate any white space on the right and left edge of the plots: 'phase'
5137 if (abs(plotrange[2]) > 0 or abs(plotrange[3]) > 0):
5138 if (amplitudeWithPhase == False or phase == ''):
5139 SetNewYLimits([plotrange[2],plotrange[3]])
5140 if (phase != '' and amplitudeWithPhase):
5141 if (phase[0] != 0 or phase[1] != 0):
5142 SetNewYLimits(phase)
5143 if (plotrange[0]==0 and plotrange[1]==0):
5144 if (xaxis.find('chan')>=0):
5145 SetNewXLimits([channels[0],channels[-1]])
5146 else:
5147 if (zoom != 'intersect'):
5148 if (overlaySpws or overlayBasebands):
5149 SetNewXLimits(frequencyRangeToPlotInBaseband[bbctr])
5150 else:
5151 SetNewXLimits([frequencies[0], frequencies[-1]])
5152 if (bOverlay):
5153 if (xrange2 >= myxrange and zoom != 'intersect'):
5154 # This is necessary if caltable2=TDM and caltable=FDM
5155 SetNewXLimits([frequencies2[0], frequencies2[-1]])
5156 if (xrange2 > myxrange+0.1 and zoom != 'intersect'):
5157 TDMisSecond = True
5158 else:
5159 SetNewXLimits([plotrange[0], plotrange[1]])
5161 # I need the following line for chanrange to work
5162 if (chanrange[0] != 0 or chanrange[1] != 0):
5163 SetLimits(plotrange, chanrange, newylimits, channels, frequencies, pfrequencies,
5164 ampMin, ampMax, xaxis,pxl, chanrangeSetXrange,
5165 chanrangePercent)
5167 # Finally, draw the atmosphere and FDM windows, if requested. 'phase'
5168 if ((overlayAntennas==False and overlayTimes==False) or
5169 (overlayAntennas==True and overlayTimes==False and xant==antennasToPlot[-1]) or
5170 (overlayTimes==True and overlayAntennas==False and doneOverlayTime) or
5171 (xant==antennasToPlot[-1] and doneOverlayTime)
5172 ):
5173 if ((showatm or showtsky) and len(atmString)>0):
5174 DrawAtmosphere(showatm, showtsky, subplotRows, atmString,
5175 mysize, TebbSky, plotrange, xaxis, atmchan,
5176 atmfreq, transmission, subplotCols,
5177 showatmPoints=showatmPoints, xframe=xframe,
5178 channels=channels, mylineno=lineNumber(),
5179 overlaySpws=overlaySpws,
5180 overlayBasebands=overlayBasebands,
5181 drewAtmosphere=drewAtmosphere,loc=205,
5182 showtsys=showtsys, Trx=Trx)
5183 if (LO1):
5184 DrawAtmosphere(showatm,showtsky, subplotRows, atmString,
5185 mysize, TebbSky, plotrange, xaxis, atmchanImage,
5186 atmfreqImage, transmissionImage, subplotCols,
5187 LO1, xframe, firstFrame, showatmPoints,
5188 channels=channels, mylineno=lineNumber(),
5189 overlaySpws=overlaySpws,
5190 overlayBasebands=overlayBasebands,
5191 drewAtmosphere=drewAtmosphere, loc=206,
5192 showtsys=showtsys, Trx=Trx)
5193 drewAtmosphere = True
5195 if (xaxis.find('freq')>=0 and showfdm and nChannels <= 256):
5196 if (tableFormat == 33):
5197 showFDM(originalSpw_casa33, chanFreqGHz_casa33, baseband, showBasebandNumber, basebandDict, overlayColors)
5198 else:
5199 showFDM(originalSpw, chanFreqGHz, baseband, showBasebandNumber, basebandDict, overlayColors)
5201 if (bOverlay):
5202 # draw polarization labels for bOverlay
5203 x0 = xstartPolLabel
5204 y0 = ystartPolLabel
5205 for p in range(nPolarizations):
5206 if (corrTypeToString(corr_type[p]) in polsToPlot):
5207 pb.text(x0, y0-p*0.03*subplotRows, corrTypeToString(corr_type[p])+'-c1',
5208 color=pcolor[p],size=mysize,transform=pb.gca().transAxes)
5209 pb.text(x0, y0-(p*0.03+0.06)*subplotRows, corrTypeToString(corr_type[p])+'-c2',
5210 color=p2color[p],size=mysize, transform=pb.gca().transAxes)
5211 if (bpolyOverlay and xaxis.find('freq')>=0):
5212 # draw polarization labels for bpolyOverlay
5213 x0 = xstartPolLabel
5214 y0 = ystartPolLabel
5215 if (xcolor != x2color):
5216 for p in range(nPolarizations):
5217 if (corrTypeToString(corr_type[p]) in polsToPlot):
5218 pb.text(x0+0.1, y0-p*0.03*subplotRows, corrTypeToString(corr_type[p]), color=p2color[p],
5219 size=mysize, transform=pb.gca().transAxes)
5220 if (bpolyOverlay2):
5221 for p in range(nPolarizations):
5222 if (corrTypeToString(corr_type[p]) in polsToPlot):
5223 pb.text(x0+0.2, y0-p*0.03*subplotRows, corrTypeToString(corr_type[p]), color=p3color[p],
5224 size=mysize, transform=pb.gca().transAxes)
5226 # endif (yaxis='phase')
5228 redisplay = False
5230 if (xframe == lastFrame):
5231 if (debug):
5232 print("*** mytime+1=%d, nUniqueTimes=%d, timerangeList[-1]=%d, doneOverlayTime=%s" % (mytime+1, nUniqueTimes,timerangeList[-1],doneOverlayTime))
5233 print("*** xant=%d, antennasToPlot[-1]=%d, overlayAntennas=%s, overlayTimes=%s" % (xant,antennasToPlot[-1],overlayAntennas,overlayTimes))
5234 print("*** xframe=%d, lastFrame=%d, xctr=%d, spwctr=%d, len(antennasToPlot)=%d, len(spwsToPlot)=%d" % (xframe,lastFrame,xctr,spwctr,len(antennasToPlot), len(spwsToPlot)))
5235 myIndexTime = uniqueTimesPerFieldPerSpw[ispwInCalTable][fieldIndex][-1]
5236 if (debug):
5237 print("myIndexTime = ", myIndexTime)
5238 if tableFormat >= 34: ### added 2024Aug
5239 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
5240 else: ### added 2024Aug
5241 scansToPlotHere = scansToPlot ### added 2024Aug
5242 matched,mymatch = sloppyMatch(myIndexTime,uniqueTimes,solutionTimeThresholdSeconds,
5243 mytime, scansToPlotHere, scansForUniqueTimes,
5244 whichone=True, myprint=False)
5245 if (matched==False and scansForUniqueTimes[mytime] in scansToPlotPerSpw[ispw]):
5246 print("---------- 2) Did not find %f within %.1f seconds of anything in %s" % (myIndexTime,solutionTimeThresholdSeconds,str(uniqueTimes)))
5247 print("Try re-running with a smaller solutionTimeThresholdSeconds (currently %f)" % (solutionTimeThresholdSeconds))
5248 return
5249 else:
5250 # we are on the final time to be plotted
5251 if (debug): print("on the final time")
5252 mytimeTest = mytime==nUniqueTimes-1
5253 if (debug):
5254 print("mytimeTest = %s" % (mytimeTest))
5255 if (scansForUniqueTimes == []):
5256 # old 3.3 cal tables will land here
5257 scanTest = False
5258 scanTest2 = False
5259 else:
5260 if (debug):
5261 print("ispw=%d len(scansToPlotPerSpw[ispw])=%d mytime=%d, len(scansForUniqueTimes)=%d" % (ispw,len(scansToPlotPerSpw[ispw]),mytime,len(scansForUniqueTimes)))
5262 print("scansToPlotPerSpw = ", scansToPlotPerSpw)
5263 if (len(scansToPlotPerSpw[ispw]) == 0):
5264 scanTest = False
5265 else:
5266 scanTest = scansToPlotPerSpw[ispw][-1]==scansForUniqueTimes[mytime] and (VisCal != 'SDSKY_PS' or mytime == timerangeList[-1]) ### added second expression 2024Aug27
5267 highestSpwIndexInSpwsToPlotThatHasCurrentScan = \
5268 computeHighestSpwIndexInSpwsToPlotThatHasCurrentScan(spwsToPlot, scansToPlotPerSpw, scansForUniqueTimes[mytime])
5269 if (highestSpwIndexInSpwsToPlotThatHasCurrentScan == -1):
5270 scanTest2 = False
5271 else:
5272 scanTest2 = (spwctr == highestSpwIndexInSpwsToPlotThatHasCurrentScan)
5273 if ((overlayAntennas==False and overlayTimes==False and overlaySpws==False and overlayBasebands==False)
5274 # either it is the last time of any, or the last time in the list of times to plot
5275 or (overlayAntennas==False and overlaySpws==False and overlayBasebands==False and (mytime+1==nUniqueTimes or mytime == timerangeList[-1])) # or mytimeTest)) # removed on July 25,2013
5276 or (xant==antennasToPlot[-1] and overlayAntennas==True and overlayTimes==False and overlaySpws==False and overlayBasebands==False)
5277 # The following case is needed to prevent frame=225 in test86 (spectral scan dataset with overlay='spw')
5278 # and the lack of showing of 7 of 8 of the spws in final frame of test61. scanTest2 matches both cases.
5279 or (scanTest and scanTest2 and overlaySpws and overlayAntennas==False and overlayTimes==False)
5280 or ((spwctr==len(spwsToPlot)-1) and (overlayBasebands or overlaySpws) and overlayAntennas==False and overlayTimes==False)
5281 # following case is needed for scans parameter with overlay='time'
5282 or (overlayTimes and scanTest and overlayAntennas==False)
5283 # Following case is needed to make subplot=11 to work for: try to support overlay='antenna,time' : 'phase'
5284 or (xframe == lastFrame and overlayTimes and overlayAntennas and
5285 xctr+1==len(antennasToPlot) and
5286 mytimeTest and
5287 spwctr<len(spwsToPlot))
5288 or (doneOverlayTime and overlayTimes==True
5289 and overlayAntennas==False
5290 )):
5291 if (debug):
5292 print("entered 'if' block")
5293 DrawBottomLegendPageCoords(msName, uniqueTimes[mytime], mysize, figfile)
5295 # added len(pages)>0 on July 30, 2013 to prevent crash when called with single
5296 # antenna and subplot=11 and all solutions flagged.
5297 if (len(figfile) > 0 and len(pages)>0):
5298 if (debug):
5299 print("calling makeplot")
5300 plotfiles.append(makeplot(figfile,msFound,msAnt,
5301 overlayAntennas,pages,pagectr,
5302 density,interactive,antennasToPlot,
5303 spwsToPlot,overlayTimes,overlayBasebands,
5304 4,xant,ispw,subplot,resample,debug,
5305 figfileSequential, figfileNumber))
5306 if (debug):
5307 print("done makeplot")
5308 figfileNumber += 1
5309 myinput = ''
5310 donetime = time.time()
5311 drewAtmosphere = False # needed for CAS-7187 (subplot=11)
5312 if (interactive):
5313 pb.draw()
5314# # # # myinput = raw_input("(%.1f sec) Press return for next screen (b for backwards, q to quit): "%(donetime-mytimestamp))
5315 myinput = input("Press return for next page (b for backwards, q to quit): ")
5316 else:
5317 myinput = ''
5318 skippingSpwMessageSent = 0
5319 mytimestamp = time.time()
5320 if (myinput.find('q') >= 0):
5321 mytime = len(uniqueTimes)
5322 spwctr = len(spwsToPlot)
5323 xctr = len(antennasToPlot)
5324 bbctr = len(spwsToPlotInBaseband)
5325 break
5326 if (debug):
5327 print("4)Setting xframe to %d" % (xframeStart))
5328 xframe = xframeStart
5329 myUniqueColor = []
5330 pb.subplots_adjust(hspace=myhspace, wspace=mywspace)
5331 if (myinput.find('b') >= 0):
5332 if (pagectr > 0):
5333 if (debug):
5334 print("Decrementing pagectr from %d to %d" % (pagectr, pagectr-1))
5335 pagectr -= 1
5336 else:
5337 if (debug):
5338 print("Not decrementing pagectr=%d" % (pagectr))
5339 redisplay = True
5340 #redisplay the current page by setting ctrs back to the value they had at start of that page
5341 xctr = pages[pagectr][PAGE_ANT]
5342 spwctr = pages[pagectr][PAGE_SPW]
5343 mytime = pages[pagectr][PAGE_TIME]
5344 myap = pages[pagectr][PAGE_AP]
5345 xant = antennasToPlot[xctr]
5346 antstring, Antstring = buildAntString(xant,msFound,msAnt)
5347 ispw = spwsToPlot[spwctr]
5348# # # # print("Returning to [%d,%d,%d,%d]" % (xctr,spwctr,mytime,myap))
5349 else:
5350 pagectr += 1
5351 if (pagectr >= len(pages)):
5352 newpage = 1
5353 else:
5354 newpage = 0
5355 if tableFormat >= 34: ### added 2024Aug
5356 scansToPlotHere = scansToPlotPerSpw[ispw] ### added 2024Aug
5357 else: ### added 2024Aug
5358 scansToPlotHere = scansToPlot ### added 2024Aug
5359 if (overlayTimes==True and
5360 sloppyMatch(uniqueTimesPerFieldPerSpw[ispwInCalTable][fieldIndex][-1],
5361 uniqueTimes[mytime],solutionTimeThresholdSeconds,
5362 mytime, scansToPlotHere, scansForUniqueTimes, # au version ### modified 2024Aug
5363 myprint=debugSloppyMatch)):
5364 # be sure to avoid any more loops through mytime which will cause 'b' button to fail
5365 if VisCal != 'SDSKY_PS':
5366 mytime = nUniqueTimes
5367 else:
5368 if (debug):
5369 print(">>>>>>>>>>> Not going to new page, uniqueTimes[mytime]=%.8f, uniqueTimesPerFieldPerSpw[ispwInCalTable=%d][fieldIndex=%d][-1]=%.8f" % (uniqueTimes[mytime], ispwInCalTable, fieldIndex, uniqueTimesPerFieldPerSpw[ispwInCalTable][fieldIndex][-1]))
5370 print("spwctr=%d ?== (len(spwsToPlot)-1)=%d, spwsToPlot=" % (spwctr,len(spwsToPlot)-1),spwsToPlot)
5371 print("test1: %s" % (overlayAntennas==False and overlayTimes==False and overlaySpws==False and overlayBasebands==False))
5372 print("test2: %s" % (overlayAntennas==False and overlaySpws==False and overlayBasebands==False and (mytime+1==nUniqueTimes or mytime == timerangeList[-1])))
5373 print("test3: %s" % (xant==antennasToPlot[-1] and overlayAntennas==True and overlayTimes==False and overlaySpws==False and overlayBasebands==False))
5374 print("*test4: %s" % ((spwctr==len(spwsToPlot)-1) and (overlaySpws or overlayBasebands) and overlayAntennas==False and overlayTimes==False) )
5375 print(" * = overlaySpws==True" )
5376 print("test5: %s" % (overlayTimes and scanTest))
5377 print("test6: %s" % (xframe == lastFrame and overlayTimes and overlayAntennas and xctr+1==len(antennasToPlot) and mytimeTest and spwctr<len(spwsToPlot)))
5378 print("test7: %s" % (doneOverlayTime and overlayTimes==True and overlayAntennas==False))
5380 if (redisplay == False):
5381 if ((overlayAntennas and xctr+1 >= len(antennasToPlot)) or
5382 ((overlaySpws or overlayBasebands) and spwctr+1 >= len(spwsToPlot)) or
5383 (overlayAntennas==False and overlaySpws==False and overlayBasebands==False)):
5384 mytime += 1
5385 if (debug):
5386 print("AT BOTTOM OF LOOP: Incrementing mytime to %d, setting firstUnflaggedAntennaToPlot to 0" % (mytime))
5387 firstUnflaggedAntennaToPlot = 0 # try this
5388 doneOverlayTime = False # added on 08-nov-2012
5389 if (overlayBasebands and (uniqueScanNumbers == sorted(scansToPlot))):
5390 if (debug): print("Breaking because scans not specified")
5391 break
5392 # end of enormous while(mytime) loop endwhile mytime
5393 if (redisplay == False):
5394 spwctr += 1
5395 if (debug):
5396 print( "---------------------------------------- Incrementing spwctr to %d, spwsToPlot=" % (spwctr), spwsToPlot)
5397 if (spwctr < len(spwsToPlot)):
5398 print("---------------------------------------- ispw = %d" % (spwsToPlot[spwctr]))
5399 else:
5400 print("---------------------------------------- done the spws in this baseband (%d)" % (baseband))
5401 else:
5402 if (debug):
5403 print("redisplay = True")
5404 # end of while(spwctr) loop
5405 if (debug): print("at bottom of spwctr loop, spwctr=%d, incrementing bbctr from %d to %d" % (spwctr,bbctr,bbctr+1))
5406 bbctr += 1
5407 # end of while(bbctr) loop
5408 if (debug): print("at bottom of bbctr loop")
5409 if (xant >= antennasToPlot[-1] and xframe != xframeStart):
5410 # this is the last antenna, so make a final plot
5411 if (len(figfile) > 0):
5412 plotfiles.append(makeplot(figfile,msFound,msAnt,overlayAntennas,
5413 pages,pagectr,density,interactive,
5414 antennasToPlot,spwsToPlot,overlayTimes,overlayBasebands,
5415 5,xant,ispw,subplot,resample,debug,
5416 figfileSequential,figfileNumber))
5417 figfileNumber += 1
5418 if (redisplay == False):
5419 xctr += 1
5420 if (debug):
5421 print("Incrementing xctr to %d" % (xctr))
5422 if (overlayAntennas):
5423 if (debug):
5424 print("Breaking out of antenna loop because we are done -------------------")
5425 break
5426 # end of while(xant) loop
5427 if (debug): print("Finished while(xant) loop----------------")
5428 pb.draw()
5429 if (len(plotfiles) == 1 and figfileSequential):
5430 # rename the single file to remove ".000"
5431 newplotfiles = [plotfiles[0].split('.000.png')[0]+'.png']
5432 print("renaming %s to %s" % (plotfiles[0],newplotfiles[0]))
5433 os.system('mv %s %s' % (plotfiles[0],newplotfiles[0]))
5434 plotfiles = newplotfiles
5435 if (len(plotfiles) > 0 and buildpdf):
5436 pdfname = figfile+'.pdf'
5437 filelist = ''
5438 plotfiles = np.unique(plotfiles)
5439 for i in range(len(plotfiles)):
5440 cmd = '%s -density %d %s %s.pdf' % (convert,density,plotfiles[i],plotfiles[i].split('.png')[0])
5441 casalogPost(debug,"Running command = %s" % (cmd))
5442 mystatus = os.system(cmd)
5443 if (mystatus != 0):
5444 print("ImageMagick's convert command not found, no PDF built")
5445 buildpdf = False
5446 break
5447 filelist += plotfiles[i].split('.png')[0] + '.pdf '
5448 if (buildpdf and (len(plotfiles)>1 or not figfileSequential)):
5449 # The following 2 lines reduce the total number of characters on the command line, which
5450 # was apparently a problem at JAO for Liza.
5451 filelist = ' '.join(pruneFilelist(filelist.split()))
5452 pdfname = pruneFilelist([pdfname])[0]
5453 cmd = '%s %s cat output %s' % (pdftk, filelist, pdfname)
5454 casalogPost(debug,"Running command = %s" % (cmd))
5455 mystatus = os.system(cmd)
5456 if (mystatus != 0):
5457 cmd = '%s -q -sPAPERSIZE=letter -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=%s %s' % (gs,pdfname,filelist)
5458 casalogPost(debug,"Running command = %s" % (cmd))
5459 mystatus = os.system(cmd)
5460 if (mystatus == 0):
5461 casalogPost(debug,"PDF left in %s" % (pdfname))
5462 print("PDF left in %s" % (pdfname))
5463 os.system("rm -f %s" % filelist)
5464 else:
5465 print("Both pdftk and ghostscript are missing, so no PDF built.")
5467 showFinalMessage(overlayAntennas, solutionTimeSpread, nUniqueTimes)
5469 if (channeldiff>0):
5470 # Compute median over all antennas, or at least those completed before 'q' was hit
5471 madstats['median'] = dict.fromkeys(spwsToPlot)
5472 spwvalue = {}
5473 spwvalue['amp'] = []
5474 spwvalue['phase'] = []
5475 for j in spwsToPlot:
5476 madstats['median'][j] = dict.fromkeys(timerangeList) # dict.fromkeys(range(len(uniqueTimes)))
5477 for k in timerangeList: # range(len(uniqueTimes)):
5478 madstats['median'][j][k] = dict.fromkeys(list(range(nPolarizations)))
5479 for l in range(nPolarizations):
5480 if (yaxis == 'both'):
5481 madstats['median'][j][k][l] = {'amp': None, 'phase': None}
5482 elif (yaxis == 'phase'):
5483 madstats['median'][j][k][l] = {'phase': None}
5484 else:
5485 # this includes tsys and amp
5486 madstats['median'][j][k][l] = {'amp': None}
5487 for m in madstats['median'][j][k][l].keys():
5488 value = []
5489 for i in madstats.keys(): # loop over antennas
5490 if (i != 'median' and i != 'platforming'):
5491 if (madstats[i][j][k][l][m] != None):
5492 if (debug): print(("madstats[%s][%d][%d][%d][%s] = " % (i,j,k,l,m), madstats[i][j][k][l][m]))
5493 value.append(madstats[i][j][k][l][m])
5494 spwvalue[m].append(madstats[i][j][k][l][m])
5495 madstats['median'][j][k][l][m] = np.median(value)
5496 # now add another spw which is the median over spw,time,polarization
5497 if (yaxis == 'both'):
5498 madstats['median']['median']={'amp': np.median(spwvalue['amp']),
5499 'phase': np.median(spwvalue['phase'])}
5500 elif (yaxis == 'phase'):
5501 madstats['median'][j][k][l] = {'phase': np.median(spwvalue['phase'])}
5502 else:
5503 madstats['median']['median'] = {'amp': np.median(spwvalue['amp'])}
5505 mymsmd.close()
5506 return(madstats)
5507 else:
5508 if (msFound and mymsmd != ''):
5509 mymsmd.close()
5510 return()
5511 # end of plotbandpass
5513def GetFieldIdsForFieldName(token, mymsmd, msFields):
5514 if (mymsmd != '' and mymsmd != None):
5515 return(mymsmd.fieldsforname(token)[0])
5516 else:
5517 return(list(msFields).index(token))
5519def GetFieldNamesForFieldId(u, mymsmd, msFields):
5520 if (mymsmd != '' and mymsmd != None):
5521 return(mymsmd.namesforfields(u)[0])
5522 else:
5523 print("B")
5524 return(msFields[u])
5526def 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):
5527 if (debug): print("overlayAntennas=True")
5528 x0 = xstartPolLabel
5529 y0 = ystartPolLabel
5530 # draw polarization labels
5531 if (debug): print("1) overlayAntennas=True")
5532 if (corrTypeToString(corr_type[0]) in polsToPlot):
5533 if (channeldiff > 0):
5534 pb.text(x0, ystartMadLabel-0.03*subplotRows*0,
5535 corrTypeToString(corr_type[0])+' MAD = %.4f, St.Dev = %.4f'%(gamp_mad[0]['mad'],gamp_std[0]['std']),
5536 color=overlayColors[0],size=mysize, transform=pb.gca().transAxes)
5537 if (ampmarkstyle.find('-')>=0):
5538 pb.text(x0, y0, corrTypeToString(corr_type[0])+' solid', color=overlayColors[0],size=mysize,
5539 transform=pb.gca().transAxes)
5540 else:
5541 pb.text(x0+0.02, y0, corrTypeToString(corr_type[0]), color=overlayColors[0],size=mysize,
5542 transform=pb.gca().transAxes)
5543 pdesc = pb.plot([x0-0.01], [y0], '%sk'%ampmarkstyle, markersize=markersize,
5544 scalex=False,scaley=False, transform=pb.gca().transAxes,markeredgewidth=markeredgewidth)
5545 if (debug): print("2) overlayAntennas=True")
5546 if (len(corr_type) > 1):
5547 if (corrTypeToString(corr_type[1]) in polsToPlot):
5548 if (channeldiff > 0):
5549 pb.text(x0, ystartMadLabel-0.03*subplotRows*1,
5550 corrTypeToString(corr_type[1])+' MAD = %.4f, St.Dev = %.4f'%(gamp_mad[1]['mad'],gamp_std[1]['std']),
5551 color=overlayColors[0],size=mysize, transform=pb.gca().transAxes)
5552 if (ampmarkstyle2.find('--')>=0):
5553 pb.text(x0, y0-0.03*subplotRows, corrTypeToString(corr_type[1])+' dashed',
5554 color=overlayColors[0],size=mysize, transform=pb.gca().transAxes)
5555 else:
5556 pb.text(x0+0.02, y0-0.03*subplotRows, corrTypeToString(corr_type[1]),
5557 color=overlayColors[0],size=mysize, transform=pb.gca().transAxes)
5558 pdesc = pb.plot([x0-0.01], [y0-0.03*subplotRows], '%sk'%ampmarkstyle2,
5559 markersize=markersize, scalex=False,scaley=False,markeredgewidth=markeredgewidth)
5560 if (debug): print("3) overlayAntennas=True")
5561 if (xframe == firstFrame):
5562 # draw title including caltable name
5563 if (debug): print("4) overlayAntennas=True")
5564 pb.text(xstartTitle, ystartTitle, caltableTitle, size=titlesize, color='k',
5565 transform=pb.gcf().transFigure)
5566 if (debug): print("5) overlayAntennas=True")
5567 DrawAntennaNames(msAnt, antennasToPlot, msFound, mysize, overlayColors)
5568 if (debug): print("6) overlayAntennas=True")
5570def getTelescopeNameFromCaltable(caltable):
5571 mytb = table()
5572 mytb.open(caltable)
5573 if ('OBSERVATION' in mytb.getkeywords()):
5574 observationTable = mytb.getkeyword('OBSERVATION').split()[1]
5575 else:
5576 observationTable = None
5577 mytb.close()
5578 if (observationTable == None):
5579 return('')
5580 else:
5581 return(getTelescopeNameFromCaltableObservationTable(observationTable))
5584def getTelescopeNameFromCaltableObservationTable(observationTable):
5585 mytb = table()
5586 mytb.open(observationTable)
5587 telescope = mytb.getcell('TELESCOPE_NAME')
5588 mytb.close()
5589 return(telescope)
5591def getCorrTypeByAntennaName(firstAntenna):
5592 """
5593 This function is used only if the OBSERVATION table of the caltable is blank and the MS is unavailable.
5594 """
5595 print("Using antenna name (%s) to set the polarization type." % (firstAntenna))
5596 if (firstAntenna.find('ea') >= 0):
5597 corr_type_string = ['RR','LL']
5598 corr_type = [5,8]
5599 elif (firstAntenna.find('dv') >= 0 or firstAntenna.find('da') >= 0 or
5600 firstAntenna.find('pm') >= 0 or firstAntenna.find('da') >= 0):
5601 corr_type_string = ['XX','YY']
5602 corr_type = [9,12]
5603 else: # SMA
5604 corr_type_string = ['XX']
5605 corr_type = [9]
5606 return(corr_type, corr_type_string, len(corr_type))
5608def MAD(a, c=0.6745, axis=0):
5609 """
5610 Median Absolute Deviation along given axis of an array:
5612 median(abs(a - median(a))) / c
5614 c = 0.6745 is the constant to convert from MAD to std; it is used by
5615 default
5616 """
5617 a = np.array(a)
5618 good = (a==a)
5619 a = np.asarray(a, np.float64)
5620 if a.ndim == 1:
5621 d = np.median(a[good])
5622 m = np.median(np.fabs(a[good] - d) / c)
5623 else:
5624 d = np.median(a[good], axis=axis)
5625 # I don't want the array to change so I have to copy it?
5626 if axis > 0:
5627 aswp = swapaxes(a[good],0,axis)
5628 else:
5629 aswp = a[good]
5630 m = np.median(np.fabs(aswp - d) / c, axis=0)
5632 return m
5634def showFinalMessage(overlayAntennas, solutionTimeSpread, nUniqueTimes):
5635 if (overlayAntennas and solutionTimeSpread > 0 and nUniqueTimes==1):
5636 print("If not all spws were shown, then try setting solutionTimeThreshold=%.0f seconds" % (solutionTimeSpread+1))
5638def computeOriginalSpwsToPlot(spwsToPlot, originalSpws, tableFormat, debug):
5639 if (tableFormat > 33):
5640 # New caltables use the same numbering as the original ms
5641 return(spwsToPlot)
5642 else:
5643 originalSpwsToPlot = []
5644 for spw in spwsToPlot:
5645 originalSpwsToPlot.append(originalSpws[spw])
5646 return(list(originalSpwsToPlot))
5648def computeScansForUniqueTimes(uniqueTimes, cal_scans, times, unique_cal_scans,
5649 debug=False):
5650 scansForUniqueTimes = []
5651 nUniqueTimes = len(uniqueTimes)
5652 for uT in uniqueTimes:
5653 if (debug): print("Checking uniqueTime = %s" % (str(uT)))
5654 scansForUniqueTimes.append(cal_scans[list(times).index(uT)])
5655 if (len(unique_cal_scans) == 1):
5656 if (unique_cal_scans[0] != -1):
5657 if (len(scansForUniqueTimes) != len(np.unique(scansForUniqueTimes))):
5658 if debug:
5659 print("Because there are multiple timestamps per scan, I will not assume there is a one-to-one match.")
5660 else:
5661 nUniqueTimes = len(np.unique(scansForUniqueTimes))
5662 else:
5663 # This 3.4 table does not have the scan numbers populated
5664 scansForUniqueTimes = []
5665 if debug:
5666 print("Because the scan numbers are either not filled in this table, or the solutions span multiple scans, I will use timestamps instead.")
5667 else:
5668 if (len(scansForUniqueTimes) != len(np.unique(scansForUniqueTimes))):
5669 if debug:
5670 print("Because there are multiple timestamps per scan, I will not assume there is a one-to-one match.")
5671 else:
5672 nUniqueTimes = len(np.unique(scansForUniqueTimes))
5673 return(scansForUniqueTimes, nUniqueTimes)
5676def calcChebyshev(coeff, validDomain, x):
5677 """
5678 Given a set of coefficients,
5679 this method evaluates a Chebyshev approximation.
5680 """
5681 if (type(x) == float or type(x) == int):
5682 x = [x]
5683 myxrange = validDomain[1] - validDomain[0]
5684 x = -1 + 2*(x-validDomain[0])/myxrange
5685 coeff[0] = 0
5686 if (True):
5687 try:
5688 # python 2.7
5689 v = np.polynomial.chebyshev.chebval(x,coeff)
5690 except:
5691 # python 2.6
5692 v = np.polynomial.chebval(x,coeff)
5693 else:
5694 # manual approach, before I found chebval()
5695 v = np.zeros(len(x))
5696 if (len(coeff) > 0):
5697 v += coeff[0] * 1
5698 if (len(coeff) > 1):
5699 v += coeff[1] * (x)
5700 if (len(coeff) > 2):
5701 v += coeff[2] * (2*x**2 - 1)
5702 if (len(coeff) > 3):
5703 v += coeff[3] * (4*x**3 - 3*x)
5704 if (len(coeff) > 4):
5705 v += coeff[4] * (8*x**4 - 8*x**2 + 1)
5706 if (len(coeff) > 5):
5707 v += coeff[5] * (16*x**5 - 20*x**3 + 5*x)
5708 if (len(coeff) > 6):
5709 v += coeff[6] * (32*x**6 - 48*x**4 + 18*x**2 - 1)
5710 if (len(coeff) > 7):
5711 v += coeff[7] * (64*x**7 -112*x**5 + 56*x**3 - 7*x)
5712 if (len(coeff) > 8):
5713 v += coeff[8] * (128*x**8 -256*x**6 +160*x**5 - 32*x**2 + 1)
5714 if (len(coeff) > 9):
5715 v += coeff[9] * (256*x**9 -576*x**7 +432*x**5 - 120*x**3 + 9*x)
5716 if (len(coeff) > 10):
5717 print("Chebyshev polynomials with degree > 10 are not implemented")
5719 return(v)
5721def ResizeFontsSetGrid(adesc,fontsize):
5722# print("Called ResizeFontsSetGrid()")
5723 yFormat = ScalarFormatter(useOffset=False)
5724 if adesc:
5725 adesc.yaxis.set_major_formatter(yFormat)
5726 adesc.xaxis.set_major_formatter(yFormat)
5727 pb.setp(adesc.get_xticklabels(), fontsize=fontsize)
5728 pb.setp(adesc.get_yticklabels(), fontsize=fontsize)
5729 adesc.xaxis.grid(True,which='major')
5730 adesc.yaxis.grid(True,which='major')
5732def complexMeanRad(phases):
5733 # convert back to real and imaginary, take mean, then convert back to phase
5734 meanSin = np.mean(np.sin(phases))
5735 meanCos = np.mean(np.cos(phases))
5736 return(180*np.arctan2(meanSin, meanCos)/math.pi)
5738def complexMeanDeg(phases):
5739 # convert back to real and imaginary, take mean, then convert back to phase
5740 phases *= math.pi/180
5741 meanSin = np.mean(np.sin(phases))
5742 meanCos = np.mean(np.cos(phases))
5743 return(180*np.arctan2(meanSin, meanCos)/math.pi)
5745def CalcAtmTransmission(chans,freqs,xaxis,pwv,vm, mymsmd,vis,asdm,antenna,timestamp,
5746 interval,field,refFreqInTable, net_sideband=0,
5747 mytime=0, missingCalWVRErrorPrinted=False, caltable='',
5748 Trx=None, showtsys=False, verbose=False):
5749 """
5750 chans: all channels, regardless of whether they are flagged
5751 freqs: frequencies corresponding to chans
5752 xaxis: what we are plotting on the xaxis: 'chan' or 'freq'
5753 """
5754# print("CalcAtm, field = ", field)
5755# print("interval = ", interval)
5756# print("refFreqInTable = ", refFreqInTable)
5757 if (type(mymsmd) == str):
5758 telescopeName = getTelescopeNameFromCaltable(caltable)
5759 else:
5760 telescopeName = mymsmd.observatorynames()[0]
5761 if (telescopeName.find('ALMA') >= 0):
5762 defaultPWV = 1.0 # a reasonable value for ALMA in case it cannot be found
5763 elif (telescopeName.find('VLA') >= 0):
5764 defaultPWV = 5.0
5765 else:
5766 defaultPWV = 5.0
5767 if (type(pwv) == str):
5768 if (pwv.find('auto')>=0):
5769 if (os.path.exists(vis+'/ASDM_CALWVR') or os.path.exists(vis+'/ASDM_CALATMOSPHERE') or
5770 os.path.exists('CalWVR.xml')):
5771 if (verbose):
5772 print("*** Computing atmospheric transmission using measured PWV, field %d, time %d (%f). ***" % (field,mytime,timestamp))
5773 timerange = [timestamp-interval/2, timestamp+interval/2]
5774 if (os.path.exists(vis+'/ASDM_CALWVR') or os.path.exists(vis+'/ASDM_CALATMOSPHERE')):
5775 [pwvmean, pwvstd] = getMedianPWV(vis,timerange,asdm,verbose=False)
5776 else:
5777 [pwvmean, pwvstd] = getMedianPWV('.',timerange,asdm='',verbose=False)
5778 if (verbose):
5779 print("retrieved pwvmean = %f" % pwvmean)
5780 retrievedPWV = pwvmean
5781 if (pwvmean < 0.00001):
5782 pwvmean = defaultPWV
5783 else:
5784 pwvmean = defaultPWV
5785 if (missingCalWVRErrorPrinted == False):
5786 missingCalWVRErrorPrinted = True
5787 if (telescopeName.find('ALMA')>=0):
5788 print("No ASDM_CALWVR, ASDM_CALATMOSPHERE, or CalWVR.xml table found. Using PWV %.1fmm." % pwvmean)
5789 else:
5790 print("This telescope has no WVR to provide a PWV measurement. Using PWV %.1fmm." % pwvmean)
5791 else:
5792 try:
5793 pwvmean = float(pwv)
5794 except:
5795 pwvmean = defaultPWV
5796 else:
5797 try:
5798 pwvmean = float(pwv)
5799 except:
5800 pwvmean = defaultPWV
5802 if (verbose):
5803 print("Using PWV = %.2f mm" % pwvmean)
5805 # default values in case we can't find them below
5806 myqa = quanta()
5807 airmass = 1.5
5808 P = 563.0
5809 H = 20.0
5810 T = 273.0
5811 roundedScanTimes = []
5812 if (type(mymsmd) != str):
5813 if (verbose):
5814 print("Looking for scans for field integer = %d" % (field))
5815 scans = mymsmd.scansforfield(field)
5816 if (verbose):
5817 print(("For field %s, Got scans = " % str(field),scans))
5818 for myscan in scans:
5819 roundedScanTimes.append(np.unique(np.round(mymsmd.timesforscan(myscan))))
5820# This method was much slower and not necessary. Removed for CAS-8065
5821# scantimes = mymsmd.timesforscans(scans) # is often longer than the scans array
5822# roundedScanTimes = np.unique(np.round(scantimes,0))
5823# 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)
5824# if (verbose): print("scantimes = %s" % (str(scantimes)))
5825# if (verbose): print("scans = %s" % (str(scans)))
5826 mindiff = 1e20
5827 bestscan = 1
5828 for i in range(len(roundedScanTimes)):
5829 stime = roundedScanTimes[i]
5830 meantime = np.mean(stime)
5831 tdiff = np.abs(meantime-timestamp)
5832 # if (verbose): print("tdiff = %s" % (str(tdiff)))
5833 if (tdiff < mindiff):
5834 bestscan = scans[i]
5835 if (verbose): print("bestscan = %s" % (str(bestscan)))
5836 mindiff = tdiff
5837 if (verbose):
5838 print("For timestamp=%.1f, got closest scan = %d, %.0f sec away" %(timestamp, bestscan,mindiff))
5839 if (verbose): print("Calling getWeather()")
5840 [conditions,myTimes] = getWeather(vis,bestscan,antenna,verbose,mymsmd)
5841 if (verbose): print("Done getWeather()")
5843 # convert pressure with unit to the value in mbar
5844 if (verbose): print("conditions = ", conditions)
5845 P = myqa.convert(myqa.quantity(conditions['pressure'], conditions['pressure_unit']), 'mbar')['value']
5846 if P < 100: ### added 2024Aug
5847 # then the units are wrong, as in early ALMA data had units="Pa" but value was in mbar
5848 P = conditions['pressure'] ### added 2024Aug
5849 casalogPost(verbose,"Ignoring pressure units '%s' because the value implied would be less than 100 mbar."%(conditions['pressure_unit'])) ### added 2024Aug
5850 H = conditions['humidity']
5851 T = conditions['temperature']+273.15
5852 if (P <= 0.0):
5853 P = 563
5854 if (H <= 0.0):
5855 H = 20
5856 else:
5857 conditions = {}
5858 if (type(mymsmd) != str):
5859 if ('elevation' not in list(conditions.keys())):
5860 # Someone cleared the POINTING table, so calculate elevation from Ra/Dec/MJD
5861# myfieldId = mymsmd.fieldsforname(mymsmd.fieldsforscan(bestscan))
5862 myfieldId = mymsmd.fieldsforscan(bestscan)[0]
5863 myscantime = np.mean(mymsmd.timesforscan(bestscan))
5864 mydirection = getRADecForField(vis, myfieldId, verbose)
5865 if (verbose):
5866 print("myfieldId = %s" % (str(myfieldId)))
5867 print("mydirection = %s" % (str(mydirection)))
5868 print("Scan = %d, time = %.1f, Field = %d, direction = %s" % (bestscan, myscantime, myfieldId, str(mydirection)))
5869 telescopeName = mymsmd.observatorynames()[0]
5870 if (len(telescopeName) < 1):
5871 telescopeName = 'ALMA'
5872 if verbose: ### added 2024Aug to prevent lots of spam to the terminal
5873 print("telescope = %s" % (telescopeName))
5874 myazel = computeAzElFromRADecMJD(mydirection, myscantime/86400., telescopeName)
5875 conditions['elevation'] = myazel[1] * 180/math.pi
5876 conditions['azimuth'] = myazel[0] * 180/math.pi
5877 if (verbose):
5878 print("Computed elevation = %.1f deg" % (conditions['elevation']))
5879 else:
5880 conditions['elevation'] = 45
5881 casalogPost(verbose,"Using 45 deg elevation since the actual value is unavailable.")
5882 bestscan = -1
5883 if (verbose):
5884 print("CalcAtm: found elevation=%f (airmass=%.3f) for scan: %s" % (conditions['elevation'],1/np.sin(conditions['elevation']*np.pi/180.), str(bestscan)))
5885 print("P,H,T = %f,%f,%f" % (P,H,T))
5886 if (conditions['elevation'] <= 3):
5887 print("Using 45 deg elevation instead")
5888 airmass = 1.0/math.cos(45*math.pi/180.)
5889 else:
5890 airmass = 1.0/math.cos((90-conditions['elevation'])*math.pi/180.)
5892 # get the elevation of the antenna
5893 geodetic_elevation = 5059
5894 if os.path.exists(os.path.join(vis, 'ANTENNA')):
5895 with sdutil.table_manager(os.path.join(vis, 'ANTENNA')) as tb:
5896 _X, _Y, _Z = (float(i) for i in tb.getcell('POSITION', antenna))
5897 geodetic_elevation = simutil.simutil().xyz2long(_X, _Y, _Z, 'WGS84')[2]
5898 if verbose:
5899 casalogPost(True,"computed geodetic_elevation from ANTENNA table as %s" % str(geodetic_elevation))
5901 tropical = 1
5902 midLatitudeSummer = 2
5903 midLatitudeWinter = 3
5904 numchan = len(freqs)
5905 # Set the reference freq to be the middle of the middle two channels
5906 reffreq=0.5*(freqs[numchan//2-1]+freqs[numchan//2])
5907 originalnumchan = numchan
5908 while (numchan > MAX_ATM_CALC_CHANNELS):
5909 numchan //= 2
5910# print("Reducing numchan to ", numchan)
5911 chans = list(range(0,originalnumchan,(originalnumchan//numchan)))
5913 chansep = (freqs[-1]-freqs[0])/(numchan-1)
5914 nbands = 1
5915 if (verbose): print("Opening casac.atmosphere()")
5916 myat = atmosphere()
5917 if (verbose): print("Opened")
5918 fCenter = myqa.quantity(reffreq,'GHz')
5919 fResolution = myqa.quantity(chansep,'GHz')
5920 fWidth = myqa.quantity(numchan*chansep,'GHz')
5921 h0 = 1.0 # km
5922 dP = 5.0 # mbar
5923 dPm = 1.1 # unitless ratio
5924# print(H, T, geodetic_elevation,P, midLatitudeWinter, maxAltitude, h0, dP, dPm)
5925 myat.initAtmProfile(humidity=H, temperature=myqa.quantity(T, "K"),
5926 altitude=myqa.quantity(geodetic_elevation, "m"),
5927 pressure=myqa.quantity(P, 'mbar'),
5928 atmType=midLatitudeWinter,
5929 h0=myqa.quantity(h0,"km"),
5930 maxAltitude=myqa.quantity(maxAltitude,"km"),
5931 dP=myqa.quantity(dP,"mbar"),
5932 dPm=dPm)
5933 myat.initSpectralWindow(nbands,fCenter,fWidth,fResolution)
5934 myat.setUserWH2O(myqa.quantity(pwvmean,'mm'))
5936# myat.setAirMass() # This does not affect the opacity, but it does effect TebbSky, so do it manually.
5938 n = myat.getNumChan()
5939 if (verbose): print("numchan = %s" % (str(n)))
5940 if ctsys.compare_version('<',[4,0,0]):
5941 dry = np.array(myat.getDryOpacitySpec(0)['dryOpacity'])
5942 wet = np.array(myat.getWetOpacitySpec(0)['wetOpacity'].value)
5943 TebbSky = []
5944 for chan in range(n): # do NOT use numchan here, use n
5945 TebbSky.append(myat.getTebbSky(nc=chan, spwid=0).value)
5946 TebbSky = np.array(TebbSky)
5947 # readback the values to be sure they got set
5948 #rf = myat.getRefFreq().value
5949 #cs = myat.getChanSep().value
5950 else: # casa >=4.0
5951 dry = np.array(myat.getDryOpacitySpec(0)[1])
5952 wet = np.array(myat.getWetOpacitySpec(0)[1]['value'])
5953 TebbSky = myat.getTebbSkySpec(spwid=0)[1]['value']
5954 # readback the values to be sure they got set
5955 #rf = myqa.convert(myat.getRefFreq(),'GHz')['value']
5956 #cs = myqa.convert(myat.getChanSep(),'GHz')['value']
5958 transmission = np.exp(-airmass*(wet+dry))
5959 TebbSky *= (1-np.exp(-airmass*(wet+dry)))/(1-np.exp(-wet-dry))
5961 if (refFreqInTable*1e-9>np.mean(freqs)):
5962 if ((net_sideband % 2) == 0):
5963 sense = 1
5964 else:
5965 sense = 2
5966 else:
5967 if ((net_sideband % 2) == 0):
5968 sense = 2
5969 else:
5970 sense = 1
5972 if (sense == 1):
5973 # The following looks right for LSB sense=1
5974 if (xaxis.find('chan')>=0):
5975 trans = np.zeros(len(transmission))
5976 Tebb = np.zeros(len(TebbSky))
5977 for i in range(len(transmission)):
5978 trans[i] = transmission[len(transmission)-1-i]
5979 Tebb[i] = TebbSky[len(TebbSky)-1-i]
5980 transmission = trans
5981 TebbSky = Tebb
5982 if showtsys:
5983 if Trx is None or Trx == 'auto':
5984 Trx = au.receiverTrxSpec(au.getBand(freqs[0]*1e9))
5985 Tsys = (Feff*TebbSky + (1.0-Feff)*Tamb + Trx) * ((1.0 + (1.0-SBGain)) / (Feff*np.exp(-airmass*(wet+dry))))
5986 else:
5987 Tsys = None
5989 # Be sure that number of frequencies matched number of transmission values - CAS-10123
5990 numchan = len(transmission)
5991 chans = list(range(len(transmission)))
5992 # Note that getChanFreq returns units of GHz, but use convert to be sure.
5993 startFreq = myqa.convert(myat.getChanFreq(0),'GHz')['value']
5994 endFreq = myqa.convert(myat.getChanFreq(numchan-1),'GHz')['value']
5995 # print("startFreq=%f endFreq=%f " % (startFreq, endFreq))
5996 freq = np.linspace(startFreq, endFreq, numchan)
5997# old method that fails on spws with an even number of channels, i.e. when the integer refchan
5998# is half a channel from the center of the span
5999# if sense == 2:
6000# freq = np.linspace(rf-((numchan-1)/2.)*chansepGHz, rf+((numchan-1)/2.)*chansepGHz, numchan)
6001# else:
6002# freq = np.linspace(rf+((numchan-1)/2.)*chansepGHz,
6003# rf-((numchan-1)/2.)*chansepGHz, numchan)
6004 # Therewas a 1-channel offset in CASA 5.0.x (CAS-10228), but it was fixed.
6005# if (ctsys.compare_version('<',[5,1,0])):
6006# freq += chansepGHz
6008 if (verbose): print("Done CalcAtmTransmission")
6009 return(freq, chans, transmission, pwvmean, airmass, TebbSky, missingCalWVRErrorPrinted)
6011def RescaleTrans(trans, lim, subplotRows, lo1='', xframe=0):
6012 # Input: the array of transmission or TebbSky values and current limits
6013 # Returns: arrays of the rescaled transmission values and the zero point
6014 # values in units of the frame, and in amplitude.
6015 debug = False
6016 yrange = lim[1]-lim[0]
6017 if (lo1 == ''):
6018 labelgap = 0.6 # Use this fraction of the margin for the PWV ATM label
6019 else:
6020 labelgap = 0.5 # Use this fraction of the margin to separate the top
6021 # curve from the upper y-axis
6022 y2 = lim[1] - labelgap*yrange*TOP_MARGIN/(1.0+TOP_MARGIN)
6023 y1 = lim[1] - yrange*TOP_MARGIN/(1.0+TOP_MARGIN)
6024 transmissionRange = np.max(trans)-np.min(trans)
6025 if (transmissionRange < 0.05):
6026 # force there to be a minimum range of transmission display
6027 # overemphasize tiny ozone lines
6028 transmissionRange = 0.05
6030 if (transmissionRange > 1 and transmissionRange < 10):
6031 # force there to be a minimum range of Tebbsky (10K) to display
6032 transmissionRange = 10
6034 # convert transmission to amplitude
6035 newtrans = y2 - (y2-y1)*(np.max(trans)-trans)/transmissionRange
6037 # Use edge values
6038 edgeValueTransmission = trans[-1]
6039 otherEdgeValueTransmission = trans[0]
6041 # Now convert the edge channels' transmission values into amplitude
6042 edgeValueAmplitude = y2 - (y2-y1)*(np.max(trans)-trans[-1])/transmissionRange
6043 otherEdgeValueAmplitude = y2 - (y2-y1)*(np.max(trans)-trans[0])/transmissionRange
6045 # Now convert amplitude to frame units, offsetting downward by half
6046 # the font size
6047 fontoffset = 0.01*subplotRows
6048 edgeValueFrame = (edgeValueAmplitude - lim[0])/yrange - fontoffset
6049 otherEdgeValueFrame = (otherEdgeValueAmplitude - lim[0])/yrange - fontoffset
6051 # scaleFactor is how large the plot is from the bottom x-axis
6052 # up to the labelgap, in units of the transmissionRange
6053 scaleFactor = (1+TOP_MARGIN*(1-labelgap)) / (TOP_MARGIN*(1-labelgap))
6055 # compute the transmission at the bottom of the plot, and label it
6056 y0transmission = np.max(trans) - transmissionRange*scaleFactor
6057 y0transmissionFrame = 0
6058 y0transmissionAmplitude = lim[0]
6060 if (y0transmission <= 0):
6061 # If the bottom of the plot is below zero transmission, then label
6062 # the location of zero transmission instead.
6063 if (debug):
6064 print("--------- y0transmission original = %f, (y1,y2)=(%f,%f)" % (y0transmission,y1,y2))
6065 y0transmissionAmplitude = y1-(y2-y1)*(np.min(trans)/transmissionRange)
6066 y0transmissionFrame = (y0transmissionAmplitude-lim[0]) / (lim[1]-lim[0])
6067 y0transmission = 0
6068 if (debug):
6069 print("-------- xframe=%d, scaleFactor = %s" % (xframe, str(scaleFactor)))
6070 print("edgeValueFrame, other = %s, %s" % (str(edgeValueFrame), str(otherEdgeValueFrame)))
6071 print("edgeValueTransmission, other = %s, %s" % (str(edgeValueTransmission), str(otherEdgeValueTransmission)))
6072 print("edgeValueAmplitude, otherEdgeValueAmplitude = %s, %s" % (str(edgeValueAmplitude), str(otherEdgeValueAmplitude)))
6073 print("y0transmission = %f, y0transmissionFrame = %f" % (y0transmission,y0transmissionFrame))
6074 print("y0transmissionAmplitude = %s" % (str(y0transmissionAmplitude)))
6075 print("transmissionRange = %s" % (str(transmissionRange)))
6076 return(newtrans, edgeValueFrame, y0transmission, y0transmissionFrame,
6077 otherEdgeValueFrame, edgeValueTransmission,
6078 otherEdgeValueTransmission, edgeValueAmplitude,
6079 otherEdgeValueAmplitude, y0transmissionAmplitude)
6081def RescaleX(chans, lim, plotrange, channels):
6082 # This function is now only used by DrawAtmosphere when xaxis='chan'.
6083 # It is only really necessary when len(chans)>MAX_ATM_CALC_CHANNELS.
6084 # - September 2012
6085 # If the user specified a plotrange, then rescale to this range,
6086 # otherwise rescale to the automatically-determined range.
6088 # chans = 0..N where N=number of channels in the ATM_CALC
6089 # channels = 0..X where X=number of channels in the spw, regardless of flagging
6091 if (len(chans) != len(channels)):
6092 if (chans[1] > chans[0]):
6093 atmchanrange = chans[-1]-chans[0]
6094 else:
6095 atmchanrange = chans[0]-chans[-1]
6096 if len(channels) == 0: ### added 2024Aug to prevent crash
6097 return(chans) ### added 2024Aug to prevent crash
6098 if (channels[1] > channels[0]):
6099 chanrange = channels[-1]-channels[0]
6100 else:
6101 chanrange = channels[0]-channels[-1]
6103 newchans = np.array(chans)*chanrange/atmchanrange
6104 return(newchans)
6105 else:
6106 return(chans)
6108def recalcYlimitsFreq(chanrange, ylimits, amp, sideband,plotrange,xchannels,
6109 debug=False,location=0,chanrangePercent=None):
6110 # Used by plots with xaxis='freq'
6111 # xchannels are the actual channel numbers of unflagged data, i.e. displayed points
6112 # amp is actual data plotted
6113 ylim_debug = False
6114 if (len(amp) < 1):
6115 return(pb.ylim()) # ylimits)
6116 if (chanrange[0]==0 and chanrange[1] == 0 and plotrange[2] == 0 and plotrange[3]==0
6117 and chanrangePercent == None):
6118 if (len(amp) == 1):
6119 if (ylim_debug):
6120 print("amp = %s" % (str(amp)))
6121 ylimits = [amp[0]-0.2, amp[0]+0.2]
6122 else:
6123 newmin = np.min(amp)
6124 newmax = np.max(amp)
6125 newmin = np.min([ylimits[0],newmin])
6126 newmax = np.max([ylimits[1],newmax])
6127 ylimits = [newmin, newmax]
6128 elif ((abs(chanrange[0]) > 0 or abs(chanrange[1]) > 0)):
6129 plottedChannels = np.intersect1d(xchannels, list(range(chanrange[0],chanrange[1]+1)))
6130 if (len(plottedChannels) < 1):
6131 return(ylimits)
6132 mylist = np.arange(xchannels.index(plottedChannels[0]), 1+xchannels.index(plottedChannels[-1]))
6133 if (mylist[-1] >= len(amp)):
6134 # prevent crash if many channels are flagged
6135 return(ylimits)
6136 if (ylim_debug):
6137 print("Starting with limits = %s" % (str(ylimits)))
6138 print("Examining channels: %s" % (str(mylist)))
6139 print("len(amp): %d" % (len(amp)))
6140 print("Examining values: amp[mylist] = %s" % (str(amp[mylist])))
6141 newmin = np.min(amp[mylist])
6142 newmax = np.max(amp[mylist])
6143 newmin = np.min([ylimits[0],newmin])
6144 newmax = np.max([ylimits[1],newmax])
6145 # The following presents a problem with overlays, as it keeps widening forever
6146# # newmin -= 0.05*(newmax-newmin)
6147# # newmax += 0.05*(newmax-newmin)
6148 ylimits = [newmin, newmax]
6149 elif (chanrangePercent != None):
6150 startFraction = (100-chanrangePercent)*0.5*0.01
6151 stopFraction = 1-(100-chanrangePercent)*0.5*0.01
6152 if (xchannels == []):
6153 # prevent crash if many channels are flagged: 2015-04-13
6154 return(ylimits)
6155 cr0 = int(np.round(np.max(xchannels)*startFraction))
6156 cr1 = int(np.round(np.max(xchannels)*stopFraction))
6157 plottedChannels = np.intersect1d(xchannels, list(range(cr0, cr1+1)))
6158 if (len(plottedChannels) < 1):
6159 return(ylimits)
6160 mylist = np.arange(xchannels.index(plottedChannels[0]), 1+xchannels.index(plottedChannels[-1]))
6161 if (mylist[-1] >= len(amp)):
6162 # prevent crash if many channels are flagged
6163 return(ylimits)
6164 if (ylim_debug):
6165 print("Starting with limits = ", ylimits)
6166 print("Examining channels: ", mylist)
6167 print("len(amp): %d" % (len(amp)))
6168 print("type(amp) = %s" % (str(type(amp))))
6169 print("Examining values: amp[mylist] = %s" % (str(amp[mylist])))
6170 newmin = np.min(amp[mylist])
6171 newmax = np.max(amp[mylist])
6172 newmin = np.min([ylimits[0],newmin])
6173 newmax = np.max([ylimits[1],newmax])
6174 ylimits = [newmin, newmax]
6175 if (ylim_debug):
6176 print("Returning with limits = %s" % (str(ylimits)))
6177 return ylimits
6179def recalcYlimits(plotrange, ylimits, amp):
6180 # Used by plots with xaxis='chan'
6181 if (len(amp) < 1):
6182 return(pb.ylim())
6183 if ((abs(plotrange[0]) > 0 or abs(plotrange[1]) > 0) and (plotrange[2] == 0 and plotrange[3] == 0)):
6184 x0 = int(plotrange[0])
6185 x1 = int(plotrange[1])
6186 if (x0 < 0):
6187 x0 = 0
6188 if (x1 > len(amp)-1):
6189 x1 = len(amp)-1
6190 if (len(amp) > x1 and x0 < x1):
6191 newmin = np.min(amp[x0:x1])
6192 newmax = np.max(amp[x0:x1])
6193 newmin = np.min([ylimits[0],newmin])
6194 newmax = np.max([ylimits[1],newmax])
6195 ylimits = [newmin, newmax]
6196 else:
6197 ylimits = pb.ylim() # added on 10/27/2011
6198# # print("current ylimits = ", ylimits)
6199 return(ylimits)
6201def SetNewYLimits(newylimits):
6202# print("Entered SetNewYLimits with ", newylimits )
6203 newrange = newylimits[1]-newylimits[0]
6204 if (newrange > 0):
6205 pb.ylim([newylimits[0]-0.0*newrange, newylimits[1]+0.0*newrange])
6207def SetNewXLimits(newxlimits, loc=0):
6208# print("loc=%d: Entered SetNewXLimits with range = %.3f (%f-%f)" % (loc,np.max(newxlimits)-np.min(newxlimits), newxlimits[0], newxlimits[1]))
6209 myxrange = np.abs(newxlimits[1]-newxlimits[0])
6210 if (myxrange == 0):
6211 myxrange = 0.001
6212 mybuffer = 0.01
6213 if (newxlimits[0] < newxlimits[1]):
6214 pb.xlim([newxlimits[0]-myxrange*mybuffer,newxlimits[1]+myxrange*mybuffer] )
6215 else:
6216# print("Swapping xlimits order")
6217 pb.xlim(newxlimits[1]-myxrange*mybuffer, newxlimits[0]+myxrange*mybuffer)
6219def sloppyMatch(newvalue, mylist, threshold, mytime=None, scansToPlot=[],
6220 scansForUniqueTimes=[], myprint=False, whichone=False):
6221 """
6222 If scan numbers are present, perform an exact match, otherwise compare the
6223 time stamps of the solutions.
6224 """
6225 debug = myprint
6226 if (debug):
6227 print("sloppyMatch: scansToPlot = %s" % (str(scansToPlot)))
6228 mymatch = None
6229 if (len(scansToPlot) > 0):
6230 if (mytime >= len(scansForUniqueTimes)):
6231 print("sloppyMatch() mytime is too large: mytime=%d >= len(scansForUniqueTimes)=%d: " % (mytime, len(scansForUniqueTimes)), scansForUniqueTimes)
6232 matched = scansForUniqueTimes[mytime] in scansToPlot
6233 if (whichone or myprint):
6234 myscan = scansForUniqueTimes[mytime]
6235 if (myscan in scansToPlot):
6236 mymatch = list(scansToPlot).index(myscan)
6237 if (matched == False and myprint==True):
6238 print("sloppyMatch: %d is not in %s" % (myscan, list(scansToPlot)))
6239 elif (myprint==True):
6240 print("sloppyMatch: %d is in %s" % (myscan, list(scansToPlot)))
6241 else:
6242 matched = False
6243 if (type(mylist) != list and type(mylist)!=np.ndarray):
6244 mylist = [mylist]
6245 mymatch = -1
6246 for i in range(len(mylist)):
6247 v = mylist[i]
6248 if (abs(newvalue-v) < threshold):
6249 matched = True
6250 mymatch = i
6251 if (matched == False and myprint==True):
6252 print("sloppyMatch: %.0f is not within %.0f of anything in %s" % (newvalue,threshold, str([int(round(b)) for b in mylist])))
6253 elif (myprint==True):
6254 print("sloppyMatch: %.0f is within %.0f of something in %s" % (newvalue,threshold, str([int(round(b)) for b in mylist])))
6255 if (whichone == False):
6256 return(matched)
6257 else:
6258 return(matched,mymatch)
6260# replacement function with extra optional parameter added on 2024Aug
6261def sloppyUnique(t, thresholdSeconds, cal_scans=None):
6262 """
6263 Takes a list of numbers and returns a list of unique values, subject
6264 to a threshold difference.
6265 cal_scans: if specified, then perform the analysis per scan number
6266 """
6267 # start with the first entry (t[0]), and only add a new entry if it is more than the threshold from prior
6268 if cal_scans is None:
6269 sloppyList = [t[0]]
6270 for i in range(1,len(t)):
6271 keepit = True
6272 # for j in range(0,i): # prior to PIPE-1519
6273 # if (abs(t[i]-t[j]) < thresholdSeconds):
6274 for j in range(len(sloppyList)):
6275 if (abs(t[i]-sloppyList[j]) < thresholdSeconds):
6276 keepit = False
6277 if (keepit):
6278 sloppyList.append(t[i])
6279 else:
6280 # build a list of one time per calibration scan
6281 uniqueCalScans = np.unique(cal_scans)
6282 t = np.array(t)
6283 sloppyList = []
6284# print("len(t) = %d, len(cal_scans) = %d" % (len(t),len(cal_scans)))
6285 for k,calscan in enumerate(uniqueCalScans):
6286 times = t[np.where(calscan == cal_scans)]
6287 sloppyList.append(times[0])
6288# print "sloppyUnique returns %d values from the original %d" % (len(sloppyList), len(t))
6289 return(sloppyList)
6291# commented out 2024Aug
6292#def sloppyUnique(t, thresholdSeconds):
6293# """
6294# Takes a list of numbers and returns a list of unique values, subject to a threshold difference.
6295# """
6296# # start with the first entry, and only add a new entry if it is more than the threshold from prior
6297# sloppyList = [t[0]]
6298# for i in range(1,len(t)):
6299# keepit = True
6300# for j in range(0,i):
6301# if (abs(t[i]-t[j]) < thresholdSeconds):
6302# keepit = False
6303# if (keepit):
6304# sloppyList.append(t[i])
6305## print("sloppyUnique returns %d values from the original %d" % (len(sloppyList), len(t)))
6306# return(sloppyList)
6308def SetLimits(plotrange, chanrange, newylimits, channels, frequencies, pfrequencies,
6309 ampMin, ampMax, xaxis, pxl, chanrangeSetXrange, chanrangePercent=None):
6310 """
6311 This is the place where chanrange actually takes effect.
6312 """
6313 if (abs(plotrange[0]) > 0 or abs(plotrange[1]) > 0):
6314 SetNewXLimits([plotrange[0],plotrange[1]])
6315 if (plotrange[2] == 0 and plotrange[3] == 0):
6316 # reset the ylimits based on the channel range shown (selected via plotrange)
6317 SetNewYLimits(newylimits)
6318 else: # set xlimits to full range
6319 if (xaxis.find('chan')>=0):
6320 SetNewXLimits([channels[0],channels[-1]])
6321 else:
6322 if (chanrangeSetXrange or (chanrange[0]==0 and chanrange[1]==0 and chanrangePercent==None)): # CAS-7965
6323 # print("SetLimits(): Setting x limits to full range (%f-%f)" % (frequencies[0], frequencies[-1]))
6324 SetNewXLimits([frequencies[0], frequencies[-1]])
6325 if (chanrange[0] != 0 or chanrange[1] != 0 or chanrangePercent != None):
6326 # reset the ylimits based on the channel range specified (selected via chanrange)
6327 if (newylimits != [LARGE_POSITIVE, LARGE_NEGATIVE]):
6328 SetNewYLimits(newylimits)
6329# print("pxl=%d, chanrange[0]=%d, chanrange[1]=%d, shape(pfreq), shape(freq)=" % (pxl, chanrange[0], chanrange[1]), np.shape(pfrequencies),np.shape(frequencies))
6330 # Use frequencies instead of pfrequencies, because frequencies are not flagged and
6331 # will continue to work if chanranze is specified and data are flagged.
6332 if chanrangeSetXrange:
6333 if (chanrangePercent == None):
6334 try:
6335 SetNewXLimits([frequencies[chanrange[0]], frequencies[chanrange[1]]]) # Apr 3, 2012
6336 except:
6337 print("a)Invalid chanrange (%d-%d). Valid range = 0-%d" % (chanrange[0],chanrange[1],len(frequencies)-1))
6338 return(-1)
6339 else:
6340 startFraction = (100-chanrangePercent)*0.5*0.01
6341 stopFraction = 1-(100-chanrangePercent)*0.5*0.01
6342 cr0 = int(np.round(np.max(channels)*startFraction))
6343 cr1 = int(np.round(np.max(channels)*stopFraction))
6344 try:
6345 SetNewXLimits([frequencies[cr0], frequencies[cr1]])
6346 except:
6347 print("b)Invalid chanrange (%d-%d). Valid range = 0-%d" % (cr0,cr1,len(frequencies)-1))
6348 return(-1)
6349 if (abs(plotrange[2]) > 0 or abs(plotrange[3]) > 0):
6350 SetNewYLimits([plotrange[2],plotrange[3]])
6351 return(0)
6353def showFDM(originalSpw, chanFreqGHz, baseband, showBasebandNumber, basebandDict, overlayColors):
6354 """
6355 Draws a horizontal bar indicating the location of FDM spws in the dataset.
6357 Still need to limit based on the baseband -- need dictionary passed in.
6358 originalSpw: should contain all spws in the dataset, not just the ones
6359 in the caltable
6360 baseband: the baseband of the current spw
6361 showBasebandNumber: force the display of all FDM spws, and their baseband number
6362 basebandDict: {1:[17,19], 2:[21,23], etc.} or {} for really old datasets
6363 """
6365 # add some space at the bottom -- Apr 25, 2012
6366 ylim = pb.ylim()
6367 yrange = ylim[1]-ylim[0]
6368 pb.ylim([ylim[0]-BOTTOM_MARGIN*yrange, ylim[1]])
6370 sdebug = False
6371 if (sdebug):
6372 print(("Showing FDM (%d)" % (len(originalSpw)), originalSpw))
6373 print("baseband = %d, basebandDict = %s" % (baseband, str(basebandDict)))
6374 fdmctr = -1
6375 x0,x1 = pb.xlim()
6376 y0,y1 = pb.ylim()
6377 yrange = y1 - y0
6378 myxrange = x1 - x0
6379 labelAbove = False # False means label to the right
6380 for i in range(len(originalSpw)):
6381 nchan = len(chanFreqGHz[i])
6382 # latter 3 values are for ACA with FPS enabled
6383 if (nchan >= 15 and nchan not in [256,128,64,32,16,248,124,62]):
6384 if (originalSpw[i] in basebandDict[baseband] or showBasebandNumber):
6385 fdmctr += 1
6386 verticalOffset = fdmctr*0.04*yrange
6387 y1a = y0 + 0.03*yrange + verticalOffset
6388 if (labelAbove):
6389 y2 = y1a + 0.01*yrange
6390 else:
6391 y2 = y1a - 0.016*yrange
6392# print("chan=%d: Drawing line at y=%f (y0=%f) from x=%f to %f" % (len(chanFreqGHz[i]),
6393# y1a,y0,chanFreqGHz[i][0], chanFreqGHz[i][-1]))
6394 f0 = chanFreqGHz[i][0]
6395 f1 = chanFreqGHz[i][-1]
6396 if (f1 < f0):
6397 swap = f1
6398 f1 = f0
6399 f0 = swap
6400 v0 = np.max([f0,x0])
6401 v1 = np.min([f1,x1])
6402 if (v1 > v0):
6403 if (labelAbove):
6404 xlabel = 0.5*(v0+v1)
6405 if (xlabel < x0):
6406 xlabel = x0
6407 if (xlabel > x1):
6408 xlabel = x1
6409 else:
6410 xlabel = v1+0.02*myxrange
6411 pb.plot([v0,v1], [y1a,y1a], '-',
6412 linewidth=4, color=overlayColors[fdmctr],markeredgewidth=markeredgewidth)
6413 if (showBasebandNumber):
6414 mybaseband = [key for key in basebandDict if i in basebandDict[key]]
6415 if (len(mybaseband) > 0):
6416 pb.text(xlabel, y2, "spw%d(bb%d)"%(i,mybaseband[0]), size=7)
6417 else:
6418 pb.text(xlabel, y2, "spw%d(bb?)"%(i), size=7)
6419 else:
6420 pb.text(xlabel, y2, "spw%d"%(i), size=7)
6421 if (sdebug): print("Plotting spw %d (%d)" % (i, originalSpw[i]))
6422 else:
6423 if (sdebug): print("Not plotting spw %d (%d) because %f < %f" % (i,originalSpw[i],v0,v1))
6424 else:
6425 if (sdebug): print("Not plotting spw %d (%d) because it is not in baseband %d (%s)" % (i,originalSpw[i],baseband,basebandDict[baseband]))
6426 else:
6427 if (sdebug): print("Not plotting spw %d (%d) because fewer than 256 channels (%d)" % (i,originalSpw[i],nchan))
6428 if (fdmctr > -1):
6429 pb.ylim([y0,y1])
6430 pb.xlim([x0,x1])
6432def DrawAtmosphere(showatm, showtsky, subplotRows, atmString, mysize,
6433 TebbSky, plotrange, xaxis, atmchan, atmfreq, transmission,
6434 subplotCols, lo1='', xframe=0, firstFrame=0,
6435 showatmPoints=False, channels=[0], mylineno=-1,xant=-1,
6436 overlaySpws=False, overlayBasebands=False, drewAtmosphere=False,
6437 loc=-1, showtsys=False, Trx=None):
6438 """
6439 Draws atmospheric transmission or Tsky on an amplitude vs. chan or freq plot.
6440 """
6441 xlim = pb.xlim()
6442 ylim = pb.ylim()
6443 myxrange = xlim[1]-xlim[0]
6444 yrange = ylim[1]-ylim[0]
6446 if (not drewAtmosphere and not overlayBasebands): # CAS-8489 final
6447 if (lo1 == ''):
6448 # add some space at the top -- Apr 16, 2012
6449 pb.ylim([ylim[0], ylim[1]+TOP_MARGIN*yrange])
6450 else:
6451 pb.ylim([ylim[0], ylim[1]+TOP_MARGIN*yrange*0.5])
6452 ylim = pb.ylim()
6453 yrange = ylim[1]-ylim[0]
6454 #
6455 ystartPolLabel = 1.0-0.04*subplotRows
6456 if (lo1 == ''):
6457 transmissionColor = 'm'
6458 tskyColor = 'm'
6459 else:
6460 transmissionColor = 'k'
6461 tskyColor = 'k'
6462 if (showatmPoints):
6463 atmline = '.'
6464 else:
6465 atmline = '-'
6466 if (showatm or showtsky):
6467 if (showatm):
6468 atmcolor = transmissionColor
6469 else:
6470 atmcolor = tskyColor
6471 if (lo1 == '' and not drewAtmosphere):
6472 pb.text(0.25, ystartPolLabel, atmString, color=atmcolor, size=mysize, transform=pb.gca().transAxes)
6474 if (showtsky):
6475 if showtsys:
6476 rescaledY = TebbSky
6477 if Trx == 'auto':
6478 scaleFactor = np.mean([ylim[1]-np.max(TebbSky), ylim[0]-np.min(TebbSky)])
6479 scaleFactor = 0.5*(ylim[1]+ylim[0]) - np.mean(TebbSky)
6480 rescaledY += scaleFactor
6481 else:
6482 rescaledY, edgeYvalue, zeroValue, zeroYValue, otherEdgeYvalue, edgeT, otherEdgeT, edgeValueAmplitude, otherEdgeValueAmplitude, zeroValueAmplitude = RescaleTrans(TebbSky, ylim, subplotRows, lo1, xframe)
6484 else:
6485 rescaledY, edgeYvalue, zeroValue, zeroYValue, otherEdgeYvalue, edgeT, otherEdgeT, edgeValueAmplitude, otherEdgeValueAmplitude, zeroValueAmplitude = RescaleTrans(transmission, ylim, subplotRows, lo1, xframe)
6486 if (overlayBasebands and xaxis.find('freq')>=0):
6487 # use axis coordinates for y-axis only so that transmission can be on common scale
6488 trans = matplotlib.transforms.blended_transform_factory(pb.gca().transData, pb.gca().transAxes)
6489 if showtsky:
6490 pb.plot(atmfreq, TebbSky/300., '%s%s'%(atmcolor,atmline),
6491 markeredgewidth=markeredgewidth, transform=trans)
6492 else:
6493 pb.plot(atmfreq, transmission, '%s%s'%(atmcolor,atmline),
6494 markeredgewidth=markeredgewidth, transform=trans)
6495 if (atmfreq[0]<atmfreq[1]):
6496 tindex = -1
6497 else:
6498 tindex = 0
6499 else:
6500 # use user coordinates
6501 if (xaxis.find('chan')>=0):
6502 rescaledX = RescaleX(atmchan, xlim, plotrange, channels)
6503 # rescaledX = atmchan
6504 pb.plot(rescaledX, rescaledY,'%s%s'%(atmcolor,atmline),markeredgewidth=markeredgewidth)
6505 tindex = -1
6506 elif (xaxis.find('freq')>=0):
6507 pb.plot(atmfreq, rescaledY, '%s%s'%(atmcolor,atmline),markeredgewidth=markeredgewidth)
6508 if (atmfreq[0]<atmfreq[1]):
6509 tindex = -1
6510 else:
6511 tindex = 0
6512 if (lo1 == ''):
6513 xEdgeLabel = 1.01
6514 else:
6515 if (xframe == firstFrame):
6516 xEdgeLabel = -0.10*subplotCols # avoids overwriting y-axis label
6517 else:
6518 xEdgeLabel = -0.10*subplotCols
6519 SetNewXLimits(xlim) # necessary for zoom='intersect'
6520 if (not overlayBasebands): # CAS-8489 final
6521 SetNewYLimits(ylim)
6522 # Now draw the percentage on right edge of plot
6523 if (not drewAtmosphere):
6524 if (overlayBasebands and xaxis.find('freq')>=0): # CAS-8489 final
6525 trans = matplotlib.transforms.blended_transform_factory(pb.gca().transData, pb.gca().transAxes)
6526 zeroValue = 0
6527 zeroValueAmplitude = 0
6528 edgeValueAmplitude = 1
6529 if (showtsky):
6530 edgeT = 300
6531 if (lo1 == ''):
6532 pb.text(xlim[1]+0.06*myxrange/subplotCols, edgeValueAmplitude,
6533 '%.0fK'%(edgeT), color=atmcolor, size=mysize, transform=trans)
6534 pb.text(xlim[1]+0.06*myxrange/subplotCols, zeroValueAmplitude,
6535 '%.0fK'%(zeroValue), color=atmcolor, transform=trans,
6536 size=mysize)
6537 else:
6538 pb.text(xEdgeLabel, edgeValueAmplitude,'%.0fK'%(edgeT),
6539 color=atmcolor,
6540 size=mysize, transform=pb.gca().transAxes)
6541 pb.text(xEdgeLabel, zeroValueAmplitude,'%.0fK'%(zeroValue),
6542 color=atmcolor,
6543 size=mysize, transform=pb.gca().transAxes)
6544 else:
6545 # showatm=True
6546 edgeT = 1
6547 if (lo1 == ''):
6548 pb.text(xlim[1]+0.05*myxrange/subplotCols, edgeValueAmplitude,
6549 '%.0f%%'%(edgeT*100), color=atmcolor, size=mysize,
6550 transform=trans, va='center')
6551 pb.text(xlim[1]+0.05*myxrange/subplotCols, zeroValueAmplitude,
6552 '%.0f%%'%(zeroValue*100), color=atmcolor, transform=trans,
6553 size=mysize, va='center')
6554 else:
6555 pb.text(xEdgeLabel, edgeValueAmplitude,'%.0f%%'%(edgeT*100),
6556 color=atmcolor, va='center',
6557 size=mysize, transform=pb.gca().transAxes)
6558 pb.text(xEdgeLabel, zeroValueAmplitude,'%.0f%%'%(zeroValue*100),
6559 color=atmcolor, va='center',
6560 size=mysize, transform=pb.gca().transAxes)
6561 elif not showtsys:
6562 if (showtsky):
6563 if (lo1 == ''):
6564 # This must be done in user coordinates since another curve
6565 # is plotted following this one.
6566 pb.text(xlim[1]+0.06*myxrange/subplotCols, edgeValueAmplitude,
6567 '%.0fK'%(edgeT), color=atmcolor, size=mysize)
6568 pb.text(xlim[1]+0.06*myxrange/subplotCols, zeroValueAmplitude,
6569 '%.0fK'%(zeroValue), color=atmcolor,
6570 size=mysize)
6571 else:
6572 # This can remain in axes units since it is the final plot.
6573 pb.text(xEdgeLabel, otherEdgeYvalue,'%.0fK'%(otherEdgeT),
6574 color=atmcolor,
6575 size=mysize, transform=pb.gca().transAxes)
6576 pb.text(xEdgeLabel, zeroYValue,'%.0fK'%(zeroValue),
6577 color=atmcolor,
6578 size=mysize, transform=pb.gca().transAxes)
6579 else:
6580 # showatm=True
6581 if (lo1 == ''):
6582 # This must be done in user coordinates since another curve
6583 # is plotted following this one.
6584 pb.text(xlim[1]+0.05*myxrange/subplotCols, edgeValueAmplitude,
6585 '%.0f%%'%(edgeT*100), color=atmcolor, size=mysize)
6586 pb.text(xlim[1]+0.05*myxrange/subplotCols, zeroValueAmplitude,
6587 '%.0f%%'%(zeroValue*100), color=atmcolor,
6588 size=mysize)
6589 else:
6590 # This can remain in axes units since it is the final plot.
6591 pb.text(xEdgeLabel, otherEdgeYvalue,'%.0f%%'%(otherEdgeT*100),
6592 color=atmcolor,
6593 size=mysize, transform=pb.gca().transAxes)
6594 pb.text(xEdgeLabel, zeroYValue,'%.0f%%'%(zeroValue*100),
6595 color=atmcolor,
6596 size=mysize, transform=pb.gca().transAxes)
6597 if (lo1 != ''):
6598 if (xframe == firstFrame):
6599 pb.text(+1.04-0.04*subplotCols, -0.07*subplotRows,
6600 'Signal SB', color='m', size=mysize,
6601 transform=pb.gca().transAxes)
6602 pb.text(-0.03-0.08*subplotCols, -0.07*subplotRows,
6603 'Image SB', color='k', size=mysize,
6604 transform=pb.gca().transAxes)
6605# pb.text(+0.96-0.08*subplotCols, -0.07*subplotRows,
6606# 'Signal Sideband', color='m', size=mysize,
6607# transform=pb.gca().transAxes)
6608# pb.text(-0.08*subplotCols, -0.07*subplotRows,
6609# 'Image Sideband', color='k', size=mysize,
6610# transform=pb.gca().transAxes)
6611 return ylim # CAS-8655
6613def DrawBottomLegendPageCoords(msName, uniqueTimesMytime, mysize, figfile):
6614 msName = msName.split('/')[-1]
6615 bottomLegend = msName + ' ObsDate=' + utdatestring(uniqueTimesMytime)
6616 if (os.path.basename(figfile).find('regression') == 0):
6617 regression = True
6618 else:
6619 regression = False
6620 if (regression == False):
6621 bottomLegend += ' plotbandpass v' \
6622 + PLOTBANDPASS_REVISION_STRING.split()[2] + ' = ' \
6623 + PLOTBANDPASS_REVISION_STRING.split()[3] + ' ' \
6624 + PLOTBANDPASS_REVISION_STRING.split()[4]
6625# The following should be used going forward, as it is better for long VLA names
6626 pb.text(0.04, 0.02, bottomLegend, size=mysize, transform=pb.gcf().transFigure)
6627# pb.text(0.1, 0.02, bottomLegend, size=mysize, transform=pb.gcf().transFigure)
6629def DrawAntennaNames(msAnt, antennasToPlot, msFound, mysize, overlayColors):
6630 for a in range(len(antennasToPlot)):
6631 if (msFound):
6632 legendString = msAnt[antennasToPlot[a]]
6633 else:
6634 legendString = str(antennasToPlot[a])
6635 if (a<maxAntennaNamesAcrossTheTop):
6636 x0 = xstartTitle+(a*antennaHorizontalSpacing)
6637 y0 = ystartOverlayLegend
6638 else:
6639 # start going down the righthand side
6640 x0 = xstartTitle+(maxAntennaNamesAcrossTheTop*antennaHorizontalSpacing)
6641 y0 = ystartOverlayLegend-(a-maxAntennaNamesAcrossTheTop)*antennaVerticalSpacing
6642 pb.text(x0, y0, legendString,color=overlayColors[a],fontsize=mysize,
6643 transform=pb.gcf().transFigure)
6645def stdInfo(a, sigma=3, edge=0, spw=-1, xant=-1, pol=-1):
6646 """
6647 Computes the standard deviation of a list, then returns the value, plus the
6648 number and list of channels that exceed sigma*std, and the worst outlier.
6649 """
6650 info = {}
6651 if (edge >= len(a)//2): # protect against too large of an edge value
6652 originalEdge = edge
6653 if (len(a) == 2*(len(a)//2)):
6654 edge = len(a)//2 - 1 # use middle 2 points
6655 else:
6656 edge = len(a)//2 # use central point
6657 if (edge < 0):
6658 edge = 0
6659 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))
6660 info['std'] = np.std(a[edge:len(a)-edge])
6661 chan = []
6662 outlierValue = 0
6663 outlierChannel = None
6664 for i in range(edge,len(a)-edge):
6665 if (np.abs(a[i]) > sigma*info['std']):
6666 chan.append(i)
6667 if (np.abs(a[i]) > np.abs(outlierValue)):
6668 outlierValue = a[i]
6669 outlierChannel = i
6670 info['nchan'] = len(chan)
6671 info['chan'] = chan
6672 info['outlierValue'] = outlierValue/info['std']
6673 info['outlierChannel'] = outlierChannel
6674 return(info)
6676def madInfo(a, madsigma=3, edge=0):
6677 """
6678 Computes the MAD of a list, then returns the value, plus the number and list
6679 of channels that exceed madsigma*MAD, and the worst outlier.
6680 """
6681 info = {}
6682 if (edge >= len(a)//2): # protect against too large of an edge value
6683 originalEdge = edge
6684 if (len(a) == 2*(len(a)//2)):
6685 edge = len(a)//2 - 1 # use middle 2 points
6686 else:
6687 edge = len(a)//2 # use central point
6688 print("WARNING edge value is too large, reducing it from %d to %d." % (originalEdge, edge))
6689 info['mad'] = mad(a[edge:len(a)-edge])
6690 chan = []
6691 outlierValue = 0
6692 outlierChannel = None
6693 for i in range(edge,len(a)-edge):
6694 if (np.abs(a[i]) > madsigma*info['mad']):
6695 chan.append(i)
6696 if (np.abs(a[i]) > np.abs(outlierValue)):
6697 outlierValue = a[i]
6698 outlierChannel = i
6699 info['nchan'] = len(chan)
6700 info['chan'] = chan
6701 info['outlierValue'] = outlierValue/info['mad']
6702 info['outlierChannel'] = outlierChannel
6703 return(info)
6705def platformingCheck(a, threshold=DEFAULT_PLATFORMING_THRESHOLD):
6706 """
6707 Checks for values outside the range of +-threshold.
6708 Meant to be passed an amplitude spectrum.
6709 """
6710 info = {}
6711 startChan = len(a)/32. - 1
6712 endChan = len(a)*31/32. + 1
6713# print("Checking channels %d-%d for platforming" % (startChan,endChan))
6714 if (startChan <= 0 or endChan >= len(a)):
6715 return
6716 middleChan = (startChan+endChan)//2
6717 channelRange1 = list(range(startChan,middleChan+1))
6718 channelRange2 = list(range(endChan,middleChan,-1))
6719 platforming = False
6720 awayFromEdge = False
6721 for i in channelRange1:
6722 if (np.abs(a[i]) > threshold):
6723 if (awayFromEdge):
6724# print("a[%d]=%f" % (i,a[i]))
6725 platforming = True
6726 return(platforming)
6727 else:
6728 awayFromEdge = True
6729 awayFromEdge = False
6730 for i in channelRange2:
6731 if (np.abs(a[i]) > threshold):
6732 if (awayFromEdge):
6733 platforming = True
6734 return(platforming)
6735 else:
6736 awayFromEdge = True
6737 return(platforming)
6739def mad(a, c=0.6745, axis=0):
6740 """
6741 Median Absolute Deviation along given axis of an array:
6743 median(abs(a - median(a))) / c
6745 c = 0.6745 is the constant to convert from MAD to std; it is used by
6746 default
6748 """
6749 a = np.array(a)
6750 good = (a==a)
6751 a = np.asarray(a, np.float64)
6752 if a.ndim == 1:
6753 d = np.median(a[good])
6754 m = np.median(np.fabs(a[good] - d) / c)
6755# print( "mad = %f" % (m))
6756 else:
6757 d = np.median(a[good], axis=axis)
6758 # I don't want the array to change so I have to copy it?
6759 if axis > 0:
6760 aswp = swapaxes(a[good],0,axis)
6761 else:
6762 aswp = a[good]
6763 m = np.median(np.fabs(aswp - d) / c, axis=0)
6765 return m
6767def callFrequencyRangeForSpws(mymsmd, spwlist, vm, caltable=None):
6768 """
6769 Returns the min and max frequency of a list of spws.
6770 Uses msmd, unless the ms is not found, in which case it uses
6771 the spw information inside the (new-style) cal-table.
6772 """
6773 if (mymsmd != '' and ctsys.compare_version('>=',[4,1,0])):
6774 return(frequencyRangeForSpws(mymsmd,spwlist))
6775 else:
6776 freqs = []
6777 if (type(vm) != str):
6778 for spw in spwlist:
6779 freqs += list(vm.spwInfo[spw]["chanFreqs"])
6780 else:
6781 mytb = table()
6782 try:
6783 mytb.open(caltable+'/SPECTRAL_WINDOW')
6784 chanfreq = []
6785 if (len(spwlist) == 0): # CAS-8489b
6786 originalSpws = list(range(len(mytb.getcol('MEAS_FREQ_REF'))))
6787 spwlist = originalSpws
6788 for i in spwlist: # CAS-8489b
6789 # The array shapes can vary.
6790 chanfreq.append(mytb.getcell('CHAN_FREQ',i))
6791 for cf in chanfreq:
6792 freqs += list(cf)
6793 mytb.close()
6794 except:
6795 mytb.done()
6796 if (freqs == []):
6797 return(0,0)
6798 else:
6799 return(np.min(freqs)*1e-9, np.max(freqs)*1e-9)
6801def frequencyRangeForSpws(mymsmd, spwlist):
6802 """
6803 Returns the min and max frequency of a list of spws.
6804 """
6805 allfreqs = []
6806 for spw in spwlist:
6807 allfreqs += list(mymsmd.chanfreqs(spw))
6808 if (len(allfreqs) == 0):
6809 return(0,0)
6810 return(np.min(allfreqs)*1e-9, np.max(allfreqs)*1e-9)
6812def buildSpwString(overlaySpws, overlayBasebands, spwsToPlot, ispw, originalSpw,
6813 observatoryName, baseband, showBasebandNumber):
6814 if (overlayBasebands):
6815 spwString = ' all'
6816 elif (overlaySpws and len(spwsToPlot)>1):
6817 if (observatoryName.find('ALMA') >= 0 or observatoryName.find('ACA') >= 0):
6818 # show a list of all spws
6819 spwString = str(spwsToPlot).replace(' ','').strip('[').strip(']')
6820 else:
6821 # show the range of spw numbers
6822 spwString = '%2d-%2d' % (np.min(spwsToPlot),np.max(spwsToPlot))
6823 elif (ispw==originalSpw):
6824 spwString = '%2d' % (ispw)
6825 else:
6826 spwString = '%2d (%d)' % (ispw,originalSpw)
6827 if (overlayBasebands==False):
6828 spwString = appendBasebandNumber(spwString, baseband, showBasebandNumber)
6829 return(spwString)
6831def appendBasebandNumber(spwString, baseband, showBasebandNumber):
6832 if (showBasebandNumber):
6833 spwString += ', bb%d' % (baseband)
6834 return(spwString)
6836def getSpwsForBaseband(vis, bb, mymsmd=None):
6837 needToClose = False
6838# if (casadef.subversion_revision >= 25753):
6839 if (mymsmd is None or mymsmd == ''):
6840 needToClose = True
6841 mymsmd = msmetadata()
6842 mymsmd.open(vis)
6843 s = mymsmd.spwsforbaseband(bb)
6844 if needToClose:
6845 mymsmd.close()
6846 return(s)
6847# else:
6848# return(getBasebandDict(vis,caltable=caltable,mymsmd=mymsmd))
6850def getBasebandDict(vis=None, spwlist=[], caltable=None, mymsmd=None):
6851 """
6852 Builds a dictionary with baseband numbers as the keys and the
6853 associated spws as the values. The optional parameter spwlist can
6854 be used to restrict the contents of the dictionary.
6855 Note: This is obsoleted by msmd.spwsforbaseband(-1)
6856 """
6857 bbdict = {}
6858 if (vis != None):
6859 if (os.path.exists(vis)):
6860 bbs = getBasebandNumbers(vis)
6861 elif (caltable != None):
6862 bbs = getBasebandNumbersFromCaltable(caltable)
6863 else:
6864 print("Must specify either vis or caltable")
6865 return
6866 elif (caltable != None):
6867 bbs = getBasebandNumbersFromCaltable(caltable)
6868 else:
6869 print("Must specify either vis or caltable")
6870 return
6871 if (type(bbs) == int): # old datasets will bomb on msmd.baseband()
6872 return(bbdict)
6873 if (ctsys.compare_version('>=',[4,1,0]) and vis != None):
6874 if (os.path.exists(vis)):
6875 needToClose = False
6876 if mymsmd is None or mymsmd == '':
6877 needToClose = True
6878 mymsmd = msmetadata()
6879 mymsmd.open(vis)
6880 if (spwlist == []):
6881 nspws = mymsmd.nspw()
6882 spwlist = list(range(nspws))
6883 for spw in spwlist:
6884 bbc_no = mymsmd.baseband(spw)
6885 if (bbc_no not in list(bbdict.keys())):
6886 bbdict[bbc_no] = [spw]
6887 else:
6888 bbdict[bbc_no].append(spw)
6889 if needToClose:
6890 mymsmd.close()
6891 if (bbdict == {}):
6892 # read from spw table
6893 ubbs = np.unique(bbs)
6894 for bb in ubbs:
6895 bbdict[bb] = []
6896 for i in range(len(bbs)):
6897 bbdict[bbs[i]].append(i)
6898 return(bbdict)
6900def getBasebandNumbersFromCaltable(caltable) :
6901 """
6902 Returns the baseband numbers associated with each spw in
6903 the specified caltable.
6904 Todd Hunter
6905 """
6906 if (os.path.exists(caltable) == False):
6907 print("getBasebandNumbersFromCaltable(): caltable set not found")
6908 return -1
6909 mytb = table()
6910 mytb.open(caltable)
6911 spectralWindowTable = mytb.getkeyword('SPECTRAL_WINDOW').split()[1]
6912 mytb.close()
6913 mytb.open(spectralWindowTable)
6914 if ("BBC_NO" in mytb.colnames()):
6915 bbNums = mytb.getcol("BBC_NO")
6916 else:
6917 # until CAS-6853 is solved, need to get it from the name
6918# print("BBC_NO not in colnames (CAS-6853). Using NAME column.")
6919 names = mytb.getcol('NAME')
6920 bbNums = []
6921 trivial = True
6922 for name in names:
6923 if (name.find('#BB_') > 0):
6924 bbNums.append(int(name.split('#BB_')[1].split('#')[0]))
6925 trivial = False
6926 else:
6927 bbNums.append(-1)
6928 if (trivial): bbNums = -1
6929 mytb.close()
6930 return bbNums
6933def getLOs(inputMs, verbose=True):
6934 """
6935 Reads the LO information from an ms's ASDM_RECEIVER table. It returns
6936 a list of 7 lists: [freqLO,band,spws,names,sidebands,receiverIDs,spwnames]
6937 The logic for converting this raw list into sensible association with
6938 spw numbers is in printLOs(). These lists are longer than the true number
6939 of spws by Nantennas-1 due to the extra WVR spws.
6940 -Todd Hunter
6941 """
6942 if (os.path.exists(inputMs)):
6943 mytb = table()
6944 if (os.path.exists("%s/ASDM_RECEIVER" % inputMs)):
6945 try:
6946 mytb.open("%s/ASDM_RECEIVER" % inputMs)
6947 except:
6948 print("Could not open the existing ASDM_RECEIVER table")
6949 mytb.close()
6950 return([])
6951 else:
6952 if (os.path.exists(inputMs+'/ASDMBinary')):
6953 print("This is an ASDM, not an ms! Use printLOsFromASDM.")
6954 else:
6955 if (verbose):
6956 print("The ASDM_RECEIVER table for this ms does not exist.")
6957 mytb.close()
6958 return([])
6959 else:
6960 print("This ms does not exist = %s." % (inputMs))
6961 return([])
6963 numLO = mytb.getcol('numLO')
6964 freqLO = []
6965 band = []
6966 spws = []
6967 names = []
6968 sidebands = []
6969 receiverIds = []
6970 for i in range(len(numLO)):
6971 spw = int((mytb.getcell('spectralWindowId',i).split('_')[1]))
6972 if (spw not in spws):
6973 spws.append(spw)
6974 freqLO.append(mytb.getcell('freqLO',i))
6975 band.append(mytb.getcell('frequencyBand',i))
6976 names.append(mytb.getcell('name',i))
6977 sidebands.append(mytb.getcell('sidebandLO',i))
6978 receiverIds.append(int(mytb.getcell('receiverId',i)))
6979 mytb.close()
6980 mytb.open("%s/SPECTRAL_WINDOW" % inputMs)
6981 spwNames = mytb.getcol("NAME")
6982 mytb.close()
6983 mytb.close()
6984 return([freqLO,band,spws,names,sidebands,receiverIds,spwNames])
6986def readPWVFromASDM_CALATMOSPHERE(vis):
6987 """
6988 Reads the PWV via the water column of the ASDM_CALATMOSPHERE table.
6989 - Todd Hunter
6990 """
6991 mytb = table()
6992 mytb.open("%s/ASDM_CALATMOSPHERE" % vis)
6993 pwvtime = mytb.getcol('startValidTime') # mjdsec
6994 antenna = mytb.getcol('antennaName')
6995 pwv = mytb.getcol('water')[0] # There seem to be 2 identical entries per row, so take first one.
6996 mytb.close()
6997 return(pwvtime, antenna, pwv)
6999def getMedianPWV(vis='.', myTimes=[0,999999999999], asdm='', verbose=False):
7000 """
7001 Extracts the PWV measurements from the WVR on all antennas for the
7002 specified time range. The time range is input as a two-element list of
7003 MJD seconds (default = all times). First, it tries to find the ASDM_CALWVR
7004 table in the ms. If that fails, it then tries to find CalWVR.xml in the
7005 specified ASDM, or failing that, an ASDM of the same name (-.ms). If neither of
7006 these exist, then it tries to find CalWVR.xml in the present working directory.
7007 If it still fails, it looks for CalWVR.xml in the .ms directory. Thus,
7008 you only need to copy this xml file from the ASDM into your ms, rather
7009 than the entire ASDM. Returns the median and standard deviation in millimeters.
7010 For further help and examples, see https://safe.nrao.edu/wiki/bin/view/ALMA/GetMedianPWV
7011 -- Todd Hunter
7012 """
7013 pwvmean = 0
7014 success = False
7015 mytb = table()
7016 if (verbose):
7017 print("in getMedianPWV with myTimes = %s" % (str(myTimes)))
7018 try:
7019 if (os.path.exists("%s/ASDM_CALWVR"%vis)):
7020 mytb.open("%s/ASDM_CALWVR" % vis)
7021 pwvtime = mytb.getcol('startValidTime') # mjdsec
7022 antenna = mytb.getcol('antennaName')
7023 pwv = mytb.getcol('water')
7024 mytb.close()
7025 success = True
7026 if (len(pwv) < 1):
7027 if (os.path.exists("%s/ASDM_CALATMOSPHERE" % vis)):
7028 pwvtime, antenna, pwv = readPWVFromASDM_CALATMOSPHERE(vis)
7029 success = True
7030 if (len(pwv) < 1):
7031 print("Found no data in ASDM_CALWVR nor ASDM_CALATMOSPHERE table")
7032 return(0,-1)
7033 else:
7034 if (verbose):
7035 print("Did not find ASDM_CALATMOSPHERE in the ms")
7036 return(0,-1)
7037 if (verbose):
7038 print("Opened ASDM_CALWVR table, len(pwvtime)=%s" % (str(len(pwvtime))))
7039 else:
7040 if (verbose):
7041 print("Did not find ASDM_CALWVR table in the ms. Will look for ASDM_CALATMOSPHERE next.")
7042 if (os.path.exists("%s/ASDM_CALATMOSPHERE" % vis)):
7043 pwvtime, antenna, pwv = readPWVFromASDM_CALATMOSPHERE(vis)
7044 success = True
7045 if (len(pwv) < 1):
7046 print("Found no data in ASDM_CALATMOSPHERE table")
7047 return(0,-1)
7048 else:
7049 if (verbose):
7050 print("Did not find ASDM_CALATMOSPHERE in the ms")
7051 except:
7052 if (verbose):
7053 print("Could not open ASDM_CALWVR table in the ms")
7054 finally:
7055 # try to find the ASDM table
7056 if (success == False):
7057 if (len(asdm) > 0):
7058 if (os.path.exists(asdm) == False):
7059 print("Could not open ASDM = %s" % (asdm))
7060 mytb.done()
7061 return(0,-1)
7062 try:
7063 [pwvtime,pwv,antenna] = readpwv(asdm)
7064 except:
7065 if (verbose):
7066 print("Could not open ASDM = %s" % (asdm))
7067 mytb.done()
7068 return(pwvmean,-1)
7069 else:
7070 try:
7071 tryasdm = vis.split('.ms')[0]
7072 if (verbose):
7073 print("No ASDM name provided, so I will try this name = %s" % (tryasdm))
7074 [pwvtime,pwv,antenna] = readpwv(tryasdm)
7075 except:
7076 try:
7077 if (verbose):
7078 print("Still did not find it. Will look for CalWVR.xml in current directory.")
7079 [pwvtime, pwv, antenna] = readpwv('.')
7080 except:
7081 try:
7082 if (verbose):
7083 print("Still did not find it. Will look for CalWVR.xml in the .ms directory.")
7084 [pwvtime, pwv, antenna] = readpwv('%s/'%vis)
7085 except:
7086 if (verbose):
7087 print("No CalWVR.xml file found, so no PWV retrieved. Copy it to this directory and try again.")
7088 mytb.done()
7089 return(pwvmean,-1)
7090 try:
7091 matches = np.where(np.array(pwvtime)>myTimes[0])[0]
7092 except:
7093 print("Found no times > %d" % (myTimes[0]))
7094 mytb.done()
7095 return(0,-1)
7096 if (len(pwv) < 1):
7097 print("Found no PWV data")
7098 return(0,-1)
7099 ptime = np.array(pwvtime)[matches]
7100 matchedpwv = np.array(pwv)[matches]
7101 matches2 = np.where(ptime<myTimes[-1])[0]
7102 if (len(matches2) < 1):
7103 # look for the value with the closest start time
7104 mindiff = 1e12
7105 for i in range(len(pwvtime)):
7106 if (abs(myTimes[0]-pwvtime[i]) < mindiff):
7107 mindiff = abs(myTimes[0]-pwvtime[i])
7108 pwvmean = pwv[i]*1000
7109 matchedpwv = []
7110 for i in range(len(pwvtime)):
7111 if (abs(abs(myTimes[0]-pwvtime[i]) - mindiff) < 1.0):
7112 matchedpwv.append(pwv[i])
7113 pwvmean = 1000*np.median(matchedpwv)
7114 if (verbose):
7115 print("Taking the median of %d pwv measurements from all antennas = %.3f mm" % (len(matchedpwv),pwvmean))
7116 pwvstd = np.std(matchedpwv)
7117 else:
7118 pwvmean = 1000*np.median(matchedpwv[matches2])
7119 pwvstd = np.std(matchedpwv[matches2])
7120 if (verbose):
7121 print("Taking the median of %d pwv measurements from all antennas = %.3f mm" % (len(matches2),pwvmean))
7122# mytb.done()
7123 return(pwvmean,pwvstd)
7124# end of getMedianPWV
7126def computeAzElFromRADecMJD(raDec, mjd, observatory='ALMA'):
7127 """
7128 Computes the az/el for a specified J2000 RA/Dec, MJD and observatory.
7130 raDec must be in radians: [ra,dec]
7131 mjd must be in days
7132 returns the [az,el] in radians
7133 - Todd Hunter
7134 """
7135 myme = measures()
7136 myqa = quanta()
7137 mydir = myme.direction('J2000', myqa.quantity(raDec[0],'rad'), myqa.quantity(raDec[1],'rad'))
7138 myme.doframe(myme.epoch('mjd', myqa.quantity(mjd, 'd')))
7139 myme.doframe(myme.observatory(observatory))
7140 myazel = myme.measure(mydir,'azel')
7141 myqa.done()
7142 myme.done()
7143 return([myazel['m0']['value'], myazel['m1']['value']])
7145def getRADecForField(msName, myfieldId, debug):
7146 """
7147 Returns RA,Dec in radians for the specified field in the specified ms.
7148 -- Todd Hunter
7149 """
7150 myms = ms()
7151 myms.open(msName)
7152 myd = myms.getfielddirmeas('DELAY_DIR', fieldid=myfieldId) # dircolname defaults to 'PHASE_DIR'
7153 myms.close()
7154 mydir = np.array([[myd['m0']['value']], [myd['m1']['value']]]) # simulates tb.getcell
7155 return(mydir)
7157def findClosestTime(mytimes, mytime):
7158 myindex = 0
7159 mysep = np.abs(mytimes[0]-mytime)
7160 for m in range(1,len(mytimes)):
7161 if (np.abs(mytimes[m] - mytime) < mysep):
7162 mysep = np.abs(mytimes[m] - mytime)
7163 myindex = m
7164 return(myindex)
7166def getWeather(vis='', scan='', antenna='0',verbose=False, mymsmd=None):
7167 """
7168 Queries the WEATHER and ANTENNA tables of an .ms by scan number or
7169 list of scan numbers in order to return median values of: angleToSun,
7170 pressure, temperature, humidity, dew point, wind speed, wind direction,
7171 azimuth, elevation, solarangle, solarelev, solarazim.
7172 If the sun is below the horizon, the solarangle returned is negated.
7173 -- Todd Hunter
7174 """
7175 if (verbose):
7176 print("Entered getWeather with vis,scan,antenna = %s,%s,%s" % (str(vis), str(scan), str(antenna)))
7177 try:
7178 if str(antenna).isdigit():
7179 antennaName = mymsmd.antennanames(antenna)[0]
7180 else:
7181 antennaName = antenna
7182 try:
7183 antenna = mymsmd.antennaids(antennaName)[0]
7184 except:
7185 antennaName = string.upper(antenna)
7186 antenna = mymsmd.antennaids(antennaName)[0]
7187 except:
7188 print("Either the ANTENNA table does not exist or antenna %s does not exist" % (antenna))
7189 return([0,[]])
7190 mytb = table()
7191 try:
7192 mytb.open("%s/POINTING" % vis)
7193 except:
7194 print("POINTING table does not exist")
7195 mytb.done()
7196 return([0,0])
7197 subtable = mytb.query("ANTENNA_ID == %s" % antenna)
7198 mytb.close()
7199 try:
7200 mytb.open("%s/OBSERVATION" % vis)
7201 observatory = mytb.getcell("TELESCOPE_NAME",0)
7202 mytb.close()
7203 except:
7204 print("OBSERVATION table does not exist, assuming observatory == ALMA")
7205 observatory = "ALMA"
7206 if (scan == ''):
7207 scan = mymsmd.scannumbers()
7208 conditions = {}
7209 conditions['pressure']=conditions['temperature']=conditions['humidity']=conditions['dewpoint']=conditions['windspeed']=conditions['winddirection'] = 0
7210 conditions['scan'] = scan
7211 if (type(scan) == str):
7212 if (scan.find('~')>0):
7213 tokens = scan.split('~')
7214 scan = [int(k) for k in range(int(tokens[0]),int(tokens[1])+1)]
7215 else:
7216 scan = [int(k) for k in scan.split(',')]
7217 if (type(scan) == type(np.ndarray(0))):
7218 scan = list(scan)
7219 if (type(scan) == list):
7220 myTimes = np.array([])
7221 for sc in scan:
7222 try:
7223 print("calling timesforscan")
7224 newTimes = mymsmd.timesforscan(sc)
7225 print("times = %s" % (str(newTimes)))
7226 except:
7227 print("Error reading scan %d, is it in the data?" % (sc))
7228 mytb.done()
7229 return([conditions,[]])
7230 myTimes = np.concatenate((myTimes,newTimes))
7231 elif (scan != None):
7232 try:
7233 myTimes = mymsmd.timesforscan(scan)
7234 except:
7235 print("Error reading scan %d, is it in the data?" % (scan))
7236 mytb.done()
7237 return([conditions,[]])
7238 else:
7239 mytb.done()
7240 return([conditions,[]])
7241 if (type(scan) == str):
7242 scan = [int(k) for k in scan.split(',')]
7243 if (type(scan) == list):
7244 listscan = ""
7245 listfield = []
7246 for sc in scan:
7247# print("Processing scan ", sc)
7248 listfield.append(mymsmd.fieldsforscan(sc))
7249 listscan += "%d" % sc
7250 if (sc != scan[-1]):
7251 listscan += ","
7252# print("listfield = ", listfield)
7253 listfields = np.unique(listfield[0])
7254 listfield = ""
7255 for field in listfields:
7256 listfield += "%s" % field
7257 if (field != listfields[-1]):
7258 listfield += ","
7259 else:
7260 listscan = str(scan)
7261 listfield = mymsmd.fieldsforscan(scan)
7262 [az,el] = ComputeSolarAzElForObservatory(myTimes[0], mymsmd)
7263 [az2,el2] = ComputeSolarAzElForObservatory(myTimes[-1], mymsmd)
7264 azsun = np.median([az,az2])
7265 elsun = np.median([el,el2])
7266 direction = subtable.getcol("DIRECTION")
7267 azeltime = subtable.getcol("TIME")
7268 subtable.close()
7269 telescopeName = mymsmd.observatorynames()[0]
7270 if (len(direction) > 0 and telescopeName.find('VLA') < 0 and telescopeName.find('NRO') < 0):
7271 azimuth = direction[0][0]*180.0/math.pi # a list of values
7272 elevation = direction[1][0]*180.0/math.pi # a list of values
7273 npat = np.array(azeltime)
7274 matches = np.where(npat>myTimes[0])[0]
7275 matches2 = np.where(npat<myTimes[-1])[0]
7276 if (len(matches2) > 0 and len(matches) > 0):
7277 if verbose: print("matches[0]=%d, matches2[-1]=%d" % (matches[0],matches[-1]))
7278 matchingIndices = list(range(matches[0],matches2[-1]+1))
7279 else:
7280 matchingIndices = []
7281 if (len(matchingIndices) > 0): # CAS-8440
7282 conditions['azimuth'] = np.median(azimuth[matches[0]:matches2[-1]+1])
7283 conditions['elevation'] = np.median(elevation[matches[0]:matches2[-1]+1])
7284 elif (len(matches) > 0): # CAS-8440
7285 if verbose: print("using median of all az/el values after time 0")
7286 conditions['azimuth'] = np.median(azimuth[matches[0]])
7287 conditions['elevation'] = np.median(elevation[matches[0]])
7288 else: # CAS-8440
7289 if verbose: print("using median of all az/el values")
7290 conditions['azimuth'] = np.median(azimuth)
7291 conditions['elevation'] = np.median(elevation)
7292 conditions['solarangle'] = angularSeparation(azsun,elsun,conditions['azimuth'],conditions['elevation'])
7293 conditions['solarelev'] = elsun
7294 conditions['solarazim'] = azsun
7295 if (verbose):
7296 print("Using antenna = %s to retrieve median azimuth and elevation" % (antennaName))
7297 print("Separation from sun = %f deg" % (abs(conditions['solarangle'])))
7298 if (elsun<0):
7299 conditions['solarangle'] = -conditions['solarangle']
7300 if (verbose):
7301 print("Sun is below horizon (elev=%.1f deg)" % (elsun))
7302 else:
7303 if (verbose):
7304 print("Sun is above horizon (elev=%.1f deg)" % (elsun))
7305 if (verbose):
7306 print("Average azimuth = %.2f, elevation = %.2f degrees" % (conditions['azimuth'],conditions['elevation']))
7307 else:
7308 if (verbose): print("The POINTING table is either blank or does not contain Azim/Elev.")
7309 if (type(scan) == int or type(scan)==np.int32):
7310 # compute Az/El for this scan
7311 myfieldId = mymsmd.fieldsforscan(scan)
7312 if (type(myfieldId) == list or type(myfieldId) == type(np.ndarray(0))):
7313 myfieldId = myfieldId[0]
7314 fieldName = mymsmd.namesforfields(myfieldId)
7315 if (type(fieldName) == list or type(fieldName) == type(np.ndarray(0))):
7316 fieldName = fieldName[0]
7317# print("A) fieldname = ", fieldName)
7318# print("myfieldId = ", myfieldId)
7319 myscantime = np.median(mymsmd.timesforscan(scan))
7320# print("Calling getRADecForField")
7321 mydirection = getRADecForField(vis, myfieldId, verbose)
7322 if (verbose): print("mydirection= %s" % (str(mydirection)))
7323 if (len(telescopeName) < 1):
7324 telescopeName = 'ALMA'
7325 myazel = computeAzElFromRADecMJD(mydirection, myscantime/86400., telescopeName)
7326 conditions['elevation'] = myazel[1] * 180/math.pi
7327 conditions['azimuth'] = myazel[0] * 180/math.pi
7328 conditions['solarangle'] = angularSeparation(azsun,elsun,conditions['azimuth'],conditions['elevation'])
7329 conditions['solarelev'] = elsun
7330 conditions['solarazim'] = azsun
7331 if (verbose):
7332 print("Separation from sun = %f deg" % (abs(conditions['solarangle'])))
7333 if (elsun<0):
7334 conditions['solarangle'] = -conditions['solarangle']
7335 if (verbose):
7336 print("Sun is below horizon (elev=%.1f deg)" % (elsun))
7337 else:
7338 if (verbose):
7339 print("Sun is above horizon (elev=%.1f deg)" % (elsun))
7340 if (verbose):
7341 print("Average azimuth = %.2f, elevation = %.2f degrees" % (conditions['azimuth'],conditions['elevation']))
7342 elif (type(scan) == list):
7343 myaz = []
7344 myel = []
7345 if (verbose):
7346 print("Scans to loop over = %s" % (str(scan)))
7347 for s in scan:
7348 fieldName = mymsmd.fieldsforscan(s)
7349 if (type(fieldName) == list):
7350 # take only the first pointing in the mosaic
7351 fieldName = fieldName[0]
7352 myfieldId = mymsmd.fieldsforname(fieldName)
7353 if (type(myfieldId) == list or type(myfieldId)==type(np.ndarray(0))):
7354 # If the same field name has two IDs (this happens in EVLA data)
7355 myfieldId = myfieldId[0]
7356 myscantime = np.median(mymsmd.timesforscan(s))
7357 mydirection = getRADecForField(vis, myfieldId, verbose)
7358 telescopeName = mymsmd.observatorynames()[0]
7359 if (len(telescopeName) < 1):
7360 telescopeName = 'ALMA'
7361 myazel = computeAzElFromRADecMJD(mydirection, myscantime/86400., telescopeName)
7362 myaz.append(myazel[0]*180/math.pi)
7363 myel.append(myazel[1]*180/math.pi)
7364 conditions['azimuth'] = np.median(myaz)
7365 conditions['elevation'] = np.median(myel)
7366 conditions['solarangle'] = angularSeparation(azsun,elsun,conditions['azimuth'],conditions['elevation'])
7367 conditions['solarelev'] = elsun
7368 conditions['solarazim'] = azsun
7369 if (verbose):
7370 print("Using antenna = %s to retrieve median azimuth and elevation" % (antennaName))
7371 print("Separation from sun = %f deg" % (abs(conditions['solarangle'])))
7372 if (elsun<0):
7373 conditions['solarangle'] = -conditions['solarangle']
7374 if (verbose):
7375 print("Sun is below horizon (elev=%.1f deg)" % (elsun))
7376 else:
7377 if (verbose):
7378 print("Sun is above horizon (elev=%.1f deg)" % (elsun))
7379 if (verbose):
7380 print("Average azimuth = %.2f, elevation = %.2f degrees" % (conditions['azimuth'],conditions['elevation']))
7383 # now, get the weather
7384 if not os.path.exists('%s/WEATHER' % vis):
7385 print("There is no WEATHER table for this ms.")
7386 if (needToClose_mymsmd): mymsmd.close()
7387 return([conditions,myTimes])
7388 try:
7389 mytb.open("%s/WEATHER" % vis)
7390 except:
7391 print("Could not open the WEATHER table for this ms.")
7392 mytb.done()
7393 return([conditions,myTimes])
7394 if (True):
7395 mjdsec = mytb.getcol('TIME')
7396 indices = np.argsort(mjdsec)
7397 mjd = mjdsec/86400.
7398 pressure = mytb.getcol('PRESSURE')
7399 conditions['pressure_unit'] = mytb.getcolkeywords('PRESSURE').get('QuantumUnits', ['mbar'])[0]
7400 relativeHumidity = mytb.getcol('REL_HUMIDITY')
7401 temperature = mytb.getcol('TEMPERATURE')
7402 if (np.median(temperature) > 100):
7403 # must be in units of Kelvin, so convert to C
7404 temperature -= 273.15
7405 if 'DEW_POINT' in mytb.colnames():
7406 dewPoint = mytb.getcol('DEW_POINT')
7407 if (np.median(dewPoint) > 100):
7408 # must be in units of Kelvin, so convert to C
7409 dewPoint -= 273.15
7410 if (np.median(dewPoint) == 0):
7411 # assume it is not measured and use NOAA formula to compute from humidity:
7412 dewPoint = ComputeDewPointCFromRHAndTempC(relativeHumidity, temperature)
7413 else:
7414 dewPoint = None # Nobeyama measurement sets do not have a dewpoint column
7415 sinWindDirection = np.sin(mytb.getcol('WIND_DIRECTION'))
7416 cosWindDirection = np.cos(mytb.getcol('WIND_DIRECTION'))
7417 windSpeed = mytb.getcol('WIND_SPEED')
7418 mytb.done()
7420 # put values into time order (they mostly are, but there can be small differences)
7421 mjdsec = np.array(mjdsec)[indices]
7422 pressure = np.array(pressure)[indices]
7423 relativeHumidity = np.array(relativeHumidity)[indices]
7424 temperature = np.array(temperature)[indices]
7425 if dewPoint is not None:
7426 dewPoint = np.array(dewPoint)[indices]
7427 windSpeed = np.array(windSpeed)[indices]
7428 sinWindDirection = np.array(sinWindDirection)[indices]
7429 cosWindDirection = np.array(cosWindDirection)[indices]
7431 # find the overlap of weather measurement times and scan times
7432 matches = np.where(mjdsec>=np.min(myTimes))[0]
7433 matches2 = np.where(mjdsec<=np.max(myTimes))[0]
7434# print("len(matches)=%d, len(matches2)=%d" % (len(matches), len(matches2)))
7435 noWeatherData = False
7436 if (len(matches)>0 and len(matches2) > 0):
7437 # average the weather points enclosed by the scan time range
7438 selectedValues = list(range(matches[0], matches2[-1]+1))
7439 if (selectedValues == []):
7440 # there was a either gap in the weather data, or an incredibly short scan duration
7441 if (verbose):
7442 print("---- Finding the nearest weather value --------------------------- ")
7443 selectedValues = findClosestTime(mjdsec, myTimes[0])
7444 elif (len(matches)>0):
7445 # all points are greater than myTime, so take the first one
7446 selectedValues = matches[0]
7447 elif (len(matches2)>0):
7448 # all points are less than myTime, so take the last one
7449 selectedValues = matches2[-1]
7450 else:
7451 # table has no weather data!
7452 noWeatherData = True
7453 if (noWeatherData):
7454 conditions['pressure'] = 563.0
7455 conditions['temperature'] = 0 # Celsius is expected
7456 conditions['humidity'] = 20.0
7457 conditions['dewpoint'] = -20.0
7458 conditions['windspeed'] = 0
7459 conditions['winddirection'] = 0
7460 print("WARNING: No weather data found in the WEATHER table!")
7461 else:
7462 if (type(selectedValues) == np.int64 or type(selectedValues) == np.int32 or
7463 type(selectedValues) == int):
7464 conditions['readings'] = 1
7465 if (verbose):
7466 print("selectedValues=%d, myTimes[0]=%.0f, len(matches)=%d, len(matches2)=%d" % (selectedValues,
7467 myTimes[0], len(matches), len(matches2)))
7468 if (len(matches) > 0):
7469 print("matches[0]=%f, matches[-1]=%f" % (matches[0], matches[-1]))
7470 if (len(matches2) > 0):
7471 print("matches2[0]=%f, matches2[-1]=%d" % (matches2[0], matches2[-1]))
7472 else:
7473 conditions['readings'] = len(selectedValues)
7474 conditions['pressure'] = np.median(pressure[selectedValues])
7475 if (conditions['pressure'] != conditions['pressure']):
7476 # A nan value got through, due to no selected values (should be impossible)"
7477 if (verbose):
7478 print(">>>>>>>>>>>>>>>>>>>>>>>> selectedValues = %s" % (str(selectedValues)))
7479 print("len(matches)=%d, len(matches2)=%d" % (len(matches), len(matches2)))
7480 print("matches[0]=%f, matches[-1]=%f, matches2[0]=%f, matches2[-1]=%d" % (matches[0], matches[-1], matches2[0], matches2[-1]))
7481 conditions['temperature'] = np.median(temperature[selectedValues])
7482 conditions['humidity'] = np.median(relativeHumidity[selectedValues])
7483 if dewPoint is not None:
7484 conditions['dewpoint'] = np.nanmedian(dewPoint[selectedValues])
7485 conditions['windspeed'] = np.median(windSpeed[selectedValues])
7486 conditions['winddirection'] = (180./math.pi)*np.arctan2(np.median(sinWindDirection[selectedValues]),np.median(cosWindDirection[selectedValues]))
7487 if (conditions['winddirection'] < 0):
7488 conditions['winddirection'] += 360
7489 if (verbose):
7490 print("Median weather values for scan %s (field %s)" % (listscan,listfield))
7491 print(" Pressure = %.2f mb" % (conditions['pressure']))
7492 print(" Temperature = %.2f C" % (conditions['temperature']))
7493 if dewPoint is not None:
7494 print(" Dew point = %.2f C" % (conditions['dewpoint']))
7495 print(" Relative Humidity = %.2f %%" % (conditions['humidity']))
7496 print(" Wind speed = %.2f m/s" % (conditions['windspeed']))
7497 print(" Wind direction = %.2f deg" % (conditions['winddirection']))
7499 return([conditions,myTimes])
7500 # end of getWeather
7502def getBasebandNumbers(inputMs) :
7503 """
7504 Returns the baseband numbers associated with each spw in the specified ms.
7505 Todd Hunter
7506 """
7507 if (os.path.exists(inputMs) == False):
7508 print("measurement set not found")
7509 return -1
7510 mytb = table()
7511 mytb.open("%s/SPECTRAL_WINDOW" % inputMs)
7512 if ("BBC_NO" in mytb.colnames()):
7513 bbNums = mytb.getcol("BBC_NO")
7514 else:
7515 return(-1)
7516 mytb.close()
7517 return bbNums
7519def yigHarmonic(bandString):
7520 """
7521 Returns the YIG harmonic for the specified ALMA band, given as a string
7522 used in casa tables.
7523 For example: yigHarmonic('ALMA_RB_03') returns the integer 6.
7524 Todd Hunter
7525 """
7526 # remove any leading spaces
7527 #bandString = bandString[bandString.find('ALMA_RB'):]
7528 harmonics = {'ALMA_RB_03':6, 'ALMA_RB_04':6, 'ALMA_RB_06': 18,
7529 'ALMA_RB_07': 18, 'ALMA_RB_08':18, 'ALMA_RB_09':27}
7530 try:
7531 harmonic = harmonics[bandString]
7532 except:
7533 harmonic = -1
7534 return(harmonic)
7536def interpretLOs(vis, parentms='', showWVR=False,
7537 showCentralFreq=False, verbose=False, show=False,
7538 alsoReturnLO2=False, showChannelAverageSpws=False,
7539 showOnlyScienceSpws=False, birdieFreq=None, birdieSpw=None,
7540 intent='OBSERVE_TARGET#ON_SOURCE', spwsForIntent=None,
7541 showEffective=False, showWindowFactors=False, mymsmd=None):
7542 """
7543 Copied from analysisUtils on May 16, 2017, to replace old version, in order
7544 to fix SCOPS-4877.
7545 Interpret (and optionally print) the LO settings for an MS from the
7546 ASDM_RECEIVER table.
7547 Options:
7548 showCentralFreq: if True, then show the mean frequency of each spw,
7549 otherwise show the frequency of the first channel
7550 showWVR: include the WVR spw in the list
7551 parentms: if the dataset has been split from a parent dataset, then
7552 you may also need to specify the name of the parent ms.
7553 alsoReturnLO2: if True, return a second dictionary of the LO2 values
7554 birdieFreq: if specified, compute the IF of this RF feature
7555 birdieSpw: only necessary if more than one LO1 in the science spws
7556 intent: which intent to use in spwsforintent (to find science spws)
7557 spwsForIntent: if specified, then avoid the call to spwsforintent
7559 Returns: a dictionary of the LO1 values (in Hz) for each spw, keyed by
7560 integer.
7562 A typical band 7 TDM dataset (prior to splitting) looks like this:
7563 SPECTRAL_WINDOW table has 39 rows: row
7564 WVR 0
7565 8 band 3 windows (pointing) 1-8
7566 8 band 7 windows 9-16
7567 22 WVR windows 17-38
7568 The corresponding ASDM_RECEIVER table has only 18 rows:
7569 WVR 0
7570 8 band 3 windows 1-8
7571 WVR 9
7572 8 band 7 windows 10-17
7573 After splitting, the ASDM_RECEIVER table remains the same, but the
7574 SPECTRAL WINDOW table then has only 4 rows, as the pointing spws and
7575 the channel-averaged data are dropped:
7576 4 band 7 windows
7578 Todd Hunter
7579 """
7580 lo1s = {} # initialize dictionary to be returned
7581 lo2s = {}
7582 try:
7583 retval = getLOs(vis)
7584 [LOs,bands,spws,names,sidebands,receiverIds,spwNames] = retval
7585 except:
7586 print("getLOs failed")
7587 return(retval)
7588 if (verbose): print("len(spws) = %d: %s" % (len(spws), str(spws)))
7589 maxSpw = np.max(spws)
7590 sawWVR = False
7591 indices = [] # will exclude the extraneous WVR spws
7592 for i in range(len(spws)):
7593 if (names[i].find('WVR') >= 0):
7594 if (not sawWVR):
7595 indices.append(i)
7596 sawWVR = True
7597 else:
7598 indices.append(i)
7599 LOs = np.array(LOs, dtype=object)[indices]
7600 bands = np.array(bands, dtype=object)[indices]
7601 spws = list(np.array(spws, dtype=object)[indices])
7602 names = np.array(names, dtype=object)[indices]
7603 sidebands = np.array(sidebands, dtype=object)[indices]
7604 receiverIds = np.array(receiverIds, dtype=object)[indices]
7605 index = list(range(len(spws)))
7606 mytb = table()
7607 mytb.open(vis+'/SPECTRAL_WINDOW')
7608 # If the data have been split into an ms with fewer spws, then this
7609 # table will be smaller (in rows) than the parent MS's table.
7610 spwNames = mytb.getcol('NAME')
7611 mytb.close()
7612 splitted = False
7613 if (maxSpw != len(spwNames)-1):
7614 splitted = True
7615 if (verbose):
7616 print("maxSpw=%d != len(spwNames)=%d)" % (maxSpw, len(spwNames)))
7617 if (parentms == '' or parentms == None):
7618 print("You appear to have split these data. Please provide the parentms as an argument.")
7619 return
7620 mytb.open(parentms+'/SPECTRAL_WINDOW')
7621 parentSpwNames = mytb.getcol('NAME')
7622 mytb.close()
7623 extractedRows = []
7624 index = []
7625 for s in range(len(spwNames)):
7626 if (len(spwNames[s]) == 0):
7627 print("This is an old dataset lacking values in the NAME column of the SPECTRAL_WINDOW table.")
7628 return
7629 if (verbose):
7630 print("Checking for %s in " % (spwNames[s]), parentSpwNames)
7631 extractedRows.append(np.where(parentSpwNames == spwNames[s])[0][0])
7632 index.append(spws.index(extractedRows[-1]))
7633 if (verbose):
7634 print("spw %d came from spw %d" % (s, extractedRows[-1]))
7635# extractedRows = the row of the parent SPECTRAL_WINDOW table that matches
7636# the split-out spw
7637# index = the row of the ASDM_RECEIVER table that matches the split-out spw
7638 vis = parentms
7639 if (verbose):
7640 print("spwNames = ", spwNames)
7641 print("spws = ", spws)
7642 print("bands = ", bands)
7643 output = "LOs = "
7644 for LO in LOs:
7645 output += "%.3f, " % (LO[0]*1e-9)
7646 print(output)
7647 print("names = ", names)
7648 print("index = ", index)
7650 bbc = getBasebandNumbers(vis) # does not use msmd
7651 if (show):
7652 print('Row refers to the row number in the ASDM_RECEIVER table (starting at 0).')
7653 if (showCentralFreq):
7654 myline = 'Row spw BB RxBand CenFreq Nchan LO1(GHz) LO2(GHz) Sampler YIG(GHz) TFBoffset(MHz)'
7655 else:
7656 myline = 'Row spw BB RxBand Ch1Freq Nchan LO1(GHz) LO2(GHz) Sampler YIG(GHz) TFBoffset(MHz)'
7657 if (showEffective):
7658 myline += ' Eff.BW(MHz) Res(MHz) Width(MHz)'
7659 if (showWindowFactors):
7660 myline += ' windowFactors'
7661 print(myline)
7663 # Loop over all rows in the ASDM_RECEIVER table, unless we've split, in
7664 # which case this will loop over the N spws in the table.
7665 needToClose = False
7666 if mymsmd is None or mymsmd == '':
7667 mymsmd = msmetadata()
7668 mymsmd.open(vis)
7669 needToClose = True
7670 if (spwsForIntent == None):
7671 if intent in mymsmd.intents(): # prevent a warning of OBSERVE_TARGET does not exist
7672 scienceSpws = np.setdiff1d(mymsmd.spwsforintent(intent),mymsmd.wvrspws())
7673 else:
7674 scienceSpws = []
7675 else:
7676 scienceSpws = spwsForIntent
7677 birdieIF = 0
7678 if (birdieFreq is not None):
7679 birdieFreq = parseFrequencyArgumentToHz(birdieFreq)
7680 birdieFreqGHz = parseFrequencyArgumentToGHz(birdieFreq)
7681 fdmSpws = mymsmd.almaspws(fdm=True)
7682 for i in range(len(index)):
7683 if (verbose):
7684 print("index[%d]=%d" % (i,index[i]))
7685 print("spws[%d] = %d" % (index[i], spws[index[i]]))
7686 myspw = i
7687 if (birdieFreq is not None and birdieIF == 0):
7688 if (myspw == birdieSpw):
7689 if verbose:
7690 print("spw=%d, Computing IF = %f - %f" % (myspw, birdieFreq, LOs[index[i]][0]))
7691 birdieIF = np.fabs(birdieFreq - LOs[index[i]][0])
7692 elif (myspw in scienceSpws and birdieSpw==None):
7693 if verbose:
7694 print("spw=%d (in %s), Computing IF = %f - %f" % (myspw, str(scienceSpws), birdieFreq, LOs[index[i]][0]))
7695 birdieIF = np.fabs(birdieFreq - LOs[index[i]][0])
7696 freqs = mymsmd.chanfreqs(myspw)
7697 meanFreqGHz = mymsmd.meanfreq(myspw) * (1e-9)
7698 if (myspw not in scienceSpws and showOnlyScienceSpws): continue
7699 if (len(freqs) < 2 and showChannelAverageSpws==False):
7700 continue
7701 if (bands[index[i]].split('_')[-1].isdigit()):
7702 rxband = bands[index[i]].split('_')[-1]
7703 elif (showWVR):
7704 rxband = 'WVR'
7705 else:
7706 continue
7707 line = "%2d %2d %d %3s " % (spws[index[i]], myspw, bbc[myspw], rxband)
7708 if (showCentralFreq):
7709 line += "%10.6f %4d " % (meanFreqGHz,len(freqs))
7710 else:
7711 line += "%10.6f %4d " % (freqs[0],len(freqs))
7713 if (LOs[index[i]][0] < 0):
7714 print(line)
7715 continue
7716 if (bbc[myspw] > 0):
7717 if (splitted):
7718 lo1s[i] = LOs[index[i]][0]
7719 lo2s[i] = LOs[index[i]][1]
7720 else:
7721 lo1s[myspw] = LOs[index[i]][0]
7722 lo2s[myspw] = LOs[index[i]][1]
7723 for j in range(len(LOs[index[i]])):
7724 if (j != 2):
7725 line = line + '%10.6f' % (LOs[index[i]][j]*1e-9)
7726 else:
7727 line = line + '%5.2f' % (LOs[index[i]][j]*1e-9)
7728 yig = LOs[index[i]][0] / yigHarmonic(bands[index[i]])
7729 if (yig > 0):
7730 line = line + ' %.6f' % (yig*1e-9)
7731 if (myspw in fdmSpws):
7732 # work out what LO4 must have been
7733 LO1 = LOs[index[i]][0]
7734 LO2 = LOs[index[i]][1]
7735 LO3 = LOs[index[i]][2]
7736 if (sidebands[index[i]][0] == 'USB'):
7737 IFlocation = LO3 - (LO2 - (meanFreqGHz*1e9 - LO1))
7738 else:
7739 IFlocation = LO3 - (LO2 - (LO1 - meanFreqGHz*1e9))
7740 LO4 = 2e9 + IFlocation
7741 TFBLOoffset = LO4-3e9
7742 line += '%9.3f %+8.3f ' % (LO4 * 1e-6, TFBLOoffset * 1e-6)
7743 else:
7744 line += 19*' '
7745 if (showEffective):
7746 line += '%9.4f %9.4f %9.4f' % (effectiveBandwidth(vis, myspw)*1e-6,
7747 effectiveResolution(vis, myspw)*1e-6,
7748 getChanWidths(mymsmd, myspw)*1e-6)
7749 if (showWindowFactors):
7750 chanwidth = abs(getChanWidths(mymsmd,myspw))
7751 line += ' %.4f %.4f' % (effectiveBandwidth(vis, myspw)/chanwidth,
7752 effectiveResolution(vis, myspw)/chanwidth)
7753 if (bands[index[i]].find('ALMA_RB_06')>=0 or bands[index[i]].find('ALMA_RB_09')>=0):
7754 if (len(LOs[index[i]]) > 1):
7755 if (LOs[index[i]][1] < 11.3e9 and LOs[index[i]][1] > 10.5e9):
7756 line = line + ' leakage of LO2 undesired sideband may degrade dynamic range'
7757 if (bands[index[i]].find('ALMA_RB_06')>=0):
7758 line += ' (and YIG may leak in)'
7759 yigLeakage = LOs[index[i]][0] + (LOs[index[i]][1] - LOs[index[i]][2]) + (yig - LOs[index[i]][1])
7760 if (yigLeakage > 0):
7761 line = line + ' at %.6f' % (yigLeakage*1e-9)
7762 if (show): print(line)
7763 if needToClose:
7764 mymsmd.done()
7765 if (birdieIF != 0):
7766 print("The feature at %f GHz is at IF = %f GHz." % (birdieFreqGHz, birdieIF*1e-9))
7767 if (alsoReturnLO2):
7768 return(lo1s, lo2s)
7769 else:
7770 return(lo1s)
7772def mjdSecondsToMJDandUT(mjdsec):
7773 """
7774 Converts a value of MJD seconds into MJD, and into a UT date/time string.
7775 example: (56000.0, '2012-03-14 00:00:00 UT')
7776 Caveat: only works for a scalar input value
7777 Todd Hunter
7778 """
7779 myme = measures()
7780 today = myme.epoch('utc','today')
7781 mjd = np.array(mjdsec) / 86400.
7782 today['m0']['value'] = mjd
7783 myqa = quanta()
7784 hhmmss = myqa.time(today['m0'], form='', prec=0, showform=False)[0]
7785# print("hhmmss = ", hhmmss)
7786 date = myqa.splitdate(today['m0'])
7787 myqa.done()
7788 utstring = "%s-%02d-%02d %s UT" % (date['year'],date['month'],date['monthday'],hhmmss)
7789 myme.done()
7790 return(mjd, utstring)
7792def ComputeSolarAzElForObservatory(mjdsec, mymsmd):
7793 pos = mymsmd.observatoryposition()
7794 longitude = pos['m0']['value'] * 180/np.pi
7795 latitude = pos['m1']['value'] * 180/np.pi
7796 return(ComputeSolarAzElLatLong(mjdsec,latitude,longitude))
7798def ComputeSolarAzElLatLong(mjdsec,latitude,longitude):
7799 """
7800 Computes the apparent Az,El of the Sun for a specified time and location
7801 on Earth. Latitude and longitude must arrive in degrees, with positive
7802 longitude meaning east of Greenwich.
7803 -- Todd Hunter
7804 """
7805 DEG_TO_RAD = math.pi/180.
7806 RAD_TO_DEG = 180/math.pi
7807 HRS_TO_RAD = math.pi/12.
7808 [RA,Dec] = ComputeSolarRADec(mjdsec)
7809 LST = ComputeLST(mjdsec, longitude)
7811 phi = latitude*DEG_TO_RAD
7812 hourAngle = HRS_TO_RAD*(LST - RA)
7813 azimuth = RAD_TO_DEG*math.atan2(math.sin(hourAngle), (math.cos(hourAngle)*math.sin(phi) - math.tan(Dec*DEG_TO_RAD)*math.cos(phi)))
7815 # the following is to convert from South=0 (which the French formula uses)
7816 # to North=0, which is what the rest of the world uses */
7817 azimuth += 180.0;
7819 if (azimuth > 360.0):
7820 azimuth -= 360.0
7821 if (azimuth < 0.0):
7822 azimuth += 360.0
7824 argument = math.sin(phi)*math.sin(Dec*DEG_TO_RAD) + math.cos(phi)*math.cos(Dec*DEG_TO_RAD) * math.cos(hourAngle);
7825 elevation = RAD_TO_DEG*math.asin(argument);
7826 return([azimuth,elevation])
7828def ComputeSolarRADec(mjdsec):
7829 """
7830 Computes the RA,Dec of the Sun for a specified time. -- Todd Hunter
7831 """
7832 jd = mjdToJD(mjdsec/86400.)
7833 RAD_TO_DEG = 180/math.pi
7834 RAD_TO_HRS = (1.0/0.2617993877991509)
7835 DEG_TO_RAD = math.pi/180.
7836 T = (jd - 2451545.0) / 36525.0
7837 Lo = 280.46646 + 36000.76983*T + 0.0003032*T*T
7838 M = 357.52911 + 35999.05029*T - 0.0001537*T*T
7839 Mrad = M * DEG_TO_RAD
7840 e = 0.016708634 - 0.000042037*T - 0.0000001267*T*T
7841 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)
7842 L = Lo + C
7843 nu = DEG_TO_RAD*(M + C)
7844 R = 1.000001018 * (1-e*e) / (1 + e*math.cos(nu))
7845 Omega = DEG_TO_RAD*(125.04 - 1934.136*T)
7846 mylambda = DEG_TO_RAD*(L - 0.00569 - 0.00478 * math.sin(Omega))
7847 epsilon0 = (84381.448 - 46.8150*T - 0.00059*T*T + 0.001813*T*T*T) / 3600.
7848 epsilon = (epsilon0 + 0.00256 * math.cos(Omega)) * DEG_TO_RAD
7849 rightAscension = RAD_TO_HRS*math.atan2(math.cos(epsilon)*math.sin(mylambda), math.cos(mylambda))
7850 if (rightAscension < 0):
7851 rightAscension += 24.0
7852 argument = math.sin(epsilon) * math.sin(mylambda)
7853 declination = RAD_TO_DEG*math.asin(argument)
7854 return([rightAscension, declination])
7856def angularSeparation(ra0,dec0,ra1,dec1, returnComponents=False):
7857 """
7858 Usage: angularSeparation(ra0,dec0,ra1,dec1)
7859 Computes the great circle angle between two celestial coordinates.
7860 using the Vincenty formula (from wikipedia) which is correct for all
7861 angles, as long as you use atan2() to handle a zero denominator.
7862 See http://en.wikipedia.org/wiki/Great_circle_distance
7863 ra,dec must be given in degrees, as is the output.
7864 It also works for the az,el coordinate system.
7865 Comopnent separations are field_0 minus field_1.
7866 See also angularSeparationRadians()
7867 -- Todd Hunter
7868 """
7869 ra0 *= math.pi/180.
7870 dec0 *= math.pi/180.
7871 ra1 *= math.pi/180.
7872 dec1 *= math.pi/180.
7873 deltaLong = ra0-ra1
7874 argument1 = (((math.cos(dec1)*math.sin(deltaLong))**2) +
7875 ((math.cos(dec0)*math.sin(dec1)-math.sin(dec0)*math.cos(dec1)*math.cos(deltaLong))**2))**0.5
7876 argument2 = math.sin(dec0)*math.sin(dec1) + math.cos(dec0)*math.cos(dec1)*math.cos(deltaLong)
7877 angle = math.atan2(argument1, argument2) / (math.pi/180.)
7878 if (returnComponents):
7879 radegrees = (ra0-ra1)*180/math.pi
7880 decdegrees = (dec0-dec1)*180/math.pi
7881 retval = angle,radegrees,decdegrees
7882 else:
7883 retval = angle
7884 return(retval)
7886def ComputeDewPointCFromRHAndTempC(relativeHumidity, temperature):
7887 """
7888 inputs: relativeHumidity in percentage, temperature in C
7889 output: in degrees C
7890 Uses formula from http://en.wikipedia.org/wiki/Dew_point#Calculating_the_dew_point
7891 Todd Hunter
7892 """
7893 temperature = np.array(temperature) # protect against it being a list
7894 relativeHumidity = np.array(relativeHumidity) # protect against it being a list
7895 es = 6.112 * np.exp(17.67 * temperature / (temperature + 243.5))
7896 E = relativeHumidity * 0.01 * es
7897 # patch problematic cases where relativy humiditiy is -1
7898 # requires changing numpy.mean to numpy.nanmean downstream the code to avoid bad averages of the dewpoint
7899 dewPoint = np.zeros(len(E))
7900 for i in range(len(E)):
7901 if E[i] <= 0:
7902 dewPoint[i] = None
7903 else:
7904 dewPoint[i] = 243.5 * np.log(E[i] / 6.112) / (17.67 - np.log(E[i] / 6.112))
7906 return dewPoint
7908def ComputeLST(mjdsec, longitude):
7909 """
7910 Computes the LST (in hours) for a specified time and longitude.
7911 The input longitude is in degrees, where east of Greenwich is positive.
7912 -- Todd Hunter
7913 """
7914 JD = mjdToJD(mjdsec/86400.)
7915 T = (JD - 2451545.0) / 36525.0
7916 sidereal = 280.46061837 + 360.98564736629*(JD - 2451545.0) + 0.000387933*T*T - T*T*T/38710000.
7917 # now we have LST in Greenwich, need to scale back to site
7918 sidereal += longitude
7919 sidereal /= 360.
7920 sidereal -= np.floor(sidereal)
7921 sidereal *= 24.0
7922 if (sidereal < 0):
7923 sidereal += 24
7924 if (sidereal >= 24):
7925 sidereal -= 24
7926 return(sidereal)
7928def mjdToJD(MJD):
7929 """
7930 Converts an MJD value to JD
7931 """
7932 JD = MJD + 2400000.5
7933 return(JD)
7935def splitListIntoContiguousLists(mylist):
7936 """
7937 Converts [1,2,3,5,6,7] into [[1,2,3],[5,6,7]], etc.
7938 -Todd Hunter
7939 """
7940 mylists = []
7941 newlist = [mylist[0]]
7942 for i in range(1,len(mylist)):
7943 if (mylist[i-1] != mylist[i]-1):
7944 mylists.append(newlist)
7945 newlist = [mylist[i]]
7946 else:
7947 newlist.append(mylist[i])
7948 mylists.append(newlist)
7949 return(mylists)
7951# Removed for CAS-8065
7952#def getScansForTimes(mymsmd, scantimes):
7953# myscans = []
7954# myscantimes = []
7955## print("len(scantimes) = ", len(scantimes))
7956# scantimes = splitListIntoContiguousLists(scantimes)
7957# for t in scantimes:
7958# mean_t = np.mean(t)
7959# range_t = (1+np.max(t)-np.min(t))*0.5
7960# scans_t = mymsmd.scansfortimes(mean_t, range_t)
7961# if (len(scans_t) > 0):
7962# scan = scans_t[0]
7963# # print("scansfortime(%f) = " % (t), scan)
7964# myscans.append(scan)
7965# myscantimes.append(t)
7966# return(myscans, myscantimes)
7968def pruneFilelist(filelist):
7969 """
7970 Reduce size of filenames in filelist to the extent that current working directory
7971 agrees with the path.
7972 """
7973 mypwd = os.getcwd() + '/'
7974 newfilelist = []
7975 for f in filelist:
7976 fstart = 0
7977 if (f.find(mypwd) == 0):
7978 fstart = len(mypwd)
7979 newfilelist.append(f[fstart:])
7980 return(newfilelist)