SourceXtractorPlusPlus  0.12
Please provide a description of the project.
FitsFile.cpp
Go to the documentation of this file.
1 
18 /*
19  * FitsFile.cpp
20  *
21  * Created on: Jun 9, 2020
22  * Author: mschefer
23  */
24 
25 #include <assert.h>
26 
27 #include <iomanip>
28 #include <fstream>
29 #include <string>
30 
31 #include <boost/filesystem/path.hpp>
32 #include <boost/filesystem/operations.hpp>
33 #include <boost/regex.hpp>
34 #include <boost/algorithm/string/case_conv.hpp>
35 #include <boost/algorithm/string/trim.hpp>
36 
39 
40 namespace SourceXtractor {
41 
49 static typename MetadataEntry::value_t valueAutoCast(const std::string& value) {
50  boost::regex float_regex("^[-+]?\\d*\\.?\\d+([eE][-+]?\\d+)?$");
51  boost::regex int_regex("^[-+]?\\d+$");
52 
53  try {
54  if (value.empty()) {
55  return value;
56  }
57  else if (boost::regex_match(value, int_regex)) {
58  return static_cast<int64_t>(std::stoll(value));
59  }
60  else if (boost::regex_match(value, float_regex)) {
61  return std::stod(value);
62  }
63  else if (value.size() == 1) {
64  return value.at(0);
65  }
66  } catch (...) {
67  }
68 
69  // Single quotes are used as escape code of another single quote, and
70  // the string starts and ends with single quotes.
71  // We used to use boost::io::quoted here, but it seems that starting with 1.73 it
72  // does not work well when the escape code and the delimiter are the same
73  std::string unquoted;
74  bool escape = false;
75  unquoted.reserve(value.size());
76  for (auto i = value.begin(); i != value.end(); ++i) {
77  if (*i == '\'' && !escape) {
78  escape = true;
79  // skip this char
80  }
81  else {
82  escape = false;
83  unquoted.push_back(*i);
84  }
85  }
86  return unquoted;
87 }
88 
90  m_filename(filename),
91  m_file_pointer(nullptr),
92  m_is_file_opened(false),
93  m_is_writeable(writeable),
94  m_was_opened_before(false),
95  m_manager(manager) {
96 }
97 
99  close();
100 }
101 
103  int status = 0;
104 
105  fits_open_image(&m_file_pointer, m_filename.c_str(), m_is_writeable ? READWRITE : READONLY, &status);
106  if (status != 0) {
107  throw Elements::Exception() << "Can't open FITS file: " << m_filename;
108  }
109 
110  m_image_hdus.clear() ;
111  int number_of_hdus = 0;
112  if (fits_get_num_hdus(m_file_pointer, &number_of_hdus, &status) < 0) {
113  throw Elements::Exception() << "Can't get the number of HDUs in FITS file: " << m_filename;
114  }
115 
116  m_headers.resize(number_of_hdus);
117 
118  // save current HDU (if the file is opened with advanced cfitsio syntax it might be set already
119  int original_hdu = 0;
120  fits_get_hdu_num(m_file_pointer, &original_hdu);
121 
122  // loop over HDUs to determine which ones are images
123  int hdu_type = 0;
124  for (int hdu_number=1; hdu_number <= number_of_hdus; hdu_number++) {
125  fits_movabs_hdu(m_file_pointer, hdu_number, &hdu_type, &status);
126  if (status != 0) {
127  throw Elements::Exception() << "Can't switch HDUs while opening: " << m_filename;
128  }
129 
130  if (hdu_type == IMAGE_HDU) {
131  int bitpix, naxis;
132  long naxes[2] = {1,1};
133 
134  fits_get_img_param(m_file_pointer, 2, &bitpix, &naxis, naxes, &status);
135  if (status == 0 && naxis == 2) {
136  m_image_hdus.emplace_back(hdu_number);
137  }
138  }
139  }
140 
141  // go back to saved HDU
142  fits_movabs_hdu(m_file_pointer, original_hdu, &hdu_type, &status);
143 
144  // load all FITS headers
145  loadHeaders();
146 
147  // load optional .head file to override headers
148  loadHeadFile();
149 
150  m_is_file_opened = true;
151  m_was_opened_before = true;
152 }
153 
155  int status = 0;
156  fits_open_image(&m_file_pointer, m_filename.c_str(), m_is_writeable ? READWRITE : READONLY, &status);
157  if (status != 0) {
158  throw Elements::Exception() << "Can't open FITS file: " << m_filename;
159  }
160  m_is_file_opened = true;
161 }
162 
164  if (!m_is_file_opened) {
165  if (m_was_opened_before) {
166  reopen();
167  } else {
168  openFirstTime();
169  }
170  }
171  assert(m_file_pointer != nullptr);
172 }
173 
175  if (m_is_file_opened) {
176  int status = 0;
177  fits_close_file(m_file_pointer, &status);
178  m_file_pointer = nullptr;
179  m_is_file_opened = false;
180  }
181 }
182 
184  if (!m_is_writeable) {
185  close();
186  m_is_writeable = true;
187  open();
188  }
189 }
190 
192  int status = 0;
193 
194  // save current HDU (if the file is opened with advanced cfitsio syntax it might be set already)
195  int original_hdu = 0;
196  fits_get_hdu_num(m_file_pointer, &original_hdu);
197 
198  int hdu_type = 0;
199  for (unsigned int i = 0; i < m_headers.size(); i++) {
200  fits_movabs_hdu(m_file_pointer, i+1, &hdu_type, &status); // +1 hdus start at 1
201 
203  }
204 
205  // go back to saved HDU
206  fits_movabs_hdu(m_file_pointer, original_hdu, &hdu_type, &status);
207 }
208 
211  char record[81];
212  int keynum = 1, status = 0;
213 
214  fits_read_record(fptr, keynum, record, &status);
215  while (status == 0 && strncmp(record, "END", 3) != 0) {
216  static boost::regex regex("([^=]{8})=([^\\/]*)(\\/(.*))?");
217  std::string record_str(record);
218 
219  boost::smatch sub_matches;
220  if (boost::regex_match(record_str, sub_matches, regex)) {
221  auto keyword = boost::to_upper_copy(sub_matches[1].str());
222  auto value = sub_matches[2].str();
223  auto comment = sub_matches[4].str();
224  boost::trim(keyword);
225  boost::trim(value);
226  boost::trim(comment);
227  headers.emplace(keyword, MetadataEntry{valueAutoCast(value), {{"comment", comment}}});
228  }
229  fits_read_record(fptr, ++keynum, record, &status);
230  }
231 
232  return headers;
233 }
234 
236  auto filename = boost::filesystem::path(m_filename);
237  auto base_name = filename.stem();
238  base_name.replace_extension(".head");
239  auto head_filename = filename.parent_path() / base_name;
240 
241  if (!boost::filesystem::exists(head_filename)) {
242  return;
243  }
244 
245  auto hdu_iter = m_image_hdus.begin();
246  std::ifstream file;
247 
248  // open the file and check
249  file.open(head_filename.native());
250  if (!file.good() || !file.is_open()) {
251  throw Elements::Exception() << "Cannot load ascii header file: " << head_filename;
252  }
253 
254  while (file.good() && hdu_iter != m_image_hdus.end()) {
255  int current_hdu = *hdu_iter;
256 
257  std::string line;
258  std::getline(file, line);
259 
260  static boost::regex regex_blank_line("\\s*$");
261  line = boost::regex_replace(line, regex_blank_line, std::string(""));
262  if (line.size() == 0) {
263  continue;
264  }
265 
266  if (boost::to_upper_copy(line) == "END") {
267  current_hdu = *(++hdu_iter);
268  }
269  else {
270  static boost::regex regex("([^=]{1,8})=([^\\/]*)(\\/ (.*))?");
271  boost::smatch sub_matches;
272  if (boost::regex_match(line, sub_matches, regex) && sub_matches.size() >= 3) {
273  auto keyword = boost::to_upper_copy(sub_matches[1].str());
274  auto value = sub_matches[2].str();
275  auto comment = sub_matches[4].str();
276  boost::trim(keyword);
277  boost::trim(value);
278  boost::trim(comment);
279  m_headers.at(current_hdu-1)[keyword] = MetadataEntry{valueAutoCast(value), {{"comment", comment}}};;
280  }
281  }
282  }
283 }
284 
285 
286 }
T empty(T... args)
T open(T... args)
T good(T... args)
boost::variant< bool, char, int64_t, double, std::string > value_t
T getline(T... args)
T stod(T... args)
std::vector< int > m_image_hdus
Definition: FitsFile.h:86
T end(T... args)
static MetadataEntry::value_t valueAutoCast(const std::string &value)
Definition: FitsFile.cpp:49
std::vector< std::map< std::string, MetadataEntry > > m_headers
Definition: FitsFile.h:88
STL class.
fitsfile * m_file_pointer
Definition: FitsFile.h:81
STL class.
T at(T... args)
T push_back(T... args)
string filename
Definition: conf.py:63
std::map< std::string, MetadataEntry > loadFitsHeader(fitsfile *fptr)
Definition: FitsFile.cpp:209
T clear(T... args)
T size(T... args)
T begin(T... args)
T strncmp(T... args)
T c_str(T... args)
T emplace(T... args)
std::string m_filename
Definition: FitsFile.h:80
T is_open(T... args)
FitsFile(const std::string &filename, bool writeable, std::shared_ptr< FitsFileManager > manager)
Definition: FitsFile.cpp:89
T stoll(T... args)
STL class.
T reserve(T... args)
T emplace_back(T... args)