lsst.jointcal  master-g52a623bc1f+3
ConstrainedPolyModel.cc
Go to the documentation of this file.
1 #include "lsst/log/Log.h"
8 #include "lsst/jointcal/AstroUtils.h" // applyTransfo(Frame)
9 
10 #include "lsst/pex/exceptions.h"
11 namespace pexExcept = lsst::pex::exceptions;
12 
13 #include <string>
14 #include <iostream>
15 
16 namespace {
17 LOG_LOGGER _log = LOG_GET("jointcal.ConstrainedPolyModel");
18 }
19 
20 namespace lsst {
21 namespace jointcal {
22 
23 /* This code does not contain anything involved. It just maps the
24 routines AstrometryFit needs to what is needed for this two-transfo model.
25 The two-transfo mappings are implemented using two one-transfo
26 mappings.*/
27 
28 // TODO : separate the polynomial degrees for chip and visit transfos.
29 // TODO propagate those into python:
30 static int DistortionDegree = 3;
31 
32 using namespace std;
33 
34 ConstrainedPolyModel::ConstrainedPolyModel(CcdImageList const &ccdImageList,
35  ProjectionHandler const *projectionHandler, bool initFromWCS,
36  unsigned nNotFit)
37  : _sky2TP(projectionHandler)
38 
39 {
40  // from datacards (or default)
41  unsigned degree = DistortionDegree;
42  // first loop to initialize all visit and chip transfos.
43  for (auto &ccdImage : ccdImageList) {
44  const CcdImage &im = *ccdImage;
45  auto visit = im.getVisit();
46  auto chip = im.getCcdId();
47  auto visitp = _visitMap.find(visit);
48  if (visitp == _visitMap.end()) {
49  if (_visitMap.size() == 0) {
50  _visitMap[visit] =
51  std::unique_ptr<SimpleGtransfoMapping>(new SimpleGtransfoMapping(GtransfoIdentity()));
52  } else {
53  _visitMap[visit] = std::unique_ptr<SimpleGtransfoMapping>(
55  }
56  }
57  auto chipp = _chipMap.find(chip);
58  if (chipp == _chipMap.end()) {
59  const Frame &frame = im.getImageFrame();
60 
61  _tpFrame += applyTransfo(frame, *im.getPix2CommonTangentPlane(), LargeFrame);
62  GtransfoPoly pol(im.getPix2TangentPlane(), frame, degree);
63  GtransfoLin shiftAndNormalize = normalizeCoordinatesTransfo(frame);
64 
65  _chipMap[chip] = std::unique_ptr<SimplePolyMapping>(
66  new SimplePolyMapping(shiftAndNormalize, pol * shiftAndNormalize.invert()));
67  }
68  }
69  // now, second loop to set the mappings of the CCdImages
70  for (auto &ccdImage : ccdImageList) {
71  const CcdImage &im = *ccdImage;
72  auto visit = im.getVisit();
73  auto chip = im.getCcdId();
74  // check that the chip_indexed part was indeed assigned
75  // (i.e. the reference visit was complete)
76  if (_chipMap.find(chip) == _chipMap.end()) {
77  LOGLS_WARN(_log, "Chip " << chip << " is missing in the reference exposure, expect troubles.");
79  _chipMap[chip] =
80  std::unique_ptr<SimplePolyMapping>(new SimplePolyMapping(norm, GtransfoPoly(degree)));
81  }
82  _mappings[&im] = std::unique_ptr<TwoTransfoMapping>(
83  new TwoTransfoMapping(_chipMap[chip].get(), _visitMap[visit].get()));
84  }
85  LOGLS_INFO(_log, "Constructor got " << _chipMap.size() << " chip mappings and " << _visitMap.size()
86  << " visit mappings.");
87  // DEBUG
88  for (auto i = _visitMap.begin(); i != _visitMap.end(); ++i) LOGLS_DEBUG(_log, i->first);
89 }
90 
92  mappingMapType::const_iterator i = _mappings.find(&ccdImage);
93  if (i == _mappings.end()) return nullptr;
94  return (i->second.get());
95 }
96 
101 unsigned ConstrainedPolyModel::assignIndices(unsigned firstIndex, std::string const &whatToFit) {
102  unsigned index = firstIndex;
103  if (whatToFit.find("Distortions") == std::string::npos) {
104  LOGLS_ERROR(_log, "assignIndices was called and Distortions is *not* in whatToFit");
105  return 0;
106  }
107  // if we get here "Distortions" is in whatToFit
108  _fittingChips = (whatToFit.find("DistortionsChip") != std::string::npos);
109  _fittingVisits = (whatToFit.find("DistortionsVisit") != std::string::npos);
110  // If nothing more than "Distortions" is specified, it means all:
111  if ((!_fittingChips) && (!_fittingVisits)) {
112  _fittingChips = _fittingVisits = true;
113  }
114  if (_fittingChips)
115  for (auto &i : _chipMap) {
116  i.second->setIndex(index);
117  index += i.second->getNpar();
118  }
119  if (_fittingVisits)
120  for (auto &i : _visitMap) {
121  i.second->setIndex(index);
122  index += i.second->getNpar();
123  }
124  // Tell the mappings which derivatives they will have to fill:
125  for (auto &i : _mappings) {
126  i.second->setWhatToFit(_fittingChips, _fittingVisits);
127  }
128  return index;
129 }
130 
131 void ConstrainedPolyModel::offsetParams(Eigen::VectorXd const &delta) {
132  if (_fittingChips)
133  for (auto i = _chipMap.begin(); i != _chipMap.end(); ++i) {
134  auto *p = (&*(i->second));
135  if (p->getNpar()) // probably useless test
136  p->offsetParams(&delta(p->getIndex()));
137  }
138  if (_fittingVisits)
139  for (auto i = _visitMap.begin(); i != _visitMap.end(); ++i) {
140  auto *p = (&*(i->second));
141  if (p->getNpar()) // probably useless test
142  p->offsetParams(&delta(p->getIndex()));
143  }
144 }
145 
147  for (auto i = _visitMap.begin(); i != _visitMap.end(); ++i) i->second->freezeErrorScales();
148  for (auto i = _chipMap.begin(); i != _chipMap.end(); ++i) i->second->freezeErrorScales();
149 }
150 
152  auto chipp = _chipMap.find(chip);
153  if (chipp == _chipMap.end()) {
154  std::stringstream errMsg;
155  errMsg << "No such chipId: '" << chip << "' found in chipMap of: " << this;
156  throw pexExcept::InvalidParameterError(errMsg.str());
157  }
158  return chipp->second->getTransfo();
159 }
160 
161 // Array of visits involved in the solution.
162 std::vector<VisitIdType> ConstrainedPolyModel::getVisits() const {
163  std::vector<VisitIdType> res;
164  res.reserve(_visitMap.size());
165  for (auto i = _visitMap.begin(); i != _visitMap.end(); ++i) res.push_back(i->first);
166  return res;
167 }
168 
170  auto visitp = _visitMap.find(visit);
171  if (visitp == _visitMap.end()) {
172  std::stringstream errMsg;
173  errMsg << "No such visitId: '" << visit << "' found in visitMap of: " << this;
174  throw pexExcept::InvalidParameterError(errMsg.str());
175  }
176  return visitp->second->getTransfo();
177 }
178 
179 std::shared_ptr<TanSipPix2RaDec> ConstrainedPolyModel::produceSipWcs(CcdImage const &ccdImage) const {
180  const TwoTransfoMapping *mapping;
181  try {
182  mapping = _mappings.at(&ccdImage).get();
183  } catch (std::out_of_range &) {
184  LOGLS_ERROR(_log, "CcdImage with ccd/visit " << ccdImage.getCcdId() << "/" << ccdImage.getVisit()
185  << " not found in constrainedPolyModel mapping list.");
186  std::ostringstream os;
187  for (auto const &i : _mappings) os << i.first << ",";
188  LOGLS_ERROR(_log, "Available CcdImages: " << os.str());
189  return nullptr;
190  }
191 
192  GtransfoPoly pix2Tp;
193  const GtransfoPoly &t1 = dynamic_cast<const GtransfoPoly &>(mapping->getTransfo1());
194  // TODO: This line produces a warning on clang (t1 is always valid: a failed dynamic_cast of a reference
195  // raises bad_cast instead of returning nullptr like a failed pointer cast), but I'll deal with it as
196  // part of DM-10524 (hopefully removing the necessity of the casts).
197  if (!(&t1)) {
198  LOGLS_ERROR(_log, "Problem with transform 1 of ccd/visit " << ccdImage.getCcdId() << "/"
199  << ccdImage.getVisit() << ": T1 "
200  << mapping->getTransfo1());
201  return nullptr;
202  }
203  // NOTE: we currently expect T2 to be an identity for the first visit, so we have to treat it separately.
204  // TODO: We are aware that this is a hack, but it will be fixed as part of DM-10524.
205  try {
206  const GtransfoIdentity &t2 = dynamic_cast<const GtransfoIdentity &>(mapping->getTransfo2());
207  pix2Tp = t1;
208  } catch (std::bad_cast &) {
209  try {
210  const GtransfoPoly &t2_poly = dynamic_cast<const GtransfoPoly &>(mapping->getTransfo2());
211  pix2Tp = t1 * t2_poly;
212  } catch (std::bad_cast &) {
213  LOGLS_ERROR(_log, "Problem with transform 2 of ccd/visit " << ccdImage.getCcdId() << "/"
214  << ccdImage.getVisit() << ": T2 "
215  << mapping->getTransfo2());
216  return nullptr;
217  }
218  }
219  const TanRaDec2Pix *proj = dynamic_cast<const TanRaDec2Pix *>(getSky2TP(ccdImage));
220  if (!proj) {
221  LOGLS_ERROR(_log, "Problem with projection of ccd/visit " << ccdImage.getCcdId() << "/"
222  << ccdImage.getVisit() << ": projection "
223  << getSky2TP(ccdImage));
224  return nullptr;
225  }
226 
227  // should be the identity, but who knows? So, let us incorporate it into the pix2TP part.
228  const GtransfoLin &projLinPart = proj->getLinPart();
229  GtransfoPoly wcsPix2Tp = GtransfoPoly(projLinPart.invert()) * pix2Tp;
230 
231  // compute a decent approximation, if higher order corrections get ignored
232  GtransfoLin cdStuff = wcsPix2Tp.linearApproximation(ccdImage.getImageFrame().getCenter());
233 
234  // wcsPix2TP = cdStuff*sip , so
235  GtransfoPoly sip = GtransfoPoly(cdStuff.invert()) * wcsPix2Tp;
236  Point tangentPoint(proj->getTangentPoint());
237  return std::make_shared<TanSipPix2RaDec>(cdStuff, tangentPoint, &sip);
238 }
239 } // namespace jointcal
240 } // namespace lsst
int getCcdId() const
returns ccd ID
Definition: CcdImage.h:132
VisitIdType getVisit() const
returns visit ID
Definition: CcdImage.h:135
implements the linear transformations (6 real coefficients).
Definition: Gtransfo.h:292
void offsetParams(Eigen::VectorXd const &Delta)
Dispaches the offsets after a fit step into the actual locations of parameters.
virtual class needed in the abstraction of the distortion model
Definition: Mapping.h:15
A point in a plane.
Definition: Point.h:13
GtransfoLin invert() const
returns the inverse: T1 = T2.invert();
Definition: Gtransfo.cc:1089
Mapping implementation for a polynomial transformation.
Gtransfo const * getPix2CommonTangentPlane() const
Definition: CcdImage.h:117
STL namespace.
Gtransfo const & getVisitTransfo(VisitIdType const &visit) const
Access to mappings.
The mapping with two transfos in a row.
Gtransfo const * getPix2TangentPlane() const
Definition: CcdImage.h:126
Polynomial transformation class.
Definition: Gtransfo.h:191
GtransfoLin normalizeCoordinatesTransfo(const Frame &frame)
Returns the transformation that maps the input frame along both axes to [-1,1].
Definition: Gtransfo.cc:724
rectangle with sides parallel to axes.
Definition: Frame.h:19
Class for a simple mapping implementing a generic Gtransfo.
Definition: Associations.h:24
std::shared_ptr< TanSipPix2RaDec > produceSipWcs(CcdImage const &ccdImage) const
Cook up a SIP WCS.
Point getTangentPoint() const
tangent point coordinates (in degrees)
Definition: Gtransfo.cc:1459
This is a virtual class that allows a lot of freedom in the choice of the projection from "Sky" (wher...
Point getCenter() const
Center of the frame.
Definition: Frame.h:41
A do-nothing transformation. It anyway has dummy routines to mimick a Gtransfo.
Definition: Gtransfo.h:148
virtual GtransfoLin linearApproximation(const Point &where, const double step=0.01) const
linear (local) approximation.
Definition: Gtransfo.cc:92
std::vector< VisitIdType > getVisits() const
Access to array of visits involved in the solution.
This one is the Tangent Plane (called gnomonic) projection (from celestial sphere to tangent plane) ...
Definition: Gtransfo.h:517
GtransfoLin getLinPart() const
The Linear part (corresponding to CD&#39;s and CRPIX&#39;s)
Definition: Gtransfo.cc:1461
a virtual (interface) class for geometric transformations.
Definition: Gtransfo.h:37
Mapping const * getMapping(CcdImage const &) const
Mapping associated to a given CcdImage.
const Gtransfo * getSky2TP(CcdImage const &ccdImage) const
The mapping of sky coordinates (i.e.
std::list< std::shared_ptr< CcdImage > > CcdImageList
Definition: CcdImage.h:22
Frame applyTransfo(const Frame &inputframe, const Gtransfo &gtransfo, const WhichTransformed which)
Transform a Frame through a Transfo.
Definition: AstroUtils.cc:15
int VisitIdType
Definition: CcdImage.h:24
unsigned assignIndices(unsigned firstIndex, std::string const &whatToFit)
Positions the various parameter sets into the parameter vector, starting at firstIndex.
Handler of an actual image from a single CCD.
Definition: CcdImage.h:31
Gtransfo const & getTransfo1() const
access to transfos
Gtransfo const & getTransfo2() const
access to transfos
Frame const & getImageFrame() const
Frame in pixels.
Definition: CcdImage.h:176
void freezeErrorScales()
From there on, measurement errors are propagated using the current transfos (and no longer evolve)...
Gtransfo const & getChipTransfo(CcdIdType const chip) const
Access to mappings.