コード例 #1
0
def generate_residual_IDR2_2(uvh5_file,
                             omni_vis,
                             omni_calfits,
                             abs_calfits,
                             outfile,
                             clobber=False):
    # reading uvh5 data file
    hd = HERAData(uvh5_file)
    data, flags, nsamples = hd.read(polarizations=['ee', 'nn'])

    # reading omnical model visibilities
    hd_oc = HERAData(omni_vis)
    omnivis, omnivis_flags, _ = hd_oc.read()

    uvo = pyuvdata.UVData()
    uvo.read_uvh5(omni_vis)

    # reading calfits file
    hc = HERACal(omni_calfits)
    oc_gains, oc_flags, oc_quals, oc_total_quals = hc.read()

    hc = HERACal(abs_calfits)
    ac_gains, ac_flags, ac_quals, ac_total_quals = hc.read()

    # calibrating the data
    abscal_data, abscal_flags = copy.deepcopy(data), copy.deepcopy(flags)
    calibrate_in_place(abscal_data,
                       ac_gains,
                       data_flags=abscal_flags,
                       cal_flags=ac_flags)

    res_data, res_flags = copy.deepcopy(hd.data_array), copy.deepcopy(
        hd.flag_array)
    resdata, resflags = copy.deepcopy(abscal_data), copy.deepcopy(abscal_flags)
    for i, p in enumerate(['ee', 'nn']):
        # reading omnical model visibilities
        hd_oc = HERAData(omni_vis)
        omnivis, omnivis_flags, _ = hd_oc.read(polarizations=[p])
        mod_bls = list(omnivis.keys())
        red_bls = get_reds(hd.antpos, pols=p)
        red = gr.RBL(red_bls)
        for mbl in mod_bls:
            bl_grp = red[tuple(mbl[0:2]) + ('J{}'.format(p), )]
            for blp in bl_grp:
                bl = (blp[0], blp[1], p)
                inds = hd.antpair2ind(bl)
                omnivis_scaled = omnivis[mbl] * oc_gains[(blp[0], 'J{}'.format(
                    p))] * np.conj(oc_gains[(blp[1], 'J{}'.format(p))])
                omnivis_scaled /= (
                    ac_gains[(blp[0], 'J{}'.format(p))] *
                    np.conj(ac_gains[(blp[1], 'J{}'.format(p))]))
                resdata[bl] = abscal_data[bl] - omnivis_scaled
                resflags[bl] = abscal_flags[bl]
                res_data[inds, 0, :, i] = resdata[bl]
                res_flags[inds, 0, :, i] = resflags[bl]

    # writing to file
    hd.data_array = res_data
    hd.flag_array = res_flags
    hd.write_uvh5(outfile, clobber=clobber)
コード例 #2
0
ファイル: test_uvflag.py プロジェクト: ianmalcolm/hera_qm
def test_init_HERAData():
    uv = UVData()
    uv.read_miriad(test_d_file)
    uvf1 = UVFlag(uv)
    hd = HERAData(test_d_file, filetype='miriad')
    hd.read()
    uvf2 = UVFlag(hd)
    nt.assert_equal(uvf1, uvf2)
コード例 #3
0
ファイル: ant_metrics.py プロジェクト: eretana/hera_qm
def reds_from_file(filename, vis_format='miriad'):
    """Get the redundant baseline pairs from a file.

    This is a wrapper around hera_cal.redcal.get_pos_reds that doesn't read
    the data file if it's possible to only read metadata.

    Parameters
    ----------
    filename : str
        The file to get reds from.
    vis_format : {'miriad', 'uvh5', 'uvfits', 'fhd', 'ms'}, optional
        Format of the data file. Default is 'miriad'.

    Returns
    -------
    reds : list of lists of tuples
        Each tuple represents antenna pairs. These are compiled in a list within
        a redundant group, and the outer list is all the redundant groups.
        See hera_cal.redcal.get_pos_reds.

    """
    from hera_cal.io import HERAData
    from hera_cal.redcal import get_pos_reds

    hd = HERAData(filename, filetype=vis_format)
    if hd.antpos is None:
        reds = get_pos_reds(hd.read()[0].antpos)
    else:
        reds = get_pos_reds(hd.antpos)
    del hd
    return reds
コード例 #4
0
def test_reds_from_file_read_file():
    from hera_cal.io import HERAData
    from hera_cal.redcal import get_pos_reds

    # Miriad file will need to be read in
    testfile = os.path.join(DATA_PATH, 'zen.2457698.40355.xx.HH.uvcAA')
    reds = ant_metrics.reds_from_file(testfile, vis_format='miriad')
    assert len(reds) > 1
    hd = HERAData(testfile, filetype='miriad')
    reds_check = get_pos_reds(hd.read()[0].antpos)
    assert reds == reds_check
コード例 #5
0
ファイル: ant_metrics.py プロジェクト: eretana/hera_qm
class AntennaMetrics():
    """Container for holding data and meta-data for ant metrics calculations.

    This class creates an object for holding relevant visibility data and metadata,
    and provides interfaces to four antenna metrics: two identify dead antennas,
    and two identify cross-polarized antennas. These metrics can be used iteratively
    to identify bad antennas. The object handles all stroage of metrics, and supports
    writing metrics to an HDF5 filetype. The analysis functions are designed to work
    on raw data from a single observation with all four polarizations.

    """

    def __init__(self, dataFileList, reds, fileformat='miriad'):
        """Initilize an AntennaMetrics object.

        Parameters
        ----------
        dataFileList : list of str
            List of data filenames of the four different visibility polarizations
            for the same observation.
        reds : list of tuples of ints
            List of lists of tuples of antenna numbers that make up redundant baseline groups.
        format : str, optional
            File type of data. Must be one of: 'miriad', 'uvh5', 'uvfits', 'fhd',
            'ms' (see pyuvdata docs). Default is 'miriad'.

        Attributes
        ----------
        hd : HERAData
            HERAData object generated from dataFileList.
        data : array
            Data contained in HERAData object.
        flags : array
            Flags contained in HERAData object.
        nsamples : array
            Nsamples contained in HERAData object.
        ants : list of ints
            List of antennas in HERAData object.
        pols : list of str
            List of polarizations in HERAData object.
        bls : list of ints
            List of baselines in HERAData object.
        dataFileList : list of str
            List of data filenames of the four different visibility polarizations
            for the same observation.
        reds : list of tuples of ints
            List of lists of tuples of antenna numbers that make up redundant baseline groups.
        version_str : str
            The version of the hera_qm module used to generate these metrics.
        history : str
            History to append to the metrics files when writing out files.

        """
        from hera_cal.io import HERAData

        self.hd = HERAData(dataFileList, filetype=fileformat)

        self.data, self.flags, self.nsamples = self.hd.read()
        self.ants = self.hd.get_ants()
        self.pols = [pol.lower() for pol in self.hd.get_pols()]
        self.antpols = [antpol.lower() for antpol in self.hd.get_feedpols()]
        self.bls = self.hd.get_antpairs()
        self.dataFileList = dataFileList
        self.reds = reds
        self.version_str = hera_qm_version_str
        self.history = ''

        if len(self.antpols) != 2 or len(self.pols) != 4:
            raise ValueError('Missing polarization information. pols ='
                             + str(self.pols) + ' and antpols = '
                             + str(self.antpols))

    def mean_Vij_metrics(self, pols=None, xants=[], rawMetric=False):
        """Calculate how an antennas's average |Vij| deviates from others.

        Local wrapper for mean_Vij_metrics in hera_qm.ant_metrics module

        Parameters
        ----------
        pols : list of str, optional
            List of visibility polarizations (e.g. ['xx','xy','yx','yy']).
            Default is self.pols.
        xants : list of tuples, optional
            List of antenna-polarization tuples that should be ignored. The
            expected format is (ant, antpol). Default is empty list.
        rawMetric : bool, optional
            If True, return the raw mean Vij metric instead of the modified z-score.
            Default is False.

        Returns
        -------
        meanMetrics : dict
            Dictionary indexed by (ant, antpol) keys. Contains the modified z-score
            of the mean of the absolute value of all visibilities associated with
            an antenna. Very small or very large numbers are probably bad antennas.

        """
        if pols is None:
            pols = self.pols
        return mean_Vij_metrics(self.data, pols, self.antpols,
                                self.ants, self.bls, xants=xants,
                                rawMetric=rawMetric)

    def red_corr_metrics(self, pols=None, xants=[], rawMetric=False,
                         crossPol=False):
        """Calculate modified Z-Score over all redundant groups for each antenna.

        This method is a local wrapper for red_corr_metrics. It calculates the extent
        to which baselines involving an antenna do not correlate with others they are
        nominmally redundant with.

        Parameters
        ----------
        data : array or HERAData
            Data for all polarizations, stored in a format that supports indexing
            as data[i,j,pol].
        pols : list of str, optional
            List of visibility polarizations (e.g. ['xx','xy','yx','yy']).
            Default is self.pols.
        xants : list of tuples, optional
            List of antenna-polarization tuples that should be ignored. The
            expected format is (ant, antpol). Default is empty list.
        rawMetric : bool, optional
            If True, return the raw power correlations instead of the modified z-score.
            Default is False.
        crossPol : bool, optional
            If True, return results only when the two visibility polarizations differ
            by a single flip. Default is False.

        Returns
        -------
        powerRedMetric : dict
            Dictionary indexed by (ant,antpol) keys. Contains the modified z-scores
            of the mean power correlations inside redundant baseline groups associated
            with each antenna. Very small numbers are probably bad antennas.

        """
        if pols is None:
            pols = self.pols
        return red_corr_metrics(self.data, pols, self.antpols,
                                self.ants, self.reds, xants=xants,
                                rawMetric=rawMetric, crossPol=crossPol)

    def mean_Vij_cross_pol_metrics(self, xants=[], rawMetric=False):
        """Calculate the ratio of cross-pol visibilities to same-pol visibilities.

        This method is a local wrapper for mean_Vij_cross_pol_metrics. It finds
        which antennas are outliers based on the ratio of mean cross-pol visibilities
        to mean same-pol visibilities:
            (Vxy+Vyx)/(Vxx+Vyy).

        Parameters
        ----------
        xants : list of tuples, optional
            List of antenna-polarization tuples that should be ignored. The
            expected format is (ant, antpol). Default is empty list.
        rawMetric : bool, optional
            If True, return the raw power correlations instead of the modified z-score.
            Default is False.

        Returns
        -------
        mean_Vij_cross_pol_metrics : dict
            Dictionary indexed by (ant,antpol) keys. Contains the modified z-scores of the
            ratio of mean visibilities, (Vxy+Vyx)/(Vxx+Vyy). Results are duplicated in
            both antpols. Very large values are likely cross-polarized.

        """
        return mean_Vij_cross_pol_metrics(self.data, self.pols,
                                          self.antpols, self.ants,
                                          self.bls, xants=xants,
                                          rawMetric=rawMetric)

    def red_corr_cross_pol_metrics(self, xants=[], rawMetric=False):
        """Calculate modified Z-Score over redundant groups; assume cross-polarized.

        This method is a local wrapper for red_corr_cross_pol_metrics. It finds
        which antennas are part of visibilities that are significantly better
        correlated with polarization-flipped visibilities in a redundant group.
        It returns the modified z-score.

        Parameters
        ----------
        xants : list of tuples, optional
            List of antenna-polarization tuples that should be ignored. The
            expected format is (ant, antpol). Default is empty list.
        rawMetric : bool, optional
            If True, return the raw power correlations instead of the modified z-score.
            Default is False.

        Returns
        -------
        redCorrCrossPolMetrics : dict
            Dictionary indexed by (ant,antpol) keys. Contains the modified z-scores
            of the mean correlation ratio between redundant visibilities and singly-
            polarization flipped ones. Very large values are probably cross-polarized.

        """
        return red_corr_cross_pol_metrics(self.data, self.pols,
                                          self.antpols, self.ants,
                                          self.reds, xants=xants,
                                          rawMetric=rawMetric)

    def reset_summary_stats(self):
        """Reset all the internal summary statistics back to empty."""
        self.xants, self.crossedAntsRemoved, self.deadAntsRemoved = [], [], []
        self.iter = 0
        self.removalIter = {}
        self.allMetrics, self.allModzScores = OrderedDict(), OrderedDict()
        self.finalMetrics, self.finalModzScores = {}, {}

    def find_totally_dead_ants(self):
        """Flag antennas whose median autoPower is 0.0.

        These antennas are marked as dead. They do not appear in recorded antenna
        metrics or zscores. Their removal iteration is -1 (i.e. before iterative
        flagging).
        """
        autoPowers = compute_median_auto_power_dict(self.data,
                                                    self.pols,
                                                    self.reds)
        power_list_by_ant = {(ant, antpol): []
                             for ant in self.ants
                             for antpol in self.antpols
                             if (ant, antpol) not in self.xants}
        for ((ant0, ant1, pol), power) in autoPowers.items():
            if ((ant0, pol[0]) not in self.xants
                    and (ant1, pol[1]) not in self.xants):
                power_list_by_ant[(ant0, pol[0])].append(power)
                power_list_by_ant[(ant1, pol[1])].append(power)
        for (key, val) in power_list_by_ant.items():
            if np.median(val) == 0:
                self.xants.append(key)
                self.deadAntsRemoved.append(key)
                self.removalIter[key] = -1

    def _run_all_metrics(self, run_mean_vij=True, run_red_corr=True,
                         run_cross_pols=True, run_cross_pols_only=False):
        """Local call for all metrics as part of iterative flagging method.

        Parameters
        ----------
        run_mean_vij : bool, optional
            Define if mean_Vij_metrics or mean_Vij_cross_pol_metrics are executed.
            Default is True.
        run_red_corr : bool, optional
            Define if red_corr_metrics or red_corr_cross_pol_metrics are executed.
            Default is True.
        run_cross_pols : bool, optional
            Define if mean_Vij_cross_pol_metrics and red_corr_cross_pol_metrics
            are executed. Default is True. Individual rules are inherited from
            run_mean_vij and run_red_corr.
        run_cross_pols_only : bool, optional
            Define if cross pol metrics are the *only* metrics to be run.
            Default is False.

        """
        # Compute all raw metrics
        metNames = []
        metVals = []

        if run_mean_vij and not run_cross_pols_only:
            metNames.append('meanVij')
            meanVij = self.mean_Vij_metrics(pols=self.pols,
                                            xants=self.xants,
                                            rawMetric=True)
            metVals.append(meanVij)

        if run_red_corr and not run_cross_pols_only:
            metNames.append('redCorr')
            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)

        if run_cross_pols:
            if run_mean_vij:
                metNames.append('meanVijXPol')
                meanVijXPol = self.mean_Vij_cross_pol_metrics(xants=self.xants,
                                                              rawMetric=True)
                metVals.append(meanVijXPol)
            if run_red_corr:
                metNames.append('redCorrXPol')
                redCorrXPol = self.red_corr_cross_pol_metrics(xants=self.xants,
                                                              rawMetric=True)
                metVals.append(redCorrXPol)

        # Save all metrics and zscores
        metrics, modzScores = {}, {}
        for metric, metName in zip(metVals, metNames):
            metrics[metName] = metric
            modz = per_antenna_modified_z_scores(metric)
            modzScores[metName] = modz
            for key in metric:
                if metName in self.finalMetrics:
                    self.finalMetrics[metName][key] = metric[key]
                    self.finalModzScores[metName][key] = modz[key]
                else:
                    self.finalMetrics[metName] = {key: metric[key]}
                    self.finalModzScores[metName] = {key: modz[key]}
        self.allMetrics.update({self.iter: metrics})
        self.allModzScores.update({self.iter: modzScores})

    def iterative_antenna_metrics_and_flagging(self, crossCut=5, deadCut=5,
                                               alwaysDeadCut=10,
                                               verbose=False,
                                               run_mean_vij=True,
                                               run_red_corr=True,
                                               run_cross_pols=True,
                                               run_cross_pols_only=False):
        """Run all four antenna metrics and stores results in self.

        Runs all four metrics: two for dead antennas, two for cross-polarized antennas.
        Saves the results internally to this this antenna metrics object.

        Parameters
        ----------
        crossCut : float, optional
            Modified z-score cut for most cross-polarized antennas. Default is 5 "sigmas".
        deadCut : float, optional
            Modified z-score cut for most likely dead antennas. Default is 5 "sigmas".
        alwaysDeadCut : float, optional
            Modified z-score cut for definitely dead antennas. Default is 10 "sigmas".
            These are all thrown away at once without waiting to iteratively throw away
            only the worst offender.
        run_mean_vij : bool, optional
            Define if mean_Vij_metrics or mean_Vij_cross_pol_metrics are executed.
            Default is True.
        run_red_corr : bool, optional
            Define if red_corr_metrics or red_corr_cross_pol_metrics are executed.
            Default is True.
        run_cross_pols : bool, optional
            Define if mean_Vij_cross_pol_metrics and red_corr_cross_pol_metrics
            are executed. Default is True. Individual rules are inherited from
            run_mean_vij and run_red_corr.
        run_cross_pols_only : bool, optional
            Define if cross pol metrics are the *only* metrics to be run. Default
            is False.

        """
        self.reset_summary_stats()
        self.find_totally_dead_ants()
        self.crossCut, self.deadCut = crossCut, deadCut
        self.alwaysDeadCut = alwaysDeadCut

        # Loop over
        for iter in range(len(self.antpols) * len(self.ants)):
            self.iter = iter
            self._run_all_metrics(run_mean_vij=run_mean_vij,
                                  run_red_corr=run_red_corr,
                                  run_cross_pols=run_cross_pols,
                                  run_cross_pols_only=run_cross_pols_only)

            # Mostly likely dead antenna
            last_iter = list(self.allModzScores)[-1]
            worstDeadCutRatio = -1
            worstCrossCutRatio = -1

            if run_mean_vij and run_red_corr and not run_cross_pols_only:
                deadMetrics = average_abs_metrics(self.allModzScores[last_iter]['meanVij'],
                                                  self.allModzScores[last_iter]['redCorr'])
            else:
                if run_mean_vij and not run_cross_pols_only:
                    deadMetrics = self.allModzScores[last_iter]['meanVij'].copy()
                elif run_red_corr and not run_cross_pols_only:
                    deadMetrics = self.allModzScores[last_iter]['redCorr'].copy()
            try:
                worstDeadAnt = max(deadMetrics, key=deadMetrics.get)
                worstDeadCutRatio = np.abs(deadMetrics[worstDeadAnt]) / deadCut
            except NameError:
                # Dead metrics weren't run, but that's fine.
                pass

            if run_cross_pols:
                # Most likely cross-polarized antenna
                if run_mean_vij and run_red_corr:
                    crossMetrics = average_abs_metrics(self.allModzScores[last_iter]['meanVijXPol'],
                                                       self.allModzScores[last_iter]['redCorrXPol'])
                elif run_mean_vij:
                    crossMetrics = self.allModzScores[last_iter]['meanVijXPol'].copy()
                elif run_red_corr:
                    crossMetrics = self.allModzScores[last_iter]['redCorrXPol'].copy()
                worstCrossAnt = max(crossMetrics, key=crossMetrics.get)
                worstCrossCutRatio = (np.abs(crossMetrics[worstCrossAnt])
                                      / crossCut)

            # Find the single worst antenna, remove it, log it, and run again
            if (worstCrossCutRatio >= worstDeadCutRatio
                    and worstCrossCutRatio >= 1.0):
                for antpol in self.antpols:
                    self.xants.append((worstCrossAnt[0], antpol))
                    self.crossedAntsRemoved.append((worstCrossAnt[0], antpol))
                    self.removalIter[(worstCrossAnt[0], antpol)] = iter
                    if verbose:
                        print('On iteration', iter, 'we flag\t', end='')
                        print((worstCrossAnt[0], antpol))
            elif (worstDeadCutRatio > worstCrossCutRatio
                    and worstDeadCutRatio > 1.0):
                dead_ants = set([worstDeadAnt])
                for (ant, metric) in deadMetrics.items():
                    if metric > alwaysDeadCut:
                        dead_ants.add(ant)
                for dead_ant in dead_ants:
                    self.xants.append(dead_ant)
                    self.deadAntsRemoved.append(dead_ant)
                    self.removalIter[dead_ant] = iter
                    if verbose:
                        print('On iteration', iter, 'we flag', dead_ant)
            else:
                break

    def save_antenna_metrics(self, filename, overwrite=False):
        """Output all meta-metrics and cut decisions to HDF5 file.

        Saves all cut decisions and meta-metrics in an HDF5 that can be loaded
        back into a dictionary using hera_qm.ant_metrics.load_antenna_metrics()

        Parameters
        ----------
        filename : str
            The file into which metrics will be written.
        overwrite: bool, optional
            Whether to overwrite an existing file. Default is False.

        """
        if not hasattr(self, 'xants'):
            raise KeyError(('Must run AntennaMetrics.'
                            'iterative_antenna_metrics_and_flagging() first.'))

        out_dict = {'xants': self.xants}
        out_dict['crossed_ants'] = self.crossedAntsRemoved
        out_dict['dead_ants'] = self.deadAntsRemoved
        out_dict['final_metrics'] = self.finalMetrics
        out_dict['all_metrics'] = self.allMetrics
        out_dict['final_mod_z_scores'] = self.finalModzScores
        out_dict['all_mod_z_scores'] = self.allModzScores
        out_dict['removal_iteration'] = self.removalIter
        out_dict['cross_pol_z_cut'] = self.crossCut
        out_dict['dead_ant_z_cut'] = self.deadCut
        out_dict['always_dead_ant_z_cut'] = self.alwaysDeadCut
        out_dict['datafile_list'] = self.dataFileList
        out_dict['reds'] = self.reds

        metrics_io.write_metric_file(filename, out_dict, overwrite=overwrite)
コード例 #6
0
model_file = model_directory
flag_files = [f"/lustre/aoc/projects/hera/aewallwi/H1C_flags/{jd}.flags.h5" for jd in [2458098,2458099,2458101,2458102,2458103,2458104,2458105,2458106,
                                                                                                        2458107,2458108,2458109,2458110,2458111,2458112,2458113,2458114,
                                                                                                        2458115,2458116]]
bad_ants = [np.loadtxt(f"/users/kshahin/kshahin/HERA_Calibration/hera_pipelines/pipelines/h1c/idr2/v2/bad_ants/{ba}.txt") for ba in [2458098,2458099,2458101,2458102,2458103,2458104,2458105,2458106,2458107,2458108,
                                                                                                                          2458109,2458110,2458111,2458112,2458113,2458114,2458115,2458116]]
flag_file = flag_files[day]
bad_ant = bad_ants[day]
if not os.path.exists(f"/users/kshahin/kshahin/HERA_Calibration/DayfxP_{day}"):
    os.mkdir(f"/users/kshahin/kshahin/HERA_Calibration/DayfxP_{day}")
flags = UVFlag(flag_file)
flags.select(frequencies = flags.freq_array[(flags.freq_array>=115*1e+6) & (flags.freq_array<175*1e+6)])
flags.select(times=flags.time_array[2600:2660])
hd_data = HERAData(data_file)
freqs = hd_data.freqs[(hd_data.freqs>=115*1e+6) & (hd_data.freqs<175*1e+6)]
data, flag, nsample = hd_data.read(polarizations=["ee"], frequencies=freqs)
for bl in data:
    if (bl[0] == bad_ant).any() or (bl[1] == bad_ant).any():
                flag[bl] = np.ones_like(flag[bl])
    flag[bl] = flags.flag_array.squeeze()
hd_data.update(flags=flag)
hd_data.write_uvh5(f"/users/kshahin/kshahin/HERA_Calibration/DayfxP_{day}/data_{day}_{chunk}.uvh5", clobber=True)
del data, flag, nsample, hd_data
redcal.redcal_run(input_data=f"/users/kshahin/kshahin/HERA_Calibration/DayfxP_{day}/data_{day}_{chunk}.uvh5", clobber=True, solar_horizon=90, verbose=True)
abscal.post_redcal_abscal_run(data_file=f"/users/kshahin/kshahin/HERA_Calibration/DayfxP_{day}/data_{day}_{chunk}.uvh5", redcal_file=f"/users/kshahin/kshahin/HERA_Calibration/DayfxP_{day}/data_{day}_{chunk}.omni.calfits", model_files=[data_file], clobber=True, data_solar_horizon=90, model_solar_horizon=90)

cs=smooth_cal.CalibrationSmoother(calfits_list=sorted(glob.glob(f"/users/kshahin/kshahin/HERA_Calibration/DayfxP_{day}/data_{day}_*.abs.calfits")))
cs.time_freq_2D_filter(time_scale=21600)
cs.write_smoothed_cal(clobber=True, output_replace=(".abs.",".smooth_abs."))

コード例 #7
0
def ant_metrics_run(files, pols=['xx', 'yy', 'xy', 'xy'], crossCut=5.0,
                    deadCut=5.0, alwaysDeadCut=10.0, metrics_path='',
                    extension='.ant_metrics.hdf5', vis_format='miriad',
                    verbose=True, history='',
                    run_mean_vij=True, run_red_corr=True,
                    run_cross_pols=True):
    """
    Run a series of ant_metrics tests on a given set of input files.

    Args:
        files: List of files to run ant metrics on.
               Can be any of the 4 polarizations
        pols: List of polarizations to perform metrics over.
             Allowed polarizations: 'xx', 'yy', 'xy', 'yx'
             Default: ['xx', 'yy', 'xy', 'yx']
        crossCut: Modified Z-Score limit to cut cross-polarized antennas.
                  Default: 5.0
        deadCut: Modifized Z-Score limit to cut dead antennas.
                 Default: 5.0
        alwaysDeadCut: Modified Z-Score limit for antennas that are definitely dead.
                       Antennas with above this limit are thrown away before iterative flagging.
                       Default: 10.0
        metrics_path: String path to directory to story output metric.
                      Default: same directy as input data files.
        extension: File extension to add to output files.
                   Default: ant_metrics.hdf5
        vis_format: File format of input visibility data.
                    Supports: 'miriad','uvfits', 'fhd', 'ms' (see pyuvdata docs)
                    Default: 'miriad'
        verbose: If True print out statements during iterative flagging
        history: The history the add to metrics.
                 Default
        run_mean_vij: Boolean flag which determines if mean_Vij_metrics is executed.
                      Default is True
        run_red_corr: Boolean flag which determines if red_corr_metrics is executed.
                      Default is True
        run_cross_pols: Boolean flag which determines if mean_Vij_cross_pol_metrics and red_corr_cross_pol_metrics are executed.
                      Default is True
    Return:
       None

    The funciton will take in a list of files and options.
    It will run the series of ant metrics tests,
    and produce an HDF5 file containing the relevant information.
    The file list need only contain one polarization type for a given JD,
    the function will look for the other polarizations in the same folder.
    If not all four polarizations are found, a warning is
    generated, since the code assumes all four polarizations are present.
    """
    from hera_cal.omni import aa_to_info
    from hera_cal.utils import get_aa_from_uv
    from hera_cal.io import HERAData

    # check the user asked to run anything
    if not any([run_mean_vij, run_red_corr, run_cross_pols]):
        raise AssertionError(("No Ant Metrics have been selected to run."
                              "Please set the correct keywords to run "
                              "the desired metrics."))

    # check that we were given some files to process
    if len(files) == 0:
        raise AssertionError('Please provide a list of visibility files')

    # generate a list of all files to be read in
    fullpol_file_list = utils.generate_fullpol_file_list(files, pols)
    if len(fullpol_file_list) == 0:
        raise AssertionError('Could not find all 4 polarizations '
                             'for any files provided')

    # generate aa object from file
    # N.B.: assumes redunancy information is the same for all files passed in
    first_file = fullpol_file_list[0][0]
    hd = HERAData(first_file, filetype='miriad')
    data, flags, nsamples = hd.read()
    aa = get_aa_from_uv(hd)
    del hd

    info = aa_to_info(aa, pols=[pols[-1][0]])
    reds = info.get_reds()

    # do the work
    for jd_list in fullpol_file_list:
        am = AntennaMetrics(jd_list, reds, fileformat=vis_format)
        am.iterative_antenna_metrics_and_flagging(crossCut=crossCut,
                                                  deadCut=deadCut,
                                                  alwaysDeadCut=alwaysDeadCut,
                                                  verbose=verbose,
                                                  run_mean_vij=run_mean_vij,
                                                  run_red_corr=run_red_corr,
                                                  run_cross_pols=run_cross_pols)

        # add history
        am.history = am.history + history

        base_filename = jd_list[0]
        abspath = os.path.abspath(base_filename)
        dirname = os.path.dirname(abspath)
        basename = os.path.basename(base_filename)
        nopol_filename = re.sub('\.{}\.'.format(pols[0]), '.', basename)
        if metrics_path == '':
            # default path is same directory as file
            metrics_path = dirname
        else:
            metrics_path = metrics_path
        metrics_basename = nopol_filename + extension
        metrics_filename = os.path.join(metrics_path, metrics_basename)
        am.save_antenna_metrics(metrics_filename)

    return
コード例 #8
0
class AntennaMetrics():
    """Container for holding data and meta-data for ant metrics calculations.

    Object for holding relevant visibility data and metadata
    interfaces to four antenna metrics:
        Two each for identifying dead or cross-polarized antennas.
    Can iteratively identifying bad antennas
    Handles all metrics stroage, and supports writing metrics to HDF5.
    Works on raw data from a single observation with all four polarizations.
    """

    def __init__(self, dataFileList, reds, fileformat='miriad'):
        """Initilize an AntennaMetrics object.

        Arguments:
            dataFileList: List of data filenames of the four different visibility polarizations for the same observation
            reds: List of lists of tuples of antenna numbers that make up redundant baseline groups.
            format: File type of data
                    Supports: 'miriad','uvfits', 'fhd', 'ms ' (see pyuvdata docs)
                    Default: 'miriad'.
        """
        from hera_cal.io import HERAData

        if fileformat == 'miriad':
            self.hd = HERAData(dataFileList, filetype='miriad')
        elif fileformat == 'uvfits':
            self.hd = HERAData(dataFileList, filetype='uvfits')
        elif fileformat == 'fhd':
            raise NotImplemented(str(fileformat) + 'not supported')
        else:
            raise ValueError('Unrecognized file format ' + str(fileformat))

        self.data, self.flags, self.nsamples = self.hd.read()
        self.ants = self.hd.get_ants()
        self.pols = [pol.lower() for pol in self.hd.get_pols()]
        self.antpols = [antpol.lower() for antpol in self.hd.get_feedpols()]
        self.bls = self.hd.get_antpairs()
        self.dataFileList = dataFileList
        self.reds = reds
        self.version_str = hera_qm_version_str
        self.history = ''

        if len(self.antpols) is not 2 or len(self.pols) is not 4:
            raise ValueError('Missing polarization information. pols ='
                             + str(self.pols) + ' and antpols = '
                             + str(self.antpols))

    def mean_Vij_metrics(self, pols=None, xants=[], rawMetric=False):
        """Calculate how an antennas's average |Vij| deviates from others.

        Local wrapper for mean_Vij_metrics in hera_qm.ant_metrics module
        Arguments:

            pols : List of visibility polarizations (e.g. ['xx','xy','yx','yy'])
                   Default: self.pols
            xants: List of antennas ithat should be ignored.
                   format: (ant,antpol)
            rawMetric:return the raw mean Vij metric instead of the modified z-score

        Returns:
            meanMetrics: Dictionary indexed by (ant,antpol) of the modified z-score
                         of the mean of the absolute value of all visibilities associated with an antenna.
                         Very small or very large numbers are probably bad antennas.
        """
        if pols is None:
            pols = self.pols
        return mean_Vij_metrics(self.data, pols, self.antpols,
                                self.ants, self.bls, xants=xants,
                                rawMetric=rawMetric)

    def red_corr_metrics(self, pols=None, xants=[], rawMetric=False,
                         crossPol=False):
        """Calculate modified Z-Score over all redundant groups for each antenna.

        Local wrapper for red_corr_metrics in hera_qm.ant_metrics module.
        Calculates the extent to which baselines involving an antenna
        do not correlate with others they are nominmally redundant with.

        Arguments:
            data: data for all polarizations
                  format must support data[i,j,pol]
            pols: List of visibility polarizations (e.g. ['xx','xy','yx','yy']).
                  Default: self.pols
            xants: List of antennas that should be ignored.
                   format: (ant, antpol)
            rawMetric: return the raw power correlations instead of the modified z-score
            crossPol: return results only when the two visibility polarizations differ by a single flip

        Returns:
            powerRedMetric: Dictionary indexed by (ant,antpol)
                            of the modified z-scores of the mean power correlations
                            inside redundant baseline groups
                            associated with each antenna.
                            Very small numbers are probably bad antennas.
        """
        if pols is None:
            pols = self.pols
        return red_corr_metrics(self.data, pols, self.antpols,
                                self.ants, self.reds, xants=xants,
                                rawMetric=rawMetric, crossPol=crossPol)

    def mean_Vij_cross_pol_metrics(self, xants=[], rawMetric=False):
        """Calculate the ratio of cross-pol visibilities to same-pol visibilities.

        Local wrapper for mean_Vij_cross_pol_metrics.
        Find which antennas are outliers based on the
        ratio of mean cross-pol visibilities to mean same-pol visibilities:
        (Vxy+Vyx)/(Vxx+Vyy).

        Arguments:
            xants: List of antennas  that should be ignored.
                   format (ant,antpol) format
                   e.g.,  if (81,'y') is excluded, (81,'x') cannot be identified
                          as cross-polarized and will be excluded.
            rawMetric: return the raw power ratio instead of the modified z-score

        Returns:
            mean_Vij_cross_pol_metrics: Dictionary indexed by (ant,antpol)
                                        The modified z-scores of the
                                        ratio of mean visibilities,
                                        (Vxy+Vyx)/(Vxx+Vyy).
                                        Results duplicated in both antpols.
                                        Very large values are likely cross-polarized.
        """
        return mean_Vij_cross_pol_metrics(self.data, self.pols,
                                          self.antpols, self.ants,
                                          self.bls, xants=xants,
                                          rawMetric=rawMetric)

    def red_corr_cross_pol_metrics(self, xants=[], rawMetric=False):
        """Calculate modified Z-Score over redundant groups; assume cross-polarized.

        Local wrapper for red_corr_cross_pol_metrics.
        Find which antennas are part of visibilities that are significantly better
        correlated with polarization-flipped visibilities in a redundant groupself.
        Returns the modified z-score.

        Arguments:
            xants: List of antennas  that should be ignored.
                   format (ant,antpol) format
                   e.g.,  if (81,'y') is excluded, (81,'x') cannot be identified
                          as cross-polarized and will be excluded.
            rawMetric: return the raw power ratio instead of the modified z-score
                        type: Boolean
                        Default: False

        Returns:
            redCorrCrossPolMetrics: Dictionary indexed by (ant,antpol)
                                    The modified z-scores of the mean correlation
                                    ratio between redundant visibilities
                                    and singlely-polarization flipped ones.
                                    Very large values are probably cross-polarized.
        """
        return red_corr_cross_pol_metrics(self.data, self.pols,
                                          self.antpols, self.ants,
                                          self.reds, xants=xants,
                                          rawMetric=rawMetric)

    def reset_summary_stats(self):
        """Reset all the internal summary statistics back to empty."""
        self.xants, self.crossedAntsRemoved, self.deadAntsRemoved = [], [], []
        self.iter = 0
        self.removalIter = {}
        self.allMetrics, self.allModzScores = OrderedDict(), OrderedDict()
        self.finalMetrics, self.finalModzScores = {}, {}

    def find_totally_dead_ants(self):
        """Flag antennas whose median autoPower is 0.0.

        These antennas are marked as dead
        They do not appear in recorded antenna metrics or zscores.
        Their removal iteration is -1 (i.e. before iterative flagging).
        """
        autoPowers = compute_median_auto_power_dict(self.data,
                                                    self.pols,
                                                    self.reds)
        power_list_by_ant = {(ant, antpol): []
                             for ant in self.ants
                             for antpol in self.antpols
                             if (ant, antpol) not in self.xants}
        for ((ant0, ant1, pol), power) in autoPowers.items():
            if ((ant0, pol[0]) not in self.xants
                    and (ant1, pol[1]) not in self.xants):
                power_list_by_ant[(ant0, pol[0])].append(power)
                power_list_by_ant[(ant1, pol[1])].append(power)
        for (key, val) in power_list_by_ant.items():
            if np.median(val) == 0:
                self.xants.append(key)
                self.deadAntsRemoved.append(key)
                self.removalIter[key] = -1

    def _run_all_metrics(self, run_mean_vij=True, run_red_corr=True,
                         run_cross_pols=True):
        """Local call for all metrics as part of iterative flagging method.

        Arguments:
            run_mean_vij: Boolean flag which determines if mean_Vij_metrics is executed.
                          Default is True
            run_red_corr: Boolean flag which determines if red_corr_metrics is executed.
                          Default is True
            run_cross_pols: Boolean flag which determines if mean_Vij_cross_pol_metrics and red_corr_cross_pol_metrics are executed.
                          Default is True
        """
        # Compute all raw metrics
        metNames = []
        metVals = []

        if run_mean_vij:
            metNames.append('meanVij')
            meanVij = self.mean_Vij_metrics(pols=self.pols,
                                            xants=self.xants,
                                            rawMetric=True)
            metVals.append(meanVij)

        if run_red_corr:
            metNames.append('redCorr')

            redCorr = self.red_corr_metrics(pols=['xx', 'yy'],
                                            xants=self.xants,
                                            rawMetric=True)
            metVals.append(redCorr)

        if run_cross_pols:
            metNames.append('meanVijXPol')
            metNames.append('redCorrXPol')

            meanVijXPol = self.mean_Vij_cross_pol_metrics(xants=self.xants,
                                                          rawMetric=True)
            redCorrXPol = self.red_corr_cross_pol_metrics(xants=self.xants,
                                                          rawMetric=True)
            metVals.append(meanVijXPol)
            metVals.append(redCorrXPol)

        # Save all metrics and zscores
        metrics, modzScores = {}, {}
        for metric, metName in zip(metVals, metNames):
            metrics[metName] = metric
            modz = per_antenna_modified_z_scores(metric)
            modzScores[metName] = modz
            for key in metric:
                if metName in self.finalMetrics:
                    self.finalMetrics[metName][key] = metric[key]
                    self.finalModzScores[metName][key] = modz[key]
                else:
                    self.finalMetrics[metName] = {key: metric[key]}
                    self.finalModzScores[metName] = {key: modz[key]}
        self.allMetrics.update({self.iter: metrics})
        self.allModzScores.update({self.iter: modzScores})


    def iterative_antenna_metrics_and_flagging(self, crossCut=5, deadCut=5,
                                               alwaysDeadCut=10,
                                               verbose=False,
                                               run_mean_vij=True,
                                               run_red_corr=True,
                                               run_cross_pols=True):
        """Run all four antenna metrics and stores results in self.

        Runs all four metrics:
            Two for dead antennas
            Two for cross-polarized antennas
        Saves the results internally to this this antenna metrics object.

        Arguments:
            crossCut: Modified z-score cut for most cross-polarized antennas.
                      Default 5 "sigmas".
            deadCut: Modified z-score cut for most likely dead antennas.
                      Default 5 "sigmas".
            alwaysDeadCut: Modified z-score cut for definitely dead antennas.
                           Default 10 "sigmas".
                           These are all thrown away at once without waiting
                           to iteratively throw away only the worst offender.
            run_mean_vij: Boolean flag which determines if mean_Vij_metrics is executed.
                          Default is True
            run_red_corr: Boolean flag which determines if red_corr_metrics is executed.
                          Default is True
            run_cross_pols: Boolean flag which determines if mean_Vij_cross_pol_metrics and red_corr_cross_pol_metrics are executed.
                          Default is True
        """
        self.reset_summary_stats()
        self.find_totally_dead_ants()
        self.crossCut, self.deadCut = crossCut, deadCut
        self.alwaysDeadCut = alwaysDeadCut

        # Loop over
        for n in range(len(self.antpols) * len(self.ants)):
            self.iter = n
            self._run_all_metrics(run_mean_vij=run_mean_vij,
                                  run_red_corr=run_red_corr,
                                  run_cross_pols=run_cross_pols)

            # Mostly likely dead antenna
            last_iter = list(self.allModzScores)[-1]
            worstDeadCutRatio = None
            worstCrossCutRatio = None
            if run_mean_vij and run_red_corr:
                deadMetrics = average_abs_metrics(self.allModzScores[last_iter]['meanVij'],
                                                  self.allModzScores[last_iter]['redCorr'])
                worstDeadAnt = max(deadMetrics, key=deadMetrics.get)
                worstDeadCutRatio = np.abs(deadMetrics[worstDeadAnt]) / deadCut
            else:
                if run_mean_vij:
                    deadMetrics = self.allModzScores[last_iter]['meanVij'].copy()
                    worstDeadAnt = max(deadMetrics, key=deadMetrics.get)
                    worstDeadCutRatio = (np.abs(deadMetrics[worstDeadAnt])
                                         / deadCut)
                elif run_red_corr:
                    deadMetrics = self.allModzScores[last_iter]['redCorr'].copy()
                    worstDeadAnt = max(deadMetrics, key=deadMetrics.get)
                    worstDeadCutRatio = (np.abs(deadMetrics[worstDeadAnt])
                                         / deadCut)
            if run_cross_pols:
                # Most likely cross-polarized antenna
                crossMetrics = average_abs_metrics(self.allModzScores[last_iter]['meanVijXPol'],
                                                   self.allModzScores[last_iter]['redCorrXPol'])
                worstCrossAnt = max(crossMetrics, key=crossMetrics.get)
                worstCrossCutRatio = (np.abs(crossMetrics[worstCrossAnt])
                                      / crossCut)

            # Find the single worst antenna, remove it, log it, and run again
            if (worstCrossCutRatio >= worstDeadCutRatio
                    and worstCrossCutRatio >= 1.0):
                for antpol in self.antpols:
                    self.xants.append((worstCrossAnt[0], antpol))
                    self.crossedAntsRemoved.append((worstCrossAnt[0], antpol))
                    self.removalIter[(worstCrossAnt[0], antpol)] = n
                    if verbose:
                        print('On iteration', n, 'we flag\t', end='')
                        print((worstCrossAnt[0], antpol))
            elif (worstDeadCutRatio > worstCrossCutRatio
                    and worstDeadCutRatio > 1.0):
                dead_ants = set([worstDeadAnt])
                for (ant, metric) in deadMetrics.items():
                    if metric > alwaysDeadCut:
                        dead_ants.add(ant)
                for dead_ant in dead_ants:
                    self.xants.append(dead_ant)
                    self.deadAntsRemoved.append(dead_ant)
                    self.removalIter[dead_ant] = n
                    if verbose:
                        print('On iteration', n, 'we flag', dead_ant)
            else:
                break

    def save_antenna_metrics(self, filename):
        """Output all meta-metrics and cut decisions to HDF5 file.

        Saves all cut decisions and meta-metrics in an HDF5 that can be loaded
        back into a dictionary using hera_qm.ant_metrics.load_antenna_metrics()

        Arguments:
            filename: The file into which metrics will be written.
        """
        if not hasattr(self, 'xants'):
            raise KeyError(('Must run AntennaMetrics.'
                            'iterative_antenna_metrics_and_flagging() first.'))

        out_dict = {'xants': self.xants}
        out_dict['crossed_ants'] = self.crossedAntsRemoved
        out_dict['dead_ants'] = self.deadAntsRemoved
        out_dict['final_metrics'] = self.finalMetrics
        out_dict['all_metrics'] = self.allMetrics
        out_dict['final_mod_z_scores'] = self.finalModzScores
        out_dict['all_mod_z_scores'] = self.allModzScores
        out_dict['removal_iteration'] = self.removalIter
        out_dict['cross_pol_z_cut'] = self.crossCut
        out_dict['dead_ant_z_cut'] = self.deadCut
        out_dict['always_dead_ant_z_cut'] = self.alwaysDeadCut
        out_dict['datafile_list'] = self.dataFileList
        out_dict['reds'] = self.reds

        metrics_io.write_metric_file(filename, out_dict)