LSST Applications g070148d5b3+33e5256705,g0d53e28543+25c8b88941,g0da5cf3356+2dd1178308,g1081da9e2a+62d12e78cb,g17e5ecfddb+7e422d6136,g1c76d35bf8+ede3a706f7,g295839609d+225697d880,g2e2c1a68ba+cc1f6f037e,g2ffcdf413f+853cd4dcde,g38293774b4+62d12e78cb,g3b44f30a73+d953f1ac34,g48ccf36440+885b902d19,g4b2f1765b6+7dedbde6d2,g5320a0a9f6+0c5d6105b6,g56b687f8c9+ede3a706f7,g5c4744a4d9+ef6ac23297,g5ffd174ac0+0c5d6105b6,g6075d09f38+66af417445,g667d525e37+2ced63db88,g670421136f+2ced63db88,g71f27ac40c+2ced63db88,g774830318a+463cbe8d1f,g7876bc68e5+1d137996f1,g7985c39107+62d12e78cb,g7fdac2220c+0fd8241c05,g96f01af41f+368e6903a7,g9ca82378b8+2ced63db88,g9d27549199+ef6ac23297,gabe93b2c52+e3573e3735,gb065e2a02a+3dfbe639da,gbc3249ced9+0c5d6105b6,gbec6a3398f+0c5d6105b6,gc9534b9d65+35b9f25267,gd01420fc67+0c5d6105b6,geee7ff78d7+a14128c129,gf63283c776+ede3a706f7,gfed783d017+0c5d6105b6,w.2022.47
LSST Data Management Base Package
Loading...
Searching...
No Matches
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 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 std::size_t 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, std::size_t 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
94void writeAliasMap(Fits& fits, AliasMap const& aliases) {
95 for (auto const &aliase : aliases) {
96 fits.writeKey("ALIAS", aliase.first + ":" + aliase.second);
97 }
98}
99
100} // namespace
101
102// the driver for all the above machinery
104 Schema schema = table->getSchema();
106 LSST_FITS_CHECK_STATUS(*_fits, "creating table");
107 std::size_t 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);
177 }
178
180 mutable int col;
181 mutable int bit;
187};
188
190 ++_row;
191 _processor->apply(&record);
192}
193} // namespace io
194} // namespace table
195} // namespace afw
196} // namespace lsst
table::Key< std::string > name
Definition: Amplifier.cc:116
int nFlags
Definition: FitsWriter.cc:91
table::Schema schema
Definition: python.h:134
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Definition: fits.h:308
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:682
void createTable()
Create a new binary table extension.
Definition: fits.cc:1132
void writeTableScalar(std::size_t row, int col, T value)
Write a scalar value to a binary table.
Definition: fits.h:611
int addColumn(std::string const &ttype, int size, std::string const &comment)
Add a column to a table.
Definition: fits.cc:1155
void writeTableArray(std::size_t row, int col, int nElements, T const *value)
Write an array value to a binary table.
Definition: fits.cc:1184
void writeMetadata(daf::base::PropertySet const &metadata)
Read a FITS header into a PropertySet or PropertyList.
Definition: fits.cc:1110
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:1164
Tag types used to declare specialized field types.
Definition: misc.h:31
Base class for all records.
Definition: BaseRecord.h:31
Field< T >::Value get(Key< T > const &key) const
Return the value of a field for the given key.
Definition: BaseRecord.h:151
Field< T >::Element * getElement(Key< T > const &key)
Return a pointer to the underlying elements of a field (non-const).
Definition: BaseRecord.h:93
Defines the fields and offsets for a table.
Definition: Schema.h:51
void forEach(F &func) const
Apply a functor to each SchemaItem in the Schema.
Definition: Schema.h:214
static int const VERSION
Definition: Schema.h:57
virtual void _writeRecord(BaseRecord const &source)
Write an individual record.
Definition: FitsWriter.cc:189
virtual void _writeTable(std::shared_ptr< BaseTable const > const &table, std::size_t nRows)
Write a table and its schema.
Definition: FitsWriter.cc:103
#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 get(T... args)
T reset(T... args)
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
Definition: FitsWriter.cc:160
ProcessRecords(Fits *fits_, Schema const &schema_, int nFlags_, std::size_t const &row_)
Definition: FitsWriter.cc:165
void operator()(SchemaItem< std::string > const &item) const
Definition: FitsWriter.cc:154
void operator()(SchemaItem< T > const &item) const
Definition: FitsWriter.cc:138
void operator()(SchemaItem< Array< T > > const &item) const
Definition: FitsWriter.cc:144