lsst.jointcal  master-ga8493ae4fe+5
SipToGtransfo.cc
Go to the documentation of this file.
1 #include <algorithm>
2 
3 #include "Eigen/Core"
5 #include "lsst/afw/image/ImageUtils.h"
6 #include "lsst/jointcal/Point.h"
7 #include "lsst/jointcal/Frame.h"
8 #include "lsst/daf/base/PropertySet.h"
9 
10 namespace jointcal = lsst::jointcal;
11 namespace afwImg = lsst::afw::image;
12 namespace afwGeom = lsst::afw::geom;
13 
14 namespace lsst {
15 namespace jointcal {
16 
17 typedef std::shared_ptr<jointcal::GtransfoPoly> GtPoly_Ptr;
18 
19 jointcal::TanSipPix2RaDec convertTanWcs(const std::shared_ptr<lsst::afw::image::TanWcs> wcs) {
20  GtPoly_Ptr sipCorr(new jointcal::GtransfoPoly(0));
21 
22  /* beware : Wcs::getPixelOrigin return crpix_fits - 1,
23  so all the algebra we perform here happens in the
24  "Lsst frame", i.e (0,0)-based. this algebra is justified in the
25  documentation of the package. */
26 
27  lsst::afw::geom::Point2D crpix_lsst = wcs->getPixelOrigin();
28 
29  lsst::daf::base::PropertyList::Ptr wcsMeta = wcs->getFitsMetadata();
30 
31  if (wcs->hasDistortion()) {
32  Eigen::MatrixXd sipA;
33  Eigen::MatrixXd sipB;
34  lsst::afw::image::TanWcs::decodeSipHeader(*wcsMeta, "A", sipA);
35  lsst::afw::image::TanWcs::decodeSipHeader(*wcsMeta, "B", sipB);
36 
37  int sipOrder = std::max(wcsMeta->get<int>("A_ORDER"), wcsMeta->get<int>("B_ORDER"));
38 
39  jointcal::GtransfoPoly sipPoly(sipOrder);
40  for (int i = 0; i <= sipOrder; ++i) {
41  for (int j = 0; j <= sipOrder; ++j) {
42  if (i < sipA.cols() && j < sipA.rows() && (i + j) <= sipOrder)
43  sipPoly.coeff(i, j, 0) = sipA(i, j);
44  if (i < sipB.cols() && j < sipB.rows() && (i + j) <= sipOrder)
45  sipPoly.coeff(i, j, 1) = sipB(i, j);
46  }
47  }
48 
49  jointcal::GtransfoLinShift s2(-crpix_lsst[0], -crpix_lsst[1]);
50 
51  /* then the SIP correction (TanWcs::undistorPixel, last line)
52  returns pix + sipPoly*secondShift(pix) where secondShift
53  subtracts crpix_header from (1,1) based coordinates, i.e. the
54  same thing as subtracting crpix_lsst from (0,0-based
55  coordinates. So undistort pixel does:
56  id+sipPoly*s2
57  */
58 
59  GtransfoLin id; // identity is the default constructor.
60  // This is what is returned by TanWcs::undistortpixel
61  jointcal::GtransfoPoly actualSip = id + sipPoly * s2;
62 
63  sipCorr.reset(new jointcal::GtransfoPoly(actualSip));
64  }
65 
66  // now compute the lin part (nothing to do with SIP) */
67  Eigen::Matrix2d cdMat = wcs->getCDMatrix();
68  jointcal::GtransfoLin cdTrans;
69  cdTrans.coeff(1, 0, 0) = cdMat(0, 0); // CD1_1
70  cdTrans.coeff(0, 1, 0) = cdMat(0, 1); // CD1_2
71  cdTrans.coeff(1, 0, 1) = cdMat(1, 0); // CD2_1
72  cdTrans.coeff(0, 1, 1) = cdMat(1, 1); // CD2_1
73  // this is by chance equal to s2, but we will not rely on this fact:
74  jointcal::GtransfoLinShift crpixShift(-crpix_lsst[0], -crpix_lsst[1]);
75 
76  // CD's apply to CRPIX-shifted coordinate
77  jointcal::GtransfoLin linPart = cdTrans * crpixShift;
78 
79  // lsst::afw::coord::Coord tp = wcs->getSkyOrigin()->getPosition(lsst::afw::geom::degrees);
80  // the above line returns radians ?!
81  double ra = wcsMeta->get<double>("CRVAL1");
82  double dec = wcsMeta->get<double>("CRVAL2");
83 
84  jointcal::Point tangentPoint(ra, dec);
85 
86  // return jointcal::TanSipPix2RaDec(linPart, tangentPoint, sipCorr->get());
87  return jointcal::TanSipPix2RaDec(linPart, tangentPoint, (const jointcal::GtransfoPoly *)sipCorr.get());
88 }
89 
90 /* The inverse transformation i.e. convert from the fit result to the SIP
91  convention. */
92 PTR(afwImg::TanWcs)
93 gtransfoToTanWcs(const jointcal::TanSipPix2RaDec wcsTransfo, const jointcal::Frame &ccdFrame,
94  const bool noLowOrderSipTerms) {
95  GtransfoLin linPart = wcsTransfo.getLinPart();
96  afwGeom::Point2D crpix_lsst; // in LSST "frame"
97  /* In order to remove the low order sip terms, one has to
98  define the linear WCS transformation as the expansion of
99  the total pix-to-tangent plane (or focal plane) at the
100  tangent point. In order to do that, we first have to find
101  which pixel transforms to the tangent point, and then expand there */
102 
103  /* compute crpix as the point that is transformed by the linear part
104  into (0,0) */
105  linPart.invert().apply(0., 0., crpix_lsst[0], crpix_lsst[1]);
106 
107  // This is what we have to respect:
108  jointcal::GtransfoPoly pix2TP = wcsTransfo.getPix2TangentPlane();
109 
110  if (noLowOrderSipTerms) {
111  Point ctmp = Point(crpix_lsst[0], crpix_lsst[1]);
112  // cookup a large Frame
113  jointcal::Frame f(ctmp.x - 10000, ctmp.y - 10000, ctmp.x + 10000, ctmp.y + 10000);
114  auto r = pix2TP.inverseTransfo(1e-6, f);
115  // overwrite crpix ...
116  r->apply(0, 0, crpix_lsst[0], crpix_lsst[1]);
117  // and the "linpart"
118  linPart = pix2TP.linearApproximation(Point(crpix_lsst[0], crpix_lsst[1]));
119  }
120 
121  /* At this stage, crpix should not be shifted from "LSST units" to
122  "FITS units" yet because the TanWcs constructors expect it in LSST
123  units */
124 
125  // crval from type conversion
126  afwGeom::Point2D crval;
127  crval[0] = wcsTransfo.getTangentPoint().x;
128  crval[1] = wcsTransfo.getTangentPoint().y;
129 
130  // CD matrix:
131  Eigen::Matrix2d cdMat;
132  cdMat(0, 0) = linPart.coeff(1, 0, 0); // CD1_1
133  cdMat(0, 1) = linPart.coeff(0, 1, 0); // CD1_2
134  cdMat(1, 0) = linPart.coeff(1, 0, 1); // CD2_1
135  cdMat(1, 1) = linPart.coeff(0, 1, 1); // CD2_2
136 
137  if (!wcsTransfo.getCorr()) // the WCS has no distortions
138  return std::make_shared<afwImg::TanWcs>(crval, crpix_lsst, cdMat);
139 
140  /* We are now given:
141  - CRPIX
142  - The CD matrix
143  - the lin part (i.e. the combination of CRPIX and CD)
144  - and pix2TP, the total transformation from pixels to tangent plane
145  and we want to extract the SIP polynomials. The algebra is detailed
146  in the appendix of the documentation */
147 
148  // This is (the opposite of) the crpix that will go into the fits header:
149  jointcal::GtransfoLinShift s2(-crpix_lsst[0], -crpix_lsst[1]);
150 
151  // for SIP, pix2TP = linpart*sipStuff, so
152  jointcal::GtransfoPoly sipTransform = jointcal::GtransfoPoly(linPart.invert()) * pix2TP;
153  // then the sip transform reads ST = (ID+PA*S2)
154  // PA*S2 = ST -ID, PA = (ST-Id)*S2^-1
155  jointcal::GtransfoLin id; // default constructor = identity
156  jointcal::GtransfoPoly sipPoly = (sipTransform - id) * s2.invert();
157 
158  // coockup the inverse sip polynomials
159  // last argument : precision in pixels.
160  auto tp2Pix = inversePolyTransfo(pix2TP, ccdFrame, 1e-4);
161  if (!tp2Pix) {
162  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
163  "GtransfoToSip: could not invert the input wcs ");
164  }
165  jointcal::GtransfoPoly invSipStuff = (*tp2Pix) * linPart;
166  jointcal::GtransfoPoly sipPolyInv = (invSipStuff - id) * s2.invert();
167 
168  // now extract sip coefficients. First forward ones:
169  int sipOrder = sipPoly.getDegree();
170  Eigen::MatrixXd sipA(Eigen::MatrixXd::Zero(sipOrder + 1, sipOrder + 1));
171  Eigen::MatrixXd sipB(Eigen::MatrixXd::Zero(sipOrder + 1, sipOrder + 1));
172  for (int i = 0; i <= sipOrder; ++i)
173  for (int j = 0; j <= sipOrder - i; ++j) {
174  sipA(i, j) = sipPoly.coeff(i, j, 0);
175  sipB(i, j) = sipPoly.coeff(i, j, 1);
176  }
177 
178  // now backwards coefficients
179  sipOrder = sipPolyInv.getDegree();
180  Eigen::MatrixXd sipAp(Eigen::MatrixXd::Zero(sipOrder + 1, sipOrder + 1));
181  Eigen::MatrixXd sipBp(Eigen::MatrixXd::Zero(sipOrder + 1, sipOrder + 1));
182  for (int i = 0; i <= sipOrder; ++i)
183  for (int j = 0; j <= sipOrder - i; ++j) {
184  sipAp(i, j) = sipPolyInv.coeff(i, j, 0);
185  sipBp(i, j) = sipPolyInv.coeff(i, j, 1);
186  }
187 
188  return std::make_shared<afwImg::TanWcs>(crval, crpix_lsst, cdMat, sipA, sipB, sipAp, sipBp);
189 }
190 } // namespace jointcal
191 } // namespace lsst
Implements the (forward) SIP distorsion scheme.
Definition: Gtransfo.h:483
implements the linear transformations (6 real coefficients).
Definition: Gtransfo.h:292
void apply(const double xIn, const double yIn, double &xOut, double &yOut) const
Definition: Gtransfo.cc:485
A point in a plane.
Definition: Point.h:13
GtransfoLin invert() const
returns the inverse: T1 = T2.invert();
Definition: Gtransfo.cc:1089
Polynomial transformation class.
Definition: Gtransfo.h:191
double x
coordinate
Definition: Point.h:18
std::unique_ptr< GtransfoPoly > inversePolyTransfo(const Gtransfo &Direct, const Frame &frame, const double Prec)
approximates the inverse by a polynomial, up to required precision.
Definition: Gtransfo.cc:1012
rectangle with sides parallel to axes.
Definition: Frame.h:19
Class for a simple mapping implementing a generic Gtransfo.
Definition: Associations.h:24
unsigned getDegree() const
returns degree
Definition: Gtransfo.h:232
boost::shared_ptr< lsst::afw::image::TanWcs > gtransfoToTanWcs(const lsst::jointcal::TanSipPix2RaDec wcsTransfo, const lsst::jointcal::Frame &ccdFrame, const bool noLowOrderSipTerms=false)
Transform the other way around.
virtual GtransfoLin linearApproximation(const Point &where, const double step=0.01) const
linear (local) approximation.
Definition: Gtransfo.cc:92
just here to provide a specialized constructor, and fit.
Definition: Gtransfo.h:356
double coeff(const unsigned powX, const unsigned powY, const unsigned whichCoord) const
access to coefficients (read only)
Definition: Gtransfo.cc:650
std::shared_ptr< jointcal::GtransfoPoly > GtPoly_Ptr
virtual std::unique_ptr< Gtransfo > inverseTransfo(const double precision, const Frame &region) const
returns an inverse transfo. Numerical if not overloaded.
Definition: Gtransfo.cc:251
TanSipPix2RaDec convertTanWcs(const std::shared_ptr< lsst::afw::image::TanWcs > wcs)
Transform an afw TanWcs into a Gtransfo.