38 using lsst::pex::exceptions::InvalidParameterError;
39 using lsst::pex::exceptions::NotFoundError;
54 using lsst::afw::table::Flag;
70 namespace lsst {
namespace ap {
namespace cluster {
78 template <
typename T>
bool operator()(T dummy)
const {
85 std::string
const & filter,
86 std::string
const & name,
87 std::string
const & unit)
89 std::string doc =
"inverse variance weighted mean of " + filter +
90 "-filter source " + name +
" (" +
91 proto.
find<Flux::MeasTag>(name).field.getDoc() +
")";
97 std::string
const & filter,
98 std::string
const & name)
100 std::string doc =
"inverse variance weighted mean of " + filter +
101 "-filter source " + name +
" (" +
102 proto.
find<Shape::MeasTag>(name).field.getDoc() +
")";
106 bool hasFluxField(
Schema const &
schema, std::string
const & name) {
108 schema.
find<Flux::MeasTag>(name);
109 }
catch (NotFoundError &) {
115 bool hasShapeField(
Schema const & schema, std::string
const & name) {
117 schema.
find<Shape::MeasTag>(name);
118 }
catch (NotFoundError &) {
124 struct FilterNameCmp {
125 bool operator()(std::string
const &, std::string
const &)
const;
128 bool FilterNameCmp::operator()(std::string
const & a, std::string
const &
b)
const {
141 throw LSST_EXCEPT(InvalidParameterError,
"Prototypical "
142 "SourceCatalog must have valid Coord and Centroid fields");
150 "covariance matrix for source sky-coordinates",
156 "ID of exposure source was measured on"));
160 "ID of filter for exposure"));
162 if (!control.
coadd) {
169 "middle of exposure time",
177 "ID of cluster containing source; 0 if source is not assigned to any cluster."));
180 "ICRS sky-coordinates of cluster containing source",
183 boost::shared_ptr<SourceTable> table =
184 SourceTable::make(mapper.getOutputSchema(), boost::shared_ptr<IdFactory>());
193 return std::make_pair(table, mapper);
199 boost::shared_ptr<IdFactory>
const & idFactory,
202 typedef std::vector<std::string>::const_iterator Iter;
209 "sample covariance matrix for coord field (unweighted mean sky-coordinates)",
213 "number of sources in cluster");
216 "set if cluster was created from a single noise source");
220 "coord.weightedmean",
221 "inverse variance weighted mean sky-coordinates (ICRS)",
224 "coord.weightedmean.err",
225 "covariance matrix for coord.weightedmean field",
228 "coord.weightedmean.count",
229 "number of samples used to compute coord.weightedmean");
234 "earliest observation time of sources in cluster (TAI)",
238 "mean observation time of sources in cluster (TAI)",
242 "latest observation time of sources in cluster (TAI)",
245 std::vector<std::string> filters = Filter::getNames();
247 std::sort(filters.begin(), filters.end(), FilterNameCmp());
249 for (Iter filt = filters.begin(), eFilt = filters.end(); filt != eFilt; ++filt) {
251 *filt +
".obs.count",
252 "number of " + *filt +
"-filter sources in cluster");
255 *filt +
".obs.time.min",
256 "earliest observation time of " + *filt +
"-filter sources in cluster (TAI)",
259 *filt +
".obs.time.max",
260 "latest observation time of " + *filt +
"-filter sources in cluster (TAI)",
264 flux != eFlux; ++flux) {
265 if (hasFluxField(prototype.
getSchema(), *flux)) {
270 shape != eShape; ++shape) {
271 if (hasShapeField(prototype.
getSchema(), *shape)) {
272 addShape(schema, prototype.
getSchema(), *filt, *shape);
278 boost::shared_ptr<SourceClusterTable> table =
282 table->defineCoordErr(
"coord.err");
283 table->defineNumSources(
"obs.count");
286 table->defineWeightedMeanCoord(
"coord.weightedmean");
287 table->defineWeightedMeanCoordErr(
"coord.weightedmean.err");
288 table->defineWeightedMeanCoordCount(
"coord.weightedmean.count");
291 table->defineTimeMin(
"obs.time.min");
292 table->defineTimeMean(
"obs.time.mean");
293 table->defineTimeMax(
"obs.time.max");
295 for (Iter filt = filters.begin(), eFilt = filters.end();
296 filt != eFilt; ++filt) {
297 table->defineNumSources(*filt,
"obs.count");
299 table->defineTimeMin(*filt,
"obs.time.min");
300 table->defineTimeMax(*filt,
"obs.time.max");
306 if (std::find(flux, eFlux, def) != eFlux) {
307 table->definePsfFlux(*filt, def);
313 if (std::find(flux, eFlux, def) != eFlux) {
314 table->defineModelFlux(*filt, def);
320 if (std::find(flux, eFlux, def) != eFlux) {
321 table->defineApFlux(*filt, def);
327 if (std::find(flux, eFlux, def) != eFlux) {
328 table->defineInstFlux(*filt, def);
335 if (std::find(shape, eShape, def) != eShape) {
336 table->defineShape(*filt, def);
385 typedef std::vector<std::string>::const_iterator StringIter;
386 typedef std::vector<Key<Flag> >::const_iterator FlagKeyIter;
387 typedef SourceCatalog::const_iterator SourceIter;
389 Log log(Log::getDefaultLog(),
"lsst.ap.cluster");
391 static_cast<long long>(expInfo.
getId()));
394 if (sources.getSchema() != badSources.getSchema() ||
395 sources.getSchema() != invalidSources.getSchema()) {
397 "SourceCatalog schema mismatch");
399 if (!sources.getSchema().contains(expSources.getSchema())) {
400 throw LSST_EXCEPT(InvalidParameterError,
"output SourceCatalog "
401 "schema does not contain input SourceCatalog schema");
404 throw LSST_EXCEPT(InvalidParameterError,
"SchemaMapper and "
405 "input source catalog disagree on input schema.");
408 throw LSST_EXCEPT(InvalidParameterError,
"SchemaMapper and "
409 "output source catalogs disagree on output schema.");
411 if (!compareSlots(*expSources.getTable(), *sources.getTable()) ||
412 !compareSlots(*sources.getTable(), *badSources.getTable()) ||
413 !compareSlots(*badSources.getTable(), *invalidSources.getTable())) {
414 throw LSST_EXCEPT(InvalidParameterError,
"slot mappings "
415 "for input and output SourceCatalogs differ");
419 std::vector<Key<Flag> > badKeys;
422 badKeys.push_back(expSources.getSchema().find<Flag>(*i).key);
439 sources.getTable()->getCentroidErrKey();
443 coordErrKey = sources.getSchema()[
"coord.err"];
444 }
catch (NotFoundError &) {
453 if (!control.
coadd) {
462 size_t ngood = 0, nbad = 0, ninvalid = 0, noutside = 0;
464 for (SourceIter s = expSources.begin(), es = expSources.end(); s != es; ++s) {
466 bool invalid =
false;
467 double x = s->getX();
468 double y = s->getY();
471 static_cast<long long>(s->getId()));
473 }
else if (x < xMin || x > xMax || y < yMin || y > yMax) {
474 log.
format(
Log::WARN,
"Centroid of source %lld does not lie on exposure",
475 static_cast<long long>(s->getId()));
480 static_cast<long long>(s->getId()));
483 if (!invalid && skyTile && !skyTile->
contains(s->getCoord())) {
490 for (FlagKeyIter f = badKeys.begin(), ef = badKeys.end(); f != ef; ++f) {
497 boost::shared_ptr<SourceRecord> os;
500 os = invalidSources.addNew();
503 os = badSources.addNew();
506 os = sources.addNew();
508 os->assign(*s, mapper);
510 if (expIdKey.isValid()) {
511 os->set(expIdKey, expInfo.
getId());
513 if (expFilterIdKey.
isValid()) {
520 os->set(expTimeMidKey, expInfo.
getEpoch());
523 if (clusterCoordKey.
isValid()) {
524 os->set(clusterCoordKey, s->getCoord());
527 if (!invalid && coordErrKey.
isValid() && centroidErrKey.
isValid()) {
528 Eigen::Matrix2d cov = s->getCentroidErr().cast<
double>();
529 bool computeErr =
true;
532 }
else if (cov(0,1) != cov(1,0)) {
542 cov(0,1) = 0.0; cov(1,0) = 0.0;
548 Eigen::Matrix2d m = expInfo.
getWcs()->linearizePixelToSky(
549 s->getCentroid(),
radians).getLinear().getMatrix();
550 os->set(coordErrKey, (m * cov * m.transpose()).cast<float>());
555 "outside sky-tile: %lld, bad: %lld, good: %lld)",
556 static_cast<long long>(expSources.size()),
557 static_cast<long long>(ninvalid),
558 static_cast<long long>(noutside),
559 static_cast<long long>(nbad),
560 static_cast<long long>(ngood));
568 typedef detail::Point<3, boost::shared_ptr<SourceRecord> > OpticsPoint;
569 typedef detail::Optics<3, SourceRecord> Optics;
572 unsigned int const MAX_SOURCES =
582 typedef SourceCatalog::const_iterator Iter;
584 if (sources.size() > MAX_SOURCES) {
585 throw LSST_EXCEPT(InvalidParameterError,
"too many sources to cluster");
588 boost::scoped_array<OpticsPoint> entries(
new OpticsPoint[sources.size()]);
589 std::vector<SourceCatalog> clusters;
591 for (Iter s = sources.begin(), e = sources.end(); s != e; ++s, ++i) {
592 entries[i].coords = s->getCoord().getVector().asEigen();
600 eps = 4.0 * eps * eps;
603 let = std::sin(0.5 * let);
604 let = 4.0 * let * let;
620 typedef SourceCatalog::iterator Iter;
628 idKey = sources.getSchema().find<int64_t>(control.
clusterPrefix +
".id").key;
631 }
catch (NotFoundError &) {
635 int64_t
const id = record.
getId();
637 for (Iter i = sources.begin(), e = sources.end(); i != e; ++i) {
639 i->set(coordKey, coord);
Defines the fields and offsets for a table.
Key< Flag > getModelFluxFlagKey() const
Return the key used for the ModelFlux slot failure flag.
bool isValid() const
Return True if all the constituent Keys are valid.
std::vector< std::string > shapeFields
"A list of shape field names which should be carried over from input\n" "source tables to output s...
int getHeight() const
Get exposure width and/or height.
boost::shared_ptr< SourceClusterTable > const makeSourceClusterTable(SourceTable const &prototype, boost::shared_ptr< IdFactory > const &idFactory, SourceProcessingControl const &control)
double indexToPosition(double ind)
Convert image index to image position.
AngleUnit const radians
constant with units of radians
CentroidSlotDefinition::MeasKey getCentroidKey() const
Return the key used for the Centroid slot measurement value.
Schema const getOutputSchema() const
Return the output schema (copy-on-write).
ShapeSlotDefinition::ErrKey getShapeErrKey() const
Return the key used for the Shape slot uncertainty.
static Schema makeMinimalSchema()
Return a minimal schema for Simple tables and records.
A mapping between the keys of two Schemas, used to copy data between them.
std::vector< SourceCatalog > const cluster(SourceCatalog const &sources, ClusteringControl const &control)
Key< Flag > getApFluxFlagKey() const
Return the key used for the ApFlux slot failure flag.
Record class that contains measurement averages on clusters of single exposure sources.
bool isValid() const
Return true if the key was initialized to valid offset.
Key< Flag > getInstFluxFlagKey() const
Return the key used for the InstFlux slot failure flag.
FluxSlotDefinition::MeasKey getApFluxKey() const
Return the key used for the ApFlux slot measurement value.
Implementation of the Optics class.
int getY0() const
Get pixel coordinates of sub-image pixel (0,0) in the parent exposure.
RecordId getId() const
Convenience accessors for the keys in the minimal reference schema.
FluxSlotDefinition::MeasKey getPsfFluxKey() const
Return the key used for the PsfFlux slot measurement value.
double getExposureTime() const
Return the exposure time, s. NaN for coadds.
lsst::afw::coord::IcrsCoord IcrsCoord
a place to record messages and descriptions of the state of processing.
lsst::afw::geom::Angle const getLeafExtentThreshold() const
FluxSlotDefinition::ErrKey getModelFluxErrKey() const
Return the key used for the ModelFlux slot uncertainty.
std::string clusterPrefix
"Prefix for cluster related fields in the output source schema.\n" "May be empty.\n" ; ...
Functions for clustering sources.
std::string getPsfFluxDefinition() const
Return the name of the field used for the PsfFlux slot.
int pointsPerLeaf
"A performance tuning parameter for the k-d tree used internally by\n" "the OPTICS implementation...
IcrsCoord getCoord() const
Convenience accessors for the keys in the minimal reference schema.
afw::geom::ellipses::Quadrupole Shape
std::string getShapeDefinition() const
Return the name of the field used for the Shape slot.
double getEpoch() const
Return the exposure mid-point, MJD TAI. NaN for coadds.
Metrics (distance functions) over K-dimensional spaces.
std::string getInstFluxDefinition() const
Return the name of the field used for the InstFlux slot.
Parameters for source processing.
bool isValid() const
Return True if all the constituent sigma Keys are valid.
int minNeighbors
"The minimum cardinality of the epsilonArcsec-neighborhood of a source\n" "S for S to be considered a...
A description of a field in a table.
static boost::shared_ptr< SourceClusterTable > make(lsst::afw::table::Schema const &schema, boost::shared_ptr< lsst::afw::table::IdFactory > const &idFactory)
Construct a new table.
void format(int importance, const char *fmt,...)
lsst::afw::geom::Angle const getEpsilon() const
SchemaItem< T > find(std::string const &name) const
Find a SchemaItem in the Schema by name.
Key< Flag > getPsfFluxFlagKey() const
Return the key used for the PsfFlux slot failure flag.
Parameters for the clustering algorithm and its internals.
Holds an integer identifier for an LSST filter.
A polymorphic functor base class for generating record IDs for a table.
void setVersion(int version)
Set the table's version.
Key< Flag > getShapeFlagKey() const
Return the key used for the Shape slot failure flag.
void addMappingsWhere(Predicate predicate, bool doReplace=true)
Add mappings for all fields that match criteria defined by a predicate.
lsst::afw::image::Filter const & getFilter() const
Return the filter of the exposure. UNKNOWN for multi-band.
Table class that contains measurements made on a single exposure.
FluxSlotDefinition::MeasKey getModelFluxKey() const
Return the key used for the ModelFlux slot measurement value.
#define LSST_EXCEPT(type,...)
Key< T > addField(Field< T > const &field, bool doReplace=false)
Add a new field to the Schema, and return the associated Key.
bool coadd
"If true, sources have been detected/measured on coadd exposures,\n" "and have no associated time-sta...
std::vector< std::string > badFlagFields
"A list of flag field names. If an input source has any of the\n" "corresponding flag bits set...
std::string getCentroidDefinition() const
Return the name of the field used for the Centroid slot.
Schema getSchema() const
Return the table's schema.
A class used as a handle to a particular field in a table.
lsst::afw::geom::Angle Angle
std::vector< std::string > fluxFields
"A list of flux field names which should be carried over from input\n" "source tables to output so...
FluxSlotDefinition::ErrKey getPsfFluxErrKey() const
Return the key used for the PsfFlux slot uncertainty.
FluxSlotDefinition::ErrKey getInstFluxErrKey() const
Return the key used for the InstFlux slot uncertainty.
int getWidth() const
Get exposure width and/or height.
static Key< Coord > getCoordKey()
Key for the celestial coordinates.
afw::table::Key< double > b
bool contains(lsst::afw::coord::Coord const &coord) const
Return true if the given coordinates lie inside the sky tile.
bool multiBand
"If true, sources have been detected/measured on multi-band\n" "exposures (e.g. chi-squared coadds) a...
Key< Flag > getCentroidFlagKey() const
Return the key used for the Centroid slot failure flag.
Record class that contains measurements made on a single exposure.
int64_t getId() const
Return the unique integer identifier for the exposure.
std::string fluxUnit
"Unit of calibrated flux.\n" ;
int getX0() const
Get pixel coordinates of sub-image pixel (0,0) in the parent exposure.
void setClusterFields(SourceCatalog &sources, SourceClusterRecord const &record, SourceProcessingControl const &control)
FluxSlotDefinition::ErrKey getApFluxErrKey() const
Return the key used for the ApFlux slot uncertainty.
ShapeSlotDefinition::MeasKey getShapeKey() const
Return the key used for the Shape slot measurement value.
Schema const getInputSchema() const
Return the input schema (copy-on-write).
void processSources(SourceCatalog const &expSources, ExposureInfo const &expInfo, lsst::ap::utils::PT1SkyTile const *skyTile, SourceProcessingControl const &control, SchemaMapper const &mapper, SourceCatalog &sources, SourceCatalog &badSources, SourceCatalog &invalidSources)
Tag types used to declare specialized field types.
std::pair< boost::shared_ptr< SourceTable >, SchemaMapper > const makeOutputSourceTable(SourceTable const &prototype, SourceProcessingControl const &control)
A class to handle Icrs coordinates (inherits from Coord)
bool isValid() const
Return True if both the x and y Keys are valid.
CentroidSlotDefinition::ErrKey getCentroidErrKey() const
Return the key used for the Centroid slot uncertainty.
FluxSlotDefinition::MeasKey getInstFluxKey() const
Return the key used for the InstFlux slot measurement value.
lsst::afw::image::Wcs::ConstPtr getWcs() const
Return the exposure WCS.
std::string exposurePrefix
"Prefix for exposure related fields in the output source schema.\n" "May be empty.\n" ;
std::string getApFluxDefinition() const
Return the name of the field used for the ApFlux slot.
KeyTuple< lsst::afw::table::Shape > addShapeFields(lsst::afw::table::Schema &schema, std::string const &filter, std::string const &name, std::string const &doc)
Convenience function to setup fields for shapes.
SortedCatalogT< SourceRecord > SourceCatalog
KeyTuple< lsst::afw::table::Flux > addFluxFields(lsst::afw::table::Schema &schema, std::string const &filter, std::string const &name, std::string const &doc, std::string const &unit)
Convenience function to setup fields for fluxes.
std::string getModelFluxDefinition() const
Return the name of the field used for the ModelFlux slot.