LSST Applications  21.0.0+04719a4bac,21.0.0-1-ga51b5d4+f5e6047307,21.0.0-11-g2b59f77+a9c1acf22d,21.0.0-11-ga42c5b2+86977b0b17,21.0.0-12-gf4ce030+76814010d2,21.0.0-13-g1721dae+760e7a6536,21.0.0-13-g3a573fe+768d78a30a,21.0.0-15-g5a7caf0+f21cbc5713,21.0.0-16-g0fb55c1+b60e2d390c,21.0.0-19-g4cded4ca+71a93a33c0,21.0.0-2-g103fe59+bb20972958,21.0.0-2-g45278ab+04719a4bac,21.0.0-2-g5242d73+3ad5d60fb1,21.0.0-2-g7f82c8f+8babb168e8,21.0.0-2-g8f08a60+06509c8b61,21.0.0-2-g8faa9b5+616205b9df,21.0.0-2-ga326454+8babb168e8,21.0.0-2-gde069b7+5e4aea9c2f,21.0.0-2-gecfae73+1d3a86e577,21.0.0-2-gfc62afb+3ad5d60fb1,21.0.0-25-g1d57be3cd+e73869a214,21.0.0-3-g357aad2+ed88757d29,21.0.0-3-g4a4ce7f+3ad5d60fb1,21.0.0-3-g4be5c26+3ad5d60fb1,21.0.0-3-g65f322c+e0b24896a3,21.0.0-3-g7d9da8d+616205b9df,21.0.0-3-ge02ed75+a9c1acf22d,21.0.0-4-g591bb35+a9c1acf22d,21.0.0-4-g65b4814+b60e2d390c,21.0.0-4-gccdca77+0de219a2bc,21.0.0-4-ge8a399c+6c55c39e83,21.0.0-5-gd00fb1e+05fce91b99,21.0.0-6-gc675373+3ad5d60fb1,21.0.0-64-g1122c245+4fb2b8f86e,21.0.0-7-g04766d7+cd19d05db2,21.0.0-7-gdf92d54+04719a4bac,21.0.0-8-g5674e7b+d1bd76f71f,master-gac4afde19b+a9c1acf22d,w.2021.13
LSST Data Management Base Package
Classes | Public Types | Public Member Functions | Static Public Attributes | List of all members
lsst::afw::table::io::FitsSchemaInputMapper Class Reference

A class that describes a mapping from a FITS binary table to an afw::table Schema. More...

#include <FitsSchemaInputMapper.h>

Classes

class  Impl
 

Public Types

typedef FitsSchemaItem Item
 

Public Member Functions

 FitsSchemaInputMapper (daf::base::PropertyList &metadata, bool stripMetadata)
 Construct a mapper from a PropertyList of FITS header values, stripping recognized keys if desired. More...
 
 FitsSchemaInputMapper (FitsSchemaInputMapper const &)
 
 FitsSchemaInputMapper (FitsSchemaInputMapper &&)
 
FitsSchemaInputMapperoperator= (FitsSchemaInputMapper const &)
 
FitsSchemaInputMapperoperator= (FitsSchemaInputMapper &&)
 
 ~FitsSchemaInputMapper ()
 
void setArchive (std::shared_ptr< InputArchive > archive)
 Set the Archive to an externally-provided one, overriding any that may have been read. More...
 
bool readArchive (afw::fits::Fits &fits)
 Set the Archive by reading from the HDU specified by the AR_HDU header entry. More...
 
bool hasArchive () const
 Return true if the mapper has an InputArchive. More...
 
Item const * find (std::string const &ttype) const
 Find an item with the given column name (ttype), returning nullptr if no such column exists. More...
 
Item const * find (int column) const
 Find an item with the given column number, returning nullptr if no such column exists. More...
 
void erase (Item const *item)
 Remove the given item (which should have been retrieved via find()) from the mapping, preventing it from being included in the regular fields added by finalize(). More...
 
void erase (std::string const &ttype)
 Remove the item with the given column name (ttype) from the mapping, preventing it from being included in the regular fields added by finalize(). More...
 
void erase (int column)
 Remove the item at the given column position from the mapping, preventing it from being included in the regular fields added by finalize(). More...
 
void customize (std::unique_ptr< FitsColumnReader > reader)
 Customize a mapping by providing a FitsColumnReader instance that will be invoked by readRecords(). More...
 
Schema finalize ()
 Map any remaining items into regular Schema items, and return the final Schema. More...
 
void readRecord (BaseRecord &record, afw::fits::Fits &fits, std::size_t row)
 Fill a record from a FITS binary table row. More...
 

Static Public Attributes

static std::size_t PREPPED_ROWS_FACTOR = 1 << 15
 When processing each column, divide this number by the record size (in bytes) and ask CFITSIO to read this many that of values from that column in a single call. More...
 

Detailed Description

A class that describes a mapping from a FITS binary table to an afw::table Schema.

A FitsSchemaInputMapper is created every time a FITS binary table is read into an afw::table catalog, allowing limited customization of the mapping between on-disk FITS table columns an in-memory fields by subclasses of BaseTable.

The object is constructed from a daf::base::PropertyList that represents the FITS header, which is used to populate a custom container of FitsSchemaItems. These can then be retrieved by name or column number via the find() methods, allowing the user to create custom readers for columns or groups of columns via addColumnReader(). They can also be removed from the "regular" fields via the erase() method. Those regular fields are filled in by the finalize() method, which automatically generates mappings for any FitsSchemaItems that have not been removed by calls to erase(). Once finalize() has been called, readRecord() may be called repeatedly to read FITS rows into record objects according to the mapping that has been defined.

Definition at line 91 of file FitsSchemaInputMapper.h.

Member Typedef Documentation

◆ Item

Definition at line 93 of file FitsSchemaInputMapper.h.

Constructor & Destructor Documentation

◆ FitsSchemaInputMapper() [1/3]

lsst::afw::table::io::FitsSchemaInputMapper::FitsSchemaInputMapper ( daf::base::PropertyList metadata,
bool  stripMetadata 
)

Construct a mapper from a PropertyList of FITS header values, stripping recognized keys if desired.

Definition at line 100 of file FitsSchemaInputMapper.cc.

101  : _impl(std::make_shared<Impl>()) {
102  // Set the table version. If AFW_TABLE_VERSION tag exists, use that
103  // If not, set to 0 if it has an AFW_TYPE, Schema default otherwise (DM-590)
104  if (!metadata.exists("AFW_TYPE")) {
105  _impl->version = lsst::afw::table::Schema::VERSION;
106  }
107  _impl->version = metadata.get("AFW_TABLE_VERSION", _impl->version);
108  _impl->type = metadata.get("AFW_TYPE", _impl->type);
109  if (stripMetadata) {
110  metadata.remove("AFW_TABLE_VERSION");
111  }
112  if (stripMetadata) {
113  metadata.remove("AFW_TYPE");
114  }
115 
116  // Find a key that indicates an Archive stored on other HDUs
117  _impl->archiveHdu = metadata.get("AR_HDU", -1);
118  if (_impl->archiveHdu > 0) {
119  --_impl->archiveHdu; // AR_HDU is 1-indexed for historical reasons (RFC-304; see Source.cc)
120  if (stripMetadata) {
121  metadata.remove("AR_HDU");
122  }
123  }
124 
125  // Read aliases, stored as header entries with key 'ALIAS'
126  try {
127  std::vector<std::string> rawAliases = metadata.getArray<std::string>("ALIAS");
128  for (std::vector<std::string>::const_iterator i = rawAliases.begin(); i != rawAliases.end(); ++i) {
129  std::size_t pos = i->find_first_of(':');
130  if (pos == std::string::npos) {
131  throw LSST_EXCEPT(afw::fits::FitsError,
132  (boost::format("Malformed alias definition: '%s'") % (*i)).str());
133  }
134  _impl->schema.getAliasMap()->set(i->substr(0, pos), i->substr(pos + 1, std::string::npos));
135  }
136  if (stripMetadata) {
137  metadata.remove("ALIAS");
138  }
139  } catch (pex::exceptions::NotFoundError &) {
140  // if there are no aliases, just move on
141  }
142 
143  if (_impl->version == 0) {
144  // Read slots saved using an old mechanism in as aliases, since the new slot mechanism delegates
145  // slot definition to the AliasMap.
146  static std::array<std::pair<std::string, std::string>, 7> oldSlotKeys = {
147  {std::make_pair("PSF_FLUX", "slot_PsfFlux"), std::make_pair("AP_FLUX", "slot_ApFlux"),
148  std::make_pair("INST_FLUX", "slot_GaussianFlux"),
149  std::make_pair("MODEL_FLUX", "slot_ModelFlux"),
150  std::make_pair("CALIB_FLUX", "slot_CalibFlux"), std::make_pair("CENTROID", "slot_Centroid"),
151  std::make_pair("SHAPE", "slot_Shape")}};
152  for (std::size_t i = 0; i < oldSlotKeys.size(); ++i) {
153  std::string target = metadata.get(oldSlotKeys[i].first + "_SLOT", std::string(""));
154  if (!target.empty()) {
155  _impl->schema.getAliasMap()->set(oldSlotKeys[i].second, target);
156  if (stripMetadata) {
157  metadata.remove(oldSlotKeys[i].first);
158  metadata.remove(oldSlotKeys[i].first + "_ERR_SLOT");
159  metadata.remove(oldSlotKeys[i].first + "_FLAG_SLOT");
160  }
161  }
162  }
163  }
164 
165  // Read the rest of the header into the intermediate inputs container.
166  std::vector<std::string> keyList = metadata.getOrderedNames();
167  for (std::vector<std::string>::const_iterator key = keyList.begin(); key != keyList.end(); ++key) {
168  if (key->compare(0, 5, "TTYPE") == 0) {
169  int column = std::stoi(key->substr(5)) - 1;
170  auto iter = _impl->byColumn().lower_bound(column);
171  if (iter == _impl->byColumn().end() || iter->column != column) {
172  iter = _impl->byColumn().insert(iter, FitsSchemaItem(column, -1));
173  }
174  std::string v = metadata.get<std::string>(*key);
175  _impl->byColumn().modify(iter, Impl::SetTTYPE(v));
176  if (iter->doc.empty()) { // don't overwrite if already set with TDOCn
177  _impl->byColumn().modify(iter, Impl::SetDoc(metadata.getComment(*key)));
178  }
179  if (stripMetadata) {
180  metadata.remove(*key);
181  }
182  } else if (key->compare(0, 5, "TFLAG") == 0) {
183  int bit = std::stoi(key->substr(5)) - 1;
184  auto iter = _impl->byBit().lower_bound(bit);
185  if (iter == _impl->byBit().end() || iter->bit != bit) {
186  iter = _impl->byBit().insert(iter, FitsSchemaItem(-1, bit));
187  }
188  std::string v = metadata.get<std::string>(*key);
189  _impl->byBit().modify(iter, Impl::SetTTYPE(v));
190  if (iter->doc.empty()) { // don't overwrite if already set with TFDOCn
191  _impl->byBit().modify(iter, Impl::SetDoc(metadata.getComment(*key)));
192  }
193  if (stripMetadata) {
194  metadata.remove(*key);
195  }
196  } else if (key->compare(0, 4, "TDOC") == 0) {
197  int column = std::stoi(key->substr(4)) - 1;
198  auto iter = _impl->byColumn().lower_bound(column);
199  if (iter == _impl->byColumn().end() || iter->column != column) {
200  iter = _impl->byColumn().insert(iter, FitsSchemaItem(column, -1));
201  }
202  _impl->byColumn().modify(iter, Impl::SetDoc(metadata.get<std::string>(*key)));
203  if (stripMetadata) {
204  metadata.remove(*key);
205  }
206  } else if (key->compare(0, 5, "TFDOC") == 0) {
207  int bit = std::stoi(key->substr(5)) - 1;
208  auto iter = _impl->byBit().lower_bound(bit);
209  if (iter == _impl->byBit().end() || iter->bit != bit) {
210  iter = _impl->byBit().insert(iter, FitsSchemaItem(-1, bit));
211  }
212  _impl->byBit().modify(iter, Impl::SetDoc(metadata.get<std::string>(*key)));
213  if (stripMetadata) {
214  metadata.remove(*key);
215  }
216  } else if (key->compare(0, 5, "TUNIT") == 0) {
217  int column = std::stoi(key->substr(5)) - 1;
218  auto iter = _impl->byColumn().lower_bound(column);
219  if (iter == _impl->byColumn().end() || iter->column != column) {
220  iter = _impl->byColumn().insert(iter, FitsSchemaItem(column, -1));
221  }
222  _impl->byColumn().modify(iter, Impl::SetTUNIT(metadata.get<std::string>(*key)));
223  if (stripMetadata) {
224  metadata.remove(*key);
225  }
226  } else if (key->compare(0, 5, "TCCLS") == 0) {
227  int column = std::stoi(key->substr(5)) - 1;
228  auto iter = _impl->byColumn().lower_bound(column);
229  if (iter == _impl->byColumn().end() || iter->column != column) {
230  iter = _impl->byColumn().insert(iter, FitsSchemaItem(column, -1));
231  }
232  _impl->byColumn().modify(iter, Impl::SetTCCLS(metadata.get<std::string>(*key)));
233  if (stripMetadata) {
234  metadata.remove(*key);
235  }
236  } else if (key->compare(0, 5, "TFORM") == 0) {
237  int column = std::stoi(key->substr(5)) - 1;
238  auto iter = _impl->byColumn().lower_bound(column);
239  if (iter == _impl->byColumn().end() || iter->column != column) {
240  iter = _impl->byColumn().insert(iter, FitsSchemaItem(column, -1));
241  }
242  _impl->byColumn().modify(iter, Impl::SetTFORM(metadata.get<std::string>(*key)));
243  if (stripMetadata) {
244  metadata.remove(*key);
245  }
246  } else if (key->compare(0, 5, "TZERO") == 0) {
247  if (stripMetadata) {
248  metadata.remove(*key);
249  }
250  } else if (key->compare(0, 5, "TSCAL") == 0) {
251  if (stripMetadata) {
252  metadata.remove(*key);
253  }
254  } else if (key->compare(0, 5, "TNULL") == 0) {
255  if (stripMetadata) {
256  metadata.remove(*key);
257  }
258  } else if (key->compare(0, 5, "TDISP") == 0) {
259  if (stripMetadata) {
260  metadata.remove(*key);
261  }
262  }
263  }
264 
265  // Find the column used to store flags, and setup the flag-handling data members from it.
266  _impl->flagColumn = metadata.get("FLAGCOL", 0);
267  if (_impl->flagColumn > 0) {
268  if (stripMetadata) {
269  metadata.remove("FLAGCOL");
270  }
271  --_impl->flagColumn; // switch from 1-indexed to 0-indexed
272  auto iter = _impl->byColumn().find(_impl->flagColumn);
273  if (iter == _impl->byColumn().end()) {
274  throw LSST_EXCEPT(
275  afw::fits::FitsError,
276  (boost::format("Column for flag data not found; FLAGCOL=%d") % _impl->flagColumn).str());
277  }
278  // Regex to unpack a FITS TFORM value for a bit array column (TFORM code 'X'). The number
279  // that precedes the code is the size of the array; the number that follows it (if present)
280  // is ignored.
281  static boost::regex const regex("(\\d+)?X\\(?(\\d)*\\)?", boost::regex::perl);
282  boost::smatch m;
283  if (!boost::regex_match(iter->tform, m, regex)) {
284  throw LSST_EXCEPT(
285  afw::fits::FitsError,
286  (boost::format("Invalid TFORM key for flags column: '%s'") % iter->tform).str());
287  }
288  int nFlags = 1;
289  if (m[1].matched) {
290  nFlags = std::stoi(m[1].str());
291  }
292  _impl->flagKeys.resize(nFlags);
293  _impl->flagWorkspace.reset(new bool[nFlags]);
294  // Delete the flag column from the input list so we don't interpret it as a
295  // regular field.
296  _impl->byColumn().erase(iter);
297  }
298 }
Key< Flag > const & target
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
int nFlags
Definition: FitsWriter.cc:91
Key< U > key
Definition: Schema.cc:281
int m
Definition: SpanSet.cc:49
T begin(T... args)
static int const VERSION
Definition: Schema.h:56
SetFitsSchemaString<&FitsSchemaItem::tccls > SetTCCLS
SetFitsSchemaString<&FitsSchemaItem::ttype > SetTTYPE
SetFitsSchemaString<&FitsSchemaItem::tunit > SetTUNIT
SetFitsSchemaString<&FitsSchemaItem::tform > SetTFORM
SetFitsSchemaString<&FitsSchemaItem::doc > SetDoc
T end(T... args)
T make_pair(T... args)
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174
T size(T... args)
T stoi(T... args)

◆ FitsSchemaInputMapper() [2/3]

lsst::afw::table::io::FitsSchemaInputMapper::FitsSchemaInputMapper ( FitsSchemaInputMapper const &  )
default

◆ FitsSchemaInputMapper() [3/3]

lsst::afw::table::io::FitsSchemaInputMapper::FitsSchemaInputMapper ( FitsSchemaInputMapper &&  )
default

◆ ~FitsSchemaInputMapper()

lsst::afw::table::io::FitsSchemaInputMapper::~FitsSchemaInputMapper ( )
default

Member Function Documentation

◆ customize()

void lsst::afw::table::io::FitsSchemaInputMapper::customize ( std::unique_ptr< FitsColumnReader reader)

Customize a mapping by providing a FitsColumnReader instance that will be invoked by readRecords().

Definition at line 364 of file FitsSchemaInputMapper.cc.

364  {
365  _impl->readers.push_back(std::move(reader));
366 }
T move(T... args)

◆ erase() [1/3]

void lsst::afw::table::io::FitsSchemaInputMapper::erase ( int  column)

Remove the item at the given column position from the mapping, preventing it from being included in the regular fields added by finalize().

Definition at line 355 of file FitsSchemaInputMapper.cc.

355  {
356  auto iter = _impl->byColumn().lower_bound(column);
357  if (iter != _impl->byColumn().end() && iter->column == column) {
358  _impl->byColumn().erase(iter);
359  }
360 }

◆ erase() [2/3]

void lsst::afw::table::io::FitsSchemaInputMapper::erase ( Item const *  item)

Remove the given item (which should have been retrieved via find()) from the mapping, preventing it from being included in the regular fields added by finalize().

Definition at line 342 of file FitsSchemaInputMapper.cc.

342  {
343  auto iter = _impl->byColumn().lower_bound(item->column);
344  assert(iter != _impl->byColumn().end() && iter->column == item->column);
345  _impl->byColumn().erase(iter);
346 }

◆ erase() [3/3]

void lsst::afw::table::io::FitsSchemaInputMapper::erase ( std::string const &  ttype)

Remove the item with the given column name (ttype) from the mapping, preventing it from being included in the regular fields added by finalize().

Definition at line 348 of file FitsSchemaInputMapper.cc.

348  {
349  auto iter = _impl->byName().find(ttype);
350  if (iter != _impl->byName().end() && iter->ttype == ttype) {
351  _impl->byName().erase(iter);
352  }
353 }

◆ finalize()

Schema lsst::afw::table::io::FitsSchemaInputMapper::finalize ( )

Map any remaining items into regular Schema items, and return the final Schema.

This method must be called before any calls to readRecords().

Definition at line 782 of file FitsSchemaInputMapper.cc.

782  {
783  if (_impl->version == 0) {
784  AliasMap &aliases = *_impl->schema.getAliasMap();
785  for (auto iter = _impl->asList().begin(); iter != _impl->asList().end(); ++iter) {
786  std::size_t flagPos = iter->ttype.find("flags");
787  if (flagPos != std::string::npos) {
788  // We want to create aliases that resolve "(.*)_flag" to "$1_flags"; old schemas will have
789  // the latter, but new conventions (including slots) expect the former.
790  // But we can't do that, because adding that alias directly results in a cycle in the
791  // aliases (since aliases do partial matches, and keep trying until there are no matches,
792  // we'd have "(.*)_flag" resolve to "$1_flagssssssssssssss...").
793  // Instead, we *rename* from "flags" to "flag", then create the reverse alias.
794  std::string ttype = iter->ttype;
795  std::string prefix = iter->ttype.substr(0, flagPos);
796  ttype.replace(flagPos, 5, "flag");
797  _impl->asList().modify(iter, Impl::SetTTYPE(ttype));
798  // Note that we're not aliasing the full field, just the first part - if we have multiple
799  // flag fields, one alias should be sufficient for all of them (because of partial matching).
800  // Of course, we'll try to recreate that alias every time we handle another flag field with
801  // the same prefix, but AliasMap know hows to handle that no-op set.
802  aliases.set(prefix + "flags", prefix + "flag");
803  } else if (isInstFlux(*iter)) {
804  // Create an alias that resolves "X_instFlux" to "X" or "X_instFluxErr" to "X_err".
805  if (endswith(iter->ttype, "_err")) {
806  aliases.set(replace(iter->ttype, "_err", "_instFluxErr"), iter->ttype);
807  } else {
808  aliases.set(iter->ttype + "_instFlux", iter->ttype);
809  }
810  } else if (endswith(iter->ttype, "_err")) {
811  // Create aliases that resolve "(.*)_(.*)Err" and "(.*)_(.*)_(.*)_Cov" to
812  // "$1_err_$2Err" and "$1_err_$2_$3_Cov", to make centroid and shape uncertainties
813  // available under the new conventions. We don't have to create aliases for the
814  // centroid and shape values themselves, as those will automatically be correct
815  // after the PointConversionReader and MomentsConversionReader do their work.
816  if (iter->tccls == "Covariance(Point)") {
817  aliases.set(replace(iter->ttype, "_err", "_yErr"), iter->ttype + "_yErr");
818  aliases.set(replace(iter->ttype, "_err", "_xErr"), iter->ttype + "_xErr");
819  aliases.set(replace(iter->ttype, "_err", "_x_y_Cov"), iter->ttype + "_x_y_Cov");
820  } else if (iter->tccls == "Covariance(Moments)") {
821  aliases.set(replace(iter->ttype, "_err", "_xxErr"), iter->ttype + "_xxErr");
822  aliases.set(replace(iter->ttype, "_err", "_yyErr"), iter->ttype + "_yyErr");
823  aliases.set(replace(iter->ttype, "_err", "_xyErr"), iter->ttype + "_xyErr");
824  aliases.set(replace(iter->ttype, "_err", "_xx_yy_Cov"), iter->ttype + "_xx_yy_Cov");
825  aliases.set(replace(iter->ttype, "_err", "_xx_xy_Cov"), iter->ttype + "_xx_xy_Cov");
826  aliases.set(replace(iter->ttype, "_err", "_yy_xy_Cov"), iter->ttype + "_yy_xy_Cov");
827  }
828  }
829  }
830  } else if (_impl->version < 3) {
831  // Version == 1 tables use Sigma when we should use Err (see RFC-333) and had no fields
832  // that should have been named Sigma. So provide aliases xErr -> xSigma.
833  // Version <= 2 tables used _flux when we should use _instFlux (see RFC-322).
834  AliasMap &aliases = *_impl->schema.getAliasMap();
835  for (auto iter = _impl->asList().begin(); iter != _impl->asList().end(); ++iter) {
836  std::string name = iter->ttype;
837  if (_impl->version < 2 && endswith(name, "Sigma")) {
838  name = replace(std::move(name), "Sigma", "Err");
839  }
840  if (_impl->version < 3 && isInstFlux(*iter)) {
841  name = replace(std::move(name), "flux", "instFlux");
842  }
843  if (name != iter->ttype) {
844  aliases.set(name, iter->ttype);
845  }
846  }
847  }
848  for (auto iter = _impl->asList().begin(); iter != _impl->asList().end(); ++iter) {
849  if (iter->bit < 0) { // not a Flag column
850  std::unique_ptr<FitsColumnReader> reader = makeColumnReader(_impl->schema, *iter);
851  if (reader) {
852  _impl->readers.push_back(std::move(reader));
853  } else {
854  LOGLS_WARN("afw.FitsSchemaInputMapper", "Format " << iter->tform << " for column "
855  << iter->ttype
856  << " not supported; skipping.");
857  }
858  } else { // is a Flag column
859  if (static_cast<std::size_t>(iter->bit) >= _impl->flagKeys.size()) {
860  throw LSST_EXCEPT(afw::fits::FitsError,
861  (boost::format("Flag field '%s' is is in bit %d (0-indexed) of only %d") %
862  iter->ttype % iter->bit % _impl->flagKeys.size())
863  .str());
864  }
865  _impl->flagKeys[iter->bit] = _impl->schema.addField<Flag>(iter->ttype, iter->doc);
866  }
867  }
868  _impl->asList().clear();
869  if (_impl->schema.getRecordSize() <= 0) {
870  throw LSST_EXCEPT(
871  pex::exceptions::LengthError,
872  (boost::format("Non-positive record size: %d; file is corrupt or invalid.") %
873  _impl->schema.getRecordSize()).str()
874  );
875  }
876  _impl->nRowsToPrep = std::max(PREPPED_ROWS_FACTOR / _impl->schema.getRecordSize(), std::size_t(1));
877  return _impl->schema;
878 }
table::Key< std::string > name
Definition: Amplifier.cc:116
#define LOGLS_WARN(logger, message)
Log a warn-level message using an iostream-based interface.
Definition: Log.h:648
std::string prefix
Definition: SchemaMapper.cc:79
static std::size_t PREPPED_ROWS_FACTOR
When processing each column, divide this number by the record size (in bytes) and ask CFITSIO to read...
T max(T... args)
T replace(T... args)

◆ find() [1/2]

FitsSchemaItem const * lsst::afw::table::io::FitsSchemaInputMapper::find ( int  column) const

Find an item with the given column number, returning nullptr if no such column exists.

The returned pointer is owned by the mapper object, and should not be deleted. It is invalidated by calls to either erase() or finalize().

Definition at line 334 of file FitsSchemaInputMapper.cc.

334  {
335  auto iter = _impl->byColumn().lower_bound(column);
336  if (iter == _impl->byColumn().end() || iter->column != column) {
337  return 0;
338  }
339  return &(*iter);
340 }

◆ find() [2/2]

FitsSchemaItem const * lsst::afw::table::io::FitsSchemaInputMapper::find ( std::string const &  ttype) const

Find an item with the given column name (ttype), returning nullptr if no such column exists.

The returned pointer is owned by the mapper object, and should not be deleted. It is invalidated by calls to either erase() or finalize().

Definition at line 326 of file FitsSchemaInputMapper.cc.

326  {
327  auto iter = _impl->byName().find(ttype);
328  if (iter == _impl->byName().end()) {
329  return 0;
330  }
331  return &(*iter);
332 }

◆ hasArchive()

bool lsst::afw::table::io::FitsSchemaInputMapper::hasArchive ( ) const

Return true if the mapper has an InputArchive.

Definition at line 324 of file FitsSchemaInputMapper.cc.

324 { return static_cast<bool>(_impl->archive); }

◆ operator=() [1/2]

FitsSchemaInputMapper & lsst::afw::table::io::FitsSchemaInputMapper::operator= ( FitsSchemaInputMapper &&  )
default

◆ operator=() [2/2]

FitsSchemaInputMapper & lsst::afw::table::io::FitsSchemaInputMapper::operator= ( FitsSchemaInputMapper const &  )
default

◆ readArchive()

bool lsst::afw::table::io::FitsSchemaInputMapper::readArchive ( afw::fits::Fits fits)

Set the Archive by reading from the HDU specified by the AR_HDU header entry.

Returns true on success, false if there is no AR_HDU entry.

Definition at line 308 of file FitsSchemaInputMapper.cc.

308  {
309  int oldHdu = fits.getHdu();
310  if (_impl->archiveHdu < 0) _impl->archiveHdu = oldHdu + 1;
311  try {
312  fits.setHdu(_impl->archiveHdu);
313  _impl->archive.reset(new io::InputArchive(InputArchive::readFits(fits)));
314  fits.setHdu(oldHdu);
315  return true;
316  } catch (afw::fits::FitsError &) {
317  fits.status = 0;
318  fits.setHdu(oldHdu);
319  _impl->archiveHdu = -1;
320  return false;
321  }
322 }
Fits * fits
Definition: FitsWriter.cc:90
static InputArchive readFits(fits::Fits &fitsfile)
Read an object from an already open FITS object.

◆ readRecord()

void lsst::afw::table::io::FitsSchemaInputMapper::readRecord ( BaseRecord record,
afw::fits::Fits fits,
std::size_t  row 
)

Fill a record from a FITS binary table row.

Definition at line 880 of file FitsSchemaInputMapper.cc.

880  {
881  if (!_impl->flagKeys.empty()) {
882  fits.readTableArray<bool>(row, _impl->flagColumn, _impl->flagKeys.size(), _impl->flagWorkspace.get());
883  for (std::size_t bit = 0; bit < _impl->flagKeys.size(); ++bit) {
884  record.set(_impl->flagKeys[bit], _impl->flagWorkspace[bit]);
885  }
886  }
887  if (_impl->nRowsToPrep != 1 && row % _impl->nRowsToPrep == 0) {
888  // Give readers a chance to read and cache up to nRowsToPrep rows-
889  // worth of values.
890  std::size_t size = std::min(_impl->nRowsToPrep, fits.countRows() - row);
891  for (auto & reader : _impl->readers) {
892  reader->prepRead(row, size, fits);
893  }
894  }
895  for (auto const & reader : _impl->readers) {
896  reader->readCell(record, row, fits, _impl->archive);
897  }
898 }
T min(T... args)
int row
Definition: CR.cc:145

◆ setArchive()

void lsst::afw::table::io::FitsSchemaInputMapper::setArchive ( std::shared_ptr< InputArchive archive)

Set the Archive to an externally-provided one, overriding any that may have been read.

Definition at line 306 of file FitsSchemaInputMapper.cc.

306 { _impl->archive = archive; }

Member Data Documentation

◆ PREPPED_ROWS_FACTOR

std::size_t lsst::afw::table::io::FitsSchemaInputMapper::PREPPED_ROWS_FACTOR = 1 << 15
static

When processing each column, divide this number by the record size (in bytes) and ask CFITSIO to read this many that of values from that column in a single call.

Both FITS binary tables and afw.table are stored row-major, so reading multiple rows from a single column at a time leads to nonsequential reads. But given the way the I/O code is structured, we tend to get nonsequential reads anyway, and it seems the per-call overload to CFITSIO is sufficiently high that it's best to do this anyway for all but the largest record sizes.

Definition at line 107 of file FitsSchemaInputMapper.h.


The documentation for this class was generated from the following files: