Coverage for python/lsst/ap/association/diaCalculationPlugins.py : 48%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# This file is part of ap_association. # # Developed for the LSST Data Management System. # This product includes software developed by the LSST Project # (https://www.lsst.org). # See the COPYRIGHT file at the top-level directory of this distribution # for details of code ownership. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>.
Output columns must be as defined in the schema of the Ppdb both in name and units. """
DiaObjectCalculationPluginConfig, DiaObjectCalculationPlugin)
"HTMIndexDiaPosition", "HTMIndexDiaPositionConfig", "NumDiaSourcesDiaPlugin", "NumDiaSourcesDiaPluginConfig", "SimpleSourceFlagDiaPlugin", "SimpleSourceFlagDiaPluginConfig", "WeightedMeanDiaPsFluxConfig", "WeightedMeanDiaPsFlux", "PercentileDiaPsFlux", "PercentileDiaPsFluxConfig", "SigmaDiaPsFlux", "SigmaDiaPsFluxConfig", "Chi2DiaPsFlux", "Chi2DiaPsFluxConfig", "MadDiaPsFlux", "MadDiaPsFluxConfig", "SkewDiaPsFlux", "SkewDiaPsFluxConfig", "MinMaxDiaPsFlux", "MinMaxDiaPsFluxConfig", "MaxSlopeDiaPsFlux", "MaxSlopeDiaPsFluxConfig", "ErrMeanDiaPsFlux", "ErrMeanDiaPsFluxConfig", "LinearFitDiaPsFlux", "LinearFitDiaPsFluxConfig", "StetsonJDiaPsFlux", "StetsonJDiaPsFluxConfig", "WeightedMeanDiaTotFlux", "WeightedMeanDiaTotFluxConfig", "SigmaDiaTotFlux", "SigmaDiaTotFluxConfig")
"""Compute the mean position of a DiaObject given a set of DiaSources. """
def getExecutionOrder(cls): return cls.DEFAULT_CATALOGCALCULATION
"""Compute the mean ra/dec position of the diaObject given the diaSource locations.
Parameters ---------- diaObject : `dict` Summary object to store values in. diaSources : `pandas.DataFrame` Catalog of DiaSources summarized by this DiaObject. """ aveCoord = geom.averageSpherePoint( list(geom.SpherePoint(src["ra"], src["decl"], geom.degrees) for idx, src in diaSources.iterrows())) if not (np.isfinite(aveCoord.getRa().asDegrees()) and np.isfinite(aveCoord.getDec().asDegrees())): self.fail(diaObject, self.outputCols) else: diaObject["ra"] = aveCoord.getRa().asDegrees() diaObject["decl"] = aveCoord.getDec().asDegrees() diaObject["radecTai"] = np.max(diaSources["midPointTai"])
doc='Select the spatial indexer to use within the database. For this ' 'plugin we enforce HTM pixelization. The configuration as is ' 'allows for different resolutions to be used.', default="HTM", )
self.indexer == "HTM"
"""Compute the mean position of a DiaObject given a set of DiaSources. """
DiaObjectCalculationPlugin.__init__(self, config, name, metadata) self.indexer = IndexerRegistry[self.config.indexer.name]( self.config.indexer.active)
def getExecutionOrder(cls): return cls.FLUX_MOMENTS_CALCULATED
"""Compute the mean position of a DiaObject given a set of DiaSources
Parameters ---------- diaObject : `dict` Summary object to store values in and read ra/decl from. """ diaObject["pixelId"] = self.indexer.indexPoints([diaObject["ra"]], [diaObject["decl"]])[0]
"""Compute the total number of DiaSources associated with this DiaObject. """
def getExecutionOrder(cls): return cls.DEFAULT_CATALOGCALCULATION
"""Compute the total number of DiaSources associated with this DiaObject.
Parameters ---------- diaObject : `dict` Summary object to store values in and read ra/decl from. """ diaObject["nDiaSources"] = len(diaSources)
"""Find if any DiaSource is flagged.
Set the DiaObject flag if any DiaSource is flagged. """
def getExecutionOrder(cls): return cls.DEFAULT_CATALOGCALCULATION
"""Find if any DiaSource is flagged.
Set the DiaObject flag if any DiaSource is flagged.
Parameters ---------- diaObject : `dict` Summary object to store values in and read ra/decl from. """ if np.any(diaSources["flags"] > 0): diaObject["flags"] = 1 else: diaObject["flags"] = 0
"""Compute the weighted mean and mean error on the point source fluxes of the DiaSource measured on the difference image.
Additionally store number of usable data points. """
def getExecutionOrder(cls): return cls.DEFAULT_CATALOGCALCULATION
diaObject, diaSources, filterDiaSources, filterName, **kwargs): """Compute the weighted mean and mean error of the point source flux.
Parameters ---------- diaObject : `dict` Summary object to store values in. diaSources : `pandas.DataFrame` DataFrame representing all diaSources associated with this diaObject. filterDiaSources : `pandas.DataFrame` DataFrame representing diaSources associated with this diaObject that are observed in the band pass ``filterName``. filterName : `str` Simple, string name of the filter for the flux being calculated. """ if len(filterDiaSources) > 0: tot_weight = np.nansum(1 / filterDiaSources["psFluxErr"] ** 2) fluxMean = np.nansum(filterDiaSources["psFlux"] / filterDiaSources["psFluxErr"] ** 2) fluxMean /= tot_weight fluxMeanErr = np.sqrt(1 / tot_weight) nFluxData = np.sum(np.isfinite(filterDiaSources["psFlux"])) else: fluxMean = np.nan fluxMeanErr = np.nan nFluxData = 0 if np.isfinite(fluxMean) and np.isfinite(fluxMeanErr): diaObject["{}PSFluxMean".format(filterName)] = fluxMean diaObject["{}PSFluxMeanErr".format(filterName)] = fluxMeanErr diaObject["{}PSFluxNdata".format(filterName)] = nFluxData else: self.fail(diaObject, ["{}{}".format(filterName, colName) for colName in self.outputCols])
"""Set diaObject position values to nan.
Since we set an explicit value instead of nan for all, we override the fail method. """ for colName in columns: if colName.endswith("Ndata"): diaObject[colName] = 0 else: diaObject[colName] = np.nan
dtype=int, default=[5, 25, 50, 75, 95], doc="Percentiles to calculate to compute values for. Should be " "integer values." )
"""Compute percentiles of diaSource fluxes. """
# Output columns are created upon instantiation of the class.
DiaObjectCalculationPlugin.__init__(self, config, name, metadata, **kwargs) self.outputCols = ["PSFluxPercentile{:02d}".format(percent) for percent in self.config.percentiles]
def getExecutionOrder(cls): return cls.DEFAULT_CATALOGCALCULATION
diaObject, diaSources, filterDiaSources, filterName, **kwargs): """Compute the percentile fluxes of the point source flux.
Parameters ---------- diaObject : `dict` Summary object to store values in. diaSources : `pandas.DataFrame` DataFrame representing all diaSources associated with this diaObject. filterDiaSources : `pandas.DataFrame` DataFrame representing diaSources associated with this diaObject that are observed in the band pass ``filterName``. filterName : `str` Simple, string name of the filter for the flux being calculated. """ if len(filterDiaSources) > 0: pTiles = np.nanpercentile(filterDiaSources["psFlux"], self.config.percentiles) for pTile, tilePercent in zip(pTiles, self.config.percentiles): diaObject[ "{}PSFluxPercentile{:02d}".format(filterName, tilePercent)] = pTile else: self.fail(diaObject, ["{}{}".format(filterName, colName) for colName in self.outputCols])
"""Compute scatter of diaSource fluxes. """
# Output columns are created upon instantiation of the class.
def getExecutionOrder(cls): return cls.DEFAULT_CATALOGCALCULATION
diaObject, diaSources, filterDiaSources, filterName, **kwargs): """Compute the sigma fluxes of the point source flux.
Parameters ---------- diaObject : `dict` Summary object to store values in. diaSources : `pandas.DataFrame` DataFrame representing all diaSources associated with this diaObject. filterDiaSources : `pandas.DataFrame` DataFrame representing diaSources associated with this diaObject that are observed in the band pass ``filterName``. filterName : `str` Simple, string name of the filter for the flux being calculated. """ # Set "delta degrees of freedom (ddf)" to 1 to calculate the unbiased # estimator of scatter (i.e. 'N - 1' instead of 'N'). if len(filterDiaSources) > 1: diaObject["{}PSFluxSigma".format(filterName)] = np.nanstd( filterDiaSources["psFlux"], ddof=1) else: self.fail(diaObject, ["{}{}".format(filterName, colName) for colName in self.outputCols])
"""Compute chi2 of diaSource fluxes. """
# Required input Cols # Output columns are created upon instantiation of the class.
def getExecutionOrder(cls): return cls.FLUX_MOMENTS_CALCULATED
diaObject, diaSources, filterDiaSources, filterName, **kwargs): """Compute the chi2 of the point source fluxes.
Parameters ---------- diaObject : `dict` Summary object to store values in. diaSources : `pandas.DataFrame` DataFrame representing all diaSources associated with this diaObject. filterDiaSources : `pandas.DataFrame` DataFrame representing diaSources associated with this diaObject that are observed in the band pass ``filterName``. filterName : `str` Simple, string name of the filter for the flux being calculated. """ if len(filterDiaSources) > 0: delta = (filterDiaSources["psFlux"] - diaObject["{}PSFluxMean".format(filterName)]) diaObject["{}PSFluxChi2".format(filterName)] = np.nansum( (delta / filterDiaSources["psFluxErr"]) ** 2) else: self.fail(diaObject, ["{}{}".format(filterName, colName) for colName in self.outputCols])
"""Compute median absolute deviation of diaSource fluxes. """
# Required input Cols # Output columns are created upon instantiation of the class.
def getExecutionOrder(cls): return cls.DEFAULT_CATALOGCALCULATION
diaObject, diaSources, filterDiaSources, filterName, **kwargs): """Compute the median absolute deviation of the point source fluxes.
Parameters ---------- diaObject : `dict` Summary object to store values in. diaSources : `pandas.DataFrame` DataFrame representing all diaSources associated with this diaObject. filterDiaSources : `pandas.DataFrame` DataFrame representing diaSources associated with this diaObject that are observed in the band pass ``filterName``. filterName : `str` Simple, string name of the filter for the flux being calculated. """ if len(filterDiaSources) > 0: diaObject["{}PSFluxMAD".format(filterName)] = ( median_absolute_deviation(filterDiaSources["psFlux"], ignore_nan=True) ) else: self.fail(diaObject, ["{}{}".format(filterName, colName) for colName in self.outputCols])
"""Compute the skew of diaSource fluxes. """
# Required input Cols # Output columns are created upon instantiation of the class.
def getExecutionOrder(cls): return cls.DEFAULT_CATALOGCALCULATION
diaObject, diaSources, filterDiaSources, filterName, **kwargs): """Compute the skew of the point source fluxes.
Parameters ---------- diaObject : `dict` Summary object to store values in. diaSources : `pandas.DataFrame` DataFrame representing all diaSources associated with this diaObject. filterDiaSources : `pandas.DataFrame` DataFrame representing diaSources associated with this diaObject that are observed in the band pass ``filterName``. filterName : `str` Simple, string name of the filter for the flux being calculated. """ if len(filterDiaSources) > 0: fluxes = filterDiaSources["psFlux"] diaObject["{}PSFluxSkew".format(filterName)] = ( skew(fluxes[~np.isnan(fluxes)]) ) else: self.fail(diaObject, ["{}{}".format(filterName, colName) for colName in self.outputCols])
"""Compute min/max of diaSource fluxes. """
# Required input Cols # Output columns are created upon instantiation of the class.
def getExecutionOrder(cls): return cls.DEFAULT_CATALOGCALCULATION
diaObject, diaSources, filterDiaSources, filterName, **kwargs): """Compute min/max of the point source fluxes.
Parameters ---------- diaObject : `dict` Summary object to store values in. diaSources : `pandas.DataFrame` DataFrame representing all diaSources associated with this diaObject. filterDiaSources : `pandas.DataFrame` DataFrame representing diaSources associated with this diaObject that are observed in the band pass ``filterName``. filterName : `str` Simple, string name of the filter for the flux being calculated. """ if len(filterDiaSources) > 0: fluxes = filterDiaSources["psFlux"] diaObject["{}PSFluxMin".format(filterName)] = np.min(fluxes) diaObject["{}PSFluxMax".format(filterName)] = np.max(fluxes) else: self.fail(diaObject, ["{}{}".format(filterName, colName) for colName in self.outputCols])
"""Compute the maximum ratio time ordered deltaFlux / deltaTime. """
# Required input Cols # Output columns are created upon instantiation of the class.
def getExecutionOrder(cls): return cls.DEFAULT_CATALOGCALCULATION
diaObject, diaSources, filterDiaSources, filterName, **kwargs): """Compute the maximum ratio time ordered deltaFlux / deltaTime.
Parameters ---------- diaObject : `dict` Summary object to store values in. diaSources : `pandas.DataFrame` DataFrame representing all diaSources associated with this diaObject. filterDiaSources : `pandas.DataFrame` DataFrame representing diaSources associated with this diaObject that are observed in the band pass ``filterName``. filterName : `str` Simple, string name of the filter for the flux being calculated. """ if len(filterDiaSources) > 1: tmpDiaSources = filterDiaSources[~np.isnan(filterDiaSources["psFlux"])] fluxes = tmpDiaSources["psFlux"].to_numpy() times = tmpDiaSources["midPointTai"].to_numpy() diaObject["{}PSFluxMaxSlope".format(filterName)] = np.max( (fluxes[1:] - fluxes[:-1]) / (times[1:] - times[:-1])) else: self.fail(diaObject, ["{}{}".format(filterName, colName) for colName in self.outputCols])
"""Compute the mean of the dia source errors. """
# Required input Cols # Output columns are created upon instantiation of the class.
def getExecutionOrder(cls): return cls.DEFAULT_CATALOGCALCULATION
diaObject, diaSources, filterDiaSources, filterName, **kwargs): """Compute the mean of the dia source errors.
Parameters ---------- diaObject : `dict` Summary object to store values in. diaSources : `pandas.DataFrame` DataFrame representing all diaSources associated with this diaObject. filterDiaSources : `pandas.DataFrame` DataFrame representing diaSources associated with this diaObject that are observed in the band pass ``filterName``. filterName : `str` Simple, string name of the filter for the flux being calculated. """ if len(filterDiaSources) > 0: diaObject["{}PSFluxErrMean".format(filterName)] = np.nanmean( filterDiaSources["psFluxErr"]) else: self.fail(diaObject, ["{}{}".format(filterName, colName) for colName in self.outputCols])
"""Compute fit a linear model to flux vs time. """
# Required input Cols # Output columns are created upon instantiation of the class.
def getExecutionOrder(cls): return cls.DEFAULT_CATALOGCALCULATION
diaObject, diaSources, filterDiaSources, filterName, **kwargs): """Compute fit a linear model to flux vs time.
Parameters ---------- diaObject : `dict` Summary object to store values in. diaSources : `pandas.DataFrame` DataFrame representing all diaSources associated with this diaObject. filterDiaSources : `pandas.DataFrame` DataFrame representing diaSources associated with this diaObject that are observed in the band pass ``filterName``. filterName : `str` Simple, string name of the filter for the flux being calculated. """ if len(filterDiaSources) > 1: tmpDiaSources = filterDiaSources[ ~np.logical_or(np.isnan(filterDiaSources["psFlux"]), np.isnan(filterDiaSources["psFluxErr"]))] fluxes = tmpDiaSources["psFlux"].to_numpy() errors = tmpDiaSources["psFluxErr"].to_numpy() times = tmpDiaSources["midPointTai"].to_numpy() A = np.array([times / errors, 1 / errors]).transpose() m, b = lsq_linear(A, fluxes / errors).x diaObject["{}PSFluxLinearSlope".format(filterName)] = m diaObject["{}PSFluxLinearIntercept".format(filterName)] = b else: self.fail(diaObject, ["{}{}".format(filterName, colName) for colName in self.outputCols])
"""Compute the StetsonJ statistic on the DIA point source fluxes. """
# Required input Cols # Output columns are created upon instantiation of the class.
def getExecutionOrder(cls): return cls.FLUX_MOMENTS_CALCULATED
diaObject, diaSources, filterDiaSources, filterName, **kwargs): """Compute the StetsonJ statistic on the DIA point source fluxes.
Parameters ---------- diaObject : `dict` Summary object to store values in. diaSources : `pandas.DataFrame` DataFrame representing all diaSources associated with this diaObject. filterDiaSources : `pandas.DataFrame` DataFrame representing diaSources associated with this diaObject that are observed in the band pass ``filterName``. filterName : `str` Simple, string name of the filter for the flux being calculated. """ if len(filterDiaSources) > 1: tmpDiaSources = filterDiaSources[ ~np.logical_or(np.isnan(filterDiaSources["psFlux"]), np.isnan(filterDiaSources["psFluxErr"]))] fluxes = tmpDiaSources["psFlux"].to_numpy() errors = tmpDiaSources["psFluxErr"].to_numpy()
diaObject["{}PSFluxStetsonJ".format(filterName)] = self._stetson_J( fluxes, errors, diaObject["{}PSFluxMean".format(filterName)]) else: self.fail(diaObject, ["{}{}".format(filterName, colName) for colName in self.outputCols])
"""Compute the single band stetsonJ statistic.
Parameters ---------- fluxes : `numpy.ndarray` (N,) Calibrated lightcurve flux values. errors : `numpy.ndarray` (N,) Errors on the calibrated lightcurve fluxes. mean : `float` Starting mean from previous plugin.
Returns ------- stetsonJ : `float` stetsonJ statistic for the input fluxes and errors.
References ---------- .. [1] Stetson, P. B., "On the Automatic Determination of Light-Curve Parameters for Cepheid Variables", PASP, 108, 851S, 1996 """ n_points = len(fluxes) flux_mean = self._stetson_mean(fluxes, errors, mean) delta_val = ( np.sqrt(n_points / (n_points - 1)) * (fluxes - flux_mean) / errors) p_k = delta_val ** 2 - 1
return np.mean(np.sign(p_k) * np.sqrt(np.fabs(p_k)))
values, errors, mean=None, alpha=2., beta=2., n_iter=20, tol=1e-6): """Compute the stetson mean of the fluxes which down-weights outliers.
Weighted biased on an error weighted difference scaled by a constant (1/``a``) and raised to the power beta. Higher betas more harshly penalize outliers and ``a`` sets the number of sigma where a weighted difference of 1 occurs.
Parameters ---------- values : `numpy.dnarray`, (N,) Input values to compute the mean of. errors : `numpy.ndarray`, (N,) Errors on the input values. mean : `float` Starting mean value or None. alpha : `float` Scalar down-weighting of the fractional difference. lower->more clipping. (Default value is 2.) beta : `float` Power law slope of the used to down-weight outliers. higher->more clipping. (Default value is 2.) n_iter : `int` Number of iterations of clipping. tol : `float` Fractional and absolute tolerance goal on the change in the mean before exiting early. (Default value is 1e-6)
Returns ------- mean : `float` Weighted stetson mean result.
References ---------- .. [1] Stetson, P. B., "On the Automatic Determination of Light-Curve Parameters for Cepheid Variables", PASP, 108, 851S, 1996 """ n_points = len(values) n_factor = np.sqrt(n_points / (n_points - 1)) inv_var = 1 / errors ** 2
if mean is None: mean = np.average(values, weights=inv_var) for iter_idx in range(n_iter): chi = np.fabs(n_factor * (values - mean) / errors) tmp_mean = np.average( values, weights=inv_var / (1 + (chi / alpha) ** beta)) diff = np.fabs(tmp_mean - mean) mean = tmp_mean if diff / mean < tol and diff < tol: break return mean
"""Compute the weighted mean and mean error on the point source fluxes forced photometered at the DiaSource location in the calibrated image.
Additionally store number of usable data points. """
def getExecutionOrder(cls): return cls.DEFAULT_CATALOGCALCULATION
diaObject, diaSources, filterDiaSources, filterName, **kwargs): """Compute the weighted mean and mean error of the point source flux.
Parameters ---------- diaObject : `dict` Summary object to store values in. diaSources : `pandas.DataFrame` DataFrame representing all diaSources associated with this diaObject. filterDiaSources : `pandas.DataFrame` DataFrame representing diaSources associated with this diaObject that are observed in the band pass ``filterName``. filterName : `str` Simple, string name of the filter for the flux being calculated. """ if len(filterDiaSources) > 0: tot_weight = np.nansum(1 / filterDiaSources["totFluxErr"] ** 2) fluxMean = np.nansum(filterDiaSources["totFlux"] / filterDiaSources["totFluxErr"] ** 2) fluxMean /= tot_weight fluxMeanErr = np.sqrt(1 / tot_weight) else: fluxMean = np.nan fluxMeanErr = np.nan if np.isfinite(fluxMean) and np.isfinite(fluxMeanErr): diaObject["{}TOTFluxMean".format(filterName)] = fluxMean diaObject["{}TOTFluxMeanErr".format(filterName)] = fluxMeanErr else: self.fail(diaObject, ["{}{}".format(filterName, colName) for colName in self.outputCols])
"""Compute scatter of diaSource fluxes. """
# Output columns are created upon instantiation of the class.
def getExecutionOrder(cls): return cls.DEFAULT_CATALOGCALCULATION
diaObject, diaSources, filterDiaSources, filterName, **kwargs): """Compute the sigma fluxes of the point source flux measured on the calibrated image.
Parameters ---------- diaObject : `dict` Summary object to store values in. diaSources : `pandas.DataFrame` DataFrame representing all diaSources associated with this diaObject. filterDiaSources : `pandas.DataFrame` DataFrame representing diaSources associated with this diaObject that are observed in the band pass ``filterName``. filterName : `str` Simple, string name of the filter for the flux being calculated. """ # Set "delta degrees of freedom (ddf)" to 1 to calculate the unbiased # estimator of scatter (i.e. 'N - 1' instead of 'N'). if len(filterDiaSources) > 1: diaObject["{}TOTFluxSigma".format(filterName)] = np.nanstd( filterDiaSources["totFlux"], ddof=1) else: self.fail(diaObject, ["{}{}".format(filterName, colName) for colName in self.outputCols]) |