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
Amplifier.cc
Go to the documentation of this file.
1// -*- lsst-c++ -*-
2/*
3 * Developed for the LSST Data Management System.
4 * This product includes software developed by the LSST Project
5 * (https://www.lsst.org).
6 * See the COPYRIGHT file at the top-level directory of this distribution
7 * for details of code ownership.
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
25
26namespace lsst {
27namespace afw {
28namespace cameraGeom {
29
30namespace {
31
32/*
33 * Private (minimalist) FunctorKey for Box2I that uses _min and _extent, since
34 * that's what AmpInfoRecord used in its schema (which predates the new
35 * _min+_max BoxKey defined in afw/table/aggregates.h) - while AmpInfoRecord
36 * will be removed shortly, its schema lives on in persisted Amplifiers, and
37 * we don't want to break our ability to read those.
38 */
39class AmpInfoBoxKey : public table::FunctorKey<lsst::geom::Box2I> {
40public:
41
56 static AmpInfoBoxKey addFields(table::Schema& schema, std::string const& name, std::string const& doc,
57 std::string const& unit) {
58 AmpInfoBoxKey result;
60 schema,
61 schema.join(name, "min"),
62 doc + ", min point",
63 unit
64 );
66 schema,
67 schema.join(name, "extent"),
68 doc + ", extent",
69 unit
70 );
71 return result;
72 }
73
74 // Default constructor; instance will not be usable unless subsequently assigned to.
75 AmpInfoBoxKey() noexcept = default;
76
77 /*
78 * Construct from a subschema, assuming _min_x, _max_x, _min_y, _max_y subfields
79 *
80 * If a schema has "a_min_x" and "a_min_x" (etc) fields, this constructor allows you to construct
81 * a BoxKey via:
82 *
83 * BoxKey<Box> k(schema["a"]);
84 */
85 AmpInfoBoxKey(table::SubSchema const& s) : _min(s["min"]), _dimensions(s["extent"]) {}
86
87 AmpInfoBoxKey(AmpInfoBoxKey const&) noexcept = default;
88 AmpInfoBoxKey(AmpInfoBoxKey&&) noexcept = default;
89 AmpInfoBoxKey& operator=(AmpInfoBoxKey const&) noexcept = default;
90 AmpInfoBoxKey& operator=(AmpInfoBoxKey&&) noexcept = default;
91 ~AmpInfoBoxKey() noexcept override = default;
92
93 // Get a Box from the given record
94 lsst::geom::Box2I get(table::BaseRecord const& record) const override {
95 return lsst::geom::Box2I(record.get(_min),
96 lsst::geom::Extent2I(record.get(_dimensions)));
97 }
98
99 // Set a Box in the given record
100 void set(table::BaseRecord& record, lsst::geom::Box2I const& value) const override {
101 record.set(_min, value.getMin());
102 record.set(_dimensions, lsst::geom::Point2I(value.getDimensions()));
103 }
104
105 // Return True if all internal keys point to actual fields in a schema.
106 bool isValid() const noexcept { return _min.isValid() && _dimensions.isValid(); }
107
108private:
110 table::Point2IKey _dimensions;
111};
112
113
114struct RecordSchemaHelper {
115 table::Schema schema;
116 table::Key<std::string> name;
117 AmpInfoBoxKey bbox;
118 table::Key<double> gain;
119 table::Key<double> saturation;
120 table::Key<double> suspectLevel;
121 table::Key<double> readNoise;
122 table::Key<int> readoutCorner;
123 table::Key<table::Array<double> > linearityCoeffs;
124 table::Key<std::string> linearityType;
125 table::Key<table::Flag> hasRawInfo;
126 AmpInfoBoxKey rawBBox;
127 AmpInfoBoxKey rawDataBBox;
128 table::Key<table::Flag> rawFlipX;
129 table::Key<table::Flag> rawFlipY;
130 table::PointKey<int> rawXYOffset;
133 AmpInfoBoxKey rawPrescanBBox;
134 table::Key<double> linearityThreshold;
135 table::Key<double> linearityMaximum;
136 table::Key<std::string> linearityUnits;
137
138 static RecordSchemaHelper const & getMinimal() {
139 static RecordSchemaHelper const instance;
140 return instance;
141 }
142
143 RecordSchemaHelper(table::Schema const & existing) :
144 schema(existing),
145 name(schema["name"]),
146 bbox(schema["bbox"]),
147 gain(schema["gain"]),
148 saturation(schema["saturation"]),
149 suspectLevel(schema["suspectlevel"]),
150 readNoise(schema["readnoise"]),
151 readoutCorner(schema["readoutcorner"]),
152 linearityCoeffs(schema["linearity_coeffs"]),
153 linearityType(schema["linearity_type"]),
154 hasRawInfo(schema["hasrawinfo"]),
155 rawBBox(schema["raw_bbox"]),
156 rawDataBBox(schema["raw_databbox"]),
157 rawFlipX(schema["raw_flip_x"]),
158 rawFlipY(schema["raw_flip_y"]),
159 rawXYOffset(schema["raw_xyoffset"]),
160 rawHorizontalOverscanBBox(schema["raw_horizontaloverscanbbox"]),
161 rawVerticalOverscanBBox(schema["raw_verticaloverscanbbox"]),
162 rawPrescanBBox(schema["raw_prescanbbox"])
163 {
164 auto setKeyIfPresent = [this](auto & key, std::string const & name) {
165 try {
166 key = schema[name];
167 } catch (pex::exceptions::NotFoundError &) {}
168 };
169 // These fields were not part of the original AmpInfoRecord minimal
170 // schema, but were frequently used and are now present on all
171 // Amplifier objects, even if unused.
172 // Unfortunately they use a different naming convention than the
173 // others, but as humans will rarely interact with the record form
174 // going forward this is not a big deal.
175 setKeyIfPresent(linearityThreshold, "linearityThreshold");
176 setKeyIfPresent(linearityMaximum, "linearityMaximum");
177 setKeyIfPresent(linearityUnits, "linearityUnits");
178 }
179
180private:
181
182 RecordSchemaHelper() :
183 schema(),
184 name(schema.addField<std::string>("name", "name of amplifier location in camera", "", 0)),
185 bbox(AmpInfoBoxKey::addFields(
186 schema, "bbox", "bbox of amplifier image data on assembled image", "pixel")),
187 gain(schema.addField<double>("gain", "amplifier gain", "electron adu^-1")),
188 saturation(schema.addField<double>(
189 "saturation",
190 "level above which pixels are considered saturated; use `nan` if no such level applies",
191 "adu")),
192 suspectLevel(schema.addField<double>(
193 "suspectlevel",
194 "level above which pixels are considered suspicious, meaning they may be affected by unknown "
195 "systematics; for example if non-linearity corrections above a certain level are unstable "
196 "then that would be a useful value for suspectLevel; use `nan` if no such level applies",
197 "adu")),
198 readNoise(schema.addField<double>("readnoise", "amplifier read noise", "electron")),
200 schema.addField<int>("readoutcorner", "readout corner, in the frame of the assembled image")),
202 schema.addField<table::Array<double> >("linearity_coeffs",
203 "coefficients for linearity fit up to cubic", "", 0)),
204 linearityType(schema.addField<std::string>("linearity_type", "type of linearity model", "", 0)),
205 hasRawInfo(schema.addField<table::Flag>(
206 "hasrawinfo", "is raw amplifier information available (e.g. untrimmed bounding boxes)?")),
207 rawBBox(AmpInfoBoxKey::addFields(schema, "raw_bbox",
208 "entire amplifier bbox on raw image", "pixel")),
209 rawDataBBox(AmpInfoBoxKey::addFields(schema, "raw_databbox",
210 "image data bbox on raw image", "pixel")),
211 rawFlipX(schema.addField<table::Flag>("raw_flip_x", "flip row order to make assembled image?")),
212 rawFlipY(schema.addField<table::Flag>("raw_flip_y", "flip column order to make an assembled image?")),
213 rawXYOffset(table::Point2IKey::addFields(
214 schema, "raw_xyoffset",
215 "offset for assembling a raw CCD image: desired xy0 - raw xy0; 0,0 if raw data comes assembled",
216 "pixel")),
218 AmpInfoBoxKey::addFields(schema, "raw_horizontaloverscanbbox",
219 "usable horizontal overscan bbox on raw image", "pixel")),
221 AmpInfoBoxKey::addFields(schema, "raw_verticaloverscanbbox",
222 "usable vertical overscan region raw image", "pixel")),
224 AmpInfoBoxKey::addFields(schema, "raw_prescanbbox",
225 "usable (horizontal) prescan bbox on raw image", "pixel")),
226 linearityThreshold(schema.addField<double>("linearityThreshold",
227 "Minimum ADU level to apply linearity.")),
228 linearityMaximum(schema.addField<double>("linearityMaximum",
229 "Maximum ADU level to apply linearity.")),
230 linearityUnits(schema.addField<std::string>("linearityUnits",
231 "Input units for linearity relation.", "", 0))
232 {
233
234 }
235
236};
237
238
239class FrozenAmplifier final : public Amplifier {
240public:
241
242 explicit FrozenAmplifier(Fields const & fields) : _fields(fields) {}
243
244 // This is a hidden implementation class, so none of its move/copy ctors or
245 // assignment operators would ever be used even if they did exist.
246
247 FrozenAmplifier(FrozenAmplifier const &) = delete;
248 FrozenAmplifier(FrozenAmplifier &&) = delete;
249
250 FrozenAmplifier & operator=(FrozenAmplifier const &) = delete;
251 FrozenAmplifier & operator=(FrozenAmplifier &&) = delete;
252
253 ~FrozenAmplifier() noexcept override = default;
254
255protected:
256
257 Fields const & getFields() const override { return _fields; }
258
259private:
260
261 Fields const _fields;
262};
263
264} // anonyomous
265
266
268 return RecordSchemaHelper::getMinimal().schema;
269}
270
272
273Amplifier::Builder::Builder(Amplifier const & other) : _fields(other.getFields()) {}
274
276 using std::swap;
277 Fields copy(other.getFields());
278 swap(_fields, copy);
279 return *this;
280}
281
283 return std::make_shared<FrozenAmplifier>(_fields);
284}
285
287 auto const helper = RecordSchemaHelper(record.getSchema());
289 result.setName(record.get(helper.name));
290 result.setBBox(record.get(helper.bbox));
291 result.setGain(record.get(helper.gain));
292 result.setReadNoise(record.get(helper.readNoise));
293 result.setSaturation(record.get(helper.saturation));
294 result.setSuspectLevel(record.get(helper.suspectLevel));
295 result.setReadoutCorner(static_cast<ReadoutCorner>(record.get(helper.readoutCorner)));
296 result.setLinearityCoeffs(ndarray::copy(record.get(helper.linearityCoeffs)));
297 result.setLinearityType(record.get(helper.linearityType));
298 result.setRawBBox(record.get(helper.rawBBox));
299 result.setRawDataBBox(record.get(helper.rawDataBBox));
300 result.setRawFlipX(record.get(helper.rawFlipX));
301 result.setRawFlipY(record.get(helper.rawFlipY));
302 result.setRawXYOffset(lsst::geom::Extent2I(record.get(helper.rawXYOffset)));
303 result.setRawHorizontalOverscanBBox(record.get(helper.rawHorizontalOverscanBBox));
304 result.setRawVerticalOverscanBBox(record.get(helper.rawVerticalOverscanBBox));
305 result.setRawHorizontalOverscanBBox(record.get(helper.rawHorizontalOverscanBBox));
306 result.setRawPrescanBBox(record.get(helper.rawPrescanBBox));
307 // Set not-always-present fields only when present. While it's usually
308 // preferable to use the public setter methods (as above), passing member
309 // function pointers through the lambda below is sufficiently unpleasant
310 // that we just set the private member directly.
311 auto setIfValid = [&record](auto & member, auto & key) {
312 if (key.isValid()) {
313 member = record.get(key);
314 }
315 };
316 setIfValid(result._fields.linearityThreshold, helper.linearityThreshold);
317 setIfValid(result._fields.linearityMaximum, helper.linearityMaximum);
318 setIfValid(result._fields.linearityUnits, helper.linearityUnits);
319 return result;
320}
321
323 auto const helper = RecordSchemaHelper(record.getSchema());
324 auto const & fields = getFields();
325 record.set(helper.name, fields.name);
326 record.set(helper.bbox, fields.bbox);
327 record.set(helper.gain, fields.gain);
328 record.set(helper.readNoise, fields.readNoise);
329 record.set(helper.saturation, fields.saturation);
330 record.set(helper.suspectLevel, fields.suspectLevel);
331 record.set(helper.readoutCorner, static_cast<int>(fields.readoutCorner));
332 ndarray::Array<double, 1, 1> coeffs = ndarray::copy(fields.linearityCoeffs);
333 record.set(helper.linearityCoeffs, coeffs);
334 record.set(helper.linearityType, fields.linearityType);
335 record.set(helper.rawBBox, fields.rawBBox);
336 record.set(helper.rawDataBBox, fields.rawDataBBox);
337 record.set(helper.rawFlipX, fields.rawFlipX);
338 record.set(helper.rawFlipY, fields.rawFlipY);
339 record.set(helper.rawXYOffset, lsst::geom::Point2I(fields.rawXYOffset));
340 record.set(helper.rawHorizontalOverscanBBox, fields.rawHorizontalOverscanBBox);
341 record.set(helper.rawVerticalOverscanBBox, fields.rawVerticalOverscanBBox);
342 record.set(helper.rawPrescanBBox, fields.rawPrescanBBox);
343 // Set not-always-present fields only when present.
344 auto setIfValid = [&record](auto value, auto & key) {
345 if (key.isValid()) {
346 record.set(key, value);
347 }
348 };
349 setIfValid(fields.linearityThreshold, helper.linearityThreshold);
350 setIfValid(fields.linearityMaximum, helper.linearityMaximum);
351 setIfValid(fields.linearityUnits, helper.linearityUnits);
352}
353
354} // namespace table
355} // namespace afw
356} // namespace lsst
py::object result
Definition: _schema.cc:429
AmpInfoBoxKey rawBBox
Definition: Amplifier.cc:126
table::Key< std::string > name
Definition: Amplifier.cc:116
table::Key< double > linearityThreshold
Definition: Amplifier.cc:134
table::Key< table::Flag > hasRawInfo
Definition: Amplifier.cc:125
table::Key< std::string > linearityType
Definition: Amplifier.cc:124
AmpInfoBoxKey bbox
Definition: Amplifier.cc:117
table::Key< double > gain
Definition: Amplifier.cc:118
table::Schema schema
Definition: Amplifier.cc:115
table::Key< table::Array< double > > linearityCoeffs
Definition: Amplifier.cc:123
table::Key< std::string > linearityUnits
Definition: Amplifier.cc:136
AmpInfoBoxKey rawVerticalOverscanBBox
Definition: Amplifier.cc:132
AmpInfoBoxKey rawHorizontalOverscanBBox
Definition: Amplifier.cc:131
table::Key< double > saturation
Definition: Amplifier.cc:119
table::Key< double > readNoise
Definition: Amplifier.cc:121
table::Key< table::Flag > rawFlipX
Definition: Amplifier.cc:128
table::Key< int > readoutCorner
Definition: Amplifier.cc:122
table::PointKey< int > rawXYOffset
Definition: Amplifier.cc:130
table::Key< table::Flag > rawFlipY
Definition: Amplifier.cc:129
table::Key< double > suspectLevel
Definition: Amplifier.cc:120
AmpInfoBoxKey rawDataBBox
Definition: Amplifier.cc:127
AmpInfoBoxKey rawPrescanBBox
Definition: Amplifier.cc:133
table::Key< double > linearityMaximum
Definition: Amplifier.cc:135
int min
A mutable Amplifier subclass class that can be used to incrementally construct or modify Amplifiers.
Definition: Amplifier.h:305
Builder & operator=(Builder const &)=default
Standard copy assignment.
Builder()=default
Construct a Builder with default values for all fields.
static Builder fromRecord(table::BaseRecord const &record)
Construct a new Builder object from the fields in the given record.
Definition: Amplifier.cc:286
std::shared_ptr< Amplifier const > finish() const
Construct an immutable Amplifier with the same values as the Builder.
Definition: Amplifier.cc:282
Geometry and electronic information about raw amplifier images.
Definition: Amplifier.h:86
Builder rebuild() const
Return a Builder object initialized with the fields of this.
Definition: Amplifier.cc:271
virtual Fields const & getFields() const =0
void toRecord(table::BaseRecord &record) const
Copy the Amplifier's fields into the given record.
Definition: Amplifier.cc:322
static table::Schema getRecordSchema()
Return the schema used in the afw.table representation of amplifiers.
Definition: Amplifier.cc:267
Base class for all records.
Definition: BaseRecord.h:31
Field< T >::Value get(Key< T > const &key) const
Return the value of a field for the given key.
Definition: BaseRecord.h:151
Schema getSchema() const
Return the Schema that holds this record's fields and keys.
Definition: BaseRecord.h:80
void set(Key< T > const &key, U const &value)
Set value of a field for the given key.
Definition: BaseRecord.h:164
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
Defines the fields and offsets for a table.
Definition: Schema.h:51
An integer coordinate rectangle.
Definition: Box.h:55
Point2I const getMin() const noexcept
Definition: Box.h:156
Extent2I const getDimensions() const noexcept
Definition: Box.h:186
daf::base::PropertySet * set
Definition: fits.cc:912
bool isValid
Definition: fits.cc:399
ReadoutCorner
Readout corner, in the frame of reference of the assembled image.
Definition: Amplifier.h:38
void swap(CameraSys &a, CameraSys &b)
Definition: CameraSys.h:157
PointKey< int > Point2IKey
Definition: aggregates.h:117
A base class for image defects.
STL namespace.
T swap(T... args)