예제 #1
0
    def coadd(self, cache, data):
        """!Construct coadd for a patch and measure

        Only slave nodes execute this method.

        Because only one argument may be passed, it is expected to
        contain multiple elements, which are:

        @param patchRef: data reference for patch
        @param selectDataList: List of SelectStruct for inputs
        """
        patchRef = getDataRef(cache.butler, data.patchId, cache.coaddType)
        selectDataList = data.selectDataList
        coadd = None
        with self.logOperation("coadding %s" % (patchRef.dataId,), catch=True):
            if self.config.doOverwriteCoadd or not patchRef.datasetExists(cache.coaddType):
                coaddResults = self.assembleCoadd.run(patchRef, selectDataList)
                if coaddResults is not None:
                    coadd = coaddResults.coaddExposure
            elif patchRef.datasetExists(cache.coaddType):
                self.log.info("%s: Reading coadd %s" % (NODE, patchRef.dataId))
                coadd = patchRef.get(cache.coaddType, immediate=True)

        if coadd is None:
            return

        with self.logOperation("detection on %s" % (patchRef.dataId,), catch=True):
            idFactory = self.detectCoaddSources.makeIdFactory(patchRef)
            # This includes background subtraction, so do it before writing the coadd
            detResults = self.detectCoaddSources.runDetection(coadd, idFactory)
            self.detectCoaddSources.write(coadd, detResults, patchRef)
예제 #2
0
    def run(self, tractPatchRefList, butler, selectIdList=[]):
        """!Determine which tracts are non-empty before processing

        @param tractPatchRefList: List of tracts and patches to include in the coaddition
        @param butler: butler reference object
        @param selectIdList: List of data Ids (i.e. visit, ccd) to consider when making the coadd
        @return list of references to sel.runTract function evaluation for each tractPatchRefList member
        """
        pool = Pool("tracts")
        pool.storeSet(butler=butler, skymap=butler.get(
            self.config.coaddName + "Coadd_skyMap"))
        tractIdList = []
        for patchRefList in tractPatchRefList:
            tractSet = set([patchRef.dataId["tract"]
                            for patchRef in patchRefList])
            assert len(tractSet) == 1
            tractIdList.append(tractSet.pop())

        selectDataList = [data for data in pool.mapNoBalance(self.readSelection, selectIdList) if
                          data is not None]
        nonEmptyList = pool.mapNoBalance(
            self.checkTract, tractIdList, selectDataList)
        tractPatchRefList = [patchRefList for patchRefList, nonEmpty in
                             zip(tractPatchRefList, nonEmptyList) if nonEmpty]
        self.log.info("Non-empty tracts (%d): %s" % (len(tractPatchRefList),
                                                     [patchRefList[0].dataId["tract"] for patchRefList in
                                                      tractPatchRefList]))

        # Install the dataRef in the selectDataList
        for data in selectDataList:
            data.dataRef = getDataRef(butler, data.dataId, "calexp")

        # Process the non-empty tracts
        return [self.runTract(patchRefList, butler, selectDataList) for patchRefList in tractPatchRefList]
    def runMeasureMerged(self, cache, dataId):
        """Run measurement on a patch for a single filter
        Only slave nodes execute this method.
        @param cache: Pool cache, with butler
        @param dataId: Data identifier for patch
        @return whether the patch requires reprocessing.
        """
        with self.logOperation("measurement on %s" % (dataId,)):
            dataRef = getDataRef(cache.butler, dataId, self.config.coaddName + "Coadd_calexp")
            reprocessing = False # Does this patch require reprocessing?
            if (not self.config.clobberMeasurements and
                dataRef.datasetExists(self.config.coaddName + "Coadd_meas")):
                if not self.config.reprocessing:
                    return False

                catalog = dataRef.get(self.config.coaddName + "Coadd_meas")
                bigFlag = catalog["deblend.parent-too-big"]
                numOldBig = bigFlag.sum()
                if numOldBig == 0:
                    self.log.info("No large footprints in %s" % (dataRef.dataId,))
                    return False
                numNewBig = sum((self.measureCoaddSources.deblend.isLargeFootprint(src.getFootprint()) for
                                 src in catalog[bigFlag]))
                if numNewBig == numOldBig:
                    self.log.info("All %d formerly large footprints continue to be large in %s" %
                                  (numOldBig, dataRef.dataId,))
                    return False
                self.log.info("Found %d large footprints to be reprocessed in %s" %
                              (numOldBig - numNewBig, dataRef.dataId))
                reprocessing = True

            self.measureCoaddSources.run(dataRef)
            return reprocessing
예제 #4
0
    def run(self, tractPatchRefList, butler, selectIdList=[]):
        """!Determine which tracts are non-empty before processing

        @param tractPatchRefList: List of tracts and patches to include in the coaddition
        @param butler: butler reference object
        @param selectIdList: List of data Ids (i.e. visit, ccd) to consider when making the coadd
        @return list of references to sel.runTract function evaluation for each tractPatchRefList member
        """
        pool = Pool("tracts")
        pool.storeSet(butler=butler, skymap=butler.get(self.config.coaddName + "Coadd_skyMap"))
        tractIdList = []
        for patchRefList in tractPatchRefList:
            tractSet = set([patchRef.dataId["tract"] for patchRef in patchRefList])
            assert len(tractSet) == 1
            tractIdList.append(tractSet.pop())

        selectDataList = [data for data in pool.mapNoBalance(self.readSelection, selectIdList) if
                          data is not None]
        nonEmptyList = pool.mapNoBalance(self.checkTract, tractIdList, selectDataList)
        tractPatchRefList = [patchRefList for patchRefList, nonEmpty in
                             zip(tractPatchRefList, nonEmptyList) if nonEmpty]
        self.log.info("Non-empty tracts (%d): %s" % (len(tractPatchRefList),
                                                     [patchRefList[0].dataId["tract"] for patchRefList in
                                                      tractPatchRefList]))

        # Install the dataRef in the selectDataList
        for data in selectDataList:
            data.dataRef = getDataRef(butler, data.dataId, "calexp")

        # Process the non-empty tracts
        return [self.runTract(patchRefList, butler, selectDataList) for patchRefList in tractPatchRefList]
예제 #5
0
    def coadd(self, cache, data):
        """!Construct coadd for a patch and measure

        Only slave nodes execute this method.

        Because only one argument may be passed, it is expected to
        contain multiple elements, which are:

        @param patchRef: data reference for patch
        @param selectDataList: List of SelectStruct for inputs
        """
        patchRef = getDataRef(cache.butler, data.patchId, cache.coaddType)
        selectDataList = data.selectDataList
        coadd = None
        with self.logOperation("coadding %s" % (patchRef.dataId, ),
                               catch=True):
            if self.config.doOverwriteCoadd or not patchRef.datasetExists(
                    cache.coaddType):
                coaddResults = self.assembleCoadd.run(patchRef, selectDataList)
                if coaddResults is not None:
                    coadd = coaddResults.coaddExposure
            elif patchRef.datasetExists(cache.coaddType):
                self.log.info("%s: Reading coadd %s" % (NODE, patchRef.dataId))
                coadd = patchRef.get(cache.coaddType, immediate=True)

        if coadd is None:
            return

        with self.logOperation("detection on %s" % (patchRef.dataId, ),
                               catch=True):
            idFactory = self.detectCoaddSources.makeIdFactory(patchRef)
            # This includes background subtraction, so do it before writing the
            # coadd
            detResults = self.detectCoaddSources.runDetection(coadd, idFactory)
            self.detectCoaddSources.write(coadd, detResults, patchRef)
 def runMergeDetections(self, cache, dataIdList):
     """Run detection merging on a patch
     Only slave nodes execute this method.
     @param cache: Pool cache, containing butler
     @param dataIdList: List of data identifiers for the patch in different filters
     """
     with self.logOperation("merge detections from %s" % (dataIdList,)):
         dataRefList = [getDataRef(cache.butler, dataId, self.config.coaddName + "Coadd") for
                        dataId in dataIdList]
         if (not self.config.clobberMergedDetections and
             dataRefList[0].datasetExists(self.config.coaddName + "Coadd_mergeDet")):
             return
         self.mergeCoaddDetections.run(dataRefList)
 def runForcedPhot(self, cache, dataId):
     """Run forced photometry on a patch for a single filter
     Only slave nodes execute this method.
     @cache: Pool cache, with butler
     @dataId: Data identifier for patch
     """
     with self.logOperation("forced photometry on %s" % (dataId,)):
         dataRef = getDataRef(cache.butler, dataId, self.config.coaddName + "Coadd")
         if (not self.config.clobberForcedPhotometry and
             not self.config.reprocessing and
             dataRef.datasetExists(self.config.coaddName + "Coadd_forced_src")):
             return
         self.forcedPhotCoadd.run(dataRef)
 def warp(self, cache, patchId, selectDataList):
     """Warp all images for a patch
     Only slave nodes execute this method.
     Because only one argument may be passed, it is expected to
     contain multiple elements, which are:
     @param patchRef: data reference for patch
     @param selectDataList: List of SelectStruct for inputs
     @return selectDataList with non-overlapping elements removed
     """
     patchRef = getDataRef(cache.butler, patchId, cache.coaddType)
     selectDataList = self.selectExposures(patchRef, selectDataList)
     with self.logOperation("warping %s" % (patchRef.dataId,), catch=True):
         self.makeCoaddTempExp.run(patchRef, selectDataList)
     return selectDataList
 def runMergeMeasurements(self, cache, dataIdList):
     """Run measurement merging on a patch
     Only slave nodes execute this method.
     @cache: Pool cache, containing butler
     @dataIdList: List of data identifiers for the patch in different filters
     """
     with self.logOperation("merge measurements from %s" % (dataIdList,)):
         dataRefList = [getDataRef(cache.butler, dataId, self.config.coaddName + "Coadd") for
                        dataId in dataIdList]
         if (not self.config.clobberMergedMeasurements and
             not self.config.reprocessing and
             dataRefList[0].datasetExists(self.config.coaddName + "Coadd_ref")):
             return
         self.mergeCoaddMeasurements.run(dataRefList)
예제 #10
0
    def runForcedPhot(self, cache, dataId):
        """!Run forced photometry on a patch for a single filter

        Only slave nodes execute this method.

        @param cache: Pool cache, with butler
        @param dataId: Data identifier for patch
        """
        with self.logOperation("forced photometry on %s" % (dataId, )):
            dataRef = getDataRef(cache.butler, dataId,
                                 self.config.coaddName + "Coadd_calexp")
            if (not self.config.clobberForcedPhotometry
                    and not self.config.reprocessing
                    and dataRef.datasetExists(self.config.coaddName +
                                              "Coadd_forced_src")):
                return
            self.forcedPhotCoadd.run(dataRef)
    def runMeasureMerged(self, cache, dataId):
        """!Run measurement on a patch for a single filter

        Only slave nodes execute this method.

        @param cache: Pool cache, with butler
        @param dataId: Data identifier for patch
        @return whether the patch requires reprocessing.
        """
        with self.logOperation("measurement on %s" % (dataId, )):
            dataRef = getDataRef(cache.butler, dataId,
                                 self.config.coaddName + "Coadd_calexp")
            reprocessing = False  # Does this patch require reprocessing?
            if ("measureCoaddSources" in self.reuse and dataRef.datasetExists(
                    self.config.coaddName + "Coadd_meas", write=True)):
                if not self.config.reprocessing:
                    self.log.info(
                        "Skipping measureCoaddSources for %s; output already exists"
                        % dataId)
                    return False

                catalog = dataRef.get(self.config.coaddName + "Coadd_meas")
                bigFlag = catalog["deblend.parent-too-big"]
                numOldBig = bigFlag.sum()
                if numOldBig == 0:
                    self.log.info("No large footprints in %s" %
                                  (dataRef.dataId, ))
                    return False
                numNewBig = sum(
                    (self.measureCoaddSources.deblend.isLargeFootprint(
                        src.getFootprint()) for src in catalog[bigFlag]))
                if numNewBig == numOldBig:
                    self.log.info(
                        "All %d formerly large footprints continue to be large in %s"
                        % (
                            numOldBig,
                            dataRef.dataId,
                        ))
                    return False
                self.log.info(
                    "Found %d large footprints to be reprocessed in %s" %
                    (numOldBig - numNewBig, dataRef.dataId))
                reprocessing = True

            self.measureCoaddSources.run(dataRef)
            return reprocessing
예제 #12
0
    def warp(self, cache, patchId, selectDataList):
        """!Warp all images for a patch

        Only slave nodes execute this method.

        Because only one argument may be passed, it is expected to
        contain multiple elements, which are:

        @param patchRef: data reference for patch
        @param selectDataList: List of SelectStruct for inputs
        @return selectDataList with non-overlapping elements removed
        """
        patchRef = getDataRef(cache.butler, patchId, cache.coaddType)
        selectDataList = self.selectExposures(patchRef, selectDataList)
        with self.logOperation("warping %s" % (patchRef.dataId, ), catch=True):
            self.makeCoaddTempExp.runDataRef(patchRef, selectDataList)
        return selectDataList
예제 #13
0
    def processPool(self, cache, dataId):
        """Process focus CCD under pool

        This is a mediator for the 'process' method when running
        under the Pool.

        Only slave nodes run this method.

        @param cache: Pool cache
        @param dataId: Data identifier for CCD
        @return Processing results (from 'process' method)
        """
        try:
            return self.process(getDataRef(cache.butler, dataId))
        except Exception as e:
            self.log.warn("Failed to process %s (%s: %s):\n%s" %
                          (dataId, e.__class__.__name__, e, traceback.format_exc()))
            return None
예제 #14
0
    def runDataRef(self, patchRefList):
        """!Run multiband processing on coadds

        Only the master node runs this method.

        No real MPI communication (scatter/gather) takes place: all I/O goes
        through the disk. We want the intermediate stages on disk, and the
        component Tasks are implemented around this, so we just follow suit.

        @param patchRefList:  Data references to run measurement
        """
        print(len(patchRefList))
        for patchRef in patchRefList:
            if patchRef:
                butler = patchRef.getButler()
                break
        else:
            raise RuntimeError("No valid patches")
        pool = Pool("all")
        pool.cacheClear()
        pool.storeSet(butler=butler)

        # Group by patch
        patches = {}
        tract = None
        for patchRef in patchRefList:
            dataId = patchRef.dataId
            if tract is None:
                tract = dataId["tract"]
            else:
                assert tract == dataId["tract"]

            patch = dataId["patch"]
            if patch not in patches:
                patches[patch] = []
            patches[patch].append(dataId)

        print(patches.values())
        dataRefList = [
            getDataRef(cache.butler, dataId,
                       self.config.coaddName + "Coadd_calexp")
            for dataId in patches.values()
        ]
        pool.map(self.runAssociation, dataRefList)
예제 #15
0
    def runMergeDetections(self, cache, dataIdList):
        """!Run detection merging on a patch

        Only slave nodes execute this method.

        @param cache: Pool cache, containing butler
        @param dataIdList: List of data identifiers for the patch in different filters
        """
        with self.logOperation("merge detections from %s" % (dataIdList, )):
            dataRefList = [
                getDataRef(cache.butler, dataId,
                           self.config.coaddName + "Coadd_calexp")
                for dataId in dataIdList
            ]
            if (not self.config.clobberMergedDetections
                    and dataRefList[0].datasetExists(self.config.coaddName +
                                                     "Coadd_mergeDet")):
                return
            self.mergeCoaddDetections.run(dataRefList)
예제 #16
0
    def coadd(self, cache, data):
        """!Construct coadd for a patch and measure

        Only slave nodes execute this method.

        Because only one argument may be passed, it is expected to
        contain multiple elements, which are:

        @param patchRef: data reference for patch
        @param selectDataList: List of SelectStruct for inputs
        """
        patchRef = getDataRef(cache.butler, data.patchId, cache.coaddType)
        selectDataList = data.selectDataList
        coadd = None
        with self.logOperation("coadding %s" % (patchRef.dataId, ),
                               catch=True):
            if self.config.doOverwriteCoadd or not patchRef.datasetExists(
                    cache.coaddType):
                coaddResults = self.assembleCoadd.run(patchRef, selectDataList)
                if coaddResults is not None:
                    coadd = coaddResults.coaddExposure
            elif patchRef.datasetExists(cache.coaddType):
                self.log.info("%s: Reading coadd %s" % (NODE, patchRef.dataId))
                coadd = patchRef.get(cache.coaddType, immediate=True)

        if coadd is None:
            return

        # The section of code below determines if the detection task should be
        # run. If detection is run, then the products are written out as
        # deepCoadd_calexp. If detection is not run, then the outputs of the
        # assemble task are written out as deepCoadd.
        if self.config.doDetection:
            with self.logOperation("detection on {}".format(patchRef.dataId),
                                   catch=True):
                idFactory = self.detectCoaddSources.makeIdFactory(patchRef)
                # This includes background subtraction, so do it before writing
                # the coadd
                detResults = self.detectCoaddSources.runDetection(
                    coadd, idFactory)
                self.detectCoaddSources.write(coadd, detResults, patchRef)
        else:
            patchRef.put(coadd, self.assembleCoadd.config.coaddName + "Coadd")
 def readSelection(self, cache, selectId):
     """Read Wcs of selected inputs
     This method only runs on slave nodes.
     This method is similar to SelectDataIdContainer.makeDataRefList,
     creating a Struct like a SelectStruct, except with a dataId instead
     of a dataRef (to ease MPI).
     @param cache: Pool cache
     @param selectId: Data identifier for selected input
     @return a SelectStruct with a dataId instead of dataRef
     """
     try:
         ref = getDataRef(cache.butler, selectId, "calexp")
         self.log.info("Reading Wcs from %s" % (selectId,))
         md = ref.get("calexp_md", immediate=True)
         wcs = afwImage.makeWcs(md)
         data = Struct(dataId=selectId, wcs=wcs, dims=(md.get("NAXIS1"), md.get("NAXIS2")))
     except FitsError as e:
         self.log.warn("Unable to construct Wcs from %s" % (selectId,))
         return None
     return data
예제 #18
0
    def runForcedPhot(self, cache, dataId):
        """!Run forced photometry on a patch for a single filter

        Only slave nodes execute this method.

        @param cache: Pool cache, with butler
        @param dataId: Data identifier for patch
        """
        with self.logOperation("forced photometry on %s" % (dataId, )):
            dataRef = getDataRef(cache.butler, dataId,
                                 self.coaddType + "Coadd_calexp")
            if ("forcedPhotCoadd" in self.reuse
                    and not self.config.reprocessing and dataRef.datasetExists(
                        self.config.coaddName + "Coadd_forced_src",
                        write=True)):
                self.log.info(
                    "Skipping forcedPhotCoadd for %s; output already exists" %
                    dataId)
                return
            self.forcedPhotCoadd.runDataRef(dataRef)
예제 #19
0
    def readSelection(self, cache, selectId):
        """!Read Wcs of selected inputs

        This method only runs on slave nodes.
        This method is similar to SelectDataIdContainer.makeDataRefList,
        creating a Struct like a SelectStruct, except with a dataId instead
        of a dataRef (to ease MPI).

        @param cache: Pool cache
        @param selectId: Data identifier for selected input
        @return a SelectStruct with a dataId instead of dataRef
        """
        try:
            ref = getDataRef(cache.butler, selectId, "calexp")
            self.log.info("Reading Wcs from %s" % (selectId,))
            md = ref.get("calexp_md", immediate=True)
            wcs = afwGeom.makeSkyWcs(md)
            data = Struct(dataId=selectId, wcs=wcs, bbox=afwImage.bboxFromMetadata(md))
        except FitsError:
            self.log.warn("Unable to construct Wcs from %s" % (selectId,))
            return None
        return data
예제 #20
0
    def runMergeDetections(self, cache, dataIdList):
        """!Run detection merging on a patch

        Only slave nodes execute this method.

        @param cache: Pool cache, containing butler
        @param dataIdList: List of data identifiers for the patch in different filters
        """
        with self.logOperation("merge detections from %s" % (dataIdList, )):
            dataRefList = [
                getDataRef(cache.butler, dataId,
                           self.coaddType + "Coadd_calexp")
                for dataId in dataIdList
            ]
            if ("mergeCoaddDetections" in self.reuse
                    and dataRefList[0].datasetExists(
                        self.config.coaddName + "Coadd_mergeDet", write=True)):
                self.log.info(
                    "Skipping mergeCoaddDetections for %s; output already exists."
                    % dataRefList[0].dataId)
                return
            self.mergeCoaddDetections.runDataRef(dataRefList)
    def combine(self, cache, struct, outputId):
        """!Combine multiple exposures of a particular CCD and write the output

        Only the slave nodes execute this method.

        This is a helper routine, containing just the start of what's needed to
        actually combine the inputs as an aid to subclasses. Note that
        thismethod does not return what the ``scatterCombine`` method expects;
        the user should call this method, and then return the combined exposure.

        Parameters
        ----------
        cache : `lsst.pipe.base.Struct`
            Process pool cache. Contains a data butler (``butler``).
        struct : `lsst.pipe.base.Struct`
            Parameters for the combination, which has the following components:

            - ``ccdName`` (`tuple`): Name tuple for CCD.
            - ``ccdIdList`` (`list`): List of data identifiers for combination.
            - ``scales``: Unused by this implementation.

        Returns
        -------
        dataRefList : `dict`
            Data identifier for combined image (exposure part only).
        outputId : `dict`
            Fully-qualified data identifier for the output.
        """
        # Check if we need to look up any keys that aren't in the output dataId
        fullOutputId = {k: struct.ccdName[i] for i, k in enumerate(self.config.ccdKeys)}
        self.addMissingKeys(fullOutputId, cache.butler)
        fullOutputId.update(outputId)  # must be after the call to queryMetadata

        dataRefList = [getDataRef(cache.butler, dataId) if dataId is not None else None for
                       dataId in struct.ccdIdList]

        self.log.info("Combining %d inputs %s on %s" % (len(dataRefList), fullOutputId, NODE))
        return Struct(dataRefList=dataRefList, outputId=fullOutputId)
예제 #22
0
    def runMeasurements(self, cache, dataId):
        """Run measurement on a patch for a single filter

        Only slave nodes execute this method.

        Parameters
        ----------
        cache: Pool cache
            Pool cache, with butler
        dataId: dataRef
            Data identifier for patch
        """
        with self.logOperation("measurements on %s" % (dataId, )):
            dataRef = getDataRef(cache.butler, dataId,
                                 self.coaddType + "Coadd_calexp")
            if ("measureCoaddSources" in self.reuse
                    and not self.config.reprocessing and dataRef.datasetExists(
                        self.config.coaddName + "Coadd_meas", write=True)):
                self.log.info(
                    "Skipping measuretCoaddSources for %s; output already exists"
                    % dataId)
                return
            self.measureCoaddSources.runDataRef(dataRef)
예제 #23
0
    def runCombine(self, cache, dataIdList):
        """! Run combination on a patch

        For all of the visits that overlap this patch in the band create a catalog with
        mjd, id, filter and values in the keepFields config parameter.

        It will write a file as a pandas DataFrame to the appropriate deepDiff directory,
        but the products are not currently declared in the mapper file.
        """

        dataRefList = [
            getDataRef(cache.butler, dataId,
                       self.config.coaddName + "Coadd_calexp")
            for dataId in dataIdList
        ]

        try:
            diaObject = dataRefList[0].get(
                f"{self.config.coaddName}Diff_diaObject")
            uri = dataRefList[0].getUri(
                f"{self.config.coaddName}Diff_diaObject")
        except Exception:
            self.log.info('Cannot read diaObject for %s' %
                          (dataRefList[0].dataId))
            return

        # Use a dictionary of arrays to store data.  Probably something more efficient
        data = {}
        data['id'] = []
        data['mjd'] = []
        data['filter'] = []
        for key, value in self.config.keepFields.items():
            data[key] = []

        for dataRef in dataRefList:

            try:
                calexp = dataRef.get(f"{self.config.coaddName}Coadd_calexp")
            except Exception:
                self.log.info('Cannot read data for %s' % (dataRef.dataId))
                continue

            visitCatalog = calexp.getInfo().getCoaddInputs().ccds

            for visitRec in visitCatalog:

                visit = int(visitRec.get('visit'))
                ccd = int(visitRec.get('ccd'))
                dataId = {"visit": visit, self.config.ccdKey: ccd}

                try:
                    src = cache.butler.get(
                        f"{self.config.coaddName}Diff_forced_dia_src", dataId)
                    diff = cache.butler.get(
                        f"{self.config.coaddName}Diff_differenceExp", dataId)
                except Exception as e:
                    self.log.debug('Cannot read data for %d %d. skipping %s',
                                   visit, ccd, e)
                    continue

                mjd = diff.getInfo().getVisitInfo().getDate().get(
                    system=DateTime.MJD)
                band = diff.getInfo().getFilter().getName()
                self.log.info('Reading diff forced src with %d sources %s',
                              len(src), dataId)

                matches = np.in1d(src['dia_object_id'],
                                  diaObject['id'],
                                  assume_unique=True)

                data['id'].extend(src['dia_object_id'][matches])
                data['mjd'].extend([mjd] * np.sum(matches))
                data['filter'].extend([band] * np.sum(matches))
                for key, value in self.config.keepFields.items():
                    data[key].extend(src[value][matches])

        tract = dataRefList[0].dataId['tract']
        patch = dataRefList[0].dataId['patch']
        path = os.path.dirname(uri)
        df = pd.DataFrame(data)
        getattr(df, "to_" + self.config.storage)(
            f'{path}/diaCombined_{tract}_{patch}.{self.config.storage}')
예제 #24
0
    def runAssociation(self, cache, dataIdList, selectDataList):
        """! Run association on a patch
        For all of the visits that overlap this patch in the band create a DIAObject
        catalog.  Only the objects in the non-overlaping area of the tract and patch
        are included.
        """
        dataRefList = [
            getDataRef(cache.butler, dataId,
                       self.config.coaddName + "Coadd_calexp")
            for dataId in dataIdList
        ]

        # We need the WCS for the patch, so we can use the first entry in the dataIdList
        dataRef = dataRefList[0]
        tract = dataRef.dataId['tract']
        skyInfo = getSkyInfo(coaddName=self.config.coaddName, patchRef=dataRef)
        skyMap = skyInfo.skyMap
        try:
            calexp = dataRef.get(f"{self.config.coaddName}Coadd_calexp")
        except Exception:
            self.log.info('Cannot read coadd data for %s' % (dataRef.dataId))
            return

        coaddWcs = calexp.getWcs()
        innerPatchBox = geom.Box2D(skyInfo.patchInfo.getInnerBBox())

        expBits = dataRef.get("deepMergedCoaddId_bits")
        expId = int(dataRef.get("deepMergedCoaddId"))
        idFactory = afwTable.IdFactory.makeSource(expId, 64 - expBits)

        if len(selectDataList) == 0:
            differenceImages = self.catalogGenerator
        else:
            differenceImages = self.idListGenerator

        initializeSelector = False
        for diffIm in differenceImages(cache, dataRefList, selectDataList):

            if initializeSelector is False:
                self.associator.initialize(diffIm.src.schema, idFactory)
                initializeSelector = True

            if len(diffIm.src) == 0:
                continue

            srcWcs = diffIm.exp.getWcs()
            isInside = np.array([
                innerPatchBox.contains(
                    coaddWcs.skyToPixel(srcWcs.pixelToSky(a.getCentroid())))
                for a in diffIm.src
            ],
                                dtype=bool)

            isGood = np.array([
                rec.getFootprint().contains(geom.Point2I(rec.getCentroid()))
                for rec in diffIm.src
            ], )

            isInnerTract = np.array([
                skyMap.findTract(srcWcs.pixelToSky(
                    a.getCentroid())).getId() == tract for a in diffIm.src
            ])

            mask = (isInside) & (isGood) & (isInnerTract)

            src = diffIm.src[mask]
            if len(src) == 0:
                continue

            self.log.info(
                'Reading difference image %d %d, %s with %d possible sources' %
                (diffIm.visit, diffIm.ccd, diffIm.filter, len(src)))

            footprints = []
            region = calexp.getBBox(afwImage.PARENT)
            for ii, rec in enumerate(src):
                # transformations on large footprints can take a long time
                # We truncate the footprint since we will rarely be interested
                # in such large footprints
                if rec.getFootprint().getArea() > self.config.maxFootprintArea:
                    spans = afwGeom.SpanSet.fromShape(
                        self.config.defaultFootprintRadius,
                        afwGeom.Stencil.CIRCLE,
                        geom.Point2I(rec.getCentroid()))
                    foot = afwDet.Footprint(spans)
                    foot.addPeak(int(rec.getX()), int(rec.getY()), 1)
                else:
                    foot = rec.getFootprint()
                footprints.append(foot.transform(srcWcs, coaddWcs, region))

            self.associator.addCatalog(src, diffIm.filter, diffIm.visit,
                                       diffIm.ccd, diffIm.calib, footprints)

        result = self.associator.finalize(idFactory)

        if len(dataRefList) > 0 and result is not None:
            dataRefList[0].put(result,
                               self.config.coaddName + 'Diff_diaObject')
            self.log.info('Total objects found %d' % len(result))

            idCatalog = self.associator.getObjectIds()
            dataRefList[0].put(idCatalog,
                               self.config.coaddName + 'Diff_diaObjectId')
예제 #25
0
파일: analysis.py 프로젝트: lsst-dm/donut
    def runDataRef(self, expRef, butler):
        """Process a single exposure, with scatter-gather-scatter using MPI.
        """
        dataIdList = dict([(ccdRef.get("ccdExposureId"), ccdRef.dataId)
                           for ccdRef in expRef.subItems("ccd")
                           if ccdRef.datasetExists("donutSrc")])
        dataIdList = collections.OrderedDict(sorted(dataIdList.items()))
        visit = expRef.dataId['visit']
        self.log.info("Running on visit {}".format(visit))

        donutConfig = getDonutConfig(expRef)
        x = []
        y = []
        vals = collections.OrderedDict()
        jmax = donutConfig.jmaxs[-1]
        for k in ['r0'] + ['z{}'.format(z) for z in range(4, jmax + 1)]:
            vals[k] = []

        for dataId in dataIdList.values():
            self.log.info("Loading ccd {}".format(dataId['ccd']))
            sensorRef = getDataRef(butler, dataId)
            donutSrc = sensorRef.get("donutSrc")
            icSrc = sensorRef.get("icSrc")
            icExp = sensorRef.get("icExp")
            x.extend([
                icSrc.find(donut.getId())['base_FPPosition_x']
                for donut in donutSrc
            ])
            y.extend([
                icSrc.find(donut.getId())['base_FPPosition_y']
                for donut in donutSrc
            ])
            for k, v in iteritems(vals):
                v.extend(donut['zfit_jmax{}_{}'.format(jmax, k)]
                         for donut in donutSrc)

        plotDir = getPlotDir(sensorRef.getButler(), "donutSrc",
                             first(dataIdList.values()))
        outfn = os.path.join(plotDir, "donutFitParam-{:07d}.pdf".format(visit))
        with PdfPages(outfn) as pdf:
            for k, v in iteritems(vals):
                self.log.info("Plotting {}".format(k))
                if k.startswith('z') and k != 'z4':
                    cmap = 'Spectral_r'
                    vmin = -max(np.abs(v))
                    vmax = max(np.abs(v))
                else:
                    cmap = 'viridis'
                    vmin = min(v)
                    vmax = max(v)
                fig, axes = subplots(1, 1, figsize=(8, 6.2))
                scatPlot = axes.scatter(x,
                                        y,
                                        c=v,
                                        s=15,
                                        linewidths=0.5,
                                        cmap=cmap,
                                        vmin=vmin,
                                        vmax=vmax)
                axes.set_title(k)
                plotCameraOutline(axes, expRef.get("camera"))
                fig.tight_layout()
                fig.colorbar(scatPlot)
                pdf.savefig(fig, dpi=100)
예제 #26
0
파일: analysis.py 프로젝트: lsst-dm/donut
    def runDataRef(self, expRef, butler):
        """Make a stamp analysis image for a single exposure, binned by CCD.
        """
        dataIdList = dict([(ccdRef.get("ccdExposureId"), ccdRef.dataId)
                           for ccdRef in expRef.subItems("ccd")
                           if ccdRef.datasetExists("donutSrc")])
        dataIdList = collections.OrderedDict(sorted(dataIdList.items()))
        visit = expRef.dataId['visit']
        self.log.info("Running on visit {}".format(visit))
        camera = expRef.get("camera")

        donutConfig = getDonutConfig(expRef)

        plotDir = getPlotDir(expRef.getButler(), "donutSrc",
                             first(dataIdList.values()))

        # Collect images
        images = {}
        models = {}
        resids = {}
        for dataId in dataIdList.values():
            ccd = dataId['ccd']
            self.log.info("Loading ccd {}".format(ccd))
            sensorRef = getDataRef(butler, dataId)
            icExp = sensorRef.get("icExp")
            donutSrc = sensorRef.get("donutSrc")
            icSrc = sensorRef.get("icSrc")

            if len(donutSrc) == 0:
                continue
            s2n = []
            for donut in donutSrc:
                icRec = icSrc.find(donut.getId())
                s2n.append(icRec['base_CircularApertureFlux_25_0_flux'] /
                           icRec['base_CircularApertureFlux_25_0_fluxSigma'])

            idx = int(np.argsort(s2n)[-1])
            donutRecord = donutSrc[idx]
            icRecord = icSrc.find(donutRecord.getId())
            data = getDonut(icRecord, icExp, donutConfig)
            model = getModel(donutRecord, icRecord, icExp, donutConfig, camera)
            resid = data - model
            images[ccd] = data
            models[ccd] = model
            resids[ccd] = resid

        # Make plots
        self.makePlot(images,
                      os.path.join(
                          plotDir,
                          "donutStampCcdData-{:07d}.pdf".format(visit),
                      ),
                      camera,
                      dataIdList,
                      cmap='viridis')

        self.makePlot(models,
                      os.path.join(
                          plotDir,
                          "donutStampCcdModel-{:07d}.pdf".format(visit),
                      ),
                      camera,
                      dataIdList,
                      cmap='viridis')

        self.makePlot(resids,
                      os.path.join(
                          plotDir,
                          "donutStampCcdResid-{:07d}.pdf".format(visit),
                      ),
                      camera,
                      dataIdList,
                      cmap='Spectral_r')
예제 #27
0
파일: analysis.py 프로젝트: lsst-dm/donut
    def runDataRef(self, expRef, butler):
        """Make a stamp analysis image for a single exposure
        """
        dataIdList = dict([(ccdRef.get("ccdExposureId"), ccdRef.dataId)
                           for ccdRef in expRef.subItems("ccd")
                           if ccdRef.datasetExists("donutSrc")])
        dataIdList = collections.OrderedDict(sorted(dataIdList.items()))
        visit = expRef.dataId['visit']
        self.log.info("Running on visit {}".format(visit))
        camera = expRef.get("camera")

        donutConfig = getDonutConfig(expRef)

        plotDir = getPlotDir(expRef.getButler(), "donutSrc",
                             first(dataIdList.values()))

        xs = []
        ys = []
        s2ns = []
        sensorRefs = []
        ids = []
        for dataId in dataIdList.values():
            ccd = dataId['ccd']
            self.log.info("Loading ccd {}".format(ccd))
            sensorRef = getDataRef(butler, dataId)
            donutSrc = sensorRef.get("donutSrc")
            icSrc = sensorRef.get("icSrc")
            if len(donutSrc) == 0:
                continue
            for donut in donutSrc:
                donutId = donut.getId()
                icRec = icSrc.find(donutId)
                s2ns.append(icRec['base_CircularApertureFlux_25_0_flux'] /
                            icRec['base_CircularApertureFlux_25_0_fluxSigma'])
                xs.append(icRec['base_FPPosition_x'])
                ys.append(icRec['base_FPPosition_y'])
                sensorRefs.append(sensorRef)
                ids.append(donutId)

        bds = camera.getFpBBox()
        xbds = np.linspace(bds.getMinX(), bds.getMaxX(),
                           self.config.nStamp + 1)
        ybds = np.linspace(bds.getMinY(), bds.getMaxY(),
                           self.config.nStamp + 1)

        # Find brightest donut in each grid cell and retrieve that one.
        s2ns = np.array(s2ns)
        xs = np.array(xs)
        ys = np.array(ys)
        imageDict = {}
        modelDict = {}
        residDict = {}
        for ix, (xmin, xmax) in enumerate(zip(xbds[:-1], xbds[1:])):
            for iy, (ymin, ymax) in enumerate(zip(ybds[:-1], ybds[1:])):
                w = (xs > xmin) & (xs <= xmax) & (ys > ymin) & (ys <= ymax)
                if not np.any(w):
                    continue
                widx = int(np.argsort(s2ns[w])[-1])
                idx = w.nonzero()[0][widx]
                sensorRef = sensorRefs[idx]
                donutId = ids[idx]
                icExp = sensorRef.get("icExp")
                icSrc = sensorRef.get("icSrc")
                donutSrc = sensorRef.get("donutSrc")
                icRec = icSrc.find(donutId)
                donut = donutSrc.find(donutId)

                data = getDonut(icRec, icExp, donutConfig)
                model = getModel(donut, icRec, icExp, donutConfig, camera)
                imageDict[(ix, iy)] = data
                modelDict[(ix, iy)] = model
                residDict[(ix, iy)] = data - model

        # Make plots
        self.makePlot(imageDict,
                      os.path.join(plotDir,
                                   "donutStampData-{:07d}.pdf".format(visit)),
                      xbds,
                      ybds,
                      camera,
                      cmap='viridis')

        self.makePlot(modelDict,
                      os.path.join(plotDir,
                                   "donutStampModel-{:07d}.pdf".format(visit)),
                      xbds,
                      ybds,
                      camera,
                      cmap='viridis')

        self.makePlot(residDict,
                      os.path.join(plotDir,
                                   "donutStampResid-{:07d}.pdf".format(visit)),
                      xbds,
                      ybds,
                      camera,
                      cmap='Spectral_r')
예제 #28
0
    def coadd(self, cache, data):
        """!Construct coadd for a patch and measure

        Only slave nodes execute this method.

        Because only one argument may be passed, it is expected to
        contain multiple elements, which are:

        @param patchRef: data reference for patch
        @param selectDataList: List of SelectStruct for inputs
        """
        patchRef = getDataRef(cache.butler, data.patchId, cache.coaddType)
        selectDataList = data.selectDataList
        coadd = None

        # We skip the assembleCoadd step if either the *Coadd dataset exists
        # or we aren't configured to write it, we're supposed to reuse
        # detectCoaddSources outputs too, and those outputs already exist.
        canSkipDetection = (
            "detectCoaddSources" in self.reuse and patchRef.datasetExists(
                self.detectCoaddSources.config.coaddName + "Coadd_det",
                write=True))
        if "assembleCoadd" in self.reuse:
            if patchRef.datasetExists(cache.coaddType, write=True):
                self.log.info(
                    "%s: Skipping assembleCoadd for %s; outputs already exist."
                    % (NODE, patchRef.dataId))
                coadd = patchRef.get(cache.coaddType, immediate=True)
            elif not self.config.assembleCoadd.doWrite and self.config.doDetection and canSkipDetection:
                self.log.info(
                    "%s: Skipping assembleCoadd and detectCoaddSources for %s; outputs already exist."
                    % (NODE, patchRef.dataId))
                return
        if coadd is None:
            with self.logOperation("coadding %s" % (patchRef.dataId, ),
                                   catch=True):
                coaddResults = self.assembleCoadd.runDataRef(
                    patchRef, selectDataList)
                if coaddResults is not None:
                    coadd = coaddResults.coaddExposure
                    canSkipDetection = False  # can't skip it because coadd may have changed
        if coadd is None:
            return

        # The section of code below determines if the detection task should be
        # run. If detection is run, then the products are written out as
        # deepCoadd_calexp. If detection is not run, then the outputs of the
        # assemble task are written out as deepCoadd.
        if self.config.doDetection:
            if canSkipDetection:
                self.log.info(
                    "%s: Skipping detectCoaddSources for %s; outputs already exist."
                    % (NODE, patchRef.dataId))
                return
            with self.logOperation("detection on {}".format(patchRef.dataId),
                                   catch=True):
                idFactory = self.detectCoaddSources.makeIdFactory(patchRef)
                expId = int(patchRef.get(self.config.coaddName + "CoaddId"))
                # This includes background subtraction, so do it before writing
                # the coadd
                detResults = self.detectCoaddSources.run(coadd,
                                                         idFactory,
                                                         expId=expId)
                self.detectCoaddSources.write(detResults, patchRef)
        else:
            if self.config.hasFakes:
                patchRef.put(
                    coadd,
                    "fakes_" + self.assembleCoadd.config.coaddName + "Coadd")
            else:
                patchRef.put(coadd,
                             self.assembleCoadd.config.coaddName + "Coadd")
예제 #29
0
    def runDeblendMerged(self, cache, dataIdList):
        """Run the deblender on a list of dataId's

        Only slave nodes execute this method.

        Parameters
        ----------
        cache: Pool cache
            Pool cache with butler.
        dataIdList: list
            Data identifier for patch in each band.

        Returns
        -------
        result: bool
            whether the patch requires reprocessing.
        """
        with self.logOperation("deblending %s" % (dataIdList, )):
            dataRefList = [
                getDataRef(cache.butler, dataId,
                           self.coaddType + "Coadd_calexp")
                for dataId in dataIdList
            ]
            reprocessing = False  # Does this patch require reprocessing?
            if ("deblendCoaddSources" in self.reuse and all([
                    dataRef.datasetExists(self.config.coaddName + "Coadd_" +
                                          self.measurementInput,
                                          write=True)
                    for dataRef in dataRefList
            ])):
                if not self.config.reprocessing:
                    self.log.info(
                        "Skipping deblendCoaddSources for %s; output already exists"
                        % dataIdList)
                    return False

                # Footprints are the same every band, therefore we can check just one
                catalog = dataRefList[0].get(self.config.coaddName + "Coadd_" +
                                             self.measurementInput)
                bigFlag = catalog["deblend_parentTooBig"]
                # Footprints marked too large by the previous deblender run
                numOldBig = bigFlag.sum()
                if numOldBig == 0:
                    self.log.info("No large footprints in %s" %
                                  (dataRefList[0].dataId))
                    return False

                # This if-statement can be removed after DM-15662
                if self.config.deblendCoaddSources.simultaneous:
                    deblender = self.deblendCoaddSources.multiBandDeblend
                else:
                    deblender = self.deblendCoaddSources.singleBandDeblend

                # isLargeFootprint() can potentially return False for a source that is marked
                # too big in the catalog, because of "new"/different deblender configs.
                # numNewBig is the number of footprints that *will* be too big if reprocessed
                numNewBig = sum((deblender.isLargeFootprint(src.getFootprint())
                                 for src in catalog[bigFlag]))
                if numNewBig == numOldBig:
                    self.log.info(
                        "All %d formerly large footprints continue to be large in %s"
                        % (
                            numOldBig,
                            dataRefList[0].dataId,
                        ))
                    return False
                self.log.info(
                    "Found %d large footprints to be reprocessed in %s" %
                    (numOldBig - numNewBig,
                     [dataRef.dataId for dataRef in dataRefList]))
                reprocessing = True

            self.deblendCoaddSources.runDataRef(dataRefList)
            return reprocessing