From 4eae2b6445edc624aa33bd5f34ebcff3a16ef051 Mon Sep 17 00:00:00 2001 From: Matthew Kolopanis Date: Wed, 30 Oct 2019 15:03:24 -0700 Subject: [PATCH 1/9] plum x_orientation through polnum2str --- hera_qm/firstcal_metrics.py | 3 ++- hera_qm/utils.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/hera_qm/firstcal_metrics.py b/hera_qm/firstcal_metrics.py index c3fafd7d..0bfe6227 100644 --- a/hera_qm/firstcal_metrics.py +++ b/hera_qm/firstcal_metrics.py @@ -348,7 +348,8 @@ def __init__(self, calfits_files, use_gp=True): self.UVC = UVCal() self.UVC.read_calfits(calfits_files) - self.pols = np.array([uvutils.polnum2str(jones) for jones in self.UVC.jones_array]) + self.pols = np.array([uvutils.polnum2str(jones, x_orientation=self.UVC.x_orientation) + for jones in self.UVC.jones_array]) self.Npols = self.pols.size # get file prefix diff --git a/hera_qm/utils.py b/hera_qm/utils.py index 476dab49..4e4ce2d9 100644 --- a/hera_qm/utils.py +++ b/hera_qm/utils.py @@ -417,7 +417,8 @@ def generate_fullpol_file_list(files, pol_list): # convert the polarization array to strings and compare with the # expected input. # If anyone file is not a full-pol file then this will be false. - input_pols = uvutils.polnum2str(uvd.polarization_array) + input_pols = uvutils.polnum2str(uvd.polarization_array, + x_orientation=uvd.x_orientation) full_pol_check = np.array_equal(np.sort(input_pols), np.sort(pol_list)) if not full_pol_check: From c9fc8fb3209957d9b02bdf918cec675515835bf0 Mon Sep 17 00:00:00 2001 From: Adam Beardsley Date: Wed, 30 Oct 2019 15:13:22 -0700 Subject: [PATCH 2/9] try to fix pols kwarg --- hera_qm/ant_metrics.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hera_qm/ant_metrics.py b/hera_qm/ant_metrics.py index 974f4b85..fef1f6f6 100644 --- a/hera_qm/ant_metrics.py +++ b/hera_qm/ant_metrics.py @@ -809,8 +809,8 @@ def _run_all_metrics(self, run_mean_vij=True, run_red_corr=True, if run_red_corr: metNames.append('redCorr') - - redCorr = self.red_corr_metrics(pols=['xx', 'yy'], + pols = [pol for pol in self.pols if pol[0] == pol[1]] + redCorr = self.red_corr_metrics(pols=pols, xants=self.xants, rawMetric=True) metVals.append(redCorr) From cbb19c415a7f0fba51fd0f55fbd0fdb557f30261 Mon Sep 17 00:00:00 2001 From: Matthew Kolopanis Date: Thu, 31 Oct 2019 12:27:57 -0700 Subject: [PATCH 3/9] add 'n' and 'e' as possible pols for regex statement in metrics io --- hera_qm/metrics_io.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hera_qm/metrics_io.py b/hera_qm/metrics_io.py index 837dda9e..399bb976 100644 --- a/hera_qm/metrics_io.py +++ b/hera_qm/metrics_io.py @@ -379,7 +379,7 @@ def _parse_key(key): return int(str(key)) except ValueError: # is key an antpol tuple? - antpol_regex = r"(\([0-9]*?, \'[xy]\'\))" + antpol_regex = r"(\([0-9]*?, \'[xyne]\'\))" matches = re.findall(antpol_regex, key) try: # split tuple into antenna number and polarization @@ -541,7 +541,7 @@ def _parse_dict(input_str, value_type=int): """ # use regex to extract keys and values # assumes keys are antpols and values are numbers - dict_regex = r'(\([0-9]*?, \'[xy]\'\)): (.*?)[,}]' + dict_regex = r'(\([0-9]*?, \'[xyne]\'\)): (.*?)[,}]' key_vals = re.findall(dict_regex, input_str) # initialize output @@ -606,7 +606,7 @@ def _parse_list_of_antpols(input_str): """ # use regex to extract entries # assumes list entries are antpols - list_regex = r"(\([0-9]*?, \'[xy]\'\))" + list_regex = r"(\([0-9]*?, \'[xyne]\'\))" entries = re.findall(list_regex, input_str) # initialize output From 2bb722f9b61a4f883f470860b37a21c10b8e3504 Mon Sep 17 00:00:00 2001 From: Matthew Kolopanis Date: Thu, 31 Oct 2019 13:15:01 -0700 Subject: [PATCH 4/9] make firstcal tests use n and e for pols in keys --- hera_qm/tests/test_firstcal_metrics.py | 32 +++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/hera_qm/tests/test_firstcal_metrics.py b/hera_qm/tests/test_firstcal_metrics.py index 0b918832..fe35a336 100644 --- a/hera_qm/tests/test_firstcal_metrics.py +++ b/hera_qm/tests/test_firstcal_metrics.py @@ -45,27 +45,27 @@ def test_init(firstcal_setup): def test_run_metrics(firstcal_setup): firstcal_setup.FC.run_metrics(std_cut=1.0) - assert firstcal_setup.FC.metrics['yy']['good_sol'] is True - assert firstcal_setup.FC.metrics['yy']['bad_ants'] == [] - assert 9 in firstcal_setup.FC.metrics['yy']['z_scores'] - assert 9 in firstcal_setup.FC.metrics['yy']['ant_std'] - assert 9 in firstcal_setup.FC.metrics['yy']['ant_avg'] - assert 9 in firstcal_setup.FC.metrics['yy']['ants'] - assert 9 in firstcal_setup.FC.metrics['yy']['z_scores'] - assert 9 in firstcal_setup.FC.metrics['yy']['ant_z_scores'] - assert np.isclose(1.0, firstcal_setup.FC.metrics['yy']['std_cut']) - assert np.isclose(firstcal_setup.FC.metrics['yy']['agg_std'], 0.044662349588061437) - assert np.isclose(firstcal_setup.FC.metrics['yy']['max_std'], 0.089829821120782846) - assert 'yy' == firstcal_setup.FC.metrics['yy']['pol'] + assert firstcal_setup.FC.metrics['nn']['good_sol'] is True + assert firstcal_setup.FC.metrics['nn']['bad_ants'] == [] + assert 9 in firstcal_setup.FC.metrics['nn']['z_scores'] + assert 9 in firstcal_setup.FC.metrics['nn']['ant_std'] + assert 9 in firstcal_setup.FC.metrics['nn']['ant_avg'] + assert 9 in firstcal_setup.FC.metrics['nn']['ants'] + assert 9 in firstcal_setup.FC.metrics['nn']['z_scores'] + assert 9 in firstcal_setup.FC.metrics['nn']['ant_z_scores'] + assert np.isclose(1.0, firstcal_setup.FC.metrics['nn']['std_cut']) + assert np.isclose(firstcal_setup.FC.metrics['nn']['agg_std'], 0.044662349588061437) + assert np.isclose(firstcal_setup.FC.metrics['nn']['max_std'], 0.089829821120782846) + assert 'nn' == firstcal_setup.FC.metrics['nn']['pol'] # Test bad ants detection firstcal_setup.FC.delay_fluctuations[0, :] *= 1000 firstcal_setup.FC.run_metrics() - assert firstcal_setup.FC.ants[0] == firstcal_setup.FC.metrics['yy']['bad_ants'] + assert firstcal_setup.FC.ants[0] == firstcal_setup.FC.metrics['nn']['bad_ants'] # Test bad full solution firstcal_setup.FC.delay_fluctuations[1:, :] *= 1000 firstcal_setup.FC.run_metrics() - assert firstcal_setup.FC.metrics['yy']['good_sol'] is False + assert firstcal_setup.FC.metrics['nn']['good_sol'] is False def test_write_error_bad_type(firstcal_setup): @@ -217,9 +217,9 @@ def test_rotated_metrics(): FC = firstcal_metrics.FirstCalMetrics(infile) FC.run_metrics(std_cut=0.5) # test pickup of rotant key - assert 'rot_ants' in FC.metrics['xx'].keys() + assert 'rot_ants' in FC.metrics['ee'].keys() # test rotants is correct - assert [43] == FC.metrics['xx']['rot_ants'] + assert [43] == FC.metrics['ee']['rot_ants'] def test_delay_smoothing(): From b5feb19c9a1d9ceca2f4eac36b87264afcc0e283 Mon Sep 17 00:00:00 2001 From: Matthew Kolopanis Date: Thu, 31 Oct 2019 13:20:59 -0700 Subject: [PATCH 5/9] check if initial metrics group is ordered dict too --- hera_qm/metrics_io.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hera_qm/metrics_io.py b/hera_qm/metrics_io.py index 399bb976..e1e916d0 100644 --- a/hera_qm/metrics_io.py +++ b/hera_qm/metrics_io.py @@ -293,6 +293,19 @@ def write_metric_file(filename, input_dict, overwrite=False): # Create group for metrics data in file mgrp = outfile.create_group('Metrics') + if isinstance(input_dict, OrderedDict): + mgrp.attrs['group_is_ordered'] = False + if isinstance(input_dict, OrderedDict): + mgrp.attrs['group_is_ordered'] = True + + # Generate additional dataset in an ordered group to save + # the order of the group + key_order = np.array(list(input_dict.keys())).astype('S') + key_set = mgrp.create_dataset('key_order', data=key_order) + + # Add boolean attribute to determine if key is a string + # Used to parse keys saved to dicts when reading + key_set.attrs['key_is_string'] = True mgrp.attrs['key_is_string'] = True _recursively_save_dict_to_group(outfile, "/Metrics/", input_dict) From e2255c193039883864050327add7ad0f652bf783 Mon Sep 17 00:00:00 2001 From: Matthew Kolopanis Date: Thu, 31 Oct 2019 13:23:18 -0700 Subject: [PATCH 6/9] add python 3.7 tests --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index dbb1b8ca..04742263 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ python: # We don't actually use the Travis Python, but this keeps it organized. - "2.7" - "3.6" + - "3.7" env: global: - COVERALLS_PARALLEL=true From f43d939b1af82224e4a06d80c7467f6149da49e6 Mon Sep 17 00:00:00 2001 From: Matthew Kolopanis Date: Thu, 31 Oct 2019 13:40:38 -0700 Subject: [PATCH 7/9] update two pol result file --- ...ple_two_polarization_firstcal_results.hdf5 | Bin 235816 -> 236024 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/hera_qm/data/example_two_polarization_firstcal_results.hdf5 b/hera_qm/data/example_two_polarization_firstcal_results.hdf5 index c748f17fd39834fa4287ebd125d9e8fa558dcef5..628dd8e1f7a2d359baee66e7f4304e545381f261 100644 GIT binary patch delta 20800 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 WI|{!xMEP&v#6BQ~U*oVOt^Nmp%UV+a delta 21117 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 Date: Thu, 31 Oct 2019 13:40:53 -0700 Subject: [PATCH 8/9] update to handle ordered groups as first dict in a metric file --- hera_qm/metrics_io.py | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/hera_qm/metrics_io.py b/hera_qm/metrics_io.py index e1e916d0..2c3cb9be 100644 --- a/hera_qm/metrics_io.py +++ b/hera_qm/metrics_io.py @@ -293,19 +293,18 @@ def write_metric_file(filename, input_dict, overwrite=False): # Create group for metrics data in file mgrp = outfile.create_group('Metrics') + mgrp.attrs['group_is_ordered'] = False if isinstance(input_dict, OrderedDict): - mgrp.attrs['group_is_ordered'] = False - if isinstance(input_dict, OrderedDict): - mgrp.attrs['group_is_ordered'] = True + mgrp.attrs['group_is_ordered'] = True - # Generate additional dataset in an ordered group to save - # the order of the group - key_order = np.array(list(input_dict.keys())).astype('S') - key_set = mgrp.create_dataset('key_order', data=key_order) + # Generate additional dataset in an ordered group to save + # the order of the group + key_order = np.array(list(input_dict.keys())).astype('S') + key_set = mgrp.create_dataset('key_order', data=key_order) - # Add boolean attribute to determine if key is a string - # Used to parse keys saved to dicts when reading - key_set.attrs['key_is_string'] = True + # Add boolean attribute to determine if key is a string + # Used to parse keys saved to dicts when reading + key_set.attrs['key_is_string'] = True mgrp.attrs['key_is_string'] = True _recursively_save_dict_to_group(outfile, "/Metrics/", input_dict) @@ -903,7 +902,19 @@ def load_metric_file(filename): else: with h5py.File(filename, 'r') as infile: metric_dict = _recursively_load_dict_to_group(infile, "/Header/") - metric_dict.update(_recursively_load_dict_to_group(infile, "/Metrics/")) + metric_item = infile["/Metrics/"] + if hasattr(metric_item, 'attrs'): + if 'group_is_ordered' in metric_item.attrs: + group_is_ordered = metric_item.attrs["group_is_ordered"] + else: + group_is_ordered = False + else: + group_is_ordered = False + metric_dict.update( + _recursively_load_dict_to_group(infile, "/Metrics/", + group_is_ordered=group_is_ordered + ) + ) _recursively_validate_dict(metric_dict) return metric_dict From c5360373ddd7d795e3bfce0121eeba921ae64e0a Mon Sep 17 00:00:00 2001 From: Matthew Kolopanis Date: Thu, 31 Oct 2019 15:47:21 -0700 Subject: [PATCH 9/9] some explicit mapping to int on validate dict because np.int32 exists --- hera_qm/metrics_io.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/hera_qm/metrics_io.py b/hera_qm/metrics_io.py index 2c3cb9be..2a477ede 100644 --- a/hera_qm/metrics_io.py +++ b/hera_qm/metrics_io.py @@ -849,11 +849,13 @@ def _recursively_validate_dict(in_dict): in_dict[key] = _reds_dict_to_list(in_dict[key]) if key in antpair_keys and key != 'reds': - in_dict[key] = list(map(tuple, in_dict[key])) + in_dict[key] = [tuple((int(a1), int(a2))) + for pair in in_dict[key] + for a1, a2 in pair] if key in antpol_keys: - in_dict[key] = [tuple((ant, qm_utils._bytes_to_str(pol))) - if isinstance(pol, bytes) else tuple((ant, (pol))) + in_dict[key] = [tuple((int(ant), qm_utils._bytes_to_str(pol))) + if isinstance(pol, bytes) else tuple((int(ant), (pol))) for ant, pol in in_dict[key]] if key in known_string_keys and isinstance(in_dict[key], bytes): @@ -863,7 +865,7 @@ def _recursively_validate_dict(in_dict): in_dict[key] = [qm_utils._bytes_to_str(n) if isinstance(n, bytes) else n for n in in_dict[key]] - if isinstance(in_dict[key], np.int64): + if isinstance(in_dict[key], (np.int64, np.int32)): in_dict[key] = np.int(in_dict[key]) if isinstance(in_dict[key], dict):