LSSTApplications  17.0+11,17.0+34,17.0+56,17.0+57,17.0+59,17.0+7,17.0-1-g377950a+33,17.0.1-1-g114240f+2,17.0.1-1-g4d4fbc4+28,17.0.1-1-g55520dc+49,17.0.1-1-g5f4ed7e+52,17.0.1-1-g6dd7d69+17,17.0.1-1-g8de6c91+11,17.0.1-1-gb9095d2+7,17.0.1-1-ge9fec5e+5,17.0.1-1-gf4e0155+55,17.0.1-1-gfc65f5f+50,17.0.1-1-gfc6fb1f+20,17.0.1-10-g87f9f3f+1,17.0.1-11-ge9de802+16,17.0.1-16-ga14f7d5c+4,17.0.1-17-gc79d625+1,17.0.1-17-gdae4c4a+8,17.0.1-2-g26618f5+29,17.0.1-2-g54f2ebc+9,17.0.1-2-gf403422+1,17.0.1-20-g2ca2f74+6,17.0.1-23-gf3eadeb7+1,17.0.1-3-g7e86b59+39,17.0.1-3-gb5ca14a,17.0.1-3-gd08d533+40,17.0.1-30-g596af8797,17.0.1-4-g59d126d+4,17.0.1-4-gc69c472+5,17.0.1-6-g5afd9b9+4,17.0.1-7-g35889ee+1,17.0.1-7-gc7c8782+18,17.0.1-9-gc4bbfb2+3,w.2019.22
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  std::string const &physicalType) :
41  Detector(name, id, type, serial, bbox, ampInfoCatalog, orientation, pixelSize,
42  TransformMap::make(CameraSys(PIXELS, name), transforms),
43  crosstalk, physicalType)
44 {}
45 
47  lsst::geom::Box2I const &bbox, table::AmpInfoCatalog const &ampInfoCatalog,
50  std::string const &physicalType) :
51  _name(name),
52  _id(id),
53  _type(type),
54  _serial(serial),
55  _bbox(bbox),
56  _ampInfoCatalog(ampInfoCatalog),
57  _ampNameIterMap(),
58  _orientation(orientation),
59  _pixelSize(pixelSize),
60  _nativeSys(CameraSys(PIXELS, name)),
61  _transformMap(std::move(transformMap)),
62  _crosstalk(crosstalk),
63  _physicalType(physicalType)
64 {
65  // make _ampNameIterMap
66  for (auto ampIter = _ampInfoCatalog.begin(); ampIter != _ampInfoCatalog.end(); ++ampIter) {
67  _ampNameIterMap.insert(std::make_pair(ampIter->getName(), ampIter));
68  }
69  if (_ampNameIterMap.size() != _ampInfoCatalog.size()) {
71  "Invalid ampInfoCatalog: not all amplifier names are unique");
72  }
73 
74  // ensure crosstalk coefficients matrix is square
75  if (hasCrosstalk()) {
76  auto shape = _crosstalk.getShape();
77  assert(shape.size() == 2); // we've declared this as a 2D array
78  if (shape[0] != shape[1]) {
80  os << "Non-square crosstalk matrix: " << _crosstalk << " for detector \"" << _name << "\"";
82  }
83  if (shape[0] != _ampInfoCatalog.size()) {
85  os << "Wrong size crosstalk matrix: " << _crosstalk << " for detector \"" << _name << "\"";
87  }
88  }
89 }
90 
93  auto nativeToCameraSys = _transformMap->getTransform(_nativeSys, cameraSys);
94  return nativeToCameraSys->applyForward(nativeCorners);
95 }
96 
98  return getCorners(makeCameraSys(cameraSysPrefix));
99 }
100 
102  auto ctrPix = lsst::geom::Box2D(_bbox).getCenter();
103  auto transform = getTransform(PIXELS, cameraSys);
104  return transform->applyForward(ctrPix);
105 }
106 
108  return getCenter(makeCameraSys(cameraSysPrefix));
109 }
110 
111 const table::AmpInfoRecord &Detector::operator[](std::string const &name) const { return *(_get(name)); }
112 
114  if (i < 0) {
115  i = _ampInfoCatalog.size() + i;
116  };
117  return _ampInfoCatalog.get(i);
118 }
119 
121  _AmpInfoMap::const_iterator ampIter = _ampNameIterMap.find(name);
122  if (ampIter == _ampNameIterMap.end()) {
124  os << "Unknown amplifier \"" << name << "\"";
126  }
127  return ampIter->second;
128 }
129 
130 bool Detector::hasTransform(CameraSys const &cameraSys) const { return _transformMap->contains(cameraSys); }
131 
132 bool Detector::hasTransform(CameraSysPrefix const &cameraSysPrefix) const {
133  return hasTransform(makeCameraSys(cameraSysPrefix));
134 }
135 
136 template <typename FromSysT, typename ToSysT>
138  ToSysT const &toSys) const {
139  return _transformMap->getTransform(makeCameraSys(fromSys), makeCameraSys(toSys));
140 }
141 
142 template <typename FromSysT, typename ToSysT>
143 lsst::geom::Point2D Detector::transform(lsst::geom::Point2D const &point, FromSysT const &fromSys,
144  ToSysT const &toSys) const {
145  return _transformMap->transform(point, makeCameraSys(fromSys), makeCameraSys(toSys));
146 }
147 
148 template <typename FromSysT, typename ToSysT>
150  FromSysT const &fromSys, ToSysT const &toSys) const {
151  return _transformMap->transform(points, makeCameraSys(fromSys), makeCameraSys(toSys));
152 }
153 
154 namespace {
155 
156 class PersistenceHelper {
157 public:
158 
159  static PersistenceHelper const & get() {
160  static PersistenceHelper const instance;
161  return instance;
162  }
163 
164  table::Schema schema;
165  table::Key<std::string> name;
166  table::Key<int> id;
167  table::Key<int> type;
168  table::Key<std::string> serial;
173  table::Key<lsst::geom::Angle> yaw;
174  table::Key<lsst::geom::Angle> pitch;
175  table::Key<lsst::geom::Angle> roll;
176  table::Key<int> transformMap;
177  table::Key<table::Array<float>> crosstalk;
178  table::Key<std::string> physicalType;
179 
180  PersistenceHelper(table::Schema const & existing) :
181  schema(existing),
182  name(schema["name"]),
183  id(schema["id"]),
184  type(schema["type"]),
185  serial(schema["serial"]),
186  bbox(schema["bbox"]),
187  pixelSize(schema["pixelSize"]),
188  fpPosition(schema["fpPosition"]),
189  refPoint(schema["refPoint"]),
190  yaw(schema["yaw"]),
191  pitch(schema["pitch"]),
192  roll(schema["roll"]),
193  transformMap(schema["transformMap"]),
194  crosstalk(schema["crosstalk"])
195  {
196  auto setKeyIfPresent = [this](auto & key, std::string const & name) {
197  try {
198  key = schema[name];
199  } catch (pex::exceptions::NotFoundError &) {}
200  };
201  // This field was not part of the original Detector minimal
202  // schema, but needed to be added
203  setKeyIfPresent(physicalType, "physicalType");
204  }
205 
206 private:
207 
208  PersistenceHelper() :
209  schema(),
210  name(schema.addField<std::string>("name", "Name of the detector", "", 0)),
211  id(schema.addField<int>("id", "Integer ID for the detector", "")),
212  type(schema.addField<int>("type", "Raw DetectorType enum value", "")),
213  serial(schema.addField<std::string>("serial", "Serial name of the detector", "", 0)),
214  bbox(table::Box2IKey::addFields(schema, "bbox", "Detector bounding box", "pixel")),
215  pixelSize(table::Point2DKey::addFields(schema, "pixelSize", "Physical pixel size", "mm")),
216  fpPosition(table::Point2DKey::addFields(schema, "fpPosition",
217  "Focal plane position of reference point", "mm")),
218  refPoint(table::Point2DKey::addFields(schema, "refPoint",
219  "Pixel position of reference point", "pixel")),
220  yaw(schema.addField<lsst::geom::Angle>("yaw", "Rotation about Z (X to Y), 1st rotation")),
221  pitch(schema.addField<lsst::geom::Angle>("pitch", "Rotation about Y' (Z'=Z to X'), 2nd rotation")),
222  roll(schema.addField<lsst::geom::Angle>("roll", "Rotation about X'' (Y''=Y' to Z''), 3rd rotation")),
223  transformMap(schema.addField<int>("transformMap", "Archive ID of TransformMap", "")),
224  crosstalk(schema.addField<table::Array<float>>("crosstalk", "Crosstalk matrix, flattened", "", 0)),
225  physicalType(schema.addField<std::string>("physicalType", "Physical type of the detector", "", 0))
226  {
227  schema.getCitizen().markPersistent();
228  }
229 
230  PersistenceHelper(PersistenceHelper const &) = delete;
231  PersistenceHelper(PersistenceHelper &&) = delete;
232 
233  PersistenceHelper & operator=(PersistenceHelper const &) = delete;
234  PersistenceHelper & operator=(PersistenceHelper &&) = delete;
235 
236 };
237 
238 
239 class DetectorFactory : public table::io::PersistableFactory {
240 public:
241 
242  DetectorFactory() : PersistableFactory("Detector") {}
243 
244  std::shared_ptr<table::io::Persistable> read(InputArchive const& archive,
245  CatalogVector const& catalogs) const override {
246  // N.b. can't use "auto const keys" as cctor is deleted
247  auto const & keys = PersistenceHelper(catalogs.front().getSchema());
248 
249  LSST_ARCHIVE_ASSERT(catalogs.size() == 2u);
250  LSST_ARCHIVE_ASSERT(catalogs.front().getSchema() == keys.schema);
251  LSST_ARCHIVE_ASSERT(catalogs.front().size() == 1u);
252  auto const & record = catalogs.front().front();
253 
254  table::AmpInfoCatalog amps(catalogs.back().getSchema());
255  amps.reserve(catalogs.back().size());
256  // we can't use amps.assign or amps.insert here because those
257  // require the input record to be a subclass of the output record
258  // to permit shallow assignment while this case is the opposte
259  for (auto const & amp : catalogs.back()) {
260  amps.addNew()->assign(amp);
261  }
262 
263  auto flattenedMatrix = record.get(keys.crosstalk);
264  ndarray::Array<float, 2, 2> crosstalk;
265  if (!flattenedMatrix.isEmpty()) {
266  crosstalk = ndarray::allocate(amps.size(), amps.size());
267  ndarray::flatten<1>(crosstalk) = flattenedMatrix;
268  }
269 
270  // get values for not-always-present fields if present
271  const auto physicalType = keys.physicalType.isValid() ? record.get(keys.physicalType) : "";
272 
273  return std::make_shared<Detector>(
274  record.get(keys.name),
275  record.get(keys.id),
276  static_cast<DetectorType>(record.get(keys.type)),
277  record.get(keys.serial),
278  record.get(keys.bbox),
279  amps,
280  Orientation(
281  record.get(keys.fpPosition),
282  record.get(keys.refPoint),
283  record.get(keys.yaw),
284  record.get(keys.pitch),
285  record.get(keys.roll)
286  ),
287  lsst::geom::Extent2D(record.get(keys.pixelSize)),
288  archive.get<TransformMap>(record.get(keys.transformMap)),
289  crosstalk,
290  physicalType
291  );
292  }
293 
294 };
295 
296 DetectorFactory const registration;
297 
298 } // anonymous
299 
300 std::string Detector::getPersistenceName() const {
301  return "Detector";
302 }
303 
304 std::string Detector::getPythonModule() const {
305  return "lsst.afw.cameraGeom";
306 }
307 
308 void Detector::write(OutputArchiveHandle& handle) const {
309  auto const & keys = PersistenceHelper::get();
310 
311  auto cat = handle.makeCatalog(keys.schema);
312  auto record = cat.addNew();
313  record->set(keys.name, getName());
314  record->set(keys.id, getId());
315  record->set(keys.type, static_cast<int>(getType()));
316  record->set(keys.serial, getSerial());
317  record->set(keys.bbox, getBBox());
318  record->set(keys.pixelSize, lsst::geom::Point2D(getPixelSize()));
319  auto orientation = getOrientation();
320  record->set(keys.fpPosition, orientation.getFpPosition());
321  record->set(keys.refPoint, orientation.getReferencePoint());
322  record->set(keys.yaw, orientation.getYaw());
323  record->set(keys.pitch, orientation.getPitch());
324  record->set(keys.roll, orientation.getRoll());
325  record->set(keys.transformMap, handle.put(getTransformMap()));
326 
327  auto flattenMatrix = [](ndarray::Array<float const, 2> const & matrix) {
328  // copy because the original isn't guaranteed to have
329  // row-major contiguous elements
330  ndarray::Array<float, 2, 2> copied = ndarray::copy(matrix);
331  // make a view to the copy
332  ndarray::Array<float, 1, 1> flattened = ndarray::flatten<1>(copied);
333  return flattened;
334  };
335 
336  record->set(keys.crosstalk, flattenMatrix(getCrosstalk()));
337  record->set(keys.physicalType, getPhysicalType());
338  handle.saveCatalog(cat);
339 
340  auto amps = handle.makeCatalog(_ampInfoCatalog.getSchema());
341  amps.assign(_ampInfoCatalog.begin(), _ampInfoCatalog.end(), true);
342  handle.saveCatalog(amps);
343 }
344 
345 
346 //
347 // Explicit instantiations
348 //
349 #define INSTANTIATE(FROMSYS, TOSYS) \
350  template std::shared_ptr<geom::TransformPoint2ToPoint2> Detector::getTransform(FROMSYS const &, \
351  TOSYS const &) const; \
352  template lsst::geom::Point2D Detector::transform(lsst::geom::Point2D const &, FROMSYS const &, \
353  TOSYS const &) const; \
354  template std::vector<lsst::geom::Point2D> Detector::transform(std::vector<lsst::geom::Point2D> const &, \
355  FROMSYS const &, TOSYS const &) const;
356 
357 INSTANTIATE(CameraSys, CameraSys);
358 INSTANTIATE(CameraSys, CameraSysPrefix);
359 INSTANTIATE(CameraSysPrefix, CameraSys);
360 INSTANTIATE(CameraSysPrefix, CameraSysPrefix);
361 
362 } // namespace cameraGeom
363 
364 namespace table {
365 namespace io {
366 
367 template class PersistableFacade<cameraGeom::Detector>;
368 
369 } // namespace io
370 } // namespace table
371 
372 
373 } // namespace afw
374 } // namespace lsst
std::vector< Point2D > getCorners() const
Get the corner points.
Definition: Box.cc:421
table::Key< std::string > name
Definition: Detector.cc:165
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
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(), std::string const &physicalType="")
Make a Detector.
Definition: Detector.cc:36
Geometry and electronic information about raw amplifier images.
Definition: AmpInfo.h:79
A floating-point coordinate rectangle geometry.
Definition: Box.h:305
Point2D const getCenter() const noexcept
Definition: Box.h:423
table::AmpInfoRecord const & operator[](size_t i) const
Get the amplifier specified by index.
Definition: Detector.h:190
BoxKey< lsst::geom::Box2I > Box2IKey
Definition: aggregates.h:201
CameraSysPrefix const PIXELS
Pixel coordinates: Nominal position on the entry surface of a given detector (x, y unbinned pixels)...
Definition: CameraSys.cc:34
table::Point2DKey refPoint
Definition: Detector.cc:172
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:113
static PointKey addFields(Schema &schema, std::string const &name, std::string const &doc, std::string const &unit)
Add a pair of _x, _y fields to a Schema, and return a PointKey that points to them.
Definition: aggregates.cc:36
STL namespace.
std::string getPhysicalType() const
Get information about the physical type of the device (e.g.
Definition: Detector.h:139
T end(T... args)
PointKey< double > Point2DKey
Definition: aggregates.h:118
table::Key< int > id
Definition: Detector.cc:166
DetectorType getType() const
Get the "type" (really purpose) of the Detector.
Definition: Detector.h:136
A class representing an angle.
Definition: Angle.h:127
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:174
CameraSys const makeCameraSys(CameraSys const &cameraSys) const
Get a coordinate system from a coordinate system (return input unchanged and untested) ...
Definition: Detector.h:260
Orientation const getOrientation() const
Get detector&#39;s orientation in the focal plane.
Definition: Detector.h:163
lsst::geom::Box2I getBBox() const
Get the bounding box.
Definition: Detector.h:145
A base class for image defects.
table::Key< int > type
Definition: Detector.cc:167
table::Key< lsst::geom::Angle > roll
Definition: Detector.cc:175
std::shared_ptr< TransformMap const > getTransformMap() const
Get the transform registry.
Definition: Detector.h:169
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:130
bool hasCrosstalk() const
Have we got crosstalk coefficients?
Definition: Detector.h:172
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:91
T str(T... args)
T make_pair(T... args)
CrosstalkMatrix const getCrosstalk() const
Get the crosstalk coefficients.
Definition: Detector.h:177
CatalogT< AmpInfoRecord > AmpInfoCatalog
Definition: fwd.h:97
table::Point2DKey pixelSize
Definition: Detector.cc:170
table::Box2IKey bbox
Definition: Detector.cc:169
lsst::geom::Point2D getCenter(CameraSys const &cameraSys) const
Get the center of the detector in the specified camera coordinate system.
Definition: Detector.cc:101
Camera coordinate system prefix.
Definition: CameraSys.h:44
table::Point2DKey fpPosition
Definition: Detector.cc:171
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
table::Key< std::string > physicalType
Definition: Detector.cc:178
std::string getName() const
Get the detector name.
Definition: Detector.h:130
STL class.
Information about a CCD or other imaging detector.
Definition: Detector.h:62
table::Key< lsst::geom::Angle > yaw
Definition: Detector.cc:173
Key< U > key
Definition: Schema.cc:281
#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:459
int getId() const
Get the detector ID.
Definition: Detector.h:133
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
table::Schema schema
Definition: Detector.cc:164
table::Key< int > transformMap
Definition: Detector.cc:176
table::Key< std::string > serial
Definition: Detector.cc:168
iterator begin()
Iterator access.
Definition: Catalog.h:396
table::Key< table::Array< float > > crosstalk
Definition: Detector.cc:177
lsst::geom::Extent2D getPixelSize() const
Get size of pixel along (mm)
Definition: Detector.h:166
DetectorType
Type of imaging detector.
Definition: Detector.h:44
ndarray::Array< float const, 2 > CrosstalkMatrix
Definition: Detector.h:64
An integer coordinate rectangle.
Definition: Box.h:54
static BoxKey addFields(Schema &schema, std::string const &name, std::string const &doc, std::string const &unit)
Add _min_x, _min_y, _max_x, _max_y fields to a Schema, and return a BoxKey that points to them...
Definition: aggregates.cc:60
std::string getSerial() const
Get the detector serial "number".
Definition: Detector.h:142
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:143
std::ostream * os
Definition: Schema.cc:746
#define INSTANTIATE(FROMSYS, TOSYS)
Definition: Detector.cc:349
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.