LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
FilterLabel.cc
Go to the documentation of this file.
1 /*
2  * This file is part of afw.
3  *
4  * Developed for the LSST Data Management System.
5  * This product includes software developed by the LSST Project
6  * (https://www.lsst.org).
7  * See the COPYRIGHT file at the top-level directory of this distribution
8  * for details of code ownership.
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program. If not, see <https://www.gnu.org/licenses/>.
22  */
23 
24 #include <memory>
25 #include <regex>
26 
27 #include "lsst/utils/hashCombine.h"
28 #include "lsst/pex/exceptions.h"
31 #include "lsst/afw/table/Flag.h"
33 #include "lsst/afw/table/Schema.h"
37 #include "lsst/afw/table/io/Persistable.cc" // Needed for PersistableFacade::dynamicCast
38 
39 using namespace std::string_literals;
40 
41 namespace lsst {
42 namespace afw {
43 namespace image {
44 
46  static std::regex const unsafeCharacters("\\W"s);
47  return std::regex_replace(filterLabel, unsafeCharacters, "_"s);
48 }
49 
50 namespace impl {
51 // Hack to allow unit tests to test states that, while legal, are
52 // not produced by (and should not be required of) standard factories.
53 FilterLabel makeTestFilterLabel(bool hasBand, std::string const &band, bool hasPhysical,
54  std::string const &physical) {
55  // private constructor accessible via friend
56  return FilterLabel(hasBand, band, hasPhysical, physical);
57 }
58 } // namespace impl
59 
60 FilterLabel::FilterLabel(bool hasBand, std::string const &band, bool hasPhysical, std::string const &physical)
61  : _hasBand(hasBand), _hasPhysical(hasPhysical), _band(band), _physical(physical) {
62  // Guard against changes to factory methods or pybind11 keyword constructor
63  if (!hasBand && !hasPhysical) {
64  throw LSST_EXCEPT(pex::exceptions::LogicError, "FilterLabel must have at least one label.");
65  }
66 }
67 
69  return FilterLabel(true, band, true, physical);
70 }
71 
72 FilterLabel FilterLabel::fromBand(std::string const &band) { return FilterLabel(true, band, false, ""s); }
73 
75  return FilterLabel(false, ""s, true, physical);
76 }
77 
78 // defaults give the right behavior with bool-and-string implementation
79 FilterLabel::FilterLabel(FilterLabel const &) = default;
80 FilterLabel::FilterLabel(FilterLabel &&) noexcept = default;
81 FilterLabel &FilterLabel::operator=(FilterLabel const &) = default;
82 FilterLabel &FilterLabel::operator=(FilterLabel &&) noexcept = default;
83 FilterLabel::~FilterLabel() noexcept = default;
84 
85 bool FilterLabel::hasBandLabel() const noexcept { return _hasBand; }
86 
88  // In no implementation I can think of will hasBandLabel() be an expensive test.
89  if (hasBandLabel()) {
90  return _band;
91  } else {
92  throw LSST_EXCEPT(pex::exceptions::LogicError, toString() + " has no band."s);
93  }
94 }
95 
96 bool FilterLabel::hasPhysicalLabel() const noexcept { return _hasPhysical; }
97 
99  // In no implementation I can think of will hasBandLabel() be an expensive test.
100  if (hasPhysicalLabel()) {
101  return _physical;
102  } else {
103  throw LSST_EXCEPT(pex::exceptions::LogicError, toString() + " has no physical filter."s);
104  }
105 }
106 
107 bool FilterLabel::operator==(FilterLabel const &rhs) const noexcept {
108  // Do not compare name unless _hasName for both
109  if (_hasBand != rhs._hasBand) {
110  return false;
111  }
112  if (_hasBand && _band != rhs._band) {
113  return false;
114  }
115  if (_hasPhysical != rhs._hasPhysical) {
116  return false;
117  }
118  if (_hasPhysical && _physical != rhs._physical) {
119  return false;
120  }
121  return true;
122 }
123 
124 // Storable support
125 
127  // Do not count _name unless _hasName
128  // (_has=false, _name="A") and (_has=false, _name="B") compare equal, so must have same hash
129  return utils::hashCombine(42, _hasBand, _hasBand ? _band : ""s, _hasPhysical,
130  _hasPhysical ? _physical : ""s);
131 }
132 
133 /* The implementation is biased toward Python in its format, but I expect
134  * the C++ calls to mostly be used for debugging rather than presentation.
135  * This class is also too simple to need "long" and "short" string forms.
136  */
138  std::string buffer("FilterLabel(");
139  bool comma = false;
140 
141  if (hasBandLabel()) {
142  if (comma) buffer += ", "s;
143  buffer += "band"s + "=\""s + getBandLabel() + "\""s;
144  comma = true;
145  }
146  if (hasPhysicalLabel()) {
147  if (comma) buffer += ", "s;
148  buffer += "physical"s + "=\""s + getPhysicalLabel() + "\""s;
149  comma = true;
150  }
151  buffer += ")"s;
152 
153  return buffer;
154 }
155 
157  return std::make_shared<FilterLabel>(*this);
158 }
159 
160 // Persistable support
161 
162 namespace {
163 
164 /* Abstract the representation of an optional string so that it's easy to
165  * add/remove filter names later. The choice of pair as the key type was
166  * dictated by the implementation of FilterLabel, and may be changed if
167  * FilterLabel's internal representation changes. The persisted form
168  * cannot be changed without breaking old files.
169  */
170 class OptionalString : public table::FunctorKey<std::pair<bool, std::string>> {
171 public:
172  static OptionalString addFields(table::Schema &schema, std::string const &name, std::string const &doc,
173  int length) {
174  table::Key<table::Flag> existsKey =
175  schema.addField<table::Flag>(schema.join(name, "exists"), "Existence flag for "s + name);
176  table::Key<std::string> valueKey = schema.addField<std::string>(name, doc, "", length);
177  return OptionalString(existsKey, valueKey);
178  }
179 
180  OptionalString() noexcept : _exists(), _value() {}
181  OptionalString(table::Key<table::Flag> const &exists, table::Key<std::string> const &value) noexcept
182  : _exists(exists), _value(value) {}
183 
184  std::pair<bool, std::string> get(table::BaseRecord const &record) const override {
185  // Suppress any weird values if they don't matter
186  bool exists = record.get(_exists);
187  return std::make_pair(exists, exists ? record.get(_value) : ""s);
188  }
189 
190  void set(table::BaseRecord &record, std::pair<bool, std::string> const &value) const override {
191  // Suppress any weird values if they don't matter
192  record.set(_exists, value.first);
193  record.set(_value, value.first ? value.second : ""s);
194  }
195 
196  bool operator==(OptionalString const &other) const noexcept {
197  return _exists == other._exists && _value == other._value;
198  }
199  bool operator!=(OptionalString const &other) const noexcept { return !(*this == other); }
200 
201  bool isValid() const noexcept { return _exists.isValid() && _value.isValid(); }
202 
203  table::Key<table::Flag> getExists() const noexcept { return _exists; }
204  table::Key<std::string> getValue() const noexcept { return _value; }
205 
206 private:
207  table::Key<table::Flag> _exists;
208  table::Key<std::string> _value;
209 };
210 
211 struct PersistenceHelper {
212  table::Schema schema;
213  OptionalString band;
214  OptionalString physical;
215 
216  static PersistenceHelper const &get() {
217  static PersistenceHelper const instance;
218  return instance;
219  }
220 
221 private:
222  PersistenceHelper()
223  : schema(),
224  band(OptionalString::addFields(schema, "band", "Name of the band.", 32)),
225  physical(OptionalString::addFields(schema, "physical", "Name of the physical filter.", 32)) {}
226 };
227 
228 std::string _getPersistenceName() noexcept { return "FilterLabel"s; }
229 
230 } // namespace
231 
232 std::string FilterLabel::getPersistenceName() const noexcept { return _getPersistenceName(); }
233 std::string FilterLabel::getPythonModule() const noexcept { return "lsst.afw.image"s; }
234 
236  PersistenceHelper const &keys = PersistenceHelper::get();
237  table::BaseCatalog catalog = handle.makeCatalog(keys.schema);
238  std::shared_ptr<table::BaseRecord> record = catalog.addNew();
239 
240  record->set(keys.band, std::make_pair(_hasBand, _band));
241  record->set(keys.physical, std::make_pair(_hasPhysical, _physical));
242  handle.saveCatalog(catalog);
243 }
244 
246 public:
248  table::io::CatalogVector const &catalogs) const override {
249  auto const &keys = PersistenceHelper::get();
250  LSST_ARCHIVE_ASSERT(catalogs.size() == 1u);
251  table::BaseRecord const &record = catalogs.front().front();
252  LSST_ARCHIVE_ASSERT(record.getSchema() == keys.schema);
253 
254  // Use explicit new operator to access private constructor
256  new FilterLabel(record.get(keys.band.getExists()), record.get(keys.band.getValue()),
257  record.get(keys.physical.getExists()), record.get(keys.physical.getValue())));
258  }
259 
260  Factory(std::string const &name) : table::io::PersistableFactory(name) {}
261 };
262 
263 // Adds FilterLabel::factory to a global registry.
264 FilterLabel::Factory FilterLabel::factory(_getPersistenceName());
265 
266 } // namespace image
267 
270 
271 } // namespace afw
272 } // namespace lsst
table::Key< std::string > name
Definition: Amplifier.cc:116
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
table::Schema schema
Definition: FilterLabel.cc:212
OptionalString physical
Definition: FilterLabel.cc:214
OptionalString band
Definition: FilterLabel.cc:213
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
Definition: Persistable.h:48
Factory(std::string const &name)
Definition: FilterLabel.cc:260
std::shared_ptr< table::io::Persistable > read(table::io::InputArchive const &archive, table::io::CatalogVector const &catalogs) const override
Construct a new object from the given InputArchive and vector of catalogs.
Definition: FilterLabel.cc:247
A group of labels for a filter in an exposure or coadd.
Definition: FilterLabel.h:58
std::string getBandLabel() const
Return the band label.
Definition: FilterLabel.cc:87
std::string getPersistenceName() const noexcept override
Return the unique name used to persist this object and look up its factory.
Definition: FilterLabel.cc:232
bool hasBandLabel() const noexcept
Return whether the filter label names a band.
Definition: FilterLabel.cc:85
static FilterLabel fromBand(std::string const &band)
Construct a FilterLabel from specific inputs.
Definition: FilterLabel.cc:72
std::string getPythonModule() const noexcept override
Return the fully-qualified Python module that should be imported to guarantee that its factory is reg...
Definition: FilterLabel.cc:233
bool hasPhysicalLabel() const noexcept
Return whether the filter label names a physical filter.
Definition: FilterLabel.cc:96
void write(table::io::OutputArchiveHandle &handle) const override
Write the object to one or more catalogs.
Definition: FilterLabel.cc:235
std::string toString() const override
Return a string representation of this object.
Definition: FilterLabel.cc:137
std::size_t hash_value() const noexcept override
Return a hash of this object.
Definition: FilterLabel.cc:126
std::shared_ptr< Storable > cloneStorable() const override
Create a new object that is a copy of this one.
Definition: FilterLabel.cc:156
std::string getPhysicalLabel() const
Return the physical filter label.
Definition: FilterLabel.cc:98
bool operator==(FilterLabel const &rhs) const noexcept
Filter labels compare equal if their components are equal.
Definition: FilterLabel.cc:107
static FilterLabel fromBandPhysical(std::string const &band, std::string const &physical)
Construct a FilterLabel from specific inputs.
Definition: FilterLabel.cc:68
FilterLabel(FilterLabel const &)
static FilterLabel fromPhysical(std::string const &physical)
Construct a FilterLabel from specific inputs.
Definition: FilterLabel.cc:74
Base class for all records.
Definition: BaseRecord.h:31
Schema getSchema() const
Return the Schema that holds this record's fields and keys.
Definition: BaseRecord.h:80
Field< T >::Value get(Key< T > const &key) const
Return the value of a field for the given key.
Definition: BaseRecord.h:151
std::shared_ptr< RecordT > addNew()
Create a new record, add it to the end of the catalog, and return a pointer to it.
Definition: Catalog.h:490
Convenience base class that combines the OutputFunctorKey and InputFunctorKey.
Definition: FunctorKey.h:74
A class used as a handle to a particular field in a table.
Definition: Key.h:53
Defines the fields and offsets for a table.
Definition: Schema.h:51
A vector of catalogs used by Persistable.
Definition: CatalogVector.h:29
A multi-catalog archive object used to load table::io::Persistable objects.
Definition: InputArchive.h:31
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.
static std::shared_ptr< T > dynamicCast(std::shared_ptr< Persistable > const &ptr)
Dynamically cast a shared_ptr.
Definition: Persistable.cc:18
A base class for factory classes used to reconstruct objects from records.
Definition: Persistable.h:228
PersistableFactory(std::string const &name)
Constructor for the factory.
Definition: Persistable.cc:74
Reports errors in the logical structure of the program.
Definition: Runtime.h:46
daf::base::PropertySet * set
Definition: fits.cc:912
bool isValid
Definition: fits.cc:399
T front(T... args)
T make_pair(T... args)
FilterLabel makeTestFilterLabel(bool hasBand, std::string const &band, bool hasPhysical, std::string const &physical)
Definition: FilterLabel.cc:53
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
std::string getDatabaseFilterLabel(std::string const &filterLabel)
Remap special characters, etc.
Definition: FilterLabel.cc:45
bool operator==(FilterProperty const &rhs) const noexcept
Return true iff two FilterProperties are identical.
bool operator!=(FilterProperty const &rhs) const noexcept
Return true iff rhs != this.
Definition: Filter.h:100
std::size_t hashCombine(std::size_t seed) noexcept
Combine hashes.
Definition: hashCombine.h:35
A base class for image defects.
T regex_replace(T... args)
T size(T... args)