Alexandria 2.31.0
SDC-CH common library for the Euclid project
Loading...
Searching...
No Matches
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
27#include "Table/AsciiReader.h"
28#include "Table/FitsReader.h"
29#include <CCfits/CCfits>
30#include <array>
31#include <fstream>
32
33namespace po = boost::program_options;
34namespace fs = boost::filesystem;
35
36namespace Euclid {
37namespace Configuration {
38
40
41static const std::string INPUT_CATALOG_FILE{"input-catalog-file"};
42static const std::string INPUT_CATALOG_FORMAT{"input-catalog-format"};
43static const std::string SOURCE_ID_COLUMN_NAME{"source-id-column-name"};
44static const std::string SOURCE_ID_COLUMN_INDEX{"source-id-column-index"};
45
46CatalogConfig::CatalogConfig(long manager_id) : Configuration(manager_id) {}
47
49 return {
50 {"Input catalog options",
51 {{INPUT_CATALOG_FILE.c_str(), po::value<std::string>()->required(), "The file containing the input catalog"},
52 {INPUT_CATALOG_FORMAT.c_str(), po::value<std::string>()->default_value("AUTO"),
53 "The format of the input catalog (AUTO, FITS or ASCII)"},
54 {SOURCE_ID_COLUMN_NAME.c_str(), po::value<std::string>(), "The name of the column representing the source ID"},
55 {SOURCE_ID_COLUMN_INDEX.c_str(), po::value<int>(), "The index of the column representing the source ID"}}}};
56}
57
59
60 if (args.find(SOURCE_ID_COLUMN_NAME) != args.end() && args.find(SOURCE_ID_COLUMN_INDEX) != args.end()) {
61 throw Elements::Exception() << "Options " << SOURCE_ID_COLUMN_NAME << " and " << SOURCE_ID_COLUMN_INDEX
62 << " are mutually exclusive";
63 }
64
65 if (args.find(SOURCE_ID_COLUMN_INDEX) != args.end() && args.at(SOURCE_ID_COLUMN_INDEX).as<int>() < 1) {
66 throw Elements::Exception() << SOURCE_ID_COLUMN_INDEX << " must be a one-based "
67 << "index but was " << args.at(SOURCE_ID_COLUMN_INDEX).as<int>();
68 }
69
70 if (args.find(INPUT_CATALOG_FORMAT) != args.end() && args.at(INPUT_CATALOG_FORMAT).as<std::string>() != "AUTO" &&
71 args.at(INPUT_CATALOG_FORMAT).as<std::string>() != "FITS" &&
72 args.at(INPUT_CATALOG_FORMAT).as<std::string>() != "ASCII") {
73 throw Elements::Exception() << INPUT_CATALOG_FORMAT << "must be one of "
74 << "AUTO, FITS or ASCII, but was " << args.at(INPUT_CATALOG_FORMAT).as<std::string>();
75 }
76}
77
78namespace {
79
80fs::path getCatalogFileFromOptions(const Configuration::UserValues& args, const fs::path& base_dir) {
81 fs::path catalog_file{args.at(INPUT_CATALOG_FILE).as<std::string>()};
82 if (catalog_file.is_relative()) {
83 catalog_file = base_dir / catalog_file;
84 }
85 if (!fs::exists(catalog_file)) {
86 throw Elements::Exception() << "Input catalog file " << catalog_file << " does not exist";
87 }
88 if (fs::is_directory(catalog_file)) {
89 throw Elements::Exception() << "Input catalog file " << catalog_file << " is not a file";
90 }
91 return catalog_file;
92}
93
94enum class FormatType { FITS, ASCII };
95
96FormatType autoDetectFormatType(fs::path file) {
97 logger.info() << "Auto-detecting format of file " << file;
98 FormatType result = FormatType::ASCII;
99 {
100 std::ifstream in{file.string()};
101 std::array<char, 81> first_header_array;
102 in.read(first_header_array.data(), 80);
103 first_header_array.back() = '\0';
104 in.close();
105 std::string first_header_str{first_header_array.data()};
106 if (first_header_str.compare(0, 9, "SIMPLE =") == 0) {
107 result = FormatType::FITS;
108 }
109 }
110 logger.info() << "Detected " << (result == FormatType::FITS ? "FITS" : "ASCII") << " format";
111 return result;
112}
113
114FormatType getFormatTypeFromOptions(const Configuration::UserValues& args, const fs::path& file) {
115 FormatType format;
116 if (args.at(INPUT_CATALOG_FORMAT).as<std::string>().compare("AUTO") == 0) {
117 format = autoDetectFormatType(file);
118 } else if (args.at(INPUT_CATALOG_FORMAT).as<std::string>().compare("FITS") == 0) {
119 format = FormatType::FITS;
120 } else {
121 format = FormatType::ASCII;
122 }
123 return format;
124}
125
126std::unique_ptr<Table::TableReader> getTableReaderImpl(bool fits_format, const boost::filesystem::path& filename) {
127 if (fits_format) {
128 return Euclid::make_unique<Table::FitsReader>(filename.native(), 1);
129 } else {
130 return Euclid::make_unique<Table::AsciiReader>(filename.native());
131 }
132}
133
134std::string getIdColumnFromOptions(const Configuration::UserValues& args, const Table::ColumnInfo& column_info) {
135 std::string id_column_name = "ID";
136 if (args.find(SOURCE_ID_COLUMN_NAME) != args.end()) {
137 id_column_name = args.at(SOURCE_ID_COLUMN_NAME).as<std::string>();
138 if (column_info.find(id_column_name) == nullptr) {
139 throw Elements::Exception() << "Input catalog file does not contain the "
140 << "ID column with name " << id_column_name;
141 }
142 }
143 if (args.find(SOURCE_ID_COLUMN_INDEX) != args.end()) {
144 std::size_t index = args.at(SOURCE_ID_COLUMN_INDEX).as<int>();
145 if (index > column_info.size()) {
146 throw Elements::Exception() << SOURCE_ID_COLUMN_INDEX << " (" << index << ") is out of range ("
147 << column_info.size() << ")";
148 }
149 id_column_name = column_info.getDescription(index - 1).name;
150 }
151 logger.info() << "Using ID column \"" << id_column_name << '"';
152 return id_column_name;
153}
154
155} // Anonymous namespace
156
158 m_filename = getCatalogFileFromOptions(args, m_base_dir);
159 m_fits_format = getFormatTypeFromOptions(args, m_filename) == FormatType::FITS;
160 m_column_info = std::make_shared<Table::ColumnInfo>(getTableReaderImpl(m_fits_format, m_filename)->getInfo());
161 m_id_column_name = getIdColumnFromOptions(args, *m_column_info);
162}
163
164void CatalogConfig::setBaseDir(const fs::path& base_dir) {
166 throw Elements::Exception() << "setBaseDir() call to initialized CatalogConfig";
167 }
168 m_base_dir = base_dir;
169}
170
172 if (getCurrentState() >= State::FINAL) {
173 throw Elements::Exception() << "addAttributeHandler() call to finalized CatalogConfig";
174 }
175 m_attribute_handlers.push_back(handler);
176}
177
180 throw Elements::Exception() << "getTableReader() call to not finalized CatalogConfig";
181 }
182 return getTableReaderImpl(m_fits_format, m_filename);
183}
184
187 throw Elements::Exception() << "getColumnInfo() call to uninitialized CatalogConfig";
188 }
189 return m_column_info;
190}
191
195
196namespace {
197
198class ConverterImpl {
199
200public:
201 ConverterImpl(std::shared_ptr<Table::ColumnInfo> column_info, const std::string& id_column_name,
203 : m_converter(column_info, id_column_name, std::move(attribute_handlers)) {}
204
205 SourceCatalog::Catalog operator()(const Table::Table& table) {
206 return m_converter.createCatalog(table);
207 }
208
209private:
210 SourceCatalog::CatalogFromTable m_converter;
211};
212
213} // Anonymous namespace
214
217 throw Elements::Exception() << "getTableToCatalogConverter() call to not finalized CatalogConfig";
218 }
220}
221
224 throw Elements::Exception() << "getAsTable() call to not finalized CatalogConfig";
225 }
226 logger.info() << "Reading table from file " << m_filename;
227 return getTableReader()->read();
228}
229
232 throw Elements::Exception() << "getCatalog() call to not finalized CatalogConfig";
233 }
234 auto table = readAsTable();
235 auto converter = getTableToCatalogConverter();
236 return converter(table);
237}
238
239const boost::filesystem::path& CatalogConfig::getFilename() const {
241 throw Elements::Exception() << "getFilename() call to not finalized CatalogConfig";
242 }
243 return m_filename;
244}
245
246} // namespace Configuration
247} // namespace Euclid
SourceCatalog::CatalogFromTable m_converter
T at(T... args)
T back(T... args)
T c_str(T... args)
static Logging getLogger(const std::string &name="")
void info(const std::string &logMessage)
boost::filesystem::path m_filename
void addAttributeHandler(std::shared_ptr< SourceCatalog::AttributeFromRow > handler)
Adds an attribute handler which will be used for adding attributes at the catalog objects.
const boost::filesystem::path & getFilename() const
Returns the filename of the input catalog.
std::map< std::string, OptionDescriptionList > getProgramOptions() override
Returns the program options defined by the CatalogConfig.
Table::Table readAsTable() const
Returns the catalog as a Table::Table object.
CatalogConfig(long manager_id)
Constructs a new CatalogConfig object.
SourceCatalog::Catalog readAsCatalog() const
Returns the Catalog object.
std::shared_ptr< Table::ColumnInfo > m_column_info
TableToCatalogConverter getTableToCatalogConverter() const
std::unique_ptr< Table::TableReader > getTableReader() const
void setBaseDir(const boost::filesystem::path &base_dir)
Sets the directory used when resolving relative paths.
std::vector< std::shared_ptr< SourceCatalog::AttributeFromRow > > m_attribute_handlers
boost::filesystem::path m_base_dir
std::shared_ptr< Table::ColumnInfo > getColumnInfo() const
void preInitialize(const UserValues &args) override
Checks that all the options are valid. See the exceptions thrown for a detailed list of the checks.
void initialize(const UserValues &args) override
Initializes the CatalogConfig instance.
Superclass of all configuration classes.
State & getCurrentState()
Returns the current state of the configuration.
std::map< std::string, boost::program_options::variable_value > UserValues
@ FINAL
The postInitialize() method has been called.
@ INITIALIZED
The initialize() method has been called.
Catalog contains a container of sources.
Definition Catalog.h:47
Represents a table.
Definition Table.h:49
T compare(T... args)
T data(T... args)
T end(T... args)
T find(T... args)
static const std::string SOURCE_ID_COLUMN_NAME
static Elements::Logging logger
static const std::string SOURCE_ID_COLUMN_INDEX
static const std::string INPUT_CATALOG_FILE
static const std::string INPUT_CATALOG_FORMAT
STL namespace.