lsst.meas.base  16.0-8-g2ce35ff+3
ApertureFlux.cc
Go to the documentation of this file.
1 // -*- lsst-c++ -*-
2 /*
3  * LSST Data Management System
4  * Copyright 2008-2016 AURA/LSST.
5  *
6  * This product includes software developed by the
7  * LSST Project (http://www.lsst.org/).
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the LSST License Statement and
20  * the GNU General Public License along with this program. If not,
21  * see <http://www.lsstcorp.org/LegalNotices/>.
22  */
23 
24 #include <numeric>
25 
26 #include "boost/algorithm/string/replace.hpp"
27 
28 #include "ndarray/eigen.h"
29 
32 #include "lsst/afw/table/Source.h"
35 
36 namespace lsst {
37 namespace meas {
38 namespace base {
39 namespace {
40 FlagDefinitionList flagDefinitions;
41 } // namespace
42 
43 FlagDefinition const ApertureFluxAlgorithm::FAILURE = flagDefinitions.addFailureFlag();
44 FlagDefinition const ApertureFluxAlgorithm::APERTURE_TRUNCATED =
45  flagDefinitions.add("flag_apertureTruncated", "aperture did not fit within measurement image");
46 FlagDefinition const ApertureFluxAlgorithm::SINC_COEFFS_TRUNCATED = flagDefinitions.add(
47  "flag_sincCoeffsTruncated", "full sinc coefficient image did not fit within measurement image");
48 
50 
51 ApertureFluxControl::ApertureFluxControl() : radii(10), maxSincRadius(10.0), shiftKernel("lanczos5") {
52  // defaults here stolen from HSC pipeline defaults
53  static std::array<double, 10> defaultRadii = {{3.0, 4.5, 6.0, 9.0, 12.0, 17.0, 25.0, 35.0, 50.0, 70.0}};
54  std::copy(defaultRadii.begin(), defaultRadii.end(), radii.begin());
55 }
56 
58  std::string prefix = (boost::format("%s_%.1f") % name % radius).str();
59  return boost::replace_all_copy(prefix, ".", "_");
60 }
61 
62 ApertureFluxAlgorithm::Keys::Keys(afw::table::Schema &schema, std::string const &prefix,
63  std::string const &doc, bool isSinc)
64  : fluxKey(FluxResultKey::addFields(schema, prefix, doc)),
65  flags(
66  // The exclusion List can either be empty, or constain the sinc coeffs flag
69  isSinc ? FlagDefinitionList() : FlagDefinitionList({{SINC_COEFFS_TRUNCATED}}))) {}
70 
73 
74  )
75  : _ctrl(ctrl), _centroidExtractor(schema, name) {
76  _keys.reserve(ctrl.radii.size());
77  for (std::size_t i = 0; i < ctrl.radii.size(); ++i) {
78  metadata.add(name + "_radii", ctrl.radii[i]);
80  std::string doc = (boost::format("flux within %f-pixel aperture") % ctrl.radii[i]).str();
81  _keys.push_back(Keys(schema, prefix, doc, ctrl.radii[i] <= ctrl.maxSincRadius));
82  }
83 }
84 
86  // This should only get called in the case of completely unexpected failures, so it's not terrible
87  // that we just set the general failure flags for all radii here instead of trying to figure out
88  // which ones we've already done. Any known failure modes are handled inside measure().
89  for (std::size_t i = 0; i < _ctrl.radii.size(); ++i) {
90  _keys[i].flags.handleFailure(measRecord, error);
91  }
92 }
93 
95  int index) const {
96  record.set(_keys[index].fluxKey, result);
97  if (result.getFlag(FAILURE.number)) {
98  _keys[index].flags.setValue(record, FAILURE.number, true);
99  }
100  if (result.getFlag(APERTURE_TRUNCATED.number)) {
101  _keys[index].flags.setValue(record, APERTURE_TRUNCATED.number, true);
102  }
103  if (result.getFlag(SINC_COEFFS_TRUNCATED.number)) {
104  _keys[index].flags.setValue(record, SINC_COEFFS_TRUNCATED.number, true);
105  }
106 }
107 
108 namespace {
109 
110 // Helper function for computeSincFlux get Sinc flux coefficients, and handle cases where the coeff
111 // image needs to be clipped to fit in the measurement image
112 template <typename T>
114 getSincCoeffs(geom::Box2I const &bbox, // measurement image bbox we need to fit inside
115  afw::geom::ellipses::Ellipse const &ellipse, // ellipse that defines the aperture
116  ApertureFluxAlgorithm::Result &result, // result object where we set flags if we do clip
117  ApertureFluxAlgorithm::Control const &ctrl // configuration
118 ) {
119  CONST_PTR(afw::image::Image<T>) cImage = SincCoeffs<T>::get(ellipse.getCore(), 0.0);
120  cImage = afw::math::offsetImage(*cImage, ellipse.getCenter().getX(), ellipse.getCenter().getY(),
121  ctrl.shiftKernel);
122  if (!bbox.contains(cImage->getBBox())) {
123  // We had to clip out at least part part of the coeff image,
124  // but since that's much larger than the aperture (and close
125  // to zero outside the aperture), it may not be a serious
126  // problem.
127  result.setFlag(ApertureFluxAlgorithm::SINC_COEFFS_TRUNCATED.number);
128  geom::Box2I overlap = cImage->getBBox();
129  overlap.clip(bbox);
130  if (!overlap.contains(geom::Box2I(ellipse.computeBBox()))) {
131  // The clipping was indeed serious, as we we did have to clip within
132  // the aperture; can't expect any decent answer at this point.
133  result.setFlag(ApertureFluxAlgorithm::APERTURE_TRUNCATED.number);
134  result.setFlag(ApertureFluxAlgorithm::FAILURE.number);
135  }
136  cImage = std::make_shared<afw::image::Image<T> >(*cImage, overlap);
137  }
138  return cImage;
139 }
140 
141 } // namespace
142 
143 template <typename T>
145  afw::image::Image<T> const &image, afw::geom::ellipses::Ellipse const &ellipse, Control const &ctrl) {
146  Result result;
147  CONST_PTR(afw::image::Image<T>) cImage = getSincCoeffs<T>(image.getBBox(), ellipse, result, ctrl);
148  if (result.getFlag(APERTURE_TRUNCATED.number)) return result;
149  afw::image::Image<T> subImage(image, cImage->getBBox());
150  result.flux =
151  (ndarray::asEigenArray(subImage.getArray()) * ndarray::asEigenArray(cImage->getArray())).sum();
152  return result;
153 }
154 
155 template <typename T>
157  afw::image::MaskedImage<T> const &image, afw::geom::ellipses::Ellipse const &ellipse,
158  Control const &ctrl) {
159  Result result;
160  CONST_PTR(afw::image::Image<T>) cImage = getSincCoeffs<T>(image.getBBox(), ellipse, result, ctrl);
161  if (result.getFlag(APERTURE_TRUNCATED.number)) return result;
163  result.flux = (ndarray::asEigenArray(subImage.getImage()->getArray()) *
164  ndarray::asEigenArray(cImage->getArray()))
165  .sum();
166  result.fluxSigma =
167  std::sqrt((ndarray::asEigenArray(subImage.getVariance()->getArray()).template cast<T>() *
168  ndarray::asEigenArray(cImage->getArray()).square())
169  .sum());
170  return result;
171 }
172 
173 template <typename T>
175  afw::image::Image<T> const &image, afw::geom::ellipses::Ellipse const &ellipse, Control const &ctrl) {
176  Result result;
177  afw::geom::ellipses::PixelRegion region(ellipse); // behaves mostly like a Footprint
178  if (!image.getBBox().contains(region.getBBox())) {
180  result.setFlag(FAILURE.number);
181  return result;
182  }
183  result.flux = 0;
184  for (afw::geom::ellipses::PixelRegion::Iterator spanIter = region.begin(), spanEnd = region.end();
185  spanIter != spanEnd; ++spanIter) {
186  typename afw::image::Image<T>::x_iterator pixIter =
187  image.x_at(spanIter->getBeginX() - image.getX0(), spanIter->getY() - image.getY0());
188  result.flux += std::accumulate(pixIter, pixIter + spanIter->getWidth(), 0.0);
189  }
190  return result;
191 }
192 
193 template <typename T>
195  afw::image::MaskedImage<T> const &image, afw::geom::ellipses::Ellipse const &ellipse,
196  Control const &ctrl) {
197  Result result;
198  afw::geom::ellipses::PixelRegion region(ellipse); // behaves mostly like a Footprint
199  if (!image.getBBox().contains(region.getBBox())) {
201  result.setFlag(FAILURE.number);
202  return result;
203  }
204  result.flux = 0.0;
205  result.fluxSigma = 0.0;
206  for (afw::geom::ellipses::PixelRegion::Iterator spanIter = region.begin(), spanEnd = region.end();
207  spanIter != spanEnd; ++spanIter) {
208  typename afw::image::MaskedImage<T>::Image::x_iterator pixIter = image.getImage()->x_at(
209  spanIter->getBeginX() - image.getX0(), spanIter->getY() - image.getY0());
210  typename afw::image::MaskedImage<T>::Variance::x_iterator varIter = image.getVariance()->x_at(
211  spanIter->getBeginX() - image.getX0(), spanIter->getY() - image.getY0());
212  result.flux += std::accumulate(pixIter, pixIter + spanIter->getWidth(), 0.0);
213  // we use this to hold variance as we accumulate...
214  result.fluxSigma += std::accumulate(varIter, varIter + spanIter->getWidth(), 0.0);
215  }
216  result.fluxSigma = std::sqrt(result.fluxSigma); // ...and switch back to sigma here.
217  return result;
218 }
219 
220 template <typename T>
222  afw::geom::ellipses::Ellipse const &ellipse,
223  Control const &ctrl) {
224  return (afw::geom::ellipses::Axes(ellipse.getCore()).getB() <= ctrl.maxSincRadius)
225  ? computeSincFlux(image, ellipse, ctrl)
226  : computeNaiveFlux(image, ellipse, ctrl);
227 }
228 
229 template <typename T>
231  afw::geom::ellipses::Ellipse const &ellipse,
232  Control const &ctrl) {
233  return (afw::geom::ellipses::Axes(ellipse.getCore()).getB() <= ctrl.maxSincRadius)
234  ? computeSincFlux(image, ellipse, ctrl)
235  : computeNaiveFlux(image, ellipse, ctrl);
236 }
237 #define INSTANTIATE(T) \
238  template ApertureFluxAlgorithm::Result ApertureFluxAlgorithm::computeFlux( \
239  afw::image::Image<T> const &, afw::geom::ellipses::Ellipse const &, Control const &); \
240  template ApertureFluxAlgorithm::Result ApertureFluxAlgorithm::computeFlux( \
241  afw::image::MaskedImage<T> const &, afw::geom::ellipses::Ellipse const &, Control const &); \
242  template ApertureFluxAlgorithm::Result ApertureFluxAlgorithm::computeSincFlux( \
243  afw::image::Image<T> const &, afw::geom::ellipses::Ellipse const &, Control const &); \
244  template ApertureFluxAlgorithm::Result ApertureFluxAlgorithm::computeSincFlux( \
245  afw::image::MaskedImage<T> const &, afw::geom::ellipses::Ellipse const &, Control const &); \
246  template ApertureFluxAlgorithm::Result ApertureFluxAlgorithm::computeNaiveFlux( \
247  afw::image::Image<T> const &, afw::geom::ellipses::Ellipse const &, Control const &); \
248  template ApertureFluxAlgorithm::Result ApertureFluxAlgorithm::computeNaiveFlux( \
249  afw::image::MaskedImage<T> const &, afw::geom::ellipses::Ellipse const &, Control const &)
250 
251 INSTANTIATE(float);
252 INSTANTIATE(double);
253 
255  afw::table::SchemaMapper &mapper)
256  : BaseTransform(name), _ctrl(ctrl) {
257  for (std::size_t i = 0; i < _ctrl.radii.size(); ++i) {
260  if (_ctrl.radii[i] > _ctrl.maxSincRadius &&
261  flag == ApertureFluxAlgorithm::SINC_COEFFS_TRUNCATED) {
262  continue;
263  }
264  mapper.addMapping(
265  mapper.getInputSchema()
266  .find<afw::table::Flag>(
267  (boost::format("%s_%s") %
268  ApertureFluxAlgorithm::makeFieldPrefix(name, _ctrl.radii[i]) % flag.name)
269  .str())
270  .key);
271  }
272  _magKeys.push_back(MagResultKey::addFields(
274  }
275 }
276 
278  afw::table::BaseCatalog &outputCatalog, afw::geom::SkyWcs const &wcs,
279  afw::image::Calib const &calib) const {
280  checkCatalogSize(inputCatalog, outputCatalog);
282  for (std::size_t i = 0; i < _ctrl.radii.size(); ++i) {
283  fluxKeys.push_back(FluxResultKey(
284  inputCatalog.getSchema()[ApertureFluxAlgorithm::makeFieldPrefix(_name, _ctrl.radii[i])]));
285  }
286  afw::table::SourceCatalog::const_iterator inSrc = inputCatalog.begin();
287  afw::table::BaseCatalog::iterator outSrc = outputCatalog.begin();
288  {
289  // While noThrow is in scope, converting a negative flux to a magnitude
290  // returns NaN rather than throwing.
292  for (; inSrc != inputCatalog.end() && outSrc != outputCatalog.end(); ++inSrc, ++outSrc) {
293  for (std::size_t i = 0; i < _ctrl.radii.size(); ++i) {
294  FluxResult fluxResult = fluxKeys[i].get(*inSrc);
295  _magKeys[i].set(*outSrc, calib.getMagnitude(fluxResult.flux, fluxResult.fluxSigma));
296  }
297  }
298  }
299 }
300 
301 } // namespace base
302 } // namespace meas
303 } // namespace lsst
std::size_t size() const
return the current size (number of defined elements) of the collection
Definition: FlagHandler.h:125
VariancePtr getVariance() const
lsst::geom::Point2D const & getCenter() const
lsst::geom::Box2I const & getBBox() const
static boost::shared_ptr< CoeffT const > get(afw::geom::ellipses::Axes const &outerEllipse, float const innerRadiusFactor=0.0)
Get the coefficients for an aperture.
Definition: SincCoeffs.cc:506
T copy(T... args)
virtual void fail(afw::table::SourceRecord &measRecord, MeasurementError *error=nullptr) const
Handle an exception thrown by the current algorithm by setting flags in the given record...
Definition: ApertureFlux.cc:85
bool getFlag(unsigned int index) const
Return the flag value associated with the given bit.
Definition: ApertureFlux.h:219
void setFlag(unsigned int index, bool value=true)
Set the flag value associated with the given bit.
Definition: ApertureFlux.h:227
Schema const getInputSchema() const
afw::table::Schema schema
virtual void operator()(afw::table::SourceCatalog const &inputCatalog, afw::table::BaseCatalog &outputCatalog, afw::geom::SkyWcs const &wcs, afw::image::Calib const &calib) const
static FlagDefinitionList const & getFlagDefinitions()
Definition: ApertureFlux.cc:49
Simple class used to define and document flags The name and doc constitute the identity of the FlagDe...
Definition: FlagHandler.h:40
_view_t::x_iterator x_iterator
Temporarily replace negative fluxes with NaNs.
BaseCore const & getCore() const
ApertureFluxAlgorithm(Control const &ctrl, std::string const &name, afw::table::Schema &schema, daf::base::PropertySet &metadata)
Construct the algorithm and add its fields to the given Schema.
Definition: ApertureFlux.cc:71
T end(T... args)
void copyResultToRecord(Result const &result, afw::table::SourceRecord &record, int index) const
Return the flag definitions which apply to aperture flux measurements.
Definition: ApertureFlux.cc:94
Exception to be thrown when a measurement algorithm experiences a known failure mode.
Definition: exceptions.h:48
static FluxResultKey addFields(afw::table::Schema &schema, std::string const &name, std::string const &doc)
Add a pair of _flux, _fluxSigma fields to a Schema, and return a FluxResultKey that points to them...
#define CONST_PTR(...)
Configuration object for multiple-aperture flux algorithms.
Definition: ApertureFlux.h:45
STL class.
T push_back(T... args)
SchemaItem< T > find(std::string const &name) const
static FlagDefinition const FAILURE
Definition: ApertureFlux.h:81
static FlagDefinition const APERTURE_TRUNCATED
Definition: ApertureFlux.h:82
lsst::geom::Box2I getBBox(ImageOrigin origin=PARENT) const
static Result computeFlux(afw::image::Image< T > const &image, afw::geom::ellipses::Ellipse const &ellipse, Control const &ctrl=Control())
Compute the flux (and optionally, uncertanties) within an aperture using the algorithm determined by ...
double maxSincRadius
"Maximum radius (in pixels) for which the sinc algorithm should be used instead of the " "faster naiv...
Definition: ApertureFlux.h:54
static std::string makeFieldPrefix(std::string const &name, double radius)
Construct an appropriate prefix for table fields.
Definition: ApertureFlux.cc:57
static FlagDefinition const SINC_COEFFS_TRUNCATED
Definition: ApertureFlux.h:83
lsst::geom::Box2D computeBBox() const
static Result computeNaiveFlux(afw::image::Image< T > const &image, afw::geom::ellipses::Ellipse const &ellipse, Control const &ctrl=Control())
Compute the flux (and optionally, uncertanties) within an aperture using naive photometry.
Key< U > key
Flux flux
Measured flux in DN.
Definition: FluxUtilities.h:42
A FunctorKey for FluxResult.
Definition: FluxUtilities.h:58
std::unique_ptr< SchemaItem< U > > result
double getMagnitude(double const flux) const
static FlagHandler addFields(afw::table::Schema &schema, std::string const &prefix, FlagDefinitionList const &flagDefs, FlagDefinitionList const &exclDefs=FlagDefinitionList::getEmptyList())
Add Flag fields to a schema, creating a FlagHandler object to manage them.
Definition: FlagHandler.cc:37
static MagResultKey addFields(afw::table::Schema &schema, std::string const &name)
Add a pair of _mag, _magErr fields to a Schema, and return a MagResultKey that points to them...
T size(T... args)
STL class.
#define INSTANTIATE(T)
std::shared_ptr< ImageT > offsetImage(ImageT const &image, float dx, float dy, std::string const &algorithmName="lanczos5", unsigned int buffer=0)
Base::const_iterator const_iterator
T begin(T... args)
bool contains(Point2I const &point) const noexcept
Abstract base class for all C++ measurement transformations.
Definition: Transform.h:85
void clip(Box2I const &other) noexcept
static Result computeSincFlux(afw::image::Image< T > const &image, afw::geom::ellipses::Ellipse const &ellipse, Control const &ctrl=Control())
Compute the flux (and optionally, uncertanties) within an aperture using Sinc photometry.
STL class.
std::string prefix
x_iterator x_at(int x, int y) const
void set(Key< T > const &key, U const &value)
table::Box2IKey bbox
void checkCatalogSize(afw::table::BaseCatalog const &cat1, afw::table::BaseCatalog const &cat2) const
Ensure that catalogs have the same size.
Definition: Transform.h:101
T sqrt(T... args)
Key< T > addMapping(Key< T > const &inputKey, bool doReplace=false)
std::string shiftKernel
"Warping kernel used to shift Sinc photometry coefficients to different center positions" ; ...
Definition: ApertureFlux.h:58
T accumulate(T... args)
std::vector< double > radii
"Radius (in pixels) of apertures." ;
Definition: ApertureFlux.h:49
vector-type utility class to build a collection of FlagDefinitions
Definition: FlagHandler.h:60
void add(std::string const &name, T const &value)
FluxErrElement fluxSigma
1-Sigma error (sqrt of variance) on flux in DN.
Definition: FluxUtilities.h:43
lsst::geom::Box2I getBBox(ImageOrigin const origin=PARENT) const
ApertureFluxTransform(Control const &ctrl, std::string const &name, afw::table::SchemaMapper &mapper)
A reusable result struct for flux measurements.
Definition: FluxUtilities.h:41
CatalogIterator< typename Internal::iterator > iterator
T reserve(T... args)
A Result struct for running an aperture flux algorithm with a single radius.
Definition: ApertureFlux.h:217