SourceXtractorPlusPlus 0.22
SourceXtractor++, the next generation SExtractor
Loading...
Searching...
No Matches
FlexibleModelFittingIterativeTask.cpp
Go to the documentation of this file.
1
17
22
26
28
32
38
42
43namespace SourceXtractor {
44
45using namespace ModelFitting;
46
47static auto logger = Elements::Logging::getLogger("FlexibleModelFitting");
48
50 unsigned int max_iterations, double modified_chi_squared_scale,
54 double scale_factor,
55 int meta_iterations,
56 double deblend_factor,
57 double meta_iteration_stop,
58 size_t max_fit_size)
59 : m_least_squares_engine(least_squares_engine), m_max_iterations(max_iterations),
60 m_modified_chi_squared_scale(modified_chi_squared_scale), m_scale_factor(scale_factor),
61 m_meta_iterations(meta_iterations), m_deblend_factor(deblend_factor), m_meta_iteration_stop(meta_iteration_stop),
62 m_max_fit_size(max_fit_size * max_fit_size), m_parameters(parameters), m_frames(frames), m_priors(priors) {
63}
64
67
68namespace {
69
70PixelRectangle getFittingRect(SourceInterface& source, int frame_index) {
71 auto fitting_rect = source.getProperty<MeasurementFrameRectangle>(frame_index).getRect();
72
73 if (fitting_rect.getWidth() <= 0 || fitting_rect.getHeight() <= 0) {
74 return PixelRectangle();
75 } else {
76 const auto& frame_info = source.getProperty<MeasurementFrameInfo>(frame_index);
77
78 auto min = fitting_rect.getTopLeft();
79 auto max = fitting_rect.getBottomRight();
80
81 // FIXME temporary, for now just enlarge the area by a fixed amount of pixels
82 PixelCoordinate border = (max - min) * .8 + PixelCoordinate(2, 2);
83
84 min -= border;
85 max += border;
86
87 // clip to image size
88 min.m_x = std::max(min.m_x, 0);
89 min.m_y = std::max(min.m_y, 0);
90 max.m_x = std::min(max.m_x, frame_info.getWidth() - 1);
91 max.m_y = std::min(max.m_y, frame_info.getHeight() - 1);
92
93 return PixelRectangle(min, max);
94 }
95}
96
97bool isFrameValid(SourceInterface& source, int frame_index) {
98 auto stamp_rect = getFittingRect(source, frame_index);
99 return stamp_rect.getWidth() > 0 && stamp_rect.getHeight() > 0;
100}
101
102std::shared_ptr<VectorImage<SeFloat>> createImageCopy(SourceInterface& source, int frame_index) {
103 const auto& frame_images = source.getProperty<MeasurementFrameImages>(frame_index);
104 auto rect = getFittingRect(source, frame_index);
105
106 auto image = VectorImage<SeFloat>::create(frame_images.getImageChunk(
107 LayerSubtractedImage, rect.getTopLeft().m_x, rect.getTopLeft().m_y, rect.getWidth(), rect.getHeight()));
108
109 return image;
110}
111
112std::shared_ptr<VectorImage<SeFloat>> createWeightImage(SourceInterface& source, int frame_index) {
113 const auto& frame_images = source.getProperty<MeasurementFrameImages>(frame_index);
114 auto frame_image = frame_images.getLockedImage(LayerSubtractedImage);
115 auto frame_image_thresholded = frame_images.getLockedImage(LayerThresholdedImage);
116 auto variance_map = frame_images.getLockedImage(LayerVarianceMap);
117
118 const auto& frame_info = source.getProperty<MeasurementFrameInfo>(frame_index);
119 SeFloat gain = frame_info.getGain();
120 SeFloat saturation = frame_info.getSaturation();
121
122 auto rect = getFittingRect(source, frame_index);
123 auto weight = VectorImage<SeFloat>::create(rect.getWidth(), rect.getHeight());
124
125 for (int y = 0; y < rect.getHeight(); y++) {
126 for (int x = 0; x < rect.getWidth(); x++) {
127 auto back_var = variance_map->getValue(rect.getTopLeft().m_x + x, rect.getTopLeft().m_y + y);
128 auto pixel_val = frame_image->getValue(rect.getTopLeft().m_x + x, rect.getTopLeft().m_y + y);
129 if (saturation > 0 && pixel_val > saturation) {
130 weight->at(x, y) = 0;
131 }
132 else if (gain > 0.0 && pixel_val > 0.0) {
133 weight->at(x, y) = sqrt(1.0 / (back_var + pixel_val / gain));
134 }
135 else {
136 weight->at(x, y) = sqrt(1.0 / back_var); // infinite gain
137 }
138 }
139 }
140
141
142 return weight;
143}
144
147 std::shared_ptr<FlexibleModelFittingFrame> frame, PixelRectangle stamp_rect, double down_scaling=1.0) {
148
149 int frame_index = frame->getFrameNb();
150
151 auto frame_coordinates = source.getProperty<MeasurementFrameCoordinates>(frame_index).getCoordinateSystem();
152 auto ref_coordinates = source.getProperty<ReferenceCoordinates>().getCoordinateSystem();
153
154 auto psf_property = source.getProperty<SourcePsfProperty>(frame_index);
155 auto jacobian = source.getProperty<JacobianSource>(frame_index).asTuple();
156
157 // The model fitting module expects to get a PSF with a pixel scale, but we have the pixel sampling step size
158 // It will be used to compute the rastering grid size, and after convolving with the PSF the result will be
159 // downscaled before copied into the frame image.
160 // We can multiply here then, as the unit is pixel/pixel, rather than "/pixel or similar
161 auto source_psf = DownSampledImagePsf(psf_property.getPixelSampling(), psf_property.getPsf(), down_scaling);
162
163 std::vector<ConstantModel> constant_models;
164 std::vector<PointModel> point_models;
166
167 double model_size = std::max(stamp_rect.getWidth(), stamp_rect.getHeight());
168 for (auto model : frame->getModels()) {
169 model->addForSource(manager, source, constant_models, point_models, extended_models, model_size,
170 jacobian, ref_coordinates, frame_coordinates, stamp_rect.getTopLeft());
171 }
172
173 // Full frame model with all sources
175 pixel_scale, (size_t) stamp_rect.getWidth(), (size_t) stamp_rect.getHeight(),
176 std::move(constant_models), std::move(point_models), std::move(extended_models), source_psf);
177
178 return frame_model;
179}
180
181}
182
183
185 FittingState fitting_state;
186
187 for (auto& source : group) {
188 SourceState initial_state;
189 initial_state.flags = Flags::NONE;
190 initial_state.iterations = 0;
191 initial_state.stop_reason = 0;
192 initial_state.reduced_chi_squared = 0.0;
193 initial_state.duration = 0.0;
194
195 for (auto parameter : m_parameters) {
197 if (free_parameter != nullptr) {
198 initial_state.parameters_initial_values[free_parameter->getId()] =
199 initial_state.parameters_values[free_parameter->getId()] = free_parameter->getInitialValue(source);
200 } else {
201 initial_state.parameters_initial_values[parameter->getId()] =
202 initial_state.parameters_values[parameter->getId()] = 0.0;
203 }
204 // Make sure we have a default value for sigmas in case we cannot do the fit
205 initial_state.parameters_sigmas[parameter->getId()] = std::numeric_limits<double>::quiet_NaN();
206 }
207
208 // Store fitting areas for later output
209 for (auto frame : m_frames) {
210 int frame_index = frame->getFrameNb();
211 // Validate that each frame covers the model fitting region
212 if (isFrameValid(source, frame_index)) {
213 auto stamp_rect = getFittingRect(source, frame_index);
214 initial_state.fitting_areas_x.push_back(stamp_rect.getWidth());
215 initial_state.fitting_areas_y.push_back(stamp_rect.getHeight());
216 } else {
217 initial_state.fitting_areas_x.push_back(-1.f);
218 initial_state.fitting_areas_y.push_back(-1.f);
219 }
220 }
221
222 fitting_state.source_states.emplace_back(std::move(initial_state));
223 }
224
225 // TODO Sort sources by flux to fit brightest sources first?
226
227 // iterate over the whole group, fitting sources one at a time
228
229 double prev_chi_squared = 999999.9;
230 for (int iteration = 0; iteration < m_meta_iterations; iteration++) {
231 int index = 0;
232 for (auto& source : group) {
233 fitSource(group, source, index, fitting_state);
234 index++;
235 }
236
237 // evaluate reduced chi squared to bail out of meta iterations if no longer improving the fit
238
239 double chi_squared = 0.0;
240 for (auto& source_state : fitting_state.source_states) {
241 chi_squared += source_state.reduced_chi_squared;
242 }
243 chi_squared /= fitting_state.source_states.size();
244
245 if (fabs(chi_squared - prev_chi_squared) / chi_squared < m_meta_iteration_stop) {
246 break;
247 }
248
249 prev_chi_squared = chi_squared;
250 }
251
252
253 // Remove parameters that couldn't be fit from the output
254
255 for (size_t index = 0; index < group.size(); index++){
256 auto& source_state = fitting_state.source_states.at(index);
257
258 for (auto parameter : m_parameters) {
260
261 if (free_parameter != nullptr && !source_state.parameters_fitted[parameter->getId()]) {
262 source_state.parameters_values[parameter->getId()] = std::numeric_limits<double>::quiet_NaN();
263 source_state.parameters_sigmas[parameter->getId()] = std::numeric_limits<double>::quiet_NaN();
264 }
265 }
266 }
267
268 // output a property for every source
269 size_t index = 0;
270 for (auto& source : group) {
271 auto& source_state = fitting_state.source_states.at(index);
272
273 int meta_iterations = source_state.chi_squared_per_meta.size();
274 source_state.chi_squared_per_meta.resize(m_meta_iterations);
275 source_state.iterations_per_meta.resize(m_meta_iterations);
276
277 source.setProperty<FlexibleModelFitting>(source_state.iterations, source_state.stop_reason,
278 source_state.reduced_chi_squared, source_state.duration, source_state.flags,
279 source_state.parameters_values, source_state.parameters_sigmas,
280 source_state.chi_squared_per_meta, source_state.iterations_per_meta,
281 meta_iterations, source_state.fitting_areas_x, source_state.fitting_areas_y);
282
283 index++;
284 }
285
286 updateCheckImages(group, 1.0, fitting_state);
287}
288
289
291 SourceGroupInterface& group, SourceInterface& source, int source_index,
293 int frame_index = frame->getFrameNb();
294 auto rect = getFittingRect(source, frame_index);
295
296 double pixel_scale = 1.0;
297 FlexibleModelFittingParameterManager parameter_manager;
298 ModelFitting::EngineParameterManager engine_parameter_manager {};
299 int n_free_parameters = 0;
300
301 int index = 0;
302 for (auto& src : group) {
303 if (index != source_index) {
304 for (auto parameter : m_parameters) {
306
307 if (free_parameter != nullptr) {
308 ++n_free_parameters;
309
310 // Initial with the values from the current iteration run
311 parameter_manager.addParameter(src, parameter,
312 free_parameter->create(parameter_manager, engine_parameter_manager, src,
313 state.source_states[index].parameters_initial_values.at(free_parameter->getId()),
314 state.source_states[index].parameters_values.at(free_parameter->getId())));
315
316 } else {
317 parameter_manager.addParameter(src, parameter,
318 parameter->create(parameter_manager, engine_parameter_manager, src));
319 }
320 }
321 }
322 index++;
323 }
324
325 auto deblend_image = VectorImage<SeFloat>::create(rect.getWidth(), rect.getHeight());
326 index = 0;
327 for (auto& src : group) {
328 if (index != source_index) {
329 auto frame_model = createFrameModel(src, pixel_scale, parameter_manager, frame, rect);
330 auto final_stamp = frame_model.getImage();
331
332 for (int y = 0; y < final_stamp->getHeight(); ++y) {
333 for (int x = 0; x < final_stamp->getWidth(); ++x) {
334 deblend_image->at(x, y) += final_stamp->at(x, y);
335 }
336 }
337 }
338 index++;
339 }
340
341 return deblend_image;
342}
343
345 FlexibleModelFittingParameterManager& parameter_manager,
346 ModelFitting::EngineParameterManager& engine_parameter_manager,
347 SourceInterface& source, int index, FittingState& state) const {
348 int free_parameters_nb = 0;
349 for (auto parameter : m_parameters) {
351
352 if (free_parameter != nullptr) {
353 ++free_parameters_nb;
354
355 // Initial with the values from the current iteration run
356 parameter_manager.addParameter(source, parameter,
357 free_parameter->create(parameter_manager, engine_parameter_manager, source,
358 state.source_states[index].parameters_initial_values.at(free_parameter->getId()),
359 state.source_states[index].parameters_values.at(free_parameter->getId())));
360 } else {
361 parameter_manager.addParameter(source, parameter,
362 parameter->create(parameter_manager, engine_parameter_manager, source));
363 }
364
365 }
366
367 // Reset access checks, as a dependent parameter could have triggered it
368 parameter_manager.clearAccessCheck();
369
370 return free_parameters_nb;
371}
372
374 ResidualEstimator& res_estimator, int& good_pixels,
375 SourceGroupInterface& group, SourceInterface& source, int index, FittingState& state, double down_scaling) const {
376
377 double pixel_scale = 1.0;
378
379 int valid_frames = 0;
380 for (auto frame : m_frames) {
381 int frame_index = frame->getFrameNb();
382 // Validate that each frame covers the model fitting region
383 if (isFrameValid(source, frame_index)) {
384 valid_frames++;
385
386 auto stamp_rect = getFittingRect(source, frame_index);
387 auto frame_model = createFrameModel(source, pixel_scale, parameter_manager, frame, stamp_rect, down_scaling);
388
389 auto image = createImageCopy(source, frame_index);
390
391 auto deblend_image = createDeblendImage(group, source, index, frame, state);
392 for (int y = 0; y < image->getHeight(); ++y) {
393 for (int x = 0; x < image->getWidth(); ++x) {
394 image->at(x, y) -= m_deblend_factor * deblend_image->at(x, y);
395 }
396 }
397
398 auto weight = createWeightImage(source, frame_index);
399
400 // count number of pixels that can be used for fitting
401 for (int y = 0; y < weight->getHeight(); ++y) {
402 for (int x = 0; x < weight->getWidth(); ++x) {
403 good_pixels += (weight->at(x, y) != 0.);
404 }
405 }
406
407 // Setup residuals
408 auto data_vs_model =
409 createDataVsModelResiduals(image, std::move(frame_model), weight,
410 //LogChiSquareComparator(m_modified_chi_squared_scale));
412 res_estimator.registerBlockProvider(std::move(data_vs_model));
413 }
414 }
415
416 return valid_frames;
417}
418
420 SourceGroupInterface& group, SourceInterface& source, int index, FittingState& state) const {
421
422 double pixel_scale = 1.0;
423
424 int total_data_points = 0;
425 SeFloat avg_reduced_chi_squared = computeChiSquared(group, source, index,pixel_scale, parameter_manager, total_data_points, state);
426
427 int nb_of_free_parameters = 0;
428 for (auto parameter : m_parameters) {
429 bool is_free_parameter = std::dynamic_pointer_cast<FlexibleModelFittingFreeParameter>(parameter).get();
430 bool accessed_by_modelfitting = parameter_manager.isParamAccessed(source, parameter);
431 if (is_free_parameter && accessed_by_modelfitting) {
432 nb_of_free_parameters++;
433 }
434 }
435 avg_reduced_chi_squared /= (total_data_points - nb_of_free_parameters);
436
437 return avg_reduced_chi_squared;
438}
439
441 FlexibleModelFittingParameterManager& parameter_manager, SourceInterface& source,
442 SeFloat avg_reduced_chi_squared, SeFloat duration, unsigned int iterations, unsigned int stop_reason, Flags flags,
444 int index, FittingState& state) const {
446 // Collect parameters for output
447 std::unordered_map<int, double> parameters_values, parameters_sigmas;
448 std::unordered_map<int, bool> parameters_fitted;
449
450 for (auto parameter : m_parameters) {
451 bool is_dependent_parameter = std::dynamic_pointer_cast<FlexibleModelFittingDependentParameter>(parameter).get();
452 bool is_constant_parameter = std::dynamic_pointer_cast<FlexibleModelFittingConstantParameter>(parameter).get();
453 bool accessed_by_modelfitting = parameter_manager.isParamAccessed(source, parameter);
454 auto modelfitting_parameter = parameter_manager.getParameter(source, parameter);
455
456 if (is_constant_parameter || is_dependent_parameter || accessed_by_modelfitting) {
457 parameters_values[parameter->getId()] = modelfitting_parameter->getValue();
458 parameters_sigmas[parameter->getId()] = parameter->getSigma(parameter_manager, source, solution.parameter_sigmas);
459 parameters_fitted[parameter->getId()] = true;
460 } else {
461 parameters_values[parameter->getId()] = state.source_states[index].parameters_values[parameter->getId()];
462 parameters_sigmas[parameter->getId()] = state.source_states[index].parameters_sigmas[parameter->getId()];
463 parameters_fitted[parameter->getId()] = false;
464
465 // Need to cascade the NaN to any potential dependent parameter
466 auto engine_parameter = std::dynamic_pointer_cast<EngineParameter>(modelfitting_parameter);
467 if (engine_parameter) {
468 engine_parameter->setEngineValue(std::numeric_limits<double>::quiet_NaN());
469 }
470
471 flags |= Flags::PARTIAL_FIT;
472 }
473 }
474
475 state.source_states[index].parameters_values = parameters_values;
476 state.source_states[index].parameters_sigmas = parameters_sigmas;
477 state.source_states[index].parameters_fitted = parameters_fitted;
478 state.source_states[index].reduced_chi_squared = avg_reduced_chi_squared;
479 state.source_states[index].chi_squared_per_meta.emplace_back(avg_reduced_chi_squared);
480 state.source_states[index].duration += duration;
481 state.source_states[index].iterations += iterations;
482 state.source_states[index].iterations_per_meta.emplace_back(iterations);
483 state.source_states[index].stop_reason = stop_reason;
484 state.source_states[index].flags = flags;
485}
486
488
490 // Determine size of fitted area and if needed downsize factor
491
492 double fit_size = 0;
493 for (auto frame : m_frames) {
494 int frame_index = frame->getFrameNb();
495 // Validate that each frame covers the model fitting region
496 if (isFrameValid(source, frame_index)) {
497 auto psf_property = source.getProperty<SourcePsfProperty>(frame_index);
498 auto stamp_rect = getFittingRect(source, frame_index);
499 fit_size = std::max(fit_size, stamp_rect.getWidth() * stamp_rect.getHeight() /
500 (psf_property.getPixelSampling() * psf_property.getPixelSampling()));
501 }
502 }
503
504 double down_scaling = m_scale_factor;
505 if (fit_size > m_max_fit_size * 2.0) {
506 down_scaling *= sqrt(double(m_max_fit_size) / fit_size);
507 logger.warn() << "Exceeding max fit size: " << fit_size << " / " << m_max_fit_size
508 << " scaling factor: " << down_scaling;
509 }
510
512 // Prepare parameters
513
514 FlexibleModelFittingParameterManager parameter_manager;
515 ModelFitting::EngineParameterManager engine_parameter_manager{};
516 int n_free_parameters = fitSourcePrepareParameters(
517 parameter_manager, engine_parameter_manager, source, index, state);
518
520 // Add models for all frames
521 ResidualEstimator res_estimator {};
522 int n_good_pixels = 0;
523 int valid_frames = fitSourcePrepareModels(
524 parameter_manager, res_estimator, n_good_pixels, group, source, index, state, down_scaling);
525
527 // Check that we had enough data for the fit
528
529 Flags flags = Flags::NONE;
530
531 if (valid_frames == 0) {
532 flags = Flags::OUTSIDE;
533 }
534 else if (n_good_pixels < n_free_parameters) {
536 }
537
538 // Do not run the model fitting for the flags above
539 if (flags != Flags::NONE) {
540 return;
541 }
542
543 if (down_scaling < 1.0) {
544 flags |= Flags::DOWNSAMPLED;
545 }
546
547
549 // Add priors
550 for (auto prior : m_priors) {
551 prior->setupPrior(parameter_manager, source, res_estimator);
552 }
553
555 // Model fitting
556
558 auto solution = engine->solveProblem(engine_parameter_manager, res_estimator);
559
560 auto iterations = solution.iteration_no;
561 auto stop_reason = solution.engine_stop_reason;
562 if (solution.status_flag == LeastSquareSummary::ERROR) {
563 flags |= Flags::ERROR;
564 }
565 auto duration = solution.duration;
566
568 // compute chi squared
569
570 SeFloat avg_reduced_chi_squared = fitSourceComputeChiSquared(parameter_manager, group, source, index, state);
571
573 // update state with results
574 fitSourceUpdateState(parameter_manager, source, avg_reduced_chi_squared, duration, iterations, stop_reason, flags, solution,
575 index, state);
576}
577
579 double pixel_scale, FittingState& state) const {
580
581 // recreate parameters
582
583 FlexibleModelFittingParameterManager parameter_manager;
584 ModelFitting::EngineParameterManager engine_parameter_manager {};
585
586 int index = 0;
587 for (auto& src : group) {
588 for (auto parameter : m_parameters) {
590
591 if (free_parameter != nullptr) {
592 // Initialize with the values from the current iteration run
593 parameter_manager.addParameter(src, parameter,
594 free_parameter->create(parameter_manager, engine_parameter_manager, src,
595 state.source_states[index].parameters_initial_values.at(free_parameter->getId()),
596 state.source_states[index].parameters_values.at(free_parameter->getId())));
597 } else {
598 parameter_manager.addParameter(src, parameter,
599 parameter->create(parameter_manager, engine_parameter_manager, src));
600 }
601 }
602 index++;
603 }
604
605 for (auto& src : group) {
606 for (auto frame : m_frames) {
607 int frame_index = frame->getFrameNb();
608
609 if (isFrameValid(src, frame_index)) {
610 auto stamp_rect = getFittingRect(src, frame_index);
611
612 auto frame_model = createFrameModel(src, pixel_scale, parameter_manager, frame, stamp_rect);
613 auto final_stamp = frame_model.getImage();
614
615 auto debug_image = CheckImages::getInstance().getModelFittingImage(frame_index);
616 if (debug_image) {
617 ImageAccessor<SeFloat> debugAccessor(debug_image);
618 for (int x = 0; x < final_stamp->getWidth(); x++) {
619 for (int y = 0; y < final_stamp->getHeight(); y++) {
620 auto x_coord = stamp_rect.getTopLeft().m_x + x;
621 auto y_coord = stamp_rect.getTopLeft().m_y + y;
622 debug_image->setValue(x_coord, y_coord,
623 debugAccessor.getValue(x_coord, y_coord) + final_stamp->getValue(x, y));
624 }
625 }
626 }
627
628 }
629 }
630 }
631}
632
634 std::shared_ptr<const Image<SeFloat>> model, std::shared_ptr<const Image<SeFloat>> weights, int& data_points) const {
635 double reduced_chi_squared = 0.0;
636 data_points = 0;
637
638 ImageAccessor<SeFloat> imageAccessor(image), modelAccessor(model);
639 ImageAccessor<SeFloat> weightAccessor(weights);
640
641 for (int y=0; y < image->getHeight(); y++) {
642 for (int x=0; x < image->getWidth(); x++) {
643 double tmp = imageAccessor.getValue(x, y) - modelAccessor.getValue(x, y);
644 reduced_chi_squared += tmp * tmp * weightAccessor.getValue(x, y) * weightAccessor.getValue(x, y);
645 if (weightAccessor.getValue(x, y) > 0) {
646 data_points++;
647 }
648 }
649 }
650 return reduced_chi_squared;
651}
652
654 double pixel_scale, FlexibleModelFittingParameterManager& manager, int& total_data_points, FittingState& state) const {
655 SeFloat total_chi_squared = 0;
656 total_data_points = 0;
657 int valid_frames = 0;
658 for (auto frame : m_frames) {
659 int frame_index = frame->getFrameNb();
660 // Validate that each frame covers the model fitting region
661 if (isFrameValid(source, frame_index)) {
662 valid_frames++;
663 auto stamp_rect = getFittingRect(source, frame_index);
664 auto frame_model = createFrameModel(source, pixel_scale, manager, frame, stamp_rect);
665 auto final_stamp = frame_model.getImage();
666
667 auto image = createImageCopy(source, frame_index);
668 auto deblend_image = createDeblendImage(group, source, index, frame, state);
669 for (int y = 0; y < image->getHeight(); ++y) {
670 for (int x = 0; x < image->getWidth(); ++x) {
671 image->at(x, y) -= deblend_image->at(x, y);
672 }
673 }
674
675 auto weight = createWeightImage(source, frame_index);
676
677 int data_points = 0;
678 SeFloat chi_squared = computeChiSquaredForFrame(image, final_stamp, weight, data_points);
679
680 total_data_points += data_points;
681 total_chi_squared += chi_squared;
682 }
683 }
684
685 return total_chi_squared;
686}
687
688}
689
690
691
const double pixel_scale
Definition TestImage.cpp:74
static Logging getLogger(const std::string &name="")
Data vs model comparator which computes a modified residual, using asinh.
Class responsible for managing the parameters the least square engine minimizes.
static std::shared_ptr< LeastSquareEngine > create(const std::string &name, unsigned max_iterations=1000)
Provides to the LeastSquareEngine the residual values.
void registerBlockProvider(std::unique_ptr< ResidualBlockProvider > provider)
Registers a ResidualBlockProvider to the ResidualEstimator.
static CheckImages & getInstance()
std::shared_ptr< WriteableImage< MeasurementImage::PixelType > > getModelFittingImage(unsigned int frame_number)
void fitSourceUpdateState(FlexibleModelFittingParameterManager &parameter_manager, SourceInterface &source, SeFloat avg_reduced_chi_squared, SeFloat duration, unsigned int iterations, unsigned int stop_reason, Flags flags, ModelFitting::LeastSquareSummary solution, int index, FittingState &state) const
void fitSource(SourceGroupInterface &group, SourceInterface &source, int index, FittingState &state) const
int fitSourcePrepareParameters(FlexibleModelFittingParameterManager &parameter_manager, ModelFitting::EngineParameterManager &engine_parameter_manager, SourceInterface &source, int index, FittingState &state) const
void computeProperties(SourceGroupInterface &group) const override
Computes one or more properties for the SourceGroup and/or the Sources it contains.
SeFloat fitSourceComputeChiSquared(FlexibleModelFittingParameterManager &parameter_manager, SourceGroupInterface &group, SourceInterface &source, int index, FittingState &state) const
std::vector< std::shared_ptr< FlexibleModelFittingFrame > > m_frames
std::shared_ptr< VectorImage< SeFloat > > createDeblendImage(SourceGroupInterface &group, SourceInterface &source, int source_index, std::shared_ptr< FlexibleModelFittingFrame > frame, FittingState &state) const
int fitSourcePrepareModels(FlexibleModelFittingParameterManager &parameter_manager, ModelFitting::ResidualEstimator &res_estimator, int &good_pixels, SourceGroupInterface &group, SourceInterface &source, int index, FittingState &state, double downscaling) const
FlexibleModelFittingIterativeTask(const std::string &least_squares_engine, unsigned int max_iterations, double modified_chi_squared_scale, std::vector< std::shared_ptr< FlexibleModelFittingParameter > > parameters, std::vector< std::shared_ptr< FlexibleModelFittingFrame > > frames, std::vector< std::shared_ptr< FlexibleModelFittingPrior > > priors, double scale_factor=1.0, int meta_iterations=3, double deblend_factor=1.0, double meta_iteration_stop=0.0001, size_t max_fit_size=100)
std::vector< std::shared_ptr< FlexibleModelFittingParameter > > m_parameters
SeFloat computeChiSquared(SourceGroupInterface &group, SourceInterface &source, int index, double pixel_scale, FlexibleModelFittingParameterManager &manager, int &total_data_points, FittingState &state) const
SeFloat computeChiSquaredForFrame(std::shared_ptr< const Image< SeFloat > > image, std::shared_ptr< const Image< SeFloat > > model, std::shared_ptr< const Image< SeFloat > > weights, int &data_points) const
void updateCheckImages(SourceGroupInterface &group, double pixel_scale, FittingState &state) const
std::vector< std::shared_ptr< FlexibleModelFittingPrior > > m_priors
void addParameter(const SourceInterface &source, std::shared_ptr< const FlexibleModelFittingParameter > parameter, std::shared_ptr< ModelFitting::BasicParameter > engine_parameter)
bool isParamAccessed(const SourceInterface &source, std::shared_ptr< const FlexibleModelFittingParameter > parameter) const
std::shared_ptr< ModelFitting::BasicParameter > getParameter(const SourceInterface &source, std::shared_ptr< const FlexibleModelFittingParameter > parameter) const
Interface representing an image.
Definition Image.h:44
std::shared_ptr< ImageAccessor< SeFloat > > getLockedImage(FrameImageLayer layer) const
Defines the interface used to group sources.
virtual unsigned int size() const =0
The SourceInterface is an abstract "source" that has properties attached to it.
const PropertyType & getProperty(unsigned int index=0) const
Convenience template method to call getProperty() with a more user-friendly syntax.
static std::shared_ptr< VectorImage< T > > create(Args &&... args)
T fabs(T... args)
T max(T... args)
T min(T... args)
T move(T... args)
static Elements::Logging logger
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)
Flags
Flagging of bad sources.
Definition SourceFlags.h:37
@ DOWNSAMPLED
The fit was done on a downsampled image due to exceeding max size.
Definition SourceFlags.h:50
@ OUTSIDE
The object is completely outside of the measurement frame.
Definition SourceFlags.h:44
@ NONE
No flag is set.
Definition SourceFlags.h:38
@ ERROR
Error flag: something bad happened during the measurement, model fitting, etc.
Definition SourceFlags.h:47
@ INSUFFICIENT_DATA
There are not enough good pixels to fit the parameters.
Definition SourceFlags.h:46
@ PARTIAL_FIT
Some/all of the model parameters could not be fitted.
Definition SourceFlags.h:45
@ LayerVarianceMap
Definition Frame.h:45
@ LayerThresholdedImage
Definition Frame.h:41
@ LayerSubtractedImage
Definition Frame.h:39
SeFloat32 SeFloat
Definition Types.h:32
T dynamic_pointer_cast(T... args)
T push_back(T... args)
T quiet_NaN(T... args)
T sqrt(T... args)
Class containing the summary information of solving a least square minimization problem.
std::vector< double > parameter_sigmas
1-sigma margin of error for all the parameters