lsst.jointcal  14.0-14-g932474c+1
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"
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] =
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] =
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) {
134  auto mapping = i.second.get();
135  mapping->offsetParams(delta.segment(mapping->getIndex(), mapping->getNpar()));
136  }
137  if (_fittingVisits)
138  for (auto &i : _visitMap) {
139  auto mapping = i.second.get();
140  mapping->offsetParams(delta.segment(mapping->getIndex(), mapping->getNpar()));
141  }
142 }
143 
145  for (auto i = _visitMap.begin(); i != _visitMap.end(); ++i) i->second->freezeErrorScales();
146  for (auto i = _chipMap.begin(); i != _chipMap.end(); ++i) i->second->freezeErrorScales();
147 }
148 
150  auto chipp = _chipMap.find(chip);
151  if (chipp == _chipMap.end()) {
152  std::stringstream errMsg;
153  errMsg << "No such chipId: '" << chip << "' found in chipMap of: " << this;
154  throw pexExcept::InvalidParameterError(errMsg.str());
155  }
156  return chipp->second->getTransfo();
157 }
158 
159 // Array of visits involved in the solution.
162  res.reserve(_visitMap.size());
163  for (auto i = _visitMap.begin(); i != _visitMap.end(); ++i) res.push_back(i->first);
164  return res;
165 }
166 
168  auto visitp = _visitMap.find(visit);
169  if (visitp == _visitMap.end()) {
170  std::stringstream errMsg;
171  errMsg << "No such visitId: '" << visit << "' found in visitMap of: " << this;
172  throw pexExcept::InvalidParameterError(errMsg.str());
173  }
174  return visitp->second->getTransfo();
175 }
176 
178  const TwoTransfoMapping *mapping;
179  try {
180  mapping = _mappings.at(&ccdImage).get();
181  } catch (std::out_of_range &) {
182  LOGLS_ERROR(_log, "CcdImage with ccd/visit " << ccdImage.getCcdId() << "/" << ccdImage.getVisit()
183  << " not found in constrainedPolyModel mapping list.");
185  for (auto const &i : _mappings) os << i.first << ",";
186  LOGLS_ERROR(_log, "Available CcdImages: " << os.str());
187  return nullptr;
188  }
189 
190  GtransfoPoly pix2Tp;
191  const GtransfoPoly &t1 = dynamic_cast<const GtransfoPoly &>(mapping->getTransfo1());
192  // TODO: This line produces a warning on clang (t1 is always valid: a failed dynamic_cast of a reference
193  // raises bad_cast instead of returning nullptr like a failed pointer cast), but I'll deal with it as
194  // part of DM-10524 (hopefully removing the necessity of the casts).
195  if (!(&t1)) {
196  LOGLS_ERROR(_log, "Problem with transform 1 of ccd/visit " << ccdImage.getCcdId() << "/"
197  << ccdImage.getVisit() << ": T1 "
198  << mapping->getTransfo1());
199  return nullptr;
200  }
201  // NOTE: we currently expect T2 to be an identity for the first visit, so we have to treat it separately.
202  // TODO: We are aware that this is a hack, but it will be fixed as part of DM-10524.
203  try {
204  const GtransfoIdentity &t2 = dynamic_cast<const GtransfoIdentity &>(mapping->getTransfo2());
205  pix2Tp = t1;
206  } catch (std::bad_cast &) {
207  try {
208  const GtransfoPoly &t2_poly = dynamic_cast<const GtransfoPoly &>(mapping->getTransfo2());
209  pix2Tp = t1 * t2_poly;
210  } catch (std::bad_cast &) {
211  LOGLS_ERROR(_log, "Problem with transform 2 of ccd/visit " << ccdImage.getCcdId() << "/"
212  << ccdImage.getVisit() << ": T2 "
213  << mapping->getTransfo2());
214  return nullptr;
215  }
216  }
217  const TanRaDec2Pix *proj = dynamic_cast<const TanRaDec2Pix *>(getSky2TP(ccdImage));
218  if (!proj) {
219  LOGLS_ERROR(_log, "Problem with projection of ccd/visit " << ccdImage.getCcdId() << "/"
220  << ccdImage.getVisit() << ": projection "
221  << getSky2TP(ccdImage));
222  return nullptr;
223  }
224 
225  // should be the identity, but who knows? So, let us incorporate it into the pix2TP part.
226  const GtransfoLin &projLinPart = proj->getLinPart();
227  GtransfoPoly wcsPix2Tp = GtransfoPoly(projLinPart.invert()) * pix2Tp;
228 
229  // compute a decent approximation, if higher order corrections get ignored
230  GtransfoLin cdStuff = wcsPix2Tp.linearApproximation(ccdImage.getImageFrame().getCenter());
231 
232  // wcsPix2TP = cdStuff*sip , so
233  GtransfoPoly sip = GtransfoPoly(cdStuff.invert()) * wcsPix2Tp;
234  Point tangentPoint(proj->getTangentPoint());
235  return std::make_shared<TanSipPix2RaDec>(cdStuff, tangentPoint, &sip);
236 }
237 } // namespace jointcal
238 } // namespace lsst
#define LOGLS_WARN(logger, message)
VisitIdType getVisit() const
returns visit ID
Definition: CcdImage.h:101
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:83
T norm(const T &x)
STL namespace.
Gtransfo const & getVisitTransfo(VisitIdType const &visit) const
Access to mappings.
T end(T... args)
CcdIdType getCcdId() const
returns ccd ID
Definition: CcdImage.h:98
The mapping with two transfos in a row.
STL class.
Gtransfo const * getPix2TangentPlane() const
Definition: CcdImage.h:92
Polynomial transformation class.
Definition: Gtransfo.h:193
GtransfoLin normalizeCoordinatesTransfo(const Frame &frame)
Returns the transformation that maps the input frame along both axes to [-1,1].
Definition: Gtransfo.cc:724
STL class.
T at(T... args)
T push_back(T... args)
rectangle with sides parallel to axes.
Definition: Frame.h:19
#define LOGLS_DEBUG(logger, message)
Class for a simple mapping implementing a generic Gtransfo.
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
T str(T... args)
This is a virtual class that allows a lot of freedom in the choice of the projection from "Sky" (wher...
#define LOGLS_INFO(logger, message)
T get(T... args)
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:150
T find(T... args)
T size(T... args)
virtual GtransfoLin linearApproximation(const Point &where, const double step=0.01) const
linear (local) approximation.
Definition: Gtransfo.cc:92
STL class.
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
T begin(T... args)
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:39
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.
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:25
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:34
#define LOG_GET(logger)
Gtransfo const & getTransfo1() const
access to transfos
Gtransfo const & getTransfo2() const
access to transfos
#define LOGLS_ERROR(logger, message)
Frame const & getImageFrame() const
Frame in pixels.
Definition: CcdImage.h:146
T reserve(T... args)
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.