Alexandria  2.19
Please provide a description of the project.
FitsReader.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 <set>
26 // The std regex library is not fully implemented in GCC 4.8. The following lines
27 // make use of the BOOST library and can be modified if GCC 4.9 will be used in
28 // the future.
29 // #include <regex>
30 #include <boost/regex.hpp>
31 using boost::regex;
32 using boost::regex_match;
33 
36 #include "ElementsKernel/Unused.h"
37 #include "Table/FitsReader.h"
38 
39 #include "FitsReaderHelper.h"
40 #include "ReaderHelper.h"
41 
42 namespace Euclid {
43 namespace Table {
44 
45 static CCfits::HDU& _readKeys(CCfits::HDU& hdu) {
46  hdu.readAllKeys();
47  return hdu;
48 }
49 
50 FitsReader::FitsReader(const CCfits::HDU& hdu) : m_hdu(hdu) {}
51 
52 FitsReader::FitsReader(const std::string& filename, int hduIndex)
53  : m_fits(Euclid::make_unique<CCfits::FITS>(filename)), m_hdu(_readKeys(m_fits->extension(hduIndex))) {}
54 
55 FitsReader::FitsReader(const std::string& filename, const std::string& hduName)
56  : m_fits(Euclid::make_unique<CCfits::FITS>(filename)), m_hdu(_readKeys(m_fits->extension(hduName))) {}
57 
59  if (m_reading_started) {
60  throw Elements::Exception() << "Fixing the column names after reading "
61  << "has started is not allowed";
62  }
63 
64  m_column_names = std::move(column_names);
65 
67  regex whitespace{".*\\s.*"}; // Checks if input contains any whitespace characters
68  for (const auto& name : m_column_names) {
69  if (name.empty()) {
70  throw Elements::Exception() << "Empty string column names are not allowed";
71  }
72  if (regex_match(name, whitespace)) {
73  throw Elements::Exception() << "Column name '" << name << "' contains "
74  << "whitespace characters";
75  }
76  if (!set.insert(name).second) { // Check for duplicate names
77  throw Elements::Exception() << "Duplicate column name " << name;
78  }
79  }
80 
81  return *this;
82 }
83 
85  if (m_column_info != nullptr) {
86  return;
87  }
88  m_reading_started = true;
89 
90  try {
91  ELEMENTS_UNUSED auto& temp = dynamic_cast<const CCfits::Table&>(m_hdu.get());
92  } catch (std::bad_cast&) {
93  throw Elements::Exception() << "Given HDU is not a table";
94  }
95  const CCfits::Table& table_hdu = dynamic_cast<const CCfits::Table&>(m_hdu.get());
96 
97  m_total_rows = table_hdu.rows();
98 
100  if (m_column_names.empty()) {
101  names = autoDetectColumnNames(table_hdu);
102  } else if (m_column_names.size() != static_cast<size_t>(table_hdu.numCols())) {
103  throw Elements::Exception() << "Columns number in HDU (" << table_hdu.numCols() << ") does not match the column names number ("
104  << m_column_names.size() << ")";
105  } else {
106  names = m_column_names;
107  }
109  autoDetectColumnDescriptions(table_hdu));
110 }
111 
113  readColumnInfo();
114  return *m_column_info;
115 }
116 
118  const CCfits::Table& table_hdu = dynamic_cast<const CCfits::Table&>(m_hdu.get());
119  return table_hdu.comment();
120 }
121 
123  readColumnInfo();
124 
125  // Compute how many rows we are going to read
126  if (m_current_row > m_total_rows) {
127  throw Elements::Exception() << "No more table rows left";
128  }
129  if (rows == -1) {
130  rows = m_total_rows - m_current_row + 1;
131  }
132  rows = std::min(rows, m_total_rows - m_current_row + 1);
133 
134  const CCfits::Table& table_hdu = dynamic_cast<const CCfits::Table&>(m_hdu.get());
135 
136  // CCfits reads per column, so we first read all the columns and then we
137  // create all the rows
139  for (int i = 1; i <= table_hdu.numCols(); ++i) {
140  // The i-1 is because CCfits starts from 1 and ColumnInfo from 0
141  data.push_back(
142  translateColumn(table_hdu.column(i), m_column_info->getDescription(i - 1).type, m_current_row, m_current_row + rows - 1));
143  }
144 
145  m_current_row += rows;
146 
147  std::vector<Row> row_list;
148  for (int i = 0; i < rows; ++i) {
150  for (const auto& column_data : data) {
151  cells.push_back(column_data[i]);
152  }
153  row_list.push_back(Row{cells, m_column_info});
154  }
155 
156  return Table{row_list};
157 }
158 
159 void FitsReader::skip(long rows) {
160  readColumnInfo();
161  m_current_row += rows;
162 }
163 
165  readColumnInfo();
166  return m_current_row < m_total_rows;
167 }
168 
170  readColumnInfo();
171  return m_total_rows - m_current_row + 1;
172 }
173 
174 } // namespace Table
175 } // namespace Euclid
Provides information about the columns of a Table.
Definition: ColumnInfo.h:52
TableReader implementation for reading FITS tables.
Definition: FitsReader.h:75
void skip(long rows) override
Implements the TableReader::skip() contract.
Definition: FitsReader.cpp:159
std::vector< std::string > m_column_names
Definition: FitsReader.h:166
FitsReader(const CCfits::HDU &hdu)
Creates a FitsReader that reads from the given HDU.
Definition: FitsReader.cpp:50
bool hasMoreRows() override
Implements the TableReader::hasMoreRows() contract.
Definition: FitsReader.cpp:164
const ColumnInfo & getInfo() override
Returns the column information of the table.
Definition: FitsReader.cpp:112
Table readImpl(long rows) override
Implements the TableReader::readImpl() contract.
Definition: FitsReader.cpp:122
std::reference_wrapper< const CCfits::HDU > m_hdu
Definition: FitsReader.h:162
std::shared_ptr< ColumnInfo > m_column_info
Definition: FitsReader.h:167
std::size_t rowsLeft() override
Implements the TableReader::rowsLeft() contract.
Definition: FitsReader.cpp:169
std::string getComment() override
Definition: FitsReader.cpp:117
FitsReader & fixColumnNames(std::vector< std::string > column_names)
Overrides the column names of the table.
Definition: FitsReader.cpp:58
Represents one row of a Table.
Definition: Row.h:64
Represents a table.
Definition: Table.h:49
T empty(T... args)
#define ELEMENTS_UNUSED
T min(T... args)
T move(T... args)
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::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::shared_ptr< ColumnInfo > createColumnInfo(const std::vector< std::string > &names, const std::vector< std::type_index > &types, const std::vector< std::string > &units, const std::vector< std::string > &descriptions)
Creates a ColumnInfo object from the given names and types.
static CCfits::HDU & _readKeys(CCfits::HDU &hdu)
Definition: FitsReader.cpp:45
std::unique_ptr< T > make_unique(Args &&... args)
Constructs an object of type T and wraps it in a std::unique_ptr using args as the parameter list for...
Definition: memory_tools.h:42
T push_back(T... args)
T size(T... args)