def makeMeasurement(self, values):
        """Compute the number of non-updated DIAObjects.

        Parameters
        ----------
        values : sequence [`dict` [`str`, `int` or `None`]]
            A list where each element corresponds to a metadata object passed
            to `run`. Each `dict` has the following keys:

            ``"updatedObjects"``
                The number of DIAObjects updated for this image (`int` or
                `None`). May be `None` if the image was not
                successfully associated.
            ``"unassociatedObjects"``
                The number of DIAObjects not associated with a DiaSource in
                this image (`int` or `None`). May be `None` if the image was
                not successfully associated.

        Returns
        -------
        measurement : `lsst.verify.Measurement` or `None`
            The total number of unassociated objects.
        """
        nUpdated = 0
        nUnassociated = 0
        associated = False
        for value in values:
            if value["updatedObjects"] is not None \
                    and value["unassociatedObjects"] is not None:
                try:
                    nUpdated += value["updatedObjects"]
                    nUnassociated += value["unassociatedObjects"]
                except TypeError as e:
                    raise MetricComputationError(
                        "Corrupted value of numUpdatedDiaObjects "
                        "or numUnassociatedDiaObjects") from e
                associated = True

        if associated:
            if nUpdated <= 0 and nUnassociated <= 0:
                raise MetricComputationError(
                    "No pre-existing DIAObjects; can't compute updated fraction."
                )
            else:
                fraction = nUpdated / (nUpdated + nUnassociated)
                return Measurement(self.getOutputMetricName(self.config),
                                   fraction * u.dimensionless_unscaled)
        else:
            self.log.info("Nothing to do: no association results found.")
            return None
Example #2
0
    def makeMeasurement(self, values):
        """Compute the number of new DIAObjects.

        Parameters
        ----------
        values : `dict` [`str`, `int` or `None`]
            A `dict` representation of the metadata. Each `dict` has the
            following key:

            ``"newObjects"``
                The number of new objects created for this image (`int`
                or `None`). May be `None` if the image was not successfully
                associated.

        Returns
        -------
        measurement : `lsst.verify.Measurement` or `None`
            The total number of new objects.
        """
        if values["newObjects"] is not None:
            try:
                nNew = int(values["newObjects"])
            except (ValueError, TypeError) as e:
                raise MetricComputationError(
                    "Corrupted value of numNewDiaObjects") from e
            else:
                return Measurement(self.config.metricName, nNew * u.count)
        else:
            self.log.info("Nothing to do: no association results found.")
            return None
Example #3
0
    def makeMeasurement(self, values):
        """Compute the total number of SolarSystemObjects within a
        detectorVisit.

        Parameters
        ----------
        values : `dict` [`str`, `int` or `None`]
            A `dict` representation of the metadata. Each `dict` has the
            following key:

            ``"numTotalSolarSystemObjects"``
                The number of SolarSystemObjects within the observable detector
                area (`int` or `None`). May be `None` if solar system
                association was not attempted or the image was not
                successfully associated.

        Returns
        -------
        measurement : `lsst.verify.Measurement` or `None`
            The total number of Solar System objects.
        """
        if values["numTotalSolarSystemObjects"] is not None:
            try:
                nNew = int(values["numTotalSolarSystemObjects"])
            except (ValueError, TypeError) as e:
                raise MetricComputationError(
                    "Corrupted value of numTotalSolarSystemObjects") from e
            else:
                return Measurement(self.config.metricName, nNew * u.count)
        else:
            self.log.info("Nothing to do: no solar system results found.")
            return None
Example #4
0
    def run(self, matchedFakes, band):
        """Compute the completeness of recovered fakes within a magnitude
        range.

        Parameters
        ----------
        matchedFakes : `lsst.afw.table.SourceCatalog` or `None`
            Catalog of fakes that were inserted into the ccdExposure matched
            to their detected counterparts.

        Returns
        -------
        result : `lsst.pipe.base.Struct`
            A `~lsst.pipe.base.Struct` containing the following component:
            ``measurement``
                the ratio (`lsst.verify.Measurement` or `None`)
        """
        if matchedFakes is not None:
            magnitudes = matchedFakes[f"{self.config.magVar}" % band]
            magCutFakes = matchedFakes[np.logical_and(magnitudes > self.config.magMin,
                                                      magnitudes < self.config.magMax)]
            if len(magCutFakes) <= 0.0:
                raise MetricComputationError(
                    "No matched fakes catalog sources found; Completeness is "
                    "ill defined.")
            else:
                meas = Measurement(
                    self.config.metricName,
                    ((magCutFakes["diaSourceId"] > 0).sum() / len(magCutFakes))
                    * u.dimensionless_unscaled)
        else:
            self.log.info("Nothing to do: no matched catalog found.")
            meas = None
        return Struct(measurement=meas)
Example #5
0
    def run(self, sciSources, diaSources):
        """Compute the ratio of DIASources to science sources.

        Parameters
        ----------
        sciSources : `lsst.afw.table.SourceCatalog` or `None`
            A science source catalog, which may be empty or `None`.
        diaSources : `lsst.afw.table.SourceCatalog` or `None`
            A DIASource catalog for the same unit of processing
            as ``sciSources``.

        Returns
        -------
        result : `lsst.pipe.base.Struct`
            A `~lsst.pipe.base.Struct` containing the following component:

            ``measurement``
                the ratio (`lsst.verify.Measurement` or `None`)
        """
        if diaSources is not None and sciSources is not None:
            nSciSources = len(sciSources)
            nDiaSources = len(diaSources)
            metricName = self.config.metricName
            if nSciSources <= 0.0:
                raise MetricComputationError(
                    "No science sources found; ratio of DIASources to science sources ill-defined."
                )
            else:
                meas = Measurement(
                    metricName,
                    nDiaSources / nSciSources * u.dimensionless_unscaled)
        else:
            self.log.info("Nothing to do: no catalogs found.")
            meas = None
        return Struct(measurement=meas)
    def makeMeasurement(self, timings):
        """Compute a wall-clock measurement from metadata provided by
        `lsst.pipe.base.timeMethod`.

        Parameters
        ----------
        timings : sequence [`dict` [`str`, any]]
            A list where each element corresponds to a metadata object passed
            to `run`. Each `dict` has the following keys:

             ``"StartTime"``
                 The time the target method started (`float` or `None`).
             ``"EndTime"``
                 The time the target method ended (`float` or `None`).

        Returns
        -------
        measurement : `lsst.verify.Measurement` or `None`
            The the total running time of the target method across all
            elements of ``metadata``.

        Raises
        ------
        MetricComputationError
            Raised if any of the timing metadata are invalid.

        Notes
        -----
        This method does not return a measurement if no timing information was
        provided by any of the metadata.
        """
        # some timings indistinguishable from 0, so don't test totalTime > 0
        timingFound = False
        totalTime = 0.0
        for singleRun in timings:
            if singleRun["StartTime"] is not None \
                    or singleRun["EndTime"] is not None:
                try:
                    totalTime += singleRun["EndTime"] - singleRun["StartTime"]
                    timingFound = True
                except TypeError:
                    raise MetricComputationError("Invalid metadata")
            # If both are None, assume the method was not run that time

        if timingFound:
            meas = Measurement(self.getOutputMetricName(self.config),
                               totalTime * u.second)
            meas.notes['estimator'] = 'pipe.base.timeMethod'
            return meas
        else:
            self.log.info("Nothing to do: no timing information for %s found.",
                          self.config.target)
            return None
Example #7
0
    def run(self, sources):
        """Count the number of science sources created by deblending.

        Parameters
        ----------
        sources : `lsst.afw.table.SourceCatalog` or `None`
            A science source catalog, which may be empty or `None`.

        Returns
        -------
        result : `lsst.pipe.base.Struct`
            A `~lsst.pipe.base.Struct` containing the following component:

            ``measurement``
                the total number of science sources from deblending
                (`lsst.verify.Measurement`). If no deblending information is
                available in ``sources``, this is `None`.

        Raises
        ------
        MetricComputationError
            Raised if ``sources`` is missing mandatory keys for
            source catalogs.
        """
        if sources is None:
            self.log.info("Nothing to do: no catalogs found.")
            meas = None
        # Use deblend_parentNChild rather than detect_fromBlend because the
        # latter need not be defined in post-deblending catalogs.
        elif "deblend_parentNChild" not in sources.schema or "deblend_nChild" not in sources.schema:
            self.log.info("Nothing to do: no deblending performed.")
            meas = None
        else:
            try:
                children = ((sources["deblend_parentNChild"] > 1)  # deblend child
                            & (sources["deblend_nChild"] == 0)     # not deblended
                            )
                children = _filterSkySources(sources, children)
            except LookupError as e:
                # Probably "parent"; all other columns already checked
                raise MetricComputationError("Invalid input catalog") from e
            else:
                nChildren = np.count_nonzero(children)
                meas = Measurement(self.config.metricName, nChildren * u.dimensionless_unscaled)

        return Struct(measurement=meas)
Example #8
0
    def makeMeasurement(self, timings):
        """Compute a wall-clock measurement from metadata provided by
        `lsst.utils.timer.timeMethod`.

        Parameters
        ----------
        timings : `dict` [`str`, any]
            A representation of the metadata passed to `run`. The `dict` has
            the following keys:

             ``"StartTime"``
                 The time the target method started (`float` or `None`).
             ``"EndTime"``
                 The time the target method ended (`float` or `None`).
             ``"StartTimestamp"``, ``"EndTimestamp"``
                 The start and end timestamps, in an ISO 8601-compliant format
                 (`str` or `None`).

        Returns
        -------
        measurement : `lsst.verify.Measurement` or `None`
            The running time of the target method.

        Raises
        ------
        MetricComputationError
            Raised if the timing metadata are invalid.
        """
        if timings["StartTime"] is not None or timings["EndTime"] is not None:
            try:
                totalTime = timings["EndTime"] - timings["StartTime"]
            except TypeError:
                raise MetricComputationError("Invalid metadata")
            else:
                meas = Measurement(self.config.metricName,
                                   totalTime * u.second)
                meas.notes["estimator"] = "utils.timer.timeMethod"
                if timings["StartTimestamp"]:
                    meas.extras["start"] = Datum(timings["StartTimestamp"])
                if timings["EndTimestamp"]:
                    meas.extras["end"] = Datum(timings["EndTimestamp"])
                return meas
        else:
            self.log.info("Nothing to do: no timing information for %s found.",
                          self.config.target)
            return None
Example #9
0
    def makeMeasurement(self, values):
        """Compute the number of non-updated DIAObjects.

        AssociationTask reports each pre-existing DIAObject as either updated
        (associated with a new DIASource) or unassociated.

        Parameters
        ----------
        values : `dict` [`str`, `int` or `None`]
            A `dict` representation of the metadata. Each `dict` has the
            following keys:

            ``"updatedObjects"``
                The number of DIAObjects updated for this image (`int` or
                `None`). May be `None` if the image was not
                successfully associated.
            ``"unassociatedObjects"``
                The number of DIAObjects not associated with a DiaSource in
                this image (`int` or `None`). May be `None` if the image was
                not successfully associated.

        Returns
        -------
        measurement : `lsst.verify.Measurement` or `None`
            The total number of unassociated objects.
        """
        if values["updatedObjects"] is not None \
                and values["unassociatedObjects"] is not None:
            try:
                nUpdated = int(values["updatedObjects"])
                nUnassociated = int(values["unassociatedObjects"])
            except (ValueError, TypeError) as e:
                raise MetricComputationError(
                    "Corrupted value of numUpdatedDiaObjects "
                    "or numUnassociatedDiaObjects") from e
            else:
                if nUpdated <= 0 and nUnassociated <= 0:
                    return None  # No pre-existing DIAObjects; no fraction to compute
                else:
                    fraction = nUpdated / (nUpdated + nUnassociated)
                    return Measurement(self.config.metricName,
                                       fraction * u.dimensionless_unscaled)
        else:
            self.log.info("Nothing to do: no association results found.")
            return None
Example #10
0
    def run(self, sources):
        """Count the number of deblended science sources.

        Parameters
        ----------
        sources : `lsst.afw.table.SourceCatalog` or `None`
            A science source catalog, which may be empty or `None`.

        Returns
        -------
        result : `lsst.pipe.base.Struct`
            A `~lsst.pipe.base.Struct` containing the following component:

            ``measurement``
                the total number of deblended science sources
                (`lsst.verify.Measurement`). If no deblending information is
                available in ``sources``, this is `None`.

        Raises
        ------
        MetricComputationError
            Raised if ``sources`` is missing mandatory keys for
            source catalogs.
        """
        if sources is None:
            self.log.info("Nothing to do: no catalogs found.")
            meas = None
        elif "deblend_nChild" not in sources.schema:
            self.log.info("Nothing to do: no deblending performed.")
            meas = None
        else:
            try:
                deblended = ((sources["parent"] == 0)           # top-level source
                             & (sources["deblend_nChild"] > 0)  # deblended
                             )
                deblended = _filterSkySources(sources, deblended)
            except LookupError as e:
                # Probably "parent"; all other columns already checked
                raise MetricComputationError("Invalid input catalog") from e
            else:
                nDeblended = np.count_nonzero(deblended)
                meas = Measurement(self.config.metricName, nDeblended * u.dimensionless_unscaled)

        return Struct(measurement=meas)
Example #11
0
    def run(self, sciSources, diaSources):
        """Compute the ratio of DIASources to science sources.

        Parameters
        ----------
        sciSources : iterable of `lsst.afw.table.SourceCatalog`
            A collection of science source catalogs, one for each unit of
            processing to be incorporated into this metric. Its elements may
            be `None` to represent missing data.
        diaSources : iterable of `lsst.afw.table.SourceCatalog`
            A collection of difference imaging catalogs similar to
            ``sciSources``.

        Returns
        -------
        result : `lsst.pipe.base.Struct`
            A `~lsst.pipe.base.Struct` containing the following component:

            ``measurement``
                the ratio (`lsst.verify.Measurement` or `None`)
        """
        nSciSources = 0
        nDiaSources = 0
        inputData = False

        for sciCatalog, diaCatalog in zip(sciSources, diaSources):
            if diaCatalog is not None and sciCatalog is not None:
                nSciSources += len(sciCatalog)
                nDiaSources += len(diaCatalog)
                inputData = True

        if inputData:
            metricName = self.getOutputMetricName(self.config)
            if nSciSources <= 0.0:
                raise MetricComputationError(
                    "No science sources found; ratio of DIASources to science sources ill-defined.")
                meas = Measurement(metricName, 0.0 * u.dimensionless_unscaled)
            else:
                meas = Measurement(metricName, nDiaSources / nSciSources * u.dimensionless_unscaled)
        else:
            self.log.info("Nothing to do: no catalogs found.")
            meas = None
        return Struct(measurement=meas)
Example #12
0
    def makeMeasurement(self, memory):
        """Compute a maximum resident set size measurement from metadata
        provided by `lsst.utils.timer.timeMethod`.

        Parameters
        ----------
        memory : `dict` [`str`, any]
            A representation of the metadata passed to `run`. Each `dict` has
            the following keys:

             ``"EndMemory"``
                 The memory usage at the end of the method (`int` or `None`).
             ``"MetadataVersion"``
                 The version of the task metadata in which the value was stored
                 (`int` or `None`). `None` is assumed to be version 0.

        Returns
        -------
        measurement : `lsst.verify.Measurement` or `None`
            The maximum memory usage of the target method.

        Raises
        ------
        MetricComputationError
            Raised if the memory metadata are invalid.
        """
        if memory["EndMemory"] is not None:
            try:
                maxMemory = int(memory["EndMemory"])
                version = memory["MetadataVersion"] \
                    if memory["MetadataVersion"] else 0
            except (ValueError, TypeError) as e:
                raise MetricComputationError("Invalid metadata") from e
            else:
                meas = Measurement(self.config.metricName,
                                   self._addUnits(maxMemory, version))
                meas.notes['estimator'] = 'utils.timer.timeMethod'
                return meas
        else:
            self.log.info("Nothing to do: no memory information for %s found.",
                          self.config.target)
            return None
Example #13
0
    def makeMeasurement(self, dbHandle, outputDataId):
        """Compute the number of unassociated DIAObjects.

        Parameters
        ----------
        dbHandle : `lsst.dax.apdb.Apdb`
            A database instance.
        outputDataId : any data ID type
            The subset of the database to which this measurement applies.
            Must be empty, as the number of unassociated sources is
            ill-defined for subsets of the dataset.

        Returns
        -------
        measurement : `lsst.verify.Measurement`
            The total number of unassociated objects.

        Raises
        ------
        MetricComputationError
            Raised on any failure to query the database.
        ValueError
            Raised if outputDataId is not empty
        """
        # All data ID types define keys()
        if outputDataId.keys() - {'instrument'}:
            raise ValueError(
                "%s must not be associated with specific data IDs (gave %s)." %
                (self.config.metricName, outputDataId))

        try:
            nUnassociatedDiaObjects = dbHandle.countUnassociatedObjects()
        except Exception as e:
            raise MetricComputationError(
                "Could not get unassociated objects from database") from e

        meas = Measurement(self.config.metricName,
                           nUnassociatedDiaObjects * u.count)
        return meas
    def _extractMetadata(metadata, metadataKeys):
        """Read multiple keys from a metadata object.

        Parameters
        ----------
        metadata : `lsst.daf.base.PropertySet`
            A metadata object, assumed not `None`.
        metadataKeys : `dict` [`str`, `str`]
            Keys are arbitrary labels, values are metadata keys (or their
            substrings) in the format of
            `lsst.pipe.base.Task.getFullMetadata()`.

        Returns
        -------
        metadataValues : `dict` [`str`, any]
            Keys are the same as for ``metadataKeys``, values are the value of
            each metadata key, or `None` if no matching key was found.

        Raises
        ------
        lsst.verify.tasks.MetricComputationError
            Raised if any metadata key string has more than one match
            in ``metadata``.
        """
        data = {}
        for dataName, keyFragment in metadataKeys.items():
            matchingKeys = MetadataMetricTask._searchKeys(
                metadata, keyFragment)
            if len(matchingKeys) == 1:
                key, = matchingKeys
                data[dataName] = metadata.getScalar(key)
            elif not matchingKeys:
                data[dataName] = None
            else:
                error = "String %s matches multiple metadata keys: %s" \
                    % (keyFragment, matchingKeys)
                raise MetricComputationError(error)
        return data
    def makeMeasurement(self, values):
        """Compute the number of non-updated DIAObjects.

        Parameters
        ----------
        values : sequence [`dict` [`str`, `int` or `None`]]
            A list where each element corresponds to a metadata object passed
            to `run`. Each `dict` has the following key:

            ``"unassociatedObjects"``
                The number of DIAObjects not associated with a DiaSource in
                this image (`int` or `None`). May be `None` if the image was
                not successfully associated.

        Returns
        -------
        measurement : `lsst.verify.Measurement` or `None`
            The total number of unassociated objects.
        """
        nNew = 0
        associated = False
        for value in values:
            if value["unassociatedObjects"] is not None:
                try:
                    nNew += value["unassociatedObjects"]
                except TypeError as e:
                    raise MetricComputationError(
                        "Corrupted value of numUnassociatedDiaObjects") from e
                associated = True

        if associated:
            return Measurement(self.getOutputMetricName(self.config),
                               nNew * u.count)
        else:
            self.log.info("Nothing to do: no association results found.")
            return None
Example #16
0
 def run(self, *args, **kwargs):
     raise MetricComputationError()