Commits

Takeshi Nakazato authored bbe7d372e53 Merge
Merge branch 'master' into CAS-13863
No tags

casatestutils/casatestutils/testhelper.py

Modified
21 21 A set of common helper functions for unit tests:
22 22 compTables - compare two CASA tables
23 23 compVarColTables - Compare a variable column of two tables
24 24 DictDiffer - a class with methods to take a difference of two
25 25 Python dictionaries
26 26 verifyMS - Function to verify spw and channels information in an MS
27 27 create_input - Save the string in a text file with the given name
28 28 '''
29 29
30 30 def phasediffabsdeg(c1, c2):
31 + """
32 + Computes the absolute phase difference between two complex numbers in degrees.
33 +
34 + This function calculates the difference in phase angles between two complex numbers
35 + and returns the result in degrees. If either input is a real number (i.e., has no
36 + imaginary component), it returns zero, as the phase difference of real numbers is always zero.
37 +
38 + Args:
39 + c1 (complex): The first complex number.
40 + c2 (complex): The second complex number.
41 +
42 + Returns:
43 + float: The absolute phase difference between `c1` and `c2` in degrees. Returns 0.0
44 + if either input is a real number.
45 +
46 + Raises:
47 + ValueError: If the inputs are not complex numbers.
48 + """
31 49 try:
32 50 a = c1.imag
33 51 a = c2.imag
34 52 except:
35 53 print("Phase difference of real numbers is always zero.")
36 54 return 0.
37 55
38 56 a = math.atan2(c1.imag, c1.real)
39 57 b = math.atan2(c2.imag, c2.real)
40 58 diff = abs(a-b)
41 59 if diff>np.pi:
42 60 diff = 2*np.pi - diff
43 61 return diff/np.pi*180. # (degrees)
44 62
45 63 def compTables(referencetab, testtab, excludecols, tolerance=0.001, mode="percentage", startrow = 0, nrow = -1, rowincr = 1):
46 -
47 64 """
48 - compTables - compare two CASA tables
49 -
50 - referencetab - the table which is assumed to be correct
51 -
52 - testtab - the table which is to be compared to referencetab
53 -
54 - excludecols - list of column names which are to be ignored
55 -
56 - tolerance - permitted fractional difference (default 0.001 = 0.1 percent)
57 -
58 - mode - comparison is made as "percentage", "absolute", "phaseabsdeg" (for complex numbers = difference of the phases in degrees)
65 + Compares columns from two tables and verifies if they match within specified tolerances.
66 +
67 + This function compares corresponding columns in two tables (`referencetab` and `testtab`) while ignoring columns listed in `excludecols`. It evaluates the differences based on the specified `mode` (e.g., "percentage", "absolute", "phaseabsdeg") and tolerance. It checks data types like float, int, string, and list/array, and reports discrepancies.
68 +
69 + Args:
70 + referencetab (str): Path to the reference table file.
71 + testtab (str): Path to the test table file.
72 + excludecols (list of str): List of column names to exclude from comparison.
73 + tolerance (float, optional): Tolerance level for comparison. Default is 0.001.
74 + mode (str, optional): Comparison mode. Can be "percentage", "absolute", or "phaseabsdeg". Default is "percentage".
75 + startrow (int, optional): Starting row index for comparison. Default is 0.
76 + nrow (int, optional): Number of rows to compare. Default is -1, which means all rows.
77 + rowincr (int, optional): Row increment for comparison. Default is 1.
78 +
79 + Returns:
80 + bool: `True` if all compared columns match within the specified tolerance, `False` otherwise.
81 +
82 + Notes:
83 + - Handles comparison of columns with different data types including lists and numpy arrays.
84 + - For "phaseabsdeg" mode, ensure that `phasediffabsdeg` function is defined.
59 85 """
60 -
61 86 rval = True
62 87
63 88 tb_local.open(referencetab)
64 89 cnames = tb_local.colnames()
65 90
66 91 tb_local2.open(testtab)
67 92
68 93 try:
69 94 for c in cnames:
70 95 if c in excludecols:
188 213 rval = False
189 214 break
190 215
191 216 if not differs: print("Column " + c + " PASSED")
192 217 finally:
193 218 tb_local.close()
194 219 tb_local2.close()
195 220
196 221 return rval
197 222
198 -
223 +
199 224 def compVarColTables(referencetab, testtab, varcol, tolerance=0.):
200 - '''Compare a variable column of two tables.
201 - referencetab --> a reference table
202 - testtab --> a table to verify
203 - varcol --> the name of a variable column (str)
204 - Returns True or False.
205 - '''
206 -
225 + """
226 + Compares a variable column from two tables to ensure they match within a specified tolerance.
227 +
228 + This function compares a specific variable column (`varcol`) from two tables (`referencetab` and `testtab`). It checks if the columns are variable columns and if the number of rows matches between the two tables. If a tolerance is provided, it verifies that the values in the column match within this tolerance. If no tolerance is specified, it checks for exact equality.
229 +
230 + Args:
231 + referencetab (str): Path to the reference table file.
232 + testtab (str): Path to the test table file.
233 + varcol (str): The name of the column to compare.
234 + tolerance (float, optional): Tolerance level for comparing numeric values. Default is 0.0, which implies exact equality.
235 +
236 + Returns:
237 + bool: `True` if the variable column matches within the specified tolerance, `False` otherwise.
238 +
239 + Example:
240 + >>> compVarColTables('ref_table.csv', 'test_table.csv', 'variable_column', tolerance=0.01)
241 + ERROR: Column variable_column of ref_table.csv and test_table.csv do not agree within tolerance 0.01
242 + False
243 +
244 + Notes:
245 + - The function assumes that both tables have the same structure and are accessible via a method to open them, retrieve column data, and check if a column is a variable column.
246 + - For lists or arrays within the column, the comparison is performed element-wise.
247 + - If `tolerance` is set to 0, the function checks for exact equality.
248 + """
207 249 retval = True
208 250
209 251 tb_local.open(referencetab)
210 252 cnames = tb_local.colnames()
211 253
212 254 tb_local2.open(testtab)
213 255 col = varcol
214 256 if tb_local.isvarcol(col) and tb_local2.isvarcol(col):
215 257 try:
216 258 # First check
260 302
261 303 else:
262 304 print('Columns are not varcolumns.')
263 305 retval = False
264 306
265 307 if retval:
266 308 print('Column %s of %s and %s agree'%(col,referencetab, testtab))
267 309
268 310 return retval
269 311
270 -
271 -
272 312 class DictDiffer(object):
273 313 """
274 314 Calculate the difference between two dictionaries as:
275 315 (1) items added
276 316 (2) items removed
277 317 (3) keys same in both but changed values
278 318 (4) keys same in both and unchanged values
279 319 Example:
280 320 mydiff = DictDiffer(dict1, dict2)
281 321 mydiff.changed() # to show what has changed
511 551 else:
512 552 discrepantrows = checkwithtaql("select from [select from "+cal1+" where SPECTRAL_WINDOW_ID=="+str(testspw)+" orderby TIME, FIELD_ID, ANTENNA1, ANTENNA2 ] t1, [select from "+cal2+" where SPECTRAL_WINDOW_ID=="+str(testspw)+" orderby TIME, FIELD_ID, ANTENNA1, ANTENNA2 ] t2 where (not all(near(t1."+colname1+",t2."+colname2+", "+str(tolerance)+")))")
513 553 if discrepantrows==0:
514 554 print("The two columns agree.")
515 555 rval = True
516 556 except Exception as instance:
517 557 print("Error: "+str(instance))
518 558
519 559 return rval
520 560
521 -
522 561 def compmsmainnumcol(vis1, vis2, tolerance, colname1='DATA', colname2="DATA"):
523 562 print("Comparing column "+colname1+" of MS "+vis1)
524 563 print(" with column "+colname2+" of MS "+vis2)
525 564 print("Discrepant row search ...")
526 565 rval = False
527 566 try:
528 567 discrepantrows = checkwithtaql("select from [select from "+vis1+" orderby TIME, DATA_DESC_ID, ANTENNA1, ANTENNA2 ] t1, [select from "+vis2+" orderby TIME, DATA_DESC_ID, ANTENNA1, ANTENNA2 ] t2 where (not all(near(t1."+colname1+",t2."+colname2+", "+str(tolerance)+")))")
529 568 if discrepantrows==0:
530 569 print("The two columns agree.")
531 570 rval = True
704 743 if verbose:
705 744 print(("%7s: "%k),s0,s1)
706 745 return status
707 746
708 747
709 748 def get_table_cache():
710 749 cache = tb_local.showcache()
711 750 # print('cache = {}'.format(cache))
712 751 return cache
713 752
714 -def is_casa6():
715 - try:
716 - # CASA 6
717 - from casatools import table
718 - return True
719 - except ImportError:
720 - try:
721 - # CASA 5
722 - from taskinit import tbtool
723 - return False
724 - except ImportError:
725 - raise Exception('Neither CASA5 nor CASA6')
726 -
727 753 class TableCacheValidator(object):
728 754 def __init__(self):
729 755 self.original_cache = get_table_cache()
730 756
731 757 def validate(self):
732 758 cache = get_table_cache()
733 759 #print 'original {} current {}'.format(self.original_cache, cache)
734 760 return len(cache) == 0 or cache == self.original_cache
735 761

Everything looks good. We'll let you know here if there's anything you should know about.

Add shortcut