Alexandria  2.25.0
SDC-CH common library for the Euclid project
PhotometricBandMappingConfig.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
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 <algorithm>
26 #include <boost/regex.hpp>
27 #include <fstream>
28 #include <sstream>
29 #include <tuple>
30 using boost::regex;
31 using boost::regex_match;
32 using boost::smatch;
33 #include <boost/algorithm/string.hpp>
34 
37 #include "ElementsKernel/Logging.h"
38 
39 namespace po = boost::program_options;
40 namespace fs = boost::filesystem;
41 
42 namespace Euclid {
43 namespace Configuration {
44 
45 static Elements::Logging logger = Elements::Logging::getLogger("PhotometricBandMappingConfig");
46 
47 static const std::string FILTER_MAPPING_FILE{"filter-mapping-file"};
48 static const std::string EXCLUDE_FILTER{"exclude-filter"};
49 
51 
53  return {
54  {"Input catalog options",
55  {{FILTER_MAPPING_FILE.c_str(), po::value<std::string>()->default_value("filter_mapping.txt"),
56  "The file containing the photometry mapping of the catalog columns"},
57  {EXCLUDE_FILTER.c_str(), po::value<std::vector<std::string>>()->default_value(std::vector<std::string>{}, ""),
58  "A list of filters to ignore"}}}};
59 }
60 
61 static fs::path getMappingFileFromOptions(const Configuration::UserValues& args, const fs::path& base_dir) {
62  fs::path mapping_file{args.at(FILTER_MAPPING_FILE).as<std::string>()};
63  if (mapping_file.is_relative()) {
64  mapping_file = base_dir / mapping_file;
65  }
66  if (!fs::exists(mapping_file)) {
67  throw Elements::Exception() << "Photometry mapping file " << mapping_file << " does not exist";
68  }
69  if (fs::is_directory(mapping_file)) {
70  throw Elements::Exception() << "Photometry mapping file " << mapping_file << " is not a file";
71  }
72  return mapping_file;
73 }
74 
77 parseFile(fs::path filename) {
78  PhotometricBandMappingConfig::MappingMap filter_name_mapping{};
80  PhotometricBandMappingConfig::ConvertFromMagMap convert_from_mag_mapping{};
81  std::ifstream in{filename.string()};
82  std::string line;
83 
84  bool header_found = false;
85  int filtr_column_index = 0;
86  int flux_column_index = 1;
87  int error_column_index = 2;
88  int upper_limit_column_index = 3;
89  int convertion_column_index = 4;
90 
91  std::vector<std::string> expected_column_name {"Filter", "Flux Column", "Error Column", "Upper Limit/error ratio", "Convert from MAG"};
92 
93 
94  while (std::getline(in, line)) {
95  boost::trim(line);
96  if (line[0] == '#') {
97  if (!header_found) {
98  std::string trimmed_line = line.substr(1);
99  boost::trim(trimmed_line);
100  std::vector<int> proposed_column_index{-1, -1, -1, -1, -1};
102  boost::split(strs, trimmed_line, boost::is_any_of(","));
103 
104  for (size_t index = 0; index < expected_column_name.size(); ++index) {
105  for (size_t index_string = 0; index_string < strs.size(); ++index_string) {
106  std::string item = strs[index_string];
107  boost::trim(item);
108  if (item==expected_column_name[index]){
109  proposed_column_index[index] = index_string;
110  }
111  }
112  }
113 
114  if (proposed_column_index[0] >= 0 && proposed_column_index[1] >= 0 && proposed_column_index[2] >=0) {
115  header_found = true;
116  filtr_column_index = proposed_column_index[0];
117  flux_column_index = proposed_column_index[1];
118  error_column_index = proposed_column_index[2];
119  upper_limit_column_index = proposed_column_index[3];
120  convertion_column_index = proposed_column_index[4];
121  }
122 
123  }
124  continue;
125  }
126 
128  boost::split(cells, line, boost::is_any_of(" "));
129 
130  try {
131  if (int(cells.size()) <= filtr_column_index ||
132  int(cells.size()) <= flux_column_index ||
133  int(cells.size()) <= error_column_index ) {
134  throw Elements::Exception() << "File with missing values for the mandatory fields";
135  }
136  std::string filter_value = cells[filtr_column_index];
137  boost::trim(filter_value);
138  std::string flux_value = cells[flux_column_index];
139  boost::trim(flux_value);
140  std::string error_value = cells[error_column_index];
141  boost::trim(error_value);
142 
143  filter_name_mapping.emplace_back(filter_value,std::make_pair(flux_value, error_value));
144 
145  if (upper_limit_column_index > 0 && int(cells.size()) > upper_limit_column_index && cells[upper_limit_column_index] != "" ) {
146  float n = std::stof(cells[upper_limit_column_index]);
147  threshold_mapping.emplace_back(filter_value, n);
148  } else {
149  threshold_mapping.emplace_back(filter_value, 3.0);
150  }
151 
152  if (convertion_column_index > 0 && int(cells.size()) > convertion_column_index && cells[convertion_column_index] != "") {
153  bool f = std::stoi(cells[convertion_column_index]);
154  convert_from_mag_mapping.emplace_back(filter_value, f);
155  } else {
156  convert_from_mag_mapping.emplace_back(filter_value, false);
157  }
158  } catch (const std::exception& e) {
159  logger.error() << "Syntax error in " << filename << ": " << line << " => " << e.what();;
160  throw Elements::Exception() << "Syntax error in " << filename << ": " << line<< " => " << e.what();
161  }
162  }
163  return std::make_tuple(filter_name_mapping, threshold_mapping, convert_from_mag_mapping);
164 }
165 
167 
168  // Parse the file with the mapping
170  auto parsed = parseFile(m_mapping_file);
171  auto all_filter_name_mapping = std::get<0>(parsed);
172  auto all_threshold_mapping = std::get<1>(parsed);
173  auto all_convert_mapping = std::get<2>(parsed);
174 
175  // Remove the filters which are marked to exclude
176  auto exclude_vector = args.at(EXCLUDE_FILTER).as<std::vector<std::string>>();
177  std::set<std::string> exclude_filters{exclude_vector.begin(), exclude_vector.end()};
178 
179  for (auto& pair : all_threshold_mapping) {
180  if (exclude_filters.count(pair.first) == 0) {
182  }
183  }
184 
185  for (auto& pair : all_convert_mapping) {
186  if (exclude_filters.count(pair.first) == 0) {
188  }
189  }
190 
191  for (auto& pair : all_filter_name_mapping) {
192  if (exclude_filters.count(pair.first) > 0) {
193  exclude_filters.erase(pair.first);
194  } else {
195  m_mapping_map.push_back(pair);
196  }
197  }
198 
199  if (!exclude_filters.empty()) {
200  std::stringstream wrong_filters{};
201  for (auto& f : exclude_filters) {
202  wrong_filters << f << " ";
203  }
204  throw Elements::Exception() << "Wrong " << EXCLUDE_FILTER << " option value(s) : " << wrong_filters.str();
205  }
206 }
207 
208 void PhotometricBandMappingConfig::setBaseDir(const boost::filesystem::path& base_dir) {
210  throw Elements::Exception() << "setBaseDir() call to initialized PhotometricBandMappingConfig";
211  }
212  m_base_dir = base_dir;
213 }
214 
217  throw Elements::Exception() << "getPhotometricBandMapping() call to uninitialized "
218  << "PhotometricBandMappingConfig";
219  }
220  return m_mapping_map;
221 }
222 
226  throw Elements::Exception() << "getUpperLimitThresholdMapping() call to uninitialized "
227  << "PhotometricBandMappingConfig";
228  }
229  return m_threshold_map;
230 }
231 
234  throw Elements::Exception() << "getConvertFromMagMapping() call to uninitialized "
235  << "PhotometricBandMappingConfig";
236  }
237  return m_convert_from_mag_map;
238 }
239 
240 
243  throw Elements::Exception() << "getMappingFile() call to uninitialized "
244  << "PhotometricBandMappingConfig";
245  }
246  return m_mapping_file;
247 }
248 
249 } // namespace Configuration
250 } // namespace Euclid
T at(T... args)
T begin(T... args)
T c_str(T... args)
void error(const std::string &logMessage)
static Logging getLogger(const std::string &name="")
Superclass of all configuration classes.
Definition: Configuration.h:45
State & getCurrentState()
Returns the current state of the configuration.
@ INITIALIZED
The initialize() method has been called.
std::vector< std::pair< std::string, std::pair< std::string, std::string > >> MappingMap
std::vector< std::pair< std::string, bool > > ConvertFromMagMap
const boost::filesystem::path getMappingFile()
Returns the mapping file to be used by other configuration class.
const MappingMap & getPhotometricBandMapping()
Returns the list of the photometric band mapping which will be red from the catalog.
std::map< std::string, OptionDescriptionList > getProgramOptions() override
Returns the program options defined by the PhotometryCatalogConfig.
const UpperLimitThresholdMap & getUpperLimitThresholdMapping()
Returns the mapping of threshold used in the upper limit computation which will be red from the catal...
PhotometricBandMappingConfig(long manager_id)
Constructs a new PhotometricBandMappingConfig object.
void initialize(const UserValues &args) override
It initializes the photometric bands list.
void setBaseDir(const boost::filesystem::path &base_dir)
Sets the directory used when resolving relative paths.
std::vector< std::pair< std::string, float > > UpperLimitThresholdMap
const ConvertFromMagMap & getConvertFromMagMapping()
Returns the mapping of the flag indicating if the photometry has to be computed from a MAG_AB.
T getline(T... args)
ELEMENTS_API auto split(Args &&... args) -> decltype(splitPath(std::forward< Args >(args)...))
T make_pair(T... args)
T make_tuple(T... args)
constexpr double e
static std::tuple< PhotometricBandMappingConfig::MappingMap, PhotometricBandMappingConfig::UpperLimitThresholdMap, PhotometricBandMappingConfig::ConvertFromMagMap > parseFile(fs::path filename)
static Elements::Logging logger
static const std::string EXCLUDE_FILTER
static fs::path getMappingFileFromOptions(const Configuration::UserValues &args, const fs::path &base_dir)
static const std::string FILTER_MAPPING_FILE
T push_back(T... args)
T size(T... args)
T stof(T... args)
T stoi(T... args)
T substr(T... args)