Alexandria  2.19
Please provide a description of the project.
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
Euclid::Table::createColumnData
std::vector< T > createColumnData(const Euclid::Table::Table &table, size_t column_index)
Definition: FitsWriterHelper.cpp:163
std::string
STL class.
Euclid::Table::vectorSize
size_t vectorSize(const Table &table, size_t column_index)
Definition: FitsWriterHelper.cpp:87
Euclid::Table::populateVectorColumn
void populateVectorColumn(const Table &table, size_t column_index, CCfits::ExtHDU &table_hdu, long first_row)
Definition: FitsWriterHelper.cpp:217
std::move
T move(T... args)
FitsWriterHelper.h
std::vector< std::string >
std::stringstream
STL class.
Euclid::NdArray::NdArray::NdArray
NdArray(const std::vector< size_t > &shape_)
Euclid::NdArray::NdArray
Definition: NdArray.h:46
Euclid::Table::createSingleValueVectorColumnData
std::vector< T > createSingleValueVectorColumnData(const Euclid::Table::Table &table, size_t column_index)
Definition: FitsWriterHelper.cpp:182
std::vector::push_back
T push_back(T... args)
Euclid::Table::getAsciiFormatList
std::vector< std::string > getAsciiFormatList(const Table &table)
Returns a vector with strings representing the FITS ASCII table formats for the given table.
Definition: FitsWriterHelper.cpp:63
Euclid::Table::ndArraySize
size_t ndArraySize(const Table &table, size_t column_index)
Definition: FitsWriterHelper.cpp:98
Exception.h
std::valarray
STL class.
std::copy
T copy(T... args)
Euclid::Table::createNdArrayColumnData
std::vector< std::valarray< T > > createNdArrayColumnData(const Euclid::Table::Table &table, size_t column_index)
Definition: FitsWriterHelper.cpp:192
Elements::Exception
Euclid::Table::populateNdArrayColumn
void populateNdArrayColumn(const Table &table, size_t column_index, CCfits::ExtHDU &table_hdu, long first_row)
Definition: FitsWriterHelper.cpp:227
Euclid::Table::createSingleNdArrayVectorColumnData
std::vector< T > createSingleNdArrayVectorColumnData(const Euclid::Table::Table &table, size_t column_index)
Definition: FitsWriterHelper.cpp:204
Euclid::Table::populateColumn
void populateColumn(const Table &table, size_t column_index, CCfits::ExtHDU &table_hdu, long first_row)
Definition: FitsWriterHelper.cpp:274
std::ostringstream
STL class.
std::vector::emplace_back
T emplace_back(T... args)
Euclid::Table::getBinaryFormatList
std::vector< std::string > getBinaryFormatList(const Table &table)
Returns a vector with strings representing the FITS binary table formats for the given table.
Definition: FitsWriterHelper.cpp:110
std::begin
T begin(T... args)
Euclid::NdArray::NdArray::shape
const std::vector< size_t > shape() const
Definition: NdArray.h:286
Euclid::Table::getTDIM
std::string getTDIM(const Table &table, size_t column_index)
Definition: FitsWriterHelper.cpp:236
std::scientific
T scientific(T... args)
Euclid::Table::Table
Represents a table.
Definition: Table.h:49
std::ostringstream::str
T str(T... args)
std::end
T end(T... args)
Euclid::Table::maxWidth
size_t maxWidth(const Table &table, size_t column_index)
Definition: FitsWriterHelper.cpp:47
Euclid::Table::scientificFormat
std::string scientificFormat(T value)
Definition: FitsWriterHelper.cpp:41
std::max
T max(T... args)
Euclid
Definition: InstOrRefHolder.h:29
Euclid::Table::maxWidthScientific
size_t maxWidthScientific(const Table &table, size_t column_index)
Definition: FitsWriterHelper.cpp:55
Euclid::Table::createVectorColumnData
std::vector< std::valarray< T > > createVectorColumnData(const Euclid::Table::Table &table, size_t column_index)
Definition: FitsWriterHelper.cpp:172
Table.h