LSST Applications g0b6bd0c080+a72a5dd7e6,g1182afd7b4+2a019aa3bb,g17e5ecfddb+2b8207f7de,g1d67935e3f+06cf436103,g38293774b4+ac198e9f13,g396055baef+6a2097e274,g3b44f30a73+6611e0205b,g480783c3b1+98f8679e14,g48ccf36440+89c08d0516,g4b93dc025c+98f8679e14,g5c4744a4d9+a302e8c7f0,g613e996a0d+e1c447f2e0,g6c8d09e9e7+25247a063c,g7271f0639c+98f8679e14,g7a9cd813b8+124095ede6,g9d27549199+a302e8c7f0,ga1cf026fa3+ac198e9f13,ga32aa97882+7403ac30ac,ga786bb30fb+7a139211af,gaa63f70f4e+9994eb9896,gabf319e997+ade567573c,gba47b54d5d+94dc90c3ea,gbec6a3398f+06cf436103,gc6308e37c7+07dd123edb,gc655b1545f+ade567573c,gcc9029db3c+ab229f5caf,gd01420fc67+06cf436103,gd877ba84e5+06cf436103,gdb4cecd868+6f279b5b48,ge2d134c3d5+cc4dbb2e3f,ge448b5faa6+86d1ceac1d,gecc7e12556+98f8679e14,gf3ee170dca+25247a063c,gf4ac96e456+ade567573c,gf9f5ea5b4d+ac198e9f13,gff490e6085+8c2580be5c,w.2022.27
LSST Data Management Base Package
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"
36
37#include "lsst/pex/exceptions.h"
39
40#include <iostream>
41#include <memory>
42#include <string>
43#include <utility>
44
45namespace {
46// Append the keys of this map into a comma-separated string.
47template <typename KeyType, typename ValueType>
48void outputMapKeys(std::map<KeyType, ValueType> const &map, std::ostream &os) {
49 bool first = true;
50 os << "[";
51 for (auto const &i : map) {
52 if (first)
53 first = false;
54 else
55 os << ", ";
56 os << i.first;
57 }
58 os << "]";
59}
60} // namespace
61
62namespace lsst {
63namespace jointcal {
64
66 CcdImageList const &ccdImageList, std::shared_ptr<ProjectionHandler const> projectionHandler,
67 int chipOrder, int visitOrder)
68 : AstrometryModel(LOG_GET("lsst.jointcal.ConstrainedAstrometryModel")),
69 _skyToTangentPlane(std::move(projectionHandler)) {
70 // keep track of which chip we want to hold fixed (the one closest to the middle of the focal plane)
71 double minRadius2 = std::numeric_limits<double>::infinity();
72 CcdIdType constrainedChip = -1;
73
74 // first loop to initialize all visit and chip transforms.
75 for (auto &ccdImage : ccdImageList) {
76 const CcdImage &im = *ccdImage;
77 auto visit = im.getVisit();
78 auto chip = im.getCcdId();
79 auto visitp = _visitMap.find(visit);
80 if (visitp == _visitMap.end()) {
81 _visitMap[visit] = std::make_shared<SimplePolyMapping>(AstrometryTransformLinear(),
83 }
84 auto chipp = _chipMap.find(chip);
85 if (chipp == _chipMap.end()) {
86 auto center = ccdImage->getDetector()->getCenter(afw::cameraGeom::FOCAL_PLANE);
87 double radius2 = std::pow(center.getX(), 2) + std::pow(center.getY(), 2);
88 if (radius2 < minRadius2) {
89 minRadius2 = radius2;
90 constrainedChip = chip;
91 }
92
93 auto pixelsToFocal =
95 Frame const &frame = im.getImageFrame();
96 // construct the chip transform by approximating the pixel->Focal afw::geom::Transform.
98 AstrometryTransformPolynomial(pixelsToFocal, frame, chipOrder);
100 _chipMap[chip] = std::make_shared<SimplePolyMapping>(shiftAndNormalize,
101 pol * shiftAndNormalize.inverted());
102 }
103 }
104
105 // Hold the "central" chip map fixed and don't fit it, to remove a degeneracy.
106 _chipMap.at(constrainedChip)->setToBeFit(false);
107
108 // now, second loop to set the mappings of the CCdImages
109 for (auto &ccdImage : ccdImageList) {
110 const CcdImage &im = *ccdImage;
111 auto visit = im.getVisit();
112 auto chip = im.getCcdId();
113
114 // check that the chip_indexed part was indeed assigned
115 // (i.e. the reference visit was complete)
116 if (_chipMap.find(chip) == _chipMap.end()) {
117 LOGLS_WARN(_log, "Chip " << chip << " is missing in the reference exposure, expect troubles.");
119 _chipMap[chip] =
120 std::make_shared<SimplePolyMapping>(norm, AstrometryTransformPolynomial(chipOrder));
121 }
122 _mappings[ccdImage->getHashKey()] =
123 std::make_unique<ChipVisitAstrometryMapping>(_chipMap[chip], _visitMap[visit]);
124 }
125 LOGLS_INFO(_log, "Got " << _chipMap.size() << " chip mappings and " << _visitMap.size()
126 << " visit mappings; holding chip " << constrainedChip << " fixed ("
127 << getTotalParameters() << " total parameters).");
128 LOGLS_DEBUG(_log, "CcdImage map has " << _mappings.size() << " mappings, with "
129 << _mappings.bucket_count() << " buckets and a load factor of "
130 << _mappings.load_factor());
131}
132
134 return findMapping(ccdImage);
135}
136
142 Eigen::Index firstIndex) {
143 Eigen::Index 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
172void 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) i.second->freezeErrorTransform();
187 for (auto & i : _chipMap) 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);
198 }
199 return chipp->second->getTransform();
200}
201
202// Array of visits involved in the solution.
205 res.reserve(_visitMap.size());
206 for (const auto & i : _visitMap) 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);
218 }
219 return visitp->second->getTransform();
220}
221
223 std::size_t 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 geom::Point2D(0, 0), geom::SpherePoint(tangentPoint.x, tangentPoint.y, geom::degrees),
250 auto iwcToSkyMap = iwcToSkyWcs->getFrameDict()->getMapping("PIXELS", "SKY");
251 auto skyFrame = iwcToSkyWcs->getFrameDict()->getFrame("SKY");
252
253 ast::FrameDict frameDict(pixelFrame);
254 frameDict.addFrame("PIXELS", *pixelsToFocal, focalFrame);
255 frameDict.addFrame("FOCAL", *focalToIwc, iwcFrame);
256 frameDict.addFrame("IWC", *iwcToSkyMap, *skyFrame);
257 return std::make_shared<afw::geom::SkyWcs>(frameDict);
258}
259
261 out << "Constrained Astrometry Model (" << _mappings.size() << " composite mappings; " << _chipMap.size()
262 << " sensor mappings, " << _visitMap.size() << " visit mappings):" << std::endl;
263 out << *_skyToTangentPlane << std::endl;
264 out << "Sensor to sky transforms:" << std::endl;
265 for (auto &i : _mappings) {
266 out << i.first << std::endl;
267 out << *(i.second) << std::endl;
268 }
269}
270
271AstrometryMapping *ConstrainedAstrometryModel::findMapping(CcdImage const &ccdImage) const {
272 auto i = _mappings.find(ccdImage.getHashKey());
273 if (i == _mappings.end())
275 "ConstrainedAstrometryModel cannot find CcdImage " + ccdImage.getName());
276 return i->second.get();
277}
278
279} // namespace jointcal
280} // namespace lsst
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
LSST DM logging module built on log4cxx.
#define LOGLS_WARN(logger, message)
Log a warn-level message using an iostream-based interface.
Definition: Log.h:659
#define LOG_GET(logger)
Returns a Log object associated with logger.
Definition: Log.h:75
#define LOGLS_INFO(logger, message)
Log a info-level message using an iostream-based interface.
Definition: Log.h:639
#define LOGLS_ERROR(logger, message)
Log a error-level message using an iostream-based interface.
Definition: Log.h:679
#define LOGLS_DEBUG(logger, message)
Log a debug-level message using an iostream-based interface.
Definition: Log.h:619
std::ostream * os
Definition: Schema.cc:557
pairs of points
A FrameSet whose frames can be referenced by domain name.
Definition: FrameDict.h:67
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
Point in an unspecified spherical coordinate system.
Definition: SpherePoint.h:57
virtual class needed in the abstraction of the distortion model
Interface between AstrometryFit and the combinations of Mappings from pixels to some tangent plane (a...
LOG_LOGGER _log
lsst.logging instance, to be created by a subclass so that messages have consistent name.
a virtual (interface) class for geometric transformations.
virtual void apply(double xIn, double yIn, double &xOut, double &yOut) const =0
virtual std::shared_ptr< ast::Mapping > toAstMap(jointcal::Frame const &domain) const
Create an equivalent AST mapping for this transformation, including an analytic inverse if possible.
implements the linear transformations (6 real coefficients).
AstrometryTransformLinear inverted() const
returns the inverse: T1 = T2.inverted();
Handler of an actual image from a single CCD.
Definition: CcdImage.h:64
CcdIdType getCcdId() const
returns ccd ID
Definition: CcdImage.h:145
std::shared_ptr< afw::cameraGeom::Detector > getDetector() const
Definition: CcdImage.h:150
VisitIdType getVisit() const
returns visit ID
Definition: CcdImage.h:148
Frame const & getImageFrame() const
Frame in pixels.
Definition: CcdImage.h:190
std::string getName() const
Return the _name that identifies this ccdImage.
Definition: CcdImage.h:79
CcdImageKey getHashKey() const
Definition: CcdImage.h:152
ConstrainedAstrometryModel(CcdImageList const &ccdImageList, std::shared_ptr< ProjectionHandler const > projectionHandler, int chipOrder, int visitOrder)
std::size_t getTotalParameters() const override
Return the total number of parameters in this model.
void offsetParams(Eigen::VectorXd const &Delta) override
Dispaches the offsets after a fit step into the actual locations of parameters.
void freezeErrorTransform() override
From there on, measurement errors are propagated using the current transforms (and no longer evolve).
void print(std::ostream &out) const override
Print a string representation of the contents of this mapping, for debugging.
AstrometryTransform const & getVisitTransform(VisitIdType const &visit) const
Access to mappings.
AstrometryTransform const & getChipTransform(CcdIdType chip) const
Access to mappings.
const std::shared_ptr< AstrometryTransform const > getSkyToTangentPlane(CcdImage const &ccdImage) const override
The mapping of sky coordinates (i.e.
std::vector< VisitIdType > getVisits() const
Access to array of visits involved in the solution.
Eigen::Index assignIndices(std::string const &whatToFit, Eigen::Index firstIndex) override
Positions the various parameter sets into the parameter vector, starting at firstIndex.
std::shared_ptr< afw::geom::SkyWcs > makeSkyWcs(CcdImage const &ccdImage) const override
Make a SkyWcs that contains this model.
AstrometryMapping const * getMapping(CcdImage const &) const override
Mapping associated to a given CcdImage.
rectangle with sides parallel to axes.
Definition: Frame.h:38
A point in a plane.
Definition: Point.h:37
double x
coordinate
Definition: Point.h:42
Reports invalid arguments.
Definition: Runtime.h:66
T endl(T... args)
T find(T... args)
T infinity(T... args)
T move(T... args)
CameraSys const FOCAL_PLANE
Focal plane coordinates: Position on a 2-d planar approximation to the focal plane (x,...
Definition: CameraSys.cc:30
CameraSysPrefix const PIXELS
Pixel coordinates: Nominal position on the entry surface of a given detector (x, y unbinned pixels).
Definition: CameraSys.cc:34
std::shared_ptr< SkyWcs > makeSkyWcs(daf::base::PropertySet &metadata, bool strip=false)
Construct a SkyWcs from FITS keywords.
Definition: SkyWcs.cc:521
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:133
T norm(const T &x)
Definition: Integrate.h:160
constexpr AngleUnit degrees
constant with units of degrees
Definition: Angle.h:110
AstrometryTransformLinear normalizeCoordinatesTransform(const Frame &frame)
Returns the transformation that maps the input frame along both axes to [-1,1].
long VisitIdType
Definition: CcdImage.h:48
A base class for image defects.
STL namespace.
T pow(T... args)
T push_back(T... args)
T reserve(T... args)
T str(T... args)