LSST Applications g02d81e74bb+86cf3d8bc9,g180d380827+7a4e862ed4,g2079a07aa2+86d27d4dc4,g2305ad1205+e1ca1c66fa,g29320951ab+012e1474a1,g295015adf3+341ea1ce94,g2bbee38e9b+0e5473021a,g337abbeb29+0e5473021a,g33d1c0ed96+0e5473021a,g3a166c0a6a+0e5473021a,g3ddfee87b4+c429d67c83,g48712c4677+f88676dd22,g487adcacf7+27e1e21933,g50ff169b8f+96c6868917,g52b1c1532d+585e252eca,g591dd9f2cf+b41db86c35,g5a732f18d5+53520f316c,g64a986408d+86cf3d8bc9,g858d7b2824+86cf3d8bc9,g8a8a8dda67+585e252eca,g99cad8db69+84912a7fdc,g9ddcbc5298+9a081db1e4,ga1e77700b3+15fc3df1f7,ga8c6da7877+a2b54eae19,gb0e22166c9+60f28cb32d,gba4ed39666+c2a2e4ac27,gbb8dafda3b+6681f309db,gc120e1dc64+f0fcc2f6d8,gc28159a63d+0e5473021a,gcf0d15dbbd+c429d67c83,gdaeeff99f8+f9a426f77a,ge6526c86ff+0433e6603d,ge79ae78c31+0e5473021a,gee10cc3b42+585e252eca,gff1a9f87cc+86cf3d8bc9,w.2024.17
LSST Data Management Base Package
Loading...
Searching...
No Matches
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
28#include "lsst/pex/exceptions.h"
31#include "lsst/afw/table/Flag.h"
37#include "lsst/afw/table/io/Persistable.cc" // Needed for PersistableFacade::dynamicCast
38
39using namespace std::string_literals;
40
41namespace lsst {
42namespace afw {
43namespace image {
44
46 static std::regex const unsafeCharacters("\\W"s);
47 return std::regex_replace(filterLabel, unsafeCharacters, "_"s);
48}
49
50namespace 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.
53FilterLabel 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
60FilterLabel::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
71
72FilterLabel FilterLabel::fromBand(std::string const &band) { return FilterLabel(true, band, false, ""s); }
73
77
78// defaults give the right behavior with bool-and-string implementation
79FilterLabel::FilterLabel(FilterLabel const &) = default;
80FilterLabel::FilterLabel(FilterLabel &&) noexcept = default;
81FilterLabel &FilterLabel::operator=(FilterLabel const &) = default;
82FilterLabel &FilterLabel::operator=(FilterLabel &&) noexcept = default;
83FilterLabel::~FilterLabel() noexcept = default;
84
85bool 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
96bool 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
107bool 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
162namespace {
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 */
170class OptionalString : public table::FunctorKey<std::pair<bool, std::string>> {
171public:
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
206private:
207 table::Key<table::Flag> _exists;
208 table::Key<std::string> _value;
209};
210
211struct 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
221private:
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
228std::string _getPersistenceName() noexcept { return "FilterLabel"s; }
229
230} // namespace
231
232std::string FilterLabel::getPersistenceName() const noexcept { return _getPersistenceName(); }
233std::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
246public:
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.
264FilterLabel::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
OptionalString physical
OptionalString band
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
Definition Persistable.h:48
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.
A group of labels for a filter in an exposure or coadd.
Definition FilterLabel.h:58
std::string getBandLabel() const
Return the band label.
std::string getPersistenceName() const noexcept override
Return the unique name used to persist this object and look up its factory.
bool hasBandLabel() const noexcept
Return whether the filter label names a band.
static FilterLabel fromBand(std::string const &band)
Construct a FilterLabel from specific inputs.
std::string getPythonModule() const noexcept override
Return the fully-qualified Python module that should be imported to guarantee that its factory is reg...
bool hasPhysicalLabel() const noexcept
Return whether the filter label names a physical filter.
void write(table::io::OutputArchiveHandle &handle) const override
Write the object to one or more catalogs.
std::string toString() const override
Return a string representation of this object.
std::size_t hash_value() const noexcept override
Return a hash of this object.
std::shared_ptr< Storable > cloneStorable() const override
Create a new object that is a copy of this one.
std::string getPhysicalLabel() const
Return the physical filter label.
bool operator==(FilterLabel const &rhs) const noexcept
Filter labels compare equal if their components are equal.
static FilterLabel fromBandPhysical(std::string const &band, std::string const &physical)
Construct a FilterLabel from specific inputs.
FilterLabel(FilterLabel const &)
static FilterLabel fromPhysical(std::string const &physical)
Construct a FilterLabel from specific inputs.
Tag types used to declare specialized field types.
Definition misc.h:31
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
Convenience base class that combines the OutputFunctorKey and InputFunctorKey.
Definition FunctorKey.h:74
Defines the fields and offsets for a table.
Definition Schema.h:51
A vector of catalogs used by Persistable.
A multi-catalog archive object used to load table::io::Persistable objects.
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.
A base class for factory classes used to reconstruct objects from records.
Reports errors in the logical structure of the program.
Definition Runtime.h:46
daf::base::PropertySet * set
Definition fits.cc:931
bool isValid
Definition fits.cc:404
T make_pair(T... args)
FilterLabel makeTestFilterLabel(bool hasBand, std::string const &band, bool hasPhysical, std::string const &physical)
std::string getDatabaseFilterLabel(std::string const &filterLabel)
Remap special characters, etc.
std::size_t hashCombine(std::size_t seed) noexcept
Combine hashes.
Definition hashCombine.h:35
T operator!=(T... args)
T regex_replace(T... args)