LSSTApplications  19.0.0+10,19.0.0+80,19.0.0-1-g20d9b18+31,19.0.0-1-g49a97f9+4,19.0.0-1-g8c57eb9+31,19.0.0-1-g9a028c0+13,19.0.0-1-ga72da6b+3,19.0.0-1-gb77924a+15,19.0.0-1-gbfe0924+66,19.0.0-1-gc3516c3,19.0.0-1-gefe1d0d+49,19.0.0-1-gf8cb8b4+3,19.0.0-14-g7511ce4+6,19.0.0-16-g3dc1a33c+6,19.0.0-17-g59f0e8a+4,19.0.0-17-g9c22e3c+9,19.0.0-18-g35bb99870+2,19.0.0-19-g2772d4a+9,19.0.0-2-g260436e+53,19.0.0-2-g31cdcee,19.0.0-2-g9675b69+3,19.0.0-2-gaa2795f,19.0.0-2-gbcc4de1,19.0.0-2-gd6f004e+6,19.0.0-2-gde8e5e3+5,19.0.0-2-gff6972b+15,19.0.0-21-ge306cd8,19.0.0-21-gf122e69+2,19.0.0-3-g2d43a51+2,19.0.0-3-gf3b1435+6,19.0.0-4-g56feb96,19.0.0-4-gac56cce+17,19.0.0-49-gce872c1+1,19.0.0-5-g66946eb+6,19.0.0-5-gd8897ba+6,19.0.0-51-gfc4a647e,19.0.0-7-g686a884+5,19.0.0-7-g886f805+5,19.0.0-8-g305ff64,w.2020.17
LSSTDataManagementBasePackage
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 
26 namespace lsst {
27 namespace afw {
28 namespace cameraGeom {
29 
30 namespace {
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  */
39 class AmpInfoBoxKey : public table::FunctorKey<lsst::geom::Box2I> {
40 public:
41 
56  static AmpInfoBoxKey addFields(table::Schema& schema, std::string const& name, std::string const& doc,
57  std::string const& unit) {
58  AmpInfoBoxKey result;
59  result._min = table::Point2IKey::addFields(
60  schema,
61  schema.join(name, "min"),
62  doc + ", min point",
63  unit
64  );
65  result._dimensions = table::Point2IKey::addFields(
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 
108 private:
109  table::Point2IKey _min;
110  table::Point2IKey _dimensions;
111 };
112 
113 
114 struct 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;
132  AmpInfoBoxKey rawVerticalOverscanBBox;
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 
180 private:
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?")),
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 
239 class FrozenAmplifier final : public Amplifier {
240 public:
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 
255 protected:
256 
257  Fields const & getFields() const override { return _fields; }
258 
259 private:
260 
261  Fields const _fields;
262 };
263 
264 } // anonyomous
265 
266 
268  return RecordSchemaHelper::getMinimal().schema;
269 }
270 
272 
273 Amplifier::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());
288  Builder result;
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 = [this, &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
AmpInfoBoxKey bbox
Definition: Amplifier.cc:117
Defines the fields and offsets for a table.
Definition: Schema.h:50
table::Key< double > linearityMaximum
Definition: Amplifier.cc:135
T swap(T... args)
PointKey< int > Point2IKey
Definition: aggregates.h:117
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
ItemVariant const * other
Definition: Schema.cc:56
table::Key< double > suspectLevel
Definition: Amplifier.cc:120
void toRecord(table::BaseRecord &record) const
Copy the Amplifier&#39;s fields into the given record.
Definition: Amplifier.cc:322
Field< T >::Value get(Key< T > const &key) const
Return the value of a field for the given key.
Definition: BaseRecord.h:151
table::Key< std::string > linearityType
Definition: Amplifier.cc:124
int min
AmpInfoBoxKey rawDataBBox
Definition: Amplifier.cc:127
Builder rebuild() const
Return a Builder object initialized with the fields of this.
Definition: Amplifier.cc:271
A mutable Amplifier subclass class that can be used to incrementally construct or modify Amplifiers...
Definition: Amplifier.h:280
STL class.
table::Key< std::string > linearityUnits
Definition: Amplifier.cc:136
table::Key< double > saturation
Definition: Amplifier.cc:119
Builder & operator=(Builder const &)=default
Standard copy assignment.
table::PointKey< int > rawXYOffset
Definition: Amplifier.cc:130
AmpInfoBoxKey rawBBox
Definition: Amplifier.cc:126
A base class for image defects.
std::shared_ptr< Amplifier const > finish() const
Construct an immutable Amplifier with the same values as the Builder.
Definition: Amplifier.cc:282
table::Key< double > gain
Definition: Amplifier.cc:118
table::Key< double > readNoise
Definition: Amplifier.cc:121
AmpInfoBoxKey rawVerticalOverscanBBox
Definition: Amplifier.cc:132
bool isValid
Definition: fits.cc:399
table::Schema schema
Definition: Amplifier.cc:115
Key< U > key
Definition: Schema.cc:281
Schema getSchema() const
Return the Schema that holds this record&#39;s fields and keys.
Definition: BaseRecord.h:80
table::Key< table::Array< double > > linearityCoeffs
Definition: Amplifier.cc:123
virtual Fields const & getFields() const =0
static Builder fromRecord(table::BaseRecord const &record)
Construct a new Builder object from the fields in the given record.
Definition: Amplifier.cc:286
Extent< int, 2 > Extent2I
Definition: Extent.h:397
table::Key< table::Flag > hasRawInfo
Definition: Amplifier.cc:125
Base class for all records.
Definition: BaseRecord.h:31
table::Key< double > linearityThreshold
Definition: Amplifier.cc:134
table::Key< std::string > name
Definition: Amplifier.cc:116
Geometry and electronic information about raw amplifier images.
Definition: Amplifier.h:86
void set(Key< T > const &key, U const &value)
Set value of a field for the given key.
Definition: BaseRecord.h:164
void swap(CameraSys &a, CameraSys &b)
Definition: CameraSys.h:157
table::Key< table::Flag > rawFlipX
Definition: Amplifier.cc:128
An integer coordinate rectangle.
Definition: Box.h:55
AmpInfoBoxKey rawPrescanBBox
Definition: Amplifier.cc:133
py::object result
Definition: _schema.cc:429
AmpInfoBoxKey rawHorizontalOverscanBBox
Definition: Amplifier.cc:131
table::Key< int > readoutCorner
Definition: Amplifier.cc:122
table::Key< table::Flag > rawFlipY
Definition: Amplifier.cc:129
Fields const & getFields() const override
Definition: Amplifier.h:411
static table::Schema getRecordSchema()
Return the schema used in the afw.table representation of amplifiers.
Definition: Amplifier.cc:267
Builder()=default
Construct a Builder with default values for all fields.