Loading [MathJax]/extensions/tex2jax.js
LSST Applications g04dff08e69+42feea4ef2,g0fba68d861+a0b9de4ea6,g1ec0fe41b4+f536777771,g1fd858c14a+42269675ea,g35bb328faa+fcb1d3bbc8,g4af146b050+bbef1ba6f0,g4d2262a081+8f21adb3a6,g53246c7159+fcb1d3bbc8,g5a012ec0e7+b20b785ecb,g60b5630c4e+43e3f0d37c,g6273192d42+e9a7147bac,g67b6fd64d1+4086c0989b,g78460c75b0+2f9a1b4bcd,g786e29fd12+cf7ec2a62a,g7b71ed6315+fcb1d3bbc8,g7bbe65ff3e+43e3f0d37c,g8352419a5c+fcb1d3bbc8,g87b7deb4dc+43704db330,g8852436030+eb2388797a,g89139ef638+4086c0989b,g9125e01d80+fcb1d3bbc8,g94187f82dc+43e3f0d37c,g989de1cb63+4086c0989b,g9d31334357+43e3f0d37c,g9f33ca652e+9b312035f9,gabe3b4be73+1e0a283bba,gabf8522325+fa80ff7197,gb1101e3267+61f2793e68,gb58c049af0+f03b321e39,gb89ab40317+4086c0989b,gc0bb628dac+834c1753f9,gcf25f946ba+eb2388797a,gd6cbbdb0b4+af3c3595f5,gde0f65d7ad+9e0145b227,ge278dab8ac+d65b3c2b70,ge410e46f29+4086c0989b,gf23fb2af72+37a5db1cfd,gf67bdafdda+4086c0989b,v29.0.0.rc7
LSST Data Management Base Package
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
FitsWriter.cc
Go to the documentation of this file.
1// -*- lsst-c++ -*-
2
3#include <memory>
4
8
9namespace lsst {
10namespace afw {
11namespace table {
12namespace io {
13
14namespace {
15
16using Fits = FitsWriter::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.
24struct 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 if (!item.field.getDoc().empty()) {
30 // We use a separate key TDOCn for documentation
31 // so we can have long strings via the CONTINUE convention.
32 // When reading, if there is no TDOCn, we'll just use the TTYPEn comment.
33 fits->writeColumnKey("TDOC", n, item.field.getDoc());
34 }
35 specialize(item, n); // delegate to other member functions that are specialized on field tag types
36 }
37
38 void operator()(SchemaItem<std::string> const& item) const {
39 std::string name = item.field.getName();
40 std::size_t n = fits->addColumn<std::string>(name, item.field.getElementCount());
41 if (!item.field.getDoc().empty()) {
42 fits->writeColumnKey("TDOC", n, item.field.getDoc());
43 }
44 specialize(item, n);
45 }
46
47 void operator()(SchemaItem<Flag> const& item) const {
48 std::string name = item.field.getName();
49 fits->writeColumnKey("TFLAG", nFlags, name);
50 if (!item.field.getDoc().empty()) {
51 // We use a separate key TFDOCn for documentation instead of the comment on TFLAGn so
52 // we can have long strings via the CONTINUE convention.
53 // When reading, if there is no TFDOCn, we'll use the TTYPEn comment.
54 fits->writeColumnKey("TFDOC", nFlags, item.field.getDoc());
55 }
56 ++nFlags;
57 }
58
59 // Create and apply the functor to a schema.
60 static void apply(Fits& fits, Schema const& schema) {
61 ProcessSchema f = {&fits, 0};
62 schema.forEach(f);
63 }
64
65 template <typename T>
66 void specialize(SchemaItem<T> const& item, int n) const {
67 if (!item.field.getUnits().empty()) fits->writeColumnKey("TUNIT", n, item.field.getUnits());
68 fits->writeColumnKey("TCCLS", n, "Scalar", "Field template used by lsst.afw.table");
69 }
70
71 void specialize(SchemaItem<lsst::geom::Angle> const& item, int n) const {
72 // Always write units for lsst::geom::Angles as radians (in-memory lsst::geom::Angles field don't use
73 // the unit attribute, single lsst::geom::Angle abstracts that away).
74 fits->writeColumnKey("TUNIT", n, "rad");
75 fits->writeColumnKey("TCCLS", n, "Angle", "Field template used by lsst.afw.table");
76 }
77
78 template <typename T>
79 void specialize(SchemaItem<Array<T> > const& item, int n) const {
80 if (!item.field.getUnits().empty()) fits->writeColumnKey("TUNIT", n, item.field.getUnits());
81 fits->writeColumnKey("TCCLS", n, "Array", "Field template used by lsst.afw.table");
82 }
83
84 void specialize(SchemaItem<std::string> const& item, std::size_t n) const {
85 if (!item.field.getUnits().empty()) fits->writeColumnKey("TUNIT", n, item.field.getUnits());
86 fits->writeColumnKey("TCCLS", n, "String", "Field template used by lsst.afw.table");
87 }
88
89 Fits* fits;
90 mutable int nFlags;
91};
92
93void writeAliasMap(Fits& fits, AliasMap const& aliases) {
94 for (auto const &aliase : aliases) {
95 fits.writeKey("ALIAS", aliase.first + ":" + aliase.second);
96 }
97}
98
99} // namespace
100
101// the driver for all the above machinery
103 Schema schema = table->getSchema();
104 _fits->createTable();
105 LSST_FITS_CHECK_STATUS(*_fits, "creating table");
106 std::size_t nFlags = schema.getFlagFieldCount();
107 if (nFlags > 0) {
108 int n = _fits->addColumn<bool>("flags", nFlags, "bits for all Flag fields; see also TFLAGn");
109 _fits->writeKey("FLAGCOL", n + 1, "Column number for the bitflags.");
110 }
111 ProcessSchema::apply(*_fits, schema);
112 writeAliasMap(*_fits, *schema.getAliasMap());
113 // write the version number to the fits header, plus any other metadata
114 std::shared_ptr<daf::base::PropertyList> metadata = table->getMetadata();
115 if (!metadata) {
117 }
118 metadata->set<int>("AFW_TABLE_VERSION", Schema::VERSION);
119 _fits->writeMetadata(*metadata);
120 // In case the metadata was attached to the table, clean it up.
121 metadata->remove("AFW_TABLE_VERSION");
122 _row = -1;
123 _fits->addRows(nRows);
124 _processor = std::make_shared<ProcessRecords>(_fits, schema, nFlags, _row);
125}
126
127//----- Code for writing FITS records -----------------------------------------------------------------------
128
129// The driver code is at the bottom of this section; it's easier to understand if you start there
130// and work your way up.
131
132// A Schema::forEach functor that writes table data for a single record when it is called.
133// We instantiate one of these, then reuse it on all the records after updating the data
134// members that tell it which record and row number it's on.
136 template <typename T>
137 void operator()(SchemaItem<T> const& item) const {
138 fits->writeTableArray(row, col, item.key.getElementCount(), record->getElement(item.key));
139 ++col;
140 }
141
142 template <typename T>
143 void operator()(SchemaItem<Array<T> > const& item) const {
144 if (item.key.isVariableLength()) {
145 ndarray::Array<T const, 1, 1> array = record->get(item.key);
146 fits->writeTableArray(row, col, array.template getSize<0>(), array.getData());
147 } else {
148 fits->writeTableArray(row, col, item.key.getElementCount(), record->getElement(item.key));
149 }
150 ++col;
151 }
152
153 void operator()(SchemaItem<std::string> const& item) const {
154 // Write fixed-length and variable-length strings the same way
155 fits->writeTableScalar(row, col, record->get(item.key));
156 ++col;
157 }
158
159 void operator()(SchemaItem<Flag> const& item) const {
160 flags[bit] = record->get(item.key);
161 ++bit;
162 }
163
164 ProcessRecords(Fits* fits_, Schema const& schema_, int nFlags_, std::size_t const& row_)
165 : row(row_), col(0), bit(0), nFlags(nFlags_), fits(fits_), schema(schema_) {
166 if (nFlags) flags.reset(new bool[nFlags]);
167 }
168
169 void apply(BaseRecord const* r) {
170 record = r;
171 col = 0;
172 bit = 0;
173 if (nFlags) ++col;
174 schema.forEach(*this);
175 if (nFlags) fits->writeTableArray(row, 0, nFlags, flags.get());
176 }
177
179 mutable int col;
180 mutable int bit;
186};
187
189 ++_row;
190 _processor->apply(&record);
191}
192} // namespace io
193} // namespace table
194} // namespace afw
195} // namespace lsst
Tag types used to declare specialized field types.
Definition misc.h:31
Base class for all records.
Definition BaseRecord.h:31
Defines the fields and offsets for a table.
Definition Schema.h:51
static int const VERSION
Definition Schema.h:57
virtual void _writeRecord(BaseRecord const &source)
Write an individual record.
virtual void _writeTable(std::shared_ptr< BaseTable const > const &table, std::size_t nRows)
Write a table and its schema.
#define LSST_FITS_CHECK_STATUS(fitsObj,...)
Throw a FitsError exception if the status of the given Fits object is nonzero.
Definition fits.h:111
T make_shared(T... args)
decltype(sizeof(void *)) size_t
Definition doctest.h:524
typename FieldBase< T >::Element Element
Type used to store field data in the table (a field may have multiple elements).
Definition Field.h:26
A simple pair-like struct for mapping a Field (name and description) with a Key (used for actual data...
Definition SchemaImpl.h:22
void operator()(SchemaItem< Flag > const &item) const
ProcessRecords(Fits *fits_, Schema const &schema_, int nFlags_, std::size_t const &row_)
void operator()(SchemaItem< std::string > const &item) const
void operator()(SchemaItem< T > const &item) const
void operator()(SchemaItem< Array< T > > const &item) const