Antenna Classification Daily Summary¶

by Josh Dillon last updated June 19, 2023

This notebook parses and summarizes the output of the file_calibration notebook to produce a report on per-antenna malfunctions on a daily basis.

Quick links:

• Summary of Per Antenna Issues¶

• Figure 1: Per File Overall Antenna Classification Summary¶

• Figure 2: Per Classifier Antenna Flagging Summary¶

• Figure 3: Array Visualization of Overall Daily Classification¶

InĀ [1]:
import os
os.environ['HDF5_USE_FILE_LOCKING'] = 'FALSE'
import h5py
import hdf5plugin  # REQUIRED to have the compression plugins available
import numpy as np
import pandas as pd
import glob
import os
import matplotlib.pyplot as plt
from hera_cal import io, utils
from hera_qm import ant_class
from uvtools.plot import plot_antpos, plot_antclass
%matplotlib inline
from IPython.display import display, HTML
display(HTML("<style>.container { width:100% !important; }</style>"))
_ = np.seterr(all='ignore')  # get rid of red warnings
%config InlineBackend.figure_format = 'retina'
A module that was compiled using NumPy 1.x cannot be run in
NumPy 2.2.2 as it may crash. To support both 1.x and 2.x
versions of NumPy, modules must be compiled with NumPy 2.0.
Some module may need to rebuild instead e.g. with 'pybind11>=2.12'.

If you are a user of the module, the easiest solution will be to
downgrade to 'numpy<2' or try to upgrade the affected module.
We expect that some modules will need time to support NumPy 2.

Traceback (most recent call last):  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel_launcher.py", line 18, in <module>
    app.launch_new_instance()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/traitlets/config/application.py", line 1075, in launch_instance
    app.start()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/kernelapp.py", line 739, in start
    self.io_loop.start()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/tornado/platform/asyncio.py", line 205, in start
    self.asyncio_loop.run_forever()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/asyncio/base_events.py", line 640, in run_forever
    self._run_once()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/asyncio/base_events.py", line 1992, in _run_once
    handle._run()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/asyncio/events.py", line 88, in _run
    self._context.run(self._callback, *self._args)
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/kernelbase.py", line 545, in dispatch_queue
    await self.process_one()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/kernelbase.py", line 534, in process_one
    await dispatch(*args)
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/kernelbase.py", line 437, in dispatch_shell
    await result
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/ipkernel.py", line 362, in execute_request
    await super().execute_request(stream, ident, parent)
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/kernelbase.py", line 778, in execute_request
    reply_content = await reply_content
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/ipkernel.py", line 449, in do_execute
    res = shell.run_cell(
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/zmqshell.py", line 549, in run_cell
    return super().run_cell(*args, **kwargs)
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3077, in run_cell
    result = self._run_cell(
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3132, in _run_cell
    result = runner(coro)
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/IPython/core/async_helpers.py", line 128, in _pseudo_sync_runner
    coro.send(None)
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3336, in run_cell_async
    has_raised = await self.run_ast_nodes(code_ast.body, cell_name,
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3519, in run_ast_nodes
    if await self.run_code(code, result, async_=asy):
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3579, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "/tmp/ipykernel_14065/3852672648.py", line 10, in <module>
    from hera_cal import io, utils
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/hera_cal/__init__.py", line 22, in <module>
    from . import utils
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/hera_cal/utils.py", line 35, in <module>
    import aipy
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/aipy/__init__.py", line 15, in <module>
    from . import phs, const, coord, deconv
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/aipy/phs.py", line 10, in <module>
    from .miriad import ij2bl, bl2ij
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/aipy/miriad.py", line 12, in <module>
    from . import _miriad
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
File ~/mambaforge/envs/RTP/lib/python3.12/site-packages/numpy/core/_multiarray_umath.py:44, in __getattr__(attr_name)
     39     # Also print the message (with traceback).  This is because old versions
     40     # of NumPy unfortunately set up the import to replace (and hide) the
     41     # error.  The traceback shouldn't be needed, but e.g. pytest plugins
     42     # seem to swallow it and we should be failing anyway...
     43     sys.stderr.write(msg + tb_msg)
---> 44     raise ImportError(msg)
     46 ret = getattr(_multiarray_umath, attr_name, None)
     47 if ret is None:

ImportError: 
A module that was compiled using NumPy 1.x cannot be run in
NumPy 2.2.2 as it may crash. To support both 1.x and 2.x
versions of NumPy, modules must be compiled with NumPy 2.0.
Some module may need to rebuild instead e.g. with 'pybind11>=2.12'.

If you are a user of the module, the easiest solution will be to
downgrade to 'numpy<2' or try to upgrade the affected module.
We expect that some modules will need time to support NumPy 2.

A module that was compiled using NumPy 1.x cannot be run in
NumPy 2.2.2 as it may crash. To support both 1.x and 2.x
versions of NumPy, modules must be compiled with NumPy 2.0.
Some module may need to rebuild instead e.g. with 'pybind11>=2.12'.

If you are a user of the module, the easiest solution will be to
downgrade to 'numpy<2' or try to upgrade the affected module.
We expect that some modules will need time to support NumPy 2.

Traceback (most recent call last):  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel_launcher.py", line 18, in <module>
    app.launch_new_instance()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/traitlets/config/application.py", line 1075, in launch_instance
    app.start()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/kernelapp.py", line 739, in start
    self.io_loop.start()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/tornado/platform/asyncio.py", line 205, in start
    self.asyncio_loop.run_forever()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/asyncio/base_events.py", line 640, in run_forever
    self._run_once()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/asyncio/base_events.py", line 1992, in _run_once
    handle._run()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/asyncio/events.py", line 88, in _run
    self._context.run(self._callback, *self._args)
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/kernelbase.py", line 545, in dispatch_queue
    await self.process_one()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/kernelbase.py", line 534, in process_one
    await dispatch(*args)
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/kernelbase.py", line 437, in dispatch_shell
    await result
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/ipkernel.py", line 362, in execute_request
    await super().execute_request(stream, ident, parent)
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/kernelbase.py", line 778, in execute_request
    reply_content = await reply_content
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/ipkernel.py", line 449, in do_execute
    res = shell.run_cell(
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/zmqshell.py", line 549, in run_cell
    return super().run_cell(*args, **kwargs)
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3077, in run_cell
    result = self._run_cell(
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3132, in _run_cell
    result = runner(coro)
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/IPython/core/async_helpers.py", line 128, in _pseudo_sync_runner
    coro.send(None)
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3336, in run_cell_async
    has_raised = await self.run_ast_nodes(code_ast.body, cell_name,
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3519, in run_ast_nodes
    if await self.run_code(code, result, async_=asy):
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3579, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "/tmp/ipykernel_14065/3852672648.py", line 10, in <module>
    from hera_cal import io, utils
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/hera_cal/__init__.py", line 23, in <module>
    from . import redcal
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/hera_cal/redcal.py", line 13, in <module>
    from .noise import predict_noise_variance_from_autos, infer_dt
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/hera_cal/noise.py", line 12, in <module>
    from . import io
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/hera_cal/io.py", line 40, in <module>
    import aipy
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/aipy/__init__.py", line 15, in <module>
    from . import phs, const, coord, deconv
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/aipy/phs.py", line 10, in <module>
    from .miriad import ij2bl, bl2ij
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/aipy/miriad.py", line 12, in <module>
    from . import _miriad
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
File ~/mambaforge/envs/RTP/lib/python3.12/site-packages/numpy/core/_multiarray_umath.py:44, in __getattr__(attr_name)
     39     # Also print the message (with traceback).  This is because old versions
     40     # of NumPy unfortunately set up the import to replace (and hide) the
     41     # error.  The traceback shouldn't be needed, but e.g. pytest plugins
     42     # seem to swallow it and we should be failing anyway...
     43     sys.stderr.write(msg + tb_msg)
---> 44     raise ImportError(msg)
     46 ret = getattr(_multiarray_umath, attr_name, None)
     47 if ret is None:

ImportError: 
A module that was compiled using NumPy 1.x cannot be run in
NumPy 2.2.2 as it may crash. To support both 1.x and 2.x
versions of NumPy, modules must be compiled with NumPy 2.0.
Some module may need to rebuild instead e.g. with 'pybind11>=2.12'.

If you are a user of the module, the easiest solution will be to
downgrade to 'numpy<2' or try to upgrade the affected module.
We expect that some modules will need time to support NumPy 2.

A module that was compiled using NumPy 1.x cannot be run in
NumPy 2.2.2 as it may crash. To support both 1.x and 2.x
versions of NumPy, modules must be compiled with NumPy 2.0.
Some module may need to rebuild instead e.g. with 'pybind11>=2.12'.

If you are a user of the module, the easiest solution will be to
downgrade to 'numpy<2' or try to upgrade the affected module.
We expect that some modules will need time to support NumPy 2.

Traceback (most recent call last):  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel_launcher.py", line 18, in <module>
    app.launch_new_instance()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/traitlets/config/application.py", line 1075, in launch_instance
    app.start()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/kernelapp.py", line 739, in start
    self.io_loop.start()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/tornado/platform/asyncio.py", line 205, in start
    self.asyncio_loop.run_forever()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/asyncio/base_events.py", line 640, in run_forever
    self._run_once()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/asyncio/base_events.py", line 1992, in _run_once
    handle._run()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/asyncio/events.py", line 88, in _run
    self._context.run(self._callback, *self._args)
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/kernelbase.py", line 545, in dispatch_queue
    await self.process_one()
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/kernelbase.py", line 534, in process_one
    await dispatch(*args)
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/kernelbase.py", line 437, in dispatch_shell
    await result
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/ipkernel.py", line 362, in execute_request
    await super().execute_request(stream, ident, parent)
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/kernelbase.py", line 778, in execute_request
    reply_content = await reply_content
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/ipkernel.py", line 449, in do_execute
    res = shell.run_cell(
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/ipykernel/zmqshell.py", line 549, in run_cell
    return super().run_cell(*args, **kwargs)
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3077, in run_cell
    result = self._run_cell(
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3132, in _run_cell
    result = runner(coro)
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/IPython/core/async_helpers.py", line 128, in _pseudo_sync_runner
    coro.send(None)
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3336, in run_cell_async
    has_raised = await self.run_ast_nodes(code_ast.body, cell_name,
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3519, in run_ast_nodes
    if await self.run_code(code, result, async_=asy):
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3579, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "/tmp/ipykernel_14065/3852672648.py", line 10, in <module>
    from hera_cal import io, utils
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/hera_cal/__init__.py", line 26, in <module>
    from . import abscal
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/hera_cal/abscal.py", line 43, in <module>
    from .smooth_cal import pick_reference_antenna, rephase_to_refant
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/hera_cal/smooth_cal.py", line 15, in <module>
    import aipy
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/aipy/__init__.py", line 15, in <module>
    from . import phs, const, coord, deconv
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/aipy/phs.py", line 10, in <module>
    from .miriad import ij2bl, bl2ij
  File "/home/obs/mambaforge/envs/RTP/lib/python3.12/site-packages/aipy/miriad.py", line 12, in <module>
    from . import _miriad
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
File ~/mambaforge/envs/RTP/lib/python3.12/site-packages/numpy/core/_multiarray_umath.py:44, in __getattr__(attr_name)
     39     # Also print the message (with traceback).  This is because old versions
     40     # of NumPy unfortunately set up the import to replace (and hide) the
     41     # error.  The traceback shouldn't be needed, but e.g. pytest plugins
     42     # seem to swallow it and we should be failing anyway...
     43     sys.stderr.write(msg + tb_msg)
---> 44     raise ImportError(msg)
     46 ret = getattr(_multiarray_umath, attr_name, None)
     47 if ret is None:

ImportError: 
A module that was compiled using NumPy 1.x cannot be run in
NumPy 2.2.2 as it may crash. To support both 1.x and 2.x
versions of NumPy, modules must be compiled with NumPy 2.0.
Some module may need to rebuild instead e.g. with 'pybind11>=2.12'.

If you are a user of the module, the easiest solution will be to
downgrade to 'numpy<2' or try to upgrade the affected module.
We expect that some modules will need time to support NumPy 2.

Settings¶

InĀ [2]:
# Parse settings from environment
ANT_CLASS_FOLDER = os.environ.get("ANT_CLASS_FOLDER", "./")
SUM_FILE = os.environ.get("SUM_FILE", None)
# ANT_CLASS_FOLDER = "/mnt/sn1/2460330"
# SUM_FILE = "/mnt/sn1/2460330/zen.2460330.25463.sum.uvh5"
OC_SKIP_OUTRIGGERS = os.environ.get("OC_SKIP_OUTRIGGERS", "TRUE").upper() == "TRUE"

for param in ['ANT_CLASS_FOLDER', 'SUM_FILE', 'OC_SKIP_OUTRIGGERS']:
    print(f"{param} = '{eval(param)}'")
ANT_CLASS_FOLDER = '/mnt/sn1/data2/2460718'
SUM_FILE = '/mnt/sn1/data2/2460718/zen.2460718.45941.sum.uvh5'
OC_SKIP_OUTRIGGERS = 'True'
InĀ [3]:
if SUM_FILE is not None:
    from astropy.time import Time, TimeDelta
    utc = Time(float(SUM_FILE.split('zen.')[-1].split('.sum.uvh5')[0]), format='jd').datetime
    print(f'Date: {utc.month}-{utc.day}-{utc.year}')
Date: 2-11-2025
InĀ [4]:
# set thresholds for fraction of the day
overall_thresh = .1
all_zero_thresh = .1
eo_zeros_thresh = .1
xengine_diff_thresh = .1
cross_pol_thresh = .5
bad_fem_thresh = .1
high_power_thresh = .1
low_power_thresh = .1
low_corr_thresh = .1
bad_shape_thresh = .5
excess_rfi_thresh = .1
chisq_thresh = .25

Load classifications and other metadata¶

InĀ [5]:
# Load csvs
csv_files = sorted(glob.glob(os.path.join(ANT_CLASS_FOLDER, '*.ant_class.csv')))
jds = [float(f.split('/')[-1].split('zen.')[-1].split('.sum')[0]) for f in csv_files]
tables = [pd.read_csv(f).dropna(axis=0, how='all') for f in csv_files]
table_cols = tables[0].columns[1::2]
class_cols = tables[0].columns[2::2]
print(f'Found {len(csv_files)} csv files starting with {csv_files[0]}')
Found 1851 csv files starting with /mnt/sn1/data2/2460718/zen.2460718.25249.sum.ant_class.csv
InĀ [6]:
# parse ant_strings
ap_strs = np.array(tables[0]['Antenna'])
ants = sorted(set(int(a[:-1]) for a in ap_strs))
translator = ''.maketrans('e', 'n') | ''.maketrans('n', 'e')
InĀ [7]:
# get node numbers
node_dict = {ant: 'Unknown' for ant in ants}
try:
    from hera_mc import cm_hookup
    hookup = cm_hookup.get_hookup('default')
    for ant_name in hookup:
        ant = int("".join(filter(str.isdigit, ant_name)))
        if ant in node_dict:
            if hookup[ant_name].get_part_from_type('node')['E<ground'] is not None:
                node_dict[ant] = int(hookup[ant_name].get_part_from_type('node')['E<ground'][1:])
except:
    pass
nodes = sorted(set(node_dict.values()))
InĀ [8]:
def classification_array(col):
    class_array = np.vstack([t[col] for t in tables])
    class_array[class_array == 'good'] = 1.7
    class_array[class_array == 'suspect'] = 1
    class_array[class_array == 'bad'] = 0
    return class_array.astype(float)
InĀ [9]:
if SUM_FILE is not None:
    hd = io.HERADataFastReader(SUM_FILE)
    ap_tuples = [(int(ap[:-1]), {'e': 'Jee', 'n': 'Jnn'}[ap[-1]]) for ap in ap_strs]
    bad_bools = np.mean(classification_array('Antenna Class') == 0, axis=0) > overall_thresh
    bad_aps = [ap_tuples[i] for i in np.arange(len(ap_tuples))[bad_bools]]
    suspect_bools = np.mean(classification_array('Antenna Class') == 1, axis=0) > overall_thresh
    suspect_aps = [ap_tuples[i] for i in np.arange(len(ap_tuples))[suspect_bools] if ap_tuples[i] not in bad_aps]
    good_aps = [ap for ap in ap_tuples if ap not in bad_aps and ap not in suspect_aps]
    overall_class = ant_class.AntennaClassification(bad=bad_aps, suspect=suspect_aps, good=good_aps)
    autos, _, _ = hd.read(bls=[bl for bl in hd.bls if utils.split_bl(bl)[0] == utils.split_bl(bl)[1]], read_flags=False, read_nsamples=False)
    avg_unflagged_auto = {}
    for pol in ['ee', 'nn']:
        unflagged_autos = [autos[bl] for bl in autos if bl[2] == pol and overall_class[utils.split_bl(bl)[0]] != 'bad']
        if len(unflagged_autos) > 0:
            avg_unflagged_auto[pol] = np.mean(unflagged_autos, axis=(0, 1))
        else:
            avg_unflagged_auto[pol] = np.zeros(len(hd.freqs), dtype=complex)

Figure out and summarize per-antenna issues¶

InĀ [10]:
def print_issue_summary(bad_ant_strs, title, notes='', plot=False):
    '''Print report for list of bad antenna polarizations strings'''
    unique_bad_antnums = [int(ap[:-1]) for ap in bad_ant_strs]
    display(HTML(f'<h2>{title}: ({len(bad_ant_strs)} antpols across {len(set([ba[:-1] for ba in bad_ant_strs]))} antennas)</h2>'))
    if len(notes) > 0:
        display(HTML(f'<h4>{notes}</h4>'))
    if len(bad_ant_strs) > 0:
        print(f'All Bad Antpols: {", ".join(bad_ant_strs)}\n')
    for node in nodes:
        if np.any([node == node_dict[a] for a in unique_bad_antnums]):
            aps = [ap for ap in bad_ant_strs if node_dict[int(ap[:-1])] == node]
            whole_ants = [str(wa) for wa in set([int(ap[:-1]) for ap in aps if ap.translate(translator) in bad_ant_strs])]
            single_pols =  [ap for ap in aps if ap.translate(translator) not in bad_ant_strs]
            print(f'Node {node}:')
            print(f'\tAntpols ({len(aps)} total): {", ".join(aps)}')
            print(f'\tWhole Ants ({len(whole_ants)} total): {", ".join(whole_ants)}')
            print(f'\tSingle Pols ({len(single_pols)} total): {", ".join(single_pols)}')
            if plot and SUM_FILE is not None:
                fig, axes = plt.subplots(1, 2, figsize=(12,4), dpi=70, sharey=True, gridspec_kw={'wspace': 0})
                for ax, pol in zip(axes, ['ee', 'nn']):                    
                    ax.semilogy(autos.freqs / 1e6, avg_unflagged_auto[pol], 'k--', label='Average\nUnflagged\nAuto')
                    for ap in aps:
                        ant = int(ap[:-1]), utils.comply_pol(ap[-1])
                        auto_bl = utils.join_bl(ant, ant)
                        if auto_bl[2] == pol:
                            ax.semilogy(autos.freqs / 1e6, np.mean(autos[auto_bl], axis=0), label=ap)
                    ax.legend()
                    ax.set_xlim([40, 299])
                    ax.set_title(f'{title} on Node {node} ({pol}-antennas)')
                    ax.set_xlabel('Frequency (MHz)')
                axes[0].set_ylabel('Single File Raw Autocorrelation')
                plt.tight_layout()
                plt.show() 
InĀ [11]:
# precompute various helpful quantities
all_slopes = np.vstack([t['Autocorr Slope'] for t in tables])
median_slope = np.median(all_slopes)
bad_slopes = np.vstack([t['Autocorr Slope Class'] for t in tables]) == 'bad'
suspect_slopes = np.vstack([t['Autocorr Slope Class'] for t in tables]) == 'suspect'
bad_shapes = np.vstack([t['Autocorr Shape Class'] for t in tables]) == 'bad'
suspect_shapes = np.vstack([t['Autocorr Shape Class'] for t in tables]) == 'suspect'
all_powers = np.vstack([t['Autocorr Power'] for t in tables])
median_power = np.median(all_powers)
bad_powers = np.vstack([t['Autocorr Power Class'] for t in tables]) == 'bad'
suspect_powers = np.vstack([t['Autocorr Power Class'] for t in tables]) == 'suspect'
bad_rfi = np.vstack([t['Auto RFI RMS Class'] for t in tables]) == 'bad'
suspect_rfi = np.vstack([t['Auto RFI RMS Class'] for t in tables]) == 'suspect'
InĀ [12]:
# find all zeros
all_zeros_strs = ap_strs[np.mean(np.vstack([t['Dead? Class'] for t in tables]) == 'bad', axis=0) > all_zero_thresh]
InĀ [13]:
# find even/odd zeros
eo_zeros_strs = ap_strs[np.mean(np.vstack([t['Even/Odd Zeros Class'] for t in tables]) == 'bad', axis=0) > eo_zeros_thresh]
eo_zeros_strs = [ap for ap in eo_zeros_strs if ap not in all_zeros_strs] 
InĀ [14]:
# find cross-polarized antennas
cross_pol_strs = ap_strs[np.mean(np.vstack([t['Cross-Polarized Class'] for t in tables]) == 'bad', axis=0) > cross_pol_thresh]
cross_pol_strs = [ap for ap in cross_pol_strs if ap not in all_zeros_strs] 
InĀ [15]:
# find FEM power issues: must be low power, high slope, and bad or suspect in power, slope, rfi, and shape
fem_off_prod = (bad_powers + .5 * suspect_powers) * (bad_slopes + .5 * suspect_slopes)
fem_off_prod *= (bad_rfi + .5 * suspect_rfi) * (bad_shapes + .5 * suspect_shapes)
fem_off_strs = ap_strs[np.mean(fem_off_prod * (all_powers < median_power) * (all_slopes > median_slope), axis=0) > .1]
InĀ [16]:
# find high power issues
high_power_strs = ap_strs[np.mean(bad_powers & (all_powers > median_power), axis=0) > high_power_thresh]
InĀ [17]:
# find other low power issues
low_power_strs = ap_strs[np.mean(bad_powers & (all_powers < median_power), axis=0) > low_power_thresh]
low_power_strs = [ap for ap in low_power_strs if ap not in all_zeros_strs and ap not in fem_off_strs] 
InĀ [18]:
# find low correlation (but not low power)
low_corr_strs = ap_strs[np.mean(np.vstack([t['Low Correlation Class'] for t in tables]) == 'bad', axis=0) > low_corr_thresh]
low_corr_strs = [ap for ap in low_corr_strs if ap not in (set(low_power_strs) | set(all_zeros_strs) | set(fem_off_strs))] 
InĀ [19]:
# find bad bandpasses
bad_bandpass_strs = ap_strs[np.mean(bad_shapes, axis=0) > bad_shape_thresh]
bad_bandpass_strs = [ap for ap in bad_bandpass_strs if ap not in (set(low_power_strs) | set(all_zeros_strs) | set(high_power_strs) | set(fem_off_strs))]
InĀ [20]:
# find antennas with excess RFI
excess_rfi_strs = ap_strs[np.mean(np.vstack([t['Auto RFI RMS Class'] for t in tables]) == 'bad', axis=0) > excess_rfi_thresh]
excess_rfi_strs = [ap for ap in excess_rfi_strs if ap not in (set(low_power_strs) | set(all_zeros_strs) |  set(fem_off_strs) |
                                                              set(bad_bandpass_strs) | set(high_power_strs))] 
InĀ [21]:
# find bad x-engine diffs
xengine_diff_strs = ap_strs[np.mean(np.vstack([t['Bad Diff X-Engines Class'] for t in tables]) == 'bad', axis=0) > xengine_diff_thresh]
xengine_diff_strs = [ap for ap in xengine_diff_strs if ap not in (set(bad_bandpass_strs) | set(low_power_strs) | set(excess_rfi_strs) | set(low_corr_strs) |
                                                                  set(all_zeros_strs) | set(high_power_strs) | set(fem_off_strs) | set(eo_zeros_strs))]
InĀ [22]:
# find antennas with high redcal chi^2
chisq_strs = ap_strs[np.mean(np.vstack([t['Redcal chi^2 Class'] for t in tables]) == 'bad', axis=0) > chisq_thresh]
chisq_strs = [ap for ap in chisq_strs if ap not in (set(bad_bandpass_strs) | set(low_power_strs) | set(excess_rfi_strs) | set(low_corr_strs) |
                                                    set(all_zeros_strs) | set(high_power_strs) | set(fem_off_strs) | set(eo_zeros_strs) | set(xengine_diff_strs))]
if OC_SKIP_OUTRIGGERS:
    chisq_strs = [ap for ap in chisq_strs if int(ap[:-1]) < 320]
InĀ [23]:
# collect all results
to_print = [(all_zeros_strs, 'All-Zeros', 'These antennas have visibilities that are more than half zeros.'),
            (eo_zeros_strs, 'Excess Zeros in Either Even or Odd Spectra', 
             'These antennas are showing evidence of packet loss or X-engine failure.', True),
            (xengine_diff_strs, 'Excess Power in X-Engine Diffs', 
             'These antennas are showing evidence of mis-written packets in either the evens or the odds.', True),            
            (cross_pol_strs, 'Cross-Polarized', 'These antennas have their east and north cables swapped.'),
            (fem_off_strs, 'Likely FEM Power Issue', 'These antennas have low power and anomolously high slopes.', True),
            (high_power_strs, 'High Power', 'These antennas have high median power.', True),
            (low_power_strs, 'Other Low Power Issues', 'These antennas have low power, but are not all-zeros and not FEM off.', True),
            (low_corr_strs, 'Low Correlation, But Not Low Power', 'These antennas are low correlation, but their autocorrelation power levels look OK.'),
            (bad_bandpass_strs, 'Bad Bandpass Shapes, But Not Bad Power', 
             'These antennas have unusual bandpass shapes, but are not all-zeros, high power, low power, or FEM off.', True),
            (excess_rfi_strs, 'Excess RFI', 'These antennas have excess RMS after DPSS filtering (likely RFI), but not low or high power or a bad bandpass.', True),
            (chisq_strs, 'Redcal chi^2', 'These antennas have been idenfied as not redundantly calibrating well, even after passing the above checks.')]
InĀ [24]:
def print_high_level_summary():
    for tp in sorted(to_print, key=lambda x: len(x[0]), reverse=True):
        print(f'{len(tp[0])} antpols (on {len(set([ap[:-1] for ap in tp[0]]))} antennas) frequently flagged for {tp[1]}.')
        
def print_all_issue_summaries():
    for tp in to_print:
        print_issue_summary(*tp)

Summary of Per-Antenna Issues¶

InĀ [25]:
print_high_level_summary()
68 antpols (on 34 antennas) frequently flagged for All-Zeros.
42 antpols (on 40 antennas) frequently flagged for Excess RFI.
25 antpols (on 22 antennas) frequently flagged for Likely FEM Power Issue.
13 antpols (on 10 antennas) frequently flagged for Other Low Power Issues.
11 antpols (on 9 antennas) frequently flagged for Low Correlation, But Not Low Power.
10 antpols (on 10 antennas) frequently flagged for Bad Bandpass Shapes, But Not Bad Power.
4 antpols (on 4 antennas) frequently flagged for Excess Power in X-Engine Diffs.
3 antpols (on 3 antennas) frequently flagged for High Power.
3 antpols (on 3 antennas) frequently flagged for Redcal chi^2.
2 antpols (on 1 antennas) frequently flagged for Cross-Polarized.
0 antpols (on 0 antennas) frequently flagged for Excess Zeros in Either Even or Odd Spectra.
InĀ [26]:
print_all_issue_summaries()

All-Zeros: (68 antpols across 34 antennas)

These antennas have visibilities that are more than half zeros.

All Bad Antpols: 43e, 43n, 45e, 45n, 46e, 46n, 60e, 60n, 63e, 63n, 64e, 64n, 73e, 73n, 78e, 78n, 89e, 89n, 124e, 124n, 143e, 143n, 144e, 144n, 145e, 145n, 146e, 146n, 147e, 147n, 148e, 148n, 149e, 149n, 163e, 163n, 164e, 164n, 165e, 165n, 166e, 166n, 184e, 184n, 185e, 185n, 186e, 186n, 187e, 187n, 199e, 199n, 203e, 203n, 219e, 219n, 235e, 235n, 322e, 322n, 325e, 325n, 326e, 326n, 327e, 327n, 331e, 331n

Node 5:
	Antpols (12 total): 43e, 43n, 45e, 45n, 46e, 46n, 60e, 60n, 73e, 73n, 322e, 322n
	Whole Ants (6 total): 322, 73, 43, 45, 46, 60
	Single Pols (0 total): 
Node 6:
	Antpols (6 total): 63e, 63n, 64e, 64n, 78e, 78n
	Whole Ants (3 total): 64, 78, 63
	Single Pols (0 total): 
Node 9:
	Antpols (6 total): 89e, 89n, 124e, 124n, 325e, 325n
	Whole Ants (3 total): 89, 124, 325
	Single Pols (0 total): 
Node 14:
	Antpols (24 total): 143e, 143n, 144e, 144n, 145e, 145n, 146e, 146n, 163e, 163n, 164e, 164n, 165e, 165n, 166e, 166n, 184e, 184n, 185e, 185n, 186e, 186n, 187e, 187n
	Whole Ants (12 total): 163, 164, 165, 166, 143, 144, 145, 146, 184, 185, 186, 187
	Single Pols (0 total): 
Node 15:
	Antpols (6 total): 147e, 147n, 148e, 148n, 149e, 149n
	Whole Ants (3 total): 147, 148, 149
	Single Pols (0 total): 
Node 17:
	Antpols (4 total): 199e, 199n, 235e, 235n
	Whole Ants (2 total): 235, 199
	Single Pols (0 total): 
Node 18:
	Antpols (4 total): 203e, 203n, 219e, 219n
	Whole Ants (2 total): 203, 219
	Single Pols (0 total): 
Node 21:
	Antpols (6 total): 326e, 326n, 327e, 327n, 331e, 331n
	Whole Ants (3 total): 331, 326, 327
	Single Pols (0 total): 

Excess Zeros in Either Even or Odd Spectra: (0 antpols across 0 antennas)

These antennas are showing evidence of packet loss or X-engine failure.

Excess Power in X-Engine Diffs: (4 antpols across 4 antennas)

These antennas are showing evidence of mis-written packets in either the evens or the odds.

All Bad Antpols: 15n, 209n, 226n, 340e

Node 1:
	Antpols (1 total): 15n
	Whole Ants (0 total): 
	Single Pols (1 total): 15n
No description has been provided for this image
Node 19:
	Antpols (1 total): 226n
	Whole Ants (0 total): 
	Single Pols (1 total): 226n
No description has been provided for this image
Node 20:
	Antpols (1 total): 209n
	Whole Ants (0 total): 
	Single Pols (1 total): 209n
No description has been provided for this image
Node 21:
	Antpols (1 total): 340e
	Whole Ants (0 total): 
	Single Pols (1 total): 340e
No description has been provided for this image

Cross-Polarized: (2 antpols across 1 antennas)

These antennas have their east and north cables swapped.

All Bad Antpols: 70e, 70n

Node 4:
	Antpols (2 total): 70e, 70n
	Whole Ants (1 total): 70
	Single Pols (0 total): 

Likely FEM Power Issue: (25 antpols across 22 antennas)

These antennas have low power and anomolously high slopes.

All Bad Antpols: 9e, 20e, 20n, 22n, 30e, 34e, 48e, 48n, 51n, 61e, 68e, 77n, 109n, 120e, 135e, 170e, 182e, 200e, 216n, 218e, 238n, 239e, 329n, 332e, 332n

Node 1:
	Antpols (1 total): 30e
	Whole Ants (0 total): 
	Single Pols (1 total): 30e
No description has been provided for this image
Node 2:
	Antpols (3 total): 9e, 20e, 20n
	Whole Ants (1 total): 20
	Single Pols (1 total): 9e
No description has been provided for this image
Node 3:
	Antpols (2 total): 51n, 68e
	Whole Ants (0 total): 
	Single Pols (2 total): 51n, 68e
No description has been provided for this image
Node 6:
	Antpols (6 total): 22n, 34e, 48e, 48n, 61e, 77n
	Whole Ants (1 total): 48
	Single Pols (4 total): 22n, 34e, 61e, 77n
No description has been provided for this image
Node 8:
	Antpols (1 total): 120e
	Whole Ants (0 total): 
	Single Pols (1 total): 120e
No description has been provided for this image
Node 10:
	Antpols (1 total): 109n
	Whole Ants (0 total): 
	Single Pols (1 total): 109n
No description has been provided for this image
Node 12:
	Antpols (2 total): 135e, 329n
	Whole Ants (0 total): 
	Single Pols (2 total): 135e, 329n
No description has been provided for this image
Node 13:
	Antpols (1 total): 182e
	Whole Ants (0 total): 
	Single Pols (1 total): 182e
No description has been provided for this image
Node 15:
	Antpols (1 total): 170e
	Whole Ants (0 total): 
	Single Pols (1 total): 170e
No description has been provided for this image
Node 17:
	Antpols (2 total): 216n, 218e
	Whole Ants (0 total): 
	Single Pols (2 total): 216n, 218e
No description has been provided for this image
Node 18:
	Antpols (3 total): 200e, 238n, 239e
	Whole Ants (0 total): 
	Single Pols (3 total): 200e, 238n, 239e
No description has been provided for this image
Node 21:
	Antpols (2 total): 332e, 332n
	Whole Ants (1 total): 332
	Single Pols (0 total): 
No description has been provided for this image

High Power: (3 antpols across 3 antennas)

These antennas have high median power.

All Bad Antpols: 201n, 232e, 320n

Node 3:
	Antpols (1 total): 320n
	Whole Ants (0 total): 
	Single Pols (1 total): 320n
No description has been provided for this image
Node 18:
	Antpols (1 total): 201n
	Whole Ants (0 total): 
	Single Pols (1 total): 201n
No description has been provided for this image
Node 21:
	Antpols (1 total): 232e
	Whole Ants (0 total): 
	Single Pols (1 total): 232e
No description has been provided for this image

Other Low Power Issues: (13 antpols across 10 antennas)

These antennas have low power, but are not all-zeros and not FEM off.

All Bad Antpols: 67n, 82e, 82n, 99e, 100n, 104n, 114e, 114n, 137e, 218n, 251e, 262e, 262n

Node 3:
	Antpols (1 total): 67n
	Whole Ants (0 total): 
	Single Pols (1 total): 67n
No description has been provided for this image
Node 7:
	Antpols (5 total): 82e, 82n, 99e, 100n, 137e
	Whole Ants (1 total): 82
	Single Pols (3 total): 99e, 100n, 137e
No description has been provided for this image
Node 8:
	Antpols (1 total): 104n
	Whole Ants (0 total): 
	Single Pols (1 total): 104n
No description has been provided for this image
Node 11:
	Antpols (2 total): 114e, 114n
	Whole Ants (1 total): 114
	Single Pols (0 total): 
No description has been provided for this image
Node 17:
	Antpols (1 total): 218n
	Whole Ants (0 total): 
	Single Pols (1 total): 218n
No description has been provided for this image
Node 20:
	Antpols (2 total): 262e, 262n
	Whole Ants (1 total): 262
	Single Pols (0 total): 
No description has been provided for this image
Node 22:
	Antpols (1 total): 251e
	Whole Ants (0 total): 
	Single Pols (1 total): 251e
No description has been provided for this image

Low Correlation, But Not Low Power: (11 antpols across 9 antennas)

These antennas are low correlation, but their autocorrelation power levels look OK.

All Bad Antpols: 27e, 28e, 28n, 70e, 70n, 104e, 171n, 200n, 255n, 328e, 329e

Node 1:
	Antpols (3 total): 27e, 28e, 28n
	Whole Ants (1 total): 28
	Single Pols (1 total): 27e
Node 4:
	Antpols (2 total): 70e, 70n
	Whole Ants (1 total): 70
	Single Pols (0 total): 
Node 8:
	Antpols (1 total): 104e
	Whole Ants (0 total): 
	Single Pols (1 total): 104e
Node 10:
	Antpols (1 total): 328e
	Whole Ants (0 total): 
	Single Pols (1 total): 328e
Node 12:
	Antpols (1 total): 329e
	Whole Ants (0 total): 
	Single Pols (1 total): 329e
Node 16:
	Antpols (1 total): 171n
	Whole Ants (0 total): 
	Single Pols (1 total): 171n
Node 18:
	Antpols (1 total): 200n
	Whole Ants (0 total): 
	Single Pols (1 total): 200n
Node 23:
	Antpols (1 total): 255n
	Whole Ants (0 total): 
	Single Pols (1 total): 255n

Bad Bandpass Shapes, But Not Bad Power: (10 antpols across 10 antennas)

These antennas have unusual bandpass shapes, but are not all-zeros, high power, low power, or FEM off.

All Bad Antpols: 27e, 28e, 32n, 33n, 130n, 142n, 161n, 180n, 188n, 340n

Node 1:
	Antpols (2 total): 27e, 28e
	Whole Ants (0 total): 
	Single Pols (2 total): 27e, 28e
No description has been provided for this image
Node 2:
	Antpols (2 total): 32n, 33n
	Whole Ants (0 total): 
	Single Pols (2 total): 32n, 33n
No description has been provided for this image
Node 10:
	Antpols (1 total): 130n
	Whole Ants (0 total): 
	Single Pols (1 total): 130n
No description has been provided for this image
Node 13:
	Antpols (3 total): 142n, 161n, 180n
	Whole Ants (0 total): 
	Single Pols (3 total): 142n, 161n, 180n
No description has been provided for this image
Node 15:
	Antpols (1 total): 188n
	Whole Ants (0 total): 
	Single Pols (1 total): 188n
No description has been provided for this image
Node 21:
	Antpols (1 total): 340n
	Whole Ants (0 total): 
	Single Pols (1 total): 340n
No description has been provided for this image

Excess RFI: (42 antpols across 40 antennas)

These antennas have excess RMS after DPSS filtering (likely RFI), but not low or high power or a bad bandpass.

All Bad Antpols: 16e, 18n, 21e, 27n, 29e, 29n, 37n, 40n, 42n, 47e, 51e, 55e, 58e, 72n, 77e, 86e, 92e, 93e, 95e, 97n, 98n, 103e, 104e, 107n, 120n, 121e, 121n, 134e, 158n, 198n, 200n, 202n, 208e, 212n, 213e, 215n, 246e, 250e, 253n, 268n, 320e, 333e

Node 1:
	Antpols (5 total): 16e, 18n, 27n, 29e, 29n
	Whole Ants (1 total): 29
	Single Pols (3 total): 16e, 18n, 27n
No description has been provided for this image
Node 2:
	Antpols (1 total): 21e
	Whole Ants (0 total): 
	Single Pols (1 total): 21e
No description has been provided for this image
Node 3:
	Antpols (3 total): 37n, 51e, 320e
	Whole Ants (0 total): 
	Single Pols (3 total): 37n, 51e, 320e
No description has been provided for this image
Node 4:
	Antpols (4 total): 40n, 42n, 55e, 72n
	Whole Ants (0 total): 
	Single Pols (4 total): 40n, 42n, 55e, 72n
No description has been provided for this image
Node 5:
	Antpols (1 total): 58e
	Whole Ants (0 total): 
	Single Pols (1 total): 58e
No description has been provided for this image
Node 6:
	Antpols (2 total): 47e, 77e
	Whole Ants (0 total): 
	Single Pols (2 total): 47e, 77e
No description has been provided for this image
Node 7:
	Antpols (1 total): 98n
	Whole Ants (0 total): 
	Single Pols (1 total): 98n
No description has been provided for this image
Node 8:
	Antpols (6 total): 86e, 103e, 104e, 120n, 121e, 121n
	Whole Ants (1 total): 121
	Single Pols (4 total): 86e, 103e, 104e, 120n
No description has been provided for this image
Node 9:
	Antpols (1 total): 107n
	Whole Ants (0 total): 
	Single Pols (1 total): 107n
No description has been provided for this image
Node 10:
	Antpols (2 total): 92e, 93e
	Whole Ants (0 total): 
	Single Pols (2 total): 92e, 93e
No description has been provided for this image
Node 11:
	Antpols (3 total): 95e, 97n, 134e
	Whole Ants (0 total): 
	Single Pols (3 total): 95e, 97n, 134e
No description has been provided for this image
Node 12:
	Antpols (2 total): 158n, 333e
	Whole Ants (0 total): 
	Single Pols (2 total): 158n, 333e
No description has been provided for this image
Node 16:
	Antpols (1 total): 213e
	Whole Ants (0 total): 
	Single Pols (1 total): 213e
No description has been provided for this image
Node 17:
	Antpols (2 total): 198n, 215n
	Whole Ants (0 total): 
	Single Pols (2 total): 198n, 215n
No description has been provided for this image
Node 18:
	Antpols (2 total): 200n, 202n
	Whole Ants (0 total): 
	Single Pols (2 total): 200n, 202n
No description has been provided for this image
Node 20:
	Antpols (2 total): 208e, 246e
	Whole Ants (0 total): 
	Single Pols (2 total): 208e, 246e
No description has been provided for this image
Node 21:
	Antpols (1 total): 212n
	Whole Ants (0 total): 
	Single Pols (1 total): 212n
No description has been provided for this image
Node 22:
	Antpols (3 total): 250e, 253n, 268n
	Whole Ants (0 total): 
	Single Pols (3 total): 250e, 253n, 268n
No description has been provided for this image

Redcal chi^2: (3 antpols across 3 antennas)

These antennas have been idenfied as not redundantly calibrating well, even after passing the above checks.

All Bad Antpols: 83n, 136n, 154n

Node 7:
	Antpols (1 total): 83n
	Whole Ants (0 total): 
	Single Pols (1 total): 83n
Node 12:
	Antpols (1 total): 136n
	Whole Ants (0 total): 
	Single Pols (1 total): 136n
Node 16:
	Antpols (1 total): 154n
	Whole Ants (0 total): 
	Single Pols (1 total): 154n

Full-Day Visualizations¶

InĀ [27]:
def classification_plot(col):
    class_array = classification_array(col)
    plt.figure(figsize=(12, len(ants) / 10), dpi=100)
    plt.imshow(class_array.T, aspect='auto', interpolation='none', cmap='RdYlGn', vmin=0, vmax=2,
               extent=[jds[0] - np.floor(jds[0]), jds[-1] - np.floor(jds[0]), len(ants), 0])
    plt.xlabel(f'JD - {int(jds[0])}')
    plt.yticks(ticks=np.arange(.5, len(ants)+.5), labels=[ant for ant in ants], fontsize=6)
    plt.ylabel('Antenna Number (East First, Then North)')
    plt.gca().tick_params(right=True, top=True, labelright=True, labeltop=True)
    plt.tight_layout()
    plt.title(f'{col}: Green is "good", Yellow is "suspect", Red is "bad"')

Figure 1: Per-File Overall Antenna Classification Summary¶

This "big green board" shows the overall (i.e. after redundant calibration) classification of antennas on a per-file basis. This is useful for looking at time-dependent effects across the array. While only antenna numbers are labeled, both polarizations are shown, first East then North going down, above and below the antenna's tick mark.

InĀ [28]:
classification_plot('Antenna Class')
No description has been provided for this image
InĀ [29]:
# compute flag fractions for all classifiers and antennas
frac_flagged = []
for col in class_cols[1:]:
    class_array = np.vstack([t[col] for t in tables])
    class_array[class_array == 'good'] = False
    class_array[class_array == 'suspect'] = False
    class_array[class_array == 'bad'] = True
    frac_flagged.append(np.sum(class_array, axis=0))
InĀ [30]:
def plot_flag_frac_all_classifiers():
    ticks = []
    for i, col in enumerate(list(class_cols[1:])):
        ticks.append(f'{col} ({np.nanmean(np.array(frac_flagged).astype(float)[i]) / len(csv_files):.2%})')
    plt.figure(figsize=(8, len(ants) / 10), dpi=100)
    plt.imshow(np.array(frac_flagged).astype(float).T, aspect='auto', interpolation='none', cmap='viridis')
    plt.xticks(ticks=np.arange(len(list(class_cols[1:]))), labels=ticks, rotation=-45, ha='left')
    plt.yticks(ticks=np.arange(.5, len(ap_strs)+.5, 2), labels=[ant for ant in ants], fontsize=6)
    plt.ylabel('Antenna Number (East First, Then North)')
    plt.gca().tick_params(right=True, labelright=True,)
    ax2 = plt.gca().twiny()
    ax2.set_xticks(ticks=np.arange(len(list(class_cols[1:]))), labels=ticks, rotation=45, ha='left')
    plt.colorbar(ax=plt.gca(), label=f'Number of Files Flagged Out of {len(csv_files)}', aspect=50)
    plt.tight_layout()

Figure 2: Per-Classifier Antenna Flagging Summary¶

This plot shows the fraction of files flagged for each reason for each antenna. It's useful for seeing which problems are transitory and which ones are more common. Note that not all flags are independent and in particular redcal chi^2 takes an OR of other classifications as an input. Also note that only antenna numbers are labeled, both polarizations are shown, first East then North going down, above and below the antenna's tick mark.

InĀ [31]:
plot_flag_frac_all_classifiers()
No description has been provided for this image
InĀ [32]:
def array_class_plot():
    fig, axes = plt.subplots(1, 2, figsize=(14, 6), dpi=100, gridspec_kw={'width_ratios': [2, 1]})
    plot_antclass(hd.antpos, overall_class, ax=axes[0], ants=[ant for ant in hd.data_ants if ant < 320], legend=False, 
                  title=f'HERA Core: Overall Flagging Based on {overall_thresh:.1%} Daily Threshold')
    plot_antclass(hd.antpos, overall_class, ax=axes[1], ants=[ant for ant in hd.data_ants if ant >= 320], radius=50, title='Outriggers')

Figure 3: Array Visualization of Overall Daily Classification¶

Overall classification of antenna-polarizations shown on the array layout. If any antenna is marked bad for any reason more than the threshold (default 10%), it is marked bad here. Likewise, if any antenna is marked suspect for more than 10% of the night (but not bad), it's suspect here.

InĀ [33]:
if SUM_FILE is not None: array_class_plot()
WARNING:matplotlib.axes._base:Ignoring fixed x limits to fulfill fixed data aspect with adjustable data limits.
WARNING:matplotlib.axes._base:Ignoring fixed x limits to fulfill fixed data aspect with adjustable data limits.
WARNING:matplotlib.axes._base:Ignoring fixed y limits to fulfill fixed data aspect with adjustable data limits.
WARNING:matplotlib.axes._base:Ignoring fixed x limits to fulfill fixed data aspect with adjustable data limits.
WARNING:matplotlib.axes._base:Ignoring fixed x limits to fulfill fixed data aspect with adjustable data limits.
No description has been provided for this image
InĀ [34]:
for repo in ['pyuvdata', 'hera_cal', 'hera_qm', 'hera_notebook_templates']:
    exec(f'from {repo} import __version__')
    print(f'{repo}: {__version__}')
pyuvdata: 3.1.3
hera_cal: 3.7.1.dev11+g34d99e4
hera_qm: 2.2.1.dev2+ga535e9e
hera_notebook_templates: 0.1.dev989+gee0995d