SourceXtractorPlusPlus 0.19.2
SourceXtractor++, the next generation SExtractor
Loading...
Searching...
No Matches
AssocModeConfig.cpp
Go to the documentation of this file.
1
18#include <map>
19#include <boost/algorithm/string.hpp>
20
21#include <CCfits/CCfits>
22
24
25#include "Table/AsciiReader.h"
26#include "Table/FitsReader.h"
27#include "Table/CastVisitor.h"
28
32
34
36
37using namespace Euclid::Configuration;
38namespace po = boost::program_options;
39
40namespace SourceXtractor {
41
43
44enum class AssocCoordType {
45 PIXEL,
46 WORLD
47};
48
49static const std::string ASSOC_CATALOG { "assoc-catalog" };
50static const std::string ASSOC_MODE { "assoc-mode" };
51static const std::string ASSOC_RADIUS { "assoc-radius" };
52static const std::string ASSOC_FILTER { "assoc-filter" };
53static const std::string ASSOC_COPY { "assoc-copy" };
54static const std::string ASSOC_COLUMNS { "assoc-columns" };
55static const std::string ASSOC_COORD_TYPE { "assoc-coord-type" };
56
57namespace {
58
69};
70
75};
76
77const std::map<std::string, AssocCoordType> assoc_coord_type_table {
80};
81
82std::vector<int> parseColumnList(const std::string& arg) {
83 if (arg.size() > 0) {
84 try {
86 boost::split(parts, arg, boost::is_any_of(","));
87
88 std::vector<int> column_list;
89 for (auto& part : parts) {
90 // the input is a 1-based index, the internal index is 0-based
91 column_list.emplace_back(boost::lexical_cast<int>(part)-1);
92 }
93 return column_list;
94 } catch(...) {
95 throw Elements::Exception() << "Can't parse column list to int: " << arg;
96 }
97 } else {
98 return {};
99 }
100}
101
102}
103
104AssocModeConfig::AssocModeConfig(long manager_id) : Configuration(manager_id), m_assoc_mode(AssocMode::UNKNOWN), m_assoc_radius(0.) {
105 declareDependency<DetectionImageConfig>();
106 declareDependency<PartitionStepConfig>();
108}
109
111 return { {"Assoc config", {
112 {ASSOC_CATALOG.c_str(), po::value<std::string>(),
113 "Assoc catalog file"},
114 {ASSOC_COLUMNS.c_str(), po::value<std::string>()->default_value("1,2"),
115 "Assoc columns to specify x/ra,y/dec[,weight] (the index of the first column is 1)"},
116 {ASSOC_MODE.c_str(), po::value<std::string>()->default_value("NEAREST"),
117 "Assoc mode [FIRST, NEAREST, MEAN, MAG_MEAN, SUM, MAG_SUM, MIN, MAX]"},
118 {ASSOC_RADIUS.c_str(), po::value<double>()->default_value(2.0),
119 "Assoc radius (Always in pixels of the detection image)"},
120 {ASSOC_FILTER.c_str(), po::value<std::string>()->default_value("ALL"),
121 "Assoc catalog filter setting: ALL, MATCHED, UNMATCHED"},
122 {ASSOC_COPY.c_str(), po::value<std::string>()->default_value(""),
123 "List of columns indices in the assoc catalog to copy on match (the index of the first column is 1). "},
124 {ASSOC_COORD_TYPE.c_str(), po::value<std::string>()->default_value("PIXEL"),
125 "Assoc coordinates type: PIXEL, WORLD"},
126 }}};
127}
128
130 readConfig(args);
131 readCatalogs(args);
132}
133
135 auto filter = boost::to_upper_copy(args.at(ASSOC_FILTER).as<std::string>());
136 if (assoc_filter_table.find(filter) != assoc_filter_table.end()) {
137 auto assoc_filter = assoc_filter_table.at(filter);
138 if (assoc_filter == AssocFilter::MATCHED) {
139 getDependency<PartitionStepConfig>().addPartitionStepCreator(
141 return std::make_shared<AssocModePartitionStep>(true);
142 }
143 );
144 } else if (assoc_filter == AssocFilter::UNMATCHED) {
145 getDependency<PartitionStepConfig>().addPartitionStepCreator(
147 return std::make_shared<AssocModePartitionStep>(false);
148 }
149 );
150 }
151 } else {
152 throw Elements::Exception() << "Invalid assoc filter: " << filter;
153 }
154
155 if (args.find(ASSOC_MODE) != args.end()) {
156 auto assoc_mode = boost::to_upper_copy(args.at(ASSOC_MODE).as<std::string>());
157 if (assoc_mode_table.find(assoc_mode) != assoc_mode_table.end()) {
158 m_assoc_mode = assoc_mode_table.at(assoc_mode);
159 } else {
160 throw Elements::Exception() << "Invalid association mode: " << assoc_mode;
161 }
162 }
163
164 m_assoc_radius = args.at(ASSOC_RADIUS).as<double>();
165}
166
168 auto columns = parseColumnList(args.at(ASSOC_COLUMNS).as<std::string>());
169 if (columns.size() < 2) {
170 throw Elements::Exception() << "At least 2 columns must be specified for x,y coordinates in the assoc catalog";
171 }
172 if (columns.size() > 3) {
173 throw Elements::Exception() << "Maximum 3 columns for x, y and weight must be specified in the assoc catalog";
174 }
175
176 m_columns_idx = parseColumnList(args.at(ASSOC_COPY).as<std::string>());
177
178 AssocCoordType assoc_coord_type = AssocCoordType::PIXEL;
179 if (args.find(ASSOC_COORD_TYPE) != args.end()) {
180 auto assoc_coord_type_str = boost::to_upper_copy(args.at(ASSOC_COORD_TYPE).as<std::string>());
181 if (assoc_coord_type_table.find(assoc_coord_type_str) != assoc_coord_type_table.end()) {
182 assoc_coord_type = assoc_coord_type_table.at(assoc_coord_type_str);
183 } else {
184 throw Elements::Exception() << "Invalid association coordinate type: " << assoc_coord_type_str;
185 }
186 }
187
188 if (args.find(ASSOC_CATALOG) != args.end()) {
189 auto filename = args.at(ASSOC_CATALOG).as<std::string>();
190 try {
192 try {
193 reader = std::make_shared<Euclid::Table::FitsReader>(filename);
194 } catch (...) {
195 // If FITS not successful try reading as ascii
196 reader = std::make_shared<Euclid::Table::AsciiReader>(filename);
197 }
198 auto table = reader->read();
199
200 for (size_t i = 0; i < getDependency<DetectionImageConfig>().getExtensionsNb(); i++) {
201 if (assoc_coord_type == AssocCoordType::WORLD) {
202 auto coordinate_system = getDependency<DetectionImageConfig>().getCoordinateSystem(i);
203 m_catalogs.emplace_back(readTable(table, columns, m_columns_idx, coordinate_system));
204 } else {
205 m_catalogs.emplace_back(readTable(table, columns, m_columns_idx, nullptr));
206 }
207 }
208 } catch (const std::exception& e) {
209 throw Elements::Exception() << "Can't either open or read assoc catalog: " << filename << " (" << e.what() << ")";
210 } catch(...) {
211 throw Elements::Exception() << "Can't either open or read assoc catalog: " << filename;
212 }
213 }
214
215 if (assoc_coord_type == AssocCoordType::PIXEL && getDependency<DetectionImageConfig>().getExtensionsNb() > 1) {
216 logger.warn() <<
217 "Using Assoc catalog matching in pixel coordinates with multiple detection images";
218 }
219}
220
222 const Euclid::Table::Table& table, const std::vector<int>& columns,
223 const std::vector<int>& copy_columns, std::shared_ptr<CoordinateSystem> coordinate_system) {
225
227 for (auto& row : table) {
228 // our internal pixel coordinates are zero-based
229
230 ImageCoordinate coord;
231 if (coordinate_system != nullptr) {
232 auto world_coord = WorldCoordinate{
233 boost::apply_visitor(CastVisitor<double>{}, row[columns.at(0)]),
234 boost::apply_visitor(CastVisitor<double>{}, row[columns.at(1)]),
235 };
236
237 coord = coordinate_system->worldToImage(world_coord);
238 } else {
239 coord = ImageCoordinate{
240 boost::apply_visitor(CastVisitor<double>{}, row[columns.at(0)]) - 1.0,
241 boost::apply_visitor(CastVisitor<double>{}, row[columns.at(1)]) - 1.0,
242 };
243 }
244 catalog.emplace_back(CatalogEntry { coord, 1.0, {} });
245 if (columns.size() == 3 && columns.at(2) >= 0) {
246 catalog.back().weight = boost::get<double>(row[columns.at(2)]);
247 }
248 for (auto column : copy_columns) {
249 if (column >= static_cast<int>(row.size())) {
250 throw Elements::Exception() << "Column index " << column << " is out of bounds";
251 }
252 if (row[column].type() == typeid(int)) {
253 catalog.back().assoc_columns.emplace_back(boost::get<int>(row[column]));
254 } else if (row[column].type() == typeid(double)) {
255 catalog.back().assoc_columns.emplace_back(boost::get<double>(row[column]));
256 } else if (row[column].type() == typeid(int64_t)) {
257 catalog.back().assoc_columns.emplace_back(boost::get<int64_t>(row[column]));
258 } else if (row[column].type() == typeid(SeFloat)) {
259 catalog.back().assoc_columns.emplace_back(boost::get<SeFloat>(row[column]));
260 } else{
261 throw Elements::Exception() << "Wrong type in assoc column (must be a numeric type)";
262 }
263 }
264 }
265 return catalog;
266}
267
268
269}
270
T at(T... args)
T back(T... args)
T c_str(T... args)
static Logging getLogger(const std::string &name="")
void warn(const std::string &logMessage)
static ConfigManager & getInstance(long id)
std::map< std::string, OptionDescriptionList > getProgramOptions() override
void readConfig(const UserValues &args)
void initialize(const UserValues &args) override
void readCatalogs(const UserValues &args)
std::vector< CatalogEntry > readTable(const Euclid::Table::Table &table, const std::vector< int > &columns, const std::vector< int > &copy_columns, std::shared_ptr< CoordinateSystem > coordinate_system)
std::vector< std::vector< CatalogEntry > > m_catalogs
T emplace_back(T... args)
T end(T... args)
T find(T... args)
T make_pair(T... args)
constexpr double e
static Elements::Logging logger
static const std::string ASSOC_COORD_TYPE
static const std::string ASSOC_COPY
SeFloat32 SeFloat
Definition Types.h:32
static const std::string ASSOC_FILTER
static const std::string ASSOC_CATALOG
static const std::string ASSOC_MODE
static const std::string ASSOC_RADIUS
static const std::string ASSOC_COLUMNS
T size(T... args)