18#include <ciiException.hpp>
31#include <fmt/format.h>
40struct FitsDataTypeValue {
41 static_assert(
true,
"invalid data for fits writer");
45struct FitsDataTypeValue<unsigned char> {
46 static constexpr int DTYPE = TBYTE;
50struct FitsDataTypeValue<signed char> {
51 static constexpr int DTYPE = TSBYTE;
55struct FitsDataTypeValue<bool> {
56 static constexpr int DTYPE = TLOGICAL;
63static_assert(
sizeof(bool) ==
sizeof(char),
64 "Cfitsio uses 'char' for TLOGICAL internally. Therefore the sizes of 'bool' and "
65 "'char' must match for this implementation to work.");
80struct FitsDataTypeValue<unsigned short> {
81 static constexpr int DTYPE = TUSHORT;
85struct FitsDataTypeValue<signed short> {
86 static constexpr int DTYPE = TSHORT;
90struct FitsDataTypeValue<unsigned int> {
91 static constexpr int DTYPE = TUINT;
95struct FitsDataTypeValue<int> {
96 static constexpr int DTYPE = TINT;
100struct FitsDataTypeValue<unsigned long> {
101 static constexpr int DTYPE = TULONG;
105struct FitsDataTypeValue<long> {
106 static constexpr int DTYPE = TLONG;
110struct FitsDataTypeValue<float> {
111 static constexpr int DTYPE = TFLOAT;
115struct FitsDataTypeValue<unsigned long long> {
116 static constexpr int DTYPE = TULONGLONG;
120struct FitsDataTypeValue<long long> {
121 static constexpr int DTYPE = TLONGLONG;
125struct FitsDataTypeValue<double> {
126 static constexpr int DTYPE = TDOUBLE;
130struct FitsDataTypeValue<
std::complex<float>> {
131 static constexpr int DTYPE = TCOMPLEX;
135struct FitsDataTypeValue<
std::complex<double>> {
136 static constexpr int DTYPE = TDBLCOMPLEX;
139template <
typename data>
140void TableWriterHelper(fitsfile* fptr,
int colnum,
long firstrow, std::vector<data>& input);
142template <
typename data>
143void TableWriterHelper(fitsfile* fptr,
int colnum,
long firstrow, std::vector<data>& input);
145void ThrowOnBadStatus(
int status,
const std::string& message) {
147 std::array<char, 80> err_text;
148 fits_get_errstatus(status, err_text.data());
150 std::array<char, 80> fits_buffer;
151 while (fits_read_errmsg(fits_buffer.data())) {
152 buffer += fits_buffer.data();
155 fmt::format(
"{} {}: {}", message, err_text.data(), buffer));
165 const std::array<
bool,
sizeof...(T)>& disabled,
166 const std::string& extension_name)
168 , m_fits_handle(nullptr, &CloseFits)
169 , m_extension_name(extension_name)
180 fitsfile* filepointer;
182 fits_create_diskfile(&filepointer, file.c_str(), &status);
183 ThrowOnBadStatus(status,
"Error in fits_open_diskfile");
184 m_fits_handle.reset(filepointer);
185 std::vector<std::string> column_names{}, column_units{}, column_forms{};
186 column_names.reserve(
sizeof...(T));
187 column_units.reserve(
sizeof...(T));
188 column_forms.reserve(
sizeof...(T));
190 column_names.push_back(std::string{column.name});
191 column_units.push_back(std::string{column.unit});
197 column_names.erase(std::next(column_names.begin(), i));
198 column_units.erase(std::next(column_units.begin(), i));
199 column_forms.erase(std::next(column_forms.begin(), i));
204 std::vector<char*> column_names_fits;
205 std::vector<char*> column_units_fits;
206 std::vector<char*> column_forms_fits;
207 column_names_fits.reserve(column_names.size());
208 column_units_fits.reserve(column_units.size());
209 column_forms_fits.reserve(column_forms.size());
210 for (
auto& column_name : column_names) {
211 column_names_fits.push_back(column_name.data());
213 for (
auto& column_unit : column_units) {
214 column_units_fits.push_back(column_unit.data());
216 for (
auto& column_form : column_forms) {
217 column_forms_fits.push_back(column_form.data());
219 fits_create_tbl(m_fits_handle.get(),
222 column_names_fits.size(),
223 column_names_fits.data(),
224 column_forms_fits.data(),
225 column_units_fits.data(),
229 ThrowOnBadStatus(status,
"error in fits_create_tbl");
234 if (m_fits_handle !=
nullptr) {
235 CII_THROW(
RtctkException,
"FitsRecorder: Setting ColumnLength after Open not allowed");
237 if (
sizeof...(T) <= column) {
240 if (length >= 4294967296) {
242 fmt::format(
"length({}) must be less than 2^32", length));
244 m_column_length[column] = length;
249 auto set_column_lengths = [
this](
const auto& first,
const auto&... args) {
251 auto set_column_length = [
this, &column](
const auto& x) {
260 set_column_length(first);
261 (set_column_length(args), ...);
263 std::apply(set_column_lengths, data);
278 auto write = [
this](
const auto& first,
const auto&... args) {
279 long fits_column = 1;
281 auto write_elem = [
this, &fits_column, &element](
const auto& x) {
291 if (not m_column_length[element].has_value()) {
293 fmt::format(
"dynamic sized type given, but length not given for {}",
295 }
else if (x.size() != m_column_length[element]) {
297 "data size does not match configured length");
299 std::vector<
typename std::decay_t<
decltype(x)>::value_type> copy(
300 x.data(), x.data() + m_column_length[element].value());
301 fits_write_col(m_fits_handle.get(),
302 FitsDataTypeValue<
typename decltype(copy)::value_type>::DTYPE,
309 ThrowOnBadStatus(status,
"Error writing to binary table");
313 std::vector<
typename std::decay_t<
decltype(x)>::value_type> copy(
314 x.data(), x.data() + x.size());
315 fits_write_col(m_fits_handle.get(),
316 FitsDataTypeValue<
typename decltype(copy)::value_type>::DTYPE,
323 ThrowOnBadStatus(status,
"Error writing to binary table");
325 }
else if constexpr (std::is_same_v<std::decay_t<
decltype(x)>, std::string>) {
327 char* char_string = copy.data();
328 fits_write_col(m_fits_handle.get(),
336 ThrowOnBadStatus(status,
"Error writing to binary table");
340 std::decay_t<
decltype(x)> copy{x};
341 fits_write_col(m_fits_handle.get(),
342 FitsDataTypeValue<
decltype(copy)>::DTYPE,
349 ThrowOnBadStatus(status,
"Error writing to binary table");
355 (write_elem(args), ...);
357 std::apply(write, data);
363 m_fits_handle.reset(
nullptr);
367void FitsRecorder<T...>::CloseFits(fitsfile* pointer) {
369 fits_close_file(pointer, &status);
370 ThrowOnBadStatus(status,
"Error closing file");
DisabledFields m_disabled_fields
Definition dataRecorder.hpp:109
const ColumnDescription m_column_description
Definition dataRecorder.hpp:110
const std::array< ColumnMetaData, sizeof...(T)> ColumnDescription
Definition dataRecorder.hpp:49
DataRecorder(const ColumnDescription &columns, const DisabledFields &disable={})
Definition dataRecorder.hpp:57
Definition fitsDataRecorder.hpp:28
FitsRecorder(const ColumnDescription &columns, const std::array< bool, sizeof...(T)> &disable={}, const std::string &extension_name="recording")
create a new recorder
Definition fitsDataRecorder.ipp:164
void Open(const std::filesystem::path &file) override
Open a file.
Definition fitsDataRecorder.ipp:178
void SetColumnLength(size_t column, size_t length)
Set the exact length of a column.
Definition fitsDataRecorder.ipp:233
void Write(const std::tuple< T... > &data) override
Write a single row of data.
Definition fitsDataRecorder.ipp:277
void Close() override
Close the currently open file.
Definition fitsDataRecorder.ipp:362
Thrown if an argument passed to a method was invalid.
Definition exceptions.hpp:302
The RtctkException class is the base class for all Rtctk exceptions.
Definition exceptions.hpp:213
Definition commandReplier.cpp:22
constexpr bool IS_STATIC_SPAN_TYPE
Is true if the type is a gsl::span type with fixed size.
Definition typeTraits.hpp:179
void GetFITSTFormWithLength(std::vector< std::string > &input, const gsl::span< std::optional< size_t >, sizeof...(Args)+1 > sizes)
Get a vactor of TFORM strings for a list of types using the custom sizes provided.
Definition fitsColumnFormat.ipp:158
constexpr bool IS_STD_ARRAY_TYPE
Is true if the type is a std::array<U> of some type U.
Definition typeTraits.hpp:149
constexpr bool IS_DYNAMIC_SPAN_TYPE
Is true if the type is a gsl::span type with dynamic size.
Definition typeTraits.hpp:209
constexpr bool IS_VECTOR_TYPE
Is true if the type is a std::vector<U> of some type U.
Definition typeTraits.hpp:47
constexpr bool IS_MATRIX_BUFFER_TYPE
Is true if the type is a MatrixBuffer<U> of some type U.
Definition typeTraits.hpp:77
Definition ddsSub.hpp:156
FitsRecorder allows to write ColumnData to into fits files in a specified directory.
Utility functions for use in data recording.
Provides useful mechanisms to test various type traits.