Alexandria  2.18
Please provide a description of the project.
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  }
171  m_attribute_handlers.push_back(handler);
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
Euclid::Configuration::CatalogConfig::m_attribute_handlers
std::vector< std::shared_ptr< SourceCatalog::AttributeFromRow > > m_attribute_handlers
Definition: CatalogConfig.h:251
Euclid::Configuration::CatalogConfig::m_filename
boost::filesystem::path m_filename
Definition: CatalogConfig.h:248
std::string
STL class.
Euclid::Configuration::CatalogConfig::m_column_info
std::shared_ptr< Table::ColumnInfo > m_column_info
Definition: CatalogConfig.h:252
std::shared_ptr
STL class.
Euclid::Configuration::CatalogConfig::getProgramOptions
std::map< std::string, OptionDescriptionList > getProgramOptions() override
Returns the program options defined by the CatalogConfig.
Definition: CatalogConfig.cpp:48
Euclid::Configuration::CatalogConfig::m_base_dir
boost::filesystem::path m_base_dir
Definition: CatalogConfig.h:247
Euclid::Configuration::Configuration::getCurrentState
State & getCurrentState()
Returns the current state of the configuration.
Definition: Configuration.cpp:43
Euclid::Configuration::CatalogConfig::initialize
void initialize(const UserValues &args) override
Initializes the CatalogConfig instance.
Definition: CatalogConfig.cpp:153
Elements::Logging
std::vector
STL class.
std::map::find
T find(T... args)
Euclid::Configuration::logger
static Elements::Logging logger
Definition: CatalogConfig.cpp:39
Euclid::Configuration::INPUT_CATALOG_FILE
static const std::string INPUT_CATALOG_FILE
Definition: CatalogConfig.cpp:41
std::function
Euclid::SourceCatalog::Catalog
Catalog contains a container of sources.
Definition: Catalog.h:47
Euclid::Configuration::CatalogConfig::preInitialize
void preInitialize(const UserValues &args) override
Checks that all the options are valid. See the exceptions thrown for a detailed list of the checks.
Definition: CatalogConfig.cpp:57
AsciiReader.h
Euclid::Configuration::CatalogConfig::m_fits_format
bool m_fits_format
Definition: CatalogConfig.h:249
Euclid::Configuration::CatalogConfig::readAsCatalog
SourceCatalog::Catalog readAsCatalog() const
Returns the Catalog object.
Definition: CatalogConfig.cpp:226
CatalogFromTable.h
std::map::at
T at(T... args)
Exception.h
Euclid::Configuration::CatalogConfig::addAttributeHandler
void addAttributeHandler(std::shared_ptr< SourceCatalog::AttributeFromRow > handler)
Adds an attribute handler which will be used for adding attributes at the catalog objects.
Definition: CatalogConfig.cpp:167
std::string::c_str
T c_str(T... args)
Euclid::Configuration::CatalogConfig::getIdColumn
std::string getIdColumn() const
Definition: CatalogConfig.cpp:188
std::string::compare
T compare(T... args)
std::array
STL class.
Euclid::Configuration::Configuration::State::FINAL
@ FINAL
The postInitialize() method has been called.
Euclid::Configuration::CatalogConfig::getColumnInfo
std::shared_ptr< Table::ColumnInfo > getColumnInfo() const
Definition: CatalogConfig.cpp:181
Elements::Exception
m_converter
SourceCatalog::CatalogFromTable m_converter
Definition: CatalogConfig.cpp:206
std::map
STL class.
Euclid::Configuration::CatalogConfig::CatalogConfig
CatalogConfig(long manager_id)
Constructs a new CatalogConfig object.
Definition: CatalogConfig.cpp:46
Euclid::Configuration::SOURCE_ID_COLUMN_INDEX
static const std::string SOURCE_ID_COLUMN_INDEX
Definition: CatalogConfig.cpp:44
Elements::Logging::info
void info(const std::string &logMessage)
Elements::Logging::getLogger
static Logging getLogger(const std::string &name="")
FitsReader.h
std
STL namespace.
Euclid::Configuration::CatalogConfig::readAsTable
Table::Table readAsTable() const
Returns the catalog as a Table::Table object.
Definition: CatalogConfig.cpp:218
Euclid::Configuration::CatalogConfig::getTableReader
std::unique_ptr< Table::TableReader > getTableReader() const
Definition: CatalogConfig.cpp:174
Euclid::Configuration::INPUT_CATALOG_FORMAT
static const std::string INPUT_CATALOG_FORMAT
Definition: CatalogConfig.cpp:42
Euclid::Table::Table
Represents a table.
Definition: Table.h:49
std::size_t
Euclid::Configuration::Configuration
Superclass of all configuration classes.
Definition: Configuration.h:45
Logging.h
std::map::end
T end(T... args)
Euclid::Configuration::SOURCE_ID_COLUMN_NAME
static const std::string SOURCE_ID_COLUMN_NAME
Definition: CatalogConfig.cpp:43
memory_tools.h
std::unique_ptr
STL class.
Euclid::Configuration::CatalogConfig::m_id_column_name
std::string m_id_column_name
Definition: CatalogConfig.h:250
Euclid
Definition: InstOrRefHolder.h:29
Euclid::Configuration::CatalogConfig::getTableToCatalogConverter
TableToCatalogConverter getTableToCatalogConverter() const
Definition: CatalogConfig.cpp:211
std::array::data
T data(T... args)
Euclid::Configuration::Configuration::State::INITIALIZED
@ INITIALIZED
The initialize() method has been called.
Euclid::Configuration::CatalogConfig::getFilename
const boost::filesystem::path & getFilename() const
Returns the filename of the input catalog.
Definition: CatalogConfig.cpp:235
Euclid::Configuration::CatalogConfig::setBaseDir
void setBaseDir(const boost::filesystem::path &base_dir)
Sets the directory used when resolving relative paths.
Definition: CatalogConfig.cpp:160
CatalogConfig.h
std::ifstream
STL class.