1 #ifndef PURIFY_PFITSIO_H
2 #define PURIFY_PFITSIO_H
3 #include "purify/config.h"
33 header_params(
const std::string &fits_name_,
const std::string &pix_units_,
34 const t_real channels_total_,
const t_real ra_,
const t_real dec_,
const stokes pol,
35 const t_real cellx_,
const t_real celly_,
const t_real mean_frequency_,
36 const t_real channel_width_,
const t_uint niters_,
const bool hasconverged_,
37 const t_real relative_variation_,
const t_real residual_convergence_,
38 const t_real epsilon_)
55 }
catch (std::out_of_range &e) {
56 PURIFY_LOW_LOG(
"Polarisation type not recognised by FITS, assuming Stokes I.");
62 #define PURIFY_MACRO(VAR, H2) (this->VAR == H2.VAR)
78 void write_key(fitsfile *fptr,
const std::string &key,
const std::string &value,
79 const std::string &comment,
int *status);
81 void write_key(fitsfile *fptr,
const std::string &key,
const char *value,
82 const std::string &comment,
int *status);
85 void write_history(fitsfile *fptr,
const std::string &context,
const std::string &history,
88 typename std::enable_if<std::is_scalar<T>::value,
void>::type
write_history(
89 fitsfile *fptr,
const std::string &context,
const T &history,
int *status) {
95 typename std::enable_if<std::is_scalar<T>::value,
void>::type
write_key(fitsfile *fptr,
96 const std::string &key,
98 const std::string &comment,
101 if (std::is_same<T, double>::value)
103 else if (std::is_same<T, float>::value)
105 else if (std::is_same<T, int>::value)
107 else if (std::is_same<T, t_int>::value)
109 else if (std::is_same<T, bool>::value)
112 throw std::runtime_error(
"Key type of value not supported by PURIFY template for " + key);
115 if (fits_write_key(fptr, datatype,
const_cast<char *
>(key.c_str()),
116 reinterpret_cast<void *
>(&entry),
const_cast<char *
>(comment.c_str()), status))
117 throw std::runtime_error(
"Problem writing key in fits file: " + key);
121 template <
typename T>
122 T
read_key(fitsfile *fptr,
const std::string &key,
int *status) {
124 char comment[FLEN_COMMENT];
125 if constexpr (std::is_same_v<T, std::string>) {
126 if (fits_read_key(fptr, TSTRING, key.data(), value.data(), comment, status)) {
127 throw std::runtime_error(
"Error reading value from key " + key);
131 if (std::is_same<T, double>::value)
133 else if (std::is_same_v<T, float>)
135 else if (std::is_same_v<T, int>)
137 else if (std::is_same_v<T, bool>)
140 throw std::runtime_error(
"Key type of value not supported by PURIFY template for " + key);
143 if (fits_read_key(fptr, datatype, key.data(), &value, comment, status)) {
144 throw std::runtime_error(
"Error reading value from key " + key);
152 const bool &overwrite =
true);
155 void write2d(
const Image<t_real> &image,
const std::string &fits_name,
156 const std::string &pix_units =
"Jy/Beam",
const bool &overwrite =
true);
158 template <
typename DERIVED>
159 void write2d(
const Eigen::EigenBase<DERIVED> &input,
int nx,
int ny,
const std::string &fits_name,
160 const std::string &pix_units =
"Jy/Beam",
const bool &overwrite =
true) {
161 Image<t_real>
const data = input.derived().real().template cast<t_real>();
162 write2d(Image<t_real>::Map(data.data(), nx, ny), fits_name, pix_units, overwrite);
164 template <
typename DERIVED>
165 void write2d(
const Eigen::EigenBase<DERIVED> &input,
int nx,
int ny,
167 Image<t_real>
const data = input.derived().real().template cast<t_real>();
168 write2d(Image<t_real>::Map(data.data(), nx, ny), header, overwrite);
173 const bool &overwrite =
true);
176 void write3d(
const std::vector<Image<t_real>> &image,
const std::string &fits_name,
177 const std::string &pix_units =
"Jy/Beam",
const bool &overwrite =
true);
179 template <
typename DERIVED>
180 void write3d(
const std::vector<Eigen::EigenBase<DERIVED>> &input,
int nx,
int ny,
181 const std::string &fits_name,
const std::string &pix_units =
"Jy/Beam",
182 const bool &overwrite =
true) {
183 std::vector<Image<t_real>> images;
184 for (
int i = 0; i < input.size(); i++) {
185 Image<t_real>
const data = input.derived().real().template cast<t_real>();
186 images.push_back(Image<t_real>::Map(data.data(), nx, ny));
188 write3d(images, fits_name, pix_units, overwrite);
190 template <
typename DERIVED>
191 void write3d(
const std::vector<Eigen::EigenBase<DERIVED>> &input,
int nx,
int ny,
193 std::vector<Image<t_real>> images;
194 for (
int i = 0; i < input.size(); i++) {
195 Image<t_real>
const data = input.derived().real().template cast<t_real>();
196 images.push_back(Image<t_real>::Map(data.data(), nx, ny));
198 write3d(images, header, overwrite);
201 template <
typename T>
202 typename std::enable_if<std::is_same<t_real, typename T::Scalar>::value,
void>::type
write3d(
203 const Eigen::EigenBase<T> &image,
const t_int rows,
const t_int cols,
const t_int chans,
204 const std::string &fits_name,
const std::string &pix_units =
"Jy/Beam",
205 const bool &overwrite =
true) {
209 write3d<T>(image, rows, cols, chans, header, overwrite);
213 template <
typename T>
214 typename std::enable_if<std::is_same<t_real, typename T::Scalar>::value,
void>::type
write3d(
215 const Eigen::EigenBase<T> &image,
const t_int rows,
const t_int cols,
const t_int chans,
223 if (image.size() != rows * cols * chans)
224 throw std::runtime_error(
"image or cube size does not match dimensions.");
227 if (overwrite ==
true) {
232 std::vector<long> naxes = {
static_cast<long>(rows),
static_cast<long>(cols),
233 static_cast<long>(chans), 1};
234 std::vector<long> fpixel = {1, 1, 1, 1};
236 if (fits_create_file(&fptr, header.
fits_name.c_str(), &status))
237 throw std::runtime_error(
"Problem creating fits file:" + header.
fits_name);
238 if (fits_create_img(fptr, DOUBLE_IMG,
static_cast<t_int
>(naxes.size()), naxes.data(), &status))
239 throw std::runtime_error(
"Problem creating HDU for image in fits file:" + header.
fits_name);
240 if (fits_write_pix(fptr, TDOUBLE, fpixel.data(),
static_cast<long>(image.size()),
241 const_cast<t_real *
>(image.derived().data()), &status))
242 throw std::runtime_error(
"Problem writing image in fits file:" + header.
fits_name);
244 #define PURIFY_MACRO(KEY, VALUE, COMMENT) write_key(fptr, KEY, VALUE, COMMENT, &status);
248 PURIFY_MACRO(
"NAXIS",
static_cast<t_int
>(naxes.size()),
"");
249 PURIFY_MACRO(
"NAXIS1",
static_cast<t_int
>(naxes.at(0)),
"");
250 PURIFY_MACRO(
"NAXIS2",
static_cast<t_int
>(naxes.at(1)),
"");
251 PURIFY_MACRO(
"NAXIS3",
static_cast<t_int
>(naxes.at(2)),
"");
252 PURIFY_MACRO(
"NAXIS4",
static_cast<t_int
>(naxes.at(3)),
"");
253 PURIFY_MACRO(
"CRPIX1",
static_cast<t_int
>(std::floor(naxes.at(0) / 2)) + 1,
"");
254 PURIFY_MACRO(
"CRPIX2",
static_cast<t_int
>(std::floor(naxes.at(1) / 2)) + 1,
"");
283 if (fits_write_date(fptr, &status))
284 throw std::runtime_error(
"Problem writing date in fits file:" + header.
fits_name);
286 if (fits_close_file(fptr, &status))
287 throw std::runtime_error(
"Problem closing fits file:" + header.
fits_name);
290 template <
typename T,
typename = std::enable_if_t<std::is_same_v<
double,
typename T::Scalar>>>
291 void read3d(
const std::string &fits_name, Eigen::EigenBase<T> &output,
int &rows,
int &cols,
292 int &channels,
int &pols) {
301 if (fits_open_image(&fptr, fits_name.c_str(), READONLY, &status))
302 throw std::runtime_error(
"Error opening image " + fits_name);
303 const int naxis = pfitsio::read_key<int>(fptr,
"NAXIS", &status);
304 if (naxis < 1)
throw std::runtime_error(
"Image contains zero axes.");
305 rows = pfitsio::read_key<int>(fptr,
"NAXIS1", &status);
306 cols = (naxis > 1) ? pfitsio::read_key<int>(fptr,
"NAXIS2", &status) : 1;
307 channels = (naxis > 2) ? pfitsio::read_key<int>(fptr,
"NAXIS3", &status) : 1;
308 pols = (naxis > 3) ? pfitsio::read_key<int>(fptr,
"NAXIS4", &status) : 1;
310 std::vector<long> fpixel(naxis, 1);
311 PURIFY_LOW_LOG(
"Dimensions {}x{}x{}x{}", rows, cols, channels, pols);
312 if (pols > 1)
throw std::runtime_error(
"Too many polarisations when reading " + fits_name);
315 output.derived() = Vector<typename T::Scalar>::Zero(rows * cols * channels * pols);
316 if (fits_read_pix(fptr, TDOUBLE, fpixel.data(),
static_cast<long>(output.size()), &nulval,
317 output.derived().data(), &anynul, &status))
318 throw std::runtime_error(
"Error reading data from image " + fits_name);
319 if (anynul)
PURIFY_LOW_LOG(
"There are bad values when reading " + fits_name);
320 if (fits_close_file(fptr, &status))
321 throw std::runtime_error(
"Problem closing fits file: " + fits_name);
325 std::vector<Image<t_complex>>
read3d(
const std::string &fits_name);
328 Image<t_complex>
read2d(
const std::string &fits_name);
#define PURIFY_LOW_LOG(...)
Low priority message.
const t_real pi
mathematical constant
void write2d(const Image< t_real > &eigen_image, const pfitsio::header_params &header, const bool &overwrite)
Write image to fits file.
void write_key(fitsfile *fptr, const std::string &key, const std::string &value, const std::string &comment, int *status)
write key to fits file header
Image< t_complex > read2d(const std::string &fits_name)
Read image from fits file.
void write3d(const std::vector< Image< t_real >> &eigen_images, const pfitsio::header_params &header, const bool &overwrite)
Write cube to fits file using header information.
std::vector< Image< t_complex > > read3d(const std::string &fits_name)
Read cube from fits file.
void write_history(fitsfile *fptr, const std::string &context, const std::string &history, int *status)
write history to fits file
T read_key(fitsfile *fptr, const std::string &key, int *status)
read fits key and return as tuple
const std::map< stokes, t_int > stokes_int
#define PURIFY_MACRO(VAR, H2)