casa
$Rev:20696$
|
00001 # 00002 # listing.py 00003 # 00004 # Module for testing the output of listing tasks (eg. liscal and listvis). 00005 # 00006 00007 import os, sys, re, math, decimal 00008 00009 #============================================================================= 00010 # METHOD: compare 00011 # 00012 # Compare the listvis output (test) with the listvis STANDARD. 00013 # 00014 # Parameters: 00015 # test = list of strings 00016 # STANDARD = list of strings. 00017 # 00018 def compare(test, standard): 00019 testFile = open(test,'r') 00020 testList = testFile.readlines() 00021 standardFile = open(standard,'r') 00022 standardList = standardFile.readlines() 00023 if (testList == standardList): 00024 testFile.close() 00025 standardFile.close() 00026 return True 00027 else: 00028 testFile.close() 00029 standardFile.close() 00030 return False 00031 #============================================================================= 00032 00033 #============================================================================= 00034 # METHOD: diffFiles 00035 # 00036 # Run diff on two files. Write output to a file. 00037 # 00038 # Parameters: 00039 # test = string; name of runtime output file 00040 # STANDARD = string; name of standard file 00041 # prefix = string; prefix for diff output 00042 # 00043 def diffFiles(testOut, standardOut, prefix=""): 00044 diffOut = prefix + '.diff' # diff output 00045 print " - Running command line utility 'diff' on output files." 00046 print " - Writing to " + diffOut 00047 cmdstr = 'diff ' + standardOut + ' ' + testOut + ' > ' + diffOut 00048 print cmdstr 00049 os.system(cmdstr) 00050 #============================================================================= 00051 00052 #============================================================================= 00053 # METHOD: runTests 00054 # 00055 # Automate the testing of metadata and data. 00056 # 00057 # Parameters: 00058 # test = string; name of runtime output file 00059 # standard = string; name of standard file 00060 # precision= string; lower limit of visibility precision allowed 00061 # prefix = string; prefix for diff output 00062 # 00063 def runTests(test, standard, precision, prefix): 00064 00065 equal = True 00066 00067 # Test metadata 00068 print " 1. Checking that metadata agree." 00069 if (diffMetadata(test,standard,prefix=prefix)): 00070 print " Metadata agree" 00071 else: 00072 print " Metadata do not agree!" 00073 equal = False 00074 00075 # Test data (floats) 00076 print " 2. Checking that data agree to within allowed imprecision..." 00077 print " Allowed visibility imprecision is " + precision 00078 if (diffAmpPhsFloat(test,standard,prefix,precision)): 00079 print " Data agree" 00080 else: 00081 print " Data do not agree!" 00082 equal = False 00083 00084 return equal 00085 #============================================================================= 00086 00087 00088 #============================================================================= 00089 # METHOD: diffMetadata 00090 # 00091 # Compare all metadata. Actually, this compares all non-float, non-space 00092 # data in the two files passed by filename. 00093 # 00094 # Parameters: 00095 # test = string; name of runtime output file 00096 # STANDARD = string; name of standard file 00097 # prefix = string; prefix for output file 00098 # 00099 def diffMetadata(testOut, standardOut, prefix=""): 00100 diffOut = prefix + '.diffMetadata' # output 00101 00102 print " - Comparing all non-floats in listing (ignore spaces)" 00103 00104 # Pattern Substitution 00105 unwanted = ((re.compile(r"[ |]([+-]?[0-9]*\.[0-9]+)"), 'x'), # floats 00106 (re.compile(r' '), ''), # spaces 00107 (re.compile(r'-+'), '-+')) # dashes 00108 00109 def filter_out_unwanted(filename, unwanted): 00110 """ 00111 Given a filename and a tuple of (pattern, substitution) 00112 pairs, returns the lines of filename with the patterns 00113 replaced by the substitutions. 00114 """ 00115 fileobj = open(filename, 'r') 00116 newList = [] 00117 for line in fileobj: 00118 filtered = line 00119 for pat, subst in unwanted: 00120 filtered = pat.sub(subst, filtered) 00121 newList.append(filtered) 00122 fileobj.close() 00123 return newList 00124 00125 testList = filter_out_unwanted(testOut, unwanted) 00126 stndList = filter_out_unwanted(standardOut, unwanted) 00127 00128 # If everything after filtering is equal, return True 00129 if testList == stndList: 00130 return True 00131 00132 # else... do the rest 00133 print " - Writing differences to ", diffOut 00134 00135 sys.stdout = open(diffOut,'w') # redirect stdout 00136 printDiff('','',[standardOut,testOut]) # Print some header info 00137 00138 countDiff = 0 # Count number of different lines 00139 00140 nlines = min(len(testList),len(stndList)) 00141 00142 #for linenum in range(len(testList)): 00143 for linenum in range(nlines): 00144 if ( testList[linenum] != stndList[linenum] ): 00145 countDiff += 1 00146 print "- (line ", linenum, ") Non-float data differs:" 00147 printDiff(stndList[linenum],testList[linenum]) 00148 00149 ndiffl = 0 00150 if nlines < len(stndList): 00151 ndiffl = len(stndList)-nlines 00152 print " missing %s lines" % ndiffl 00153 if nlines == len(stndList): 00154 ndiffl = len(testList)-nlines 00155 print " extra %s lines" % ndiffl 00156 00157 countDiff += ndiffl 00158 print "" 00159 print "SUMMARY (diffMetadata): " 00160 print " %10i = Total number of lines with non-float differences" % countDiff 00161 00162 # Restore stdout 00163 sys.stdout = sys.__stdout__ 00164 00165 return False 00166 #============================================================================= 00167 00168 #============================================================================= 00169 # METHOD: diffAmpPhsFloat 00170 # 00171 # Compare floating point values of Amplitude and Phase. 00172 # 00173 00174 def diffAmpPhsFloat(test, standard, prefix="", precision="1e-6"): 00175 00176 # Preliminary messages 00177 floatOut = prefix + '.diffAmpPhsFloat' 00178 print " - Comparing float content of output." 00179 #print " - Assuming all floats are Amplitude-Phase pairs!" 00180 print " - Writing to " + floatOut 00181 00182 sys.stdout = open(floatOut,'w') 00183 00184 # Read in files 00185 testFile = open(test,'r') 00186 standardFile = open(standard,'r') 00187 testList = testFile.readlines() 00188 standardList = standardFile.readlines() 00189 00190 # Reg exp for matching floats 00191 floatPat = re.compile(r"[ |]([+-]?[0-9]*\.[0-9]+)") 00192 00193 # Verify same number of lines 00194 if ( len(standardList) != len(testList) ): 00195 print "- Standard and test files do not have the same number of lines." 00196 testFile.close() 00197 standardFile.close() 00198 return False 00199 00200 # Initialize some variables 00201 equal = True # To start, assume floats are equal 00202 countUnequal = 0 # Count of unequal Amp-Phs pairs 00203 countBigDif = 0 # Count of Amp-Phs pairs that differ above precision 00204 maxAmpDiff = 0 # Maximum difference amplitude 00205 precision = decimal.Decimal(precision) # Allowed precision 00206 00207 # For each line, compare Amp-Phs in both files 00208 00209 for linenum in range(min(10, len(testList))): 00210 # Generate a list of all floats 00211 tFloatList = floatPat.findall(testList[linenum]) 00212 sFloatList = floatPat.findall(standardList[linenum]) 00213 #print 'tFloatList=', tFloatList 00214 # Test floats 00215 # Same number of floats in both lines? 00216 if ( len(tFloatList) != len(sFloatList) ): 00217 equal = False 00218 print "- (line ", linenum, ") Number of floats not equal:" 00219 printDiff(standardList[linenum],testList[linenum]) 00220 continue 00221 # Number of floats per line should be even 00222 #elif ( len(tFloatList) % 2 ): 00223 #print "- (line ", linenum, ") Odd number of floats! All must be Amp-Phs pairs!" 00224 # continue 00225 #print "stopping listing.diffAmpPhsFloat now!" 00226 #return 00227 00228 # Compare all Amp-Phs pairs on this line 00229 for i in range(len(tFloatList)/2): 00230 00231 # If the Amp or Phs not exactly equal 00232 if ( ( tFloatList[i*2] != sFloatList[i*2] ) or 00233 ( tFloatList[i*2+1] != sFloatList[i*2+1] ) ): 00234 00235 countUnequal += 1 00236 00237 # Calculate complex number for test file 00238 tamp = decimal.Decimal(tFloatList[i*2]) 00239 tphs_deg = decimal.Decimal(tFloatList[i*2+1]) 00240 pi = decimal.Decimal(str(math.pi)) 00241 tphs = tphs_deg * pi / 180 00242 def dcos(x): return decimal.Decimal(str(math.cos(x))) 00243 def dsin(x): return decimal.Decimal(str(math.sin(x))) 00244 tre = dcos(tphs) * tamp 00245 tim = dsin(tphs) * tamp 00246 00247 # Calculate complex number for standard file 00248 samp = decimal.Decimal(sFloatList[i*2]) 00249 sphs_deg = decimal.Decimal(sFloatList[i*2+1]) 00250 sphs = sphs_deg * pi / 180 00251 sre = dcos(sphs) * samp 00252 sim = dsin(sphs) * samp 00253 00254 # Compute number of significant figures 00255 # Find the minimum sig figs for both Amp-Phs pairs. 00256 # Here significant figures means the number of 00257 # digits displayed, not including an exponent. 00258 # Examples: '0.00' has 3 sig figs 00259 # '0.001' has 4 sig fig 00260 # '-1e-15' has 1 sig fig 00261 def remove_exp(x): return x.split("e")[0] 00262 digitPattern = re.compile(r"([0-9])") 00263 minSigFigs = 8 00264 for i in [tamp, tphs_deg, tphs, samp, sphs_deg]: 00265 num1 = str(i) 00266 num1 = remove_exp(num1) 00267 sigFigs = digitPattern.findall(num1) 00268 if (len(sigFigs) < minSigFigs): minSigFigs = len(sigFigs) 00269 00270 # Compute difference of real and imaginary parts 00271 re_diff = (sre - tre) 00272 im_diff = (sim - tim) 00273 00274 # Compute the amplitude of the difference 00275 amp_diff = str(math.sqrt( re_diff**2 + im_diff**2 )) 00276 amp_diff = decimal.Decimal(amp_diff) 00277 00278 # If necessary, reduce amp_diff to minimum sig figs 00279 # I do this by taking advantage of the decimal module, 00280 # which can output and input a tuple. 00281 # * I truncate the number. Rounding would be better, 00282 # I just have not implemented it yet. 00283 adTup = amp_diff.as_tuple() 00284 digits_adTup = len(adTup[1]) 00285 if (digits_adTup > minSigFigs): 00286 amp_diff = decimal.Decimal( (adTup[0], 00287 adTup[1][0:minSigFigs], 00288 adTup[2]+(digits_adTup-minSigFigs) ) ) 00289 00290 # Keep track of the maximum Amp difference between both files 00291 if (amp_diff > maxAmpDiff): maxAmpDiff = amp_diff 00292 00293 # Are Amp-Phs pairs equal within precision? 00294 if (amp_diff > precision): 00295 if (countBigDif == 0): printDiff("","",[standard,test]) # Print header info 00296 equal = False # test evaluates false 00297 countBigDif += 1 00298 print "- (line ", linenum, ") Amp,Phs differ by more than precision:" 00299 printDiff(standardList[linenum],testList[linenum]) 00300 print " (Amp,Phs): (", samp,",",sphs_deg,") , (",tamp,",",tphs_deg,")" 00301 print " ( Re, Im): (", sre ,",",sim ,") , (",tre ,",",tim ,")" 00302 print " Min sig figs = ", minSigFigs 00303 print " Difference amplitude :", amp_diff, " > ", precision 00304 # else: 00305 # print "- (line ", linenum, ") Amp,Phs within required precision:" 00306 # printDiff(standardList[linenum],testList[linenum]) 00307 # print " Difference amplitude :", amp_diff, " <= ", precision 00308 00309 print "" 00310 print "SUMMARY (diffAmpPhsFloat): " 00311 print " %10i = Total number of Amp-Phs pair differences" % countUnequal 00312 print " %10i = Total number of differences above precision" % countBigDif 00313 print " %10f = Input precision requirement" % precision 00314 print " %10f = Largest difference amplitude" % maxAmpDiff 00315 00316 # Restore stdout 00317 sys.stdout = sys.__stdout__ 00318 00319 # cleanup 00320 testFile.close() 00321 standardFile.close() 00322 00323 return equal 00324 00325 #============================================================================= 00326 00327 #============================================================================= 00328 # METHOD: printDiff 00329 # 00330 # Print two different strings 00331 def printDiff(s1, s2, filenames=[]): 00332 if (filenames): 00333 print "Printing lines with differences for comparison:" 00334 print " < ", filenames[0] 00335 print " > ", filenames[1] 00336 else: 00337 print "< " + s1, 00338 print "> " + s2, 00339 00340 #============================================================================= 00341 00342 #============================================================================= 00343 # METHOD: removeOut 00344 # 00345 # Remove old output file if it exists 00346 # 00347 # Parameters: 00348 # outputFile = string; file to be removed 00349 def removeOut(outputFile): 00350 if (os.path.exists(outputFile)): 00351 print "Removing old test file " + outputFile 00352 os.remove(outputFile) 00353 #============================================================================= 00354 00355 #============================================================================= 00356 # METHOD: resetData 00357 # 00358 # Reset local data? Returns True or False. 00359 # 00360 # Test data is typically acquired from the local data repository, and is often 00361 # copied to the local directory (in the case of a Measurement Set) or converted 00362 # to a measurement set in the local directory (in the case of a FITS file). 00363 # This method determines whether or not the test should rebuild the data in the 00364 # working directory or use what already exists. 00365 # 00366 # Parameters: 00367 # msname = list of strings; Names of Tables that will be created 00368 # 00369 def resetData(msname, automate=True): 00370 00371 reset_for_test = " " 00372 00373 # If running in automated mode, always refresh data 00374 if (automate): 00375 return True 00376 00377 # Does the data already exist? 00378 for dataFile in msname: 00379 if (not os.path.exists(dataFile)): return True 00380 00381 # If data exists, prompt for user direction 00382 while ( ( reset_for_test[0] != "y" and 00383 reset_for_test[0] != "n" and 00384 reset_for_test[0] != "\n" ) ): 00385 for dataFile in msname: 00386 sys.stdout.write(" " + dataFile+"\n") 00387 sys.stdout.write("Reset above data from scratch? y/[n]: ") 00388 reset_for_test = sys.stdin.readline() 00389 if (reset_for_test[0] == "y"): return True 00390 else: return False 00391 #============================================================================= 00392 00393 #============================================================================= 00394 # METHOD: listcalFix 00395 # 00396 # Remove first line of listcal output. 00397 # (First line contains hard-coded path to input files) 00398 00399 def listcalFix(listcalOut): 00400 os.system('mv ' + listcalOut + ' ' + listcalOut + '.tmp') 00401 os.system('tail -n +2 ' + listcalOut + '.tmp > ' + listcalOut) 00402 os.system('rm -f ' + listcalOut + '.tmp') 00403 return 00404 #============================================================================= 00405 00406 #============================================================================= 00407 # METHOD: reduce 00408 # 00409 # Reduce the size of the output listing by printing every Nth line of file. 00410 # 00411 # This is necessary because the standard listings are stored in the data 00412 # repository and we want to keep these files small. 00413 # 00414 # Parameters: 00415 # N = integer; beginning with line one, print every Nth line of the 00416 # original file 00417 def reduce(filename, N): 00418 00419 # This command prints every 11th line of the file: 00420 # sed -n '1,${p;n;n;n;n;n;n;n;n;n;n;}' infile > outfile 00421 00422 infile = open(filename,'r') 00423 listing = infile.readlines() 00424 00425 rangeL = range(len(listing)) 00426 00427 # picks holds the indices of listing that I want to keep 00428 def f(x): 00429 return x % (N-1) == 0 00430 picks = filter(f,rangeL) 00431 00432 reducedListing = [ listing[i] for i in picks ] 00433 00434 #for i in range(20): print reducedListing[i] 00435 00436 infile.close() 00437 return reducedListing 00438 #============================================================================= 00439 00440 ## #============================================================================= 00441 ## # METHOD: studyDiff 00442 ## # 00443 ## # Return: 1) the number of leading identical digits 00444 ## # 2) the order of magnitude of the difference. 00445 ## def studyDiff(sfloat, tfloat, diffDict=diffDict_template): 00446 ## import math 00447 ## order = 1 00448 ## # Order of magnitude of the difference 00449 ## diffOrd = int(round(math.log10(abs(sfloat - tfloat)))) 00450 ## # Order of magnitude of sfloat 00451 ## ord = int(round(math.log10(abs(sfloat))+0.5)) 00452 ## # Number of digits in common, starting from left 00453 ## digits = ord - diffOrd - 1 00454 ## # Sign difference? 00455 ## signDiff = ( abs(sfloat - tfloat) != abs( abs(sfloat) - abs(tfloat) ) ) 00456 ## if (signDiff): digits = 0 # correct digits 00457 ## # Absolute difference 00458 ## absDiff = abs(sfloat - tfloat) 00459 ## # Relative difference 00460 ## relDiff = abs( (sfloat - tfloat) / sfloat) 00461 ## print "Difference order = ", diffOrd 00462 ## print "Digits same = ", digits 00463 ## print "Sign difference = ", signDiff 00464 ## print "Absolute difference = ", absDiff 00465 ## print "Relative difference = ", relDiff 00466 ## 00467 ## diffDict['diffOrd'].append(diffOrd) 00468 ## diffDict['digits'].append(digits) 00469 ## diffDict['signDiff'].append(signDiff) 00470 ## diffDict['absDiff'].append(absDiff) 00471 ## diffDict['relDiff'].append(relDiff) 00472 ## 00473 ## return 00474 ## 00475 ## #============================================================================= 00476