24 #include <boost/python/extract.hpp>
25 #include <boost/python/object.hpp>
26 #include <boost/python/tuple.hpp>
27 #include <boost/python/dict.hpp>
44 #include <boost/python/extract.hpp>
45 #include <boost/python/object.hpp>
47 #ifdef WITH_ONNX_MODELS
54 using namespace Euclid::Configuration;
55 namespace py = boost::python;
60 namespace SourceXtractor {
62 template<
typename Signature>
74 if (!wrapped.isCompiled()) {
75 logger.
warn() <<
"Could not compile " << readable <<
": " << wrapped.reason()->what();
76 wrapped.reason()->log(log4cpp::Priority::DEBUG,
logger);
81 wrapped.getTree()->visit(gv);
98 if (!wrapped.isCompiled()) {
99 logger.
warn() <<
"Could not compile " << readable <<
": " << wrapped.reason()->what();
100 wrapped.reason()->log(log4cpp::Priority::DEBUG,
logger);
105 wrapped.getTree()->visit(gv);
118 py::object py_func) {
121 if (!wrapped.isCompiled()) {
122 logger.
warn() <<
"Could not compile " << readable <<
": " << wrapped.reason()->what();
123 wrapped.reason()->log(log4cpp::Priority::DEBUG,
logger);
128 wrapped.getTree()->visit(gv);
138 ModelFittingConfig::ModelFittingConfig(
long manager_id) :
Configuration(manager_id) {
139 declareDependency<PythonConfig>();
156 throw e.
log(log4cpp::Priority::ERROR,
logger);
157 }
catch (py::error_already_set& e) {
164 return coord_system->imageToWorld({
x, y}).m_alpha;
169 return coord_system->imageToWorld({
x, y}).m_delta;
182 for (
auto& p : getDependency<PythonConfig>().getInterpreter().getConstantParameters()) {
184 "Constant parameter", expr_builder, p.second.attr(
"get_value")
187 m_parameters[p.first] = std::make_shared<FlexibleModelFittingConstantParameter>(
188 p.first, value_func);
192 for (
auto& p : getDependency<PythonConfig>().getInterpreter().getFreeParameters()) {
194 "Free parameter", expr_builder, p.second.attr(
"get_init_value")
197 auto py_range_obj = p.second.attr(
"get_range")();
200 std::string type_string(py::extract<char const*>(py_range_obj.attr(
"__class__").attr(
"__name__")));
202 if (type_string ==
"Unbounded") {
204 "Unbounded", expr_builder, py_range_obj.attr(
"get_normalization_factor")
206 converter = std::make_shared<FlexibleModelFittingUnboundedConverterFactory>(factor_func);
207 }
else if (type_string ==
"Range") {
209 "Range min", expr_builder, py_range_obj.attr(
"get_min")
212 "Range max", expr_builder, py_range_obj.attr(
"get_max")
216 return {min_func(init, o), max_func(init, o)};
219 bool is_exponential = py::extract<int>(py_range_obj.attr(
"get_type")().attr(
"value")) == 2;
221 if (is_exponential) {
222 converter = std::make_shared<FlexibleModelFittingExponentialRangeConverterFactory>(range_func);
224 converter = std::make_shared<FlexibleModelFittingLinearRangeConverterFactory>(range_func);
229 m_parameters[p.first] = std::make_shared<FlexibleModelFittingFreeParameter>(
230 p.first, init_value_func, converter);
234 for (
auto& p : getDependency<PythonConfig>().getInterpreter().getDependentParameters()) {
235 auto py_func = p.second.attr(
"func");
237 py::list dependees = py::extract<py::list>(p.second.attr(
"params"));
238 for (
int i = 0; i < py::len(dependees); ++i) {
239 int id = py::extract<int>(dependees[i].attr(
"id"));
244 ::
get(
"Dependent parameter", expr_builder, py_func, params.size());
248 context[
"coordinate_system"] = cs;
249 return dependent(context, params);
252 m_parameters[p.first] = std::make_shared<FlexibleModelFittingDependentParameter>(
253 p.first, dependent_func, params);
256 for (
auto& p : getDependency<PythonConfig>().getInterpreter().getConstantModels()) {
257 int value_id = py::extract<int>(p.second.attr(
"value").attr(
"id"));
258 m_models[p.first] = std::make_shared<FlexibleModelFittingConstantModel>(
m_parameters.at(value_id));
261 for (
auto& p : getDependency<PythonConfig>().getInterpreter().getPointSourceModels()) {
262 int x_coord_id = py::extract<int>(p.second.attr(
"x_coord").attr(
"id"));
263 int y_coord_id = py::extract<int>(p.second.attr(
"y_coord").attr(
"id"));
264 int flux_id = py::extract<int>(p.second.attr(
"flux").attr(
"id"));
265 m_models[p.first] = std::make_shared<FlexibleModelFittingPointModel>(
269 for (
auto& p : getDependency<PythonConfig>().getInterpreter().getSersicModels()) {
270 int x_coord_id = py::extract<int>(p.second.attr(
"x_coord").attr(
"id"));
271 int y_coord_id = py::extract<int>(p.second.attr(
"y_coord").attr(
"id"));
272 int flux_id = py::extract<int>(p.second.attr(
"flux").attr(
"id"));
273 int effective_radius_id = py::extract<int>(p.second.attr(
"effective_radius").attr(
"id"));
274 int aspect_ratio_id = py::extract<int>(p.second.attr(
"aspect_ratio").attr(
"id"));
275 int angle_id = py::extract<int>(p.second.attr(
"angle").attr(
"id"));
276 int n_id = py::extract<int>(p.second.attr(
"n").attr(
"id"));
277 m_models[p.first] = std::make_shared<FlexibleModelFittingSersicModel>(
283 for (
auto& p : getDependency<PythonConfig>().getInterpreter().getExponentialModels()) {
284 int x_coord_id = py::extract<int>(p.second.attr(
"x_coord").attr(
"id"));
285 int y_coord_id = py::extract<int>(p.second.attr(
"y_coord").attr(
"id"));
286 int flux_id = py::extract<int>(p.second.attr(
"flux").attr(
"id"));
287 int effective_radius_id = py::extract<int>(p.second.attr(
"effective_radius").attr(
"id"));
288 int aspect_ratio_id = py::extract<int>(p.second.attr(
"aspect_ratio").attr(
"id"));
289 int angle_id = py::extract<int>(p.second.attr(
"angle").attr(
"id"));
290 m_models[p.first] = std::make_shared<FlexibleModelFittingExponentialModel>(
295 for (
auto& p : getDependency<PythonConfig>().getInterpreter().getDeVaucouleursModels()) {
296 int x_coord_id = py::extract<int>(p.second.attr(
"x_coord").attr(
"id"));
297 int y_coord_id = py::extract<int>(p.second.attr(
"y_coord").attr(
"id"));
298 int flux_id = py::extract<int>(p.second.attr(
"flux").attr(
"id"));
299 int effective_radius_id = py::extract<int>(p.second.attr(
"effective_radius").attr(
"id"));
300 int aspect_ratio_id = py::extract<int>(p.second.attr(
"aspect_ratio").attr(
"id"));
301 int angle_id = py::extract<int>(p.second.attr(
"angle").attr(
"id"));
302 m_models[p.first] = std::make_shared<FlexibleModelFittingDevaucouleursModel>(
307 #ifdef WITH_ONNX_MODELS
308 for (
auto& p : getDependency<PythonConfig>().getInterpreter().getOnnxModels()) {
309 int x_coord_id = py::extract<int>(p.second.attr(
"x_coord").attr(
"id"));
310 int y_coord_id = py::extract<int>(p.second.attr(
"y_coord").attr(
"id"));
311 int flux_id = py::extract<int>(p.second.attr(
"flux").attr(
"id"));
312 int aspect_ratio_id = py::extract<int>(p.second.attr(
"aspect_ratio").attr(
"id"));
313 int angle_id = py::extract<int>(p.second.attr(
"angle").attr(
"id"));
314 int scale_id = py::extract<int>(p.second.attr(
"scale").attr(
"id"));
317 py::dict parameters = py::extract<py::dict>(p.second.attr(
"params"));
318 py::list names = parameters.keys();
319 for (
int i = 0; i < py::len(names); ++i) {
320 std::string name = py::extract<std::string>(names[i]);
321 params[name] =
m_parameters.at(py::extract<int>(parameters[names[i]].attr(
"id")));
325 py::list models = py::extract<py::list>(p.second.attr(
"models"));
326 for (
int i = 0; i < py::len(models); ++i) {
327 std::string model_filename = py::extract<std::string>(models[i]);
328 onnx_models.
emplace_back(std::make_shared<OnnxModel>(model_filename));
330 if (onnx_models.
back()->getOutputType() != ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT ||
331 onnx_models.
back()->getOutputShape().size() != 4 ||
332 onnx_models.
back()->getOutputShape()[1] != onnx_models.
back()->getOutputShape()[2] ||
333 onnx_models.
back()->getOutputShape()[3] != 1)
335 throw Elements::Exception() <<
"ONNX models for ModelFitting must output a square array of floats";
339 m_models[p.first] = std::make_shared<FlexibleModelFittingOnnxModel>(
344 if (getDependency<PythonConfig>().getInterpreter().getOnnxModels().size() > 0) {
349 for (
auto& p : getDependency<PythonConfig>().getInterpreter().getFrameModelsMap()) {
351 for (
int x : p.second) {
354 m_frames.push_back(std::make_shared<FlexibleModelFittingFrame>(p.first, model_list));
357 for (
auto& p : getDependency<PythonConfig>().getInterpreter().
getPriors()) {
358 auto& prior = p.second;
359 int param_id = py::extract<int>(prior.attr(
"param"));
363 "Prior mean", expr_builder, prior.attr(
"value")
366 "Prior sigma", expr_builder, prior.attr(
"sigma")
369 m_priors[p.first] = std::make_shared<FlexibleModelFittingPrior>(param, value_func, sigma_func);
372 m_outputs = getDependency<PythonConfig>().getInterpreter().getModelFittingOutputColumns();
374 auto parameters = getDependency<PythonConfig>().getInterpreter().getModelFittingParams();
std::shared_ptr< DependentParameter< std::shared_ptr< EngineParameter > > > x
const Exception & log(log4cpp::Priority::Value level, Elements::Logging &logger) const
void info(const std::string &logMessage)
void debug(const std::string &logMessage)
std::shared_ptr< DependentParameter< std::shared_ptr< EngineParameter > > > y
static std::string getDefault()
void warn(const std::string &logMessage)
static Elements::Logging logger
void registerFunction(const std::string &repr, std::function< Signature > functor)
ExpressionTree< Signature > build(const boost::python::object &pyfunc, BuildParams &&...build_params) const
std::map< std::string, Attribute > AttributeSet
static Logging getLogger(const std::string &name="")