Alexandria  2.14.1
Please provide a description of the project.
FitsReader.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 <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 
35 #include "ElementsKernel/Unused.h"
37 #include "Table/FitsReader.h"
38 
39 #include "ReaderHelper.h"
40 #include "FitsReaderHelper.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 
53 FitsReader::FitsReader(const std::string& filename, int hduIndex)
54  : m_fits(make_unique<CCfits::FITS>(filename)), m_hdu(_readKeys(m_fits->extension(hduIndex))) {
55 }
56 
57 FitsReader::FitsReader(const std::string& filename, const std::string& hduName)
58  : m_fits(make_unique<CCfits::FITS>(filename)), m_hdu(_readKeys(m_fits->extension(hduName))) {
59 }
60 
62  if (m_reading_started) {
63  throw Elements::Exception() << "Fixing the column names after reading "
64  << "has started is not allowed";
65  }
66 
67  m_column_names = std::move(column_names);
68 
69  std::set<std::string> set {};
70  regex whitespace {".*\\s.*"}; // Checks if input contains any whitespace characters
71  for (const auto& name : m_column_names) {
72  if (name.empty()) {
73  throw Elements::Exception() << "Empty string column names are not allowed";
74  }
75  if (regex_match(name, whitespace)) {
76  throw Elements::Exception() << "Column name '" << name << "' contains "
77  << "whitespace characters";
78  }
79  if (!set.insert(name).second) { // Check for duplicate names
80  throw Elements::Exception() << "Duplicate column name " << name;
81  }
82  }
83 
84  return *this;
85 }
86 
88  if (m_column_info != nullptr) {
89  return;
90  }
91  m_reading_started = true;
92 
93  try {
94  ELEMENTS_UNUSED auto& temp = dynamic_cast<const CCfits::Table&>(m_hdu.get());
95  } catch (std::bad_cast&) {
96  throw Elements::Exception() << "Given HDU is not a table";
97  }
98  const CCfits::Table& table_hdu = dynamic_cast<const CCfits::Table&>(m_hdu.get());
99 
100  m_total_rows = table_hdu.rows();
101 
102  std::vector<std::string> names {};
103  if (m_column_names.empty()) {
104  names = autoDetectColumnNames(table_hdu);
105  } else if (m_column_names.size() != static_cast<size_t>(table_hdu.numCols())) {
106  throw Elements::Exception() << "Columns number in HDU (" << table_hdu.numCols()
107  << ") does not match the column names number ("
108  << m_column_names.size() << ")";
109  } else {
110  names = m_column_names;
111  }
113  autoDetectColumnUnits(table_hdu), autoDetectColumnDescriptions(table_hdu));
114 }
115 
117  readColumnInfo();
118  return *m_column_info;
119 }
120 
122  const CCfits::Table& table_hdu = dynamic_cast<const CCfits::Table&>(m_hdu.get());
123  return table_hdu.comment();
124 }
125 
127  readColumnInfo();
128 
129  // Compute how many rows we are going to read
130  if (m_current_row > m_total_rows) {
131  throw Elements::Exception() << "No more table rows left";
132  }
133  if (rows == -1) {
134  rows = m_total_rows - m_current_row + 1;
135  }
136  rows = std::min(rows, m_total_rows-m_current_row+1);
137 
138  const CCfits::Table& table_hdu = dynamic_cast<const CCfits::Table&>(m_hdu.get());
139 
140  // CCfits reads per column, so we first read all the columns and then we
141  // create all the rows
143  for (int i=1; i<=table_hdu.numCols(); ++i) {
144  // The i-1 is because CCfits starts from 1 and ColumnInfo from 0
145  data.push_back(translateColumn(table_hdu.column(i), m_column_info->getDescription(i-1).type, m_current_row, m_current_row + rows - 1));
146  }
147 
148  m_current_row += rows;
149 
150  std::vector<Row> row_list;
151  for (int i=0; i<rows; ++i) {
153  for (const auto& column_data : data) {
154  cells.push_back(column_data[i]);
155  }
156  row_list.push_back(Row{cells, m_column_info});
157  }
158 
159  return Table{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 
178 } // Table namespace
179 } // Euclid namespace
180 
181 
182 
Euclid::Table::createColumnInfo
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.
Definition: ReaderHelper.cpp:30
Euclid::Table::FitsReader::readColumnInfo
void readColumnInfo()
Definition: FitsReader.cpp:87
std::string
STL class.
std::move
T move(T... args)
Euclid::Table::FitsReader::getInfo
const ColumnInfo & getInfo() override
Returns the column information of the table.
Definition: FitsReader.cpp:116
Euclid::Table::FitsReader::m_hdu
std::reference_wrapper< const CCfits::HDU > m_hdu
Definition: FitsReader.h:165
Euclid::Table::FitsReader::getComment
std::string getComment() override
Definition: FitsReader.cpp:121
Euclid::Table::autoDetectColumnDescriptions
std::map< std::string, ColumnDescription > autoDetectColumnDescriptions(std::istream &in, const std::string &comment)
Reads the column descriptions of the given stream.
Definition: AsciiReaderHelper.cpp:111
Euclid::Table::translateColumn
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.
Definition: FitsReaderHelper.cpp:200
std::vector< std::string >
Euclid::Table::FitsReader::readImpl
Table readImpl(long rows) override
Implements the TableReader::readImpl() contract.
Definition: FitsReader.cpp:126
std::vector::size
T size(T... args)
Euclid::Table::FitsReader::m_current_row
long m_current_row
Definition: FitsReader.h:168
std::reference_wrapper::get
T get(T... args)
Euclid::Table::FitsReader::fixColumnNames
FitsReader & fixColumnNames(std::vector< std::string > column_names)
Overrides the column names of the table.
Definition: FitsReader.cpp:61
std::bad_cast
STL class.
std::vector::push_back
T push_back(T... args)
Euclid::Table::FitsReader::FitsReader
FitsReader(const CCfits::HDU &hdu)
Creates a FitsReader that reads from the given HDU.
Definition: FitsReader.cpp:50
Euclid::Table::ColumnInfo
Provides information about the columns of a Table.
Definition: ColumnInfo.h:52
Exception.h
Euclid::Table::FitsReader::rowsLeft
std::size_t rowsLeft() override
Implements the TableReader::rowsLeft() contract.
Definition: FitsReader.cpp:172
Euclid::Table::autoDetectColumnNames
std::vector< std::string > autoDetectColumnNames(std::istream &in, const std::string &comment, size_t columns_number)
Reads the column names of the given stream.
Definition: AsciiReaderHelper.cpp:178
Elements::Exception
Euclid::Table::autoDetectColumnUnits
std::vector< std::string > autoDetectColumnUnits(const CCfits::Table &table_hdu)
Reads the column units based on the TUNITn keyword.
Definition: FitsReaderHelper.cpp:144
Euclid::Table::FitsReader::m_total_rows
long m_total_rows
Definition: FitsReader.h:167
Euclid::make_unique
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:41
std::min
T min(T... args)
Euclid::Table::FitsReader::m_column_names
std::vector< std::string > m_column_names
Definition: FitsReader.h:169
FitsReader.h
Euclid::Table::FitsReader
TableReader implementation for reading FITS tables.
Definition: FitsReader.h:75
Euclid::Table::_readKeys
static CCfits::HDU & _readKeys(CCfits::HDU &hdu)
Definition: FitsReader.cpp:45
Euclid::Table::autoDetectColumnTypes
std::vector< std::type_index > autoDetectColumnTypes(const CCfits::Table &table_hdu)
Reads the column types of the given table HDU.
Definition: FitsReaderHelper.cpp:129
ReaderHelper.h
Euclid::Table::Table
Represents a table.
Definition: Table.h:49
std::vector::empty
T empty(T... args)
std::size_t
Euclid::Table::Row
Represents one row of a Table.
Definition: Row.h:64
Unused.h
memory_tools.h
Euclid
Definition: InstOrRefHolder.h:29
FitsReaderHelper.h
Euclid::Table::FitsReader::hasMoreRows
bool hasMoreRows() override
Implements the TableReader::hasMoreRows() contract.
Definition: FitsReader.cpp:167
Euclid::Table::FitsReader::m_column_info
std::shared_ptr< ColumnInfo > m_column_info
Definition: FitsReader.h:170
Euclid::Table::FitsReader::skip
void skip(long rows) override
Implements the TableReader::skip() contract.
Definition: FitsReader.cpp:162
std::set
STL class.
ELEMENTS_UNUSED
#define ELEMENTS_UNUSED
Euclid::Table::FitsReader::m_reading_started
bool m_reading_started
Definition: FitsReader.h:166