Пример #1
0
    def writeCatalog(self, allSource, wcsDic, calibDic, ffpDic):
        num = sum(
            sum(1 for src in ss if src.getExp() >= 0 and src.getChip() >= 0)
            for ss in allSource)

        import pyfits

        schema = pyfits.ColDefs([
            pyfits.Column(name="id", format="K"),
            pyfits.Column(name="ra", format="D"),
            pyfits.Column(name="dec", format="D"),
            pyfits.Column(name="mag", format="E"),
            pyfits.Column(name="err", format="E"),
            pyfits.Column(name="corr", format="E"),
        ])

        outHdu = pyfits.new_table(schema, nrows=num)
        outData = outHdu.data

        i = 0
        for ss in allSource:
            for src in ss:
                iexp = src.getExp()
                ichip = src.getChip()
                if iexp < 0 or ichip < 0:
                    continue

                outData.id[i] = src.getId()
                x, y = src.getX(), src.getY()
                wcs = wcsDic[iexp][ichip]
                ra, dec = wcs.pixelToSky(x, y).getPosition(afwGeom.degrees)
                outData.ra[i] = ra
                outData.dec[i] = dec
                fluxMag0 = calibDic[iexp][ichip].getFluxMag0()[0]
                flux = src.getFlux()
                if flux > 0 and fluxMag0 > 0:
                    mcor = ffpDic[iexp][ichip].eval(x, y)
                    jcor = -2.5 * math.log10(
                        measMosaic.computeJacobian(wcs, afwGeom.Point2D(x, y)))
                    outData.mag[i] = -2.5 * math.log10(
                        flux / fluxMag0) + mcor + jcor
                    outData.err[i] = 2.5 / math.log(
                        10) * src.getFluxErr() / flux
                    outData.corr[i] = mcor + jcor
                    i += 1

        outHdu.writeto("catalog_check.fits", clobber=True)
    def writeCatalog(self, allSource, wcsDic, calibDic, ffpDic):
        num = sum(sum(1 for src in ss if src.getExp() >=0 and src.getChip() >= 0) for ss in allSource)

        from astropy.io import fits

        schema = fits.ColDefs([fits.Column(name="id", format="K"),
                                 fits.Column(name="ra", format="D"),
                                 fits.Column(name="dec", format="D"),
                                 fits.Column(name="mag", format="E"),
                                 fits.Column(name="err", format="E"),
                                 fits.Column(name="corr", format="E"),
                                 ])

        outHdu = fits.new_table(schema, nrows=num)
        outData = outHdu.data

        i = 0
        for ss in allSource:
            for src in ss:
                iexp = src.getExp()
                ichip = src.getChip()
                if iexp < 0 or ichip < 0:
                    continue

                outData.id[i] = src.getId()
                x, y = src.getX(), src.getY()
                wcs = wcsDic[iexp][ichip]
                ra, dec = wcs.pixelToSky(x, y).getPosition(afwGeom.degrees)
                outData.ra[i] = ra
                outData.dec[i] = dec
                fluxMag0 = calibDic[iexp][ichip].getInstFluxAtZeroMagnitude()
                flux = src.getFlux()
                if flux > 0 and fluxMag0 > 0:
                    mcor = ffpDic[iexp][ichip].eval(x, y)
                    jcor = -2.5*math.log10(measMosaic.computeJacobian(wcs, afwGeom.Point2D(x, y)))
                    outData.mag[i] = -2.5*math.log10(flux/fluxMag0) + mcor + jcor
                    outData.err[i] = 2.5/math.log(10) * src.getFluxErr() / flux
                    outData.corr[i] = mcor + jcor
                    i += 1

        outHdu.writeto("catalog_check.fits", clobber=True)
    def run(self, matchLists, filterName, wcsList, butler):

        if self.config.applyColorTerms:
            ct = self.config.colorterms.selectColorTerm(filterName)
        else:
            ct = None

        # Convert matchLists to meas_mosaic specific format
        mlVisit = dict()
        for ccdId in matchLists:
            if matchLists[ccdId] is None:
                continue
            visit, ccd = self.decodeCcdExposureId(ccdId)
            if visit not in mlVisit:
                mlVisit[visit] = list()
            matches = [m for m in matchLists[ccdId] if m[0] is not None]
            keys = self.getKeys(matches[0][1].schema)
            matches = self.selectMatches(matches, keys)
            matches = self.selectStars(matches)

            # Apply color term
            if ct is not None and len(matches) != 0:
                refSchema = matches[0][0].schema
                key_p = refSchema.find(ct.primary).key
                key_s = refSchema.find(ct.secondary).key
                key_f = refSchema.find("flux").key
                refFlux1 = numpy.array([m[0].get(key_p) for m in matches])
                refFlux2 = numpy.array([m[0].get(key_s) for m in matches])
                refMag1 = -2.5 * numpy.log10(refFlux1)
                refMag2 = -2.5 * numpy.log10(refFlux2)
                refMag = ct.transformMags(refMag1, refMag2)
                refFlux = numpy.power(10.0, -0.4 * refMag)
                matches = [
                    self.setCatFlux(m, f, key_f)
                    for m, f in zip(matches, refFlux) if f == f
                ]

            for m in matches:
                if m[0] is not None and m[1] is not None:
                    match = (measMosaic.Source(m[0], wcsList[ccdId]),
                             measMosaic.Source(m[1]))
                    match[1].setExp(visit)
                    match[1].setChip(ccd)
                    mlVisit[visit].append(match)

        matchList = []
        for visit in mlVisit:
            matchList.append(mlVisit[visit])

        rootMat = measMosaic.kdtreeMat(matchList)
        allMat = rootMat.mergeMat()

        # Read CCD information
        ccdSet = {}
        for ccdId in matchLists:
            if matchLists[ccdId] is None:
                continue
            visit, ccd = self.decodeCcdExposureId(ccdId)
            if ccd not in ccdSet:
                ccdDev = cameraGeomUtils.findCcd(butler.mapper.camera,
                                                 cameraGeom.Id(int(ccd)))
                ccdSet[ccd] = ccdDev

        # meas_mosaic specific wcs information
        wcsDic = {}
        for ccdId in wcsList:
            visit, ccd = self.decodeCcdExposureId(ccdId)
            if visit not in wcsDic and wcsList[ccdId] is not None:
                wcs = wcsList[ccdId]
                ccdDev = ccdSet[ccd]
                offset = afwGeom.Extent2D(ccdDev.getCenter().getPixels(
                    ccdDev.getPixelSize()))
                wcsDic[visit] = wcs.copyAtShiftedPixelOrigin(offset)

        # meas_mosaic specific object list
        matchVec = measMosaic.obsVecFromSourceGroup(allMat, wcsDic, ccdSet)
        sourceVec = []

        # Apply Jocabian correction calculated from wcs
        for m in matchVec:
            wcs = wcsList[m.iexp * 200 + m.ichip]
            m.mag -= 2.5 * math.log10(
                measMosaic.computeJacobian(wcs, afwGeom.Point2D(m.x, m.y)))

        fluxFitOrder = self.config.fluxFitOrder
        absolute = True
        chebyshev = True
        commonFluxCorr = False
        solveCcdScale = True
        ffpSet = {}
        for visit in wcsDic:
            ffp = measMosaic.FluxFitParams(fluxFitOrder, absolute, chebyshev)
            u_max, v_max = self.getExtent(matchVec)
            ffp.u_max = (math.floor(u_max / 10.) + 1) * 10
            ffp.v_max = (math.floor(v_max / 10.) + 1) * 10
            ffpSet[visit] = ffp

        fexp = {}
        fchip = {}

        matchVec, sourceVec, wcsDic, ccdSet, fexp, fchip, ffpSet = measMosaic.fluxFit(
            absolute, commonFluxCorr, matchVec, len(matchVec), sourceVec,
            len(sourceVec), wcsDic, ccdSet, fexp, fchip, ffpSet, solveCcdScale)

        self.writeFcr(butler, list(matchLists.keys()), ccdSet, filterName,
                      fexp, fchip, ffpSet)

        return (1.0 / fexp[list(fexp.keys())[0]])
Пример #4
0
    def mosaic(self,
               dataRefList,
               tractInfo,
               ct=None,
               debug=False,
               diagDir=".",
               diagnostics=False,
               snapshots=False,
               numCoresForReadSource=1,
               readTimeout=9999,
               verbose=False):

        self.log.info(str(self.config))

        self.outputDir = os.path.join(diagDir, "%04d" % tractInfo.getId())

        if ((diagnostics or snapshots) and not os.path.isdir(self.outputDir)):
            os.makedirs(self.outputDir)

        if self.config.nBrightest != 0:
            self.log.fatal("Config paremeter nBrightest is deprecated.")
            self.log.fatal("Please use cellSize and nStarPerCell.")
            self.log.fatal("Exiting ...")
            return []

        dataRefListOverlapWithTract, dataRefListToUse = self.checkOverlapWithTract(
            tractInfo, dataRefList)

        sourceSet, matchList, dataRefListUsed = self.readCatalog(
            dataRefListToUse, ct, numCoresForReadSource, readTimeout, verbose)

        dataRefListToOutput = list(
            set(dataRefListUsed) & set(dataRefListOverlapWithTract))

        ccdSet = self.readCcd(dataRefListUsed)

        if debug:
            for ccd in ccdSet.values():
                self.log.info(
                    str(ccd.getId().getSerial()) + " " +
                    str(ccd.getCenter().getPixels(ccd.getPixelSize())) + " " +
                    str(ccd.getOrientation().getYaw()))

        wcsDic = self.readWcs(dataRefListUsed, ccdSet)

        self.removeNonExistCcd(dataRefListUsed, ccdSet)

        if debug:
            for iexp, wcs in wcsDic.items():
                self.log.info(
                    str(iexp) + " " + str(wcs.getPixelOrigin()) + " " +
                    str(wcs.getSkyOrigin().getPosition(afwGeom.degrees)))

        self.log.info("frameIds : " + str(list(wcsDic.keys())))
        self.log.info("ccdIds : " + str(list(ccdSet.keys())))

        d_lim = afwGeom.Angle(self.config.radXMatch, afwGeom.arcseconds)
        if debug:
            self.log.info("d_lim : %f" % d_lim)

        allMat, allSource = self.mergeCatalog(sourceSet, matchList, ccdSet,
                                              d_lim)

        self.log.info("Flag suspect objects")
        measMosaic.flagSuspect(allMat, allSource, wcsDic)

        if self.config.clipSourcesOutsideTract:
            tractBBox = afwGeom.Box2D(tractInfo.getBBox())
            tractWcs = tractInfo.getWcs()
            allSourceClipped = [
                ss for ss in allSource
                if tractBBox.contains(tractWcs.skyToPixel(ss[0].getSky()))
            ]
            self.log.info("Num of allSources: %d" % (len(allSource)))
            self.log.info("Num of clipped allSources: %d" %
                          (len(allSourceClipped)))
            allSource = allSourceClipped

        self.log.info("Make obsVec")
        nmatch = len(allMat)
        nsource = len(allSource)
        matchVec = measMosaic.obsVecFromSourceGroup(allMat, wcsDic, ccdSet)
        sourceVec = measMosaic.obsVecFromSourceGroup(allSource, wcsDic, ccdSet)

        self.log.info("Solve mosaic ...")
        order = self.config.fittingOrder
        internal = self.config.internalFitting
        solveCcd = self.config.solveCcd
        allowRotation = self.config.allowRotation
        fluxFitOrder = self.config.fluxFitOrder
        chebyshev = self.config.chebyshev
        absolute = self.config.fluxFitAbsolute
        solveCcdScale = self.config.fluxFitSolveCcd
        catRMS = self.config.catRMS

        if not internal:
            sourceVec = []

        if debug:
            self.log.info("order : %d" % order)
            self.log.info("internal : %r" % internal)
            self.log.info("solveCcd : %r " % solveCcd)
            self.log.info("allowRotation : %r" % allowRotation)

        if self.config.doSolveWcs:
            if internal:
                coeffSet, matchVec, sourceVec, wcsDic, ccdSet = measMosaic.solveMosaic_CCD(
                    order, nmatch, nsource, matchVec, sourceVec, wcsDic,
                    ccdSet, solveCcd, allowRotation, verbose, catRMS,
                    snapshots, self.outputDir)
            else:
                coeffSet, matchVec, wcsDic, ccdSet = measMosaic.solveMosaic_CCD_shot(
                    order, nmatch, matchVec, wcsDic, ccdSet, solveCcd,
                    allowRotation, verbose, catRMS, snapshots, self.outputDir)

            self.matchVec = matchVec
            self.sourceVec = sourceVec
            self.wcsDic = wcsDic
            self.ccdSet = ccdSet
            self.coeffSet = coeffSet

            self.writeNewWcs(dataRefListToOutput)

            if diagnostics:
                self.outputDiagWcs()

            for m in matchVec:
                coeff = coeffSet[m.iexp]
                scale = coeff.pixelScale()
                m.mag -= 2.5 * math.log10(coeff.detJ(m.u, m.v) / scale**2)

            if len(sourceVec) != 0:
                for s in sourceVec:
                    coeff = coeffSet[s.iexp]
                    scale = coeff.pixelScale()
                    s.mag -= 2.5 * math.log10(coeff.detJ(s.u, s.v) / scale**2)

        else:

            wcsAll = dict()

            for dataRef in dataRefListUsed:
                frameId = "%07d-%03d" % (dataRef.dataId["visit"],
                                         dataRef.dataId["ccd"])
                md = dataRef.get("calexp_md")
                wcsAll[frameId] = afwGeom.makeSkyWcs(md)
                del md

            for m in matchVec:
                wcs = wcsAll["%07d-%03d" % (m.iexp, m.ichip)]
                m.mag -= 2.5 * math.log10(
                    measMosaic.computeJacobian(wcs, afwGeom.Point2D(m.x, m.y)))

            if len(sourceVec) != 0:
                for s in sourceVec:
                    wcs = wcsAll["%07d-%03d" % (s.iexp, s.ichip)]
                    s.mag -= 2.5 * math.log10(
                        measMosaic.computeJacobian(wcs,
                                                   afwGeom.Point2D(s.x, s.y)))

            del wcsAll

        if self.config.doSolveFlux:

            ffpSet = {}
            for visit in wcsDic:
                ffp = measMosaic.FluxFitParams(fluxFitOrder, absolute,
                                               chebyshev)
                u_max, v_max = mosaicUtils.getExtent(matchVec)
                ffp.u_max = (math.floor(u_max / 10.0) + 1) * 10
                ffp.v_max = (math.floor(v_max / 10.0) + 1) * 10
                ffpSet[visit] = ffp

            fexp = {}
            fchip = {}

            matchVec, sourceVec, wcsDic, ccdSet, fexp, fchip, ffpSet = measMosaic.fluxFit(
                absolute, self.config.commonFluxCorr, matchVec, len(matchVec),
                sourceVec, len(sourceVec), wcsDic, ccdSet, fexp, fchip, ffpSet,
                solveCcdScale)

            self.ffpSet = ffpSet
            self.fexp = fexp
            self.fchip = fchip

            self.writeFcr(dataRefListToOutput)

            if diagnostics:
                self.outputDiagFlux()

        if diagnostics and self.config.doSolveWcs and self.config.doSolveFlux:
            if len(sourceVec) != 0:
                mosaicUtils.writeCatalog(
                    coeffSet, ffpSet, fexp, fchip, matchVec, sourceVec,
                    os.path.join(self.outputDir, "catalog.fits"))

        return list(wcsDic.keys())
    def makeDiffPosFlux(self, allMat, allSource, wcsDic, calibDic, ffpDic):
        dx_m = list()
        dy_m = list()
        dx_s = list()
        dy_s = list()
        m0_m = list()
        dm_m  = list()
        m0_s = list()
        dm_s  = list()
        for ss in allMat:
            ra_cat = ss[0].getRa().asDegrees()
            dec_cat = ss[0].getDec().asDegrees()
            mag_cat = -2.5*math.log10(ss[0].getFlux())
            for j in range(1,len(ss)):
                if (ss[j].getFlux() > 0 and ss[j].getFlux() != float('inf')):
                    iexp = ss[j].getExp()
                    ichip = ss[j].getChip()
                    x, y = ss[j].getX(), ss[j].getY()
                    wcs = wcsDic[iexp][ichip]
                    ra, dec = wcs.pixelToSky(x, y).getPosition(afwGeom.degrees)
                    dx_m.append((ra - ra_cat) * 3600)
                    dy_m.append((dec - dec_cat) * 3600)
                    mag = 2.5*math.log10(calibDic[iexp][ichip].getInstFluxAtZeroMagnitude()/ss[j].getFlux())
                    mcor = ffpDic[iexp][ichip].eval(x,y)
                    jcor = -2.5*math.log10(measMosaic.computeJacobian(wcs, afwGeom.Point2D(x, y)))
                    m0_m.append(mag_cat)
                    dm_m.append(mag+mcor+jcor-mag_cat)

            if len(ss) > 2:
                n = 0
                ra_cat = 0.0
                dec_cat = 0.0
                S  = 0.0
                Sx = 0.0
                ra_source = list()
                dec_source = list()
                mag_source = list()
                for j in range(1,len(ss)):
                    if (ss[j].getFlux() > 0 and ss[j].getFlux() != float('inf')):
                        iexp = ss[j].getExp()
                        ichip = ss[j].getChip()
                        x, y = ss[j].getX(), ss[j].getY()
                        wcs = wcsDic[iexp][ichip]
                        ra, dec = wcs.pixelToSky(x, y).getPosition(afwGeom.degrees)
                        ra_source.append(ra)
                        dec_source.append(dec)
                        n += 1
                        ra_cat += ra
                        dec_cat += dec

                        mag = 2.5*math.log10(calibDic[iexp][ichip].getInstFluxAtZeroMagnitude()/ss[j].getFlux())
                        err = 2.5 / math.log(10) * ss[j].getFluxErr() / ss[j].getFlux()
                        mcor = ffpDic[iexp][ichip].eval(x,y)
                        jcor = -2.5*math.log10(measMosaic.computeJacobian(wcs, afwGeom.Point2D(x, y)))
                        mag_source.append(mag+mcor+jcor)
                        Sx += (mag+mcor+jcor) / (err*err)
                        S  += 1. / (err*err)

                if n != 0 and S != 0:
                    ra_cat /= n
                    dec_cat /= n
                    mag_cat = Sx / S
                    for ra, dec, mag in zip(ra_source, dec_source, mag_source):
                        dx_s.append((ra - ra_cat) * 3600)
                        dy_s.append((dec - dec_cat) * 3600)
                        m0_s.append(mag_cat)
                        dm_s.append(mag - mag_cat)

        dx_m = numpy.array(dx_m)
        dy_m = numpy.array(dy_m)
        m0_m = numpy.array(m0_m)
        dm_m = numpy.array(dm_m)

        for ss in allSource:
            n = 0
            ra_cat = 0.0
            dec_cat = 0.0
            Sx = 0.0
            S  = 0.0
            ra_source = list()
            dec_source = list()
            mag_source = list()
            for j in range(1,len(ss)):
                if (ss[j].getFlux() > 0 and ss[j].getFlux() != float('inf')):
                    iexp = ss[j].getExp()
                    ichip = ss[j].getChip()
                    x, y = ss[j].getX(), ss[j].getY()
                    wcs = wcsDic[iexp][ichip]
                    ra, dec = wcs.pixelToSky(x, y).getPosition(afwGeom.degrees)
                    ra_source.append(ra)
                    dec_source.append(dec)
                    n += 1
                    ra_cat += ra
                    dec_cat += dec

                    mag = 2.5*math.log10(calibDic[iexp][ichip].getInstFluxAtZeroMagnitude()/ss[j].getFlux())
                    err = 2.5 / math.log(10) * ss[j].getFluxErr() / ss[j].getFlux()
                    mcor = ffpDic[iexp][ichip].eval(x,y)
                    jcor = -2.5*math.log10(measMosaic.computeJacobian(wcs, afwGeom.Point2D(x, y)))
                    mag_source.append(mag+mcor+jcor)
                    Sx += (mag+mcor+jcor) / (err*err)
                    S  += 1. / (err*err)

            if n != 0:
                ra_cat /= n
                dec_cat /= n
                mag_cat = Sx / S
                for ra, dec, mag in zip(ra_source, dec_source, mag_source):
                    dx_s.append((ra - ra_cat) * 3600)
                    dy_s.append((dec - dec_cat) * 3600)
                    m0_s.append(mag_cat)
                    dm_s.append(mag - mag_cat)

        dx_s = numpy.array(dx_s)
        dy_s = numpy.array(dy_s)
        m0_s = numpy.array(m0_s)
        dm_s = numpy.array(dm_s)

        return dx_m, dy_m, dx_s, dy_s, m0_m, dm_m, m0_s, dm_s
    def makeFluxStat(self, allMat, allSource, calibDic, ffpDic, wcsDic):

        x = list()
        y = list()
        ra = list()
        dec = list()
        id = list()
        for ss in allMat:
            Sxx = 0.0
            Sx  = 0.0
            S   = 0.0
            Sr  = 0.0
            Sd  = 0.0
            if len(ss) > 2:
                for j in range(1,len(ss)):
                    iexp = ss[j].getExp()
                    ichip = ss[j].getChip()
                    if ss[j].getFlux() > 0.0:
                        mag = calibDic[iexp][ichip].instFluxToMagnitude(ss[j].getFlux())
                        err = 2.5 / math.log(10) * ss[j].getFluxErr() / ss[j].getFlux()
                        xs, ys = ss[j].getX(), ss[j].getY()
                        mcor = ffpDic[iexp][ichip].eval(xs, ys)
                        wcs = wcsDic[iexp][ichip]
                        jcor = -2.5*math.log10(measMosaic.computeJacobian(wcs, afwGeom.Point2D(xs, ys)))
                        Sxx += (mag+mcor+jcor)*(mag+mcor+jcor) / (err*err)
                        Sx  += (mag+mcor+jcor) / (err*err)
                        S   += 1. / (err*err)
                        Sr += ss[j].getRa().asDegrees()
                        Sd += ss[j].getDec().asDegrees()
                avg = Sx / S
                sig = math.sqrt(Sxx/S - avg*avg)
                x.append(avg)
                y.append(sig)
                ra.append(Sr / (len(ss)-1))
                dec.append(Sd / (len(ss)-1))

        for ss in allSource:
            Sxx = 0.0
            Sx = 0.0
            S  = 0.0
            Sr  = 0.0
            Sd  = 0.0
            for j in range(1,len(ss)):
                iexp = ss[j].getExp()
                ichip = ss[j].getChip()
                #print iexp, ichip, calibDic[iexp][ichip].getInstFluxAtZeroMagnitude(), ss[j].getFlux()
                if calibDic[iexp][ichip].getInstFluxAtZeroMagnitude() > 0 and ss[j].getFlux() > 0.0:
                    mag = calibDic[iexp][ichip].instFluxToMagnitude(ss[j].getFlux())
                    err = 2.5 / math.log(10) * ss[j].getFluxErr() / ss[j].getFlux()
                    xs, ys = ss[j].getX(), ss[j].getY()
                    mcor = ffpDic[iexp][ichip].eval(xs, ys)
                    wcs = wcsDic[iexp][ichip]
                    jcor = -2.5*math.log10(measMosaic.computeJacobian(wcs, afwGeom.Point2D(xs, ys)))
                    Sxx += (mag+mcor+jcor)*(mag+mcor+jcor) / (err*err)
                    Sx  += (mag+mcor+jcor) / (err*err)
                    S   += 1. / (err*err)
                    Sr += ss[j].getRa().asDegrees()
                    Sd += ss[j].getDec().asDegrees()
            if S > 0:
                try:
                    avg = Sx / S
                    sig = math.sqrt(Sxx/S - avg*avg)
                    x.append(avg)
                    y.append(sig)
                    ra.append(Sr / (len(ss)-1))
                    dec.append(Sd / (len(ss)-1))
                except Exception as e:
                    #print Sxx, S, avg, Sxx/S - avg*avg, len(ss)-1
                    pass

        if True:
            plt.clf()
            plt.plot(x, y, ',', markeredgewidth=0)
            plt.xlim(15, 25)
            plt.ylim(0.0, 0.20)
            plt.plot([15, 25], [0.01, 0.01], 'k--')
            plt.xlabel('mag (avg)')
            plt.ylabel('RMS')
            #plt.title('r-band')
            plt.savefig('fluxMean.png')
        else:
            for r, d, m, dm in zip(ra, dec, x, y):
                print('%9.5f %9.5f %7.4f %7.4f' % (r, d, m ,dm))
Пример #7
0
    def run(self, dataRefList, tractInfo, ct=None, debug=False, diagDir=".",
            diagnostics=False, snapshots=False, numCoresForReadSource=1, readTimeout=9999, verbose=False):

        self.log.info(str(self.config))

        self.outputDir = os.path.join(diagDir, "%04d" % tractInfo.getId())

        if ((diagnostics or snapshots) and not os.path.isdir(self.outputDir)):
            os.makedirs(self.outputDir)

        if self.config.nBrightest != 0:
            self.log.fatal("Config paremeter nBrightest is deprecated.")
            self.log.fatal("Please use cellSize and nStarPerCell.")
            self.log.fatal("Exiting ...")
            return []

        dataRefListOverlapWithTract, dataRefListToUse = self.checkOverlapWithTract(tractInfo, dataRefList)

        sourceSet, matchList, dataRefListUsed = self.readCatalog(dataRefListToUse, ct, numCoresForReadSource,
                                                                 readTimeout, verbose)
        if not matchList:
            raise RuntimeError("No reference source matches found")

        dataRefListToOutput = list(set(dataRefListUsed) & set(dataRefListOverlapWithTract))

        ccdSet = self.readCcd(dataRefListUsed)

        if debug:
            for ccd in ccdSet.values():
                self.log.info(str(ccd.getId().getSerial()) + " " +
                              str(ccd.getCenter().getPixels(ccd.getPixelSize())) + " " +
                              str(ccd.getOrientation().getYaw()))

        wcsDic = self.readWcs(dataRefListUsed, ccdSet)

        self.removeNonExistCcd(dataRefListUsed, ccdSet)

        if debug:
            for iexp, wcs in wcsDic.items():
                self.log.info(str(iexp) + " " + str(wcs.getPixelOrigin()) + " " +
                              str(wcs.getSkyOrigin().getPosition(afwGeom.degrees)))

        self.log.info("frameIds : " + str(list(wcsDic.keys())))
        self.log.info("ccdIds : " + str(list(ccdSet.keys())))

        d_lim = afwGeom.Angle(self.config.radXMatch, afwGeom.arcseconds)
        if debug:
            self.log.info("d_lim : %f" % d_lim)

        allMat, allSource =self.mergeCatalog(sourceSet, matchList, ccdSet, d_lim)

        self.log.info("Flag suspect objects")
        measMosaic.flagSuspect(allMat, allSource, wcsDic)

        if self.config.clipSourcesOutsideTract:
            tractBBox = afwGeom.Box2D(tractInfo.getBBox())
            tractWcs = tractInfo.getWcs()
            allSourceClipped = [ss for ss in allSource if tractBBox.contains(tractWcs.skyToPixel(ss[0].getSky()))]
            self.log.info("Num of allSources: %d" % (len(allSource)))
            self.log.info("Num of clipped allSources: %d" % (len(allSourceClipped)))
            allSource = allSourceClipped

        self.log.info("Make obsVec")
        nmatch  = len(allMat)
        nsource = len(allSource)
        matchVec  = measMosaic.obsVecFromSourceGroup(allMat, wcsDic, ccdSet)
        sourceVec = measMosaic.obsVecFromSourceGroup(allSource, wcsDic, ccdSet)

        self.log.info("Solve mosaic ...")
        order = self.config.fittingOrder
        internal = self.config.internalFitting
        solveCcd = self.config.solveCcd
        allowRotation = self.config.allowRotation
        fluxFitOrder = self.config.fluxFitOrder
        chebyshev = self.config.chebyshev
        absolute = self.config.fluxFitAbsolute
        solveCcdScale = self.config.fluxFitSolveCcd
        catRMS = self.config.catRMS

        if not internal:
            sourceVec = []

        if debug:
            self.log.info("order : %d" % order)
            self.log.info("internal : %r" % internal)
            self.log.info("solveCcd : %r " % solveCcd)
            self.log.info("allowRotation : %r" % allowRotation)

        if self.config.doSolveWcs:
            if internal:
                coeffSet, matchVec, sourceVec, wcsDic, ccdSet = measMosaic.solveMosaic_CCD(order, nmatch, nsource,
                                                      matchVec, sourceVec,
                                                      wcsDic, ccdSet,
                                                      solveCcd, allowRotation,
                                                      verbose, catRMS,
                                                      snapshots, self.outputDir)
            else:
                coeffSet, matchVec, wcsDic, ccdSet = measMosaic.solveMosaic_CCD_shot(order, nmatch, matchVec,
                                                           wcsDic, ccdSet,
                                                           solveCcd, allowRotation,
                                                           verbose, catRMS,
                                                           snapshots, self.outputDir)

            self.matchVec = matchVec
            self.sourceVec = sourceVec
            self.wcsDic = wcsDic
            self.ccdSet = ccdSet
            self.coeffSet = coeffSet

            self.writeNewWcs(dataRefListToOutput)

            if diagnostics:
                self.outputDiagWcs()

            for m in matchVec:
                coeff = coeffSet[m.iexp]
                scale = coeff.pixelScale()
                m.mag -= 2.5*math.log10(coeff.detJ(m.u, m.v)/scale**2)

            if len(sourceVec) != 0:
                for s in sourceVec:
                    coeff = coeffSet[s.iexp]
                    scale = coeff.pixelScale()
                    s.mag -= 2.5*math.log10(coeff.detJ(s.u, s.v)/scale**2)

        else:

            wcsAll = dict()

            for dataRef in dataRefListUsed:
                frameId = "%07d-%03d" % (dataRef.dataId["visit"], dataRef.dataId["ccd"])
                md = dataRef.get("calexp_md")
                wcsAll[frameId] = afwGeom.makeSkyWcs(md)
                del md

            for m in matchVec:
                wcs = wcsAll["%07d-%03d" % (m.iexp, m.ichip)]
                m.mag -= 2.5*math.log10(measMosaic.computeJacobian(wcs, afwGeom.Point2D(m.x, m.y)))

            if len(sourceVec) != 0:
                for s in sourceVec:
                    wcs = wcsAll["%07d-%03d" % (s.iexp, s.ichip)]
                    s.mag -= 2.5*math.log10(measMosaic.computeJacobian(wcs, afwGeom.Point2D(s.x, s.y)))

            del wcsAll

        if self.config.doSolveFlux:

            ffpSet = {}
            for visit in wcsDic:
                ffp = measMosaic.FluxFitParams(fluxFitOrder, absolute, chebyshev)
                u_max, v_max = mosaicUtils.getExtent(matchVec)
                ffp.u_max = (math.floor(u_max/10.0) + 1)*10
                ffp.v_max = (math.floor(v_max/10.0) + 1)*10
                ffpSet[visit] = ffp

            fexp = {}
            fchip = {}

            matchVec, sourceVec, wcsDic, ccdSet, fexp, fchip, ffpSet = measMosaic.fluxFit(absolute, self.config.commonFluxCorr, matchVec, len(matchVec), sourceVec, len(sourceVec), wcsDic, ccdSet, fexp, fchip, ffpSet, solveCcdScale)

            self.ffpSet = ffpSet
            self.fexp = fexp
            self.fchip = fchip

            self.writeFcr(dataRefListToOutput)

            if diagnostics:
                self.outputDiagFlux()

        if diagnostics and self.config.doSolveWcs and self.config.doSolveFlux:
            if len(sourceVec) != 0:
                mosaicUtils.writeCatalog(coeffSet, ffpSet, fexp, fchip, matchVec, sourceVec,
                                         os.path.join(self.outputDir, "catalog.fits"))

        return list(wcsDic.keys())
    def run(self, matchLists, filterName, wcsList, butler):

        if self.config.applyColorTerms:
            ct = self.config.colorterms.selectColorTerm(filterName)
        else:
            ct = None

        # Convert matchLists to meas_mosaic specific format
        mlVisit = dict()
        for ccdId in matchLists:
            if matchLists[ccdId] is None:
                continue
            visit, ccd = self.decodeCcdExposureId(ccdId)
            if visit not in mlVisit:
                mlVisit[visit] = list()
            matches = [m for m in matchLists[ccdId] if m[0] is not None]
            keys = self.getKeys(matches[0][1].schema)
            matches = self.selectMatches(matches, keys)
            matches = self.selectStars(matches)

            # Apply color term
            if ct is not None and len(matches) != 0:
                refSchema = matches[0][0].schema
                key_p = refSchema.find(ct.primary).key
                key_s = refSchema.find(ct.secondary).key
                key_f = refSchema.find("flux").key
                refFlux1 = numpy.array([m[0].get(key_p) for m in matches])
                refFlux2 = numpy.array([m[0].get(key_s) for m in matches])
                refMag1 = -2.5*numpy.log10(refFlux1)
                refMag2 = -2.5*numpy.log10(refFlux2)
                refMag = ct.transformMags(refMag1, refMag2)
                refFlux = numpy.power(10.0, -0.4*refMag)
                matches = [self.setCatFlux(m, f, key_f) for m, f in zip(matches, refFlux) if f == f]

            for m in matches:
                if m[0] is not None and m[1] is not None:
                    match = (measMosaic.Source(m[0], wcsList[ccdId]), measMosaic.Source(m[1]))
                    match[1].setExp(visit)
                    match[1].setChip(ccd)
                    mlVisit[visit].append(match)


        matchList = []
        for visit in mlVisit:
            matchList.append(mlVisit[visit])

        rootMat = measMosaic.kdtreeMat(matchList)
        allMat = rootMat.mergeMat()

        # Read CCD information
        ccdSet = {}
        for ccdId in matchLists:
            if matchLists[ccdId] is None:
                continue
            visit, ccd = self.decodeCcdExposureId(ccdId)
            if ccd not in ccdSet:
                ccdDev = cameraGeomUtils.findCcd(butler.mapper.camera, cameraGeom.Id(int(ccd)))
                ccdSet[ccd] = ccdDev

        # meas_mosaic specific wcs information
        wcsDic = {}
        for ccdId in wcsList:
            visit, ccd = self.decodeCcdExposureId(ccdId)
            if visit not in wcsDic and wcsList[ccdId] is not None:
                wcs = wcsList[ccdId]
                ccdDev = ccdSet[ccd]
                offset = afwGeom.Extent2D(ccdDev.getCenter().getPixels(ccdDev.getPixelSize()))
                wcsDic[visit] = wcs.copyAtShiftedPixelOrigin(offset)

        # meas_mosaic specific object list
        matchVec  = measMosaic.obsVecFromSourceGroup(allMat, wcsDic, ccdSet)
        sourceVec = []

        # Apply Jocabian correction calculated from wcs
        for m in matchVec:
            wcs = wcsList[m.iexp*200+m.ichip]
            m.mag -= 2.5*math.log10(measMosaic.computeJacobian(wcs, afwGeom.Point2D(m.x, m.y)))

        fluxFitOrder = self.config.fluxFitOrder
        absolute = True
        chebyshev = True
        commonFluxCorr = False
        solveCcdScale = True
        ffpSet = {}
        for visit in wcsDic:
            ffp = measMosaic.FluxFitParams(fluxFitOrder, absolute, chebyshev)
            u_max, v_max = self.getExtent(matchVec)
            ffp.u_max = (math.floor(u_max / 10.) + 1) * 10
            ffp.v_max = (math.floor(v_max / 10.) + 1) * 10
            ffpSet[visit] = ffp

        fexp = {}
        fchip = {}

        matchVec, sourceVec, wcsDic, ccdSet, fexp, fchip, ffpSet = measMosaic.fluxFit(absolute, commonFluxCorr, matchVec, len(matchVec), sourceVec, len(sourceVec), wcsDic, ccdSet, fexp, fchip, ffpSet, solveCcdScale)

        self.writeFcr(butler, list(matchLists.keys()), ccdSet, filterName,
                      fexp, fchip, ffpSet)

        return (1.0/fexp[list(fexp.keys())[0]])