lsst.meas.base ga44f29b7aa+252f03e95a
Loading...
Searching...
No Matches
CentroidUtilities.cc
Go to the documentation of this file.
1/*
2 * LSST Data Management System
3 * Copyright 2008-2014 LSST Corporation.
4 *
5 * This product includes software developed by the
6 * LSST Project (http://www.lsst.org/).
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the LSST License Statement and
19 * the GNU General Public License along with this program. If not,
20 * see <http://www.lsstcorp.org/LegalNotices/>.
21 */
22
23#include <cmath>
24
25#include "lsst/geom/Angle.h"
26#include "lsst/geom/Point.h"
29
30namespace lsst {
31namespace meas {
32namespace base {
33
35 : x(std::numeric_limits<CentroidElement>::quiet_NaN()),
36 y(std::numeric_limits<CentroidElement>::quiet_NaN()),
37 xErr(std::numeric_limits<ErrElement>::quiet_NaN()),
38 yErr(std::numeric_limits<ErrElement>::quiet_NaN()),
39 x_y_Cov(std::numeric_limits<ErrElement>::quiet_NaN()) {}
40
41Centroid const CentroidResult::getCentroid() const { return Centroid(x, y); }
42
44 x = centroid.getX();
45 y = centroid.getY();
46}
47
50 m << xErr * xErr, x_y_Cov, x_y_Cov, yErr * yErr;
51 return m;
52}
53
55 xErr = std::sqrt(matrix(0, 0));
56 yErr = std::sqrt(matrix(1, 1));
57 x_y_Cov = matrix(0, 1);
58}
59
61 xErr = _xErr;
62 yErr = _yErr;
63 x_y_Cov = 0.0;
64}
65
67 os << "x=" << result.x << ", y=" << result.y << ", xErr=" << result.xErr << ", yErr=" << result.yErr;
68 return os;
69}
70
72 std::string const &doc, UncertaintyEnum uncertainty) {
74 r._centroid = afw::table::PointKey<CentroidElement>::addFields(schema, name, doc, "pixel");
75 if (uncertainty != NO_UNCERTAINTY) {
78 sigma[0] = schema.addField<ErrElement>(schema.join(name, "xErr"), "1-sigma uncertainty on x position",
79 "pixel");
80 sigma[1] = schema.addField<ErrElement>(schema.join(name, "yErr"), "1-sigma uncertainty on y position",
81 "pixel");
82 if (uncertainty == FULL_COVARIANCE) {
83 cov.push_back(schema.addField<ErrElement>(schema.join(name, "x_y_Cov"),
84 "uncertainty covariance in x and y", "pixel^2"));
85 }
86 r._centroidErr = afw::table::CovarianceMatrixKey<ErrElement, 2>(sigma, cov);
87 }
88 return r;
89}
90
91namespace {
92
93std::vector<std::string> getNameVector() {
95 v.push_back("x");
96 v.push_back("y");
97 return v;
98}
99
100} // namespace
101
103 static std::vector<std::string> names = getNameVector(); // C++11 TODO: just use initializer list
104 try {
105 _centroidErr = afw::table::CovarianceMatrixKey<ErrElement, 2>(s, names);
107 }
108}
109
112 r.setCentroid(record.get(_centroid));
113 if (_centroidErr.isValid()) {
114 r.setCentroidErr(record.get(_centroidErr));
115 }
116 return r;
117}
118
120 record.set(_centroid, value.getCentroid());
121 if (_centroidErr.isValid()) {
122 record.set(_centroidErr, value.getCentroidErr());
123 }
124}
125
127 : BaseTransform{name} {
128 // Map the flag through to the output
129 mapper.addMapping(mapper.getInputSchema().find<afw::table::Flag>(name + "_flag").key);
130
131 // Add keys for the coordinates
132 auto &s = mapper.editOutputSchema();
133 _coordKey = afw::table::CoordKey::addFields(s, name, "ICRS coordinates");
134
135 // If the centroid has an error key we also include one on the celestial
136 // coordinates; otherwise, it isn't necessary. Note that if we provide for
137 // errors in celestial coordinates, we always need the full covariance.
138 //
139 // Note that the covariance is computed using a Jacobian on a local
140 // tangent plane centered on the source.
141 if (CentroidResultKey(mapper.getInputSchema()[name]).getCentroidErr().isValid()) {
144 sigma[0] = s.addField<ErrElement>(
145 s.join(name, "raErr"),
146 "1-sigma uncertainty on the local tangent-plane longitude offset"
147 " xi = RA*cos(Dec).",
148 "rad");
149 sigma[1] = s.addField<ErrElement>(
150 s.join(name, "decErr"),
151 "1-sigma uncertainty on Dec.",
152 "rad");
153 cov[0] = s.addField<ErrElement>(
154 s.join(name, "ra_dec_Cov"),
155 "Tangent-plane covariance Cov(xi, eta) = Cov(RA*cos(Dec), Dec).",
156 "rad^2");
157 _coordErrKey = afw::table::CovarianceMatrixKey<ErrElement, 2>(sigma, cov);
158 }
159}
160
162 afw::table::BaseCatalog &outputCatalog, afw::geom::SkyWcs const &wcs,
163 afw::image::PhotoCalib const &photoCalib) const {
164 checkCatalogSize(inputCatalog, outputCatalog);
165 CentroidResultKey centroidResultKey(inputCatalog.getSchema()[_name]);
166
168 afw::table::BaseCatalog::iterator outSrc = outputCatalog.begin();
169
170 for (; inSrc != inputCatalog.end() && outSrc != outputCatalog.end(); ++inSrc, ++outSrc) {
171 CentroidResult centroidResult = centroidResultKey.get(*inSrc);
172
173 _coordKey.set(*outSrc, wcs.pixelToSky(centroidResult.getCentroid()));
174
175 if (centroidResultKey.getCentroidErr().isValid()) {
176 CentroidCov centroidCov = centroidResult.getCentroidErr();
177 if (!(std::isnan(centroidCov(0, 0)) || std::isnan(centroidCov(1, 1)))) {
178 auto transform = wcs.linearizePixelToSky(centroidResult.getCentroid(), geom::radians)
179 .getLinear()
180 .getMatrix();
181 _coordErrKey.set(*outSrc, (transform * centroidResult.getCentroidErr().cast<double>() *
182 transform.transpose())
183 .cast<ErrElement>());
184 }
185 }
186 }
187}
188
189// Add a key "flag_resetToPeak" if something is wrong with the centroid
190// Save a key to this algorithm's Centroid, as well as the general failure flag
191CentroidChecker::CentroidChecker(afw::table::Schema &schema, std::string const &name, bool doFootprintCheck,
192 double maxDistFromPeak)
193 : _doFootprintCheck(doFootprintCheck), _maxDistFromPeak(maxDistFromPeak) {
194 _resetKey = schema.addField<afw::table::Flag>(schema.join(name, "flag_resetToPeak"),
195 "set if CentroidChecker reset the centroid");
196 _failureKey = schema.find<afw::table::Flag>(schema.join(name, "flag")).key;
197 _xKey = schema.find<CentroidElement>(schema.join(name, "x")).key;
198 _yKey = schema.find<CentroidElement>(schema.join(name, "y")).key;
199
200 // We only check errors on the centroid if they exist: not all measurement
201 // algorithms provide them.
202 try {
203 _xErrKey = schema.find<ErrElement>(schema.join(name, "xErr")).key;
204 } catch (pex::exceptions::NotFoundError &err) {
205 }
206 try {
207 _yErrKey = schema.find<ErrElement>(schema.join(name, "yErr")).key;
208 } catch (pex::exceptions::NotFoundError &err) {
209 }
210 if (_xErrKey.isValid() || _yErrKey.isValid()) {
211 _badErrorKey = schema.addField<afw::table::Flag>(schema.join(name, "flag_badError"),
212 "Error on x and/or y position is NaN");
213 }
214}
215
217 CentroidElement x = record.get(_xKey);
218 CentroidElement y = record.get(_yKey);
219
220 // Check any errors specified on the centroid position are valid.
221 if ((_xErrKey.isValid() && std::isnan(record.get(_xErrKey))) ||
222 (_yErrKey.isValid() && std::isnan(record.get(_yErrKey)))) {
223 record.set(_badErrorKey, true);
224 record.set(_failureKey, true);
225 }
226
227 // Only proceed with checking if appropriately configured.
228 if (!_doFootprintCheck && _maxDistFromPeak < 0.0) {
229 return false;
230 }
231
232 // Check that the centroid has a footprint that we can validate; otherwise, give up.
234 if (!footprint) {
235 throw LSST_EXCEPT(pex::exceptions::RuntimeError, "No Footprint attached to record");
236 }
237 if (footprint->getPeaks().empty()) {
238 throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Footprint has no peaks; cannot verify centroid.");
239 }
240
241 // Set the centroid to the first footprint if the centroid is either more than
242 // _maxDistFromPeak pixels from the centroid, or if it is outside the footprint.
243 CentroidElement footX = footprint->getPeaks().front().getFx();
244 CentroidElement footY = footprint->getPeaks().front().getFy();
245 double distsq = (x - footX) * (x - footX) + (y - footY) * (y - footY);
246 if ((_doFootprintCheck && !footprint->contains(geom::Point2I(geom::Point2D(x, y)))) ||
247 ((_maxDistFromPeak > 0) && (distsq > _maxDistFromPeak * _maxDistFromPeak))) {
248 record.set(_xKey, footX);
249 record.set(_yKey, footY);
250 record.set(_failureKey, true);
251 record.set(_resetKey, true);
252 return true;
253 }
254 return false;
255}
256} // namespace base
257} // namespace meas
258} // namespace lsst
#define LSST_EXCEPT(type,...)
lsst::geom::SpherePoint pixelToSky(lsst::geom::Point2D const &pixel) const
lsst::geom::AffineTransform linearizePixelToSky(lsst::geom::SpherePoint const &coord, lsst::geom::AngleUnit const &skyUnit) const
Field< T >::Value get(Key< T > const &key) const
void set(Key< T > const &key, U const &value)
CatalogIterator< typename Internal::iterator > iterator
static CoordKey addFields(afw::table::Schema &schema, std::string const &name, std::string const &doc)
static PointKey addFields(Schema &schema, std::string const &name, std::string const &doc, std::string const &unit)
std::string join(std::string const &a, std::string const &b) const
Key< T > addField(Field< T > const &field, bool doReplace=false)
SchemaItem< T > find(std::string const &name) const
Key< T > addMapping(Key< T > const &inputKey, bool doReplace=false)
Schema const getInputSchema() const
typename Base::const_iterator const_iterator
std::shared_ptr< Footprint > getFootprint() const
LinearTransform const & getLinear() const noexcept
Matrix const & getMatrix() const noexcept
void checkCatalogSize(afw::table::BaseCatalog const &cat1, afw::table::BaseCatalog const &cat2) const
Ensure that catalogs have the same size.
Definition Transform.h:102
BaseTransform(std::string const &name)
Definition Transform.h:88
CentroidChecker(afw::table::Schema &schema, std::string const &name, bool inside=true, double maxDistFromPeak=-1.0)
Check source record produced by a centroid algorithm called "name".
bool operator()(afw::table::SourceRecord &record) const
Set the centroid to the first footprint if the centroid is either more than _dist pixels from the foo...
A FunctorKey for CentroidResult.
virtual void set(afw::table::BaseRecord &record, CentroidResult const &value) const
Set a CentroidResult in the given record.
afw::table::CovarianceMatrixKey< ErrElement, 2 > getCentroidErr() const
Return a FunctorKey to just the uncertainty matrix.
CentroidResultKey()
Default constructor; instance will not be usuable unless subsequently assigned to.
virtual CentroidResult get(afw::table::BaseRecord const &record) const
Get a CentroidResult from the given record.
static CentroidResultKey addFields(afw::table::Schema &schema, std::string const &name, std::string const &doc, UncertaintyEnum uncertainty)
Add the appropriate fields to a Schema, and return a CentroidResultKey that manages them.
CentroidTransform(std::string const &name, afw::table::SchemaMapper &mapper)
virtual void operator()(afw::table::SourceCatalog const &inputCatalog, afw::table::BaseCatalog &outputCatalog, afw::geom::SkyWcs const &wcs, afw::image::PhotoCalib const &photoCalib) const
T isnan(T... args)
CatalogT< BaseRecord > BaseCatalog
SortedCatalogT< SourceRecord > SourceCatalog
AngleUnit constexpr radians
Point< double, 2 > Point2D
Point< int, 2 > Point2I
UncertaintyEnum
An enum used to specify how much uncertainty information measurement algorithms provide.
Definition constants.h:43
@ FULL_COVARIANCE
The full covariance matrix is provided.
Definition constants.h:46
@ NO_UNCERTAINTY
Algorithm provides no uncertainy information at all.
Definition constants.h:44
std::ostream & operator<<(std::ostream &os, CentroidResult const &result)
Eigen::Matrix< ErrElement, 2, 2, Eigen::DontAlign > CentroidCov
Definition constants.h:59
double CentroidElement
Definition constants.h:56
geom::Point< CentroidElement, 2 > Centroid
Definition constants.h:58
STL namespace.
T push_back(T... args)
T sqrt(T... args)
A reusable struct for centroid measurements.
CentroidElement y
y (row) coordinate of the measured position
Centroid const getCentroid() const
Return a Point object containing the measured x and y.
CentroidElement x
x (column) coordinate of the measured position
void setCentroidErr(CentroidCov const &matrix)
Set the struct uncertainty fields from the given matrix, with rows and columns ordered (x,...
CentroidCov const getCentroidErr() const
Return the 2x2 symmetric covariance matrix, with rows and columns ordered (x, y)
void setCentroid(Centroid const &centroid)
Set the struct fields from the given Point object.
ErrElement yErr
standard deviation of y
CentroidResult()
Constructor; initializes everything to NaN.
ErrElement x_y_Cov
x,y term in the uncertainty convariance matrix
ErrElement xErr
standard deviation of x