11 #include "boost/multi_index_container.hpp" 
   12 #include "boost/multi_index/sequenced_index.hpp" 
   13 #include "boost/multi_index/ordered_index.hpp" 
   14 #include "boost/multi_index/hashed_index.hpp" 
   15 #include "boost/multi_index/member.hpp" 
   34 template <std::
string FitsSchemaItem::*Member>
 
   35 struct SetFitsSchemaString {
 
   36     void operator()(FitsSchemaItem &item) { item.*Member = _v; }
 
   37     explicit SetFitsSchemaString(
std::string const &v) : _v(v) {}
 
   51     using InputContainer = boost::multi_index_container<FitsSchemaItem, boost::multi_index::indexed_by<boost::multi_index::ordered_non_unique<boost::multi_index::member<FitsSchemaItem, int, &FitsSchemaItem::column>>, boost::multi_index::ordered_non_unique<boost::multi_index::member<FitsSchemaItem, int, &FitsSchemaItem::bit>>, boost::multi_index::hashed_unique<boost::multi_index::member<FitsSchemaItem, std::string, &FitsSchemaItem::ttype>>, boost::multi_index::sequenced<>>>;
 
   54     using SetTTYPE = SetFitsSchemaString<&FitsSchemaItem::ttype>;
 
   55     using SetTFORM = SetFitsSchemaString<&FitsSchemaItem::tform>;
 
   56     using SetTCCLS = SetFitsSchemaString<&FitsSchemaItem::tccls>;
 
   57     using SetTUNIT = SetFitsSchemaString<&FitsSchemaItem::tunit>;
 
   58     using SetDoc = SetFitsSchemaString<&FitsSchemaItem::doc>;
 
   90         : _impl(
std::make_shared<
Impl>()) {
 
   93     if (!metadata.
exists(
"AFW_TYPE")) {
 
   97     _impl->
type = metadata.
get(
"AFW_TYPE", _impl->
type);
 
   99         metadata.
remove(
"AFW_TABLE_VERSION");
 
  102         metadata.
remove(
"AFW_TYPE");
 
  110             metadata.
remove(
"AR_HDU");
 
  117         for (
auto const &rawAliase : rawAliases) {
 
  119             if (pos == std::string::npos) {
 
  121                                   (
boost::format(
"Malformed alias definition: '%s'") % rawAliase).str());
 
  123             _impl->
schema.
getAliasMap()->set(rawAliase.substr(0, pos), rawAliase.substr(pos + 1, std::string::npos));
 
  141         for (
auto const &oldSlotKey : oldSlotKeys) {
 
  146                     metadata.
remove(oldSlotKey.first);
 
  147                     metadata.
remove(oldSlotKey.first + 
"_ERR_SLOT");
 
  148                     metadata.
remove(oldSlotKey.first + 
"_FLAG_SLOT");
 
  156     for (
auto const &key : keyList) {
 
  157         if (key.compare(0, 5, 
"TTYPE") == 0) {
 
  158             int column = 
std::stoi(key.substr(5)) - 1;
 
  165             if (
iter->doc.empty()) {  
 
  171         } 
else if (key.compare(0, 5, 
"TFLAG") == 0) {
 
  173             auto iter = _impl->
byBit().lower_bound(bit);
 
  179             if (
iter->doc.empty()) {  
 
  185         } 
else if (key.compare(0, 4, 
"TDOC") == 0) {
 
  186             int column = 
std::stoi(key.substr(4)) - 1;
 
  195         } 
else if (key.compare(0, 5, 
"TFDOC") == 0) {
 
  197             auto iter = _impl->
byBit().lower_bound(bit);
 
  205         } 
else if (key.compare(0, 5, 
"TUNIT") == 0) {
 
  206             int column = 
std::stoi(key.substr(5)) - 1;
 
  215         } 
else if (key.compare(0, 5, 
"TCCLS") == 0) {
 
  216             int column = 
std::stoi(key.substr(5)) - 1;
 
  225         } 
else if (key.compare(0, 5, 
"TFORM") == 0) {
 
  226             int column = 
std::stoi(key.substr(5)) - 1;
 
  235         } 
else if (key.compare(0, 5, 
"TZERO") == 0) {
 
  239         } 
else if (key.compare(0, 5, 
"TSCAL") == 0) {
 
  243         } 
else if (key.compare(0, 5, 
"TNULL") == 0) {
 
  247         } 
else if (key.compare(0, 5, 
"TDISP") == 0) {
 
  258             metadata.
remove(
"FLAGCOL");
 
  270         static std::regex const regex(
"(\\d+)?X\\(?(\\d)*\\)?");
 
  275                     (
boost::format(
"Invalid TFORM key for flags column: '%s'") % 
iter->tform).str());
 
  298     int oldHdu = 
fits.getHdu();
 
  359 template <
typename T>
 
  368             : _column(item.column), _key(
schema.addField<
T>(item.ttype, item.doc, item.tunit, base)),
 
  369               _cache(), _cacheFirstRow(0)
 
  376         if (_key.getElementCount() == 1u) {
 
  377             std::size_t nElements = nRows*_key.getElementCount();
 
  378             _cache.resize(nElements);
 
  379             _cacheFirstRow = firstRow;
 
  380             fits.readTableArray(firstRow, _column, nElements, &_cache.front());
 
  386         if (_cache.empty()) {
 
  387             fits.readTableArray(
row, _column, _key.getElementCount(), record.getElement(_key));
 
  389             assert(
row >= _cacheFirstRow);
 
  391             assert(offset < _cache.size());
 
  392             std::copy_n(_cache.begin() + offset, _key.getElementCount(), record.getElement(_key));
 
  404 class AngleReader : 
public FitsColumnReader {
 
  407             Schema &
schema, FitsSchemaItem 
const &item,
 
  408             FieldBase<lsst::geom::Angle> 
const &base = FieldBase<lsst::geom::Angle>()) {
 
  412     AngleReader(Schema &
schema, FitsSchemaItem 
const &item, FieldBase<lsst::geom::Angle> 
const &base)
 
  413             : _column(item.column), _key(
schema.addField<
lsst::
geom::
Angle>(item.ttype, item.doc, 
"", base)) {
 
  418         if (!item.tunit.empty() && item.tunit != 
"rad") {
 
  420                               "Angle fields must be persisted in radians (TUNIT='rad').");
 
  425         assert(_key.getElementCount() == 1u);
 
  426         _cache.resize(nRows);
 
  427         _cacheFirstRow = firstRow;
 
  428         fits.readTableArray(firstRow, _column, nRows, &_cache.front());
 
  433         if (_cache.empty()) {
 
  435             fits.readTableScalar(
row, _column, tmp);
 
  438             assert(
row >= _cacheFirstRow);
 
  440             assert(offset < _cache.size());
 
  447     Key<lsst::geom::Angle> _key;
 
  452 class StringReader : 
public FitsColumnReader {
 
  458     StringReader(Schema &
schema, FitsSchemaItem 
const &item, 
int size)
 
  459             : _column(item.column),
 
  460               _key(
schema.addField<
std::string>(item.ttype, item.doc, item.tunit, size)),
 
  461               _isVariableLength(size == 0) {}
 
  466         fits.readTableScalar(
row, _column, s, _isVariableLength);
 
  472     Key<std::string> _key;
 
  473     bool _isVariableLength;
 
  476 template <
typename T>
 
  477 class VariableLengthArrayReader : 
public FitsColumnReader {
 
  483     VariableLengthArrayReader(Schema &
schema, FitsSchemaItem 
const &item)
 
  484             : _column(item.column), _key(
schema.addField<Array<
T>>(item.ttype, item.doc, item.tunit, 0)) {}
 
  488         int size = 
fits.getTableArraySize(
row, _column);
 
  489         ndarray::Array<T, 1, 1> array = ndarray::allocate(size);
 
  490         fits.readTableArray(
row, _column, size, array.getData());
 
  491         record.set(_key, array);
 
  501 template <
typename T>
 
  502 class PointConversionReader : 
public FitsColumnReader {
 
  508     PointConversionReader(Schema &
schema, FitsSchemaItem 
const &item)
 
  509             : _column(item.column), _key(PointKey<
T>::addFields(
schema, item.ttype, item.doc, item.tunit)) {}
 
  514         fits.readTableArray(
row, _column, 2, buffer.
data());
 
  525 class CoordConversionReader : 
public FitsColumnReader {
 
  531     CoordConversionReader(Schema &
schema, FitsSchemaItem 
const &item)
 
  532             : _column(item.column), _key(CoordKey::addFields(
schema, item.ttype, item.doc)) {}
 
  537         fits.readTableArray(
row, _column, 2, buffer.
data());
 
  548 class MomentsConversionReader : 
public FitsColumnReader {
 
  554     MomentsConversionReader(Schema &
schema, FitsSchemaItem 
const &item)
 
  555             : _column(item.column),
 
  561         fits.readTableArray(
row, _column, 3, buffer.
data());
 
  562         record.set(_key, geom::ellipses::Quadrupole(buffer[0], buffer[1], buffer[2], 
false));
 
  573 template <
typename T, 
int N>
 
  574 class CovarianceConversionReader : 
public FitsColumnReader {
 
  577         static std::regex const regex(
"(.*)(\\^(\\d+))?");
 
  592     CovarianceConversionReader(Schema &
schema, FitsSchemaItem 
const &item,
 
  594             : _column(item.column),
 
  596               _key(CovarianceMatrixKey<
T, N>::addFields(
schema, item.ttype, names, guessUnits(item.tunit))),
 
  602         for (
int i = 0; i < 
_size; ++i) {
 
  603             for (
int j = i; j < 
_size; ++j) {
 
  612     CovarianceMatrixKey<T, N> _key;
 
  620     static std::regex const regex(
"(\\d+)?([PQ])?([A-Z])\\(?(\\d)*\\)?");
 
  630     char code = 
m[3].str()[0];
 
  640                 if (item.tccls == 
"Array") {
 
  641                     return StandardReader<Array<std::uint8_t>>::make(
schema, item, size);
 
  643                 return StandardReader<std::uint8_t>::make(
schema, item);
 
  646                 return VariableLengthArrayReader<std::uint8_t>::make(
schema, item);
 
  648             return StandardReader<Array<std::uint8_t>>::make(
schema, item, size);
 
  653                 if (item.tccls == 
"Array") {
 
  654                     return StandardReader<Array<std::uint16_t>>::make(
schema, item, size);
 
  656                 return StandardReader<std::uint16_t>::make(
schema, item);
 
  659                 return VariableLengthArrayReader<std::uint16_t>::make(
schema, item);
 
  661             return StandardReader<Array<std::uint16_t>>::make(
schema, item, size);
 
  664                 return VariableLengthArrayReader<std::int32_t>::make(
schema, item);
 
  666             if (item.tccls == 
"Point") {
 
  667                 return PointConversionReader<std::int32_t>::make(
schema, item);
 
  669             if (size > 1 || item.tccls == 
"Array") {
 
  670                 return StandardReader<Array<std::int32_t>>::make(
schema, item, size);
 
  672             return StandardReader<std::int32_t>::make(
schema, item);
 
  675                 return StandardReader<std::int64_t>::make(
schema, item);
 
  679                 return VariableLengthArrayReader<float>::make(
schema, item);
 
  682                 if (item.tccls == 
"Array") {
 
  683                     return StandardReader<Array<float>>::make(
schema, item, 1);
 
  687                 return StandardReader<float>::make(
schema, item);
 
  689             if (size == 3 && item.tccls == 
"Covariance(Point)") {
 
  691                 return CovarianceConversionReader<float, 2>::make(
schema, item, names);
 
  693             if (size == 6 && item.tccls == 
"Covariance(Moments)") {
 
  695                 return CovarianceConversionReader<float, 3>::make(
schema, item, names);
 
  697             if (item.tccls == 
"Covariance") {
 
  698                 double v = 0.5 * (
std::sqrt(1 + 8 * size) - 1);
 
  700                 if (n * (n + 1) != size * 2) {
 
  701                     throw LSST_EXCEPT(afw::fits::FitsError, 
"Covariance field has invalid size.");
 
  707                 return CovarianceConversionReader<float, Eigen::Dynamic>::make(
schema, item, names);
 
  709             return StandardReader<Array<float>>::make(
schema, item, size);
 
  712                 return VariableLengthArrayReader<double>::make(
schema, item);
 
  715                 if (item.tccls == 
"Angle") {
 
  716                     return AngleReader::make(
schema, item);
 
  718                 if (item.tccls == 
"Array") {
 
  719                     return StandardReader<Array<double>>::make(
schema, item, 1);
 
  721                 return StandardReader<double>::make(
schema, item);
 
  724                 if (item.tccls == 
"Point") {
 
  725                     return PointConversionReader<double>::make(
schema, item);
 
  727                 if (item.tccls == 
"Coord") {
 
  728                     return CoordConversionReader::make(
schema, item);
 
  731             if (size == 3 && item.tccls == 
"Moments") {
 
  732                 return MomentsConversionReader::make(
schema, item);
 
  734             return StandardReader<Array<double>>::make(
schema, item, size);
 
  737             return StringReader::make(
schema, item, size);
 
  747 bool isInstFlux(FitsSchemaItem 
const & item) {
 
  752     if (!
includes(item.ttype, 
"flux")) 
return false;
 
  753     if (
includes(item.ttype, 
"modelfit_CModel") && item.tunit.empty()) {
 
  760     std::transform(units.begin(), units.end(), units.begin(), [](
char c) { return std::tolower(c); } );
 
  776             if (flagPos != std::string::npos) {
 
  785                 ttype.
replace(flagPos, 5, 
"flag");
 
  792             } 
else if (isInstFlux(*
iter)) {
 
  794                 if (endswith(
iter->ttype, 
"_err")) {
 
  795                     aliases.
set(replace(
iter->ttype, 
"_err", 
"_instFluxErr"), 
iter->ttype);
 
  797                     aliases.
set(
iter->ttype + 
"_instFlux", 
iter->ttype);
 
  799             } 
else if (endswith(
iter->ttype, 
"_err")) {
 
  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");
 
  819     } 
else if (_impl->
version < 3) {
 
  826             if (_impl->
version < 2 && endswith(
name, 
"Sigma")) {
 
  843                 LOGLS_WARN(
"lsst.afw.FitsSchemaInputMapper", 
"Format " << 
iter->tform << 
" for column " 
  845                                                                   << 
" not supported; skipping.");
 
  850                                   (
boost::format(
"Flag field '%s' is is in bit %d (0-indexed) of only %d") %
 
  861             (
boost::format(
"Non-positive record size: %d; file is corrupt or invalid.") %
 
  880         for (
auto const &reader : _impl->
readers) {
 
  881             reader->prepRead(
row, size, 
fits);
 
  884     for (
auto const & reader : _impl->
readers) {
 
table::Key< std::string > name
 
Key< Flag > const  & target
 
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
 
LSST DM logging module built on log4cxx.
 
#define LOGLS_WARN(logger, message)
Log a warn-level message using an iostream-based interface.
 
An exception thrown when problems are found when reading or writing FITS files.
 
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
 
Mapping class that holds aliases for a Schema.
 
void set(std::string const &alias, std::string const &target)
Add an alias to the schema or replace an existing one.
 
Base class for all records.
 
void set(Key< T > const &key, U const &value)
Set value of a field for the given key.
 
Defines the fields and offsets for a table.
 
Key< T > addField(Field< T > const &field, bool doReplace=false)
Add a new field to the Schema, and return the associated Key.
 
std::size_t getRecordSize() const
Return the raw size of a record in bytes.
 
std::shared_ptr< AliasMap > getAliasMap() const
Return the map of aliases.
 
Polymorphic reader interface used to read different kinds of objects from one or more FITS binary tab...
 
Class for storing ordered metadata with comments.
 
T get(std::string const &name) const
Get the last value for a property name (possibly hierarchical).
 
std::string const  & getComment(std::string const &name) const
Get the comment for a string property name (possibly hierarchical).
 
std::vector< T > getArray(std::string const &name) const
Get the vector of values for a property name (possibly hierarchical).
 
std::vector< std::string > getOrderedNames() const
Get the list of property names, in the order they were added.
 
virtual void remove(std::string const &name)
Remove all values for a property name (possibly hierarchical).
 
bool exists(std::string const &name) const
Determine if a name (possibly hierarchical) exists.
 
A coordinate class intended to represent absolute positions (2-d specialization).
 
Point in an unspecified spherical coordinate system.
 
Reports attempts to exceed implementation-defined length limits for some classes.
 
Reports attempts to access elements using an invalid key.
 
std::size_t computeCovariancePackedSize(std::size_t size)
Defines the packed size of a covariance matrices.
 
std::size_t indexCovariance(std::size_t i, std::size_t j)
Defines the ordering of packed covariance matrices.
 
CoordinateType
Enum used to set units for geometric FunctorKeys.
 
constexpr AngleUnit radians
constant with units of radians
 
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
 
A base class for image defects.
 
table::Key< table::Array< int > > _size
 
Field base class default implementation (used for numeric scalars and lsst::geom::Angle).
 
A structure that describes a field as a collection of related strings read from the FITS header.