Alexandria  2.19
Please provide a description of the project.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FitsWriterHelper.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 "FitsWriterHelper.h"
27 #include "Table/Table.h"
28 #include <CCfits/CCfits>
29 #include <algorithm>
30 #include <boost/lexical_cast.hpp>
31 #include <iomanip>
32 #include <sstream>
33 #include <valarray>
34 
35 namespace Euclid {
36 namespace Table {
37 
38 using NdArray::NdArray;
39 
40 template <typename T>
42  std::ostringstream stream;
43  stream << std::scientific << value;
44  return stream.str();
45 }
46 
47 size_t maxWidth(const Table& table, size_t column_index) {
48  size_t width = 0;
49  for (const auto& row : table) {
50  width = std::max(width, boost::lexical_cast<std::string>(row[column_index]).size());
51  }
52  return width;
53 }
54 
55 size_t maxWidthScientific(const Table& table, size_t column_index) {
56  size_t width = 0;
57  for (const auto& row : table) {
58  width = std::max(width, scientificFormat(row[column_index]).size());
59  }
60  return width;
61 }
62 
64  auto column_info = table.getColumnInfo();
65  std::vector<std::string> format_list{};
66  for (size_t column_index = 0; column_index < column_info->size(); ++column_index) {
67  auto type = column_info->getDescription(column_index).type;
68  if (type == typeid(bool)) {
69  format_list.push_back("I1");
70  } else if (type == typeid(int32_t) || type == typeid(int64_t)) {
71  size_t width = maxWidth(table, column_index);
72  format_list.push_back("I" + boost::lexical_cast<std::string>(width));
73  } else if (type == typeid(float) || type == typeid(double)) {
74  size_t width = maxWidthScientific(table, column_index);
75  format_list.push_back("E" + boost::lexical_cast<std::string>(width));
76  } else if (type == typeid(std::string)) {
77  size_t width = maxWidth(table, column_index);
78  format_list.push_back("A" + boost::lexical_cast<std::string>(width));
79  } else {
80  throw Elements::Exception() << "Unsupported column format for FITS ASCII table export: " << type.name();
81  }
82  }
83  return format_list;
84 }
85 
86 template <typename T>
87 size_t vectorSize(const Table& table, size_t column_index) {
88  size_t size = boost::get<std::vector<T>>(table[0][column_index]).size();
89  for (const auto& row : table) {
90  if (boost::get<std::vector<T>>(row[column_index]).size() != size) {
91  throw Elements::Exception() << "Binary FITS table variable length vector columns are not supported";
92  }
93  }
94  return size;
95 }
96 
97 template <typename T>
98 size_t ndArraySize(const Table& table, size_t column_index) {
99  const auto& ndarray = boost::get<NdArray<T>>(table[0][column_index]);
100  size_t size = ndarray.size();
101  auto shape = ndarray.shape();
102  for (const auto& row : table) {
103  if (boost::get<NdArray<T>>(row[column_index]).shape() != shape) {
104  throw Elements::Exception() << "Binary FITS table variable shape array columns are not supported";
105  }
106  }
107  return size;
108 }
109 
111  auto column_info = table.getColumnInfo();
112  std::vector<std::string> format_list{};
113  for (size_t column_index = 0; column_index < column_info->size(); ++column_index) {
114  auto type = column_info->getDescription(column_index).type;
115  if (type == typeid(bool)) {
116  format_list.push_back("L");
117  } else if (type == typeid(int32_t)) {
118  format_list.push_back("J");
119  } else if (type == typeid(int64_t)) {
120  format_list.push_back("K");
121  } else if (type == typeid(float)) {
122  format_list.push_back("E");
123  } else if (type == typeid(double)) {
124  format_list.push_back("D");
125  } else if (type == typeid(std::string)) {
126  size_t width = maxWidth(table, column_index);
127  format_list.push_back(boost::lexical_cast<std::string>(width) + "A");
128  } else if (type == typeid(std::vector<bool>)) {
129  size_t size = vectorSize<bool>(table, column_index);
130  format_list.push_back(boost::lexical_cast<std::string>(size) + "L");
131  } else if (type == typeid(std::vector<int32_t>)) {
132  size_t size = vectorSize<int32_t>(table, column_index);
133  format_list.push_back(boost::lexical_cast<std::string>(size) + "J");
134  } else if (type == typeid(std::vector<int64_t>)) {
135  size_t size = vectorSize<int64_t>(table, column_index);
136  format_list.push_back(boost::lexical_cast<std::string>(size) + "K");
137  } else if (type == typeid(std::vector<float>)) {
138  size_t size = vectorSize<float>(table, column_index);
139  format_list.push_back(boost::lexical_cast<std::string>(size) + "E");
140  } else if (type == typeid(std::vector<double>)) {
141  size_t size = vectorSize<double>(table, column_index);
142  format_list.push_back(boost::lexical_cast<std::string>(size) + "D");
143  } else if (type == typeid(NdArray<int32_t>)) {
144  size_t size = ndArraySize<int32_t>(table, column_index);
145  format_list.push_back(boost::lexical_cast<std::string>(size) + "J");
146  } else if (type == typeid(NdArray<int64_t>)) {
147  size_t size = ndArraySize<int64_t>(table, column_index);
148  format_list.push_back(boost::lexical_cast<std::string>(size) + "K");
149  } else if (type == typeid(NdArray<float>)) {
150  size_t size = ndArraySize<float>(table, column_index);
151  format_list.push_back(boost::lexical_cast<std::string>(size) + "E");
152  } else if (type == typeid(NdArray<double>)) {
153  size_t size = ndArraySize<double>(table, column_index);
154  format_list.push_back(boost::lexical_cast<std::string>(size) + "D");
155  } else {
156  throw Elements::Exception() << "Unsupported column format for FITS binary table export: " << type.name();
157  }
158  }
159  return format_list;
160 }
161 
162 template <typename T>
163 std::vector<T> createColumnData(const Euclid::Table::Table& table, size_t column_index) {
164  std::vector<T> data{};
165  for (const auto& row : table) {
166  data.push_back(boost::get<T>(row[column_index]));
167  }
168  return data;
169 }
170 
171 template <typename T>
174  for (auto& row : table) {
175  const auto& vec = boost::get<std::vector<T>>(row[column_index]);
176  result.emplace_back(vec.data(), vec.size());
177  }
178  return result;
179 }
180 
181 template <typename T>
183  std::vector<T> result{};
184  for (auto& row : table) {
185  const auto& vec = boost::get<std::vector<T>>(row[column_index]);
186  result.push_back(vec.front());
187  }
188  return result;
189 }
190 
191 template <typename T>
194  for (auto& row : table) {
195  const auto& ndarray = boost::get<NdArray<T>>(row[column_index]);
196  std::valarray<T> data(ndarray.size());
197  std::copy(std::begin(ndarray), std::end(ndarray), std::begin(data));
198  result.emplace_back(std::move(data));
199  }
200  return result;
201 }
202 
203 template <typename T>
205  std::vector<T> result{};
206  for (auto& row : table) {
207  const auto& nd = boost::get<NdArray<T>>(row[column_index]);
208  if (nd.size() > 0)
209  result.push_back(*nd.begin());
210  else
211  result.push_back(0);
212  }
213  return result;
214 }
215 
216 template <typename T>
217 void populateVectorColumn(const Table& table, size_t column_index, CCfits::ExtHDU& table_hdu, long first_row) {
218  const auto& vec = boost::get<std::vector<T>>(table[0][column_index]);
219  if (vec.size() > 1) {
220  table_hdu.column(column_index + 1).writeArrays(createVectorColumnData<T>(table, column_index), first_row);
221  } else {
222  table_hdu.column(column_index + 1).write(createSingleValueVectorColumnData<T>(table, column_index), first_row);
223  }
224 }
225 
226 template <typename T>
227 void populateNdArrayColumn(const Table& table, size_t column_index, CCfits::ExtHDU& table_hdu, long first_row) {
228  const auto& nd = boost::get<NdArray<T>>(table[0][column_index]);
229  if (nd.size() > 1) {
230  table_hdu.column(column_index + 1).writeArrays(createNdArrayColumnData<T>(table, column_index), first_row);
231  } else {
232  table_hdu.column(column_index + 1).write(createSingleNdArrayVectorColumnData<T>(table, column_index), first_row);
233  }
234 }
235 
236 std::string getTDIM(const Table& table, size_t column_index) {
237  auto& first_row = table[0];
238  auto& cell = first_row[column_index];
239  auto type = table.getColumnInfo()->getDescription(column_index).type;
240  std::vector<size_t> shape;
241 
242  if (type == typeid(NdArray<int32_t>)) {
243  shape = boost::get<NdArray<int32_t>>(cell).shape();
244  } else if (type == typeid(NdArray<int64_t>)) {
245  shape = boost::get<NdArray<int64_t>>(cell).shape();
246  } else if (type == typeid(NdArray<float>)) {
247  shape = boost::get<NdArray<float>>(cell).shape();
248  } else if (type == typeid(NdArray<double>)) {
249  shape = boost::get<NdArray<double>>(cell).shape();
250  } else {
251  return "";
252  }
253 
254  int64_t ncells = 1;
255  for (auto& axis : shape) {
256  ncells *= axis;
257  }
258  if (ncells == 1) {
259  return "";
260  }
261 
262  std::stringstream stream;
263  stream << '(';
264 
265  int j;
266  for (j = shape.size() - 1; j > 0; --j) {
267  stream << shape[j] << ",";
268  }
269 
270  stream << shape[j] << ')';
271  return stream.str();
272 }
273 
274 void populateColumn(const Table& table, size_t column_index, CCfits::ExtHDU& table_hdu, long first_row) {
275  auto type = table.getColumnInfo()->getDescription(column_index).type;
276  // CCfits indices start from 1
277  if (type == typeid(bool)) {
278  table_hdu.column(column_index + 1).write(createColumnData<bool>(table, column_index), first_row);
279  } else if (type == typeid(int32_t)) {
280  table_hdu.column(column_index + 1).write(createColumnData<int32_t>(table, column_index), first_row);
281  } else if (type == typeid(int64_t)) {
282  table_hdu.column(column_index + 1).write(createColumnData<int64_t>(table, column_index), first_row);
283  } else if (type == typeid(float)) {
284  table_hdu.column(column_index + 1).write(createColumnData<float>(table, column_index), first_row);
285  } else if (type == typeid(double)) {
286  table_hdu.column(column_index + 1).write(createColumnData<double>(table, column_index), first_row);
287  } else if (type == typeid(std::string)) {
288  table_hdu.column(column_index + 1).write(createColumnData<std::string>(table, column_index), first_row);
289  } else if (type == typeid(std::vector<int32_t>)) {
290  populateVectorColumn<int32_t>(table, column_index, table_hdu, first_row);
291  } else if (type == typeid(std::vector<int64_t>)) {
292  populateVectorColumn<int64_t>(table, column_index, table_hdu, first_row);
293  } else if (type == typeid(std::vector<float>)) {
294  populateVectorColumn<float>(table, column_index, table_hdu, first_row);
295  } else if (type == typeid(std::vector<double>)) {
296  populateVectorColumn<double>(table, column_index, table_hdu, first_row);
297  } else if (type == typeid(NdArray<int32_t>)) {
298  populateNdArrayColumn<int32_t>(table, column_index, table_hdu, first_row);
299  } else if (type == typeid(NdArray<int64_t>)) {
300  populateNdArrayColumn<int64_t>(table, column_index, table_hdu, first_row);
301  } else if (type == typeid(NdArray<float>)) {
302  populateNdArrayColumn<float>(table, column_index, table_hdu, first_row);
303  } else if (type == typeid(NdArray<double>)) {
304  populateNdArrayColumn<double>(table, column_index, table_hdu, first_row);
305  } else {
306  throw Elements::Exception() << "Cannot populate FITS column with data of type " << type.name();
307  }
308 }
309 
310 } // namespace Table
311 } // end of namespace Euclid
T copy(T...args)
std::vector< T > createSingleNdArrayVectorColumnData(const Euclid::Table::Table &table, size_t column_index)
std::vector< T > createColumnData(const Euclid::Table::Table &table, size_t column_index)
std::vector< std::valarray< T > > createNdArrayColumnData(const Euclid::Table::Table &table, size_t column_index)
T end(T...args)
void populateColumn(const Table &table, size_t column_index, CCfits::ExtHDU &table_hdu, long first_row)
std::vector< T > createSingleValueVectorColumnData(const Euclid::Table::Table &table, size_t column_index)
STL class.
T push_back(T...args)
size_t maxWidthScientific(const Table &table, size_t column_index)
STL class.
std::string scientificFormat(T value)
T max(T...args)
T move(T...args)
T scientific(T...args)
Represents a table.
Definition: Table.h:49
void populateNdArrayColumn(const Table &table, size_t column_index, CCfits::ExtHDU &table_hdu, long first_row)
std::vector< std::valarray< T > > createVectorColumnData(const Euclid::Table::Table &table, size_t column_index)
T begin(T...args)
std::string getTDIM(const Table &table, size_t column_index)
size_t ndArraySize(const Table &table, size_t column_index)
size_t vectorSize(const Table &table, size_t column_index)
std::vector< std::string > getAsciiFormatList(const Table &table)
Returns a vector with strings representing the FITS ASCII table formats for the given table...
void populateVectorColumn(const Table &table, size_t column_index, CCfits::ExtHDU &table_hdu, long first_row)
std::vector< std::string > getBinaryFormatList(const Table &table)
Returns a vector with strings representing the FITS binary table formats for the given table...
size_t maxWidth(const Table &table, size_t column_index)
T emplace_back(T...args)