SourceXtractorPlusPlus  0.14
Please provide a description of the project.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ModelFittingConfig.cpp
Go to the documentation of this file.
1 
17 /*
18  * @file ModelFittingConfig.cpp
19  * @author Nikolaos Apostolakos <nikoapos@gmail.com>
20  */
21 
22 #include "ElementsKernel/Logging.h"
29 #include "SEUtils/Python.h"
30 
31 #include <string>
32 #include <boost/python/extract.hpp>
33 #include <boost/python/object.hpp>
34 #include <boost/python/tuple.hpp>
35 
36 
37 using namespace Euclid::Configuration;
38 namespace py = boost::python;
39 
41 
42 namespace SourceXtractor {
43 
59 template <typename R, typename ...T>
60 R py_call_wrapper(const py::object& func, T... args) {
61  GILStateEnsure ensure;
62  try {
63  return py::extract<R>(func(args...));
64  }
65  catch (const py::error_already_set &e) {
67  }
68 }
69 
82  public:
83  PyObjectHolder(py::object&& obj): m_obj_ptr(std::make_shared<py::object>(obj)) {}
84 
85  PyObjectHolder(const PyObjectHolder&) = default;
86  PyObjectHolder(PyObjectHolder&&) = default;
87 
88  operator const py::object&() const {
89  return *m_obj_ptr;
90  }
91 
92  const py::object& operator *() const {
93  return *m_obj_ptr;
94  }
95 
96  py::object attr(const char *name) {
97  return m_obj_ptr->attr(name);
98  }
99 
100  private:
102 };
103 
104 ModelFittingConfig::ModelFittingConfig(long manager_id) : Configuration(manager_id) {
105  declareDependency<PythonConfig>();
106 }
107 
109  GILStateEnsure ensure;
110  m_parameters.clear();
111  m_models.clear();
112  m_frames.clear();
113  m_priors.clear();
114  m_outputs.clear();
115 }
116 
117 void ModelFittingConfig::initialize(const UserValues&) {
118  GILStateEnsure ensure;
119  try {
120  initializeInner();
121  }
122  catch (py::error_already_set &e) {
124  }
125 }
126 
128  for (auto& p : getDependency<PythonConfig>().getInterpreter().getConstantParameters()) {
129  auto py_value_func = PyObjectHolder(p.second.attr("get_value")());
130  auto value_func = [py_value_func] (const SourceInterface& o) -> double {
131  ObjectInfo oi {o};
132  return py_call_wrapper<double>(py_value_func, oi);
133  };
134  m_parameters[p.first] = std::make_shared<FlexibleModelFittingConstantParameter>(
135  p.first, value_func);
136  }
137 
138  for (auto& p : getDependency<PythonConfig>().getInterpreter().getFreeParameters()) {
139  auto py_init_value_func = PyObjectHolder(p.second.attr("get_init_value")());
140  auto init_value_func = [py_init_value_func] (const SourceInterface& o) -> double {
141  ObjectInfo oi {o};
142  return py_call_wrapper<double>(py_init_value_func, oi);
143  };
144 
145  auto py_range_obj = PyObjectHolder(p.second.attr("get_range")());
146 
148  std::string type_string(py::extract<char const*>(py_range_obj.attr("__class__").attr("__name__")));
149  if (type_string == "Unbounded") {
150  auto py_factor_func = PyObjectHolder(py_range_obj.attr("get_normalization_factor")());
151  auto factor_func = [py_factor_func] (double init, const SourceInterface& o) -> double {
152  ObjectInfo oi {o};
153  return py_call_wrapper<double>(py_factor_func, init, oi);
154  };
155  converter = std::make_shared<FlexibleModelFittingUnboundedConverterFactory>(factor_func);
156  } else if (type_string == "Range") {
157  auto py_range_func = PyObjectHolder(py_range_obj.attr("get_limits")());
158  auto range_func = [py_range_func] (double init, const SourceInterface& o) -> std::pair<double, double> {
159  ObjectInfo oi {o};
160  py::tuple range = py_call_wrapper<py::tuple>(py_range_func, init, oi);
161  double low = py::extract<double>(range[0]);
162  double high = py::extract<double>(range[1]);
163  return {low, high};
164  };
165  bool is_exponential = py::extract<int>(py_range_obj.attr("get_type")().attr("value")) == 2;
166 
167  if (is_exponential) {
168  converter = std::make_shared<FlexibleModelFittingExponentialRangeConverterFactory>(range_func);
169  } else {
170  converter = std::make_shared<FlexibleModelFittingLinearRangeConverterFactory>(range_func);
171  }
172  } else {
173  throw Elements::Exception("Unknown converter type: " + type_string);
174  }
175  m_parameters[p.first] = std::make_shared<FlexibleModelFittingFreeParameter>(
176  p.first, init_value_func, converter);
177  }
178 
179  for (auto& p : getDependency<PythonConfig>().getInterpreter().getDependentParameters()) {
180  auto py_func = PyObjectHolder(p.second.attr("func"));
182  py::list param_ids = py::extract<py::list>(p.second.attr("params"));
183  for (int i = 0; i < py::len(param_ids); ++i) {
184  int id = py::extract<int>(param_ids[i]);
185  params.push_back(m_parameters[id]);
186  }
187 
188  auto dependent_func = [py_func](const std::shared_ptr<CoordinateSystem> &cs, const std::vector<double> &params) -> double {
189  try {
190  GILStateEnsure ensure;
192  return py::extract<double>((*py_func)(*py::tuple(params)));
193  }
194  catch (const py::error_already_set&) {
196  }
197  };
198 
199  m_parameters[p.first] = std::make_shared<FlexibleModelFittingDependentParameter>(
200  p.first, dependent_func, params);
201  }
202 
203  for (auto& p : getDependency<PythonConfig>().getInterpreter().getConstantModels()) {
204  int value_id = py::extract<int>(p.second.attr("value").attr("id"));
205  m_models[p.first] = std::make_shared<FlexibleModelFittingConstantModel>(
206  m_parameters[value_id]);
207  }
208 
209 
210  for (auto& p : getDependency<PythonConfig>().getInterpreter().getPointSourceModels()) {
211  int x_coord_id = py::extract<int>(p.second.attr("x_coord").attr("id"));
212  int y_coord_id = py::extract<int>(p.second.attr("y_coord").attr("id"));
213  int flux_id = py::extract<int>(p.second.attr("flux").attr("id"));
214  m_models[p.first] = std::make_shared<FlexibleModelFittingPointModel>(
215  m_parameters[x_coord_id], m_parameters[y_coord_id], m_parameters[flux_id]);
216  }
217 
218  for (auto& p : getDependency<PythonConfig>().getInterpreter().getSersicModels()) {
219  int x_coord_id = py::extract<int>(p.second.attr("x_coord").attr("id"));
220  int y_coord_id = py::extract<int>(p.second.attr("y_coord").attr("id"));
221  int flux_id = py::extract<int>(p.second.attr("flux").attr("id"));
222  int effective_radius_id = py::extract<int>(p.second.attr("effective_radius").attr("id"));
223  int aspect_ratio_id = py::extract<int>(p.second.attr("aspect_ratio").attr("id"));
224  int angle_id = py::extract<int>(p.second.attr("angle").attr("id"));
225  int n_id = py::extract<int>(p.second.attr("n").attr("id"));
226  m_models[p.first] = std::make_shared<FlexibleModelFittingSersicModel>(
227  m_parameters[x_coord_id], m_parameters[y_coord_id], m_parameters[flux_id], m_parameters[n_id],
228  m_parameters[effective_radius_id], m_parameters[aspect_ratio_id],
229  m_parameters[angle_id]);
230  }
231 
232  for (auto& p : getDependency<PythonConfig>().getInterpreter().getExponentialModels()) {
233  int x_coord_id = py::extract<int>(p.second.attr("x_coord").attr("id"));
234  int y_coord_id = py::extract<int>(p.second.attr("y_coord").attr("id"));
235  int flux_id = py::extract<int>(p.second.attr("flux").attr("id"));
236  int effective_radius_id = py::extract<int>(p.second.attr("effective_radius").attr("id"));
237  int aspect_ratio_id = py::extract<int>(p.second.attr("aspect_ratio").attr("id"));
238  int angle_id = py::extract<int>(p.second.attr("angle").attr("id"));
239  m_models[p.first] = std::make_shared<FlexibleModelFittingExponentialModel>(
240  m_parameters[x_coord_id], m_parameters[y_coord_id], m_parameters[flux_id],
241  m_parameters[effective_radius_id], m_parameters[aspect_ratio_id], m_parameters[angle_id]);
242  }
243 
244  for (auto& p : getDependency<PythonConfig>().getInterpreter().getDeVaucouleursModels()) {
245  int x_coord_id = py::extract<int>(p.second.attr("x_coord").attr("id"));
246  int y_coord_id = py::extract<int>(p.second.attr("y_coord").attr("id"));
247  int flux_id = py::extract<int>(p.second.attr("flux").attr("id"));
248  int effective_radius_id = py::extract<int>(p.second.attr("effective_radius").attr("id"));
249  int aspect_ratio_id = py::extract<int>(p.second.attr("aspect_ratio").attr("id"));
250  int angle_id = py::extract<int>(p.second.attr("angle").attr("id"));
251  m_models[p.first] = std::make_shared<FlexibleModelFittingDevaucouleursModel>(
252  m_parameters[x_coord_id], m_parameters[y_coord_id], m_parameters[flux_id],
253  m_parameters[effective_radius_id], m_parameters[aspect_ratio_id], m_parameters[angle_id]);
254  }
255 
256  for (auto& p : getDependency<PythonConfig>().getInterpreter().getFrameModelsMap()) {
258  for (int x : p.second) {
259  model_list.push_back(m_models[x]);
260  }
261  m_frames.push_back(std::make_shared<FlexibleModelFittingFrame>(p.first, model_list));
262  }
263 
264  for (auto& p : getDependency<PythonConfig>().getInterpreter().getPriors()) {
265  auto& prior = p.second;
266  int param_id = py::extract<int>(prior.attr("param"));
267  auto param = m_parameters[param_id];
268  auto py_value_func = PyObjectHolder(prior.attr("value"));
269  auto value_func = [py_value_func] (const SourceInterface& o) -> double {
270  ObjectInfo oi {o};
271  return py_call_wrapper<double>(py_value_func, oi);
272  };
273  auto py_sigma_func = PyObjectHolder(prior.attr("sigma"));
274  auto sigma_func = [py_sigma_func] (const SourceInterface& o) -> double {
275  ObjectInfo oi {o};
276  return py_call_wrapper<double>(py_sigma_func, oi);
277  };
278  m_priors[p.first] = std::make_shared<FlexibleModelFittingPrior>(param, value_func, sigma_func);
279  }
280 
281  m_outputs = getDependency<PythonConfig>().getInterpreter().getModelFittingOutputColumns();
282 
283  auto parameters = getDependency<PythonConfig>().getInterpreter().getModelFittingParams();
284  m_least_squares_engine = py::extract<std::string>(parameters["engine"]);
287  }
288  m_max_iterations = py::extract<int>(parameters["max_iterations"]);
289  m_modified_chi_squared_scale = py::extract<double>(parameters["modified_chi_squared_scale"]);
290 }
291 
293  return m_parameters;
294 }
295 
297  return m_models;
298 }
299 
301  return m_frames;
302 }
303 
305  return m_priors;
306 }
307 
309  return m_outputs;
310 }
311 
312 }
const std::map< int, std::shared_ptr< FlexibleModelFittingParameter > > & getParameters() const
T empty(T...args)
static auto logger
Definition: WCS.cpp:46
py::object attr(const char *name)
std::map< int, std::shared_ptr< FlexibleModelFittingPrior > > m_priors
const std::vector< std::pair< std::string, std::vector< int > > > & getOutputs() const
std::shared_ptr< DependentParameter< std::shared_ptr< EngineParameter > > > x
const std::vector< std::shared_ptr< FlexibleModelFittingFrame > > & getFrames() const
constexpr double e
void setCoordinateSystem(std::shared_ptr< CoordinateSystem > coordinate_system)
void initialize(const UserValues &args) override
Elements::Exception pyToElementsException(Elements::Logging &logger)
Definition: Python.cpp:30
STL class.
R py_call_wrapper(const py::object &func, T...args)
std::map< int, std::shared_ptr< FlexibleModelFittingParameter > > m_parameters
STL class.
T push_back(T...args)
std::map< int, std::shared_ptr< FlexibleModelFittingModel > > m_models
const std::map< int, std::shared_ptr< FlexibleModelFittingModel > > & getModels() const
static Elements::Logging logger
STL class.
T make_shared(T...args)
constexpr Flags operator*(const Flags &a, const bool b)
Definition: SourceFlags.h:58
std::shared_ptr< py::object > m_obj_ptr
Hold a reference to a Python object.
std::vector< std::shared_ptr< FlexibleModelFittingFrame > > m_frames
const std::map< int, std::shared_ptr< FlexibleModelFittingPrior > > & getPriors() const
The SourceInterface is an abstract &quot;source&quot; that has properties attached to it.
static Logging getLogger(const std::string &name="")
static PythonInterpreter & getSingleton()
std::vector< std::pair< std::string, std::vector< int > > > m_outputs