LSSTApplications  18.0.0+106,18.0.0+50,19.0.0,19.0.0+1,19.0.0+10,19.0.0+11,19.0.0+13,19.0.0+17,19.0.0+2,19.0.0-1-g20d9b18+6,19.0.0-1-g425ff20,19.0.0-1-g5549ca4,19.0.0-1-g580fafe+6,19.0.0-1-g6fe20d0+1,19.0.0-1-g7011481+9,19.0.0-1-g8c57eb9+6,19.0.0-1-gb5175dc+11,19.0.0-1-gdc0e4a7+9,19.0.0-1-ge272bc4+6,19.0.0-1-ge3aa853,19.0.0-10-g448f008b,19.0.0-12-g6990b2c,19.0.0-2-g0d9f9cd+11,19.0.0-2-g3d9e4fb2+11,19.0.0-2-g5037de4,19.0.0-2-gb96a1c4+3,19.0.0-2-gd955cfd+15,19.0.0-3-g2d13df8,19.0.0-3-g6f3c7dc,19.0.0-4-g725f80e+11,19.0.0-4-ga671dab3b+1,19.0.0-4-gad373c5+3,19.0.0-5-ga2acb9c+2,19.0.0-5-gfe96e6c+2,w.2020.01
LSSTDataManagementBasePackage
ConstrainedAstrometryModel.cc
Go to the documentation of this file.
1 // -*- LSST-C++ -*-
2 /*
3  * This file is part of jointcal.
4  *
5  * Developed for the LSST Data Management System.
6  * This product includes software developed by the LSST Project
7  * (https://www.lsst.org).
8  * See the COPYRIGHT file at the top-level directory of this distribution
9  * for details of code ownership.
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program. If not, see <https://www.gnu.org/licenses/>.
23  */
24 
25 #include "astshim.h"
26 #include "lsst/afw/geom.h"
27 #include "lsst/geom.h"
28 #include "lsst/log/Log.h"
31 #include "lsst/jointcal/CcdImage.h"
36 
37 #include "lsst/pex/exceptions.h"
39 
40 #include <memory>
41 #include <string>
42 #include <iostream>
43 
44 namespace {
45 // Append the keys of this map into a comma-separated string.
46 template <typename KeyType, typename ValueType>
47 void outputMapKeys(std::map<KeyType, ValueType> const &map, std::ostream &os) {
48  bool first = true;
49  os << "[";
50  for (auto const &i : map) {
51  if (first)
52  first = false;
53  else
54  os << ", ";
55  os << i.first;
56  }
57  os << "]";
58 }
59 } // namespace
60 
61 namespace lsst {
62 namespace jointcal {
63 
64 ConstrainedAstrometryModel::ConstrainedAstrometryModel(
66  int chipOrder, int visitOrder)
67  : AstrometryModel(LOG_GET("jointcal.ConstrainedAstrometryModel")),
68  _skyToTangentPlane(projectionHandler) {
69  // keep track of which chip we want to hold fixed (the one closest to the middle of the focal plane)
70  double minRadius2 = std::numeric_limits<double>::infinity();
71  CcdIdType constrainedChip = -1;
72 
73  // first loop to initialize all visit and chip transforms.
74  for (auto &ccdImage : ccdImageList) {
75  const CcdImage &im = *ccdImage;
76  auto visit = im.getVisit();
77  auto chip = im.getCcdId();
78  auto visitp = _visitMap.find(visit);
79  if (visitp == _visitMap.end()) {
80  _visitMap[visit] = std::make_shared<SimplePolyMapping>(AstrometryTransformLinear(),
81  AstrometryTransformPolynomial(visitOrder));
82  }
83  auto chipp = _chipMap.find(chip);
84  if (chipp == _chipMap.end()) {
85  auto center = ccdImage->getDetector()->getCenter(afw::cameraGeom::FOCAL_PLANE);
86  double radius2 = std::pow(center.getX(), 2) + std::pow(center.getY(), 2);
87  if (radius2 < minRadius2) {
88  minRadius2 = radius2;
89  constrainedChip = chip;
90  }
91 
92  auto pixelsToFocal =
94  Frame const &frame = im.getImageFrame();
95  // construct the chip transform by approximating the pixel->Focal afw::geom::Transform.
97  AstrometryTransformPolynomial(pixelsToFocal, frame, chipOrder);
99  _chipMap[chip] = std::make_shared<SimplePolyMapping>(shiftAndNormalize,
100  pol * shiftAndNormalize.inverted());
101  }
102  }
103 
104  // Hold the "central" chip map fixed and don't fit it, to remove a degeneracy.
105  _chipMap.at(constrainedChip)->setToBeFit(false);
106 
107  // now, second loop to set the mappings of the CCdImages
108  for (auto &ccdImage : ccdImageList) {
109  const CcdImage &im = *ccdImage;
110  auto visit = im.getVisit();
111  auto chip = im.getCcdId();
112 
113  // check that the chip_indexed part was indeed assigned
114  // (i.e. the reference visit was complete)
115  if (_chipMap.find(chip) == _chipMap.end()) {
116  LOGLS_WARN(_log, "Chip " << chip << " is missing in the reference exposure, expect troubles.");
118  _chipMap[chip] =
119  std::make_shared<SimplePolyMapping>(norm, AstrometryTransformPolynomial(chipOrder));
120  }
121  _mappings[ccdImage->getHashKey()] =
122  std::make_unique<ChipVisitAstrometryMapping>(_chipMap[chip], _visitMap[visit]);
123  }
124  LOGLS_INFO(_log, "Got " << _chipMap.size() << " chip mappings and " << _visitMap.size()
125  << " visit mappings; holding chip " << constrainedChip << " fixed ("
126  << getTotalParameters() << " total parameters).");
127  LOGLS_DEBUG(_log, "CcdImage map has " << _mappings.size() << " mappings, with "
128  << _mappings.bucket_count() << " buckets and a load factor of "
129  << _mappings.load_factor());
130 }
131 
133  return findMapping(ccdImage);
134 }
135 
141  std::string const &whatToFit,
142  Eigen::Index firstIndex
143 ) {
144  Eigen::Index index = firstIndex;
145  if (whatToFit.find("Distortions") == std::string::npos) {
146  LOGLS_ERROR(_log, "assignIndices was called and Distortions is *not* in whatToFit");
147  return 0;
148  }
149  // if we get here "Distortions" is in whatToFit
150  _fittingChips = (whatToFit.find("DistortionsChip") != std::string::npos);
151  _fittingVisits = (whatToFit.find("DistortionsVisit") != std::string::npos);
152  // If nothing more than "Distortions" is specified, it means all:
153  if ((!_fittingChips) && (!_fittingVisits)) {
154  _fittingChips = _fittingVisits = true;
155  }
156  if (_fittingChips)
157  for (auto &i : _chipMap) {
158  i.second->setIndex(index);
159  index += i.second->getNpar();
160  }
161  if (_fittingVisits)
162  for (auto &i : _visitMap) {
163  i.second->setIndex(index);
164  index += i.second->getNpar();
165  }
166  // Tell the mappings which derivatives they will have to fill:
167  for (auto &i : _mappings) {
168  i.second->setWhatToFit(_fittingChips, _fittingVisits);
169  }
170  return index;
171 }
172 
173 void ConstrainedAstrometryModel::offsetParams(Eigen::VectorXd const &delta) {
174  if (_fittingChips)
175  for (auto &i : _chipMap) {
176  auto mapping = i.second.get();
177  mapping->offsetParams(delta.segment(mapping->getIndex(), mapping->getNpar()));
178  }
179  if (_fittingVisits)
180  for (auto &i : _visitMap) {
181  auto mapping = i.second.get();
182  mapping->offsetParams(delta.segment(mapping->getIndex(), mapping->getNpar()));
183  }
184 }
185 
187  for (auto i = _visitMap.begin(); i != _visitMap.end(); ++i) i->second->freezeErrorTransform();
188  for (auto i = _chipMap.begin(); i != _chipMap.end(); ++i) i->second->freezeErrorTransform();
189 }
190 
192  auto chipp = _chipMap.find(chip);
193  if (chipp == _chipMap.end()) {
194  std::stringstream errMsg;
195  errMsg << "No such chipId: " << chip << " among ";
196  outputMapKeys(_chipMap, errMsg);
197  std::cout << std::endl;
198  throw pexExcept::InvalidParameterError(errMsg.str());
199  }
200  return chipp->second->getTransform();
201 }
202 
203 // Array of visits involved in the solution.
206  res.reserve(_visitMap.size());
207  for (auto i = _visitMap.begin(); i != _visitMap.end(); ++i) res.push_back(i->first);
208  return res;
209 }
210 
212  auto visitp = _visitMap.find(visit);
213  if (visitp == _visitMap.end()) {
214  std::stringstream errMsg;
215  errMsg << "No such visitId: " << visit << " among ";
216  outputMapKeys(_visitMap, errMsg);
217  std::cout << std::endl;
218  throw pexExcept::InvalidParameterError(errMsg.str());
219  }
220  return visitp->second->getTransform();
221 }
222 
224  std::size_t total = 0;
225  for (auto &i : _chipMap) {
226  total += i.second->getNpar();
227  }
228  for (auto &i : _visitMap) {
229  total += i.second->getNpar();
230  }
231  return total;
232 }
233 
235  auto proj = std::dynamic_pointer_cast<const TanRaDecToPixel>(getSkyToTangentPlane(ccdImage));
236  jointcal::Point tangentPoint(proj->getTangentPoint());
237 
238  auto imageFrame = ccdImage.getImageFrame();
239  auto pixelsToFocal = getChipTransform(ccdImage.getCcdId()).toAstMap(imageFrame);
240  jointcal::Frame focalBox = getChipTransform(ccdImage.getCcdId()).apply(imageFrame, false);
241  auto focalToIwc = getVisitTransform(ccdImage.getVisit()).toAstMap(focalBox);
242 
243  ast::Frame pixelFrame(2, "Domain=PIXELS");
244  ast::Frame focalFrame(2, "Domain=FOCAL");
245  ast::Frame iwcFrame(2, "Domain=IWC");
246 
247  // make a basic SkyWcs and extract the IWC portion
248  auto iwcToSkyWcs = afw::geom::makeSkyWcs(
249  geom::Point2D(0, 0),
250  geom::SpherePoint(tangentPoint.x, tangentPoint.y, geom::degrees),
252  auto iwcToSkyMap = iwcToSkyWcs->getFrameDict()->getMapping("PIXELS", "SKY");
253  auto skyFrame = iwcToSkyWcs->getFrameDict()->getFrame("SKY");
254 
255  ast::FrameDict frameDict(pixelFrame);
256  frameDict.addFrame("PIXELS", *pixelsToFocal, focalFrame);
257  frameDict.addFrame("FOCAL", *focalToIwc, iwcFrame);
258  frameDict.addFrame("IWC", *iwcToSkyMap, *skyFrame);
259  return std::make_shared<afw::geom::SkyWcs>(frameDict);
260 }
261 
262 AstrometryMapping *ConstrainedAstrometryModel::findMapping(CcdImage const &ccdImage) const {
263  auto i = _mappings.find(ccdImage.getHashKey());
264  if (i == _mappings.end())
266  "ConstrainedAstrometryModel cannot find CcdImage " + ccdImage.getName());
267  return i->second.get();
268 }
269 
270 } // namespace jointcal
271 } // namespace lsst
#define LOGLS_WARN(logger, message)
Log a warn-level message using an iostream-based interface.
Definition: Log.h:648
AstrometryTransform const & getVisitTransform(VisitIdType const &visit) const
Access to mappings.
VisitIdType getVisit() const
returns visit ID
Definition: CcdImage.h:148
Eigen::Index assignIndices(std::string const &whatToFit, Eigen::Index firstIndex) override
Positions the various parameter sets into the parameter vector, starting at firstIndex.
implements the linear transformations (6 real coefficients).
A point in a plane.
Definition: Point.h:36
LOG_LOGGER _log
lsst.logging instance, to be created by a subclass so that messages have consistent name...
std::string getName() const
Return the _name that identifies this ccdImage.
Definition: CcdImage.h:79
CameraSysPrefix const PIXELS
Pixel coordinates: Nominal position on the entry surface of a given detector (x, y unbinned pixels)...
Definition: CameraSys.cc:34
const std::shared_ptr< AstrometryTransform const > getSkyToTangentPlane(CcdImage const &ccdImage) const override
The mapping of sky coordinates (i.e.
T endl(T... args)
Interface between AstrometryFit and the combinations of Mappings from pixels to some tangent plane (a...
T norm(const T &x)
Definition: Integrate.h:194
std::vector< VisitIdType > getVisits() const
Access to array of visits involved in the solution.
std::size_t getTotalParameters() const override
Return the total number of parameters in this model.
CcdIdType getCcdId() const
returns ccd ID
Definition: CcdImage.h:145
STL class.
AstrometryMapping const * getMapping(CcdImage const &) const override
Mapping associated to a given CcdImage.
STL class.
LSST DM logging module built on log4cxx.
pairs of points
T push_back(T... args)
rectangle with sides parallel to axes.
Definition: Frame.h:38
AstrometryTransformLinear normalizeCoordinatesTransform(const Frame &frame)
Returns the transformation that maps the input frame along both axes to [-1,1].
#define LOGLS_DEBUG(logger, message)
Log a debug-level message using an iostream-based interface.
Definition: Log.h:608
AngleUnit constexpr degrees
constant with units of degrees
Definition: Angle.h:109
A base class for image defects.
void addFrame(int iframe, Mapping const &map, Frame const &frame) override
Add a new Frame and an associated Mapping to this FrameSet so as to define a new coordinate system...
Definition: FrameDict.cc:32
Frame is used to represent a coordinate system.
Definition: Frame.h:157
std::shared_ptr< afw::geom::SkyWcs > makeSkyWcs(CcdImage const &ccdImage) const override
Make a SkyWcs that contains this model.
T str(T... args)
void freezeErrorTransform() override
From there on, measurement errors are propagated using the current transforms (and no longer evolve)...
This one is the Tangent Plane (called gnomonic) projection (from celestial sphere to tangent plane) ...
T dynamic_pointer_cast(T... args)
T infinity(T... args)
#define LOGLS_INFO(logger, message)
Log a info-level message using an iostream-based interface.
Definition: Log.h:628
T find(T... args)
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
STL class.
void offsetParams(Eigen::VectorXd const &Delta) override
Dispaches the offsets after a fit step into the actual locations of parameters.
a virtual (interface) class for geometric transformations.
Point in an unspecified spherical coordinate system.
Definition: SpherePoint.h:57
T pow(T... args)
AstrometryTransform const & getChipTransform(CcdIdType const chip) const
Access to mappings.
std::shared_ptr< SkyWcs > makeSkyWcs(daf::base::PropertySet &metadata, bool strip=false)
Construct a SkyWcs from FITS keywords.
Definition: SkyWcs.cc:506
Eigen::Matrix2d makeCdMatrix(lsst::geom::Angle const &scale, lsst::geom::Angle const &orientation=0 *lsst::geom::degrees, bool flipX=false)
Make a WCS CD matrix.
Definition: SkyWcs.cc:138
Reports invalid arguments.
Definition: Runtime.h:66
int VisitIdType
Definition: CcdImage.h:48
virtual class needed in the abstraction of the distortion model
CcdImageKey getHashKey() const
Definition: CcdImage.h:152
std::shared_ptr< afw::cameraGeom::Detector > getDetector() const
Definition: CcdImage.h:150
Handler of an actual image from a single CCD.
Definition: CcdImage.h:64
#define LOG_GET(logger)
Returns a Log object associated with logger.
Definition: Log.h:75
A FrameSet whose frames can be referenced by domain name.
Definition: FrameDict.h:67
std::ostream * os
Definition: Schema.cc:746
CameraSys const FOCAL_PLANE
Focal plane coordinates: Position on a 2-d planar approximation to the focal plane (x...
Definition: CameraSys.cc:30
STL class.
#define LOGLS_ERROR(logger, message)
Log a error-level message using an iostream-based interface.
Definition: Log.h:668
Frame const & getImageFrame() const
Frame in pixels.
Definition: CcdImage.h:191
T reserve(T... args)