LSSTApplications  16.0-10-g0ee56ad+5,16.0-11-ga33d1f2+5,16.0-12-g3ef5c14+3,16.0-12-g71e5ef5+18,16.0-12-gbdf3636+3,16.0-13-g118c103+3,16.0-13-g8f68b0a+3,16.0-15-gbf5c1cb+4,16.0-16-gfd17674+3,16.0-17-g7c01f5c+3,16.0-18-g0a50484+1,16.0-20-ga20f992+8,16.0-21-g0e05fd4+6,16.0-21-g15e2d33+4,16.0-22-g62d8060+4,16.0-22-g847a80f+4,16.0-25-gf00d9b8+1,16.0-28-g3990c221+4,16.0-3-gf928089+3,16.0-32-g88a4f23+5,16.0-34-gd7987ad+3,16.0-37-gc7333cb+2,16.0-4-g10fc685+2,16.0-4-g18f3627+26,16.0-4-g5f3a788+26,16.0-5-gaf5c3d7+4,16.0-5-gcc1f4bb+1,16.0-6-g3b92700+4,16.0-6-g4412fcd+3,16.0-6-g7235603+4,16.0-69-g2562ce1b+2,16.0-8-g14ebd58+4,16.0-8-g2df868b+1,16.0-8-g4cec79c+6,16.0-8-gadf6c7a+1,16.0-8-gfc7ad86,16.0-82-g59ec2a54a+1,16.0-9-g5400cdc+2,16.0-9-ge6233d7+5,master-g2880f2d8cf+3,v17.0.rc1
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/log/Log.h"
30 #include "lsst/jointcal/CcdImage.h"
35 
36 #include "lsst/pex/exceptions.h"
38 
39 #include <memory>
40 #include <string>
41 #include <iostream>
42 
43 namespace {
44 LOG_LOGGER _log = LOG_GET("jointcal.ConstrainedAstrometryModel");
45 }
46 
47 namespace {
48 // Append the keys of this map into a comma-separated string.
49 template <typename KeyType, typename ValueType>
50 void outputMapKeys(std::map<KeyType, ValueType> const &map, std::ostream &os) {
51  bool first = true;
52  os << "[";
53  for (auto const &i : map) {
54  if (first)
55  first = false;
56  else
57  os << ", ";
58  os << i.first;
59  }
60  os << "]";
61 }
62 } // namespace
63 
64 namespace lsst {
65 namespace jointcal {
66 
67 ConstrainedAstrometryModel::ConstrainedAstrometryModel(
69  int chipOrder, int visitOrder)
70  : _skyToTangentPlane(projectionHandler) {
71  // keep track of which chip we want to hold fixed (the one closest to the middle of the focal plane)
72  double minRadius2 = std::numeric_limits<double>::infinity();
73  CcdIdType constrainedChip = -1;
74 
75  // first loop to initialize all visit and chip transforms.
76  for (auto &ccdImage : ccdImageList) {
77  const CcdImage &im = *ccdImage;
78  auto visit = im.getVisit();
79  auto chip = im.getCcdId();
80  auto visitp = _visitMap.find(visit);
81  if (visitp == _visitMap.end()) {
82  _visitMap[visit] = std::make_shared<SimplePolyMapping>(AstrometryTransformLinear(),
83  AstrometryTransformPolynomial(visitOrder));
84  }
85  auto chipp = _chipMap.find(chip);
86  if (chipp == _chipMap.end()) {
87  auto center = ccdImage->getDetector()->getCenter(afw::cameraGeom::FOCAL_PLANE);
88  double radius2 = std::pow(center.getX(), 2) + std::pow(center.getY(), 2);
89  if (radius2 < minRadius2) {
90  minRadius2 = radius2;
91  constrainedChip = chip;
92  }
93 
94  auto pixelsToFocal =
96  Frame const &frame = im.getImageFrame();
97  // construct the chip transform by approximating the pixel->Focal afw::geom::Transform.
99  AstrometryTransformPolynomial(pixelsToFocal, frame, chipOrder);
100  AstrometryTransformLinear shiftAndNormalize = normalizeCoordinatesTransform(frame);
101  _chipMap[chip] = std::make_shared<SimplePolyMapping>(shiftAndNormalize,
102  pol * shiftAndNormalize.inverted());
103  }
104  }
105 
106  // Hold the "central" chip map fixed and don't fit it, to remove a degeneracy.
107  _chipMap.at(constrainedChip)->setToBeFit(false);
108 
109  // now, second loop to set the mappings of the CCdImages
110  for (auto &ccdImage : ccdImageList) {
111  const CcdImage &im = *ccdImage;
112  auto visit = im.getVisit();
113  auto chip = im.getCcdId();
114 
115  // check that the chip_indexed part was indeed assigned
116  // (i.e. the reference visit was complete)
117  if (_chipMap.find(chip) == _chipMap.end()) {
118  LOGLS_WARN(_log, "Chip " << chip << " is missing in the reference exposure, expect troubles.");
120  _chipMap[chip] =
121  std::make_shared<SimplePolyMapping>(norm, AstrometryTransformPolynomial(chipOrder));
122  }
123  _mappings[ccdImage->getHashKey()] =
124  std::make_unique<ChipVisitAstrometryMapping>(_chipMap[chip], _visitMap[visit]);
125  }
126  LOGLS_INFO(_log, "Got " << _chipMap.size() << " chip mappings and " << _visitMap.size()
127  << " visit mappings; holding chip " << constrainedChip << " fixed ("
128  << getTotalParameters() << " total parameters).");
129  LOGLS_DEBUG(_log, "CcdImage map has " << _mappings.size() << " mappings, with "
130  << _mappings.bucket_count() << " buckets and a load factor of "
131  << _mappings.load_factor());
132 }
133 
135  return findMapping(ccdImage);
136 }
137 
142 unsigned ConstrainedAstrometryModel::assignIndices(std::string const &whatToFit, unsigned firstIndex) {
143  unsigned index = firstIndex;
144  if (whatToFit.find("Distortions") == std::string::npos) {
145  LOGLS_ERROR(_log, "assignIndices was called and Distortions is *not* in whatToFit");
146  return 0;
147  }
148  // if we get here "Distortions" is in whatToFit
149  _fittingChips = (whatToFit.find("DistortionsChip") != std::string::npos);
150  _fittingVisits = (whatToFit.find("DistortionsVisit") != std::string::npos);
151  // If nothing more than "Distortions" is specified, it means all:
152  if ((!_fittingChips) && (!_fittingVisits)) {
153  _fittingChips = _fittingVisits = true;
154  }
155  if (_fittingChips)
156  for (auto &i : _chipMap) {
157  i.second->setIndex(index);
158  index += i.second->getNpar();
159  }
160  if (_fittingVisits)
161  for (auto &i : _visitMap) {
162  i.second->setIndex(index);
163  index += i.second->getNpar();
164  }
165  // Tell the mappings which derivatives they will have to fill:
166  for (auto &i : _mappings) {
167  i.second->setWhatToFit(_fittingChips, _fittingVisits);
168  }
169  return index;
170 }
171 
172 void ConstrainedAstrometryModel::offsetParams(Eigen::VectorXd const &delta) {
173  if (_fittingChips)
174  for (auto &i : _chipMap) {
175  auto mapping = i.second.get();
176  mapping->offsetParams(delta.segment(mapping->getIndex(), mapping->getNpar()));
177  }
178  if (_fittingVisits)
179  for (auto &i : _visitMap) {
180  auto mapping = i.second.get();
181  mapping->offsetParams(delta.segment(mapping->getIndex(), mapping->getNpar()));
182  }
183 }
184 
186  for (auto i = _visitMap.begin(); i != _visitMap.end(); ++i) i->second->freezeErrorTransform();
187  for (auto i = _chipMap.begin(); i != _chipMap.end(); ++i) i->second->freezeErrorTransform();
188 }
189 
191  auto chipp = _chipMap.find(chip);
192  if (chipp == _chipMap.end()) {
193  std::stringstream errMsg;
194  errMsg << "No such chipId: " << chip << " among ";
195  outputMapKeys(_chipMap, errMsg);
196  std::cout << std::endl;
197  throw pexExcept::InvalidParameterError(errMsg.str());
198  }
199  return chipp->second->getTransform();
200 }
201 
202 // Array of visits involved in the solution.
205  res.reserve(_visitMap.size());
206  for (auto i = _visitMap.begin(); i != _visitMap.end(); ++i) res.push_back(i->first);
207  return res;
208 }
209 
211  auto visitp = _visitMap.find(visit);
212  if (visitp == _visitMap.end()) {
213  std::stringstream errMsg;
214  errMsg << "No such visitId: " << visit << " among ";
215  outputMapKeys(_visitMap, errMsg);
216  std::cout << std::endl;
217  throw pexExcept::InvalidParameterError(errMsg.str());
218  }
219  return visitp->second->getTransform();
220 }
221 
223  int total = 0;
224  for (auto &i : _chipMap) {
225  total += i.second->getNpar();
226  }
227  for (auto &i : _visitMap) {
228  total += i.second->getNpar();
229  }
230  return total;
231 }
232 
234  auto proj = std::dynamic_pointer_cast<const TanRaDecToPixel>(getSkyToTangentPlane(ccdImage));
235  jointcal::Point tangentPoint(proj->getTangentPoint());
236 
237  auto imageFrame = ccdImage.getImageFrame();
238  auto pixelsToFocal = getChipTransform(ccdImage.getCcdId()).toAstMap(imageFrame);
239  jointcal::Frame focalBox = getChipTransform(ccdImage.getCcdId()).apply(imageFrame, false);
240  auto focalToIwc = getVisitTransform(ccdImage.getVisit()).toAstMap(focalBox);
241 
242  ast::Frame pixelFrame(2, "Domain=PIXELS");
243  ast::Frame focalFrame(2, "Domain=FOCAL");
244  ast::Frame iwcFrame(2, "Domain=IWC");
245 
246  // make a basic SkyWcs and extract the IWC portion
247  auto iwcToSkyWcs = afw::geom::makeSkyWcs(
248  afw::geom::Point2D(0, 0),
249  afw::geom::SpherePoint(tangentPoint.x, tangentPoint.y, afw::geom::degrees),
251  auto iwcToSkyMap = iwcToSkyWcs->getFrameDict()->getMapping("PIXELS", "SKY");
252  auto skyFrame = iwcToSkyWcs->getFrameDict()->getFrame("SKY");
253 
254  ast::FrameDict frameDict(pixelFrame);
255  frameDict.addFrame("PIXELS", *pixelsToFocal, focalFrame);
256  frameDict.addFrame("FOCAL", *focalToIwc, iwcFrame);
257  frameDict.addFrame("IWC", *iwcToSkyMap, *skyFrame);
258  return std::make_shared<afw::geom::SkyWcs>(frameDict);
259 }
260 
261 AstrometryMapping *ConstrainedAstrometryModel::findMapping(CcdImage const &ccdImage) const {
262  auto i = _mappings.find(ccdImage.getHashKey());
263  if (i == _mappings.end())
265  "ConstrainedAstrometryModel cannot find CcdImage " + ccdImage.getName());
266  return i->second.get();
267 }
268 
269 } // namespace jointcal
270 } // namespace lsst
#define LOGLS_WARN(logger, message)
Log a warn-level message using an iostream-based interface.
Definition: Log.h:633
unsigned assignIndices(std::string const &whatToFit, unsigned firstIndex) override
Positions the various parameter sets into the parameter vector, starting at firstIndex.
AstrometryTransform const & getVisitTransform(VisitIdType const &visit) const
Access to mappings.
VisitIdType getVisit() const
returns visit ID
Definition: CcdImage.h:148
#define LOG_LOGGER
Definition: Log.h:688
implements the linear transformations (6 real coefficients).
A point in a plane.
Definition: Point.h:36
std::string getName() const
Return the _name that identifies this ccdImage.
Definition: CcdImage.h:79
CameraSysPrefix const PIXELS
Nominal pixels on the detector (unbinned) This ignores manufacturing imperfections, "tree ring" distortions and all other such effects.
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)
T norm(const T &x)
Definition: Integrate.h:194
std::vector< VisitIdType > getVisits() const
Access to array of visits involved in the solution.
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:593
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:613
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
int getTotalParameters() const override
Return the total number of parameters in this model.
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:476
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:139
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
CameraSys const FOCAL_PLANE
Focal plane coordinates: Rectilinear x, y (and z when talking about the location of a detector) on th...
Definition: CameraSys.cc:30
STL class.
#define LOGLS_ERROR(logger, message)
Log a error-level message using an iostream-based interface.
Definition: Log.h:653
Frame const & getImageFrame() const
Frame in pixels.
Definition: CcdImage.h:191
std::ostream * os
Definition: Schema.cc:746
T reserve(T... args)