Ejemplo n.º 1
0
def run_rmclean(mDictS,
                aDict,
                cutoff,
                maxIter=1000,
                gain=0.1,
                nBits=32,
                showPlots=False,
                verbose=False,
                log=print):
    """Run RM-CLEAN on a complex FDF spectrum given a RMSF.

    Args:
        mDictS (dict): Summary of RM synthesis results.
        aDict (dict): Data output by RM synthesis.
        cutoff (float): CLEAN cutoff in flux units

    Kwargs:
        maxIter (int): Maximum number of CLEAN iterations per pixel.
        gain (float): CLEAN loop gain.
        nBits (int): Precision of floating point numbers.
        showPlots (bool): Show plots?
        verbose (bool): Verbosity.
        log (function): Which logging function to use.

    Returns:
        mDict (dict): Summary of RMCLEAN results.
        arrdict (dict): Data output by RMCLEAN.

    """
    phiArr_radm2 = aDict["phiArr_radm2"]
    freqArr_Hz = aDict["freqArr_Hz"]
    weightArr = aDict["weightArr"]
    dirtyFDF = aDict["dirtyFDF"]
    phi2Arr_radm2 = aDict["phi2Arr_radm2"]
    RMSFArr = aDict["RMSFArr"]

    lambdaSqArr_m2 = np.power(C / freqArr_Hz, 2.0)

    # If the cutoff is negative, assume it is a sigma level
    if verbose:
        log("Expected RMS noise = %.4g flux units" % (mDictS["dFDFth"]))
    if cutoff < 0:
        if verbose: log("Using a sigma cutoff of %.1f." % (-1 * cutoff))
        cutoff = -1 * mDictS["dFDFth"] * cutoff
        if verbose: log("Absolute value = %.3g" % cutoff)
    else:
        if verbose:
            log("Using an absolute cutoff of %.3g (%.1f x expected RMS)." %
                (cutoff, cutoff / mDictS["dFDFth"]))

    startTime = time.time()
    # Perform RM-clean on the spectrum
    cleanFDF, ccArr, iterCountArr, residFDF = \
              do_rmclean_hogbom(dirtyFDF        = dirtyFDF,
                                phiArr_radm2    = phiArr_radm2,
                                RMSFArr         = RMSFArr,
                                phi2Arr_radm2   = phi2Arr_radm2,
                                fwhmRMSFArr     = np.array(mDictS["fwhmRMSF"]),
                                cutoff          = cutoff,
                                maxIter         = maxIter,
                                gain            = gain,
                                verbose         = verbose,
                                doPlots         = showPlots)

    # ALTERNATIVE RM_CLEAN CODE ----------------------------------------------#
    '''
    cleanFDF, ccArr, fwhmRMSF, iterCount = \
              do_rmclean(dirtyFDF     = dirtyFDF,
                         phiArr       = phiArr_radm2,
                         lamSqArr     = lamSqArr_m2,
                         cutoff       = cutoff,
                         maxIter      = maxIter,
                         gain         = gain,
                         weight       = weightArr,
                         RMSFArr      = RMSFArr,
                         RMSFphiArr   = phi2Arr_radm2,
                         fwhmRMSF     = mDictS["fwhmRMSF"],
                         doPlots      = True)
    '''
    #-------------------------------------------------------------------------#

    endTime = time.time()
    cputime = (endTime - startTime)
    if verbose: log("> RM-CLEAN completed in %.4f seconds." % cputime)

    # Measure the parameters of the deconvolved FDF
    mDict = measure_FDF_parms(
        FDF=cleanFDF,
        phiArr=phiArr_radm2,
        fwhmRMSF=mDictS["fwhmRMSF"],
        #dFDF        = mDictS["dFDFth"],
        lamSqArr_m2=lambdaSqArr_m2,
        lam0Sq=mDictS["lam0Sq_m2"])
    mDict["cleanCutoff"] = cutoff
    mDict["nIter"] = int(iterCountArr)

    # Measure the complexity of the clean component spectrum
    mDict["mom2CCFDF"] = measure_fdf_complexity(phiArr=phiArr_radm2, FDF=ccArr)

    #Calculating observed errors (based on dFDFcorMAD)
    mDict["dPhiObserved_rm2"] = mDict["dPhiPeakPIfit_rm2"] * mDict[
        "dFDFcorMAD"] / mDictS["dFDFth"]
    mDict["dAmpObserved"] = mDict["dFDFcorMAD"]
    mDict["dPolAngleFitObserved_deg"] = mDict["dPolAngleFit_deg"] * mDict[
        "dFDFcorMAD"] / mDictS["dFDFth"]

    nChansGood = np.sum(np.where(lambdaSqArr_m2 == lambdaSqArr_m2, 1.0, 0.0))
    varLamSqArr_m2 = (np.sum(lambdaSqArr_m2**2.0) -
                      np.sum(lambdaSqArr_m2)**2.0 / nChansGood) / (nChansGood -
                                                                   1)
    mDict["dPolAngle0ChanObserved_deg"] = \
    np.degrees(np.sqrt( mDict["dFDFcorMAD"]**2.0 / (4.0*(nChansGood-2.0)*mDict["ampPeakPIfit"]**2.0) *
                 ((nChansGood-1)/nChansGood + mDictS["lam0Sq_m2"]**2.0/varLamSqArr_m2) ))

    if verbose:
        # Print the results to the screen
        log()
        log('-' * 80)
        log('RESULTS:\n')
        log('FWHM RMSF = %.4g rad/m^2' % (mDictS["fwhmRMSF"]))
        log('Pol Angle = %.4g (+/-%.4g observed, +- %.4g theoretical) deg' %
            (mDict["polAngleFit_deg"], mDict["dPolAngleFitObserved_deg"],
             mDict["dPolAngleFit_deg"]))
        log('Pol Angle 0 = %.4g (+/-%.4g observed, +- %.4g theoretical) deg' %
            (mDict["polAngle0Fit_deg"], mDict["dPolAngle0ChanObserved_deg"],
             mDict["dPolAngle0Fit_deg"]))
        log('Peak FD = %.4g (+/-%.4g observed, +- %.4g theoretical) rad/m^2' %
            (mDict["phiPeakPIfit_rm2"], mDict["dPhiObserved_rm2"],
             mDict["dPhiPeakPIfit_rm2"]))
        log('freq0_GHz = %.4g ' % (mDictS["freq0_Hz"] / 1e9))
        log('I freq0 = %.4g %s' % (mDictS["Ifreq0"], mDictS["units"]))
        log('Peak PI = %.4g (+/-%.4g observed, +- %.4g theoretical) %s' %
            (mDict["ampPeakPIfit"], mDict["dAmpObserved"],
             mDict["dAmpPeakPIfit"], mDictS["units"]))
        log('QU Noise = %.4g %s' % (mDictS["dQU"], mDictS["units"]))
        log('FDF Noise (theory)   = %.4g %s' %
            (mDictS["dFDFth"], mDictS["units"]))
        log('FDF Noise (Corrected MAD) = %.4g %s' %
            (mDict["dFDFcorMAD"], mDictS["units"]))
        log('FDF Noise (rms)   = %.4g %s' %
            (mDict["dFDFrms"], mDictS["units"]))

        log('FDF SNR = %.4g ' % (mDict["snrPIfit"]))
        log()
        log('-' * 80)

    # Pause to display the figure
    if showPlots:
        plot_clean_spec(phiArr_radm2, dirtyFDF, cleanFDF, ccArr, residFDF,
                        cutoff, mDictS["units"])
        print("Press <RETURN> to exit ...", end=' ')
        input()

    #add array dictionary
    arrdict = dict()
    arrdict["phiArr_radm2"] = phiArr_radm2
    arrdict["freqArr_Hz"] = freqArr_Hz
    arrdict["cleanFDF"] = cleanFDF
    arrdict["ccArr"] = ccArr
    arrdict["iterCountArr"] = iterCountArr
    arrdict["residFDF"] = residFDF

    return mDict, arrdict
Ejemplo n.º 2
0
def run_rmclean(mDict,
                aDict,
                cutoff,
                maxIter=1000,
                gain=0.1,
                nBits=32,
                showPlots=False,
                prefixOut="",
                verbose=False,
                log=print,
                saveFigures=False,
                window=None):
    """Run RM-CLEAN on a complex FDF spectrum given a RMSF.

    Args:
        mDict (dict): Summary of RM synthesis results.
        aDict (dict): Data output by RM synthesis.
        cutoff (float): CLEAN cutoff in flux units (positive)
                        or as multiple of theoretical noise (negative)
                        (i.e. -8 = clean to 8 sigma threshold)

    Kwargs:
        maxIter (int): Maximum number of CLEAN iterations per pixel.
        gain (float): CLEAN loop gain.
        nBits (int): Precision of floating point numbers.
        showPlots (bool): Show plots?
        verbose (bool): Verbosity.
        log (function): Which logging function to use.
        window (float): Threshold for deeper windowed cleaning

    Returns:
        mDict_cl (dict): Summary of RMCLEAN results.
        aDict_cl (dict): Data output by RMCLEAN.

    """
    phiArr_radm2 = aDict["phiArr_radm2"]
    freqArr_Hz = aDict["freqArr_Hz"]
    weightArr = aDict["weightArr"]
    dirtyFDF = aDict["dirtyFDF"]
    phi2Arr_radm2 = aDict["phi2Arr_radm2"]
    RMSFArr = aDict["RMSFArr"]

    lambdaSqArr_m2 = np.power(C / freqArr_Hz, 2.0)

    # If the cutoff is negative, assume it is a sigma level
    if verbose: log("Expected RMS noise = %.4g flux units" % (mDict["dFDFth"]))
    if cutoff < 0:
        if verbose: log("Using a sigma cutoff of %.1f." % (-1 * cutoff))
        cutoff = -1 * mDict["dFDFth"] * cutoff
        if verbose: log("Absolute value = %.3g" % cutoff)
    else:
        if verbose:
            log("Using an absolute cutoff of %.3g (%.1f x expected RMS)." %
                (cutoff, cutoff / mDict["dFDFth"]))

    if window is None:
        window = np.nan
    else:
        if window < 0:
            if verbose:
                log("Using a window sigma cutoff of %.1f." % (-1 * window))
            window = -1 * mDict["dFDFth"] * window
            if verbose: log("Absolute value = %.3g" % window)
        else:
            if verbose:
                log("Using an absolute window cutoff of %.3g (%.1f x expected RMS)."
                    % (window, window / mDict["dFDFth"]))

    startTime = time.time()
    # Perform RM-clean on the spectrum
    cleanFDF, ccArr, iterCountArr, residFDF = \
              do_rmclean_hogbom(dirtyFDF        = dirtyFDF,
                                phiArr_radm2    = phiArr_radm2,
                                RMSFArr         = RMSFArr,
                                phi2Arr_radm2   = phi2Arr_radm2,
                                fwhmRMSFArr     = np.array(mDict["fwhmRMSF"]),
                                cutoff          = cutoff,
                                maxIter         = maxIter,
                                gain            = gain,
                                verbose         = verbose,
                                doPlots         = showPlots,
                                window          = window
                                )

    # ALTERNATIVE RM_CLEAN CODE ----------------------------------------------#
    '''
    cleanFDF, ccArr, fwhmRMSF, iterCount = \
              do_rmclean(dirtyFDF     = dirtyFDF,
                         phiArr       = phiArr_radm2,
                         lamSqArr     = lamSqArr_m2,
                         cutoff       = cutoff,
                         maxIter      = maxIter,
                         gain         = gain,
                         weight       = weightArr,
                         RMSFArr      = RMSFArr,
                         RMSFphiArr   = phi2Arr_radm2,
                         fwhmRMSF     = mDict["fwhmRMSF"],
                         doPlots      = True)
    '''
    #-------------------------------------------------------------------------#

    endTime = time.time()
    cputime = (endTime - startTime)
    if verbose: log("> RM-CLEAN completed in %.4f seconds." % cputime)

    # Measure the parameters of the deconvolved FDF
    mDict_cl = measure_FDF_parms(FDF=cleanFDF,
                                 phiArr=phiArr_radm2,
                                 fwhmRMSF=mDict["fwhmRMSF"],
                                 dFDF=mDict["dFDFth"],
                                 lamSqArr_m2=lambdaSqArr_m2,
                                 lam0Sq=mDict["lam0Sq_m2"])
    mDict_cl["cleanCutoff"] = cutoff
    mDict_cl["nIter"] = int(iterCountArr)

    # Measure the complexity of the clean component spectrum
    mDict_cl["mom2CCFDF"] = measure_fdf_complexity(phiArr=phiArr_radm2,
                                                   FDF=ccArr)

    #Calculating observed errors (based on dFDFcorMAD)
    mDict_cl["dPhiObserved_rm2"] = mDict_cl["dPhiPeakPIfit_rm2"] * mDict_cl[
        "dFDFcorMAD"] / mDict["dFDFth"]
    mDict_cl["dAmpObserved"] = mDict_cl["dFDFcorMAD"]
    mDict_cl["dPolAngleFitObserved_deg"] = mDict_cl[
        "dPolAngleFit_deg"] * mDict_cl["dFDFcorMAD"] / mDict["dFDFth"]
    mDict_cl["dPolAngleFit0Observed_deg"] = mDict_cl[
        "dPolAngle0Fit_deg"] * mDict_cl["dFDFcorMAD"] / mDict["dFDFth"]

    if verbose:
        # Print the results to the screen
        log()
        log('-' * 80)
        log('RESULTS:\n')
        log('FWHM RMSF = %.4g rad/m^2' % (mDict["fwhmRMSF"]))
        log('Pol Angle = %.4g (+/-%.4g observed, +- %.4g theoretical) deg' %
            (mDict_cl["polAngleFit_deg"], mDict_cl["dPolAngleFitObserved_deg"],
             mDict_cl["dPolAngleFit_deg"]))
        log('Pol Angle 0 = %.4g (+/-%.4g observed, +- %.4g theoretical) deg' %
            (mDict_cl["polAngle0Fit_deg"],
             mDict_cl["dPolAngleFit0Observed_deg"],
             mDict_cl["dPolAngle0Fit_deg"]))
        log('Peak FD = %.4g (+/-%.4g observed, +- %.4g theoretical) rad/m^2' %
            (mDict_cl["phiPeakPIfit_rm2"], mDict_cl["dPhiObserved_rm2"],
             mDict_cl["dPhiPeakPIfit_rm2"]))
        log('freq0_GHz = %.4g ' % (mDict["freq0_Hz"] / 1e9))
        log('I freq0 = %.4g %s' % (mDict["Ifreq0"], mDict["units"]))
        log('Peak PI = %.4g (+/-%.4g observed, +- %.4g theoretical) %s' %
            (mDict_cl["ampPeakPIfit"], mDict_cl["dAmpObserved"],
             mDict_cl["dAmpPeakPIfit"], mDict["units"]))
        log('QU Noise = %.4g %s' % (mDict["dQU"], mDict["units"]))
        log('FDF Noise (theory)   = %.4g %s' %
            (mDict["dFDFth"], mDict["units"]))
        log('FDF Noise (Corrected MAD) = %.4g %s' %
            (mDict_cl["dFDFcorMAD"], mDict["units"]))
        log('FDF Noise (rms)   = %.4g %s' %
            (mDict_cl["dFDFrms"], mDict["units"]))

        log('FDF SNR = %.4g ' % (mDict_cl["snrPIfit"]))
        log()
        log('-' * 80)

    # Pause to display the figure
    if showPlots or saveFigures:
        fdfFig = plot_clean_spec(phiArr_radm2, dirtyFDF, cleanFDF, ccArr,
                                 residFDF, cutoff, window, mDict["units"])
    # Pause if plotting enabled
    if showPlots:
        plt.show()
    if saveFigures:
        if verbose: print("Saving CLEAN FDF plot:")
        outFilePlot = prefixOut + "_cleanFDF-plots.pdf"
        if verbose: print("> " + outFilePlot)
        fdfFig.savefig(outFilePlot, bbox_inches='tight')
        # print("Press <RETURN> to exit ...", end=' ')
        # input()

    #add array dictionary
    aDict_cl = dict()
    aDict_cl["phiArr_radm2"] = phiArr_radm2
    aDict_cl["freqArr_Hz"] = freqArr_Hz
    aDict_cl["cleanFDF"] = cleanFDF
    aDict_cl["ccArr"] = ccArr
    aDict_cl["iterCountArr"] = iterCountArr
    aDict_cl["residFDF"] = residFDF

    return mDict_cl, aDict_cl
Ejemplo n.º 3
0
def run_rmclean(mDictS,
                aDict,
                cutoff,
                maxIter=1000,
                gain=0.1,
                prefixOut="",
                outDir="",
                nBits=32,
                showPlots=False,
                doAnimate=False,
                verbose=False,
                log=print):
    """
    Run RM-CLEAN on a complex FDF spectrum given a RMSF.
    """
    phiArr_radm2 = aDict["phiArr_radm2"]
    freqArr_Hz = aDict["freqArr_Hz"]
    weightArr = aDict["weightArr"]
    dirtyFDF = aDict["dirtyFDF"]
    phi2Arr_radm2 = aDict["phi2Arr_radm2"]
    RMSFArr = aDict["RMSFArr"]

    lambdaSqArr_m2 = np.power(C / freqArr_Hz, 2.0)

    # If the cutoff is negative, assume it is a sigma level
    if verbose:
        log("Expected RMS noise = %.4g mJy/beam/rmsf" %
            (mDictS["dFDFth_Jybm"] * 1e3))
    if cutoff < 0:
        log("Using a sigma cutoff of %.1f." % (-1 * cutoff))
        cutoff = -1 * mDictS["dFDFth_Jybm"] * cutoff
        log("Absolute value = %.3g" % cutoff)
    else:
        log("Using an absolute cutoff of %.3g (%.1f x expected RMS)." %
            (cutoff, cutoff / mDictS["dFDFth_Jybm"]))

    startTime = time.time()
    # Perform RM-clean on the spectrum
    cleanFDF, ccArr, iterCountArr = \
              do_rmclean_hogbom(dirtyFDF        = dirtyFDF,
                                phiArr_radm2    = phiArr_radm2,
                                RMSFArr         = RMSFArr,
                                phi2Arr_radm2   = phi2Arr_radm2,
                                fwhmRMSFArr     = np.array(mDictS["fwhmRMSF"]),
                                cutoff          = cutoff,
                                maxIter         = maxIter,
                                gain            = gain,
                                verbose         = verbose,
                                doPlots         = showPlots,
                                doAnimate       = doAnimate)

    # ALTERNATIVE RM_CLEAN CODE ----------------------------------------------#
    '''
    cleanFDF, ccArr, fwhmRMSF, iterCount = \
              do_rmclean(dirtyFDF     = dirtyFDF,
                         phiArr       = phiArr_radm2,
                         lamSqArr     = lamSqArr_m2,
                         cutoff       = cutoff,
                         maxIter      = maxIter,
                         gain         = gain,
                         weight       = weightArr,
                         RMSFArr      = RMSFArr,
                         RMSFphiArr   = phi2Arr_radm2,
                         fwhmRMSF     = mDictS["fwhmRMSF"],
                         doPlots      = True)
    '''
    #-------------------------------------------------------------------------#

    endTime = time.time()
    cputime = (endTime - startTime)
    log("> RM-CLEAN completed in %.4f seconds." % cputime)

    # Measure the parameters of the deconvolved FDF
    mDict = measure_FDF_parms(
        FDF=cleanFDF,
        phiArr=phiArr_radm2,
        fwhmRMSF=mDictS["fwhmRMSF"],
        #dFDF        = mDictS["dFDFth_Jybm"],
        lamSqArr_m2=lambdaSqArr_m2,
        lam0Sq=mDictS["lam0Sq_m2"])
    mDict["cleanCutoff"] = cutoff
    mDict["nIter"] = int(iterCountArr)

    # Measure the complexity of the clean component spectrum
    mDict["mom2CCFDF"] = measure_fdf_complexity(phiArr=phiArr_radm2, FDF=ccArr)

    #Calculating observed errors (based on dFDFcorMAD)
    mDict["dPhiObserved_rm2"] = mDict["dPhiPeakPIfit_rm2"] * mDict[
        "dFDFcorMAD_Jybm"] / mDictS["dFDFth_Jybm"]
    mDict["dAmpObserved_Jybm"] = mDict["dFDFcorMAD_Jybm"]
    mDict["dPolAngleFitObserved_deg"] = mDict["dPolAngleFit_deg"] * mDict[
        "dFDFcorMAD_Jybm"] / mDictS["dFDFth_Jybm"]

    nChansGood = np.sum(np.where(lambdaSqArr_m2 == lambdaSqArr_m2, 1.0, 0.0))
    varLamSqArr_m2 = (np.sum(lambdaSqArr_m2**2.0) -
                      np.sum(lambdaSqArr_m2)**2.0 / nChansGood) / (nChansGood -
                                                                   1)
    mDict["dPolAngle0ChanObserved_deg"] = \
    np.degrees(np.sqrt( mDict["dFDFcorMAD_Jybm"]**2.0 / (4.0*(nChansGood-2.0)*mDict["ampPeakPIfit_Jybm"]**2.0) *
                 ((nChansGood-1)/nChansGood + mDictS["lam0Sq_m2"]**2.0/varLamSqArr_m2) ))

    # Save the deconvolved FDF and CC model to ASCII files
    log("Saving the clean FDF and component model to ASCII files.")
    outFile = prefixOut + "_FDFclean.dat"
    log("> %s" % outFile)
    np.savetxt(outFile, list(zip(phiArr_radm2, cleanFDF.real, cleanFDF.imag)))
    outFile = prefixOut + "_FDFmodel.dat"
    log("> %s" % outFile)
    np.savetxt(outFile, list(zip(phiArr_radm2, ccArr.real, ccArr.imag)))

    # Save the RM-clean measurements to a "key=value" text file
    log("Saving the measurements on the FDF in 'key=val' and JSON formats.")
    outFile = prefixOut + "_RMclean.dat"
    log("> %s" % outFile)
    FH = open(outFile, "w")
    for k, v in mDict.items():
        FH.write("%s=%s\n" % (k, v))
    FH.close()
    outFile = prefixOut + "_RMclean.json"
    log("> %s" % outFile)
    json.dump(mDict, open(outFile, "w"))

    # Print the results to the screen
    log()
    log('-' * 80)
    log('RESULTS:\n')
    log('FWHM RMSF = %.4g rad/m^2' % (mDictS["fwhmRMSF"]))
    log('Pol Angle = %.4g (+/-%.4g observed, +- %.4g theoretical) deg' %
        (mDict["polAngleFit_deg"], mDict["dPolAngleFitObserved_deg"],
         mDict["dPolAngleFit_deg"]))
    log('Pol Angle 0 = %.4g (+/-%.4g observed, +- %.4g theoretical) deg' %
        (mDict["polAngle0Fit_deg"], mDict["dPolAngle0ChanObserved_deg"],
         mDict["dPolAngle0Fit_deg"]))
    log('Peak FD = %.4g (+/-%.4g observed, +- %.4g theoretical) rad/m^2' %
        (mDict["phiPeakPIfit_rm2"], mDict["dPhiObserved_rm2"],
         mDict["dPhiPeakPIfit_rm2"]))
    log('freq0_GHz = %.4g ' % (mDictS["freq0_Hz"] / 1e9))
    log('I freq0 = %.4g mJy/beam' % (mDictS["Ifreq0_mJybm"]))
    log('Peak PI = %.4g (+/-%.4g observed, +- %.4g theoretical) mJy/beam' %
        (mDict["ampPeakPIfit_Jybm"] * 1e3, mDict["dAmpObserved_Jybm"] * 1e3,
         mDict["dAmpPeakPIfit_Jybm"] * 1e3))
    log('QU Noise = %.4g mJy/beam' % (mDictS["dQU_Jybm"] * 1e3))
    log('FDF Noise (theory)   = %.4g mJy/beam' % (mDictS["dFDFth_Jybm"] * 1e3))
    log('FDF Noise (Corrected MAD) = %.4g mJy/beam' %
        (mDict["dFDFcorMAD_Jybm"] * 1e3))
    log('FDF Noise (rms)   = %.4g mJy/beam' % (mDict["dFDFrms_Jybm"] * 1e3))

    log('FDF SNR = %.4g ' % (mDict["snrPIfit"]))
    log()
    log('-' * 80)

    # Pause to display the figure
    if showPlots or doAnimate:
        print("Press <RETURN> to exit ...", end=' ')
        input()

    return mDict
Ejemplo n.º 4
0
def run_rmclean(fdfFile,
                rmsfFile,
                weightFile,
                rmSynthFile,
                cutoff,
                maxIter=1000,
                gain=0.1,
                prefixOut="",
                outDir="",
                nBits=32,
                showPlots=False,
                doAnimate=False):
    """
    Run RM-CLEAN on a complex FDF spectrum given a RMSF.
    """

    # Default data types
    dtFloat = "float" + str(nBits)
    dtComplex = "complex" + str(2 * nBits)

    # Read the frequency vector for the lambda^2 array
    freqArr_Hz, weightArr = np.loadtxt(weightFile, unpack=True, dtype=dtFloat)
    lambdaSqArr_m2 = np.power(C / freqArr_Hz, 2.0)

    # Read the FDF from the ASCII file
    phiArr_radm2, FDFreal, FDFimag = np.loadtxt(fdfFile,
                                                unpack=True,
                                                dtype=dtFloat)
    dirtyFDF = FDFreal + 1j * FDFimag

    # Read the RMSF from the ASCII file
    phi2Arr_radm2, RMSFreal, RMSFimag = np.loadtxt(rmsfFile,
                                                   unpack=True,
                                                   dtype=dtFloat)
    RMSFArr = RMSFreal + 1j * RMSFimag

    # Read the RM-synthesis parameters from the JSON file
    mDictS = json.load(open(rmSynthFile, "r"))

    # If the cutoff is negative, assume it is a sigma level
    print "Expected RMS noise = %.4g mJy/beam/rmsf"  % \
        (mDictS["dFDFth_Jybm"]*1e3)
    if cutoff < 0:
        print "Using a sigma cutoff of %.1f." % (-1 * cutoff),
        cutoff = -1 * mDictS["dFDFth_Jybm"] * cutoff
        print "Absolute value = %.3g" % cutoff
    else:
        print "Using an absolute cutoff of %.3g (%.1f x expected RMS)." % \
            (cutoff, cutoff/mDictS["dFDFth_Jybm"])

    startTime = time.time()

    # Perform RM-clean on the spectrum
    cleanFDF, ccArr, iterCountArr = \
              do_rmclean_hogbom(dirtyFDF        = dirtyFDF,
                                phiArr_radm2    = phiArr_radm2,
                                RMSFArr         = RMSFArr,
                                phi2Arr_radm2   = phi2Arr_radm2,
                                fwhmRMSFArr     = np.array(mDictS["fwhmRMSF"]),
                                cutoff          = cutoff,
                                maxIter         = maxIter,
                                gain            = gain,
                                verbose         = False,
                                doPlots         = showPlots,
                                doAnimate       = doAnimate)
    cleanFDF  #/= 1e3
    ccArr  #/= 1e3

    # ALTERNATIVE RM_CLEAN CODE ----------------------------------------------#
    '''
    cleanFDF, ccArr, fwhmRMSF, iterCount = \
              do_rmclean(dirtyFDF     = dirtyFDF,
                         phiArr       = phiArr_radm2,
                         lamSqArr     = lamSqArr_m2,
                         cutoff       = cutoff,
                         maxIter      = maxIter,
                         gain         = gain,
                         weight       = weightArr,
                         RMSFArr      = RMSFArr,
                         RMSFphiArr   = phi2Arr_radm2,
                         fwhmRMSF     = mDictS["fwhmRMSF"],
                         doPlots      = True)
    '''
    #-------------------------------------------------------------------------#

    endTime = time.time()
    cputime = (endTime - startTime)
    print "> RM-CLEAN completed in %.4f seconds." % cputime

    # Measure the parameters of the deconvolved FDF
    mDict = measure_FDF_parms(
        FDF=cleanFDF,
        phiArr=phiArr_radm2,
        fwhmRMSF=mDictS["fwhmRMSF"],
        #dFDF        = mDictS["dFDFth_Jybm"],
        lamSqArr_m2=lambdaSqArr_m2,
        lam0Sq=mDictS["lam0Sq_m2"])
    mDict["cleanCutoff"] = cutoff
    mDict["nIter"] = int(iterCountArr)

    # Measure the complexity of the clean component spectrum
    mDict["mom2CCFDF"] = measure_fdf_complexity(phiArr=phiArr_radm2, FDF=ccArr)

    # Save the deconvolved FDF and CC model to ASCII files
    print "Saving the clean FDF and component model to ASCII files."
    outFile = prefixOut + "_FDFclean.dat"
    print "> %s" % outFile
    np.savetxt(outFile, zip(phiArr_radm2, cleanFDF.real, cleanFDF.imag))
    outFile = prefixOut + "_FDFmodel.dat"
    print "> %s" % outFile
    np.savetxt(outFile, zip(phiArr_radm2, ccArr))

    # Save the RM-clean measurements to a "key=value" text file
    print "Saving the measurements on the FDF in 'key=val' and JSON formats."
    outFile = prefixOut + "_RMclean.dat"
    print "> %s" % outFile
    FH = open(outFile, "w")
    for k, v in mDict.iteritems():
        FH.write("%s=%s\n" % (k, v))
    FH.close()
    outFile = prefixOut + "_RMclean.json"
    print "> %s" % outFile
    json.dump(mDict, open(outFile, "w"))

    # Print the results to the screen
    print
    print '-' * 80
    print 'RESULTS:\n'
    print 'FWHM RMSF = %.4g rad/m^2' % (mDictS["fwhmRMSF"])

    print 'Pol Angle = %.4g (+/-%.4g) deg' % (mDict["polAngleFit_deg"],
                                              mDict["dPolAngleFit_deg"])
    print 'Pol Angle 0 = %.4g (+/-%.4g) deg' % (mDict["polAngle0Fit_deg"],
                                                mDict["dPolAngle0Fit_deg"])
    print 'Peak FD = %.4g (+/-%.4g) rad/m^2' % (mDict["phiPeakPIfit_rm2"],
                                                mDict["dPhiPeakPIfit_rm2"])
    print 'freq0_GHz = %.4g ' % (mDictS["freq0_Hz"] / 1e9)
    print 'I freq0 = %.4g mJy/beam' % (mDictS["Ifreq0_mJybm"])
    print 'Peak PI = %.4g (+/-%.4g) mJy/beam' % (
        mDict["ampPeakPIfit_Jybm"] * 1e3, mDict["dAmpPeakPIfit_Jybm"] * 1e3)
    print 'QU Noise = %.4g mJy/beam' % (mDictS["dQU_Jybm"] * 1e3)
    print 'FDF Noise (measure) = %.4g mJy/beam' % (mDict["dFDFms_Jybm"] * 1e3)
    print 'FDF SNR = %.4g ' % (mDict["snrPIfit"])
    print
    print '-' * 80

    # Pause to display the figure
    if showPlots or doAnimate:
        print "Press <RETURN> to exit ...",
        raw_input()