lsst.afw  20.0.0-17-g80088cf60+109ac6652c
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 
64  return FilterLabel(true, band, true, physical);
65 }
66 
67 FilterLabel FilterLabel::fromBand(std::string const &band) { return FilterLabel(true, band, false, ""s); }
68 
70  return FilterLabel(false, ""s, true, physical);
71 }
72 
73 // defaults give the right behavior with bool-and-string implementation
74 FilterLabel::FilterLabel(FilterLabel const &) = default;
75 FilterLabel::FilterLabel(FilterLabel &&) noexcept = default;
76 FilterLabel &FilterLabel::operator=(FilterLabel const &) = default;
77 FilterLabel &FilterLabel::operator=(FilterLabel &&) noexcept = default;
78 FilterLabel::~FilterLabel() noexcept = default;
79 
80 bool FilterLabel::hasBandLabel() const noexcept { return _hasBand; }
81 
83  // In no implementation I can think of will hasBandLabel() be an expensive test.
84  if (hasBandLabel()) {
85  return _band;
86  } else {
87  throw LSST_EXCEPT(pex::exceptions::LogicError, toString() + " has no band."s);
88  }
89 }
90 
91 bool FilterLabel::hasPhysicalLabel() const noexcept { return _hasPhysical; }
92 
94  // In no implementation I can think of will hasBandLabel() be an expensive test.
95  if (hasPhysicalLabel()) {
96  return _physical;
97  } else {
98  throw LSST_EXCEPT(pex::exceptions::LogicError, toString() + " has no physical filter."s);
99  }
100 }
101 
102 bool FilterLabel::operator==(FilterLabel const &rhs) const noexcept {
103  // Do not compare name unless _hasName for both
104  if (_hasBand != rhs._hasBand) {
105  return false;
106  }
107  if (_hasBand && _band != rhs._band) {
108  return false;
109  }
110  if (_hasPhysical != rhs._hasPhysical) {
111  return false;
112  }
113  if (_hasPhysical && _physical != rhs._physical) {
114  return false;
115  }
116  return true;
117 }
118 
119 // Storable support
120 
122  // Do not count _name unless _hasName
123  // (_has=false, _name="A") and (_has=false, _name="B") compare equal, so must have same hash
124  return utils::hashCombine(42, _hasBand, _hasBand ? _band : ""s, _hasPhysical,
125  _hasPhysical ? _physical : ""s);
126 }
127 
128 /* The implementation is biased toward Python in its format, but I expect
129  * the C++ calls to mostly be used for debugging rather than presentation.
130  * This class is also too simple to need "long" and "short" string forms.
131  */
133  std::string buffer("FilterLabel(");
134  bool comma = false;
135 
136  if (hasBandLabel()) {
137  if (comma) buffer += ", "s;
138  buffer += "band"s + "=\""s + getBandLabel() + "\""s;
139  comma = true;
140  }
141  if (hasPhysicalLabel()) {
142  if (comma) buffer += ", "s;
143  buffer += "physical"s + "=\""s + getPhysicalLabel() + "\""s;
144  comma = true;
145  }
146  buffer += ")"s;
147 
148  return buffer;
149 }
150 
152  return std::make_shared<FilterLabel>(*this);
153 }
154 
155 // Persistable support
156 
157 namespace {
158 
159 /* Abstract the representation of an optional string so that it's easy to
160  * add/remove filter names later. The choice of pair as the key type was
161  * dictated by the implementation of FilterLabel, and may be changed if
162  * FilterLabel's internal representation changes. The persisted form
163  * cannot be changed without breaking old files.
164  */
165 class OptionalString : public table::FunctorKey<std::pair<bool, std::string>> {
166 public:
167  static OptionalString addFields(table::Schema &schema, std::string const &name, std::string const &doc,
168  int length) {
169  table::Key<table::Flag> existsKey =
170  schema.addField<table::Flag>(schema.join(name, "exists"), "Existence flag for "s + name);
171  table::Key<std::string> valueKey = schema.addField<std::string>(name, doc, "", length);
172  return OptionalString(existsKey, valueKey);
173  }
174 
175  OptionalString() noexcept : _exists(), _value() {}
176  OptionalString(table::Key<table::Flag> const &exists, table::Key<std::string> const &value) noexcept
177  : _exists(exists), _value(value) {}
178 
179  std::pair<bool, std::string> get(table::BaseRecord const &record) const override {
180  // Suppress any weird values if they don't matter
181  bool exists = record.get(_exists);
182  return std::make_pair(exists, exists ? record.get(_value) : ""s);
183  }
184 
185  void set(table::BaseRecord &record, std::pair<bool, std::string> const &value) const override {
186  // Suppress any weird values if they don't matter
187  record.set(_exists, value.first);
188  record.set(_value, value.first ? value.second : ""s);
189  }
190 
191  bool operator==(OptionalString const &other) const noexcept {
192  return _exists == other._exists && _value == other._value;
193  }
194  bool operator!=(OptionalString const &other) const noexcept { return !(*this == other); }
195 
196  bool isValid() const noexcept { return _exists.isValid() && _value.isValid(); }
197 
198  table::Key<table::Flag> getExists() const noexcept { return _exists; }
199  table::Key<std::string> getValue() const noexcept { return _value; }
200 
201 private:
202  table::Key<table::Flag> _exists;
203  table::Key<std::string> _value;
204 };
205 
206 struct PersistenceHelper {
207  table::Schema schema;
208  OptionalString band;
209  OptionalString physical;
210 
211  static PersistenceHelper const &get() {
212  static PersistenceHelper const instance;
213  return instance;
214  }
215 
216 private:
217  PersistenceHelper()
218  : schema(),
219  band(OptionalString::addFields(schema, "band", "Name of the band.", 32)),
220  physical(OptionalString::addFields(schema, "physical", "Name of the physical filter.", 32)) {}
221 };
222 
223 std::string _getPersistenceName() noexcept { return "FilterLabel"s; }
224 
225 } // namespace
226 
227 std::string FilterLabel::getPersistenceName() const noexcept { return _getPersistenceName(); }
228 std::string FilterLabel::getPythonModule() const noexcept { return "lsst.afw.image"s; }
229 
231  PersistenceHelper const &keys = PersistenceHelper::get();
232  table::BaseCatalog catalog = handle.makeCatalog(keys.schema);
233  std::shared_ptr<table::BaseRecord> record = catalog.addNew();
234 
235  record->set(keys.band, std::make_pair(_hasBand, _band));
236  record->set(keys.physical, std::make_pair(_hasPhysical, _physical));
237  handle.saveCatalog(catalog);
238 }
239 
241 public:
243  table::io::CatalogVector const &catalogs) const override {
244  auto const &keys = PersistenceHelper::get();
245  LSST_ARCHIVE_ASSERT(catalogs.size() == 1u);
246  table::BaseRecord const &record = catalogs.front().front();
247  LSST_ARCHIVE_ASSERT(record.getSchema() == keys.schema);
248 
249  // Use explicit new operator to access private constructor
251  new FilterLabel(record.get(keys.band.getExists()), record.get(keys.band.getValue()),
252  record.get(keys.physical.getExists()), record.get(keys.physical.getValue())));
253  }
254 
255  Factory(std::string const &name) : table::io::PersistableFactory(name) {}
256 };
257 
258 // Adds FilterLabel::factory to a global registry.
259 FilterLabel::Factory FilterLabel::factory(_getPersistenceName());
260 
261 } // namespace image
262 
265 
266 } // namespace afw
267 } // namespace lsst
lsst::afw::image::FilterLabel::hasPhysicalLabel
bool hasPhysicalLabel() const noexcept
Return whether the filter label names a physical filter.
Definition: FilterLabel.cc:91
lsst::afw::image
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
Definition: imageAlgorithm.dox:1
lsst::afw::image::FilterLabel::fromPhysical
static FilterLabel fromPhysical(std::string const &physical)
Construct a FilterLabel from specific inputs.
Definition: FilterLabel.cc:69
LSST_ARCHIVE_ASSERT
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
Definition: Persistable.h:48
std::string
STL class.
std::shared_ptr
STL class.
lsst::afw::image::FilterLabel::write
void write(table::io::OutputArchiveHandle &handle) const override
Write the object to one or more catalogs.
Definition: FilterLabel.cc:230
lsst::afw::table::BaseRecord::get
Field< T >::Value get(Key< T > const &key) const
Return the value of a field for the given key.
Definition: BaseRecord.h:151
std::pair
std::rel_ops::operator!=
T operator!=(T... args)
lsst::afw::table::io::OutputArchiveHandle
An object passed to Persistable::write to allow it to persist itself.
Definition: OutputArchive.h:118
lsst::afw::table::FunctorKey
Convenience base class that combines the OutputFunctorKey and InputFunctorKey.
Definition: FunctorKey.h:74
std::vector::size
T size(T... args)
lsst::afw::table::io::OutputArchiveHandle::saveCatalog
void saveCatalog(BaseCatalog const &catalog)
Save a catalog in the archive.
Definition: OutputArchive.cc:211
lsst::afw::table::io::InputArchive
A multi-catalog archive object used to load table::io::Persistable objects.
Definition: InputArchive.h:31
lsst::afw::image::FilterLabel::Factory::read
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:242
keys
def keys(self)
schema
table::Schema schema
Definition: FilterLabel.cc:207
lsst::afw::table::Schema
Defines the fields and offsets for a table.
Definition: Schema.h:50
CatalogVector.h
lsst::afw::image::FilterLabel::getPhysicalLabel
std::string getPhysicalLabel() const
Return the physical filter label.
Definition: FilterLabel.cc:93
lsst::afw::geom.transform.transformContinued.name
string name
Definition: transformContinued.py:32
std::vector::front
T front(T... args)
hashCombine.h
lsst::afw::image::FilterLabel::getPersistenceName
std::string getPersistenceName() const noexcept override
Return the unique name used to persist this object and look up its factory.
Definition: FilterLabel.cc:227
lsst::afw::table::io::PersistableFactory::PersistableFactory
PersistableFactory(std::string const &name)
Constructor for the factory.
Definition: Persistable.cc:74
lsst::afw::table::io::OutputArchiveHandle::makeCatalog
BaseCatalog makeCatalog(Schema const &schema)
Return a new, empty catalog with the given schema.
Definition: OutputArchive.cc:207
BaseRecord.h
lsst::afw::image::FilterLabel::FilterLabel
FilterLabel(FilterLabel const &)
lsst::afw::image::getDatabaseFilterLabel
std::string getDatabaseFilterLabel(std::string const &filterLabel)
Remap special characters, etc.
Definition: FilterLabel.cc:45
physical
OptionalString physical
Definition: FilterLabel.cc:209
lsst::afw::image::FilterLabel::cloneStorable
std::shared_ptr< Storable > cloneStorable() const override
Create a new object that is a copy of this one.
Definition: FilterLabel.cc:151
FunctorKey.h
set
daf::base::PropertySet * set
Definition: fits.cc:912
other
ItemVariant const * other
Definition: Schema.cc:56
lsst::afw::table::BaseRecord
Base class for all records.
Definition: BaseRecord.h:31
lsst::pex::exceptions::LogicError
lsst::afw::table::io::CatalogVector
A vector of catalogs used by Persistable.
Definition: CatalogVector.h:29
Persistable.cc
lsst::afw::table::Key
A class used as a handle to a particular field in a table.
Definition: fwd.h:45
lsst::afw::table::io::PersistableFactory
A base class for factory classes used to reconstruct objects from records.
Definition: Persistable.h:228
lsst::afw::image::FilterLabel::hasBandLabel
bool hasBandLabel() const noexcept
Return whether the filter label names a band.
Definition: FilterLabel.cc:80
lsst::afw::image::FilterLabel
A group of labels for a filter in an exposure or coadd.
Definition: FilterLabel.h:55
std::regex
lsst
A base class for image defects.
LSST_EXCEPT
#define LSST_EXCEPT(type,...)
exceptions.h
lsst::afw::table::io::PersistableFacade::dynamicCast
static std::shared_ptr< T > dynamicCast(std::shared_ptr< Persistable > const &ptr)
Dynamically cast a shared_ptr.
Definition: Persistable.cc:18
lsst::afw::image::FilterLabel::getPythonModule
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:228
lsst::afw::image::impl::makeTestFilterLabel
FilterLabel makeTestFilterLabel(bool hasBand, std::string const &band, bool hasPhysical, std::string const &physical)
Definition: FilterLabel.cc:53
lsst::afw::image::FilterLabel::fromBandPhysical
static FilterLabel fromBandPhysical(std::string const &band, std::string const &physical)
Construct a FilterLabel from specific inputs.
Definition: FilterLabel.cc:63
lsst::afw::image::FilterLabel::getBandLabel
std::string getBandLabel() const
Return the band label.
Definition: FilterLabel.cc:82
lsst::utils::hashCombine
std::size_t hashCombine(std::size_t seed) noexcept
lsst::afw::image::FilterLabel::hash_value
std::size_t hash_value() const noexcept override
Return a hash of this object.
Definition: FilterLabel.cc:121
isValid
bool isValid
Definition: fits.cc:399
lsst::afw::image::FilterLabel::toString
std::string toString() const override
Return a string representation of this object.
Definition: FilterLabel.cc:132
lsst::afw::image::FilterLabel::Factory
Definition: FilterLabel.cc:240
band
OptionalString band
Definition: FilterLabel.cc:208
lsst::afw::table::BaseRecord::getSchema
Schema getSchema() const
Return the Schema that holds this record's fields and keys.
Definition: BaseRecord.h:80
lsst::afw::image::FilterLabel::fromBand
static FilterLabel fromBand(std::string const &band)
Construct a FilterLabel from specific inputs.
Definition: FilterLabel.cc:67
InputArchive.h
std::size_t
Schema.h
std::make_pair
T make_pair(T... args)
lsst::afw::image::FilterLabel::operator==
bool operator==(FilterLabel const &rhs) const noexcept
Filter labels compare equal if their components are equal.
Definition: FilterLabel.cc:102
lsst::afw::table::CatalogT::addNew
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:485
lsst::afw::image::FilterLabel::Factory::Factory
Factory(std::string const &name)
Definition: FilterLabel.cc:255
length
def length(self)
lsst::afw::table::CatalogT< BaseRecord >
std::regex_replace
T regex_replace(T... args)
OutputArchive.h
FilterLabel.h
Flag.h