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
ApertureFlux.cc
Go to the documentation of this file.
1 // -*- lsst-c++ -*-
2 /*
3  * LSST Data Management System
4  * Copyright 2008-2015 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/array.hpp"
27 
28 #include "ndarray/eigen.h"
29 
32 #include "lsst/afw/table/Source.h"
35 
36 namespace lsst { namespace meas { namespace base {
37 
38 ApertureFluxControl::ApertureFluxControl() : radii(10), maxSincRadius(10.0), shiftKernel("lanczos5") {
39  // defaults here stolen from HSC pipeline defaults
40  static boost::array<double,10> defaultRadii = {{
41  3.0, 4.5, 6.0, 9.0, 12.0, 17.0, 25.0, 35.0, 50.0, 70.0
42  }};
43  std::copy(defaultRadii.begin(), defaultRadii.end(), radii.begin());
44 }
45 
46 namespace {
47 
48 boost::array<FlagDefinition,ApertureFluxAlgorithm::N_FLAGS> const & getFlagDefinitions() {
49  static boost::array<FlagDefinition,ApertureFluxAlgorithm::N_FLAGS> flagDefs = {{
50  {"flag", "flag set if aperture failed for any reason"},
51  {"flag_apertureTruncated", "flag set if aperture did not fit within the measurement image"},
52  {"flag_sincCoeffsTruncated",
53  "flag set if the full sinc coefficient image for aperture %d did not "
54  "fit within the measurement image"}
55  }};
56  return flagDefs;
57 }
58 
59 } // anonymous
60 
62  afw::table::Schema & schema, std::string const & prefix, std::string const & doc, bool isSinc
63 ) :
64  fluxKey(FluxResultKey::addFields(schema, prefix, doc)),
65  flags(
66  FlagHandler::addFields(
67  schema, prefix,
68  getFlagDefinitions().begin(),
69  getFlagDefinitions().begin() + (isSinc ? 3 : 2)
70  )
71  )
72 {}
73 
75  Control const & ctrl,
76  std::string const & name,
78  daf::base::PropertySet & metadata
79 
80 ) : _ctrl(ctrl),
81  _centroidExtractor(schema, name)
82 {
83  _keys.reserve(ctrl.radii.size());
84  for (std::size_t i = 0; i < ctrl.radii.size(); ++i) {
85  metadata.add(name + "_radii", ctrl.radii[i]);
86  std::string prefix = (boost::format("%s_%d") % name % i).str();
87  std::string doc = (boost::format("flux within %f-pixel aperture") % ctrl.radii[i]).str();
88  _keys.push_back(Keys(schema, prefix, doc, ctrl.radii[i] <= ctrl.maxSincRadius));
89  }
90 }
91 
93  // This should only get called in the case of completely unexpected failures, so it's not terrible
94  // that we just set the general failure flags for all radii here instead of trying to figure out
95  // which ones we've already done. Any known failure modes are handled inside measure().
96  for (std::size_t i = 0; i < _ctrl.radii.size(); ++i) {
97  _keys[i].flags.handleFailure(measRecord, error);
98  }
99 }
100 
102  Result const & result,
103  afw::table::SourceRecord & record,
104  int index
105 ) const {
106  record.set(_keys[index].fluxKey, result);
107  if (result.getFlag(FAILURE)) {
108  _keys[index].flags.setValue(record, FAILURE, true);
109  }
110  if (result.getFlag(APERTURE_TRUNCATED)) {
111  _keys[index].flags.setValue(record, APERTURE_TRUNCATED, true);
112  }
113  if (result.getFlag(SINC_COEFFS_TRUNCATED)) {
114  _keys[index].flags.setValue(record, SINC_COEFFS_TRUNCATED, true);
115  }
116 }
117 
118 namespace {
119 
120 // Helper function for computeSincFlux get Sinc flux coefficients, and handle cases where the coeff
121 // image needs to be clipped to fit in the measurement image
122 template <typename T>
123 CONST_PTR(afw::image::Image<T>) getSincCoeffs(
124  afw::geom::Box2I const & bbox, // measurement image bbox we need to fit inside
125  afw::geom::ellipses::Ellipse const & ellipse, // ellipse that defines the aperture
126  ApertureFluxAlgorithm::Result & result, // result object where we set flags if we do clip
127  ApertureFluxAlgorithm::Control const & ctrl // configuration
128 ) {
129  CONST_PTR(afw::image::Image<T>) cImage = SincCoeffs<T>::get(ellipse.getCore(), 0.0);
130  cImage = afw::math::offsetImage(
131  *cImage,
132  ellipse.getCenter().getX(),
133  ellipse.getCenter().getY(),
134  ctrl.shiftKernel
135  );
136  if (!bbox.contains(cImage->getBBox())) {
137  // We had to clip out at least part part of the coeff image,
138  // but since that's much larger than the aperture (and close
139  // to zero outside the aperture), it may not be a serious
140  // problem.
142  afw::geom::Box2I overlap = cImage->getBBox();
143  overlap.clip(bbox);
144  if (!overlap.contains(afw::geom::Box2I(ellipse.computeBBox()))) {
145  // The clipping was indeed serious, as we we did have to clip within
146  // the aperture; can't expect any decent answer at this point.
148  result.setFlag(ApertureFluxAlgorithm::FAILURE);
149  }
150  cImage = boost::make_shared< afw::image::Image<T> >(*cImage, overlap);
151  }
152  return cImage;
153 }
154 
155 } // anonymous
156 
157 template <typename T>
159  afw::image::Image<T> const & image,
160  afw::geom::ellipses::Ellipse const & ellipse,
161  Control const & ctrl
162 ) {
163  Result result;
164  CONST_PTR(afw::image::Image<T>) cImage = getSincCoeffs<T>(image.getBBox(), ellipse, result, ctrl);
165  if (result.getFlag(APERTURE_TRUNCATED)) return result;
166  afw::image::Image<T> subImage(image, cImage->getBBox());
167  result.flux = (subImage.getArray().template asEigen<Eigen::ArrayXpr>()
168  * cImage->getArray().template asEigen<Eigen::ArrayXpr>()).sum();
169  return result;
170 }
171 
172 template <typename T>
175  afw::geom::ellipses::Ellipse const & ellipse,
176  Control const & ctrl
177 ) {
178  Result result;
179  CONST_PTR(afw::image::Image<T>) cImage = getSincCoeffs<T>(image.getBBox(), ellipse, result, ctrl);
180  if (result.getFlag(APERTURE_TRUNCATED)) return result;
182  result.flux = (subImage.getImage()->getArray().template asEigen<Eigen::ArrayXpr>()
183  * cImage->getArray().template asEigen<Eigen::ArrayXpr>()).sum();
184  result.fluxSigma = std::sqrt(
185  (subImage.getVariance()->getArray().template asEigen<Eigen::ArrayXpr>().template cast<T>()
186  * cImage->getArray().template asEigen<Eigen::ArrayXpr>().square()).sum()
187  );
188  return result;
189 }
190 
191 template <typename T>
193  afw::image::Image<T> const & image,
194  afw::geom::ellipses::Ellipse const & ellipse,
195  Control const & ctrl
196 ) {
197  Result result;
198  afw::geom::ellipses::PixelRegion region(ellipse); // behaves mostly like a Footprint
199  if (!image.getBBox().contains(region.getBBox())) {
200  result.setFlag(APERTURE_TRUNCATED);
201  result.setFlag(FAILURE);
202  return result;
203  }
204  result.flux = 0;
205  for (
206  afw::geom::ellipses::PixelRegion::Iterator spanIter = region.begin(), spanEnd = region.end();
207  spanIter != spanEnd;
208  ++spanIter
209  ) {
210  typename afw::image::Image<T>::x_iterator pixIter = image.x_at(
211  spanIter->getBeginX() - image.getX0(),
212  spanIter->getY() - image.getY0()
213  );
214  result.flux += std::accumulate(pixIter, pixIter + spanIter->getWidth(), 0.0);
215  }
216  return result;
217 }
218 
219 template <typename T>
222  afw::geom::ellipses::Ellipse const & ellipse,
223  Control const & ctrl
224 ) {
225  Result result;
226  afw::geom::ellipses::PixelRegion region(ellipse); // behaves mostly like a Footprint
227  if (!image.getBBox().contains(region.getBBox())) {
228  result.setFlag(APERTURE_TRUNCATED);
229  result.setFlag(FAILURE);
230  return result;
231  }
232  result.flux = 0.0;
233  result.fluxSigma = 0.0;
234  for (
235  afw::geom::ellipses::PixelRegion::Iterator spanIter = region.begin(), spanEnd = region.end();
236  spanIter != spanEnd;
237  ++spanIter
238  ) {
239  typename afw::image::MaskedImage<T>::Image::x_iterator pixIter = image.getImage()->x_at(
240  spanIter->getBeginX() - image.getX0(),
241  spanIter->getY() - image.getY0()
242  );
243  typename afw::image::MaskedImage<T>::Variance::x_iterator varIter = image.getVariance()->x_at(
244  spanIter->getBeginX() - image.getX0(),
245  spanIter->getY() - image.getY0()
246  );
247  result.flux += std::accumulate(pixIter, pixIter + spanIter->getWidth(), 0.0);
248  // we use this to hold variance as we accumulate...
249  result.fluxSigma += std::accumulate(varIter, varIter + spanIter->getWidth(), 0.0);
250  }
251  result.fluxSigma = std::sqrt(result.fluxSigma); // ...and switch back to sigma here.
252  return result;
253 }
254 
255 template <typename T>
257  afw::image::Image<T> const & image,
258  afw::geom::ellipses::Ellipse const & ellipse,
259  Control const & ctrl
260 ) {
261  return (afw::geom::ellipses::Axes(ellipse.getCore()).getB() <= ctrl.maxSincRadius)
262  ? computeSincFlux(image, ellipse, ctrl)
263  : computeNaiveFlux(image, ellipse, ctrl);
264 }
265 
266 template <typename T>
269  afw::geom::ellipses::Ellipse const & ellipse,
270  Control const & ctrl
271 ) {
272  return (afw::geom::ellipses::Axes(ellipse.getCore()).getB() <= ctrl.maxSincRadius)
273  ? computeSincFlux(image, ellipse, ctrl)
274  : computeNaiveFlux(image, ellipse, ctrl);
275 }
276 #define INSTANTIATE(T) \
277  template \
278  ApertureFluxAlgorithm::Result ApertureFluxAlgorithm::computeFlux( \
279  afw::image::Image<T> const &, \
280  afw::geom::ellipses::Ellipse const &, \
281  Control const & \
282  ); \
283  template \
284  ApertureFluxAlgorithm::Result ApertureFluxAlgorithm::computeFlux( \
285  afw::image::MaskedImage<T> const &, \
286  afw::geom::ellipses::Ellipse const &, \
287  Control const & \
288  ); \
289  template \
290  ApertureFluxAlgorithm::Result ApertureFluxAlgorithm::computeSincFlux( \
291  afw::image::Image<T> const &, \
292  afw::geom::ellipses::Ellipse const &, \
293  Control const & \
294  ); \
295  template \
296  ApertureFluxAlgorithm::Result ApertureFluxAlgorithm::computeSincFlux( \
297  afw::image::MaskedImage<T> const &, \
298  afw::geom::ellipses::Ellipse const &, \
299  Control const & \
300  ); \
301  template \
302  ApertureFluxAlgorithm::Result ApertureFluxAlgorithm::computeNaiveFlux( \
303  afw::image::Image<T> const &, \
304  afw::geom::ellipses::Ellipse const &, \
305  Control const & \
306  ); \
307  template \
308  ApertureFluxAlgorithm::Result ApertureFluxAlgorithm::computeNaiveFlux( \
309  afw::image::MaskedImage<T> const &, \
310  afw::geom::ellipses::Ellipse const &, \
311  Control const & \
312  )
313 
314 INSTANTIATE(float);
315 INSTANTIATE(double);
316 
318  Control const & ctrl,
319  std::string const & name,
320  afw::table::SchemaMapper & mapper
321 ) :
322  BaseTransform(name),
323  _ctrl(ctrl)
324 {
325  for (std::size_t i = 0; i < _ctrl.radii.size(); ++i) {
326  for (auto flag = getFlagDefinitions().begin();
327  flag < getFlagDefinitions().begin() + (_ctrl.radii[i] <= _ctrl.maxSincRadius ? 3 : 2); flag++) {
328  mapper.addMapping(mapper.getInputSchema().find<afw::table::Flag>(
329  (boost::format("%s_%d_%s") % name % i % flag->name).str()).key);
330  }
332  (boost::format("%s_%d") % name % i).str()));
333  }
334 }
335 
337  afw::table::SourceCatalog const & inputCatalog,
338  afw::table::BaseCatalog & outputCatalog,
339  afw::image::Wcs const & wcs,
340  afw::image::Calib const & calib
341 ) const {
342  checkCatalogSize(inputCatalog, outputCatalog);
343  std::vector<FluxResultKey> fluxKeys;
344  for (std::size_t i = 0; i < _ctrl.radii.size(); ++i) {
345  fluxKeys.push_back(FluxResultKey(inputCatalog.getSchema()[(boost::format("%s_%d") % _name % i).str()]));
346  }
347  afw::table::SourceCatalog::const_iterator inSrc = inputCatalog.begin();
348  afw::table::BaseCatalog::iterator outSrc = outputCatalog.begin();
349  for (; inSrc < inputCatalog.end() && outSrc < outputCatalog.end(); ++inSrc, ++outSrc) {
350  for (std::size_t i = 0; i < _ctrl.radii.size(); ++i) {
351  FluxResult fluxResult = fluxKeys[i].get(*inSrc);
352  _magKeys[i].set(*outSrc, calib.getMagnitude(fluxResult.flux, fluxResult.fluxSigma));
353  }
354  }
355 }
356 
357 }}} // namespace lsst::meas::base
358 
double getMagnitude(double const flux) const
Definition: Calib.cc:391
Defines the fields and offsets for a table.
Definition: Schema.h:46
void setFlag(ApertureFluxAlgorithm::FlagBits bit, bool value=true)
Set the flag value associated with the given bit.
Definition: ApertureFlux.h:240
int getWidth() const
Return the number of columns in the image.
Definition: MaskedImage.h:901
#define CONST_PTR(...)
Definition: base.h:47
ImagePtr getImage(bool const noThrow=false) const
Return a (Ptr to) the MaskedImage&#39;s image.
Definition: MaskedImage.h:869
virtual void fail(afw::table::SourceRecord &measRecord, MeasurementError *error=NULL) const
Definition: ApertureFlux.cc:92
void clip(Box2I const &other)
Shrink this to ensure that other.contains(*this).
Eigen matrix objects that present a view into an ndarray::Array.
Schema & editOutputSchema()
Return a reference to the output schema that allows it to be modified in place.
Definition: SchemaMapper.h:29
A custom container class for records, based on std::vector.
Definition: Catalog.h:94
void checkCatalogSize(afw::table::BaseCatalog const &cat1, afw::table::BaseCatalog const &cat2) const
Ensure that catalogs have the same size.
Definition: Transform.h:101
A mapping between the keys of two Schemas, used to copy data between them.
Definition: SchemaMapper.h:19
SelectEigenView< T >::Type copy(Eigen::EigenBase< T > const &other)
Copy an arbitrary Eigen expression into a new EigenView.
Definition: eigen.h:390
virtual void operator()(afw::table::SourceCatalog const &inputCatalog, afw::table::BaseCatalog &outputCatalog, afw::image::Wcs const &wcs, afw::image::Calib const &calib) const
ApertureFluxAlgorithm(Control const &ctrl, std::string const &name, afw::table::Schema &schema, daf::base::PropertySet &metadata)
Definition: ApertureFlux.cc:74
Implementation of the WCS standard for a any projection.
Definition: Wcs.h:107
Exception to be thrown when a measurement algorithm experiences a known failure mode.
Definition: exceptions.h:48
bool getFlag(ApertureFluxAlgorithm::FlagBits bit) const
Return the flag value associated with the given bit.
Definition: ApertureFlux.h:237
void copyResultToRecord(Result const &result, afw::table::SourceRecord &record, int index) const
boost::enable_if< typename ExpressionTraits< Scalar >::IsScalar, Scalar >::type sum(Scalar const &scalar)
Definition: operators.h:1250
An integer coordinate rectangle.
Definition: Box.h:53
Key< T > addMapping(Key< T > const &inputKey, bool doReplace=false)
Add a new field to the output Schema that is a copy of a field in the input Schema.
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
Keys(afw::table::Schema &schema, std::string const &prefix, std::string const &doc, bool isSinc)
Definition: ApertureFlux.cc:61
VariancePtr getVariance(bool const noThrow=false) const
Return a (Ptr to) the MaskedImage&#39;s variance.
Definition: MaskedImage.h:890
def error
Definition: log.py:108
int getWidth() const
Return the number of columns in the image.
Definition: Image.h:237
tbl::Schema schema
Definition: CoaddPsf.cc:324
Custom catalog class for record/table subclasses that are guaranteed to have an ID, and should generally be sorted by that ID.
Definition: fwd.h:55
Schema getSchema() const
Return the schema associated with the catalog&#39;s table.
Definition: Catalog.h:114
static Result computeFlux(afw::image::Image< T > const &image, afw::geom::ellipses::Ellipse const &ellipse, Control const &ctrl=Control())
geom::Box2I getBBox(ImageOrigin const origin=PARENT) const
Definition: MaskedImage.h:905
An ellipse defined by an arbitrary BaseCore and a center point.
Definition: Ellipse.h:50
double maxSincRadius
&quot;Maximum radius (in pixels) for which the sinc algorithm should be used instead of the &quot; &quot;faster naiv...
Definition: ApertureFlux.h:56
x_iterator x_at(int x, int y) const
Return an x_iterator to the point (x, y) in the image.
Definition: Image.h:329
Iterator class for CatalogT.
Definition: Catalog.h:34
A class to manipulate images, masks, and variance as a single object.
Definition: MaskedImage.h:77
static Result computeNaiveFlux(afw::image::Image< T > const &image, afw::geom::ellipses::Ellipse const &ellipse, Control const &ctrl=Control())
SchemaItem< T > find(std::string const &name) const
Find a SchemaItem in the Schema by name.
Flux flux
Measured flux in DN.
Definition: FluxUtilities.h:38
if(width!=gim.getWidth()||height!=gim.getHeight()||x0!=gim.getX0()||y0!=gim.getY0())
Definition: saturated.cc:47
void add(std::string const &name, T const &value)
Definition: PropertySet.cc:619
bool contains(Point2I const &point) const
Return true if the box contains the point.
Box2I const & getBBox() const
Definition: PixelRegion.h:45
A FunctorKey for FluxResult.
Definition: FluxUtilities.h:56
int getY0() const
Definition: Image.h:255
ImageT::Ptr offsetImage(ImageT const &image, float dx, float dy, std::string const &algorithmName="lanczos5", unsigned int buffer=0)
Return an image offset by (dx, dy) using the specified algorithm.
Definition: offsetImage.cc:55
static MagResultKey addFields(afw::table::Schema &schema, std::string const &name)
#define INSTANTIATE(T)
An ellipse core for the semimajor/semiminor axis and position angle parametrization (a...
Definition: Axes.h:45
geom::Box2I getBBox(ImageOrigin origin=PARENT) const
Definition: Image.h:377
_view_t::x_iterator x_iterator
An iterator for traversing the pixels in a row.
Definition: Image.h:151
Class for storing generic metadata.
Definition: PropertySet.h:82
static Result computeSincFlux(afw::image::Image< T > const &image, afw::geom::ellipses::Ellipse const &ellipse, Control const &ctrl=Control())
void set(Key< T > const &key, U const &value)
Set value of a field for the given key.
Definition: BaseRecord.h:136
Record class that contains measurements made on a single exposure.
Definition: Source.h:81
std::vector< MagResultKey > _magKeys
Definition: ApertureFlux.h:274
BaseCore const & getCore() const
Return the ellipse core.
Definition: Ellipse.h:75
std::vector< double > radii
&quot;Radius (in pixels) of apertures.&quot; ;
Definition: ApertureFlux.h:50
FluxErrElement fluxSigma
1-Sigma error (sqrt of variance) on flux in DN.
Definition: FluxUtilities.h:39
Schema const getInputSchema() const
Return the input schema (copy-on-write).
Definition: SchemaMapper.h:23
A class to represent a 2-dimensional array of pixels.
Definition: PSF.h:43
ApertureFluxTransform(Control const &ctrl, std::string const &name, afw::table::SchemaMapper &mapper)
A reusable result struct for flux measurements.
Definition: FluxUtilities.h:37
int getX0() const
Definition: Image.h:247
SafeCentroidExtractor _centroidExtractor
Definition: ApertureFlux.h:214