SourceXtractorPlusPlus 0.21
SourceXtractor++, the next generation SExtractor
Loading...
Searching...
No Matches
MoffatModelFittingTask.cpp
Go to the documentation of this file.
1
17/*
18 * MoffatModelTask.cpp
19 *
20 * Created on: May 2, 2017
21 * Author: mschefer
22 */
23
24#include <iostream>
25#include <tuple>
26#include <vector>
27#include <valarray>
28#include <boost/any.hpp>
29#include <mutex>
30
31#include "AlexandriaKernel/memory_tools.h"
35#include "ElementsKernel/PathSearch.h"
36
39
42
55
59
61
62
65
67
76
78
80
82
83
84namespace SourceXtractor {
85
86using namespace ModelFitting;
88
89namespace {
90
91struct SourceModel {
92 double m_size;
95
99
100 SourceModel(double size, double x_guess, double y_guess, double pos_range,
101 double exp_flux_guess, double exp_radius_guess, double exp_aspect_guess, double exp_rot_guess) :
102
103 m_size(size),
106
107 x(createDependentParameter([x_guess](double dx) { return dx + x_guess + 0.5; }, dx)),
108 y(createDependentParameter([y_guess](double dy) { return dy + y_guess + 0.5; }, dy)),
109
110 // FIXME
112 moffat_i0(std::make_shared<EngineParameter>(exp_i0_guess, make_unique<ExpSigmoidConverter>(exp_i0_guess * .00001, exp_i0_guess * 1000))),
113
114 moffat_index(std::make_shared<EngineParameter>(1, make_unique<ExpSigmoidConverter>(0.5, 8))),
115 minkowski_exponent(std::make_shared<EngineParameter>(2, make_unique<ExpSigmoidConverter>(0.5, 10))),
116 flat_top_offset(std::make_shared<EngineParameter>(1, make_unique<ExpSigmoidConverter>(0.000001, 10))),
117
118 moffat_x_scale(std::make_shared<EngineParameter>(1, make_unique<ExpSigmoidConverter>(0.0001, 100.0))),
119 moffat_y_scale(std::make_shared<EngineParameter>(1, make_unique<ExpSigmoidConverter>(0.0001, 100.0))),
120 moffat_rotation(std::make_shared<EngineParameter>(-exp_rot_guess, make_unique<SigmoidConverter>(-2*M_PI, 2*M_PI)))
121 {
122 }
123
125 manager.registerParameter(dx);
126 manager.registerParameter(dy);
127
128 manager.registerParameter(moffat_i0);
129 manager.registerParameter(moffat_index);
130 manager.registerParameter(minkowski_exponent);
131 manager.registerParameter(flat_top_offset);
132
133 manager.registerParameter(moffat_x_scale);
134 manager.registerParameter(moffat_y_scale);
135 manager.registerParameter(moffat_rotation);
136 }
137
139 // Moffat model
140 {
142 auto moff = Euclid::make_unique<FlattenedMoffatComponent>(moffat_i0, moffat_index, minkowski_exponent, flat_top_offset);
143 component_list.clear();
144 component_list.emplace_back(std::move(moff));
146 std::move(component_list), moffat_x_scale, moffat_y_scale, moffat_rotation, m_size, m_size, x, y));
147 }
148 }
149};
150
151}
152
153
155 auto& source_stamp = source.getProperty<DetectionFrameSourceStamp>().getStamp();
156 auto& variance_stamp = source.getProperty<DetectionFrameSourceStamp>().getVarianceStamp();
157 auto& thresholded_stamp = source.getProperty<DetectionFrameSourceStamp>().getThresholdedStamp();
158 auto& threshold_map_stamp = source.getProperty<DetectionFrameSourceStamp>().getThresholdMapStamp();
160
161 // Computes the minimum flux that a detection should have (min. detection threshold for every pixel)
162 // This will be used instead of lower or negative fluxes that can happen for various reasons
163 double min_flux = 0.;
164 auto& pixel_coordinates = source.getProperty<PixelCoordinateList>().getCoordinateList();
165 for (auto pixel : pixel_coordinates) {
167
169 }
170
171 double pixel_scale = 1;
172
177
178 auto& pixel_centroid = source.getProperty<PixelCentroid>();
179 auto& shape_parameters = source.getProperty<ShapeParameters>();
180 auto iso_flux = source.getProperty<IsophotalFlux>().getFlux();
181
182 auto size = std::max<double>(source_stamp.getWidth(), source_stamp.getHeight());
183
184 double radius_guess = shape_parameters.getEllipseA() / 2.0;
185
186 double guess_x = pixel_centroid.getCentroidX() - stamp_top_left.m_x;
187 double guess_y = pixel_centroid.getCentroidY() - stamp_top_left.m_y;
188
190
192 double exp_aspect_guess = std::max<double>(shape_parameters.getEllipseB() / shape_parameters.getEllipseA(), 0.01);
193 double exp_rot_guess = shape_parameters.getEllipseTheta();
194
197
199 source_model->registerParameters(manager);
200
201 // Full frame model with all sources
205 (size_t) source_stamp.getWidth(), (size_t) source_stamp.getHeight(),
209 };
210
211 auto weight = VectorImage<SeFloat>::create(source_stamp.getWidth(), source_stamp.getHeight());
212 std::fill(weight->getData().begin(), weight->getData().end(), 1);
213
214 for (int y=0; y < source_stamp.getHeight(); y++) {
215 for (int x=0; x < source_stamp.getWidth(); x++) {
216 weight->at(x, y) = (thresholded_stamp.getValue(x, y) >= 0) ? 0 : 1;
217 }
218 }
219
220 for (auto pixel : pixel_coordinates) {
222 weight->at(pixel.m_x, pixel.m_y) = 1;
223 }
224
225 const auto& detection_frame_info = source.getProperty<DetectionFrameInfo>();
226 SeFloat gain = detection_frame_info.getGain();
227 SeFloat saturation = detection_frame_info.getSaturation();
228
229 for (int y=0; y < source_stamp.getHeight(); y++) {
230 for (int x=0; x < source_stamp.getWidth(); x++) {
231 auto back_var = variance_stamp.getValue(x, y);
232 if (saturation > 0 && source_stamp.getValue(x, y) >= saturation) {
233 weight->at(x, y) = 0;
234 } else if (weight->at(x, y)>0) {
235 if (gain > 0.0) {
236 weight->at(x, y) = sqrt(1.0 / (back_var + source_stamp.getValue(x, y) / gain));
237 } else {
238 weight->at(x, y) = sqrt(1.0 / back_var); // infinite gain
239 }
240 }
241 }
242 }
243
244 // FIXME we should be able to use the source_stamp Image interface directly
246
247 auto data_vs_model =
249
251 res_estimator.registerBlockProvider(move(data_vs_model));
252
253 // Perform the minimization
255 auto solution = engine->solveProblem(manager, res_estimator);
256 size_t iterations = solution.iteration_no;
257
259
260 {
261
262 // renders an image of the model for a single source with the final parameters
268 (size_t)source_stamp.getWidth(),
269 (size_t)source_stamp.getHeight(),
273 auto final_image = frame_model_after.getImage();
274
275 // integrates the flux for that source
276 double total_flux = 0;
277 for (int y = 0; y < source_stamp.getHeight(); y++) {
278 for (int x = 0; x < source_stamp.getWidth(); x++) {
281
282 // build final stamp
283 final_stamp->setValue(x, y, final_stamp->getValue(x, y) + final_image->getValue(x, y));
284
285 total_flux += final_image->getValue(x, y);
286 }
287 }
288
289 auto coordinate_system = source.getProperty<DetectionFrameCoordinates>().getCoordinateSystem();
290
291 SeFloat x = stamp_top_left.m_x + source_model->x->getValue() - 0.5f;
292 SeFloat y = stamp_top_left.m_y + source_model->y->getValue() - 0.5f;
293
294 source.setProperty<MoffatModelFitting>(
295 x, y,
296
297 source_model->moffat_i0->getValue(), source_model->moffat_index->getValue(),
298 source_model->minkowski_exponent->getValue(), source_model->flat_top_offset->getValue(), source_model->m_size,
299 source_model->moffat_x_scale->getValue(), source_model->moffat_y_scale->getValue(),
300 source_model->moffat_rotation->getValue(),
301
302 iterations);
303 }
304}
305
306}
307
std::shared_ptr< EngineParameter > moffat_i0
std::shared_ptr< EngineParameter > dx
std::shared_ptr< EngineParameter > moffat_rotation
double exp_i0_guess
std::shared_ptr< DependentParameter< std::shared_ptr< EngineParameter > > > x
std::shared_ptr< EngineParameter > moffat_y_scale
std::shared_ptr< EngineParameter > moffat_x_scale
std::shared_ptr< EngineParameter > moffat_index
std::shared_ptr< EngineParameter > minkowski_exponent
std::shared_ptr< EngineParameter > flat_top_offset
std::shared_ptr< DependentParameter< std::shared_ptr< EngineParameter > > > y
std::shared_ptr< EngineParameter > dy
double m_size
const double pixel_scale
Definition TestImage.cpp:74
Data vs model comparator which computes a modified residual, using asinh.
Class responsible for managing the parameters the least square engine minimizes.
EngineParameter are those derived from the minimization process.
static std::shared_ptr< LeastSquareEngine > create(const std::string &name, unsigned max_iterations=1000)
Provides to the LeastSquareEngine the residual values.
CoordinateConverter implementation using the sigmoid function.
A copy of the rectangular region of the detection image just large enough to include the whole Source...
Computes the isophotal flux and magnitude.
void computeProperties(SourceInterface &source) const override
Computes one or more properties for the Source.
The centroid of all the pixels in the source, weighted by their DetectionImage pixel values.
The SourceInterface is an abstract "source" that has properties attached to it.
static std::shared_ptr< VectorImage< T > > create(Args &&... args)
T fill(T... args)
T make_shared(T... args)
T move(T... args)
std::unique_ptr< T > make_unique(Args &&... args)
std::shared_ptr< DependentParameter< Parameters... > > createDependentParameter(typename DependentParameter< Parameters... >::ValueCalculator value_calculator, Parameters... parameters)
std::unique_ptr< DataVsModelResiduals< typename std::remove_reference< DataType >::type, typename std::remove_reference< ModelType >::type, typename std::remove_reference< WeightType >::type, typename std::remove_reference< Comparator >::type > > createDataVsModelResiduals(DataType &&data, ModelType &&model, WeightType &&weight, Comparator &&comparator)
STL namespace.
T sqrt(T... args)
A pixel coordinate made of two integers m_x and m_y.