lsst.jointcal  15.0-7-gab4c137+8
ConstrainedAstrometryModel.cc
Go to the documentation of this file.
1 #include "astshim.h"
2 #include "lsst/afw/geom.h"
3 #include "lsst/log/Log.h"
11 
12 #include "lsst/pex/exceptions.h"
14 
15 #include <memory>
16 #include <string>
17 #include <iostream>
18 
19 namespace {
20 LOG_LOGGER _log = LOG_GET("jointcal.ConstrainedAstrometryModel");
21 }
22 
23 namespace {
24 // Append the keys of this map into a comma-separated string.
25 template <typename KeyType, typename ValueType>
26 void outputMapKeys(std::map<KeyType, ValueType> const &map, std::ostream &os) {
27  bool first = true;
28  os << "[";
29  for (auto const &i : map) {
30  if (first)
31  first = false;
32  else
33  os << ", ";
34  os << i.first;
35  }
36  os << "]";
37 }
38 } // namespace
39 
40 namespace lsst {
41 namespace jointcal {
42 
43 ConstrainedAstrometryModel::ConstrainedAstrometryModel(
45  int chipOrder, int visitOrder)
46  : _sky2TP(projectionHandler) {
47  // keep track of which chip we want to hold fixed (the one closest to the middle of the focal plane)
48  double minRadius2 = std::numeric_limits<double>::infinity();
49  CcdIdType constrainedChip = -1;
50 
51  // first loop to initialize all visit and chip transfos.
52  for (auto &ccdImage : ccdImageList) {
53  const CcdImage &im = *ccdImage;
54  auto visit = im.getVisit();
55  auto chip = im.getCcdId();
56  auto visitp = _visitMap.find(visit);
57  if (visitp == _visitMap.end()) {
58  _visitMap[visit] = std::make_shared<SimplePolyMapping>(GtransfoLin(), GtransfoPoly(visitOrder));
59  }
60  auto chipp = _chipMap.find(chip);
61  if (chipp == _chipMap.end()) {
62  auto center = ccdImage->getDetector()->getCenter(afw::cameraGeom::FOCAL_PLANE);
63  double radius2 = std::pow(center.getX(), 2) + std::pow(center.getY(), 2);
64  if (radius2 < minRadius2) {
65  minRadius2 = radius2;
66  constrainedChip = chip;
67  }
68 
69  auto pixelsToFocal =
71  Frame const &frame = im.getImageFrame();
72  // construct the chip gtransfo by approximating the pixel->Focal afw::geom::Transform.
73  GtransfoPoly pol = GtransfoPoly(pixelsToFocal, frame, chipOrder);
74  GtransfoLin shiftAndNormalize = normalizeCoordinatesTransfo(frame);
75  _chipMap[chip] =
76  std::make_shared<SimplePolyMapping>(shiftAndNormalize, pol * shiftAndNormalize.invert());
77  }
78  }
79 
80  // Hold the "central" chip map fixed and don't fit it, to remove a degeneracy.
81  _chipMap.at(constrainedChip)->setToBeFit(false);
82 
83  // now, second loop to set the mappings of the CCdImages
84  for (auto &ccdImage : ccdImageList) {
85  const CcdImage &im = *ccdImage;
86  auto visit = im.getVisit();
87  auto chip = im.getCcdId();
88 
89  // check that the chip_indexed part was indeed assigned
90  // (i.e. the reference visit was complete)
91  if (_chipMap.find(chip) == _chipMap.end()) {
92  LOGLS_WARN(_log, "Chip " << chip << " is missing in the reference exposure, expect troubles.");
94  _chipMap[chip] = std::make_shared<SimplePolyMapping>(norm, GtransfoPoly(chipOrder));
95  }
96  _mappings[ccdImage->getHashKey()] =
97  std::make_unique<TwoTransfoMapping>(_chipMap[chip], _visitMap[visit]);
98  }
99  LOGLS_INFO(_log, "Got " << _chipMap.size() << " chip mappings and " << _visitMap.size()
100  << " visit mappings; holding chip " << constrainedChip << " fixed.");
101  LOGLS_DEBUG(_log, "CcdImage map has " << _mappings.size() << " mappings, with "
102  << _mappings.bucket_count() << " buckets and a load factor of "
103  << _mappings.load_factor());
104 }
105 
107  return findMapping(ccdImage);
108 }
109 
114 unsigned ConstrainedAstrometryModel::assignIndices(std::string const &whatToFit, unsigned firstIndex) {
115  unsigned index = firstIndex;
116  if (whatToFit.find("Distortions") == std::string::npos) {
117  LOGLS_ERROR(_log, "assignIndices was called and Distortions is *not* in whatToFit");
118  return 0;
119  }
120  // if we get here "Distortions" is in whatToFit
121  _fittingChips = (whatToFit.find("DistortionsChip") != std::string::npos);
122  _fittingVisits = (whatToFit.find("DistortionsVisit") != std::string::npos);
123  // If nothing more than "Distortions" is specified, it means all:
124  if ((!_fittingChips) && (!_fittingVisits)) {
125  _fittingChips = _fittingVisits = true;
126  }
127  if (_fittingChips)
128  for (auto &i : _chipMap) {
129  i.second->setIndex(index);
130  index += i.second->getNpar();
131  }
132  if (_fittingVisits)
133  for (auto &i : _visitMap) {
134  i.second->setIndex(index);
135  index += i.second->getNpar();
136  }
137  // Tell the mappings which derivatives they will have to fill:
138  for (auto &i : _mappings) {
139  i.second->setWhatToFit(_fittingChips, _fittingVisits);
140  }
141  return index;
142 }
143 
144 void ConstrainedAstrometryModel::offsetParams(Eigen::VectorXd const &delta) {
145  if (_fittingChips)
146  for (auto &i : _chipMap) {
147  auto mapping = i.second.get();
148  mapping->offsetParams(delta.segment(mapping->getIndex(), mapping->getNpar()));
149  }
150  if (_fittingVisits)
151  for (auto &i : _visitMap) {
152  auto mapping = i.second.get();
153  mapping->offsetParams(delta.segment(mapping->getIndex(), mapping->getNpar()));
154  }
155 }
156 
158  for (auto i = _visitMap.begin(); i != _visitMap.end(); ++i) i->second->freezeErrorTransform();
159  for (auto i = _chipMap.begin(); i != _chipMap.end(); ++i) i->second->freezeErrorTransform();
160 }
161 
163  auto chipp = _chipMap.find(chip);
164  if (chipp == _chipMap.end()) {
165  std::stringstream errMsg;
166  errMsg << "No such chipId: " << chip << " among ";
167  outputMapKeys(_chipMap, errMsg);
168  std::cout << std::endl;
169  throw pexExcept::InvalidParameterError(errMsg.str());
170  }
171  return chipp->second->getTransfo();
172 }
173 
174 // Array of visits involved in the solution.
177  res.reserve(_visitMap.size());
178  for (auto i = _visitMap.begin(); i != _visitMap.end(); ++i) res.push_back(i->first);
179  return res;
180 }
181 
183  auto visitp = _visitMap.find(visit);
184  if (visitp == _visitMap.end()) {
185  std::stringstream errMsg;
186  errMsg << "No such visitId: " << visit << " among ";
187  outputMapKeys(_visitMap, errMsg);
188  std::cout << std::endl;
189  throw pexExcept::InvalidParameterError(errMsg.str());
190  }
191  return visitp->second->getTransfo();
192 }
193 
195  auto proj = std::dynamic_pointer_cast<const TanRaDec2Pix>(getSky2TP(ccdImage));
196  jointcal::Point tangentPoint(proj->getTangentPoint());
197 
198  auto imageFrame = ccdImage.getImageFrame();
199  auto pixelsToFocal = getChipTransfo(ccdImage.getCcdId()).toAstMap(imageFrame);
200  jointcal::Frame focalBox = getChipTransfo(ccdImage.getCcdId()).apply(imageFrame, false);
201  auto focalToIwc = getVisitTransfo(ccdImage.getVisit()).toAstMap(focalBox);
202 
203  ast::Frame pixelFrame(2, "Domain=PIXELS");
204  ast::Frame focalFrame(2, "Domain=FOCAL");
205  ast::Frame iwcFrame(2, "Domain=IWC");
206 
207  // make a basic SkyWcs and extract the IWC portion
208  auto iwcToSkyWcs = afw::geom::makeSkyWcs(
209  afw::geom::Point2D(0, 0),
210  afw::geom::SpherePoint(tangentPoint.x, tangentPoint.y, afw::geom::degrees),
212  auto iwcToSkyMap = iwcToSkyWcs->getFrameDict()->getMapping("PIXELS", "SKY");
213  auto skyFrame = iwcToSkyWcs->getFrameDict()->getFrame("SKY");
214 
215  ast::FrameDict frameDict(pixelFrame);
216  frameDict.addFrame("PIXELS", *pixelsToFocal, focalFrame);
217  frameDict.addFrame("FOCAL", *focalToIwc, iwcFrame);
218  frameDict.addFrame("IWC", *iwcToSkyMap, *skyFrame);
219  return std::make_shared<afw::geom::SkyWcs>(frameDict);
220 }
221 
222 AstrometryMapping *ConstrainedAstrometryModel::findMapping(CcdImage const &ccdImage) const {
223  auto i = _mappings.find(ccdImage.getHashKey());
224  if (i == _mappings.end())
226  "ConstrainedAstrometryModel cannot find CcdImage " + ccdImage.getName());
227  return i->second.get();
228 }
229 
230 } // namespace jointcal
231 } // namespace lsst
const std::shared_ptr< Gtransfo const > getSky2TP(CcdImage const &ccdImage) const
The mapping of sky coordinates (i.e.
VisitIdType getVisit() const
returns visit ID
Definition: CcdImage.h:108
implements the linear transformations (6 real coefficients).
Definition: Gtransfo.h:391
A point in a plane.
Definition: Point.h:13
unsigned assignIndices(std::string const &whatToFit, unsigned firstIndex)
Positions the various parameter sets into the parameter vector, starting at firstIndex.
void freezeErrorTransform()
From there on, measurement errors are propagated using the current transfos (and no longer evolve)...
std::string getName() const
Return the _name that identifies this ccdImage.
Definition: CcdImage.h:50
CameraSysPrefix const PIXELS
T endl(T... args)
AngleUnit constexpr degrees
T norm(const T &x)
std::vector< VisitIdType > getVisits() const
Access to array of visits involved in the solution.
std::shared_ptr< afw::geom::SkyWcs > makeSkyWcs(CcdImage const &ccdImage) const
Make a SkyWcs that contains this model.
CcdIdType getCcdId() const
returns ccd ID
Definition: CcdImage.h:105
Gtransfo const & getVisitTransfo(VisitIdType const &visit) const
Access to mappings.
Polynomial transformation class.
Definition: Gtransfo.h:253
GtransfoLin normalizeCoordinatesTransfo(const Frame &frame)
Returns the transformation that maps the input frame along both axes to [-1,1].
Definition: Gtransfo.cc:764
STL class.
#define LOGLS_INFO(logger, message)
STL class.
pairs of points
T push_back(T... args)
void addFrame(int iframe, Mapping const &map, Frame const &frame) override
first
rectangle with sides parallel to axes.
Definition: Frame.h:15
Class for a simple mapping implementing a generic Gtransfo.
T str(T... args)
void offsetParams(Eigen::VectorXd const &Delta)
Dispaches the offsets after a fit step into the actual locations of parameters.
T dynamic_pointer_cast(T... args)
T infinity(T... args)
Gtransfo const & getChipTransfo(CcdIdType const chip) const
Access to mappings.
T find(T... args)
#define LSST_EXCEPT(type,...)
STL class.
This one is the Tangent Plane (called gnomonic) projection (from celestial sphere to tangent plane) ...
Definition: Gtransfo.h:653
T pow(T... args)
a virtual (interface) class for geometric transformations.
Definition: Gtransfo.h:42
std::shared_ptr< SkyWcs > makeSkyWcs(daf::base::PropertySet &metadata, bool strip=false)
#define LOGLS_DEBUG(logger, message)
Eigen::Matrix2d makeCdMatrix(Angle const &scale, Angle const &orientation=0 *degrees, bool flipX=false)
int VisitIdType
Definition: CcdImage.h:25
virtual class needed in the abstraction of the distortion model
CcdImageKey getHashKey() const
Definition: CcdImage.h:112
std::shared_ptr< afw::cameraGeom::Detector > getDetector() const
Definition: CcdImage.h:110
AstrometryMapping const * getMapping(CcdImage const &) const
Mapping associated to a given CcdImage.
Handler of an actual image from a single CCD.
Definition: CcdImage.h:35
CameraSys const FOCAL_PLANE
STL class.
#define LOG_GET(logger)
Frame const & getImageFrame() const
Frame in pixels.
Definition: CcdImage.h:150
#define LOGLS_ERROR(logger, message)
#define LOGLS_WARN(logger, message)
T reserve(T... args)