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
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

using Item = FitsSchemaItem
 

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 89 of file FitsSchemaInputMapper.cc.

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

353  {
354  _impl->readers.push_back(std::move(reader));
355 }
std::vector< std::unique_ptr< FitsColumnReader > > readers
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 344 of file FitsSchemaInputMapper.cc.

344  {
345  auto iter = _impl->byColumn().lower_bound(column);
346  if (iter != _impl->byColumn().end() && iter->column == column) {
347  _impl->byColumn().erase(iter);
348  }
349 }

◆ 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 331 of file FitsSchemaInputMapper.cc.

331  {
332  auto iter = _impl->byColumn().lower_bound(item->column);
333  assert(iter != _impl->byColumn().end() && iter->column == item->column);
334  _impl->byColumn().erase(iter);
335 }

◆ 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 337 of file FitsSchemaInputMapper.cc.

337  {
338  auto iter = _impl->byName().find(ttype);
339  if (iter != _impl->byName().end() && iter->ttype == ttype) {
340  _impl->byName().erase(iter);
341  }
342 }

◆ 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 771 of file FitsSchemaInputMapper.cc.

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

323  {
324  auto iter = _impl->byColumn().lower_bound(column);
325  if (iter == _impl->byColumn().end() || iter->column != column) {
326  return nullptr;
327  }
328  return &(*iter);
329 }

◆ 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 315 of file FitsSchemaInputMapper.cc.

315  {
316  auto iter = _impl->byName().find(ttype);
317  if (iter == _impl->byName().end()) {
318  return nullptr;
319  }
320  return &(*iter);
321 }

◆ hasArchive()

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

Return true if the mapper has an InputArchive.

Definition at line 313 of file FitsSchemaInputMapper.cc.

313 { 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 297 of file FitsSchemaInputMapper.cc.

297  {
298  int oldHdu = fits.getHdu();
299  if (_impl->archiveHdu < 0) _impl->archiveHdu = oldHdu + 1;
300  try {
301  fits.setHdu(_impl->archiveHdu);
302  _impl->archive.reset(new io::InputArchive(InputArchive::readFits(fits)));
303  fits.setHdu(oldHdu);
304  return true;
305  } catch (afw::fits::FitsError &) {
306  fits.status = 0;
307  fits.setHdu(oldHdu);
308  _impl->archiveHdu = -1;
309  return false;
310  }
311 }
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 869 of file FitsSchemaInputMapper.cc.

869  {
870  if (!_impl->flagKeys.empty()) {
871  fits.readTableArray<bool>(row, _impl->flagColumn, _impl->flagKeys.size(), _impl->flagWorkspace.get());
872  for (std::size_t bit = 0; bit < _impl->flagKeys.size(); ++bit) {
873  record.set(_impl->flagKeys[bit], _impl->flagWorkspace[bit]);
874  }
875  }
876  if (_impl->nRowsToPrep != 1 && row % _impl->nRowsToPrep == 0) {
877  // Give readers a chance to read and cache up to nRowsToPrep rows-
878  // worth of values.
879  std::size_t size = std::min(_impl->nRowsToPrep, fits.countRows() - row);
880  for (auto const &reader : _impl->readers) {
881  reader->prepRead(row, size, fits);
882  }
883  }
884  for (auto const & reader : _impl->readers) {
885  reader->readCell(record, row, fits, _impl->archive);
886  }
887 }
T get(T... args)
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 295 of file FitsSchemaInputMapper.cc.

295 { _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: