Alexandria  2.19
Please provide a description of the project.
FitsReaderHelper.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012-2021 Euclid Science Ground Segment
3  *
4  * This library is free software; you can redistribute it and/or modify it under
5  * the terms of the GNU Lesser General Public License as published by the Free
6  * Software Foundation; either version 3.0 of the License, or (at your option)
7  * any later version.
8  *
9  * This library is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12  * details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
25 #include "FitsReaderHelper.h"
27 #include <CCfits/CCfits>
28 #include <boost/lexical_cast.hpp>
29 #include <boost/tokenizer.hpp>
30 
31 namespace Euclid {
32 namespace Table {
33 
34 using NdArray::NdArray;
35 
36 std::vector<std::string> autoDetectColumnNames(const CCfits::Table& table_hdu) {
38  for (int i = 1; i <= table_hdu.numCols(); ++i) {
39  std::string name = table_hdu.column(i).name();
40  if (name.empty()) {
41  name = "Col" + std::to_string(i);
42  }
43  names.push_back(std::move(name));
44  }
45  return names;
46 }
47 
49  if (format[0] == 'A') {
50  return typeid(std::string);
51  } else if (format[0] == 'I') {
52  return typeid(int64_t);
53  } else if (format[0] == 'F') {
54  return typeid(double);
55  } else if (format[0] == 'E') {
56  return typeid(double);
57  } else if (format[0] == 'D') {
58  return typeid(double);
59  }
60  throw Elements::Exception() << "FITS ASCII table format " << format << " is not "
61  << "yet supported";
62 }
63 
65  // Get the size out of the format string
66  char ft = format.front();
67  int size = 1;
68  if (std::isdigit(format.front())) {
69  size = std::stoi(format.substr(0, format.size() - 1));
70  ft = format.back();
71  }
72 
73  // If shape is set, it is an NdArray
74  if (!shape.empty()) {
75  if (ft == 'B') {
76  return typeid(NdArray<int32_t>);
77  } else if (ft == 'I') {
78  return typeid(NdArray<int32_t>);
79  } else if (ft == 'J') {
80  return typeid(NdArray<int32_t>);
81  } else if (ft == 'K') {
82  return typeid(NdArray<int64_t>);
83  } else if (ft == 'E') {
84  return typeid(NdArray<float>);
85  } else if (ft == 'D') {
86  return typeid(NdArray<double>);
87  }
88  }
89  // If the dimensionality is 1, it is a scalar
90  else if (size == 1) {
91  if (ft == 'L') {
92  return typeid(bool);
93  } else if (ft == 'B') {
94  return typeid(int32_t);
95  } else if (ft == 'I') {
96  return typeid(int32_t);
97  } else if (ft == 'J') {
98  return typeid(int32_t);
99  } else if (ft == 'K') {
100  return typeid(int64_t);
101  } else if (ft == 'E') {
102  return typeid(float);
103  } else if (ft == 'D') {
104  return typeid(double);
105  }
106  }
107  // Last, vectors
108  else {
109  if (ft == 'B') {
110  return typeid(std::vector<int32_t>);
111  } else if (ft == 'I') {
112  return typeid(std::vector<int32_t>);
113  } else if (ft == 'J') {
114  return typeid(std::vector<int32_t>);
115  } else if (ft == 'K') {
116  return typeid(std::vector<int64_t>);
117  } else if (ft == 'E') {
118  return typeid(std::vector<float>);
119  } else if (ft == 'D') {
120  return typeid(std::vector<double>);
121  } else if (ft == 'A') {
122  return typeid(std::string);
123  }
124  }
125  throw Elements::Exception() << "FITS binary table format " << format << " is not "
126  << "yet supported";
127 }
128 
130  std::vector<size_t> result{};
131  if (!tdim.empty() && tdim.front() == '(' && tdim.back() == ')') {
132  auto subtdim = tdim.substr(1, tdim.size() - 2);
133  boost::char_separator<char> sep{","};
134  boost::tokenizer<boost::char_separator<char>> tok{subtdim, sep};
135  for (auto& s : tok) {
136  result.push_back(boost::lexical_cast<size_t>(s));
137  }
138  // Note: the shape is in fortran order, so we need to reverse
139  std::reverse(result.begin(), result.end());
140  }
141  return result;
142 }
143 
144 std::vector<std::type_index> autoDetectColumnTypes(const CCfits::Table& table_hdu) {
146  for (int i = 1; i <= table_hdu.numCols(); i++) {
147  auto& column = table_hdu.column(i);
148 
149  if (typeid(table_hdu) == typeid(CCfits::BinTable)) {
150  column.setDimen();
151  types.push_back(binaryFormatToType(column.format(), parseTDIM(column.dimen())));
152  } else {
153  types.push_back(asciiFormatToType(column.format()));
154  }
155  }
156  return types;
157 }
158 
159 std::vector<std::string> autoDetectColumnUnits(const CCfits::Table& table_hdu) {
160  std::vector<std::string> units{};
161  for (int i = 1; i <= table_hdu.numCols(); ++i) {
162  units.push_back(table_hdu.column(i).unit());
163  }
164  return units;
165 }
166 
168  std::vector<std::string> descriptions{};
169  for (int i = 1; i <= table_hdu.numCols(); ++i) {
170  std::string desc;
171  auto key = table_hdu.keyWord().find("TDESC" + std::to_string(i));
172  if (key != table_hdu.keyWord().end()) {
173  key->second->value(desc);
174  }
175  descriptions.push_back(desc);
176  }
177  return descriptions;
178 }
179 
180 template <typename T>
181 std::vector<Row::cell_type> convertScalarColumn(CCfits::Column& column, long first, long last) {
182  std::vector<T> data;
183  column.read(data, first, last);
185  for (auto value : data) {
186  result.push_back(value);
187  }
188  return result;
189 }
190 
191 template <typename T>
192 std::vector<Row::cell_type> convertVectorColumn(CCfits::Column& column, long first, long last) {
194  column.readArrays(data, first, last);
196  for (auto& valar : data) {
197  result.push_back(std::vector<T>(std::begin(valar), std::end(valar)));
198  }
199  return result;
200 }
201 
202 template <typename T>
203 std::vector<Row::cell_type> convertNdArrayColumn(CCfits::Column& column, long first, long last) {
205  column.readArrays(data, first, last);
206  std::vector<size_t> shape = parseTDIM(column.dimen());
207 
209  for (auto& valar : data) {
210  result.push_back(NdArray<T>(shape, std::move(std::vector<T>(std::begin(valar), std::end(valar)))));
211  }
212  return result;
213 }
214 
216  return translateColumn(column, type, 1, column.rows());
217 }
218 
219 std::vector<Row::cell_type> translateColumn(CCfits::Column& column, std::type_index type, long first, long last) {
220  if (type == typeid(bool)) {
221  return convertScalarColumn<bool>(column, first, last);
222  } else if (type == typeid(int32_t)) {
223  return convertScalarColumn<int32_t>(column, first, last);
224  } else if (type == typeid(int64_t)) {
225  return convertScalarColumn<int64_t>(column, first, last);
226  } else if (type == typeid(float)) {
227  return convertScalarColumn<float>(column, first, last);
228  } else if (type == typeid(double)) {
229  return convertScalarColumn<double>(column, first, last);
230  } else if (type == typeid(std::string)) {
231  return convertScalarColumn<std::string>(column, first, last);
232  } else if (type == typeid(std::vector<int32_t>)) {
233  return convertVectorColumn<int32_t>(column, first, last);
234  } else if (type == typeid(std::vector<int64_t>)) {
235  return convertVectorColumn<int64_t>(column, first, last);
236  } else if (type == typeid(std::vector<float>)) {
237  return convertVectorColumn<float>(column, first, last);
238  } else if (type == typeid(std::vector<double>)) {
239  return convertVectorColumn<double>(column, first, last);
240  } else if (type == typeid(NdArray<int32_t>)) {
241  return convertNdArrayColumn<int32_t>(column, first, last);
242  } else if (type == typeid(NdArray<int64_t>)) {
243  return convertNdArrayColumn<int64_t>(column, first, last);
244  } else if (type == typeid(NdArray<float>)) {
245  return convertNdArrayColumn<float>(column, first, last);
246  } else if (type == typeid(NdArray<double>)) {
247  return convertNdArrayColumn<double>(column, first, last);
248  }
249  throw Elements::Exception() << "Unsupported column type " << type.name();
250 }
251 
252 } // namespace Table
253 } // end of namespace Euclid
T back(T... args)
T begin(T... args)
NdArray(const std::vector< size_t > &shape_)
T empty(T... args)
T end(T... args)
T find(T... args)
T front(T... args)
T isdigit(T... args)
T move(T... args)
T name(T... args)
constexpr double s
std::type_index asciiFormatToType(const std::string &format)
std::vector< size_t > parseTDIM(const std::string &tdim)
std::vector< std::type_index > autoDetectColumnTypes(const CCfits::Table &table_hdu)
Reads the column types of the given table HDU.
std::map< std::string, ColumnDescription > autoDetectColumnDescriptions(std::istream &in, const std::string &comment)
Reads the column descriptions of the given stream.
std::vector< std::string > autoDetectColumnUnits(const CCfits::Table &table_hdu)
Reads the column units based on the TUNITn keyword.
std::vector< std::string > autoDetectColumnNames(std::istream &in, const std::string &comment, size_t columns_number)
Reads the column names of the given stream.
std::type_index binaryFormatToType(const std::string &format, const std::vector< size_t > &shape)
std::vector< Row::cell_type > convertScalarColumn(CCfits::Column &column, long first, long last)
std::vector< Row::cell_type > translateColumn(CCfits::Column &column, std::type_index type)
Returns a vector representing the given FITS table column data, converted to the requested type.
std::vector< Row::cell_type > convertNdArrayColumn(CCfits::Column &column, long first, long last)
std::vector< Row::cell_type > convertVectorColumn(CCfits::Column &column, long first, long last)
T push_back(T... args)
T reverse(T... args)
T size(T... args)
T stoi(T... args)
T substr(T... args)
T to_string(T... args)