24#include <unordered_set>
44template <
typename Iter>
45Iter findAmpIterByName(Iter first, Iter last,
std::string const & name) {
49 pex::exceptions::InvalidParameterError,
50 (boost::format(
"Amplifier with name %s not found.") % name).str()
59 return std::make_shared<PartialRebuilder>(*
this);
64 auto nativeToCameraSys = _transformMap->getTransform(
getNativeCoordSys(), cameraSys);
65 return nativeToCameraSys->applyForward(nativeCorners);
88template <
typename FromSysT,
typename ToSysT>
90 ToSysT
const &toSys)
const {
94template <
typename FromSysT,
typename ToSysT>
96 ToSysT
const &toSys)
const {
100template <
typename FromSysT,
typename ToSysT>
102 FromSysT
const &fromSys, ToSysT
const &toSys)
const {
107 return *findAmpIterByName(_amplifiers.begin(), _amplifiers.end(), name);
112void checkForDuplicateAmpNames(AmpVector
const & amplifiers) {
114 for (
auto const &
ptr : amplifiers) {
115 if (!amplifierNames.
insert(
ptr->getName()).second) {
117 (boost::format(
"Multiple amplifiers with name %s") %
ptr->getName()).str());
125 assert(shape.size() == 2);
126 if (shape[0] != shape[1]) {
131 if (shape[0] != nAmps) {
141 AmpVector &&lifiers) :
144 checkForDuplicateAmpNames(_amplifiers);
156int constexpr SERIALIZATION_VERSION = 2;
158class DetectorSchema {
161 table::Key<std::string> name;
163 table::Key<int> type;
170 table::Key<lsst::geom::Angle>
yaw;
171 table::Key<lsst::geom::Angle>
pitch;
172 table::Key<lsst::geom::Angle>
roll;
179 DetectorSchema(
const DetectorSchema&) =
delete;
180 DetectorSchema& operator=(
const DetectorSchema&) =
delete;
183 DetectorSchema(DetectorSchema&&) =
delete;
184 DetectorSchema& operator=(DetectorSchema&&) =
delete;
186 DetectorSchema(
int detectorVersion = SERIALIZATION_VERSION)
188 name(
schema.addField<
std::string>(
"name",
"Name of the detector",
"", 0)),
189 id(
schema.addField<int>(
"id",
"Integer ID for the detector",
"")),
190 type(
schema.addField<int>(
"type",
"Raw DetectorType enum value",
"")),
191 serial(
schema.addField<
std::string>(
"serial",
"Serial name of the detector",
"", 0)),
192 bbox(table::Box2IKey::addFields(
schema,
"bbox",
"Detector bounding box",
"pixel")),
193 pixelSize(table::Point2DKey::addFields(
schema,
"pixelSize",
"Physical pixel size",
"mm"))
195 if (detectorVersion >= 2) {
197 schema,
"fpPosition",
"Focal plane position of reference point",
"mm"
201 schema,
"fpPosition",
"Focal plane position of reference point",
"mm"
205 schema,
"refPoint",
"Pixel position of reference point",
"pixel"
210 transformMap =
schema.addField<
int>(
"transformMap",
"Archive ID of TransformMap",
"");
211 crosstalk =
schema.addField<table::Array<float>>(
"crosstalk",
"Crosstalk matrix, flattened",
"", 0);
213 if (detectorVersion >= 1) {
216 if (detectorVersion >= 2) {
217 version =
schema.addField<
int>(
"version",
"version of this Detector");
236 auto const & record = catalogs.front().front();
237 int version = getVersion(catalogs);
238 if (
version > SERIALIZATION_VERSION) {
241 "Cannot read Detector FITS version > " +
245 auto const & keys = DetectorSchema(
version);
248 amps.reserve(catalogs.back().size());
249 for (
auto const & record : catalogs.back()) {
253 auto flattenedMatrix = record.get(keys.crosstalk);
255 if (!flattenedMatrix.isEmpty()) {
256 crosstalk = ndarray::allocate(amps.size(), amps.size());
257 ndarray::flatten<1>(
crosstalk) = flattenedMatrix;
272 record.get(keys.name),
275 record.get(keys.serial),
276 record.get(keys.bbox),
279 record.get(keys.refPoint),
280 record.get(keys.yaw),
281 record.get(keys.pitch),
282 record.get(keys.roll)
303 auto const & record = catalogs.front().front();
305 auto versionKey = record.getSchema().find<
int>(
"version");
306 return record.get(versionKey.key);
310 catalogs.front().getSchema().find<
std::string>(
"physicalType");
326 return "lsst.afw.cameraGeom";
330 auto const & keys = DetectorSchema();
333 auto record = cat.
addNew();
334 record->set(keys.name,
getName());
335 record->set(keys.id,
getId());
336 record->set(keys.type,
static_cast<int>(
getType()));
338 record->set(keys.bbox,
getBBox());
341 record->set(keys.fpPosition, orientation.getFpPosition3());
342 record->set(keys.refPoint, orientation.getReferencePoint());
343 record->set(keys.yaw, orientation.getYaw());
344 record->set(keys.pitch, orientation.getPitch());
345 record->set(keys.roll, orientation.getRoll());
348 auto flattenMatrix = [](ndarray::Array<float const, 2>
const & matrix) {
351 ndarray::Array<float, 2, 2> copied = ndarray::copy(matrix);
353 ndarray::Array<float, 1, 1> flattened = ndarray::flatten<1>(copied);
357 record->set(keys.crosstalk, flattenMatrix(
getCrosstalk()));
359 record->set(keys.version, SERIALIZATION_VERSION);
365 auto record = ampCat.addNew();
366 amp->toRecord(*record);
373 return *findAmpIterByName(_amplifiers.begin(), _amplifiers.end(), name);
377 _amplifiers.push_back(
std::move(builder));
385 for (
auto const & ampPtr :
detector) {
386 result.push_back(std::make_shared<Amplifier::Builder>(*ampPtr));
400 result.reserve(_amplifiers.size());
401 for (
auto const & ampBuilderPtr : _amplifiers) {
402 result.push_back(ampBuilderPtr->finish());
409 Builder(detector._fields, rebuildAmplifiers(detector)),
425template <
typename Iter>
426Iter findConnection(Iter first, Iter last,
CameraSys const & toSys) {
429 [&toSys](
auto const & connection) {
430 return connection.toSys == toSys;
452 (boost::format(
"Cannot add coordinate system for detector '%s' to detector '%s'.") %
456 auto iter = findConnection(_connections.begin(), _connections.end(), toSys);
457 if (iter == _connections.end()) {
458 _connections.push_back(
474 (boost::format(
"Cannot add coordinate system for detector '%s' to detector '%s'.") %
478 auto iter = findConnection(_connections.begin(), _connections.end(), toSys);
479 if (iter != _connections.end()) {
480 _connections.erase(iter);
487Detector::InCameraBuilder::InCameraBuilder(
Detector const & detector) :
491Detector::InCameraBuilder::InCameraBuilder(
std::string const & name,
int id) :
499 auto amplifiers = finishAmplifiers();
509#define INSTANTIATE(FROMSYS, TOSYS) \
510 template std::shared_ptr<geom::TransformPoint2ToPoint2> Detector::getTransform(FROMSYS const &, \
511 TOSYS const &) const; \
512 template lsst::geom::Point2D Detector::transform(lsst::geom::Point2D const &, FROMSYS const &, \
513 TOSYS const &) const; \
514 template std::vector<lsst::geom::Point2D> Detector::transform(std::vector<lsst::geom::Point2D> const &, \
515 FROMSYS const &, TOSYS const &) const;
527template class PersistableFacade<cameraGeom::Detector>;
table::Key< std::string > name
table::Key< int > transformMap
table::Point2DKey refPoint
table::Point3DKey fpPosition
table::Key< lsst::geom::Angle > yaw
table::Point2DKey fpPosition2
table::Key< lsst::geom::Angle > roll
#define INSTANTIATE(FROMSYS, TOSYS)
table::Key< std::string > physicalType
table::Point2DKey pixelSize
table::Key< lsst::geom::Angle > pitch
table::Key< std::string > serial
table::Key< table::Array< float > > crosstalk
table::Key< int > detector
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
static Builder fromRecord(table::BaseRecord const &record)
Construct a new Builder object from the fields in the given record.
std::shared_ptr< Amplifier const > finish() const
Construct an immutable Amplifier with the same values as the Builder.
static table::Schema getRecordSchema()
Return the schema used in the afw.table representation of amplifiers.
Camera coordinate system; used as a key in in TransformMap.
bool hasDetectorName() const noexcept
Does this have a non-blank detector name?
std::string getDetectorName() const
Get detector name, or "" if not a detector-specific coordinate system.
Camera coordinate system prefix.
A helper class for Detector that allows amplifiers and most fields to be modified.
~Builder() noexcept override=0
Builder(Builder const &)=delete
static std::vector< std::shared_ptr< Amplifier::Builder > > rebuildAmplifiers(Detector const &detector)
Create a vector of Amplifier::Builders from the Amplifiers in a Detector.
void append(std::shared_ptr< Amplifier::Builder > builder)
Append a new amplifier.
std::shared_ptr< Amplifier::Builder > operator[](size_t i) const
Get the amplifier builder specified by index.
Factory(std::string const &name)
std::shared_ptr< table::io::Persistable > read(InputArchive const &archive, CatalogVector const &catalogs) const override
Construct a new object from the given InputArchive and vector of catalogs.
static Factory const registration
void setTransformFromPixelsTo(CameraSysPrefix const &toSys, std::shared_ptr< afw::geom::TransformPoint2ToPoint2 const > transform)
Set the transformation from PIXELS to the given coordinate system.
bool discardTransformFromPixelsTo(CameraSysPrefix const &toSys)
Remove any transformation from PIXELS to the given coordinate system.
PartialRebuilder(Detector const &detector)
Construct a PartialRebuilder initialized to the state of the given Detector.
std::shared_ptr< Detector const > finish() const
Construct a new Detector from the current state of the Builder.
lsst::geom::Box2I getBBox() const
Get the bounding box.
lsst::geom::Extent2D getPixelSize() const
Get size of pixel along (mm)
std::string getName() const
Get the detector name.
CameraSys getNativeCoordSys() const
The "native" coordinate system of this detector.
bool hasCrosstalk() const
Have we got crosstalk coefficients?
int getId() const
Get the detector ID.
std::string getPhysicalType() const
Get the detector's physical type.
Orientation getOrientation() const
Get detector's orientation in the focal plane.
std::string getSerial() const
Get the detector serial "number".
CameraSys makeCameraSys(CameraSys const &cameraSys) const
Get a coordinate system from a coordinate system (return input unchanged and untested)
CrosstalkMatrix getCrosstalk() const
Get the crosstalk coefficients.
ndarray::Array< float const, 2 > CrosstalkMatrix
DetectorType getType() const
Return the purpose of this detector.
A representation of a detector in a mosaic camera.
std::vector< std::shared_ptr< Amplifier const > > const & getAmplifiers() const
Return the sequence of Amplifiers directly.
bool hasTransform(CameraSys const &cameraSys) const
Can this object convert between PIXELS and the specified camera coordinate system?
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,...
std::string getPythonModule() const override
Return the fully-qualified Python module that should be imported to guarantee that its factory is reg...
std::size_t size() const
Get the number of amplifiers.
std::shared_ptr< Amplifier const > operator[](size_t i) const
Get the amplifier specified by index.
std::string getPersistenceName() const override
Return the unique name used to persist this object and look up its factory.
std::shared_ptr< TransformMap const > getTransformMap() const
Get the transform registry.
Fields const & getFields() const override
Return a reference to a Fields struct.
void write(OutputArchiveHandle &handle) const override
Write the object to one or more catalogs.
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.
std::vector< lsst::geom::Point2D > getCorners(CameraSys const &cameraSys) const
Get the corners of the detector in the specified camera coordinate system.
lsst::geom::Point2D getCenter(CameraSys const &cameraSys) const
Get the center of the detector in the specified camera coordinate system.
std::shared_ptr< PartialRebuilder > rebuild() const
Return a Builder object initialized with the state of this Detector.
Describe a detector's orientation in the focal plane.
std::shared_ptr< RecordT > addNew()
Create a new record, add it to the end of the catalog, and return a pointer to it.
void reserve(size_type n)
Increase the capacity of the catalog to the given size.
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.
A vector of catalogs used by Persistable.
An object passed to Persistable::write to allow it to persist itself.
void saveCatalog(BaseCatalog const &catalog)
Save a catalog in the archive.
BaseCatalog makeCatalog(Schema const &schema)
Return a new, empty catalog with the given schema.
int put(Persistable const *obj, bool permissive=false)
Save an object to the archive and return a unique ID that can be used to retrieve it from an InputArc...
A base class for factory classes used to reconstruct objects from records.
A class representing an angle.
A floating-point coordinate rectangle geometry.
Point2D const getCenter() const noexcept
Return true if the box contains no points.
std::vector< Point2D > getCorners() const
Get the corner points.
Reports invalid arguments.
Reports attempts to access elements using an invalid key.
Reports errors from accepting an object of an unexpected or inappropriate type.
DetectorType
Type of imaging detector.
Point3Key< double > Point3DKey
BoxKey< lsst::geom::Box2I > Box2IKey
PointKey< double > Point2DKey
Extent< double, 2 > Extent2D
Point< double, 3 > Point3D