Alexandria  2.27.0
SDC-CH common library for the Euclid project
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FitsReader.cpp
Go to the documentation of this file.
1 
25 #include <set>
26 
29 #include "ElementsKernel/Unused.h"
30 #include "Table/FitsReader.h"
31 
33 #include "FitsReaderHelper.h"
34 #include "ReaderHelper.h"
35 
36 namespace Euclid {
37 namespace Table {
38 
39 static CCfits::HDU& _readKeys(CCfits::HDU& hdu) {
40  hdu.readAllKeys();
41  return hdu;
42 }
43 
44 FitsReader::FitsReader(const CCfits::HDU& hdu) : m_hdu(hdu) {}
45 
46 FitsReader::FitsReader(const std::string& filename, int hduIndex)
47  : m_fits(Euclid::make_unique<CCfits::FITS>(filename)), m_hdu(_readKeys(m_fits->extension(hduIndex))) {}
48 
49 FitsReader::FitsReader(const std::string& filename, const std::string& hduName)
50  : m_fits(Euclid::make_unique<CCfits::FITS>(filename)), m_hdu(_readKeys(m_fits->extension(hduName))) {}
51 
53  if (m_reading_started) {
54  throw Elements::Exception() << "Fixing the column names after reading "
55  << "has started is not allowed";
56  }
57 
58  m_column_names = std::move(column_names);
59 
61  regex::regex whitespace{".*\\s.*"}; // Checks if input contains any whitespace characters
62  for (const auto& name : m_column_names) {
63  if (name.empty()) {
64  throw Elements::Exception() << "Empty string column names are not allowed";
65  }
66  if (regex_match(name, whitespace)) {
67  throw Elements::Exception() << "Column name '" << name << "' contains "
68  << "whitespace characters";
69  }
70  if (!set.insert(name).second) { // Check for duplicate names
71  throw Elements::Exception() << "Duplicate column name " << name;
72  }
73  }
74 
75  return *this;
76 }
77 
79  if (m_column_info != nullptr) {
80  return;
81  }
82  m_reading_started = true;
83 
84  try {
85  ELEMENTS_UNUSED auto& temp = dynamic_cast<const CCfits::Table&>(m_hdu.get());
86  } catch (std::bad_cast&) {
87  throw Elements::Exception() << "Given HDU is not a table";
88  }
89  const CCfits::Table& table_hdu = dynamic_cast<const CCfits::Table&>(m_hdu.get());
90 
91  m_total_rows = table_hdu.rows();
92 
94  if (m_column_names.empty()) {
95  names = autoDetectColumnNames(table_hdu);
96  } else if (m_column_names.size() != static_cast<size_t>(table_hdu.numCols())) {
97  throw Elements::Exception() << "Columns number in HDU (" << table_hdu.numCols()
98  << ") does not match the column names number (" << m_column_names.size() << ")";
99  } else {
100  names = m_column_names;
101  }
103  autoDetectColumnDescriptions(table_hdu));
104 }
105 
107  readColumnInfo();
108  return *m_column_info;
109 }
110 
112  const CCfits::Table& table_hdu = dynamic_cast<const CCfits::Table&>(m_hdu.get());
113  return table_hdu.comment();
114 }
115 
117  readColumnInfo();
118 
119  // Compute how many rows we are going to read
120  if (m_current_row > m_total_rows) {
121  return Table(m_column_info);
122  }
123  if (rows == -1) {
124  rows = m_total_rows - m_current_row + 1;
125  }
126  rows = std::min(rows, m_total_rows - m_current_row + 1);
127 
128  const CCfits::Table& table_hdu = dynamic_cast<const CCfits::Table&>(m_hdu.get());
129 
130  // CCfits reads per column, so we first read all the columns and then we
131  // create all the rows
133  data.reserve(table_hdu.numCols());
134  for (int i = 1; i <= table_hdu.numCols(); ++i) {
135  // The i-1 is because CCfits starts from 1 and ColumnInfo from 0
136  // We use a clone of the column because CCfits will cache in memory the read data, so multiple calls
137  // to readImpl will steadily increase the memory consumption, which will only be released when
138  // the FitsReader is destroyed (~FitsReader() => ~Table() => ~Column())
139  // For scalars this is not a big deal, but when the column has an array (i.e. a bunch of PDZs), the
140  // pile up can be significant after a while.
141  std::unique_ptr<CCfits::Column> column(table_hdu.column(i).clone());
142  data.emplace_back(
143  translateColumn(*column, m_column_info->getDescription(i - 1).type, m_current_row, m_current_row + rows - 1));
144  }
145 
146  m_current_row += rows;
147 
148  std::vector<Row> row_list;
149  row_list.reserve(rows);
150  for (int i = 0; i < rows; ++i) {
152  cells.reserve(data.size());
153  for (auto& column_data : data) {
154  cells.emplace_back(std::move(column_data[i]));
155  }
156  row_list.emplace_back(cells, m_column_info);
157  }
158 
159  return Table(std::move(row_list));
160 }
161 
162 void FitsReader::skip(long rows) {
163  readColumnInfo();
164  m_current_row += rows;
165 }
166 
168  readColumnInfo();
169  return m_current_row <= m_total_rows;
170 }
171 
173  readColumnInfo();
174  return m_total_rows - m_current_row + 1;
175 }
176 
177 } // namespace Table
178 } // namespace Euclid
static CCfits::HDU & _readKeys(CCfits::HDU &hdu)
Definition: FitsReader.cpp:39
T empty(T...args)
const ColumnInfo & getInfo() override
Returns the column information of the table.
Definition: FitsReader.cpp:106
std::shared_ptr< ColumnInfo > m_column_info
Definition: FitsReader.h:167
FitsReader & fixColumnNames(std::vector< std::string > column_names)
Overrides the column names of the table.
Definition: FitsReader.cpp:52
Table readImpl(long rows) override
Implements the TableReader::readImpl() contract.
Definition: FitsReader.cpp:116
std::reference_wrapper< const CCfits::HDU > m_hdu
Definition: FitsReader.h:162
FitsReader(const CCfits::HDU &hdu)
Creates a FitsReader that reads from the given HDU.
Definition: FitsReader.cpp:44
std::size_t rowsLeft() override
Implements the TableReader::rowsLeft() contract.
Definition: FitsReader.cpp:172
STL class.
STL class.
T min(T...args)
std::vector< std::string > m_column_names
Definition: FitsReader.h:166
T move(T...args)
std::map< std::string, ColumnDescription > autoDetectColumnDescriptions(std::istream &in, const std::string &comment)
Reads the column descriptions of the given stream.
Represents a table.
Definition: Table.h:49
T size(T...args)
STL class.
Provides information about the columns of a Table.
Definition: ColumnInfo.h:52
STL class.
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< std::pair< std::type_index, std::size_t > > autoDetectColumnTypes(const CCfits::Table &table_hdu)
Reads the column types of the given table HDU.
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
void skip(long rows) override
Implements the TableReader::skip() contract.
Definition: FitsReader.cpp:162
TableReader implementation for reading FITS tables.
Definition: FitsReader.h:75
std::shared_ptr< ColumnInfo > createColumnInfo(const std::vector< std::string > &names, const std::vector< std::pair< std::type_index, std::size_t >> &types, const std::vector< std::string > &units, const std::vector< std::string > &descriptions)
Creates a ColumnInfo object from the given names and types.
#define ELEMENTS_UNUSED
bool hasMoreRows() override
Implements the TableReader::hasMoreRows() contract.
Definition: FitsReader.cpp:167
std::vector< std::string > autoDetectColumnUnits(const CCfits::Table &table_hdu)
Reads the column units based on the TUNITn keyword.
T reserve(T...args)
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::string getComment() override
Definition: FitsReader.cpp:111
T emplace_back(T...args)