Skip to content

Commit

Permalink
Transform SdssShape measurements.
Browse files Browse the repository at this point in the history
  • Loading branch information
jdswinbank committed Apr 11, 2015
1 parent f3e40e6 commit eebdcd1
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 5 deletions.
32 changes: 32 additions & 0 deletions include/lsst/meas/base/SdssShape.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,38 @@ class SdssShapeResult : public ShapeResult, public CentroidResult, public FluxRe

};

/**
* Transformation for SdssShape measurements.
*
* SdssShape measures not just shape but also flux and centroid. This
* transform operates on the first directly, and delegates to the Flux and
* Centroid transforms for the other two.
*/
class SdssShapeTransform : public BaseTransform {
public:
typedef SdssShapeControl Control;

SdssShapeTransform(Control const & ctrl, std::string const & name, afw::table::SchemaMapper & mapper);

/*
* @brief Perform transformation from inputCatalog to outputCatalog.
*
* @param[in] inputCatalog Source of data to be transformed
* @param[in,out] outputCatalog Container for transformed results
* @param[in] wcs World coordinate system under which transformation will take place
* @param[in] calib Photometric calibration under which transformation will take place
* @throws LengthError Catalog sizes do not match
*/
virtual void operator()(afw::table::SourceCatalog const & inputCatalog,
afw::table::BaseCatalog & outputCatalog,
afw::image::Wcs const & wcs,
afw::image::Calib const & calib) const;
private:
FluxTransform _fluxTransform;
CentroidTransform _centroidTransform;
ShapeResultKey _outShapeKey;
};

}}} // namespace lsst::meas::base

#endif // !LSST_MEAS_BASE_SdssShape_h_INCLUDED
3 changes: 2 additions & 1 deletion python/lsst/meas/base/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@
wrapSimpleAlgorithm(SdssCentroidAlgorithm, Control=SdssCentroidControl,
TransformClass=SdssCentroidTransform, executionOrder=0.0)
wrapSimpleAlgorithm(PixelFlagsAlgorithm, Control=PixelFlagsControl, executionOrder=2.0)
wrapSimpleAlgorithm(SdssShapeAlgorithm, Control=SdssShapeControl, executionOrder=1.0)
wrapSimpleAlgorithm(SdssShapeAlgorithm, Control=SdssShapeControl,
TransformClass=SdssShapeTransform, executionOrder=1.0)

wrapSimpleAlgorithm(CircularApertureFluxAlgorithm, needsMetadata=True, Control=ApertureFluxControl,
TransformClass=ApertureFluxTransform, executionOrder=2.0)
Expand Down
2 changes: 2 additions & 0 deletions python/lsst/meas/base/pluginsLib.i
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
%convertConfig(lsst::meas::base, GaussianCentroidTransform)
%convertConfig(lsst::meas::base, SdssCentroidTransform)

%convertConfig(lsst::meas::base, SdssShapeTransform)

%include "lsst/meas/base/Transform.h"

// flux algorithms
Expand Down
2 changes: 1 addition & 1 deletion python/lsst/meas/base/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def makeMinimalSchema(cls):
schema, "truth", "true simulated centroid", "pixels"
)
cls.keys["shape"] = lsst.afw.table.QuadrupoleKey.addFields(
schema, "truth", "true shape after PSF convolution", "pixels^2"
schema, "truth", "true shape after PSF convolution", lsst.afw.table.PIXEL
)
cls.keys["isStar"] = schema.addField("truth_isStar", type="Flag",
doc="set if the object is a star")
Expand Down
2 changes: 1 addition & 1 deletion python/lsst/meas/base/utilities.i
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// -*- lsst-c++ -*-
/*
* LSST Data Management System
* Copyright 2008-2014 LSST Corporation.
* Copyright 2008-2015 AURA/LSST.
*
* This product includes software developed by the
* LSST Project (http://www.lsst.org/).
Expand Down
52 changes: 51 additions & 1 deletion src/SdssShape.cc
Original file line number Diff line number Diff line change
Expand Up @@ -882,5 +882,55 @@ INSTANTIATE_PIXEL(int);
INSTANTIATE_PIXEL(float);
INSTANTIATE_PIXEL(double);

}}} // end namespace lsst::meas::base
SdssShapeTransform::SdssShapeTransform(
Control const & ctrl,
std::string const & name,
afw::table::SchemaMapper & mapper
) :
BaseTransform{name},
_fluxTransform{name, mapper},
_centroidTransform{name, mapper}
{
for (auto flag = flagDefs.begin() + 1; flag < flagDefs.end(); flag++) {
mapper.addMapping(mapper.getInputSchema().find<afw::table::Flag>(
mapper.getInputSchema().join(name, flag->name)).key);
}

_outShapeKey = ShapeResultKey::addFields(mapper.editOutputSchema(), name, "Shape in celestial moments",
FULL_COVARIANCE, afw::table::CoordinateType::CELESTIAL);
}

void SdssShapeTransform::operator()(
afw::table::SourceCatalog const & inputCatalog,
afw::table::BaseCatalog & outputCatalog,
afw::image::Wcs const & wcs,
afw::image::Calib const & calib
) const {
// The flux and cetroid transforms will check that the catalog lengths
// match and throw if not, so we don't repeat the test here.
_fluxTransform(inputCatalog, outputCatalog, wcs, calib);
_centroidTransform(inputCatalog, outputCatalog, wcs, calib);

CentroidResultKey centroidKey(inputCatalog.getSchema()[_name]);
ShapeResultKey inShapeKey(inputCatalog.getSchema()[_name]);

afw::table::SourceCatalog::const_iterator inSrc = inputCatalog.begin();
afw::table::BaseCatalog::iterator outSrc = outputCatalog.begin();
for (; inSrc < inputCatalog.end(); ++inSrc, ++outSrc) {
ShapeResult inShape = inShapeKey.get(*inSrc);
ShapeResult outShape;

// The transformation from the (x, y) to the (Ra, Dec) basis.
afw::geom::AffineTransform crdTr = wcs.linearizePixelToSky(centroidKey.get(*inSrc).getCentroid(),
afw::geom::radians);
outShape.setShape(inShape.getShape().transform(crdTr.getLinear()));

// Transformation matrix from pixel to celestial basis.
ShapeTrMatrix m = makeShapeTransformMatrix(crdTr.getLinear());
outShape.setShapeErr((m*inShape.getShapeErr().cast<double>()*m.transpose()).cast<ErrElement>());

_outShapeKey.set(*outSrc, outShape);
}
}

}}} // end namespace lsst::meas::base
42 changes: 41 additions & 1 deletion tests/testSdssShape.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@

import lsst.utils.tests
import lsst.meas.base.tests
from lsst.meas.base.tests import (AlgorithmTestCase, FluxTransformTestCase,
CentroidTransformTestCase, SingleFramePluginTransformSetupHelper)

class SdssShapeTestCase(lsst.meas.base.tests.AlgorithmTestCase):
class SdssShapeTestCase(AlgorithmTestCase):

def setUp(self):
self.bbox = lsst.afw.geom.Box2I(lsst.afw.geom.Point2I(-20, -30),
Expand Down Expand Up @@ -73,13 +75,51 @@ def testGaussians(self):
self.assertFinite(result.yy_xy_Cov)


class SdssShapeTransformTestCase(FluxTransformTestCase, CentroidTransformTestCase,
SingleFramePluginTransformSetupHelper):
name = "sdssShape"
controlClass = lsst.meas.base.SdssShapeControl
algorithmClass = lsst.meas.base.SdssShapeAlgorithm
transformClass = lsst.meas.base.SdssShapeTransform
flagNames = ("flag", "flag_unweighted", "flag_unweightedBad", "flag_shift", "flag_maxIter")
singleFramePlugins = ('base_SdssShape',)
forcedPlugins = ('base_SdssShape',)

def _setFieldsInRecord(self, record, name):
FluxTransformTestCase._setFieldsInRecord(self, record, name)
CentroidTransformTestCase._setFieldsInRecord(self, record, name)
for field in ('xx', 'yy', 'xy', 'xxSigma', 'yySigma', 'xySigma'):
record[record.schema.join(name, field)] = numpy.random.random()

def _compareFieldsInRecords(self, inSrc, outSrc, name):
FluxTransformTestCase._compareFieldsInRecords(self, inSrc, outSrc, name)
CentroidTransformTestCase._compareFieldsInRecords(self, inSrc, outSrc, name)

inShape = lsst.meas.base.ShapeResultKey(inSrc.schema[name], lsst.afw.table.PIXEL).get(inSrc)
outShape = lsst.meas.base.ShapeResultKey(outSrc.schema[name], lsst.afw.table.CELESTIAL).get(outSrc)

centroid = lsst.meas.base.CentroidResultKey(inSrc.schema[name]).get(inSrc).getCentroid()
xform = self.calexp.getWcs().linearizePixelToSky(centroid, lsst.afw.geom.radians)

trInShape = inShape.getShape().transform(xform.getLinear())
self.assertEqual(trInShape.getIxx(), outShape.getShape().getIxx())
self.assertEqual(trInShape.getIyy(), outShape.getShape().getIyy())
self.assertEqual(trInShape.getIxy(), outShape.getShape().getIxy())

m = lsst.meas.base.makeShapeTransformMatrix(xform.getLinear())
numpy.testing.assert_array_almost_equal(
numpy.dot(numpy.dot(m, inShape.getShapeErr()), m.transpose()), outShape.getShapeErr()
)


def suite():
"""Returns a suite containing all the test cases in this module."""

lsst.utils.tests.init()

suites = []
suites += unittest.makeSuite(SdssShapeTestCase)
suites += unittest.makeSuite(SdssShapeTransformTestCase)
suites += unittest.makeSuite(lsst.utils.tests.MemoryTestCase)
return unittest.TestSuite(suites)

Expand Down

0 comments on commit eebdcd1

Please sign in to comment.