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
InputArchive.cc
Go to the documentation of this file.
1// -*- lsst-c++ -*-
2
3#include "boost/format.hpp"
4
10#include "lsst/afw/fits.h"
11
12namespace lsst {
13namespace afw {
14namespace table {
15namespace io {
16
17namespace {
18
19ArchiveIndexSchema const& indexKeys = ArchiveIndexSchema::get();
20
21// Functor to sort records by ID and then by catPersistable
22struct IndexSortCompare {
23 bool operator()(BaseRecord const& a, BaseRecord const& b) const {
24 if (a.get(indexKeys.id) < b.get(indexKeys.id)) {
25 return true;
26 }
27 if (a.get(indexKeys.id) == b.get(indexKeys.id)) {
28 return a.get(indexKeys.catPersistable) < b.get(indexKeys.catPersistable);
29 }
30 return false;
31 }
32};
33
34} // namespace
35
36// ----- InputArchive::Impl ---------------------------------------------------------------------------------
37
39public:
42 if (id == 0) return empty;
44 if (r.second) {
45 // insertion successful means we haven't reassembled this object yet; do that now.
46 CatalogVector factoryArgs;
47 // iterate over records in index with this ID; we know they're sorted by ID and then
48 // by catPersistable, so we can just append to factoryArgs.
51 for (BaseCatalog::iterator indexIter = _index.find(id, indexKeys.id);
52 indexIter != _index.end() && indexIter->get(indexKeys.id) == id; ++indexIter) {
53 if (name.empty()) {
54 name = indexIter->get(indexKeys.name);
55 } else if (name != indexIter->get(indexKeys.name)) {
56 throw LSST_EXCEPT(
58 (boost::format("Inconsistent name in index for ID %d; got '%s', expected '%s'") %
59 indexIter->get(indexKeys.id) % indexIter->get(indexKeys.name) % name)
60 .str());
61 }
62 if (module.empty()) {
63 module = indexIter->get(indexKeys.module);
64 } else if (module != indexIter->get(indexKeys.module)) {
65 throw LSST_EXCEPT(
68 "Inconsistent module in index for ID %d; got '%s', expected '%s'") %
69 indexIter->get(indexKeys.id) % indexIter->get(indexKeys.module) % module)
70 .str());
71 }
72 int catArchive = indexIter->get(indexKeys.catArchive);
73 if (catArchive == ArchiveIndexSchema::NO_CATALOGS_SAVED) {
74 break; // object was written with saveEmpty, and hence no catalogs.
75 }
76 std::size_t catN = catArchive - 1;
77 if (catN >= _catalogs.size()) {
78 throw LSST_EXCEPT(
81 "Invalid catalog number in index for ID %d; got '%d', max is '%d'") %
82 indexIter->get(indexKeys.id) % catN % _catalogs.size())
83 .str());
84 }
85 BaseCatalog& fullCatalog = _catalogs[catN];
86 std::size_t i1 = indexIter->get(indexKeys.row0);
87 std::size_t i2 = i1 + indexIter->get(indexKeys.nRows);
88 if (i2 > fullCatalog.size()) {
90 (boost::format("Index and data catalogs do not agree for ID %d; "
91 "catalog %d has %d rows, not %d") %
92 indexIter->get(indexKeys.id) % indexIter->get(indexKeys.catArchive) %
93 fullCatalog.size() % i2)
94 .str());
95 }
96 factoryArgs.push_back(BaseCatalog(fullCatalog.getTable(), fullCatalog.begin() + i1,
97 fullCatalog.begin() + i2));
98 }
99 try {
101 r.first->second = factory.read(self, factoryArgs);
102 } catch (pex::exceptions::Exception& err) {
103 LSST_EXCEPT_ADD(err,
104 (boost::format("loading object with id=%d, name='%s'") % id % name).str());
105 throw;
106 }
107 // If we're loading the object for the first time, and we've failed, we should have already
108 // thrown an exception, and we assert that here.
109 assert(r.first->second);
110 } else if (!r.first->second) {
111 // If we'd already tried and failed to load this object before - but we'd caught the exception
112 // previously (because the calling code didn't consider that to be a fatal error) - we'll
113 // just throw an exception again. While we can't know exactly what was thrown before,
114 // it's most likely it was a NotFoundError because a needed extension package was not setup.
115 // And conveniently it's appropriate to throw that here too, since now the problem is that
116 // the object should have been loaded into the cache and it wasn't found there.
118 (boost::format("Not trying to reload object with id=%d; a previous attempt to "
119 "load it already failed.") %
120 id)
121 .str());
122 }
123 return r.first->second;
124 }
125
126 Map const& getAll(InputArchive const& self) {
127 int id = 0;
128 for (BaseCatalog::iterator indexIter = _index.begin(); indexIter != _index.end(); ++indexIter) {
129 if (indexIter->get(indexKeys.id) != id) {
130 id = indexIter->get(indexKeys.id);
131 get(id, self);
132 }
133 }
134 return _map;
135 }
136
138
139 Impl(BaseCatalog const& index, CatalogVector const& catalogs) : _index(index), _catalogs(catalogs) {
140 if (index.getSchema() != indexKeys.schema) {
141 throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Incorrect schema for index catalog");
142 }
144 _index.sort(IndexSortCompare());
145 }
146
147 // No copying
148 Impl(const Impl&) = delete;
149 Impl& operator=(const Impl&) = delete;
150
151 // No moving
152 Impl(Impl&&) = delete;
153 Impl& operator=(Impl&&) = delete;
154
158};
159
160// ----- InputArchive ---------------------------------------------------------------------------------------
161
163
165
167 : _impl(new Impl(index, catalogs)) {}
168
169InputArchive::InputArchive(InputArchive const& other) = default;
170// Delegate to copy constructor for backwards compatibility
172
173InputArchive& InputArchive::operator=(InputArchive const& other) = default;
174// Delegate to copy assignment for backwards compatibility
175InputArchive& InputArchive::operator=(InputArchive&& other) { return *this = other; }
176
178
179std::shared_ptr<Persistable> InputArchive::get(int id) const { return _impl->get(id, *this); }
180
181InputArchive::Map const& InputArchive::getAll() const { return _impl->getAll(*this); }
182
184 BaseCatalog index = BaseCatalog::readFits(fitsfile);
185 std::shared_ptr<daf::base::PropertyList> metadata = index.getTable()->popMetadata();
186 assert(metadata); // BaseCatalog::readFits should always read metadata, even if there's nothing there
187 if (metadata->get<std::string>("EXTTYPE") != "ARCHIVE_INDEX") {
188 throw LSST_FITS_EXCEPT(fits::FitsError, fitsfile,
189 boost::format("Wrong value for archive index EXTTYPE: '%s'") %
190 metadata->get<std::string>("EXTTYPE"));
191 }
192 int nCatalogs = metadata->get<int>("AR_NCAT");
193 CatalogVector catalogs;
194 catalogs.reserve(nCatalogs);
195 for (int n = 1; n < nCatalogs; ++n) {
196 fitsfile.setHdu(1, true); // increment HDU by one
197 catalogs.push_back(BaseCatalog::readFits(fitsfile));
198 metadata = catalogs.back().getTable()->popMetadata();
199 if (metadata->get<std::string>("EXTTYPE") != "ARCHIVE_DATA") {
200 throw LSST_FITS_EXCEPT(fits::FitsError, fitsfile,
201 boost::format("Wrong value for archive data EXTTYPE: '%s'") %
202 metadata->get<std::string>("EXTTYPE"));
203 }
204 if (metadata->get<int>("AR_CATN") != n) {
205 throw LSST_FITS_EXCEPT(
206 fits::FitsError, fitsfile,
207 boost::format("Incorrect order for archive catalogs: AR_CATN=%d found at position %d") %
208 metadata->get<int>("AR_CATN") % n);
209 }
210 }
211 std::shared_ptr<Impl> impl(new Impl(index, catalogs));
212 return InputArchive(impl);
213}
214} // namespace io
215} // namespace table
216} // namespace afw
217} // namespace lsst
table::Key< std::string > name
Definition: Amplifier.cc:116
#define LSST_EXCEPT_ADD(e, m)
Add the current location and a message to an existing exception before rethrowing it.
Definition: Exception.h:54
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
table::Key< int > b
table::Key< int > a
table::Schema schema
Definition: python.h:134
An exception thrown when problems are found when reading or writing FITS files.
Definition: fits.h:36
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Definition: fits.h:297
void setHdu(int hdu, bool relative=false)
Set the current HDU.
Definition: fits.cc:513
Iterator class for CatalogT.
Definition: Catalog.h:40
static CatalogT readFits(std::string const &filename, int hdu=fits::DEFAULT_HDU, int flags=0)
Read a FITS binary table from a regular file.
Definition: Catalog.h:348
size_type size() const
Return the number of elements in the catalog.
Definition: Catalog.h:413
iterator find(typename Field< T >::Value const &value, Key< T > const &key)
Return an iterator to the record with the given value.
Definition: Catalog.h:763
iterator begin()
Iterator access.
Definition: Catalog.h:401
void sort(Key< T > const &key)
Sort the catalog in-place by the field with the given key.
Definition: Catalog.h:756
std::shared_ptr< Table > getTable() const
Return the table associated with the catalog.
Definition: Catalog.h:115
Schema getSchema() const
Return the schema associated with the catalog's table.
Definition: Catalog.h:118
A vector of catalogs used by Persistable.
Definition: CatalogVector.h:29
Impl & operator=(const Impl &)=delete
Impl(BaseCatalog const &index, CatalogVector const &catalogs)
std::shared_ptr< Persistable > get(int id, InputArchive const &self)
Definition: InputArchive.cc:40
Map const & getAll(InputArchive const &self)
A multi-catalog archive object used to load table::io::Persistable objects.
Definition: InputArchive.h:31
static InputArchive readFits(fits::Fits &fitsfile)
Read an object from an already open FITS object.
InputArchive & operator=(InputArchive const &other)
Assignment. Does not deep-copy loaded Persistables.
Map const & getAll() const
Load and return all objects in the archive.
std::shared_ptr< Persistable > get(int id) const
Load the Persistable with the given ID and return it.
InputArchive()
Construct an empty InputArchive that contains no objects.
An exception thrown when an InputArchive's contents do not make sense.
Definition: Persistable.h:39
A base class for factory classes used to reconstruct objects from records.
Definition: Persistable.h:228
virtual std::shared_ptr< Persistable > read(InputArchive const &archive, CatalogVector const &catalogs) const =0
Construct a new object from the given InputArchive and vector of catalogs.
static PersistableFactory const & lookup(std::string const &name, std::string const &module="")
Return the factory that has been registered with the given name.
Definition: Persistable.cc:76
Provides consistent interface for LSST exceptions.
Definition: Exception.h:107
Reports attempts to access elements using an invalid key.
Definition: Runtime.h:151
Reports errors that are due to events beyond the control of the program.
Definition: Runtime.h:104
#define LSST_FITS_EXCEPT(type, fitsObj,...)
A FITS-related replacement for LSST_EXCEPT that takes an additional Fits object and uses makeErrorMes...
Definition: fits.h:105
T get(T... args)
T insert(T... args)
T make_pair(T... args)
CatalogT< BaseRecord > BaseCatalog
Definition: fwd.h:72
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174
A base class for image defects.
T push_back(T... args)
T reserve(T... args)
T size(T... args)
Schema for the index catalog that specifies where objects are stored in the data catalogs.
static constexpr int const NO_CATALOGS_SAVED
Special value used for catArchive, catPersistable, and row0 when an object with no state is saved.
static ArchiveIndexSchema const & get()
Return the singleton instance.