Alexandria  2.14.1
Please provide a description of the project.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
FitsWriterHelper.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012-2020 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 <algorithm>
26 #include <sstream>
27 #include <iomanip>
28 #include <valarray>
29 #include <boost/lexical_cast.hpp>
30 #include <CCfits/CCfits>
31 #include "FitsWriterHelper.h"
32 #include "Table/Table.h"
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<bool>)) {
144  size_t size = ndArraySize<bool>(table, column_index);
145  format_list.push_back(boost::lexical_cast<std::string>(size) + "L");
146  } else if (type == typeid(NdArray<int32_t>)) {
147  size_t size = ndArraySize<int32_t>(table, column_index);
148  format_list.push_back(boost::lexical_cast<std::string>(size) + "J");
149  } else if (type == typeid(NdArray<int64_t>)) {
150  size_t size = ndArraySize<int64_t>(table, column_index);
151  format_list.push_back(boost::lexical_cast<std::string>(size) + "K");
152  } else if (type == typeid(NdArray<float>)) {
153  size_t size = ndArraySize<float>(table, column_index);
154  format_list.push_back(boost::lexical_cast<std::string>(size) + "E");
155  } else if (type == typeid(NdArray<double>)) {
156  size_t size = ndArraySize<double>(table, column_index);
157  format_list.push_back(boost::lexical_cast<std::string>(size) + "D");
158  } else {
159  throw Elements::Exception() << "Unsupported column format for FITS binary table export: " << type.name();
160  }
161  }
162  return format_list;
163 }
164 
165 template<typename T>
166 std::vector<T> createColumnData(const Euclid::Table::Table& table, size_t column_index) {
167  std::vector<T> data {};
168  for (const auto& row : table) {
169  data.push_back(boost::get<T>(row[column_index]));
170  }
171  return data;
172 }
173 
174 template <typename T>
176  std::vector<std::valarray<T>> result {};
177  for (auto& row : table) {
178  const auto& vec = boost::get<std::vector<T>>(row[column_index]);
179  result.emplace_back(vec.data(), vec.size());
180  }
181  return result;
182 }
183 
184 template <typename T>
186  std::vector<T> result {};
187  for (auto& row : table) {
188  const auto& vec = boost::get<std::vector<T>>(row[column_index]);
189  result.push_back(vec.front());
190  }
191  return result;
192 }
193 
194 template <typename T>
197  for (auto& row : table) {
198  const auto& ndarray = boost::get<NdArray<T>>(row[column_index]);
199  result.emplace_back(ndarray.data().data(), ndarray.size());
200  }
201  return result;
202 }
203 
204 template <typename T>
206  std::vector<T> result {};
207  for (auto& row : table) {
208  const auto& nd = boost::get<NdArray<T>>(row[column_index]);
209  if (nd.size() > 0)
210  result.push_back(*nd.begin());
211  else
212  result.push_back(0);
213  }
214  return result;
215 }
216 
217 template <typename T>
218 void populateVectorColumn(const Table& table, size_t column_index, CCfits::ExtHDU& table_hdu, long first_row) {
219  const auto& vec = boost::get<std::vector<T>>(table[0][column_index]);
220  if (vec.size() > 1) {
221  table_hdu.column(column_index+1).writeArrays(createVectorColumnData<T>(table, column_index), first_row);
222  } else {
223  table_hdu.column(column_index+1).write(createSingleValueVectorColumnData<T>(table, column_index), first_row);
224  }
225 }
226 
227 template <typename T>
228 void populateNdArrayColumn(const Table& table, size_t column_index, CCfits::ExtHDU& table_hdu, long first_row) {
229  const auto& nd = boost::get<NdArray<T>>(table[0][column_index]);
230  if (nd.size() > 1) {
231  table_hdu.column(column_index + 1).writeArrays(createNdArrayColumnData<T>(table, column_index), first_row);
232  }
233  else {
234  table_hdu.column(column_index+1).write(createSingleNdArrayVectorColumnData<T>(table, column_index), first_row);
235  }
236 }
237 
238 std::string getTDIM(const Table& table, size_t column_index) {
239  auto& first_row = table[0];
240  auto& cell = first_row[column_index];
241  auto type = table.getColumnInfo()->getDescription(column_index).type;
242  std::vector<size_t> shape;
243 
244  if (type == typeid(NdArray<bool>)) {
245  shape = boost::get<NdArray<bool>>(cell).shape();
246  } else if (type == typeid(NdArray<int32_t>)) {
247  shape = boost::get<NdArray<int32_t>>(cell).shape();
248  } else if (type == typeid(NdArray<int64_t>)) {
249  shape = boost::get<NdArray<int64_t>>(cell).shape();
250  } else if (type == typeid(NdArray<float>)) {
251  shape = boost::get<NdArray<float>>(cell).shape();
252  } else if (type == typeid(NdArray<double>)) {
253  shape = boost::get<NdArray<double>>(cell).shape();
254  } else {
255  return "";
256  }
257 
258  int64_t ncells = 1;
259  for (auto &axis : shape) {
260  ncells *= axis;
261  }
262  if (ncells == 1) {
263  return "";
264  }
265 
266  std::stringstream stream;
267  stream << '(';
268 
269  int j;
270  for (j = shape.size() - 1; j > 0; --j) {
271  stream << shape[j] << ",";
272  }
273 
274  stream << shape[j] << ')';
275  return stream.str();
276 }
277 
278 void populateColumn(const Table& table, size_t column_index, CCfits::ExtHDU& table_hdu, long first_row) {
279  auto type = table.getColumnInfo()->getDescription(column_index).type;
280  // CCfits indices start from 1
281  if (type == typeid(bool)) {
282  table_hdu.column(column_index+1).write(createColumnData<bool>(table, column_index), first_row);
283  } else if (type == typeid(int32_t)) {
284  table_hdu.column(column_index+1).write(createColumnData<int32_t>(table, column_index), first_row);
285  } else if (type == typeid(int64_t)) {
286  table_hdu.column(column_index+1).write(createColumnData<int64_t>(table, column_index), first_row);
287  } else if (type == typeid(float)) {
288  table_hdu.column(column_index+1).write(createColumnData<float>(table, column_index), first_row);
289  } else if (type == typeid(double)) {
290  table_hdu.column(column_index+1).write(createColumnData<double>(table, column_index), first_row);
291  } else if (type == typeid(std::string)) {
292  table_hdu.column(column_index+1).write(createColumnData<std::string>(table, column_index), first_row);
293  } else if (type == typeid(std::vector<int32_t>)) {
294  populateVectorColumn<int32_t>(table, column_index, table_hdu, first_row);
295  } else if (type == typeid(std::vector<int64_t>)) {
296  populateVectorColumn<int64_t>(table, column_index, table_hdu, first_row);
297  } else if (type == typeid(std::vector<float>)) {
298  populateVectorColumn<float>(table, column_index, table_hdu, first_row);
299  } else if (type == typeid(std::vector<double>)) {
300  populateVectorColumn<double>(table, column_index, table_hdu, first_row);
301  } else if (type == typeid(NdArray<int32_t>)) {
302  populateNdArrayColumn<int32_t>(table, column_index, table_hdu, first_row);
303  } else if (type == typeid(NdArray<int64_t>)) {
304  populateNdArrayColumn<int64_t>(table, column_index, table_hdu, first_row);
305  } else if (type == typeid(NdArray<float>)) {
306  populateNdArrayColumn<float>(table, column_index, table_hdu, first_row);
307  } else if (type == typeid(NdArray<double>)) {
308  populateNdArrayColumn<double>(table, column_index, table_hdu, first_row);
309  } else {
310  throw Elements::Exception() << "Cannot populate FITS column with data of type " << type.name();
311  }
312 }
313 
314 }
315 } // end of namespace Euclid
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)
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)
std::string scientificFormat(T value)
T max(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)
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)