LSSTApplications  19.0.0-14-gb0260a2+72efe9b372,20.0.0+7927753e06,20.0.0+8829bf0056,20.0.0+995114c5d2,20.0.0+b6f4b2abd1,20.0.0+bddc4f4cbe,20.0.0-1-g253301a+8829bf0056,20.0.0-1-g2b7511a+0d71a2d77f,20.0.0-1-g5b95a8c+7461dd0434,20.0.0-12-g321c96ea+23efe4bbff,20.0.0-16-gfab17e72e+fdf35455f6,20.0.0-2-g0070d88+ba3ffc8f0b,20.0.0-2-g4dae9ad+ee58a624b3,20.0.0-2-g61b8584+5d3db074ba,20.0.0-2-gb780d76+d529cf1a41,20.0.0-2-ged6426c+226a441f5f,20.0.0-2-gf072044+8829bf0056,20.0.0-2-gf1f7952+ee58a624b3,20.0.0-20-geae50cf+e37fec0aee,20.0.0-25-g3dcad98+544a109665,20.0.0-25-g5eafb0f+ee58a624b3,20.0.0-27-g64178ef+f1f297b00a,20.0.0-3-g4cc78c6+e0676b0dc8,20.0.0-3-g8f21e14+4fd2c12c9a,20.0.0-3-gbd60e8c+187b78b4b8,20.0.0-3-gbecbe05+48431fa087,20.0.0-38-ge4adf513+a12e1f8e37,20.0.0-4-g97dc21a+544a109665,20.0.0-4-gb4befbc+087873070b,20.0.0-4-gf910f65+5d3db074ba,20.0.0-5-gdfe0fee+199202a608,20.0.0-5-gfbfe500+d529cf1a41,20.0.0-6-g64f541c+d529cf1a41,20.0.0-6-g9a5b7a1+a1cd37312e,20.0.0-68-ga3f3dda+5fca18c6a4,20.0.0-9-g4aef684+e18322736b,w.2020.45
LSSTDataManagementBasePackage
FitsWriter.cc
Go to the documentation of this file.
1 // -*- lsst-c++ -*-
2 
3 #include <memory>
4 
8 
9 namespace lsst {
10 namespace afw {
11 namespace table {
12 namespace io {
13 
14 namespace {
15 
16 typedef FitsWriter::Fits Fits;
17 
18 //----- Code to write FITS headers --------------------------------------------------------------------------
19 
20 // The driver code is at the bottom of this section; it's easier to understand if you start there
21 // and work your way up.
22 
23 // A Schema::forEach functor that writes FITS header keys for a field when it is called.
24 struct ProcessSchema {
25  template <typename T>
26  void operator()(SchemaItem<T> const& item) const {
27  std::string name = item.field.getName();
28  int n = fits->addColumn<typename Field<T>::Element>(name, item.field.getElementCount(),
29  item.field.getDoc());
30  if (!item.field.getDoc().empty()) {
31  // We use a separate key TDOCn for documentation (in addition to the TTYPEn comments)
32  // so we can have long strings via the CONTINUE convention.
33  // When reading, if there is no TDOCn, we'll just use the TTYPEn comment.
34  fits->writeColumnKey("TDOC", n, item.field.getDoc());
35  }
36  specialize(item, n); // delegate to other member functions that are specialized on field tag types
37  }
38 
39  void operator()(SchemaItem<std::string> const& item) const {
40  std::string name = item.field.getName();
41  int n = fits->addColumn<std::string>(name, item.field.getElementCount(), item.field.getDoc());
42  if (!item.field.getDoc().empty()) {
43  fits->writeColumnKey("TDOC", n, item.field.getDoc());
44  }
45  specialize(item, n);
46  }
47 
48  void operator()(SchemaItem<Flag> const& item) const {
49  std::string name = item.field.getName();
50  fits->writeColumnKey("TFLAG", nFlags, name);
51  if (!item.field.getDoc().empty()) {
52  // We use a separate key TFDOCn for documentation instead of the comment on TFLAGn so
53  // we can have long strings via the CONTINUE convention.
54  // When reading, if there is no TFDOCn, we'll use the TTYPEn comment.
55  fits->writeColumnKey("TFDOC", nFlags, item.field.getDoc());
56  }
57  ++nFlags;
58  }
59 
60  // Create and apply the functor to a schema.
61  static void apply(Fits& fits, Schema const& schema) {
62  ProcessSchema f = {&fits, 0};
63  schema.forEach(f);
64  }
65 
66  template <typename T>
67  void specialize(SchemaItem<T> const& item, int n) const {
68  if (!item.field.getUnits().empty()) fits->writeColumnKey("TUNIT", n, item.field.getUnits());
69  fits->writeColumnKey("TCCLS", n, "Scalar", "Field template used by lsst.afw.table");
70  }
71 
72  void specialize(SchemaItem<lsst::geom::Angle> const& item, int n) const {
73  // Always write units for lsst::geom::Angles as radians (in-memory lsst::geom::Angles field don't use
74  // the unit attribute, single lsst::geom::Angle abstracts that away).
75  fits->writeColumnKey("TUNIT", n, "rad");
76  fits->writeColumnKey("TCCLS", n, "Angle", "Field template used by lsst.afw.table");
77  }
78 
79  template <typename T>
80  void specialize(SchemaItem<Array<T> > const& item, int n) const {
81  if (!item.field.getUnits().empty()) fits->writeColumnKey("TUNIT", n, item.field.getUnits());
82  fits->writeColumnKey("TCCLS", n, "Array", "Field template used by lsst.afw.table");
83  }
84 
85  void specialize(SchemaItem<std::string> const& item, int n) const {
86  if (!item.field.getUnits().empty()) fits->writeColumnKey("TUNIT", n, item.field.getUnits());
87  fits->writeColumnKey("TCCLS", n, "String", "Field template used by lsst.afw.table");
88  }
89 
90  Fits* fits;
91  mutable int nFlags;
92 };
93 
94 void writeAliasMap(Fits& fits, AliasMap const& aliases) {
95  for (AliasMap::Iterator i = aliases.begin(); i != aliases.end(); ++i) {
96  fits.writeKey("ALIAS", i->first + ":" + i->second);
97  }
98 }
99 
100 } // namespace
101 
102 // the driver for all the above machinery
104  Schema schema = table->getSchema();
105  _fits->createTable();
106  LSST_FITS_CHECK_STATUS(*_fits, "creating table");
107  int nFlags = schema.getFlagFieldCount();
108  if (nFlags > 0) {
109  int n = _fits->addColumn<bool>("flags", nFlags, "bits for all Flag fields; see also TFLAGn");
110  _fits->writeKey("FLAGCOL", n + 1, "Column number for the bitflags.");
111  }
112  ProcessSchema::apply(*_fits, schema);
113  writeAliasMap(*_fits, *schema.getAliasMap());
114  // write the version number to the fits header, plus any other metadata
115  std::shared_ptr<daf::base::PropertyList> metadata = table->getMetadata();
116  if (!metadata) {
117  metadata = std::make_shared<daf::base::PropertyList>();
118  }
119  metadata->set<int>("AFW_TABLE_VERSION", Schema::VERSION);
120  _fits->writeMetadata(*metadata);
121  // In case the metadata was attached to the table, clean it up.
122  metadata->remove("AFW_TABLE_VERSION");
123  _row = -1;
124  _fits->addRows(nRows);
125  _processor = std::make_shared<ProcessRecords>(_fits, schema, nFlags, _row);
126 }
127 
128 //----- Code for writing FITS records -----------------------------------------------------------------------
129 
130 // The driver code is at the bottom of this section; it's easier to understand if you start there
131 // and work your way up.
132 
133 // A Schema::forEach functor that writes table data for a single record when it is called.
134 // We instantiate one of these, then reuse it on all the records after updating the data
135 // members that tell it which record and row number it's on.
137  template <typename T>
138  void operator()(SchemaItem<T> const& item) const {
139  fits->writeTableArray(row, col, item.key.getElementCount(), record->getElement(item.key));
140  ++col;
141  }
142 
143  template <typename T>
144  void operator()(SchemaItem<Array<T> > const& item) const {
145  if (item.key.isVariableLength()) {
146  ndarray::Array<T const, 1, 1> array = record->get(item.key);
147  fits->writeTableArray(row, col, array.template getSize<0>(), array.getData());
148  } else {
149  fits->writeTableArray(row, col, item.key.getElementCount(), record->getElement(item.key));
150  }
151  ++col;
152  }
153 
154  void operator()(SchemaItem<std::string> const& item) const {
155  // Write fixed-length and variable-length strings the same way
157  ++col;
158  }
159 
160  void operator()(SchemaItem<Flag> const& item) const {
161  flags[bit] = record->get(item.key);
162  ++bit;
163  }
164 
165  ProcessRecords(Fits* fits_, Schema const& schema_, int nFlags_, std::size_t const& row_)
166  : row(row_), col(0), bit(0), nFlags(nFlags_), fits(fits_), schema(schema_) {
167  if (nFlags) flags.reset(new bool[nFlags]);
168  }
169 
170  void apply(BaseRecord const* r) {
171  record = r;
172  col = 0;
173  bit = 0;
174  if (nFlags) ++col;
175  schema.forEach(*this);
176  if (nFlags) fits->writeTableArray(row, 0, nFlags, flags.get());
177  }
178 
179  std::size_t const& row;
180  mutable int col;
181  mutable int bit;
182  int nFlags;
187 };
188 
190  ++_row;
191  _processor->apply(&record);
192 }
193 } // namespace io
194 } // namespace table
195 } // namespace afw
196 } // namespace lsst
schema
table::Schema schema
Definition: Amplifier.cc:115
lsst::afw::fits::Fits::writeTableArray
void writeTableArray(std::size_t row, int col, int nElements, T const *value)
Write an array value to a binary table.
Definition: fits.cc:1169
lsst::afw::fits::Fits::addRows
std::size_t addRows(std::size_t nRows)
Append rows to a table, and return the index of the first new row.
Definition: fits.cc:1149
lsst::afw::table::io::FitsWriter::Fits
afw::fits::Fits Fits
Definition: FitsWriter.h:27
std::string
STL class.
std::shared_ptr
STL class.
lsst::afw::fits::Fits::createTable
void createTable()
Create a new binary table extension.
Definition: fits.cc:1117
lsst::afw::table::io::FitsWriter::_writeRecord
virtual void _writeRecord(BaseRecord const &source)
Write an individual record.
Definition: FitsWriter.cc:189
lsst::afw::table::BaseRecord::get
Field< T >::Value get(Key< T > const &key) const
Return the value of a field for the given key.
Definition: BaseRecord.h:151
lsst::afw::table::io::FitsWriter::_row
std::size_t _row
Definition: FitsWriter.h:99
lsst::afw::fits::Fits
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Definition: fits.h:297
lsst::afw::table::SchemaItem::key
Key< T > key
Definition: SchemaImpl.h:26
lsst::afw::fits::Fits::writeMetadata
void writeMetadata(daf::base::PropertySet const &metadata)
Read a FITS header into a PropertySet or PropertyList.
Definition: fits.cc:1095
lsst::afw::fits::Fits::writeKey
void writeKey(std::string const &key, T const &value, std::string const &comment)
Add a FITS header key to the bottom of the header.
Definition: fits.cc:667
lsst::afw
Definition: imageAlgorithm.dox:1
std::unique_ptr::get
T get(T... args)
lsst::afw::table::io::FitsWriter::ProcessRecords::schema
Schema schema
Definition: FitsWriter.cc:186
lsst::afw::table::io::FitsWriter::ProcessRecords::fits
Fits * fits
Definition: FitsWriter.cc:183
lsst::afw::table::Schema
Defines the fields and offsets for a table.
Definition: Schema.h:50
lsst::afw::table::io::FitsWriter::ProcessRecords::operator()
void operator()(SchemaItem< T > const &item) const
Definition: FitsWriter.cc:138
lsst::afw::geom.transform.transformContinued.name
string name
Definition: transformContinued.py:32
lsst::afw::table::io::FitsWriter::ProcessRecords::flags
std::unique_ptr< bool[]> flags
Definition: FitsWriter.cc:184
std::unique_ptr::reset
T reset(T... args)
lsst::afw::table::BaseRecord::getElement
Field< T >::Element * getElement(Key< T > const &key)
Return a pointer to the underlying elements of a field (non-const).
Definition: BaseRecord.h:93
lsst::afw::table::Schema::forEach
void forEach(F &&func) const
Apply a functor to each SchemaItem in the Schema.
Definition: Schema.h:212
BaseRecord.h
lsst::afw::table::io::FitsWriter::ProcessRecords::col
int col
Definition: FitsWriter.cc:180
fits
Fits * fits
Definition: FitsWriter.cc:90
lsst::afw::fits::Fits::writeTableScalar
void writeTableScalar(std::size_t row, int col, T value)
Write a scalar value to a binary table.
Definition: fits.h:583
lsst::afw::table::io::FitsWriter::ProcessRecords::operator()
void operator()(SchemaItem< std::string > const &item) const
Definition: FitsWriter.cc:154
lsst::afw::table::io::FitsWriter::ProcessRecords::apply
void apply(BaseRecord const *r)
Definition: FitsWriter.cc:170
lsst::afw::table::BaseRecord
Base class for all records.
Definition: BaseRecord.h:31
lsst::afw::table::io::FitsWriter::ProcessRecords::operator()
void operator()(SchemaItem< Array< T > > const &item) const
Definition: FitsWriter.cc:144
lsst::afw::table::io::FitsWriter::ProcessRecords::ProcessRecords
ProcessRecords(Fits *fits_, Schema const &schema_, int nFlags_, std::size_t const &row_)
Definition: FitsWriter.cc:165
lsst::afw::table::SchemaItem
A simple pair-like struct for mapping a Field (name and description) with a Key (used for actual data...
Definition: SchemaImpl.h:25
lsst::afw::table::io::FitsWriter::ProcessRecords::record
BaseRecord const * record
Definition: FitsWriter.cc:185
lsst::afw::table::Array
Tag types used to declare specialized field types.
Definition: misc.h:32
lsst::afw::table::io::FitsWriter::_fits
Fits * _fits
Definition: FitsWriter.h:97
lsst
A base class for image defects.
Definition: imageAlgorithm.dox:1
lsst::afw::fits::Fits::addColumn
int addColumn(std::string const &ttype, int size, std::string const &comment)
Add a column to a table.
Definition: fits.cc:1140
nFlags
int nFlags
Definition: FitsWriter.cc:91
lsst::afw::table::io::FitsWriter::_writeTable
virtual void _writeTable(std::shared_ptr< BaseTable const > const &table, std::size_t nRows)
Write a table and its schema.
Definition: FitsWriter.cc:103
lsst::afw::table::io::FitsWriter::ProcessRecords::nFlags
int nFlags
Definition: FitsWriter.cc:182
lsst::afw::table::Schema::VERSION
static int const VERSION
Definition: Schema.h:56
LSST_FITS_CHECK_STATUS
#define LSST_FITS_CHECK_STATUS(fitsObj,...)
Throw a FitsError exception if the status of the given Fits object is nonzero.
Definition: fits.h:111
std::map::begin
T begin(T... args)
lsst::afw::table::io::FitsWriter::ProcessRecords::bit
int bit
Definition: FitsWriter.cc:181
lsst::afw::table::io::FitsWriter::ProcessRecords::row
std::size_t const & row
Definition: FitsWriter.cc:179
BaseTable.h
std::size_t
lsst::afw::table::Field::Element
FieldBase< T >::Element Element
Type used to store field data in the table (a field may have multiple elements).
Definition: Field.h:26
std::string::end
T end(T... args)
FitsWriter.h
lsst::afw::table::io::FitsWriter::ProcessRecords::operator()
void operator()(SchemaItem< Flag > const &item) const
Definition: FitsWriter.cc:160
std::unique_ptr< bool[]>
lsst::afw::table::io::FitsWriter::ProcessRecords
Definition: FitsWriter.cc:136
lsst::afw::table::AliasMap::Iterator
std::map< std::string, std::string >::const_iterator Iterator
An iterator over alias->target pairs.
Definition: AliasMap.h:57