LSSTApplications  1.1.2+25,10.0+13,10.0+132,10.0+133,10.0+224,10.0+41,10.0+8,10.0-1-g0f53050+14,10.0-1-g4b7b172+19,10.0-1-g61a5bae+98,10.0-1-g7408a83+3,10.0-1-gc1e0f5a+19,10.0-1-gdb4482e+14,10.0-11-g3947115+2,10.0-12-g8719d8b+2,10.0-15-ga3f480f+1,10.0-2-g4f67435,10.0-2-gcb4bc6c+26,10.0-28-gf7f57a9+1,10.0-3-g1bbe32c+14,10.0-3-g5b46d21,10.0-4-g027f45f+5,10.0-4-g86f66b5+2,10.0-4-gc4fccf3+24,10.0-40-g4349866+2,10.0-5-g766159b,10.0-5-gca2295e+25,10.0-6-g462a451+1
LSSTDataManagementBasePackage
Namespaces | Classes | Typedefs | Functions
lsst::ap::cluster Namespace Reference

Namespaces

 config
 
 detail
 

Classes

class  SourceAndExposure
 
struct  ClusteringControl
 Parameters for the clustering algorithm and its internals. More...
 
class  SourceClusterColumnViewT
 
struct  KeyTuple
 A three-element tuple of mean, uncertainty, and count keys. More...
 
class  SourceClusterRecord
 Record class that contains measurement averages on clusters of single exposure sources. More...
 
class  SourceClusterTable
 Table class that contains measurement means on clusters of single exposure sources. More...
 
class  SourceClusterIdFactory
 
struct  SourceProcessingControl
 Parameters for source processing. More...
 

Typedefs

typedef
SourceClusterColumnViewT
< SourceClusterRecord
SourceClusterColumnView
 
typedef
lsst::afw::table::SortedCatalogT
< SourceClusterRecord
SourceClusterCatalog
 
typedef
lsst::afw::table::SortedCatalogT
< SourceClusterRecord const > 
ConstSourceClusterCatalog
 

Functions

boost::shared_ptr< std::vector
< SourceAndExposure > > const 
computeBasicAttributes (SourceClusterRecord &cluster, SourceCatalog const &sources, ExposureInfoMap const &exposures, std::string const &exposurePrefix)
 
void computeFluxMean (SourceClusterRecord &cluster, std::vector< SourceAndExposure > const &sources, std::string const &fluxDef, std::vector< Key< Flag > > const &skipFlags, double fluxScale)
 
void computeShapeMean (SourceClusterRecord &cluster, std::vector< SourceAndExposure > const &sources, std::string const &shapeDef, std::vector< lsst::afw::table::Key< lsst::afw::table::Flag > > const &skipFlags)
 
std::pair< boost::shared_ptr
< SourceTable >, SchemaMapper >
const 
makeOutputSourceTable (SourceTable const &prototype, SourceProcessingControl const &control)
 
boost::shared_ptr
< SourceClusterTable > const 
makeSourceClusterTable (SourceTable const &prototype, boost::shared_ptr< IdFactory > const &idFactory, SourceProcessingControl const &control)
 
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)
 
std::vector< SourceCatalog > const cluster (SourceCatalog const &sources, ClusteringControl const &control)
 
void setClusterFields (SourceCatalog &sources, SourceClusterRecord const &record, SourceProcessingControl const &control)
 
KeyTuple< lsst::afw::table::ShapeaddShapeFields (lsst::afw::table::Schema &schema, std::string const &filter, std::string const &name, std::string const &doc)
 Convenience function to setup fields for shapes. More...
 
KeyTuple< lsst::afw::table::FluxaddFluxFields (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. More...
 
boost::shared_ptr< std::vector
< SourceAndExposure > > const 
computeBasicAttributes (SourceClusterRecord &cluster, lsst::afw::table::SourceCatalog const &sources, lsst::ap::match::ExposureInfoMap const &exposures, std::string const &exposurePrefix)
 
void computeFluxMean (SourceClusterRecord &cluster, std::vector< SourceAndExposure > const &sources, std::string const &fluxDef, std::vector< lsst::afw::table::Key< lsst::afw::table::Flag > > const &skipFlags, double fluxScale)
 
boost::shared_ptr
< SourceClusterTable > const 
makeSourceClusterTable (lsst::afw::table::SourceTable const &prototype, boost::shared_ptr< lsst::afw::table::IdFactory > const &idFactory, SourceProcessingControl const &control)
 
void processSources (lsst::afw::table::SourceCatalog const &expSources, lsst::ap::match::ExposureInfo const &expInfo, lsst::ap::utils::PT1SkyTile const *skyTile, SourceProcessingControl const &control, lsst::afw::table::SchemaMapper const &mapper, lsst::afw::table::SourceCatalog &sources, lsst::afw::table::SourceCatalog &badSources, lsst::afw::table::SourceCatalog &invalidSources)
 
std::vector
< lsst::afw::table::SourceCatalog >
const 
cluster (lsst::afw::table::SourceCatalog const &sources, ClusteringControl const &control)
 
void setClusterFields (lsst::afw::table::SourceCatalog &sources, SourceClusterRecord const &record, SourceProcessingControl const &control)
 

Typedef Documentation

Definition at line 858 of file SourceCluster.h.

Definition at line 857 of file SourceCluster.h.

Definition at line 826 of file SourceCluster.h.

Function Documentation

KeyTuple< lsst::afw::table::Flux > lsst::ap::cluster::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.

Definition at line 435 of file SourceCluster.cc.

441 {
443  KeyTuple<Flux> kt;
444  kt.mean = schema.addField<Flux::MeasTag>(
445  filter + "." + name, doc, unit);
446  kt.err = schema.addField<Flux::ErrTag>(
447  filter + "." + name + ".err",
448  "uncertainty for " + filter + "." + name,
449  unit);
450  kt.count = schema.addField<int>(
451  filter + "." + name + ".count",
452  "Number of samples used to compute the " + filter +
453  "." + name + " mean");
454  return kt;
455 }
Key< T > addField(Field< T > const &field, bool doReplace=false)
Add a new field to the Schema, and return the associated Key.
KeyTuple< lsst::afw::table::Shape > lsst::ap::cluster::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.

Definition at line 414 of file SourceCluster.cc.

419 {
421  KeyTuple<Shape> kt;
422  kt.mean = schema.addField<Shape::MeasTag>(
423  filter + "." + name, doc, "rad^2");
424  kt.err = schema.addField<Shape::ErrTag>(
425  filter + "." + name + ".err",
426  "covariance matrix for " + filter + "." + name,
427  "rad^4");
428  kt.count = schema.addField<int>(
429  filter + "." + name + ".count",
430  "Number of samples used to compute the " + filter +
431  "." + name + " mean");
432  return kt;
433 }
afw::geom::ellipses::Quadrupole Shape
Definition: constants.h:58
Key< T > addField(Field< T > const &field, bool doReplace=false)
Add a new field to the Schema, and return the associated Key.
std::vector<lsst::afw::table::SourceCatalog> const lsst::ap::cluster::cluster ( lsst::afw::table::SourceCatalog const &  sources,
ClusteringControl const &  control 
)

Spatially cluster sources using the OPTICS algorithm. For details, see the following paper:

"OPTICS: Ordering Points To Identify the Clustering Structure". Mihael Ankerst, Markus M. Breunig, Hans-Peter Kriegel, Jorg Sander (1999). ACM SIGMOD international conference on Management of data. ACM Press. pp. 49-60.

http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.129.6542 http://en.wikipedia.org/wiki/OPTICS_algorithm

Parameters
[in]sourcesSources to cluster.
[in]controlClustering parameters.
std::vector<SourceCatalog> const lsst::ap::cluster::cluster ( SourceCatalog const &  sources,
ClusteringControl const &  control 
)

Definition at line 578 of file clustering.cc.

581 {
582  typedef SourceCatalog::const_iterator Iter;
583 
584  if (sources.size() > MAX_SOURCES) {
585  throw LSST_EXCEPT(InvalidParameterError, "too many sources to cluster");
586  }
587  control.validate();
588  boost::scoped_array<OpticsPoint> entries(new OpticsPoint[sources.size()]);
589  std::vector<SourceCatalog> clusters;
590  int i = 0;
591  for (Iter s = sources.begin(), e = sources.end(); s != e; ++s, ++i) {
592  entries[i].coords = s->getCoord().getVector().asEigen();
593  entries[i].data = s;
594  }
595  if (i > 0) {
596  // Convert epsilon and leafExtentThreshold to radians, and account
597  // for the fact that our metric is the squared euclidian distance,
598  // not angular separation.
599  double eps = std::sin(0.5 * control.getEpsilon().asRadians());
600  eps = 4.0 * eps * eps;
601  double let = control.getLeafExtentThreshold().asRadians();
602  if (let > 0.0) {
603  let = std::sin(0.5 * let);
604  let = 4.0 * let * let;
605  }
606  Optics optics(entries.get(), i, control.minNeighbors, eps, let, control.pointsPerLeaf);
607  optics.run(sources.getTable(), clusters, detail::SquaredEuclidianDistanceOverSphere());
608  }
609  return clusters;
610 }
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
boost::shared_ptr<std::vector<SourceAndExposure> > const lsst::ap::cluster::computeBasicAttributes ( SourceClusterRecord &  cluster,
lsst::afw::table::SourceCatalog const &  sources,
lsst::ap::match::ExposureInfoMap const &  exposures,
std::string const &  exposurePrefix 
)

Compute basic cluster attributes.

The Coord slot of cluster is set to the unweighted mean of the coordinates of the associated sources. This fiducial cluster position is used as the center of a N,E tangent plane projection that serves as a common coordinate system for averaging other measurements. Exposure information for each input source is looked up, and used to create a vector of tuples that bundle a source with it's originating exposure and an affine transform from the pixel space coordinate system centered on the source's centroid to the common coordinate system.

This vector of tuples is sorted such that sources originating from exposures in the same filter are all consecutive.

Finally, several other cluster attributes are computed/set:

  • "obs.count" : number of sources in the cluster
  • "obs.time.min", "obs.time.max", "obs.time.mean" : observation time range
  • "coord.weighted", "coord.weighted.err", "coord.weighted.count" : inverse variance weighted mean coordinate, error, and sample count (computed only if input sources have a valid CoordErr slot mapping).
  • "\<filter\>.obs.count" : filter specific source count
  • "\<filter\>.time.min", "\<filter\>.time.max" : filter specific observation time range
Parameters
[out]clusterSourceClusterRecord to store results in.
[in]sourcesSources in cluster.
[in]exposuresMap from exposure ID to exposure information.
[in]exposurePrefixExposure column name prefix.
Returns
A list of (source, exposure information, transform) tuples, grouped by filter.
boost::shared_ptr<std::vector<SourceAndExposure> > const lsst::ap::cluster::computeBasicAttributes ( SourceClusterRecord &  cluster,
SourceCatalog const &  sources,
ExposureInfoMap const &  exposures,
std::string const &  exposurePrefix 
)

Definition at line 334 of file attributes.cc.

339 {
340  typedef SourceCatalog::const_iterator SourceIter;
341  typedef std::vector<SourceAndExposure>::const_iterator SeIter;
342 
343  if (sources.empty()) {
344  throw LSST_EXCEPT(InvalidParameterError, "No sources in cluster");
345  }
346  // unweighted mean coordinates
347  meanCoord(cluster, sources);
348 
349  boost::shared_ptr<std::vector<SourceAndExposure> > se(
350  new std::vector<SourceAndExposure>);
351  NeTanProj const proj(cluster.getCoord());
352  Schema const schema = sources.getSchema();
353  Key<int64_t> const expIdKey = schema.find<int64_t>(exposurePrefix + ".id").key;
354  Key<double> const expTimeMidKey = schema.find<double>(exposurePrefix + ".time.mid").key;
355  // fill in vector of source,exposure pairs
356  se->reserve(sources.size());
357  for (SourceIter i = sources.begin(), e = sources.end(); i != e; ++i) {
358  boost::shared_ptr<ExposureInfo> exp =
359  const_cast<ExposureInfoMap &>(exposures).get(i->get(expIdKey));
360  if (!exp) {
361  throw LSST_EXCEPT(NotFoundError, "No ExposureInfo for source");
362  }
363  se->push_back(SourceAndExposure(
364  i, exp, proj.pixelToNeTransform(i->getCentroid().asEigen(), *exp->getWcs())));
365  }
366  // source counts and observation time range
367  StatTuple t;
368  t.compute(se->begin(), se->end(), expTimeMidKey);
369  cluster.setNumSources(static_cast<int>(sources.size()));
370  cluster.setTimeMin(t.min);
371  cluster.setTimeMean(t.mean);
372  cluster.setTimeMax(t.max);
373  // inverse variance weighted mean coordinates
374  if (sources.getTable()->getCentroidKey().isValid() &&
375  sources.getTable()->getCentroidErrKey().isValid()) {
376  weightedMeanCoord(cluster, *se, proj);
377  }
378  // sort source,exposure vector by filter
379  std::sort(se->begin(), se->end(), CmpSourceAndExposure());
380  // per-filter source counts and observation time range
381  SeIter i = se->begin();
382  SeIter const e = se->end();
383  while (i != e) {
384  int const filterId = i->getExposureInfo()->getFilter().getId();
385  SeIter j = i;
386  for (++j; j != e && filterId == j->getExposureInfo()->getFilter().getId(); ++j) { }
387  std::string const filterName = i->getExposureInfo()->getFilter().getName();
388  cluster.setNumSources(filterName, static_cast<int>(j - i));
389  t.compute(i, j, expTimeMidKey);
390  cluster.setTimeMin(filterName, t.min);
391  cluster.setTimeMax(filterName, t.max);
392  i = j;
393  }
394  return se;
395 }
Defines the fields and offsets for a table.
Definition: Schema.h:46
std::vector< SourceCatalog > const cluster(SourceCatalog const &sources, ClusteringControl const &control)
Definition: clustering.cc:578
tbl::Schema schema
Definition: CoaddPsf.cc:324
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
A class used as a handle to a particular field in a table.
Definition: fwd.h:44
void lsst::ap::cluster::computeFluxMean ( SourceClusterRecord &  cluster,
std::vector< SourceAndExposure > const &  sources,
std::string const &  fluxDef,
std::vector< lsst::afw::table::Key< lsst::afw::table::Flag > > const &  skipFlags,
double  fluxScale 
)

Compute per-filter calibrated flux means for a cluster of sources.

The input source vector is assumed to be grouped by filter. Flux measurments and errors are obtained from fields named '<fluxDef>' and '<fluxDef>.err'. Results are stored in fields named '<filter>.<fluxDef>' and '<filter>.<fluxDef>.err', with a sample count stored in '<filter>.<fluxDef>.count' field. For an input source to be included in the mean, the following must hold:

  • the source must have finite flux
  • the source must have positive flux error
  • none of the flag fields in skipFlags must be set.

If, after applying these filtering critera, 2 or more flux samples are available, then the inverse variance weighted mean of the samples (after calibration) is computed and stored. If only one sample is available, the input flux and error are calibrated and stored directly. If no samples are available, the output flux, error, and sample count fields are set to NaN, NaN, and 0.

Parameters
[out]clusterCluster to store results in.
[in]sourcesList of sources and their exposures.
[in]fluxDefName of flux field to operate on.
[in]skipFlagsFlags marking sources to skip.
[in]fluxScaleFlux scaling factor.
void lsst::ap::cluster::computeFluxMean ( SourceClusterRecord &  cluster,
std::vector< SourceAndExposure > const &  sources,
std::string const &  fluxDef,
std::vector< Key< Flag > > const &  skipFlags,
double  fluxScale 
)

Definition at line 439 of file attributes.cc.

445 {
446  typedef std::vector<SourceAndExposure>::const_iterator Iter;
447  typedef std::vector<Key<Flag > >::const_iterator FlagIter;
448 
449  if (sources.empty()) {
450  throw LSST_EXCEPT(InvalidParameterError, "No sources in cluster");
451  }
452  Schema const sourceSchema = sources[0].getSource()->getSchema();
453  Schema const clusterSchema = cluster.getSchema();
454  Flux::MeasKey const sourceFluxKey = sourceSchema[fluxDef];
455  Flux::ErrKey const sourceFluxErrKey = sourceSchema[fluxDef + ".err"];
456 
457  Iter i = sources.begin();
458  Iter const e = sources.end();
459  while (i != e) {
460  // Determine range [i, j) containing sources from the same filter
461  int const filterId = i->getExposureInfo()->getFilter().getId();
462  Iter j = i;
463  for (++j; j != e && filterId == j->getExposureInfo()->getFilter().getId(); ++j) { }
464  // iterate over [i, j), storing all valid flux/error pairs
465  // after calibrating them.
466  std::vector<FluxAndVariance> samples;
467  samples.reserve(j - i);
468  std::string const filter = i->getExposureInfo()->getFilter().getName();
469  for (; i < j; ++i) {
470  SourceRecord const * r = i->getSource().get();
471  double flux = r->get(sourceFluxKey);
472  double fluxErr = r->get(sourceFluxErrKey);
473  if (!lsst::utils::isfinite(flux) || lsst::utils::isnan(fluxErr) || fluxErr <= 0.0) {
474  continue;
475  }
476  bool skip = false;
477  for (FlagIter f = skipFlags.begin(), fe = skipFlags.end(); f != fe; ++f) {
478  if (r->get(*f)) {
479  skip = true;
480  break;
481  }
482  }
483  if (skip) {
484  continue;
485  }
486  samples.push_back(i->getExposureInfo()->calibrateFlux(flux, fluxErr, fluxScale));
487  }
488  FluxAndErr mean = weightedMeanFlux(samples);
489  Flux::MeasKey const measKey = clusterSchema[filter + "." + fluxDef];
490  cluster.set(measKey, mean.first);
491  Flux::ErrKey const errKey = clusterSchema[filter + "." + fluxDef + ".err"];
492  cluster.set(errKey, mean.second);
493  Key<int> const countKey = clusterSchema[filter + "." + fluxDef + ".count"];
494  cluster.set(countKey, static_cast<int>(samples.size()));
495  }
496 }
Defines the fields and offsets for a table.
Definition: Schema.h:46
std::vector< SourceCatalog > const cluster(SourceCatalog const &sources, ClusteringControl const &control)
Definition: clustering.cc:578
int isnan(T t)
Definition: ieee.h:110
Field< T >::Value get(Key< T > const &key) const
Return the value of a field for the given key.
Definition: BaseRecord.h:123
double mean
Definition: attributes.cc:217
int isfinite(T t)
Definition: ieee.h:100
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
A class used as a handle to a particular field in a table.
Definition: fwd.h:44
Record class that contains measurements made on a single exposure.
Definition: Source.h:81
void lsst::ap::cluster::computeShapeMean ( SourceClusterRecord &  cluster,
std::vector< SourceAndExposure > const &  sources,
std::string const &  shapeDef,
std::vector< lsst::afw::table::Key< lsst::afw::table::Flag > > const &  skipFlags 
)

Compute per-filter shape means for a cluster.

The input source vector is assumed to be grouped by filter. Shape measurments and errors are obtained from fields named '<shapeDef>' and '<shapeDef>.err'. Results are stored in fields named '<filter>.<shapeDef>' and '<filter>.<shapeDef>.err', with a sample count stored in '<filter>.<shapeDef>.count' field. For an input source to be included in the mean, the following must hold:

  • the source must have finite moments
  • the source must have positive entries in the covariance matrix diagonals
  • off diagonal elements of the covariance matrix must not be NaN
  • the covariance matrix must be symmetric.
  • none of the flag fields in skipFlags must be set.

If, after applying these filtering critera, 2 or more shape samples are available, then the inverse variance weighted mean of the samples (after transformation to a coordinate system S centered on the cluster position with the standard N,E basis) is computed and stored. If only one sample is available, the input shape and error are transformed to S and stored directly. If no samples are available, the output moments and covariance matrix are set to NaNs, and the sample count is zeroed.

Parameters
[out]clusterCluster to store results in.
[in]sourcesList of sources and their exposures.
[in]shapeDefName of shape field to operate on.
[in]skipFlagsFlags marking sources to skip.

Definition at line 535 of file attributes.cc.

540 {
541  typedef std::vector<SourceAndExposure>::const_iterator Iter;
542  typedef std::vector<Key<Flag > >::const_iterator FlagIter;
543 
544  if (sources.empty()) {
545  throw LSST_EXCEPT(InvalidParameterError, "No sources in cluster");
546  }
547  Schema const sourceSchema = sources[0].getSource()->getSchema();
548  Schema const clusterSchema = cluster.getSchema();
549  Shape::MeasKey const sourceShapeKey = sourceSchema[shapeDef];
550  Shape::ErrKey const sourceShapeErrKey = sourceSchema[shapeDef + ".err"];
551 
552  Iter i = sources.begin();
553  Iter const e = sources.end();
554  while (i != e) {
555  // Determine range [i, j) containing sources from the same filter
556  int const filterId = i->getExposureInfo()->getFilter().getId();
557  Iter j = i;
558  for (++j; j != e && filterId == j->getExposureInfo()->getFilter().getId(); ++j) { }
559  // iterate over [i, j) storing all valid shape/error pairs in samples
560  std::vector<ShapeAndErr> samples;
561  samples.reserve(j - i);
562  std::string const filter = i->getExposureInfo()->getFilter().getName();
563  for (; i < j; ++i) {
564  SourceRecord const * r = i->getSource().get();
565  bool skip = false;
566  for (FlagIter f = skipFlags.begin(), fe = skipFlags.end(); f != fe; ++f) {
567  if (r->get(*f)) {
568  skip = true;
569  break;
570  }
571  }
572  if (skip) {
573  continue;
574  }
575  Quadrupole q = r->get(sourceShapeKey);
576  if (!lsst::utils::isfinite(q.getIxx()) ||
579  continue; // shape contains NaNs
580  }
581  Eigen::Matrix3d cov = r->get(sourceShapeErrKey).cast<double>();
582  if (lsst::utils::isnan(cov(0,0)) ||
583  lsst::utils::isnan(cov(1,1)) ||
584  lsst::utils::isnan(cov(2,2))) {
585  continue; // covariance matrix contains NaNs
586  } else if (cov(0,0) <= 0.0 ||
587  cov(1,1) <= 0.0 ||
588  cov(2,2) <= 0.0) {
589  continue; // negative variance
590  }
591  // FIXME: for now, no measurement algorithms actually
592  // compute full covariance matrixes, and the
593  // off diagonal matrix elements are always NaN.
594  // Longer term, we will need some algorithm metadata
595  // to decide whether an off-diagonal NaN means a
596  // sample should be ignored because a computation failed,
597  // or whether it should be zeroed because the algorithm
598  // never computes it.
599  if (cov(0,1) != cov(1,0) || cov(0,2) != cov(2,0) || cov(1,2) != cov(2,1)) {
600  if (lsst::utils::isnan(cov(0,1)) && lsst::utils::isnan(cov(1,0)) &&
601  lsst::utils::isnan(cov(0,2)) && lsst::utils::isnan(cov(2,0)) &&
602  lsst::utils::isnan(cov(1,2)) && lsst::utils::isnan(cov(2,1))) {
603  cov(0,1) = 0.0; cov(1,0) = 0.0;
604  cov(0,2) = 0.0; cov(2,0) = 0.0;
605  cov(1,2) = 0.0; cov(2,1) = 0.0;
606  } else {
607  continue; // covariance matrix not symmetric
608  }
609  }
610  // transform moments and covariance matrix to N,E basis
611  LinearTransform const * xform = &(i->getTransform().getLinear());
612  Eigen::Matrix3d j = q.transform(*xform).d();
613  q.transform(*xform).inPlace();
614  cov = j * cov * j.transpose();
615  samples.push_back(ShapeAndErr(q, cov));
616  }
617  ShapeAndErr mean;
618  weightedMeanShape(mean, samples);
619  Shape::MeasKey const measKey = clusterSchema[filter + "." + shapeDef];
620  cluster.set(measKey, mean.first);
621  Shape::ErrKey const errKey = clusterSchema[filter + "." + shapeDef + ".err"];
622  cluster.set(errKey, mean.second);
623  Key<int> const countKey = clusterSchema[filter + "." + shapeDef + ".count"];
624  cluster.set(countKey, static_cast<int>(samples.size()));
625  }
626 }
An ellipse core with quadrupole moments as parameters.
Definition: Quadrupole.h:45
Defines the fields and offsets for a table.
Definition: Schema.h:46
DerivativeMatrix d() const
Return the derivative of transformed core with respect to input core.
std::vector< SourceCatalog > const cluster(SourceCatalog const &sources, ClusteringControl const &control)
Definition: clustering.cc:578
double const getIyy() const
Definition: Quadrupole.h:59
int isnan(T t)
Definition: ieee.h:110
void inPlace()
Transform the ellipse core in-place.
Field< T >::Value get(Key< T > const &key) const
Return the value of a field for the given key.
Definition: BaseRecord.h:123
A 2D linear coordinate transformation.
double mean
Definition: attributes.cc:217
double const getIxx() const
Definition: Quadrupole.h:56
int isfinite(T t)
Definition: ieee.h:100
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
A class used as a handle to a particular field in a table.
Definition: fwd.h:44
Transformer transform(LinearTransform const &transform)
Definition: Transformer.h:117
double const getIxy() const
Definition: Quadrupole.h:62
Record class that contains measurements made on a single exposure.
Definition: Source.h:81
std::pair< boost::shared_ptr< lsst::afw::table::SourceTable >, lsst::afw::table::SchemaMapper > const lsst::ap::cluster::makeOutputSourceTable ( lsst::afw::table::SourceTable const &  prototype,
SourceProcessingControl const &  control 
)
Create an output source table based on a prototypical input source table.
The schema and slot mappings from the input table are used as is, and exposure
related fields, required for database ingestion / clustering, are added.

In particular, the following additions are performed:

    - "coord.err"             (CovPointD) : Source sky-coordinate error
    - "<exposure>.id"         (L)         : ID of exposure source was measured on.

i * - "<cluster>.id" (L) : ID of cluster containing source.

  • "<cluster>.coord" (Coord) : ICRS coordinates of cluster containing source.

If the control.multiBand config parameter is false:

  • "<exposure>.filter.id" (I) : ID of filter for exposure.

If the control.coadd config parameter is false:

  • "<exposure>.time" (F) : Exposure time (s).
  • "<exposure>.time.mid" (D) : Middle of exposure time (MJD).

"<exposure>" and "<cluster>" are field name prefixes obtained from SourceProcessingControl. If either prefix is empty, the corresponding fields will not be added. Note however that the exposure related fields are necessary for attribute computation and database ingest into the LSST schema. The cluster related fields are required only for database ingest.

Parameters
[in]prototypePrototypical schema/slot mappings.
[in]controlSource processing parameters.
Returns
An output SourceTable and a SchemaMapper that can be used to copy common field values between input and output records.

Definition at line 135 of file clustering.cc.

138 {
139  if (!prototype.getCoordKey().isValid() ||
140  !prototype.getCentroidKey().isValid()) {
141  throw LSST_EXCEPT(InvalidParameterError, "Prototypical "
142  "SourceCatalog must have valid Coord and Centroid fields");
143  }
144  SchemaMapper mapper(prototype.getSchema());
145  // add all fields in the input schema to the output schema.
146  mapper.addMappingsWhere(True());
147  // add coordinate error
148  mapper.addOutputField(Field<Covariance<lsst::afw::table::Point<float> > >(
149  "coord.err",
150  "covariance matrix for source sky-coordinates",
151  "rad^2"));
152  if (!control.exposurePrefix.empty()) {
153  // add exposure related fields
154  mapper.addOutputField(Field<int64_t>(
155  control.exposurePrefix + ".id",
156  "ID of exposure source was measured on"));
157  if (!control.multiBand) {
158  mapper.addOutputField(Field<int>(
159  control.exposurePrefix + ".filter.id",
160  "ID of filter for exposure"));
161  }
162  if (!control.coadd) {
163  mapper.addOutputField(Field<float>(
164  control.exposurePrefix + ".time",
165  "exposure time",
166  "s"));
167  mapper.addOutputField(Field<double>(
168  control.exposurePrefix + ".time.mid",
169  "middle of exposure time",
170  "mjd"));
171  }
172  }
173  if (!control.clusterPrefix.empty()) {
174  // add cluster related fields
175  mapper.addOutputField(Field<int64_t>(
176  control.clusterPrefix + ".id",
177  "ID of cluster containing source; 0 if source is not assigned to any cluster."));
178  mapper.addOutputField(Field<lsst::afw::table::Coord>(
179  control.clusterPrefix + ".coord",
180  "ICRS sky-coordinates of cluster containing source",
181  "rad"));
182  }
183  boost::shared_ptr<SourceTable> table =
184  SourceTable::make(mapper.getOutputSchema(), boost::shared_ptr<IdFactory>());
185  // copy slot mappings from prototype
186  table->definePsfFlux(prototype.getPsfFluxDefinition());
187  table->defineModelFlux(prototype.getModelFluxDefinition());
188  table->defineApFlux(prototype.getApFluxDefinition());
189  table->defineInstFlux(prototype.getInstFluxDefinition());
190  table->defineCentroid(prototype.getCentroidDefinition());
191  table->defineShape(prototype.getShapeDefinition());
192 
193  return std::make_pair(table, mapper);
194 }
A mapping between the keys of two Schemas, used to copy data between them.
Definition: SchemaMapper.h:19
A description of a field in a table.
Definition: Field.h:22
void addMappingsWhere(Predicate predicate, bool doReplace=true)
Add mappings for all fields that match criteria defined by a predicate.
Definition: SchemaMapper.h:225
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
Tag types used to declare specialized field types.
Definition: misc.h:35
boost::shared_ptr<SourceClusterTable> const lsst::ap::cluster::makeSourceClusterTable ( lsst::afw::table::SourceTable const &  prototype,
boost::shared_ptr< lsst::afw::table::IdFactory > const &  idFactory,
SourceProcessingControl const &  control 
)

Create a source cluster table based on a prototypical input source table. The names of flux/shape fields from SourceProcessingControl which correspond to fields in the prototype are used to create flux/shape fields for every filter that has been defined via the lsst::afw::image::Filter API. Slots from the prototype are used to setup corresponding filter specific slots in the source cluster table.

Note that filters are typically defined by the data butler's mapper class (see e.g. the obs_lsstSim package). The names of flux/shape fields in the cluster schema are prefixed with filter names - for example, if the PSF flux slot in the prototype is mapped to a field named "flux.naive" and filters "u" and "g" are defined, then the cluster schema will contain fields "u.flux.naive" and "g.flux.naive", with filter specific PSF flux slots mapped accordingly.

The following additional fields will be created (names not configurable at the moment):

- "id"                  (L)         : cluster ID (from minimal schema)
- "coord"               (Coord)     : mean sky-coordinates (from minimal schema)
- "coord.err"           (CovPointD) : uncertainty of coord
- "obs.count"           (I)         : number of sources in cluster
- "flag.noise"          (Flag)      : was cluster created from a single noise source?
- "<filter>.obs.count"  (I)         : numer of sources in a specific filter

If the input table has valid centroid and centroid error slot keys, then the following fields are added:

- "coord.weightedmean"       (Coord)     : inverse variance weighted mean sky-coordinates
- "coord.weightedmean.err"   (CovPointD) : covariance matrix for coord.weighted
- "coord.weightedmean.count" (I)         : number of samples included in "coord.weighted"

Finally, if the "<exposure>.time.mid" field exists in the input table, then:

- "obs.time.min"          (D)       : earliest observation time of sources in cluster
- "obs.time.mean"         (D)       : mean observation time of sources in cluster
- "obs.time.max"          (D)       : latest observation time of sources in cluster
- "<filter>.obs.time.min" (D)       : earliest observation time in a specific filter
- "<filter>.obs.time.max" (D)       : latest observation time in a specific filter

are added (where the "<exposure>" prefix is obtained from SourceProcessingControl).

Parameters
[in]prototypePrototypical schema/slot mappings.
[in]idFactoryID generator.
[in]controlSource processing parameters.
Returns
A SourceClusterTable corresponding to clusters of sources having the given prototypical schema and slots.
boost::shared_ptr<SourceClusterTable> const lsst::ap::cluster::makeSourceClusterTable ( SourceTable const &  prototype,
boost::shared_ptr< IdFactory > const &  idFactory,
SourceProcessingControl const &  control 
)

Definition at line 197 of file clustering.cc.

201 {
202  typedef std::vector<std::string>::const_iterator Iter;
203 
204  Schema schema = SourceClusterTable::makeMinimalSchema();
205  schema.setVersion(0);
206  // Add basic fields
208  "coord.err",
209  "sample covariance matrix for coord field (unweighted mean sky-coordinates)",
210  "rad^2");
211  schema.addField<int>(
212  "obs.count",
213  "number of sources in cluster");
214  schema.addField<Flag>(
215  "flag.noise",
216  "set if cluster was created from a single noise source");
217  if (prototype.getCentroidKey().isValid() &&
218  prototype.getCentroidErrKey().isValid()) {
220  "coord.weightedmean",
221  "inverse variance weighted mean sky-coordinates (ICRS)",
222  "rad");
224  "coord.weightedmean.err",
225  "covariance matrix for coord.weightedmean field",
226  "rad^2");
227  schema.addField<int>(
228  "coord.weightedmean.count",
229  "number of samples used to compute coord.weightedmean");
230  }
231  if (!control.exposurePrefix.empty()) {
232  schema.addField<double>(
233  "obs.time.min",
234  "earliest observation time of sources in cluster (TAI)",
235  "mjd");
236  schema.addField<double>(
237  "obs.time.mean",
238  "mean observation time of sources in cluster (TAI)",
239  "mjd");
240  schema.addField<double>(
241  "obs.time.max",
242  "latest observation time of sources in cluster (TAI)",
243  "mjd");
244  }
245  std::vector<std::string> filters = Filter::getNames();
246  // Sort filter names by ID so that fields are added in a consistent order
247  std::sort(filters.begin(), filters.end(), FilterNameCmp());
248  // Add filter specific fields
249  for (Iter filt = filters.begin(), eFilt = filters.end(); filt != eFilt; ++filt) {
250  schema.addField<int>(
251  *filt + ".obs.count",
252  "number of " + *filt + "-filter sources in cluster");
253  if (!control.exposurePrefix.empty()) {
254  schema.addField<double>(
255  *filt + ".obs.time.min",
256  "earliest observation time of " + *filt + "-filter sources in cluster (TAI)",
257  "mjd");
258  schema.addField<double>(
259  *filt + ".obs.time.max",
260  "latest observation time of " + *filt + "-filter sources in cluster (TAI)",
261  "mjd");
262  }
263  for (Iter flux = control.fluxFields.begin(), eFlux = control.fluxFields.end();
264  flux != eFlux; ++flux) {
265  if (hasFluxField(prototype.getSchema(), *flux)) {
266  addFlux(schema, prototype.getSchema(), *filt, *flux, control.fluxUnit);
267  }
268  }
269  for (Iter shape = control.shapeFields.begin(), eShape = control.shapeFields.end();
270  shape != eShape; ++shape) {
271  if (hasShapeField(prototype.getSchema(), *shape)) {
272  addShape(schema, prototype.getSchema(), *filt, *shape);
273  }
274  }
275  }
276 
277  // Create table
278  boost::shared_ptr<SourceClusterTable> table =
279  SourceClusterTable::make(schema, idFactory);
280 
281  // setup slot mappings
282  table->defineCoordErr("coord.err");
283  table->defineNumSources("obs.count");
284  if (prototype.getCentroidKey().isValid() &&
285  prototype.getCentroidErrKey().isValid()) {
286  table->defineWeightedMeanCoord("coord.weightedmean");
287  table->defineWeightedMeanCoordErr("coord.weightedmean.err");
288  table->defineWeightedMeanCoordCount("coord.weightedmean.count");
289  }
290  if (!control.exposurePrefix.empty()) {
291  table->defineTimeMin("obs.time.min");
292  table->defineTimeMean("obs.time.mean");
293  table->defineTimeMax("obs.time.max");
294  }
295  for (Iter filt = filters.begin(), eFilt = filters.end();
296  filt != eFilt; ++filt) {
297  table->defineNumSources(*filt, "obs.count");
298  if (!control.exposurePrefix.empty()) {
299  table->defineTimeMin(*filt, "obs.time.min");
300  table->defineTimeMax(*filt, "obs.time.max");
301  }
302  Iter flux = control.fluxFields.begin(), eFlux = control.fluxFields.end();
303  if (prototype.getPsfFluxKey().isValid() &&
304  prototype.getPsfFluxErrKey().isValid()) {
305  std::string def = prototype.getPsfFluxDefinition();
306  if (std::find(flux, eFlux, def) != eFlux) {
307  table->definePsfFlux(*filt, def);
308  }
309  }
310  if (prototype.getModelFluxKey().isValid() &&
311  prototype.getModelFluxErrKey().isValid()) {
312  std::string def = prototype.getModelFluxDefinition();
313  if (std::find(flux, eFlux, def) != eFlux) {
314  table->defineModelFlux(*filt, def);
315  }
316  }
317  if (prototype.getApFluxKey().isValid() &&
318  prototype.getApFluxErrKey().isValid()) {
319  std::string def = prototype.getApFluxDefinition();
320  if (std::find(flux, eFlux, def) != eFlux) {
321  table->defineApFlux(*filt, def);
322  }
323  }
324  if (prototype.getInstFluxKey().isValid() &&
325  prototype.getInstFluxErrKey().isValid()) {
326  std::string def = prototype.getInstFluxDefinition();
327  if (std::find(flux, eFlux, def) != eFlux) {
328  table->defineInstFlux(*filt, def);
329  }
330  }
331  if (prototype.getShapeKey().isValid() &&
332  prototype.getShapeErrKey().isValid()) {
333  std::string def = prototype.getShapeDefinition();
334  Iter shape = control.shapeFields.begin(), eShape = control.shapeFields.end();
335  if (std::find(shape, eShape, def) != eShape) {
336  table->defineShape(*filt, def);
337  }
338  }
339  }
340  return table;
341 }
Defines the fields and offsets for a table.
Definition: Schema.h:46
tbl::Schema schema
Definition: CoaddPsf.cc:324
void setVersion(int version)
Set the table&#39;s version.
Definition: Schema.h:325
Key< T > addField(Field< T > const &field, bool doReplace=false)
Add a new field to the Schema, and return the associated Key.
void lsst::ap::cluster::processSources ( lsst::afw::table::SourceCatalog const &  expSources,
lsst::ap::match::ExposureInfo const &  expInfo,
lsst::ap::utils::PT1SkyTile const *  skyTile,
SourceProcessingControl const &  control,
lsst::afw::table::SchemaMapper const &  mapper,
lsst::afw::table::SourceCatalog sources,
lsst::afw::table::SourceCatalog badSources,
lsst::afw::table::SourceCatalog invalidSources 
)

Process input sourcees, distributing them to one of 3 output catalogs.

  • sources: sources suitable for spatial clustering.
  • badSources: sources ignored for the purposes of clustering; identified by one or more flags.
  • invalidSources: sources which do not have sky-coordinates or centroids.

Sources not lying in the given sky-tile are discarded. Note that one can pass in a NULL sky-tile pointer, in which case no sources are discarded.

Existing fields in the input sources are modified as follows:

  • source footprints are discarded
  • source sky-coordinate errors are computed and added
  • exposure information (ID, filter ID, etc...) is added to each source.
  • the cluster coordinates for a source are set to the source coordinates.

The output catalogs will typically have been constructed from tables obtained via makeOutputSourceTable() - their schemas and slot mappings must all be identical. The input table slots must match output table slots, and the input schema must be fully contained in the output schema.

Parameters
[in]expSourcesSingle exposure sources to process.
[in]expInfoExposure information.
[in]skyTileSky-tile being processed - may be NULL.
[in]controlSource processing parameters.
[in]mapperMaps between input and output source records.
[out]sourcesCatalog for sources that will be clustered.
[out]badSourcesCatalog for sources with bad measurement flags.
[out]invalidSourcesCatalog for sources with invalid measurements.
void lsst::ap::cluster::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 
)

Definition at line 375 of file clustering.cc.

384 {
385  typedef std::vector<std::string>::const_iterator StringIter;
386  typedef std::vector<Key<Flag> >::const_iterator FlagKeyIter;
387  typedef SourceCatalog::const_iterator SourceIter;
388 
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()));
392 
393  // Validate that schemas and slots match as expected
394  if (sources.getSchema() != badSources.getSchema() ||
395  sources.getSchema() != invalidSources.getSchema()) {
396  throw LSST_EXCEPT(InvalidParameterError, "output "
397  "SourceCatalog schema mismatch");
398  }
399  if (!sources.getSchema().contains(expSources.getSchema())) {
400  throw LSST_EXCEPT(InvalidParameterError, "output SourceCatalog "
401  "schema does not contain input SourceCatalog schema");
402  }
403  if (mapper.getInputSchema() != expSources.getSchema()) {
404  throw LSST_EXCEPT(InvalidParameterError, "SchemaMapper and "
405  "input source catalog disagree on input schema.");
406  }
407  if (mapper.getOutputSchema() != sources.getSchema()) {
408  throw LSST_EXCEPT(InvalidParameterError, "SchemaMapper and "
409  "output source catalogs disagree on output schema.");
410  }
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");
416  }
417 
418  // Construct bad source flag key vector
419  std::vector<Key<Flag> > badKeys;
420  for (StringIter i = control.badFlagFields.begin(),
421  e = control.badFlagFields.end(); i != e; ++i) {
422  badKeys.push_back(expSources.getSchema().find<Flag>(*i).key);
423  }
424  // Extract exposure X/Y bounds relative to parent exposure (if there is one).
425  // This is because centroids of coadd-sources are in the pixel coordinate system
426  // of the tract exposure containing the patch they were measured on, NOT in
427  // the pixel coordinate system of the patch.
428  double const xMin = indexToPosition(expInfo.getX0()) - 0.5;
429  double const yMin = indexToPosition(expInfo.getY0()) - 0.5;
430  double const xMax = indexToPosition(expInfo.getX0() + expInfo.getWidth() - 1) + 0.5;
431  double const yMax = indexToPosition(expInfo.getY0() + expInfo.getHeight() - 1) + 0.5;
432 
433  // Set up keys to additional fields
434  Key<int64_t> expIdKey;
435  Key<int> expFilterIdKey;
436  Key<float> expTimeKey;
437  Key<double> expTimeMidKey;
438  afw::table::CovarianceMatrixKey<float,2> centroidErrKey =
439  sources.getTable()->getCentroidErrKey();
441  Key<lsst::afw::coord::Coord> clusterCoordKey;
442  try {
443  coordErrKey = sources.getSchema()["coord.err"];
444  } catch (NotFoundError &) {
445  // no easy way to ask whether a field exists by name?
446  }
447  if (!control.exposurePrefix.empty()) {
448  Schema schema = mapper.getOutputSchema();
449  expIdKey = schema[control.exposurePrefix + ".id"];
450  if (!control.multiBand) {
451  expFilterIdKey = schema[control.exposurePrefix + ".filter.id"];
452  }
453  if (!control.coadd) {
454  expTimeKey = schema[control.exposurePrefix + ".time"];
455  expTimeMidKey = schema[control.exposurePrefix + ".time.mid"];
456  }
457  }
458  if (!control.clusterPrefix.empty()) {
459  Schema schema = mapper.getOutputSchema();
460  clusterCoordKey = schema[control.clusterPrefix + ".coord"];
461  }
462  size_t ngood = 0, nbad = 0, ninvalid = 0, noutside = 0;
463  // Loop over input sources
464  for (SourceIter s = expSources.begin(), es = expSources.end(); s != es; ++s) {
465  // Check source validity
466  bool invalid = false;
467  double x = s->getX();
468  double y = s->getY();
469  if (lsst::utils::isnan(x) || lsst::utils::isnan(y)) {
470  log.format(Log::WARN, "Centroid of source %lld contains NaNs",
471  static_cast<long long>(s->getId()));
472  invalid = true;
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()));
476  invalid = true;
477  } else if (lsst::utils::isnan(s->getRa().asRadians()) ||
478  lsst::utils::isnan(s->getDec().asRadians())) {
479  log.format(Log::WARN, "Sky-coord of source %lld contains NaNs",
480  static_cast<long long>(s->getId()));
481  invalid = true;
482  }
483  if (!invalid && skyTile && !skyTile->contains(s->getCoord())) {
484  // skip sources outside the sky-tilea
485  noutside += 1;
486  continue;
487  }
488  bool bad = false;
489  // Check whether source is flagged as bad
490  for (FlagKeyIter f = badKeys.begin(), ef = badKeys.end(); f != ef; ++f) {
491  if (s->get(*f)) {
492  bad = true;
493  break;
494  }
495  }
496  // Copy input source to appropriate output catalog
497  boost::shared_ptr<SourceRecord> os;
498  if (invalid) {
499  ninvalid += 1;
500  os = invalidSources.addNew();
501  } else if (bad) {
502  nbad += 1;
503  os = badSources.addNew();
504  } else {
505  ngood += 1;
506  os = sources.addNew();
507  }
508  os->assign(*s, mapper);
509  // Add exposure parameters
510  if (expIdKey.isValid()) {
511  os->set(expIdKey, expInfo.getId());
512  }
513  if (expFilterIdKey.isValid()) {
514  os->set(expFilterIdKey, expInfo.getFilter().getId());
515  }
516  if (expTimeKey.isValid()) {
517  os->set(expTimeKey, expInfo.getExposureTime());
518  }
519  if (expTimeMidKey.isValid()) {
520  os->set(expTimeMidKey, expInfo.getEpoch());
521  }
522  // Source cluster coords default to source coordinates
523  if (clusterCoordKey.isValid()) {
524  os->set(clusterCoordKey, s->getCoord());
525  }
526  // Compute sky-coordinate errors
527  if (!invalid && coordErrKey.isValid() && centroidErrKey.isValid()) {
528  Eigen::Matrix2d cov = s->getCentroidErr().cast<double>();
529  bool computeErr = true;
530  if (lsst::utils::isnan(cov(0,0)) || lsst::utils::isnan(cov(1,1))) {
531  computeErr = false;
532  } else if (cov(0,1) != cov(1,0)) {
533  // FIXME: for now, no measurement algorithms actually
534  // compute full covariance matrixes, and the
535  // off diagonal matrix elements are always NaN.
536  // Longer term, we will need some algorithm metadata
537  // to decide whether an off-diagonal NaN means a
538  // sample should be ignored because a computation failed,
539  // or whether it should be zeroed because the algorithm
540  // never computes it.
541  if (lsst::utils::isnan(cov(0,1)) && lsst::utils::isnan(cov(1,0))) {
542  cov(0,1) = 0.0; cov(1,0) = 0.0;
543  } else {
544  computeErr = false;
545  }
546  }
547  if (computeErr) {
548  Eigen::Matrix2d m = expInfo.getWcs()->linearizePixelToSky(
549  s->getCentroid(), radians).getLinear().getMatrix();
550  os->set(coordErrKey, (m * cov * m.transpose()).cast<float>());
551  }
552  }
553  }
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));
561 }
int y
Defines the fields and offsets for a table.
Definition: Schema.h:46
double indexToPosition(double ind)
Convert image index to image position.
Definition: ImageUtils.h:54
AngleUnit const radians
constant with units of radians
Definition: Angle.h:91
bool isValid() const
Return true if the key was initialized to valid offset.
Definition: Key.h:83
int isnan(T t)
Definition: ieee.h:110
a place to record messages and descriptions of the state of processing.
Definition: Log.h:154
def log
Definition: log.py:85
tbl::Schema schema
Definition: CoaddPsf.cc:324
int x
int INFO
Definition: log.py:37
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
A class used as a handle to a particular field in a table.
Definition: fwd.h:44
int WARN
Definition: log.py:38
void lsst::ap::cluster::setClusterFields ( lsst::afw::table::SourceCatalog sources,
SourceClusterRecord const &  record,
SourceProcessingControl const &  control 
)

Set the "<cluster>.id" and "<cluster>.coord" fields of each source in the given catalog to the ID and sky-coordinates of the given cluster. The "<cluster>" field name prefix is obtained from SourceProcessingControl. If those fields are not setup in the given catalog, this function is a no-op.

This is intended to support database ingest via qserv, where sources are partitioned by their associated astrophysical object, and objects (for which clusters are a temporary stand-in) are partitioned by position. Denormalizing the output source schema by appending cluster position avoids a potentially very expensive join during database ingest.

Parameters
[out]sourcesSources to update.
[in]recordCluster to obtain ID/sky-coordinates from.
[in]controlSupplies cluster field name prefix.
void lsst::ap::cluster::setClusterFields ( SourceCatalog &  sources,
SourceClusterRecord const &  record,
SourceProcessingControl const &  control 
)

Definition at line 615 of file clustering.cc.

619 {
620  typedef SourceCatalog::iterator Iter;
621 
622  if (control.clusterPrefix.empty()) {
623  return;
624  }
625  Key<int64_t> idKey;
627  try {
628  idKey = sources.getSchema().find<int64_t>(control.clusterPrefix + ".id").key;
629  coordKey = sources.getSchema().find<lsst::afw::coord::Coord>(
630  control.clusterPrefix + ".coord").key;
631  } catch (NotFoundError &) {
632  // could not find fields with the expected name
633  return;
634  }
635  int64_t const id = record.getId();
636  IcrsCoord const coord = record.getCoord();
637  for (Iter i = sources.begin(), e = sources.end(); i != e; ++i) {
638  i->set(idKey, id);
639  i->set(coordKey, coord);
640  }
641 }
A class used as a handle to a particular field in a table.
Definition: fwd.h:44
A class to handle Icrs coordinates (inherits from Coord)
Definition: Coord.h:155