File Inspection (Experimental)¶

by Josh Dillon, Aaron Parsons, and Tyler Cox, last updated September 25, 2022

This notebook is designed to infer as much information about the array from a single file, including pushing the calibration and RFI mitigation as far as possible

Here's a set of links to skip to particular figures and tables:

  • Figure 1: Plot of autocorrelations with classifications
  • Figure 2: Summary of antenna classifications prior to calibration
  • Figure 3: Redundant calibration of a single baseline group
  • Figure 4: chi^2 per antenna across the array
  • Figure 5: Summary of antenna classifications after redundant calibration
  • Table 1: Complete summary of per antenna classifications
In [1]:
import time
tstart = time.time()
In [2]:
import os
os.environ['HDF5_USE_FILE_LOCKING'] = 'FALSE'
import numpy as np
from scipy import constants, interpolate
import copy
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
pd.set_option('display.max_rows', 1000)
from uvtools.plot import plot_antpos, plot_antclass
from hera_qm import ant_metrics, ant_class, xrfi
from hera_cal import io, utils, redcal, apply_cal, datacontainer, abscal
from hera_notebook_templates.data import DATA_PATH as HNBT_DATA
from IPython.display import display, HTML
import linsolve
display(HTML("<style>.container { width:100% !important; }</style>"))
_ = np.seterr(all='ignore')  # get rid of red warnings
%config InlineBackend.figure_format = 'retina'

Parse inputs¶

To use this notebook interactively, you will have to provide a sum filename path if none exists as an environment variable. All other parameters have reasonable default values.

In [3]:
# get file names
SUM_FILE = os.environ.get("SUM_FILE", None)
# SUM_FILE = '/mnt/sn1/zen.2459797.30001.sum.uvh5'  # If sum_file is not defined in the environment variables, define it here.
DIFF_FILE = SUM_FILE.replace('sum', 'diff')
PLOT = os.environ.get("PLOT", "TRUE").upper() == "TRUE"
if PLOT:
    %matplotlib inline
print(f"SUM_FILE = '{SUM_FILE}'")
SUM_FILE = '/mnt/sn1/2459851/zen.2459851.31239.sum.uvh5'

Parse settings¶

Load settings relating to the operation of the notebook, then print what was loaded (or default).

In [4]:
# parse plotting settings
PLOT = os.environ.get("PLOT", True)
if PLOT:
    %matplotlib inline

# parse omnical settings
OC_MAX_DIMS = int(os.environ.get("OC_MAX_DIMS", 4))
OC_MIN_DIM_SIZE = int(os.environ.get("OC_MIN_DIM_SIZE", 8))
OC_SKIP_OUTRIGGERS = os.environ.get("OC_SKIP_OUTRIGGERS", "TRUE").upper() == "TRUE"
OC_MAXITER = int(os.environ.get("OC_MAXITER", 50))
OC_MAX_RERUN = int(os.environ.get("OC_MAX_RERUN", 4))

# print settings
for setting in ['PLOT', 'OC_MAX_DIMS', 'OC_MIN_DIM_SIZE', 'OC_SKIP_OUTRIGGERS', 'OC_MAXITER', 'OC_MAX_RERUN']:
    print(f'{setting} = {eval(setting)}')
PLOT = True
OC_MAX_DIMS = 4
OC_MIN_DIM_SIZE = 8
OC_SKIP_OUTRIGGERS = True
OC_MAXITER = 50
OC_MAX_RERUN = 4

Parse bounds¶

Load settings related to classifying antennas as good, suspect, or bad, then print what was loaded (or default).

In [5]:
# ant_metrics bounds for low correlation / dead antennas
am_corr_bad = (0, float(os.environ.get("AM_CORR_BAD", 0.3)))
am_corr_suspect = (float(os.environ.get("AM_CORR_BAD", 0.3)), float(os.environ.get("AM_CORR_SUSPECT", 0.5)))

# ant_metrics bounds for cross-polarized antennas
am_xpol_bad = (-1, float(os.environ.get("AM_XPOL_BAD", -0.1)))
am_xpol_suspect = (float(os.environ.get("AM_XPOL_BAD", -0.1)), float(os.environ.get("AM_XPOL_SUSPECT", 0)))

# bounds on zeros in spectra
good_zeros_per_eo_spectrum = (0, int(os.environ.get("MAX_ZEROS_PER_EO_SPEC_GOOD", 2)))
suspect_zeros_per_eo_spectrum = (0, int(os.environ.get("MAX_ZEROS_PER_EO_SPEC_SUSPECT", 8)))

# bounds on autocorrelation power
auto_power_good = (float(os.environ.get("AUTO_POWER_GOOD_LOW", 5)), float(os.environ.get("AUTO_POWER_GOOD_HIGH", 30)))
auto_power_suspect = (float(os.environ.get("AUTO_POWER_SUSPECT_LOW", 1)), float(os.environ.get("AUTO_POWER_SUSPECT_HIGH", 80)))

# bounds on autocorrelation slope
auto_slope_good = (float(os.environ.get("AUTO_SLOPE_GOOD_LOW", -0.2)), float(os.environ.get("AUTO_SLOPE_GOOD_HIGH", 0.2)))
auto_slope_suspect = (float(os.environ.get("AUTO_SLOPE_SUSPECT_LOW", -0.4)), float(os.environ.get("AUTO_SLOPE_SUSPECT_HIGH", 0.4)))

# bounds on autocorrelation RFI
auto_rfi_good = (0, float(os.environ.get("AUTO_RFI_GOOD", 0.075)))
auto_rfi_suspect = (0, float(os.environ.get("AUTO_RFI_SUSPECT", 0.15)))

# bounds on chi^2 per antenna in omnical
oc_cspa_good = (0, float(os.environ.get("OC_CSPA_GOOD", 3)))
oc_cspa_suspect = (float(os.environ.get("OC_CSPA_GOOD", 3)), float(os.environ.get("OC_CSPA_SUSPECT", 4)))

# print bounds
for bound in ['am_corr_bad', 'am_corr_suspect', 'am_xpol_bad', 'am_xpol_suspect', 
              'good_zeros_per_eo_spectrum', 'suspect_zeros_per_eo_spectrum',
              'auto_power_good', 'auto_power_suspect', 'auto_slope_good', 'auto_slope_suspect',
              'auto_rfi_good', 'auto_rfi_suspect', 'oc_cspa_good', 'oc_cspa_suspect']:
    print(f'{bound} = {eval(bound)}')
am_corr_bad = (0, 0.2)
am_corr_suspect = (0.2, 0.4)
am_xpol_bad = (-1, -0.1)
am_xpol_suspect = (-0.1, 0.0)
good_zeros_per_eo_spectrum = (0, 2)
suspect_zeros_per_eo_spectrum = (0, 8)
auto_power_good = (5.0, 30.0)
auto_power_suspect = (1.0, 80.0)
auto_slope_good = (-0.2, 0.2)
auto_slope_suspect = (-0.4, 0.4)
auto_rfi_good = (0, 0.075)
auto_rfi_suspect = (0, 0.15)
oc_cspa_good = (0, 3.0)
oc_cspa_suspect = (3.0, 4.0)

Load sum and diff data¶

In [6]:
hd = io.HERADataFastReader(SUM_FILE)
data, _, _ = hd.read(read_flags=False, read_nsamples=False)
hd_diff = io.HERADataFastReader(DIFF_FILE)
diff_data, _, _ = hd_diff.read(read_flags=False, read_nsamples=False)
In [7]:
ants = sorted(set([ant for bl in hd.bls for ant in utils.split_bl(bl)]))
auto_bls = [bl for bl in data if (bl[0] == bl[1]) and (utils.split_pol(bl[2])[0] == utils.split_pol(bl[2])[1])]
antpols = sorted(set([ant[1] for ant in ants]))
In [8]:
# print basic information about the file
print(f'File: {SUM_FILE}')
print(f'JDs: {hd.times} ({np.median(np.diff(hd.times)) * 24 * 3600:.5f} s integrations)')
print(f'LSTS: {hd.lsts * 12 / np.pi } hours')
print(f'Frequencies: {len(hd.freqs)} {np.median(np.diff(hd.freqs)) / 1e6:.5f} MHz channels from {hd.freqs[0] / 1e6:.5f} to {hd.freqs[-1] / 1e6:.5f} MHz')
print(f'Antennas: {len(hd.data_ants)}')
print(f'Polarizations: {hd.pols}')
File: /mnt/sn1/2459851/zen.2459851.31239.sum.uvh5
JDs: [2459851.31233331 2459851.31244516] (9.66368 s integrations)
LSTS: [21.42803482 21.43072653] hours
Frequencies: 1536 0.12207 MHz channels from 46.92078 to 234.29871 MHz
Antennas: 156
Polarizations: ['nn', 'ee', 'ne', 'en']

Classify good, suspect, and bad antpols¶

Run ant_metrics¶

This classifies antennas as cross-polarized, low-correlation, or dead. Such antennas are excluded from any calibration.

In [9]:
am = ant_metrics.AntennaMetrics(SUM_FILE, DIFF_FILE, sum_data=data, diff_data=diff_data)
am.iterative_antenna_metrics_and_flagging(crossCut=am_xpol_bad[1], deadCut=am_corr_bad[1])
In [10]:
# Turn ant metrics into classifications
totally_dead_ants = [ant for ant, i in am.removal_iteration.items() if i == -1]
am_totally_dead = ant_class.AntennaClassification(good=[ant for ant in ants if ant not in totally_dead_ants], bad=totally_dead_ants)
am_corr = ant_class.antenna_bounds_checker(am.final_metrics['corr'], bad=[am_corr_bad], suspect=[am_corr_suspect], good=[(0, 1)])
am_xpol = ant_class.antenna_bounds_checker(am.final_metrics['corrXPol'], bad=[am_xpol_bad], suspect=[am_xpol_suspect], good=[(-1, 1)])
ant_metrics_class = am_totally_dead + am_corr + am_xpol

Classify antennas responsible for 0s in visibilities as bad:¶

This classifier looks for X-engine failure or packet loss specific to an antenna which causes either the even visibilities (or the odd ones, or both) to be 0s.

In [11]:
zeros_class = ant_class.even_odd_zeros_checker(data, diff_data, good=good_zeros_per_eo_spectrum, suspect=suspect_zeros_per_eo_spectrum)

Examine and classify autocorrelation power, slope, and RFI occpancy¶

These classifiers look for antennas with too high or low power, to steep a slope, or too much excess RFI.

In [12]:
auto_power_class = ant_class.auto_power_checker(data, good=auto_power_good, suspect=auto_power_suspect)
auto_slope_class = ant_class.auto_slope_checker(data, good=auto_slope_good, suspect=auto_slope_suspect, edge_cut=100, filt_size=17)
auto_rfi_class = ant_class.auto_rfi_checker(data, good=auto_rfi_good, suspect=auto_rfi_suspect)
auto_class = auto_power_class + auto_slope_class + auto_rfi_class
In [13]:
def autocorr_plot():    
    fig, axes = plt.subplots(1, 2, figsize=(14, 5), dpi=100, sharey=True, gridspec_kw={'wspace': 0})
    labels = []
    colors = ['darkgreen', 'goldenrod', 'maroon']
    for ax, pol in zip(axes, antpols):
        for ant in auto_class.ants:
            if ant[1] == pol:
                color = colors[auto_class.quality_classes.index(auto_class[ant])]
                ax.semilogy(np.mean(data[utils.join_bl(ant, ant)], axis=0), color=color, lw=.5)
        ax.set_xlabel('Channel', fontsize=12)
        ax.set_title(f'{utils.join_pol(pol, pol)}-Polarized Autos')

    axes[0].set_ylabel('Raw Autocorrelation', fontsize=12)
    axes[1].legend([matplotlib.lines.Line2D([0], [0], color=color) for color in colors], 
                   [cls.capitalize() for cls in auto_class.quality_classes], ncol=1, fontsize=12, loc='upper right', framealpha=1)
    plt.tight_layout()

Figure 1: Plot of autocorrelations with classifications¶

This figure shows a plot of all autocorrelations in the array, split by polarization. Antennas are classified based on their autocorrelations into good, suspect, and bad, by examining power, slope, and RFI-occupancy.

In [14]:
if PLOT: autocorr_plot()

Summarize antenna classification prior to redundant-baseline calibration¶

In [15]:
final_class = ant_metrics_class + zeros_class + auto_class
In [16]:
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, final_class, ax=axes[0], ants=[ant for ant in hd.data_ants if ant < 320], legend=False, title='HERA Core')
    plot_antclass(hd.antpos, final_class, ax=axes[1], ants=[ant for ant in hd.data_ants if ant >= 320], radius=50, title='Outriggers')

Figure 2: Summary of antenna classifications prior to calibration¶

This figure shows the location and classification of all antennas prior to calibration. Antennas are split along the diagonal, with ee-polarized antpols represented by the southeast half of each antenna and nn-polarized antpols represented by the northwest half. Outriggers are split from the core and shown at exaggerated size in the right-hand panel. This classification includes ant_metrics, a count of the zeros in the even or odd visibilities, and autocorrelation power, slope, and RFI occupancy. An antenna classified as bad in any classification will be considered bad. An antenna marked as suspect any in any classification will be considered suspect unless it is also classified as bad elsewhere.

In [17]:
if PLOT: array_class_plot()

Perform redundant-baseline calibration¶

In [18]:
def classify_off_grid(reds, all_ants):
    '''Returns AntennaClassification of all_ants where good ants are in reds while bad ants are not.'''
    ants_in_reds = set([ant for red in reds for bl in red for ant in utils.split_bl(bl)])
    on_grid = [ant for ant in all_ants if ant in ants_in_reds]
    off_grid = [ant for ant in all_ants if ant not in ants_in_reds]
    return ant_class.AntennaClassification(good=on_grid, bad=off_grid)

Perform iterative redcal¶

In [19]:
redcal_start = time.time()
rc_settings = {'fc_conv_crit': 1e-6, 'fc_maxiter': 1, 'fc_min_vis_per_ant': 100, 'max_dims': OC_MAX_DIMS,
               'oc_conv_crit': 1e-10, 'gain': 0.4, 'oc_maxiter': OC_MAXITER, 'check_after': OC_MAXITER}

# figure out and filter reds and classify antennas based on whether or not they are on the main grid
reds = redcal.get_reds(hd.data_antpos, pols=['ee', 'nn'], pol_mode='2pol')
reds = redcal.filter_reds(reds, ex_ants=final_class.bad_ants, max_dims=OC_MAX_DIMS, min_dim_size=1)
if OC_SKIP_OUTRIGGERS:
    reds = redcal.filter_reds(reds, ex_ants=[ant for ant in ants if ant[0] >= 320])
redcal_class = classify_off_grid(reds, ants)

# perform first stage of redundant calibration, 
cal = redcal.redundantly_calibrate(data, reds, **rc_settings)
max_dly = np.max(np.abs(list(cal['fc_meta']['dlys'].values())))
med_cspa = {ant: np.median(cal['chisq_per_ant'][ant]) for ant in cal['chisq_per_ant']}
cspa_class = ant_class.antenna_bounds_checker(med_cspa, good=np.array(oc_cspa_good)*2, suspect=np.array(oc_cspa_suspect)*2, bad=(0, np.inf))
redcal_class += cspa_class
print(f'Removing {cspa_class.bad_ants} for high chi^2.')

# iteratively rerun redundant calibration
for i in range(OC_MAX_RERUN):
    # build RedDataContainer of old visibility solution
    prior_vis = datacontainer.RedDataContainer(cal['v_omnical'], reds)
    
    # refilter reds and update classification to reflect new off-grid ants, if any
    reds = redcal.filter_reds(reds, ex_ants=(final_class + redcal_class).bad_ants, max_dims=OC_MAX_DIMS, min_dim_size=1)
    reds = sorted(reds, key=len, reverse=True)
    redcal_class += classify_off_grid(reds, ants)
    ants_in_reds = set([ant for red in reds for bl in red for ant in utils.split_bl(bl)])    
   
    # re-run redundant calibration using previous solution, updating bad and suspicious antennas
    prior_sol = redcal.RedSol(reds, gains={ant: cal['g_omnical'][ant] for ant in ants_in_reds}, 
                              vis={red[0]: prior_vis[red[0]] for red in reds})    
    cal = redcal.redundantly_calibrate(data, reds, prior_firstcal=prior_sol, prior_sol=prior_sol, **rc_settings)
    med_cspa = {ant: np.median(cal['chisq_per_ant'][ant]) for ant in cal['chisq_per_ant']}
    cspa_class = ant_class.antenna_bounds_checker(med_cspa, good=oc_cspa_good, suspect=oc_cspa_suspect, bad=(0, np.inf))
    redcal_class += cspa_class
    print(f'Removing {cspa_class.bad_ants} for high chi^2.')
    if len(cspa_class.bad_ants) == 0:
        break  # no new antennas to flag
final_class += redcal_class
print(f'Finished redcal in {(time.time() - redcal_start) / 60:.2f} minutes.')
Removing {(70, 'Jnn'), (71, 'Jnn'), (180, 'Jee'), (70, 'Jee'), (71, 'Jee')} for high chi^2.
Removing set() for high chi^2.
Finished redcal in 1.83 minutes.

Fix the firstcal delay slope degeneracy using RFI transmitters¶

In [20]:
# find channels clearly contaminated by RFI
not_bad_ants = [ant for ant in final_class.ants if final_class[ant] != 'bad']
chan_flags = np.mean([xrfi.detrend_medfilt(data[utils.join_bl(ant, ant)], Kf=8, Kt=2) for ant in not_bad_ants], axis=(0, 1)) > 5

# hardcoded RFI transmitters and their headings
# channel: frequency (Hz), heading (rad), chi^2
phs_sol = {359: ( 90744018.5546875, 0.7853981, 23.3),
           360: ( 90866088.8671875, 0.7853981, 10.8),
           385: ( 93917846.6796875, 0.7853981, 27.3),
           386: ( 94039916.9921875, 0.7853981, 18.1),
           400: ( 95748901.3671875, 6.0632738, 24.0),
           441: (100753784.1796875, 0.7853981, 21.7),
           442: (100875854.4921875, 0.7853981, 19.4),
           455: (102462768.5546875, 6.0632738, 18.8),
           456: (102584838.8671875, 6.0632738,  8.8),
           471: (104415893.5546875, 0.7853981, 13.3),
           484: (106002807.6171875, 6.0632738, 21.2),
           485: (106124877.9296875, 6.0632738,  4.0),
          1181: (191085815.4296875, 0.7853981, 26.3),
          1182: (191207885.7421875, 0.7853981, 27.0),
          1183: (191329956.0546875, 0.7853981, 25.6),
          1448: (223678588.8671875, 2.6075219, 25.7),
          1449: (223800659.1796875, 2.6075219, 22.6),
          1450: (223922729.4921875, 2.6075219, 11.6),
          1451: (224044799.8046875, 2.6075219,  5.9),
          1452: (224166870.1171875, 2.6075219, 22.6),
          1510: (231246948.2421875, 0.1068141, 23.9)}
rfi_chans = [chan for chan in phs_sol if chan_flags[chan]]
print('Channels used for delay-slope calibration with RFI:', rfi_chans)
rfi_angles = np.array([phs_sol[chan][1] for chan in rfi_chans])
rfi_headings = np.array([np.cos(rfi_angles), np.sin(rfi_angles), np.zeros_like(rfi_angles)])
rfi_chisqs = np.array([phs_sol[chan][2] for chan in rfi_chans])
Channels used for delay-slope calibration with RFI: [359, 360, 385, 386, 400, 441, 442, 455, 456, 471, 484, 485]
In [21]:
# resolve firstcal degeneracy with delay slopes set by RFI transmitters, update cal
RFI_dly_slope_gains = abscal.RFI_delay_slope_cal(reds, hd.antpos, cal['v_omnical'], hd.freqs, rfi_chans, rfi_headings, rfi_wgts=rfi_chisqs**-.5,
                                                 min_tau=-max_dly, max_tau=max_dly, delta_tau=0.1e-9, return_gains=True, gain_ants=cal['g_omnical'].keys())
cal['g_omnical'] = {ant: g * RFI_dly_slope_gains[ant] for ant, g in cal['g_omnical'].items()}
apply_cal.calibrate_in_place(cal['v_omnical'], RFI_dly_slope_gains)

Perform approximate absolute amplitude calibration using a model of autocorrelations¶

In [22]:
# Load simulated and then downsampled model of autocorrelations that includes receiver noise, then interpolate to upsample
hd_model = io.HERADataFastReader(f'{HNBT_DATA}/SSM_autocorrelations_downsampled.uvh5')
model, _, _ = hd_model.read(read_flags=False, read_nsamples=False)
model = {bl[2]: interpolate.interp2d(model.freqs, model.lsts, np.abs(model[bl]), kind='cubic')(data.freqs, data.lsts) for bl in model}
model = {bl: model[bl[2]] for bl in auto_bls if utils.split_bl(bl)[0] not in final_class.bad_ants}
In [23]:
# Run abscal and update omnical gains with abscal gains
g_abscal = abscal.abs_amp_lincal(model, data, verbose=False, return_gains=True, gain_ants=cal['g_omnical'])
cal['g_omnical'] = {ant: g * g_abscal[ant] for ant, g in cal['g_omnical'].items()}
apply_cal.calibrate_in_place(cal['v_omnical'], g_abscal)
In [24]:
def redundant_group_plot():
    fig, axes = plt.subplots(2, 2, figsize=(14, 6), dpi=100, sharex='col', sharey='row', gridspec_kw={'hspace': 0, 'wspace': 0})
    for i, pol in enumerate(['ee', 'nn']):
        reds_here = redcal.get_reds(hd.data_antpos, pols=[pol], pol_mode='1pol')
        red = sorted(redcal.filter_reds(reds_here, ex_ants=final_class.bad_ants), key=len, reverse=True)[0]
        rc_data = {bl: np.array(data[bl]) for bl in red}
        apply_cal.calibrate_in_place(rc_data, cal['g_omnical'])
        for bl in red:
            axes[0, i].plot(hd.freqs/1e6, np.angle(rc_data[bl][0]), alpha=.5, lw=.5)
            axes[1, i].semilogy(hd.freqs/1e6, np.abs(rc_data[bl][0]), alpha=.5, lw=.5)
        axes[0, i].plot(hd.freqs / 1e6, np.angle(cal['v_omnical'][red[0]][0]), lw=2, c='k')
        axes[1, i].semilogy(hd.freqs / 1e6, np.abs(cal['v_omnical'][red[0]][0]), lw=2, c='k', label=f'Baseline Group:\n{red[0]}')

        axes[1, i].set_xlabel('Frequency (MHz)')
        axes[1, i].legend(loc='upper right')
    axes[0, 0].set_ylabel('Visibility Phase (radians)')
    axes[1, 0].set_ylabel('Visibility Amplitude (Jy)')
    plt.tight_layout()

Figure 3: Redundant calibration of a single baseline group¶

The results of a redundant-baseline calibration of a single integration and a single group, the one with the highest redundancy in each polarization after antenna classification and excision based on the above, plus the removal of antennas with high chi^2 per antenna. The black line is the redundant visibility solution. Each thin colored line is a different baseline group. Phases are shown in the top row, amplitudes in the bottom, ee-polarized visibilities in the left column, and nn-polarized visibilities in the right.

In [25]:
if PLOT: redundant_group_plot()

Attempt to calibrate some flagged antennas¶

This attempts to calibrate bad antennas using information from good or suspect antennas without allowing bad antennas to affect their calibration. However antennas flagged for ant_metrics or lots of zeros in the even or odd visibilities are considered beyond saving. Likewise, some antennas would add extra degeneracies (controlled by OC_MAX_DIMS, OC_MIN_DIM_SIZE, and OC_SKIP_OUTRIGGERS) are excluded.

In [26]:
expand_start = time.time()
expanded_reds = redcal.get_reds(hd.data_antpos, pols=['ee', 'nn'], pol_mode='2pol')
expanded_reds = redcal.filter_reds(expanded_reds, ex_ants=(ant_metrics_class + zeros_class).bad_ants, max_dims=OC_MAX_DIMS, min_dim_size=OC_MIN_DIM_SIZE)
if OC_SKIP_OUTRIGGERS:
    expanded_reds = redcal.filter_reds(expanded_reds, ex_ants=[ant for ant in ants if ant[0] >= 320])
nsamples = datacontainer.DataContainer({bl: np.ones_like(data[bl], dtype=float) for bl in data})
redcal.expand_omni_sol(cal, expanded_reds, data, nsamples)
print(f'Finished expanding omni_sol in {(time.time() - expand_start) / 60:.2f} minutes.')
Finished expanding omni_sol in 0.33 minutes.
In [27]:
def array_chisq_plot():
    fig, axes = plt.subplots(1, 2, figsize=(14, 5), dpi=100)
    for ax, pol in zip(axes, ['ee', 'nn']):
        ants_to_plot = set([ant for ant in cal['chisq_per_ant'] if utils.join_pol(ant[1], ant[1]) == pol])
        cspas = [np.median(cal['chisq_per_ant'][ant]) for ant in ants_to_plot]
        xpos = [hd.antpos[ant[0]][0] for ant in ants_to_plot]
        ypos = [hd.antpos[ant[0]][1] for ant in ants_to_plot]
        scatter = ax.scatter(xpos, ypos, s=300, c=cspas, norm=matplotlib.colors.LogNorm(vmin=1, vmax=10))
        for ant in ants_to_plot:
            ax.text(hd.antpos[ant[0]][0], hd.antpos[ant[0]][1], ant[0], va='center', ha='center', fontsize=9,
                    c=('r' if ant in final_class.bad_ants else 'w'))
        plt.colorbar(scatter, ax=ax, extend='both')
        ax.axis('equal')
        ax.set_xlabel('East-West Position (meters)')
        ax.set_ylabel('North-South Position (meters)')
        ax.set_title(f'{pol}-pol $\\chi^2$ / Antenna (Red is Flagged)')
    plt.tight_layout()

Figure 4: chi^2 per antenna across the array¶

This plot shows median (taken over time and frequency) of the normalized chi^2 per antenna. The expectation value for this quantity when the array is perfectly redundant is 1.0. Antennas that are classified as bad for any reason have their numbers shown in red. Some of those antennas were classified as bad during redundant calibration for high chi^2. Some of those antennas were originally excluded from redundant calibration because they were classified as bad earlier for some reason. See here for more details. Note that the color scale saturates at below 1 and above 10.

In [28]:
if PLOT: array_chisq_plot()
In [29]:
def array_class_after_redcal_plot():
    fig, axes = plt.subplots(1, 2, figsize=(14, 6), dpi=100, gridspec_kw={'width_ratios': [2, 1]})
    plot_antclass(hd.antpos, final_class, ax=axes[0], ants=[ant for ant in hd.data_ants if ant < 320], legend=False, title='HERA Core, Post-Redcal')
    plot_antclass(hd.antpos, final_class, ax=axes[1], ants=[ant for ant in hd.data_ants if ant >= 320], radius=50, title='Outriggers')

Figure 5: Summary of antenna classifications after redundant calibration¶

This figure is the same as Figure 2, except that it now includes additional suspect or bad antennas based on redundant calibration. This can include antennas with high chi^2, but it can also include antennas classified as "bad" because they would add extra degeneracies to calibration.

In [30]:
if PLOT: array_class_after_redcal_plot()
In [31]:
to_show = {'Antenna': [f'{ant[0]}{ant[1][-1]}' for ant in ants]}
classes = {'Antenna': [final_class[ant] if ant in final_class else '-' for ant in ants]}
to_show['Dead?'] = [{'good': 'No', 'bad': 'Yes'}[am_totally_dead[ant]] if (ant in am_totally_dead) else '' for ant in ants]
classes['Dead?'] = [am_totally_dead[ant] if (ant in am_totally_dead) else '' for ant in ants]
for title, ac in [('Low Correlation', am_corr),
                  ('Cross-Polarized', am_xpol),
                  ('Even/Odd Zeros', zeros_class),
                  ('Autocorr Power', auto_power_class),
                  ('Autocorr Slope', auto_slope_class),
                  ('RFI in Autos', auto_rfi_class)]:
    to_show[title] = [f'{ac._data[ant]:.2G}' if (ant in ac._data) else '' for ant in ants]
    classes[title] = [ac[ant] if ant in ac else '' for ant in ants]
    
to_show['Redcal chi^2'] = [f'{np.median(cal["chisq_per_ant"][ant]):.3G}' if (ant in cal['chisq_per_ant']) else '-' for ant in ants]
classes['Redcal chi^2'] = [redcal_class[ant] if ant in redcal_class else '' for ant in ants]

df = pd.DataFrame(to_show)
df2 = pd.DataFrame(classes)
colors = {'good': 'darkgreen', 'suspect': 'goldenrod', 'bad': 'maroon'}
df2 = df2.applymap(lambda x: f'background-color: {colors.get(x, None)}')

table = df.style.hide_index() \
                .apply(lambda x: pd.DataFrame(df2.values, columns=x.columns), axis=None) \
                .set_properties(subset=['Antenna'], **{'font-weight': 'bold', 'border-right': "3pt solid black"}) \
                .set_properties(subset=df.columns[1:], **{'border-left': "1pt solid black"}) \
                .set_properties(**{'text-align': 'center', 'color': 'white'}) \
                .set_sticky(axis=1)

Table 1: Complete summary of per-antenna classifications¶

This table summarizes the results of the various classifications schemes detailed above. As before, green is good, yellow is suspect, and red is bad. The color for each antenna (first column) is the final summary of all other classifications. Antennas missing from redcal $\chi^2$ were excluded redundant-baseline calibration, either because they were flagged by ant_metrics or the even/odd zeros check, or because they would add unwanted extra degeneracies.

In [32]:
HTML(table.render())
Out[32]:
Antenna Dead? Low Correlation Cross-Polarized Even/Odd Zeros Autocorr Power Autocorr Slope RFI in Autos Redcal chi^2
3e No 0.84 0.45 0 7 0.24 0.053 1.85
3n No 0.64 0.45 0 7 0.058 0.047 1.43
4e No 0.85 0.45 0 5.9 0.048 0.09 1.8
4n No 0.63 0.45 0 7.3 0.18 0.058 1.53
5e No 0.85 0.45 0 7.3 0.034 0.054 1.65
5n No 0.65 0.45 0 10 0.027 0.048 1.47
7e Yes 1.5E+03 0 NAN 0 -
7n Yes 1.5E+03 0 NAN 0 -
8e Yes 1.5E+03 0 NAN 0 -
8n Yes 1.5E+03 0 NAN 0 -
9e Yes 1.5E+03 0 NAN 0 -
9n Yes 1.5E+03 0 NAN 0 -
10e Yes 1.5E+03 0 NAN 0 -
10n Yes 1.5E+03 0 NAN 0 -
15e No 0.86 0.45 0 5.5 0.1 0.055 1.82
15n No 0.64 0.45 0 6.2 0.041 0.043 1.54
16e No 0.87 0.46 0 6.3 0.073 0.049 1.77
16n No 0.65 0.46 1 7.2 0.11 0.044 1.52
17e No 0.85 0.43 0 7 0.024 0.049 1.82
17n No 0.66 0.43 0 8.1 0.091 0.044 1.61
18e No 0.84 0.57 0 8 -0.038 0.37 2.38
18n No 0.41 0.57 0 8.6 0.11 0.37 1.61
19e Yes 1.5E+03 0 NAN 0 -
19n Yes 1.5E+03 0 NAN 0 -
20e Yes 1.5E+03 0 NAN 0 -
20n Yes 1.5E+03 0 NAN 0 -
21e Yes 1.5E+03 0 NAN 0 -
21n Yes 1.5E+03 0 NAN 0 -
22e No 0.63 0.28 0 11 0.93 0.054 2.86
22n No 0.6 0.28 0 24 0.44 0.046 2.65
27e No 0.033 0.0066 0 0.68 0.51 0.1 -
27n No 0.043 0.0066 1 0.65 0.55 0.066 -
28e No 0.44 0.27 0 8.9 0.64 0.041 5.32
28n No 0.18 0.27 0 10 0.74 0.39 -
29e No 0.86 0.43 0 7.6 0.018 0.051 1.65
29n No 0.66 0.43 0 8.4 0.068 0.045 1.56
30e No 0.85 0.44 0 6.6 0.089 0.053 1.64
30n No 0.66 0.44 0 7.2 0.036 0.041 1.52
31e Yes 1.5E+03 0 NAN 0 -
31n Yes 1.5E+03 0 NAN 0 -
32e Yes 1.5E+03 0 NAN 0 -
32n Yes 1.5E+03 0 NAN 0 -
33e Yes 1.5E+03 0 NAN 0 -
33n Yes 1.5E+03 0 NAN 0 -
34e No 0.044 0.49 0 2.9 0.57 0.068 -
34n No 0.62 0.49 0 20 0.095 0.041 2.08
35e No 0.81 0.48 1 8.2 0.18 0.065 1.86
35n No 0.61 0.48 0 16 0.11 0.043 1.95
36e No 0.86 0.47 0 6.9 -0.3 0.05 1.81
36n No 0.65 0.47 0 8 -0.22 0.044 1.79
37e No 0.85 0.44 0 8.5 0.012 0.049 1.71
37n No 0.65 0.44 0 8.5 0.075 0.048 1.7
38e No 0.86 0.44 0 7.2 0.026 0.047 1.82
38n No 0.66 0.44 0 6.9 0.0034 0.043 1.61
40e No 0.85 0.44 0 7.2 0.032 0.049 2
40n No 0.66 0.44 0 7.2 0.052 0.044 1.7
41e No 0.86 0.45 0 10 -0.035 0.051 2.31
41n No 0.66 0.45 0 8.1 0.072 0.042 1.89
42e No 0.86 0.45 0 8.5 0.02 0.047 1.71
42n No 0.66 0.45 0 7.9 0.12 0.042 1.75
43e No 0.041 0.46 1 0.7 0.48 0.083 -
43n No 0.66 0.46 0 9 0.17 0.042 1.74
44e No 0.84 0.43 0 6.8 0.13 0.049 1.97
44n No 0.68 0.43 0 7.7 0.099 0.045 1.82
45e No 0.85 0.45 0 7.1 -0.014 0.052 1.55
45n No 0.66 0.45 0 7.1 0.053 0.044 1.5
46e No 0.85 0.67 0 8.7 0.059 0.049 1.61
46n No 0.038 0.67 1 0.64 0.57 0.098 -
47e No 0.036 0.47 0 3 0.56 0.048 -
47n No 0.63 0.47 0 19 0.12 0.041 1.97
48e No 0.84 0.47 0 32 0.11 0.043 1.97
48n No 0.63 0.47 0 39 0.051 0.039 2.07
49e No 0.83 0.46 0 16 0.085 0.05 1.72
49n No 0.62 0.46 0 33 0.057 0.041 1.9
50e No 0.85 0.45 0 6.9 0.075 0.049 1.99
50n No 0.55 0.45 0 8.6 0.73 0.043 2.96
51e No 0.039 0.4 1 0.34 1 0.21 -
51n No 0.66 0.4 0 6.4 0.028 0.12 1.61
52e No 0.86 0.44 0 5.7 -0.27 0.05 1.71
52n No 0.66 0.44 0 5.9 -0.22 0.043 1.58
53e No 0.86 0.44 0 6.1 0.0076 0.053 2.03
53n No 0.68 0.44 0 6.5 -0.076 0.042 1.61
54e No 0.053 0.54 0 0.68 0.51 0.073 -
54n No 0.65 0.54 0 7.9 0.24 0.041 1.68
55e No 0.85 0.64 0 7.5 0.12 0.049 1.95
55n No 0.032 0.64 0 0.62 0.59 0.049 -
56e No 0.85 0.42 0 8.4 0.067 0.048 2.51
56n No 0.67 0.42 0 10 0.11 0.042 1.77
57e No 0.75 0.4 0 3.3 0.95 0.062 3.42
57n No 0.66 0.4 0 8.8 0.092 0.049 1.66
58e No 0.037 0.001 0 0.69 0.5 0.12 -
58n No 0.034 0.001 0 0.62 0.57 0.08 -
59e No 0.79 0.41 0 9.5 0.74 0.046 2.49
59n No 0.66 0.41 0 7.2 0.18 0.042 1.6
60e No 0.029 0.0019 0 0.68 0.53 0.066 -
60n No 0.028 0.0019 0 0.62 0.56 0.095 -
61e No 0.82 0.46 0 11 0.23 0.048 1.72
61n No 0.61 0.46 0 11 0.24 0.041 1.66
62e No 0.84 0.47 0 27 0.071 0.049 1.7
62n No 0.63 0.47 0 36 0.015 0.039 1.66
63e No 0.82 0.73 0 26 0.15 0.049 1.64
63n No 0.046 0.73 0 2.8 0.57 0.12 -
64e No 0.82 0.47 0 18 0.12 0.05 1.73
64n No 0.6 0.47 0 30 0.054 0.041 1.54
65e No 0.85 0.45 0 6.6 0.061 0.053 1.67
65n No 0.64 0.45 0 7.7 0.036 0.045 1.53
66e No 0.86 0.45 0 6.3 0.0026 0.047 1.71
66n No 0.66 0.45 0 7.5 -0.033 0.044 1.53
67e No 0.86 0.44 0 7.7 0.039 0.05 2.09
67n No 0.68 0.44 0 9 0.049 0.045 1.58
68e No 0.86 0.55 0 6.4 0.15 0.05 1.91
68n No 0.032 0.55 0 0.26 1.1 0.22 -
69e No 0.85 0.43 0 8.5 0.082 0.051 2.47
69n No 0.67 0.43 0 6.8 0.096 0.042 1.65
70e No 0.86 0.45 0 7.7 -0.27 0.051 24.9
70n No 0.67 0.45 0 7.9 0.042 0.042 16.6
71e No 0.85 0.43 0 6.7 0.04 0.049 22.6
71n No 0.67 0.43 0 8.2 0.092 0.042 16.4
72e No 0.85 0.44 0 7.6 0.19 0.046 1.95
72n No 0.67 0.44 0 9.6 0.024 0.043 1.66
73e No 0.044 0.47 0 0.7 0.48 0.1 -
73n No 0.66 0.47 0 7.1 0.1 0.042 1.53
74e No 0.031 0.17 0 0.65 0.54 0.084 -
74n No 0.28 0.17 0 0.69 0.49 0.12 1.36
75e No 0.83 0.66 0 4 0.25 0.062 1.95
75n No 0.048 0.66 0 0.61 0.58 0.096 -
77e No 0.75 0.36 0 29 0.67 0.071 3.73
77n No 0.53 0.36 0 24 0.65 0.067 3.01
78e No 0.66 0.28 0 24 0.94 0.046 4.58
78n No 0.62 0.28 0 27 0.041 0.038 1.47
84e No 0.87 0.74 0 7.4 -0.29 0.055 1.96
84n No 0.044 0.74 0 0.27 0.96 0.15 -
85e No 0.85 0.43 0 8.8 0.022 0.049 1.78
85n No 0.65 0.43 0 8.9 -0.0052 0.044 1.44
86e No 0.85 0.45 0 8.5 -0.019 0.051 2.55
86n No 0.62 0.45 0 6.8 0.22 0.042 1.63
87e No 0.86 0.42 0 16 -0.24 0.051 1.84
87n No 0.66 0.42 0 7.3 -0.28 0.046 1.58
92e No 0.39 0.14 0 12 1.4 0.041 3.26
92n No 0.31 0.14 0 12 1.7 0.036 4.33
93e No 0.85 0.44 0 6.6 0.13 0.055 1.75
93n No 0.66 0.44 0 7.7 0.1 0.041 1.5
94e No 0.86 0.45 0 8.1 0.019 0.053 1.63
94n No 0.64 0.45 0 7 0.042 0.041 1.47
101e No 0.85 0.44 0 13 -0.3 0.051 1.7
101n No 0.65 0.44 0 9.8 -0.3 0.044 1.41
102e No 0.67 0.58 0 1 0.39 0.064 1.52
102n No 0.042 0.58 1 0.72 0.57 0.16 -
103e No 0.028 0.0016 0 0.48 0.96 0.23 -
103n No 0.03 0.0016 0 0.41 0.98 0.24 -
104e No 0.86 0.47 0 13 -0.29 0.049 1.94
104n No 0.62 0.47 1 1.2 1.8 0.047 1.88
109e No 0.86 0.61 0 7.9 0.052 0.047 1.88
109n No 0.04 0.61 0 0.67 0.56 0.068 -
110e No 0.74 0.3 0 8.3 1 0.046 4.3
110n No 0.66 0.3 0 7.6 0.02 0.042 1.6
111e No 0.85 0.61 0 6.6 0.037 0.049 1.85
111n No 0.2 0.61 1 0.7 0.5 0.08 -
112e No 0.86 0.46 0 7.1 0.056 0.048 1.68
112n No 0.64 0.46 0 8.1 0.067 0.042 1.44
120e No 0.84 0.72 0 2.5 0.074 0.049 1.68
120n No 0.036 0.72 1 0.3 0.94 0.22 -
121e No 0.86 0.45 0 6.3 0.096 0.061 1.9
121n No 0.66 0.45 0 6.6 -0.18 0.045 1.5
122e No 0.86 0.43 0 6.8 -0.32 0.05 2.05
122n No 0.67 0.43 0 6.6 -0.27 0.043 1.5
123e No 0.86 0.44 0 10 -0.29 0.05 1.89
123n No 0.67 0.44 0 7.9 -0.32 0.044 1.52
127e No 0.85 0.44 0 5.9 0.014 0.052 1.77
127n No 0.65 0.44 0 7.7 0.06 0.042 1.5
128e No 0.85 0.46 0 6.4 0.052 0.047 1.91
128n No 0.64 0.46 0 9.4 0.2 0.043 1.54
129e No 0.86 0.46 0 7.2 0.073 0.049 2.03
129n No 0.64 0.46 0 8.1 0.053 0.042 1.63
130e No 0.85 0.46 0 7.5 0.13 0.047 1.98
130n No 0.63 0.46 0 7.6 0.12 0.042 1.46
135e No 0.84 0.61 0 3.7 0.069 0.048 2.16
135n No 0.037 0.61 0 0.61 0.57 0.03 -
136e No 0.83 0.48 0 5.7 0.13 0.05 1.79
136n No 0.62 0.48 0 6.8 0.057 0.045 1.59
140e No 0.041 0.0067 0 0.71 0.51 0.074 -
140n No 0.037 0.0067 0 0.63 0.58 0.1 -
141e No 0.85 0.44 0 6.8 0.067 0.047 3.03
141n No 0.61 0.44 0 3.3 0.21 0.48 2.85
142e No 0.42 0.25 0 8.4 1 0.038 9.41
142n No 0.037 0.25 0 0.63 0.56 0.056 -
143e No 0.85 0.43 0 6.7 0.072 0.049 2.07
143n No 0.67 0.43 0 8 0.058 0.043 1.6
144e No 0.85 0.44 0 7.5 0.067 0.048 1.99
144n No 0.64 0.44 0 5.6 -0.011 0.042 1.56
145e No 0.033 0.006 0 0.67 0.53 0.065 -
145n No 0.027 0.006 0 0.62 0.58 0.13 -
147e Yes 1.5E+03 0 NAN 0 -
147n Yes 1.5E+03 0 NAN 0 -
148e Yes 1.5E+03 0 NAN 0 -
148n Yes 1.5E+03 0 NAN 0 -
149e Yes 1.5E+03 0 NAN 0 -
149n Yes 1.5E+03 0 NAN 0 -
150e Yes 1.5E+03 0 NAN 0 -
150n Yes 1.5E+03 0 NAN 0 -
151e Yes 1.5E+03 0 NAN 0 -
151n Yes 1.5E+03 0 NAN 0 -
152e Yes 1.5E+03 0 NAN 0 -
152n Yes 1.5E+03 0 NAN 0 -
153e Yes 1.5E+03 0 NAN 0 -
153n Yes 1.5E+03 0 NAN 0 -
154e Yes 1.5E+03 0 NAN 0 -
154n Yes 1.5E+03 0 NAN 0 -
155e No 0.061 0.44 0 0.73 0.5 0.061 -
155n No 0.63 0.44 0 9.4 0.023 0.057 1.76
156e No 0.13 0.43 0 0.69 0.47 0.043 -
156n No 0.64 0.43 0 10 0.0015 0.045 1.75
157e No 0.85 0.46 0 8.4 0.002 0.049 1.87
157n No 0.63 0.46 0 5.7 0.073 0.044 1.6
158e No 0.85 0.45 0 49 0.019 0.047 1.72
158n No 0.64 0.45 0 5.7 0.086 0.055 1.55
160e No 0.04 0.005 0 0.69 0.55 0.092 -
160n No 0.041 0.005 0 0.64 0.6 0.11 -
161e No 0.86 0.44 0 7.2 0.094 0.049 1.88
161n No 0.53 0.44 0 10 1 0.039 4.15
162e No 0.85 0.44 0 7.2 0.086 0.048 2.02
162n No 0.65 0.44 0 8.6 0.08 0.043 1.81
163e No 0.86 0.43 0 7.4 -0.026 0.048 1.78
163n No 0.66 0.43 0 7.3 -0.0067 0.043 1.71
164e No 0.85 0.44 0 7.2 0.083 0.048 1.76
164n No 0.65 0.44 0 6.5 0.054 0.043 1.59
165e No 0.86 0.44 0 13 -0.015 0.046 1.65
165n No 0.64 0.44 0 8.1 -0.03 0.044 1.6
166e No 0.82 0.45 0 8.6 0.33 0.046 2.9
166n No 0.58 0.45 0 8.9 0.62 0.041 3.9
167e Yes 1.5E+03 0 NAN 0 -
167n Yes 1.5E+03 0 NAN 0 -
168e Yes 1.5E+03 0 NAN 0 -
168n Yes 1.5E+03 0 NAN 0 -
169e Yes 1.5E+03 0 NAN 0 -
169n Yes 1.5E+03 0 NAN 0 -
170e Yes 1.5E+03 0 NAN 0 -
170n Yes 1.5E+03 0 NAN 0 -
171e Yes 1.5E+03 0 NAN 0 -
171n Yes 1.5E+03 0 NAN 0 -
173e Yes 1.5E+03 0 NAN 0 -
173n Yes 1.5E+03 0 NAN 0 -
176e No 0.84 0.47 0 5.9 -0.0016 0.058 2.63
176n No 0.63 0.47 0 6.1 0.029 0.054 1.71
177e No 0.86 0.47 0 6.7 0.055 0.055 1.91
177n No 0.64 0.47 0 10 0.098 0.044 1.48
178e No 0.79 0.46 0 1.6 0.26 0.046 1.68
178n No 0.63 0.46 0 4.3 0.047 0.044 1.5
179e No 0.032 0.018 0 0.66 0.55 0.038 -
179n No 0.062 0.018 0 0.56 0.61 0.044 -
180e No 0.86 0.63 0 8 0.063 0.047 18.9
180n No 0.26 0.63 0 0.7 0.5 0.089 2.41
181e No 0.049 0.13 0 0.65 0.54 0.066 -
181n No 0.24 0.13 0 16 1.6 0.026 2.53
182e No 0.85 0.68 0 45 0.0017 0.039 1.77
182n No 0.053 0.68 0 0.67 0.55 0.055 -
183e No 0.85 0.45 0 6.3 0.044 0.049 1.71
183n No 0.65 0.45 0 8.3 0.064 0.042 1.47
184e No 0.86 0.46 0 7.4 0.0047 0.051 2.07
184n No 0.65 0.46 0 7.1 0.042 0.043 1.62
185e No 0.86 0.44 0 8.1 -0.044 0.051 1.69
185n No 0.64 0.44 0 7.1 0.031 0.043 1.46
186e No 0.85 0.45 0 6.6 -0.026 0.055 1.67
186n No 0.63 0.45 0 7.9 -0.011 0.043 1.49
187e No 0.85 0.46 0 6.2 0.049 0.049 2.28
187n No 0.63 0.46 0 7.6 0.017 0.042 1.68
189e Yes 1.5E+03 0 NAN 0 -
189n Yes 1.5E+03 0 NAN 0 -
190e Yes 1.5E+03 0 NAN 0 -
190n Yes 1.5E+03 0 NAN 0 -
191e Yes 1.5E+03 0 NAN 0 -
191n Yes 1.5E+03 0 NAN 0 -
192e Yes 1.5E+03 0 NAN 0 -
192n Yes 1.5E+03 0 NAN 0 -
193e Yes 1.5E+03 0 NAN 0 -
193n Yes 1.5E+03 0 NAN 0 -
200e Yes 1.5E+03 0 NAN 0 -
200n Yes 1.5E+03 0 NAN 0 -
201e Yes 1.5E+03 0 NAN 0 -
201n Yes 1.5E+03 0 NAN 0 -
202e Yes 1.5E+03 0 NAN 0 -
202n Yes 1.5E+03 0 NAN 0 -
203e Yes 1.5E+03 0 NAN 0 -
203n Yes 1.5E+03 0 NAN 0 -
219e Yes 1.5E+03 0 NAN 0 -
219n Yes 1.5E+03 0 NAN 0 -
220e Yes 1.5E+03 0 NAN 0 -
220n Yes 1.5E+03 0 NAN 0 -
221e Yes 1.5E+03 0 NAN 0 -
221n Yes 1.5E+03 0 NAN 0 -
222e Yes 1.5E+03 0 NAN 0 -
222n Yes 1.5E+03 0 NAN 0 -
237e Yes 1.5E+03 0 NAN 0 -
237n Yes 1.5E+03 0 NAN 0 -
238e Yes 1.5E+03 0 NAN 0 -
238n Yes 1.5E+03 0 NAN 0 -
239e Yes 1.5E+03 0 NAN 0 -
239n Yes 1.5E+03 0 NAN 0 -
320e No 0.85 0.61 0 11 0.099 0.054 -
320n No 0.052 0.61 0 1.6 0.59 0.15 -
321e Yes 1.5E+03 0 NAN 0 -
321n Yes 1.5E+03 0 NAN 0 -
322e No 0.8 0.47 0 26 0.11 0.051 -
322n No 0.55 0.47 0 45 0.06 0.038 -
323e Yes 1.5E+03 0 NAN 0 -
323n Yes 1.5E+03 0 NAN 0 -
324e No 0.81 0.46 0 33 0.065 0.048 -
324n No 0.56 0.46 0 40 0.038 0.041 -
329e No 0.77 0.47 0 7.6 0.3 0.11 -
329n No 0.55 0.47 0 22 0.094 0.059 -
333e No 0.75 0.45 0 7.7 0.29 0.072 -
333n No 0.56 0.45 0 19 0.15 0.049 -
In [33]:
print('Final Ant-Pol Classification:\n\n', final_class)
Final Ant-Pol Classification:

 Jee:
----------
good (57 antpols):
5, 15, 16, 17, 29, 30, 35, 37, 38, 40, 41, 42, 44, 45, 46, 49, 50, 53, 55, 56, 62, 63, 64, 65, 66, 67, 68, 69, 72, 85, 86, 93, 94, 109, 111, 112, 121, 127, 128, 129, 130, 136, 143, 144, 157, 161, 162, 163, 164, 165, 176, 177, 183, 184, 185, 186, 187

suspect (21 antpols):
3, 4, 36, 48, 52, 61, 75, 84, 87, 101, 102, 104, 120, 122, 123, 135, 141, 158, 166, 178, 182

bad (78 antpols):
7, 8, 9, 10, 18, 19, 20, 21, 22, 27, 28, 31, 32, 33, 34, 43, 47, 51, 54, 57, 58, 59, 60, 70, 71, 73, 74, 77, 78, 92, 103, 110, 140, 142, 145, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 160, 167, 168, 169, 170, 171, 173, 179, 180, 181, 189, 190, 191, 192, 193, 200, 201, 202, 203, 219, 220, 221, 222, 237, 238, 239, 320, 321, 322, 323, 324, 329, 333


Jnn:
----------
good (58 antpols):
3, 4, 5, 15, 16, 17, 29, 30, 34, 35, 37, 38, 40, 41, 42, 43, 44, 45, 47, 53, 56, 57, 59, 64, 65, 66, 67, 69, 72, 73, 78, 85, 93, 94, 110, 112, 121, 127, 129, 130, 136, 143, 144, 155, 156, 157, 158, 162, 163, 164, 165, 176, 177, 183, 184, 185, 186, 187

suspect (15 antpols):
36, 48, 49, 51, 52, 54, 61, 62, 86, 87, 101, 122, 123, 128, 178

bad (83 antpols):
7, 8, 9, 10, 18, 19, 20, 21, 22, 27, 28, 31, 32, 33, 46, 50, 55, 58, 60, 63, 68, 70, 71, 74, 75, 77, 84, 92, 102, 103, 104, 109, 111, 120, 135, 140, 141, 142, 145, 147, 148, 149, 150, 151, 152, 153, 154, 160, 161, 166, 167, 168, 169, 170, 171, 173, 179, 180, 181, 182, 189, 190, 191, 192, 193, 200, 201, 202, 203, 219, 220, 221, 222, 237, 238, 239, 320, 321, 322, 323, 324, 329, 333

TODO: Find and flag RFI¶

TODO: Perfrom nucal¶

Metadata¶

In [34]:
from hera_cal import __version__
print('hera_cal:', __version__)
from hera_qm import __version__
print('hera_qm:', __version__)
hera_cal: 3.1.5.dev83+g5d33d87
hera_qm: 2.0.4.dev9+gdffdef6
In [35]:
print(f'Finished execution in {(time.time() - tstart) / 60:.2f} minutes.')
Finished execution in 3.12 minutes.