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");
390 log.
format(Log::INFO,
"Processing sources from exposure %lld",
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();
470 log.
format(Log::WARN,
"Centroid of source %lld contains NaNs",
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()));
479 log.
format(Log::WARN,
"Sky-coord of source %lld contains NaNs",
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>());
554 log.
format(Log::INFO,
"processed %lld sources (invalid: %lld, "
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);
bool isValid() const
Return true if the key was initialized to valid offset.
Defines the fields and offsets for a table.
FluxSlotDefinition::MeasKey getModelFluxKey() const
Return the key used for the ModelFlux slot measurement value.
Key< Flag > getModelFluxFlagKey() const
Return the key used for the ModelFlux slot failure flag.
std::string getInstFluxDefinition() const
Return the name of the field used for the InstFlux slot.
std::vector< std::string > shapeFields
"A list of shape field names which should be carried over from input\n" "source tables to output s...
lsst::afw::geom::Angle Angle
int getHeight() const
Get exposure width and/or height.
Schema const getOutputSchema() const
Return the output schema (copy-on-write).
double indexToPosition(double ind)
Convert image index to image position.
static Schema makeMinimalSchema()
Return a minimal schema for Simple tables and records.
Schema const getInputSchema() const
Return the input schema (copy-on-write).
std::string getShapeDefinition() const
Return the name of the field used for the Shape slot.
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)
bool isValid() const
Return True if all the constituent Keys are valid.
FluxSlotDefinition::ErrKey getApFluxErrKey() const
Return the key used for the ApFlux slot uncertainty.
void format(int importance, const char *fmt,...)
Record class that contains measurement averages on clusters of single exposure sources.
Key< Flag > getPsfFluxFlagKey() const
Return the key used for the PsfFlux slot failure flag.
Implementation of the Optics class.
int getY0() const
Get pixel coordinates of sub-image pixel (0,0) in the parent exposure.
std::string getApFluxDefinition() const
Return the name of the field used for the ApFlux slot.
double getExposureTime() const
Return the exposure time, s. NaN for coadds.
FluxSlotDefinition::MeasKey getInstFluxKey() const
Return the key used for the InstFlux slot measurement value.
Key< T > addField(Field< T > const &field, bool doReplace=false)
Add a new field to the Schema, and return the associated Key.
a place to record messages and descriptions of the state of processing.
lsst::afw::geom::Angle const getLeafExtentThreshold() const
CentroidSlotDefinition::ErrKey getCentroidErrKey() const
Return the key used for the Centroid slot uncertainty.
FluxSlotDefinition::ErrKey getModelFluxErrKey() const
Return the key used for the ModelFlux slot uncertainty.
bool isValid() const
Return True if both the x and y Keys are valid.
Key< Flag > getCentroidFlagKey() const
Return the key used for the Centroid slot failure flag.
std::string clusterPrefix
"Prefix for cluster related fields in the output source schema.\n" "May be empty.\n" ; ...
Functions for clustering sources.
definition of the DualLog class
int pointsPerLeaf
"A performance tuning parameter for the k-d tree used internally by\n" "the OPTICS implementation...
afw::geom::ellipses::Quadrupole Shape
double getEpoch() const
Return the exposure mid-point, MJD TAI. NaN for coadds.
Metrics (distance functions) over K-dimensional spaces.
ShapeSlotDefinition::MeasKey getShapeKey() const
Return the key used for the Shape slot measurement value.
lsst::afw::coord::IcrsCoord IcrsCoord
Parameters for source processing.
Key< Flag > getShapeFlagKey() const
Return the key used for the Shape slot failure flag.
AngleUnit const radians
constant with units of radians
Key< Flag > getInstFluxFlagKey() const
Return the key used for the InstFlux slot failure flag.
void addMappingsWhere(Predicate predicate, bool doReplace=true)
Add mappings for all fields that match criteria defined by a predicate.
FluxSlotDefinition::ErrKey getInstFluxErrKey() const
Return the key used for the InstFlux slot uncertainty.
static Key< Coord > getCoordKey()
Key for the celestial coordinates.
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.
lsst::afw::geom::Angle const getEpsilon() const
IcrsCoord getCoord() const
Convenience accessors for the keys in the minimal reference schema.
std::string getModelFluxDefinition() const
Return the name of the field used for the ModelFlux slot.
RecordId getId() const
Convenience accessors for the keys in the minimal reference schema.
FluxSlotDefinition::MeasKey getApFluxKey() const
Return the key used for the ApFlux slot measurement value.
Parameters for the clustering algorithm and its internals.
Key< Flag > getApFluxFlagKey() const
Return the key used for the ApFlux slot failure flag.
Holds an integer identifier for an LSST filter.
A polymorphic functor base class for generating record IDs for a table.
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.
#define LSST_EXCEPT(type,...)
ShapeSlotDefinition::ErrKey getShapeErrKey() const
Return the key used for the Shape slot uncertainty.
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...
void setVersion(int version)
Set the table's version.
A class used as a handle to a particular field in a table.
CentroidSlotDefinition::MeasKey getCentroidKey() const
Return the key used for the Centroid slot measurement value.
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::MeasKey getPsfFluxKey() const
Return the key used for the PsfFlux slot measurement value.
SortedCatalogT< SourceRecord > SourceCatalog
int getWidth() const
Get exposure width and/or height.
Schema getSchema() const
Return the table's schema.
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...
bool isValid() const
Return True if all the constituent sigma Keys are valid.
std::string getPsfFluxDefinition() const
Return the name of the field used for the PsfFlux slot.
Record class that contains measurements made on a single exposure.
SchemaItem< T > find(std::string const &name) const
Find a SchemaItem in the Schema by name.
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 getPsfFluxErrKey() const
Return the key used for the PsfFlux slot uncertainty.
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)
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" ;
afw::table::SourceRecord * record
boost::shared_ptr< SourceClusterTable > const makeSourceClusterTable(SourceTable const &prototype, boost::shared_ptr< IdFactory > const &idFactory, SourceProcessingControl const &control)
std::string getCentroidDefinition() const
Return the name of the field used for the Centroid 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.
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.