17#include <ciiException.hpp>
30#include <fmt/format.h>
39struct FitsDataTypeValue {
40 static_assert(
true,
"invalid data for fits writer");
44struct FitsDataTypeValue<unsigned char> {
45 static constexpr int DTYPE = TBYTE;
49struct FitsDataTypeValue<signed char> {
50 static constexpr int DTYPE = TSBYTE;
54struct FitsDataTypeValue<bool> {
55 static constexpr int DTYPE = TLOGICAL;
62static_assert(
sizeof(bool) ==
sizeof(char),
63 "Cfitsio uses 'char' for TLOGICAL internally. Therefore the sizes of 'bool' and "
64 "'char' must match for this implementation to work.");
79struct FitsDataTypeValue<unsigned short> {
80 static constexpr int DTYPE = TUSHORT;
84struct FitsDataTypeValue<signed short> {
85 static constexpr int DTYPE = TSHORT;
89struct FitsDataTypeValue<unsigned int> {
90 static constexpr int DTYPE = TUINT;
94struct FitsDataTypeValue<int> {
95 static constexpr int DTYPE = TINT;
99struct FitsDataTypeValue<unsigned long> {
100 static constexpr int DTYPE = TULONG;
104struct FitsDataTypeValue<long> {
105 static constexpr int DTYPE = TLONG;
109struct FitsDataTypeValue<float> {
110 static constexpr int DTYPE = TFLOAT;
114struct FitsDataTypeValue<unsigned long long> {
115 static constexpr int DTYPE = TULONGLONG;
119struct FitsDataTypeValue<long long> {
120 static constexpr int DTYPE = TLONGLONG;
124struct FitsDataTypeValue<double> {
125 static constexpr int DTYPE = TDOUBLE;
129struct FitsDataTypeValue<
std::complex<float>> {
130 static constexpr int DTYPE = TCOMPLEX;
134struct FitsDataTypeValue<
std::complex<double>> {
135 static constexpr int DTYPE = TDBLCOMPLEX;
138template <
typename data>
139void TableWriterHelper(fitsfile* fptr,
int colnum,
long firstrow, std::vector<data>& input);
141template <
typename data>
142void TableWriterHelper(fitsfile* fptr,
int colnum,
long firstrow, std::vector<data>& input);
144void ThrowOnBadStatus(
int status,
const std::string& message) {
146 std::array<char, 80> err_text;
147 fits_get_errstatus(status, err_text.data());
149 std::array<char, 80> fits_buffer;
150 while (fits_read_errmsg(fits_buffer.data())) {
151 buffer += fits_buffer.data();
154 fmt::format(
"{} {}: {}", message, err_text.data(), buffer));
164 const std::array<
bool,
sizeof...(T)>& disabled,
165 const std::string& extension_name)
167 , m_fits_handle(nullptr, &CloseFits)
168 , m_extension_name(extension_name)
179 fitsfile* filepointer;
181 fits_create_diskfile(&filepointer, file.c_str(), &status);
182 ThrowOnBadStatus(status,
"Error in fits_open_diskfile");
183 m_fits_handle.reset(filepointer);
184 std::vector<std::string> column_names{}, column_units{}, column_forms{};
185 column_names.reserve(
sizeof...(T));
186 column_units.reserve(
sizeof...(T));
187 column_forms.reserve(
sizeof...(T));
189 column_names.push_back(std::string{column.name});
190 column_units.push_back(std::string{column.unit});
196 column_names.erase(std::next(column_names.begin(), i));
197 column_units.erase(std::next(column_units.begin(), i));
198 column_forms.erase(std::next(column_forms.begin(), i));
203 std::vector<char*> column_names_fits;
204 std::vector<char*> column_units_fits;
205 std::vector<char*> column_forms_fits;
206 column_names_fits.reserve(column_names.size());
207 column_units_fits.reserve(column_units.size());
208 column_forms_fits.reserve(column_forms.size());
210 for (
auto& column_name : column_names) {
212 column_names_fits.push_back(column_name.data());
215 for (
auto& column_unit : column_units) {
217 column_units_fits.push_back(column_unit.data());
220 for (
auto& column_form : column_forms) {
222 column_forms_fits.push_back(column_form.data());
224 fits_create_tbl(m_fits_handle.get(),
227 column_names_fits.size(),
228 column_names_fits.data(),
229 column_forms_fits.data(),
230 column_units_fits.data(),
234 ThrowOnBadStatus(status,
"error in fits_create_tbl");
239 if (m_fits_handle !=
nullptr) {
240 CII_THROW(
RtctkException,
"FitsRecorder: Setting ColumnLength after Open not allowed");
242 if (
sizeof...(T) <= column) {
245 if (length >= 4294967296) {
247 fmt::format(
"length({}) must be less than 2^32", length));
249 m_column_length[column] = length;
254 auto set_column_lengths = [
this](
const auto& first,
const auto&... args) {
256 auto set_column_length = [
this, &column](
const auto& x) {
265 set_column_length(first);
266 (set_column_length(args), ...);
268 std::apply(set_column_lengths, data);
283 auto write = [
this](
const auto& first,
const auto&... args) {
284 long fits_column = 1;
286 auto write_elem = [
this, &fits_column, &element](
const auto& x) {
296 if (not m_column_length[element].has_value()) {
298 fmt::format(
"dynamic sized type given, but length not given for {}",
300 }
else if (x.size() != m_column_length[element]) {
302 "data size does not match configured length");
304 std::vector<
typename std::decay_t<
decltype(x)>::value_type> copy(
305 x.data(), x.data() + m_column_length[element].value());
306 fits_write_col(m_fits_handle.get(),
307 FitsDataTypeValue<
typename decltype(copy)::value_type>::DTYPE,
314 ThrowOnBadStatus(status,
"Error writing to binary table");
318 std::vector<
typename std::decay_t<
decltype(x)>::value_type> copy(
319 x.data(), x.data() + x.size());
320 fits_write_col(m_fits_handle.get(),
321 FitsDataTypeValue<
typename decltype(copy)::value_type>::DTYPE,
328 ThrowOnBadStatus(status,
"Error writing to binary table");
330 }
else if constexpr (std::is_same_v<std::decay_t<
decltype(x)>, std::string>) {
332 char* char_string = copy.data();
333 fits_write_col(m_fits_handle.get(),
341 ThrowOnBadStatus(status,
"Error writing to binary table");
345 std::decay_t<
decltype(x)> copy{x};
346 fits_write_col(m_fits_handle.get(),
347 FitsDataTypeValue<
decltype(copy)>::DTYPE,
354 ThrowOnBadStatus(status,
"Error writing to binary table");
360 (write_elem(args), ...);
362 std::apply(write, data);
368 m_fits_handle.reset(
nullptr);
372void FitsRecorder<T...>::CloseFits(fitsfile* pointer) {
374 fits_close_file(pointer, &status);
375 ThrowOnBadStatus(status,
"Error closing file");
DisabledFields m_disabled_fields
Definition dataRecorder.hpp:108
const ColumnDescription m_column_description
Definition dataRecorder.hpp:109
const std::array< ColumnMetaData, sizeof...(T)> ColumnDescription
Definition dataRecorder.hpp:48
DataRecorder(const ColumnDescription &columns, const DisabledFields &disable={})
Definition dataRecorder.hpp:56
Definition fitsDataRecorder.hpp:27
FitsRecorder(const ColumnDescription &columns, const std::array< bool, sizeof...(T)> &disable={}, const std::string &extension_name="recording")
create a new recorder
Definition fitsDataRecorder.ipp:163
void Open(const std::filesystem::path &file) override
Open a file.
Definition fitsDataRecorder.ipp:177
void SetColumnLength(size_t column, size_t length)
Set the exact length of a column.
Definition fitsDataRecorder.ipp:238
void Write(const std::tuple< T... > &data) override
Write a single row of data.
Definition fitsDataRecorder.ipp:282
void Close() override
Close the currently open file.
Definition fitsDataRecorder.ipp:367
Thrown if an argument passed to a method was invalid.
Definition exceptions.hpp:309
The RtctkException class is the base class for all Rtctk exceptions.
Definition exceptions.hpp:220
constexpr bool IS_STATIC_SPAN_TYPE
Is true if the type is a gsl::span type with fixed size.
Definition typeTraits.hpp:178
constexpr bool IS_STD_ARRAY_TYPE
Is true if the type is a std::array<U> of some type U.
Definition typeTraits.hpp:148
constexpr bool IS_DYNAMIC_SPAN_TYPE
Is true if the type is a gsl::span type with dynamic size.
Definition typeTraits.hpp:208
constexpr bool IS_VECTOR_TYPE
Is true if the type is a std::vector<U> of some type U.
Definition typeTraits.hpp:46
constexpr bool IS_MATRIX_BUFFER_TYPE
Is true if the type is a MatrixBuffer<U> of some type U.
Definition typeTraits.hpp:76
Definition commandReplier.cpp:21
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:157
Definition ddsSub.hpp:155
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.