Commits
Takeshi Nakazato authored bbe7d372e53 Merge
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 | |