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
Detector.cc
Go to the documentation of this file.
1 /*
2  * LSST Data Management System
3  * Copyright 2014 LSST Corporation.
4  *
5  * This product includes software developed by the
6  * LSST Project (http://www.lsst.org/).
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the LSST License Statement and
19  * the GNU General Public License along with this program. If not,
20  * see <http://www.lsstcorp.org/LegalNotices/>.
21  */
22 
23 #include <sstream>
24 #include <utility>
25 
29 #include "lsst/afw/table/io/Persistable.cc"
31 
32 namespace lsst {
33 namespace afw {
34 namespace cameraGeom {
35 
37  lsst::geom::Box2I const &bbox, table::AmpInfoCatalog const &ampInfoCatalog,
39  TransformMap::Transforms const &transforms, CrosstalkMatrix const &crosstalk) :
40  Detector(name, id, type, serial, bbox, ampInfoCatalog, orientation, pixelSize,
41  TransformMap::make(CameraSys(PIXELS, name), transforms),
42  crosstalk)
43 {}
44 
46  lsst::geom::Box2I const &bbox, table::AmpInfoCatalog const &ampInfoCatalog,
49  _name(name),
50  _id(id),
51  _type(type),
52  _serial(serial),
53  _bbox(bbox),
54  _ampInfoCatalog(ampInfoCatalog),
55  _ampNameIterMap(),
56  _orientation(orientation),
57  _pixelSize(pixelSize),
58  _nativeSys(CameraSys(PIXELS, name)),
59  _transformMap(std::move(transformMap)),
60  _crosstalk(crosstalk)
61 {
62  // make _ampNameIterMap
63  for (auto ampIter = _ampInfoCatalog.begin(); ampIter != _ampInfoCatalog.end(); ++ampIter) {
64  _ampNameIterMap.insert(std::make_pair(ampIter->getName(), ampIter));
65  }
66  if (_ampNameIterMap.size() != _ampInfoCatalog.size()) {
68  "Invalid ampInfoCatalog: not all amplifier names are unique");
69  }
70 
71  // ensure crosstalk coefficients matrix is square
72  if (hasCrosstalk()) {
73  auto shape = _crosstalk.getShape();
74  assert(shape.size() == 2); // we've declared this as a 2D array
75  if (shape[0] != shape[1]) {
77  os << "Non-square crosstalk matrix: " << _crosstalk << " for detector \"" << _name << "\"";
79  }
80  if (shape[0] != _ampInfoCatalog.size()) {
82  os << "Wrong size crosstalk matrix: " << _crosstalk << " for detector \"" << _name << "\"";
84  }
85  }
86 }
87 
90  auto nativeToCameraSys = _transformMap->getTransform(_nativeSys, cameraSys);
91  return nativeToCameraSys->applyForward(nativeCorners);
92 }
93 
95  return getCorners(makeCameraSys(cameraSysPrefix));
96 }
97 
99  auto ctrPix = lsst::geom::Box2D(_bbox).getCenter();
100  auto transform = getTransform(PIXELS, cameraSys);
101  return transform->applyForward(ctrPix);
102 }
103 
105  return getCenter(makeCameraSys(cameraSysPrefix));
106 }
107 
108 const table::AmpInfoRecord &Detector::operator[](std::string const &name) const { return *(_get(name)); }
109 
111  if (i < 0) {
112  i = _ampInfoCatalog.size() + i;
113  };
114  return _ampInfoCatalog.get(i);
115 }
116 
118  _AmpInfoMap::const_iterator ampIter = _ampNameIterMap.find(name);
119  if (ampIter == _ampNameIterMap.end()) {
121  os << "Unknown amplifier \"" << name << "\"";
123  }
124  return ampIter->second;
125 }
126 
127 bool Detector::hasTransform(CameraSys const &cameraSys) const { return _transformMap->contains(cameraSys); }
128 
129 bool Detector::hasTransform(CameraSysPrefix const &cameraSysPrefix) const {
130  return hasTransform(makeCameraSys(cameraSysPrefix));
131 }
132 
133 template <typename FromSysT, typename ToSysT>
135  ToSysT const &toSys) const {
136  return _transformMap->getTransform(makeCameraSys(fromSys), makeCameraSys(toSys));
137 }
138 
139 template <typename FromSysT, typename ToSysT>
140 lsst::geom::Point2D Detector::transform(lsst::geom::Point2D const &point, FromSysT const &fromSys,
141  ToSysT const &toSys) const {
142  return _transformMap->transform(point, makeCameraSys(fromSys), makeCameraSys(toSys));
143 }
144 
145 template <typename FromSysT, typename ToSysT>
147  FromSysT const &fromSys, ToSysT const &toSys) const {
148  return _transformMap->transform(points, makeCameraSys(fromSys), makeCameraSys(toSys));
149 }
150 
151 namespace {
152 
153 class PersistenceHelper {
154 public:
155 
156  static PersistenceHelper const & get() {
157  static PersistenceHelper const instance;
158  return instance;
159  }
160 
161  table::Schema schema;
162  table::Key<std::string> name;
163  table::Key<int> id;
164  table::Key<int> type;
165  table::Key<std::string> serial;
170  table::Key<lsst::geom::Angle> yaw;
171  table::Key<lsst::geom::Angle> pitch;
172  table::Key<lsst::geom::Angle> roll;
173  table::Key<int> transformMap;
174  table::Key<table::Array<float>> crosstalk;
175 
176 private:
177 
178  PersistenceHelper() :
179  schema(),
180  name(schema.addField<std::string>("name", "Name of the detector", "", 0)),
181  id(schema.addField<int>("id", "Integer ID for the detector", "")),
182  type(schema.addField<int>("type", "Raw DetectorType enum value", "")),
183  serial(schema.addField<std::string>("serial", "Serial name of the detector", "", 0)),
184  bbox(table::Box2IKey::addFields(schema, "bbox", "Detector bounding box", "pixel")),
185  pixelSize(table::Point2DKey::addFields(schema, "pixelSize", "Physical pixel size", "mm")),
186  fpPosition(table::Point2DKey::addFields(schema, "fpPosition",
187  "Focal plane position of reference point", "mm")),
188  refPoint(table::Point2DKey::addFields(schema, "refPoint",
189  "Pixel position of reference point", "pixel")),
190  yaw(schema.addField<lsst::geom::Angle>("yaw", "Rotation about Z (X to Y), 1st rotation")),
191  pitch(schema.addField<lsst::geom::Angle>("pitch", "Rotation about Y' (Z'=Z to X'), 2nd rotation")),
192  roll(schema.addField<lsst::geom::Angle>("roll", "Rotation about X'' (Y''=Y' to Z''), 3rd rotation")),
193  transformMap(schema.addField<int>("transformMap", "Archive ID of TransformMap", "")),
194  crosstalk(schema.addField<table::Array<float>>("crosstalk", "Crosstalk matrix, flattened", "", 0))
195  {
196  schema.getCitizen().markPersistent();
197  }
198 
199  PersistenceHelper(PersistenceHelper const &) = delete;
200  PersistenceHelper(PersistenceHelper &&) = delete;
201 
202  PersistenceHelper & operator=(PersistenceHelper const &) = delete;
203  PersistenceHelper & operator=(PersistenceHelper &&) = delete;
204 
205 };
206 
207 
208 class DetectorFactory : public table::io::PersistableFactory {
209 public:
210 
211  DetectorFactory() : PersistableFactory("Detector") {}
212 
213  std::shared_ptr<table::io::Persistable> read(InputArchive const& archive,
214  CatalogVector const& catalogs) const override {
215  auto const & keys = PersistenceHelper::get();
216 
217  LSST_ARCHIVE_ASSERT(catalogs.size() == 2u);
218  LSST_ARCHIVE_ASSERT(catalogs.front().getSchema() == keys.schema);
219  LSST_ARCHIVE_ASSERT(catalogs.front().size() == 1u);
220  auto const & record = catalogs.front().front();
221 
222  table::AmpInfoCatalog amps(catalogs.back().getSchema());
223  amps.reserve(catalogs.back().size());
224  // we can't use amps.assign or amps.insert here because those
225  // require the input record to be a subclass of the output record
226  // to permit shallow assignment while this case is the opposte
227  for (auto const & amp : catalogs.back()) {
228  amps.addNew()->assign(amp);
229  }
230 
231  auto flattenedMatrix = record.get(keys.crosstalk);
232  ndarray::Array<float, 2, 2> crosstalk;
233  if (!flattenedMatrix.isEmpty()) {
234  crosstalk = ndarray::allocate(amps.size(), amps.size());
235  ndarray::flatten<1>(crosstalk) = flattenedMatrix;
236  }
237 
238  return std::make_shared<Detector>(
239  record.get(keys.name),
240  record.get(keys.id),
241  static_cast<DetectorType>(record.get(keys.type)),
242  record.get(keys.serial),
243  record.get(keys.bbox),
244  amps,
245  Orientation(
246  record.get(keys.fpPosition),
247  record.get(keys.refPoint),
248  record.get(keys.yaw),
249  record.get(keys.pitch),
250  record.get(keys.roll)
251  ),
252  lsst::geom::Extent2D(record.get(keys.pixelSize)),
253  archive.get<TransformMap>(record.get(keys.transformMap)),
254  crosstalk
255  );
256  }
257 
258 };
259 
260 DetectorFactory const registration;
261 
262 } // anonymous
263 
264 std::string Detector::getPersistenceName() const {
265  return "Detector";
266 }
267 
268 std::string Detector::getPythonModule() const {
269  return "lsst.afw.cameraGeom";
270 }
271 
272 void Detector::write(OutputArchiveHandle& handle) const {
273  auto const & keys = PersistenceHelper::get();
274 
275  auto cat = handle.makeCatalog(keys.schema);
276  auto record = cat.addNew();
277  record->set(keys.name, getName());
278  record->set(keys.id, getId());
279  record->set(keys.type, static_cast<int>(getType()));
280  record->set(keys.serial, getSerial());
281  record->set(keys.bbox, getBBox());
282  record->set(keys.pixelSize, lsst::geom::Point2D(getPixelSize()));
283  auto orientation = getOrientation();
284  record->set(keys.fpPosition, orientation.getFpPosition());
285  record->set(keys.refPoint, orientation.getReferencePoint());
286  record->set(keys.yaw, orientation.getYaw());
287  record->set(keys.pitch, orientation.getPitch());
288  record->set(keys.roll, orientation.getRoll());
289  record->set(keys.transformMap, handle.put(getTransformMap()));
290 
291  auto flattenMatrix = [](ndarray::Array<float const, 2> const & matrix) {
292  // copy because the original isn't guaranteed to have
293  // row-major contiguous elements
294  ndarray::Array<float, 2, 2> copied = ndarray::copy(matrix);
295  // make a view to the copy
296  ndarray::Array<float, 1, 1> flattened = ndarray::flatten<1>(copied);
297  return flattened;
298  };
299 
300  record->set(keys.crosstalk, flattenMatrix(getCrosstalk()));
301  handle.saveCatalog(cat);
302 
303  auto amps = handle.makeCatalog(_ampInfoCatalog.getSchema());
304  amps.assign(_ampInfoCatalog.begin(), _ampInfoCatalog.end(), true);
305  handle.saveCatalog(amps);
306 }
307 
308 
309 //
310 // Explicit instantiations
311 //
312 #define INSTANTIATE(FROMSYS, TOSYS) \
313  template std::shared_ptr<geom::TransformPoint2ToPoint2> Detector::getTransform(FROMSYS const &, \
314  TOSYS const &) const; \
315  template lsst::geom::Point2D Detector::transform(lsst::geom::Point2D const &, FROMSYS const &, \
316  TOSYS const &) const; \
317  template std::vector<lsst::geom::Point2D> Detector::transform(std::vector<lsst::geom::Point2D> const &, \
318  FROMSYS const &, TOSYS const &) const;
319 
320 INSTANTIATE(CameraSys, CameraSys);
321 INSTANTIATE(CameraSys, CameraSysPrefix);
322 INSTANTIATE(CameraSysPrefix, CameraSys);
323 INSTANTIATE(CameraSysPrefix, CameraSysPrefix);
324 
325 } // namespace cameraGeom
326 
327 namespace table {
328 namespace io {
329 
330 template class PersistableFacade<cameraGeom::Detector>;
331 
332 } // namespace io
333 } // namespace table
334 
335 
336 } // namespace afw
337 } // namespace lsst
std::vector< Point2D > getCorners() const
Get the corner points.
Definition: Box.cc:417
table::Key< std::string > name
Definition: Detector.cc:162
A registry of 2-dimensional coordinate transforms for a specific camera.
Definition: TransformMap.h:64
Camera coordinate system; used as a key in in TransformMap.
Definition: CameraSys.h:83
Geometry and electronic information about raw amplifier images.
Definition: AmpInfo.h:79
A floating-point coordinate rectangle geometry.
Definition: Box.h:294
Point2D const getCenter() const noexcept
Definition: Box.h:412
table::AmpInfoRecord const & operator[](size_t i) const
Get the amplifier specified by index.
Definition: Detector.h:181
BoxKey< lsst::geom::Box2I > Box2IKey
Definition: aggregates.h:201
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
table::Point2DKey refPoint
Definition: Detector.cc:169
std::shared_ptr< table::AmpInfoRecord const > _get(int i) const
Get the amplifier specified by index, returning a shared pointer to an AmpInfo record.
Definition: Detector.cc:110
STL namespace.
T end(T... args)
PointKey< double > Point2DKey
Definition: aggregates.h:118
table::Key< int > id
Definition: Detector.cc:163
DetectorType getType() const
Definition: Detector.h:130
Describe a detector&#39;s orientation in the focal plane.
Definition: Orientation.h:52
STL class.
table::Key< lsst::geom::Angle > pitch
Definition: Detector.cc:171
CameraSys const makeCameraSys(CameraSys const &cameraSys) const
Get a coordinate system from a coordinate system (return input unchanged and untested) ...
Definition: Detector.h:251
Orientation const getOrientation() const
Get detector&#39;s orientation in the focal plane.
Definition: Detector.h:154
lsst::geom::Box2I getBBox() const
Get the bounding box.
Definition: Detector.h:136
A base class for image defects.
table::Key< int > type
Definition: Detector.cc:164
table::Key< lsst::geom::Angle > roll
Definition: Detector.cc:172
std::shared_ptr< TransformMap const > getTransformMap() const
Get the transform registry.
Definition: Detector.h:160
iterator end()
Iterator access.
Definition: Catalog.h:397
bool hasTransform(CameraSys const &cameraSys) const
Can this object convert between PIXELS and the specified camera coordinate system?
Definition: Detector.cc:127
bool hasCrosstalk() const
Have we got crosstalk coefficients?
Definition: Detector.h:163
std::vector< lsst::geom::Point2D > getCorners(CameraSys const &cameraSys) const
Get the corners of the detector in the specified camera coordinate system.
Definition: Detector.cc:88
T str(T... args)
T make_pair(T... args)
CrosstalkMatrix const getCrosstalk() const
Get the crosstalk coefficients.
Definition: Detector.h:168
CatalogT< AmpInfoRecord > AmpInfoCatalog
Definition: fwd.h:97
table::Point2DKey pixelSize
Definition: Detector.cc:167
table::Box2IKey bbox
Definition: Detector.cc:166
lsst::geom::Point2D getCenter(CameraSys const &cameraSys) const
Get the center of the detector in the specified camera coordinate system.
Definition: Detector.cc:98
Camera coordinate system prefix.
Definition: CameraSys.h:44
table::Point2DKey fpPosition
Definition: Detector.cc:168
T insert(T... args)
void reserve(size_type n)
Increase the capacity of the catalog to the given size.
Definition: Catalog.h:428
T find(T... args)
T size(T... args)
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
std::string getName() const
Get the detector name.
Definition: Detector.h:125
STL class.
Information about a CCD or other imaging detector.
Definition: Detector.h:61
table::Key< lsst::geom::Angle > yaw
Definition: Detector.cc:170
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
Definition: Persistable.h:48
Detector & operator=(Detector const &)=delete
std::shared_ptr< RecordT > const get(size_type i) const
Return a pointer to the record at index i.
Definition: Catalog.h:446
int getId() const
Get the detector ID.
Definition: Detector.h:128
Reports invalid arguments.
Definition: Runtime.h:66
io::OutputArchiveHandle OutputArchiveHandle
Definition: Persistable.h:108
size_type size() const
Return the number of elements in the catalog.
Definition: Catalog.h:408
lsst::geom::Angle Angle
Definition: misc.h:33
table::Schema schema
Definition: Detector.cc:161
table::Key< int > transformMap
Definition: Detector.cc:173
table::Key< std::string > serial
Definition: Detector.cc:165
Detector(std::string const &name, int id, DetectorType type, std::string const &serial, lsst::geom::Box2I const &bbox, lsst::afw::table::AmpInfoCatalog const &ampInfoCatalog, Orientation const &orientation, lsst::geom::Extent2D const &pixelSize, TransformMap::Transforms const &transforms, CrosstalkMatrix const &crosstalk=CrosstalkMatrix())
Make a Detector.
Definition: Detector.cc:36
iterator begin()
Iterator access.
Definition: Catalog.h:396
table::Key< table::Array< float > > crosstalk
Definition: Detector.cc:174
lsst::geom::Extent2D getPixelSize() const
Get size of pixel along (mm)
Definition: Detector.h:157
DetectorType
Type of imaging detector.
Definition: Detector.h:43
ndarray::Array< float const, 2 > CrosstalkMatrix
Definition: Detector.h:63
An integer coordinate rectangle.
Definition: Box.h:54
std::string getSerial() const
Get the detector serial "number".
Definition: Detector.h:133
lsst::geom::Point2D transform(lsst::geom::Point2D const &point, FromSysT const &fromSys, ToSysT const &toSys) const
Transform a point from one camera system to another.
Definition: Detector.cc:140
std::ostream * os
Definition: Schema.cc:746
#define INSTANTIATE(FROMSYS, TOSYS)
Definition: Detector.cc:312
std::shared_ptr< afw::geom::TransformPoint2ToPoint2 > getTransform(FromSysT const &fromSys, ToSysT const &toSys) const
Get a Transform from one camera coordinate system, or camera coordinate system prefix, to another.