Alexandria  2.18
Please provide a description of the project.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CatalogConfig.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 the terms of the GNU Lesser General
5  * Public License as published by the Free Software Foundation; either version 3.0 of the License, or (at your option)
6  * any later version.
7  *
8  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
9  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
10  * details.
11  *
12  * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to
13  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
14  */
15 
25 #include "ElementsKernel/Logging.h"
27 #include "Table/AsciiReader.h"
28 #include "Table/FitsReader.h"
29 #include <CCfits/CCfits>
30 #include <array>
31 #include <fstream>
32 
33 namespace po = boost::program_options;
34 namespace fs = boost::filesystem;
35 
36 namespace Euclid {
37 namespace Configuration {
38 
40 
41 static const std::string INPUT_CATALOG_FILE{"input-catalog-file"};
42 static const std::string INPUT_CATALOG_FORMAT{"input-catalog-format"};
43 static const std::string SOURCE_ID_COLUMN_NAME{"source-id-column-name"};
44 static const std::string SOURCE_ID_COLUMN_INDEX{"source-id-column-index"};
45 
46 CatalogConfig::CatalogConfig(long manager_id) : Configuration(manager_id) {}
47 
49  return {{"Input catalog options",
50  {{INPUT_CATALOG_FILE.c_str(), po::value<std::string>()->required(), "The file containing the input catalog"},
51  {INPUT_CATALOG_FORMAT.c_str(), po::value<std::string>()->default_value("AUTO"),
52  "The format of the input catalog (AUTO, FITS or ASCII)"},
53  {SOURCE_ID_COLUMN_NAME.c_str(), po::value<std::string>(), "The name of the column representing the source ID"},
54  {SOURCE_ID_COLUMN_INDEX.c_str(), po::value<int>(), "The index of the column representing the source ID"}}}};
55 }
56 
58 
59  if (args.find(SOURCE_ID_COLUMN_NAME) != args.end() && args.find(SOURCE_ID_COLUMN_INDEX) != args.end()) {
60  throw Elements::Exception() << "Options " << SOURCE_ID_COLUMN_NAME << " and " << SOURCE_ID_COLUMN_INDEX
61  << " are mutually exclusive";
62  }
63 
64  if (args.find(SOURCE_ID_COLUMN_INDEX) != args.end() && args.at(SOURCE_ID_COLUMN_INDEX).as<int>() < 1) {
65  throw Elements::Exception() << SOURCE_ID_COLUMN_INDEX << " must be a one-based "
66  << "index but was " << args.at(SOURCE_ID_COLUMN_INDEX).as<int>();
67  }
68 
69  if (args.find(INPUT_CATALOG_FORMAT) != args.end() && args.at(INPUT_CATALOG_FORMAT).as<std::string>() != "AUTO" &&
70  args.at(INPUT_CATALOG_FORMAT).as<std::string>() != "FITS" && args.at(INPUT_CATALOG_FORMAT).as<std::string>() != "ASCII") {
71  throw Elements::Exception() << INPUT_CATALOG_FORMAT << "must be one of "
72  << "AUTO, FITS or ASCII, but was " << args.at(INPUT_CATALOG_FORMAT).as<std::string>();
73  }
74 }
75 
76 namespace {
77 
78 fs::path getCatalogFileFromOptions(const Configuration::UserValues& args, const fs::path& base_dir) {
79  fs::path catalog_file{args.at(INPUT_CATALOG_FILE).as<std::string>()};
80  if (catalog_file.is_relative()) {
81  catalog_file = base_dir / catalog_file;
82  }
83  if (!fs::exists(catalog_file)) {
84  throw Elements::Exception() << "Input catalog file " << catalog_file << " does not exist";
85  }
86  if (fs::is_directory(catalog_file)) {
87  throw Elements::Exception() << "Input catalog file " << catalog_file << " is not a file";
88  }
89  return catalog_file;
90 }
91 
92 enum class FormatType { FITS, ASCII };
93 
94 FormatType autoDetectFormatType(fs::path file) {
95  logger.info() << "Auto-detecting format of file " << file;
96  FormatType result = FormatType::ASCII;
97  {
98  std::ifstream in{file.string()};
99  std::array<char, 80> first_header_array;
100  in.read(first_header_array.data(), 80);
101  in.close();
102  std::string first_header_str{first_header_array.data()};
103  if (first_header_str.compare(0, 9, "SIMPLE =") == 0) {
104  result = FormatType::FITS;
105  }
106  }
107  logger.info() << "Detected " << (result == FormatType::FITS ? "FITS" : "ASCII") << " format";
108  return result;
109 }
110 
111 FormatType getFormatTypeFromOptions(const Configuration::UserValues& args, const fs::path& file) {
112  FormatType format;
113  if (args.at(INPUT_CATALOG_FORMAT).as<std::string>().compare("AUTO") == 0) {
114  format = autoDetectFormatType(file);
115  } else if (args.at(INPUT_CATALOG_FORMAT).as<std::string>().compare("FITS") == 0) {
116  format = FormatType::FITS;
117  } else {
118  format = FormatType::ASCII;
119  }
120  return format;
121 }
122 
123 std::unique_ptr<Table::TableReader> getTableReaderImpl(bool fits_format, const boost::filesystem::path& filename) {
124  if (fits_format) {
125  return Euclid::make_unique<Table::FitsReader>(filename.native(), 1);
126  } else {
127  return Euclid::make_unique<Table::AsciiReader>(filename.native());
128  }
129 }
130 
131 std::string getIdColumnFromOptions(const Configuration::UserValues& args, const Table::ColumnInfo& column_info) {
132  std::string id_column_name = "ID";
133  if (args.find(SOURCE_ID_COLUMN_NAME) != args.end()) {
134  id_column_name = args.at(SOURCE_ID_COLUMN_NAME).as<std::string>();
135  if (column_info.find(id_column_name) == nullptr) {
136  throw Elements::Exception() << "Input catalog file does not contain the "
137  << "ID column with name " << id_column_name;
138  }
139  }
140  if (args.find(SOURCE_ID_COLUMN_INDEX) != args.end()) {
141  std::size_t index = args.at(SOURCE_ID_COLUMN_INDEX).as<int>();
142  if (index > column_info.size()) {
143  throw Elements::Exception() << SOURCE_ID_COLUMN_INDEX << " (" << index << ") is out of range (" << column_info.size() << ")";
144  }
145  id_column_name = column_info.getDescription(index - 1).name;
146  }
147  logger.info() << "Using ID column \"" << id_column_name << '"';
148  return id_column_name;
149 }
150 
151 } // Anonymous namespace
152 
154  m_filename = getCatalogFileFromOptions(args, m_base_dir);
155  m_fits_format = getFormatTypeFromOptions(args, m_filename) == FormatType::FITS;
156  m_column_info = std::make_shared<Table::ColumnInfo>(getTableReaderImpl(m_fits_format, m_filename)->getInfo());
157  m_id_column_name = getIdColumnFromOptions(args, *m_column_info);
158 }
159 
160 void CatalogConfig::setBaseDir(const fs::path& base_dir) {
162  throw Elements::Exception() << "setBaseDir() call to initialized CatalogConfig";
163  }
164  m_base_dir = base_dir;
165 }
166 
168  if (getCurrentState() >= State::FINAL) {
169  throw Elements::Exception() << "addAttributeHandler() call to finalized CatalogConfig";
170  }
172 }
173 
175  if (getCurrentState() < State::FINAL) {
176  throw Elements::Exception() << "getTableReader() call to not finalized CatalogConfig";
177  }
178  return getTableReaderImpl(m_fits_format, m_filename);
179 }
180 
183  throw Elements::Exception() << "getColumnInfo() call to uninitialized CatalogConfig";
184  }
185  return m_column_info;
186 }
187 
189  return m_id_column_name;
190 }
191 
192 namespace {
193 
194 class ConverterImpl {
195 
196 public:
197  ConverterImpl(std::shared_ptr<Table::ColumnInfo> column_info, const std::string& id_column_name,
199  : m_converter(column_info, id_column_name, std::move(attribute_handlers)) {}
200 
201  SourceCatalog::Catalog operator()(const Table::Table& table) {
202  return m_converter.createCatalog(table);
203  }
204 
205 private:
206  SourceCatalog::CatalogFromTable m_converter;
207 };
208 
209 } // Anonymous namespace
210 
212  if (getCurrentState() < State::FINAL) {
213  throw Elements::Exception() << "getTableToCatalogConverter() call to not finalized CatalogConfig";
214  }
215  return ConverterImpl{m_column_info, m_id_column_name, m_attribute_handlers};
216 }
217 
219  if (getCurrentState() < State::FINAL) {
220  throw Elements::Exception() << "getAsTable() call to not finalized CatalogConfig";
221  }
222  logger.info() << "Reading table from file " << m_filename;
223  return getTableReader()->read();
224 }
225 
227  if (getCurrentState() < State::FINAL) {
228  throw Elements::Exception() << "getCatalog() call to not finalized CatalogConfig";
229  }
230  auto table = readAsTable();
231  auto converter = getTableToCatalogConverter();
232  return converter(table);
233 }
234 
235 const boost::filesystem::path& CatalogConfig::getFilename() const {
237  throw Elements::Exception() << "getFilename() call to not finalized CatalogConfig";
238  }
239  return m_filename;
240 }
241 
242 } // namespace Configuration
243 } // namespace Euclid
static const std::string SOURCE_ID_COLUMN_NAME
SourceCatalog::Catalog readAsCatalog() const
Returns the Catalog object.
TableToCatalogConverter getTableToCatalogConverter() const
Superclass of all configuration classes.
Definition: Configuration.h:45
void addAttributeHandler(std::shared_ptr< SourceCatalog::AttributeFromRow > handler)
Adds an attribute handler which will be used for adding attributes at the catalog objects...
std::shared_ptr< Table::ColumnInfo > getColumnInfo() const
static const std::string SOURCE_ID_COLUMN_INDEX
static const std::string INPUT_CATALOG_FILE
void info(const std::string &logMessage)
T end(T...args)
State & getCurrentState()
Returns the current state of the configuration.
STL class.
STL class.
boost::filesystem::path m_base_dir
T at(T...args)
void initialize(const UserValues &args) override
Initializes the CatalogConfig instance.
T push_back(T...args)
T data(T...args)
std::vector< std::shared_ptr< SourceCatalog::AttributeFromRow > > m_attribute_handlers
The postInitialize() method has been called.
void preInitialize(const UserValues &args) override
Checks that all the options are valid. See the exceptions thrown for a detailed list of the checks...
static Elements::Logging logger
void setBaseDir(const boost::filesystem::path &base_dir)
Sets the directory used when resolving relative paths.
Represents a table.
Definition: Table.h:49
T find(T...args)
Table::Table readAsTable() const
Returns the catalog as a Table::Table object.
STL class.
STL class.
const boost::filesystem::path & getFilename() const
Returns the filename of the input catalog.
std::unique_ptr< Table::TableReader > getTableReader() const
boost::filesystem::path m_filename
T c_str(T...args)
CatalogConfig(long manager_id)
Constructs a new CatalogConfig object.
STL class.
std::shared_ptr< Table::ColumnInfo > m_column_info
Catalog contains a container of sources.
Definition: Catalog.h:47
SourceCatalog::CatalogFromTable m_converter
std::map< std::string, OptionDescriptionList > getProgramOptions() override
Returns the program options defined by the CatalogConfig.
static Logging getLogger(const std::string &name="")
The initialize() method has been called.
static const std::string INPUT_CATALOG_FORMAT
STL class.