MOONS Pipeline Reference Manual 0.13.2
moo_localise.c
1/*
2 * This file is part of the MOONS Pipeline
3 * Copyright (C) 2002-2016 European Southern Observatory
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24/*-----------------------------------------------------------------------------
25 Includes
26 -----------------------------------------------------------------------------*/
27#include <math.h>
28#include <string.h>
29#include <cpl.h>
30#include <hdrl.h>
31#include "moo_utils.h"
32#include "moo_dfs.h"
33#include "moo_pfits.h"
34#include "moo_qc.h"
35#include "moo_params.h"
36#include "moo_badpix.h"
37#include "moo_single.h"
38#include "moo_det.h"
39#include "moo_localise.h"
40#include "moo_loc_single.h"
41#include "moo_detector.h"
42#include "moo_fibres_table.h"
43#include "moo_line_table.h"
44
45#ifdef _OPENMP
46#include <omp.h>
47#endif
48
49/*----------------------------------------------------------------------------*/
54/*----------------------------------------------------------------------------*/
55
56typedef struct
57{
58 double center;
59 double width;
60 int ymin;
61 int ymax;
62 int num;
63 int health;
64 float goodfrac;
65} fibre;
68/*-----------------------------------------------------------------------------
69 Function codes
70 -----------------------------------------------------------------------------*/
71
72/*----------------------------------------------------------------------------*/
81/*----------------------------------------------------------------------------*/
82static double
83_moo_get_flux(cpl_vector *fluxes, double posy)
84{
85 double flux;
86
87 int nx = cpl_vector_get_size(fluxes);
88 int pos1 = (int)floor(posy);
89 int pos2 = pos1;
90
91 double flux1 = cpl_vector_get(fluxes, pos1 - 1);
92 while (isnan(flux1)) {
93 pos1--;
94 flux1 = cpl_vector_get(fluxes, pos1 - 1);
95 }
96 if (pos1 == nx) {
97 flux = flux1;
98 }
99 else {
100 double flux2 = NAN;
101 while (isnan(flux2)) {
102 pos2++;
103 flux2 = cpl_vector_get(fluxes, pos2 - 1);
104 }
105 flux = flux1 + (posy - pos1) * (flux2 - flux1);
106 }
107 return flux;
108}
109
110/*----------------------------------------------------------------------------*/
119/*----------------------------------------------------------------------------*/
120static double
121_moo_get_image_flux(const cpl_image *fluxes, int x, double posy)
122{
123 double flux;
124 int rej;
125 int ny = cpl_image_get_size_y(fluxes);
126 int pos1 = (int)floor(posy);
127 int pos2 = pos1;
128
129 double flux1 = cpl_image_get(fluxes, x, pos1, &rej);
130 while (rej == 1) {
131 pos1--;
132 flux1 = cpl_image_get(fluxes, x, pos1, &rej);
133 }
134 if (pos1 == ny) {
135 flux = flux1;
136 }
137 else {
138 double flux2;
139 rej = 1;
140 while (rej == 1) {
141 pos2++;
142 flux2 = cpl_image_get(fluxes, x, pos2, &rej);
143 }
144 double diff = pos2 - pos1;
145 flux = (pos2 - posy) / diff * flux1 + (posy - pos1) / diff * flux2;
146 }
147 return flux;
148}
149/*----------------------------------------------------------------------------*/
158/*----------------------------------------------------------------------------*/
159static double
160_moo_get_flux_integrate_low(cpl_vector *fluxes, double posy, double *cbin)
161{
162 double flux;
163
164 int ipos = (int)round(posy);
165
166 flux = cpl_vector_get(fluxes, ipos - 1);
167 double frac = ipos + 0.5 - posy;
168 flux = frac * flux;
169 *cbin = posy + frac / 2.;
170 return flux;
171}
172
173/*----------------------------------------------------------------------------*/
182/*----------------------------------------------------------------------------*/
183static double
184_moo_get_flux_integrate_up(cpl_vector *fluxes, double posy, double *cbin)
185{
186 double flux;
187
188 int ipos = (int)round(posy);
189
190 flux = cpl_vector_get(fluxes, ipos - 1);
191 double frac = posy - (ipos - 0.5);
192 flux = frac * flux;
193 *cbin = posy - frac / 2.;
194 return flux;
195}
196
197/*----------------------------------------------------------------------------*/
209/*----------------------------------------------------------------------------*/
210static cpl_bivector *
211_moo_extract_profile(cpl_vector *fluxes, double ymin, double ymax)
212{
213 cpl_ensure(fluxes, CPL_ERROR_NULL_INPUT, NULL);
214 cpl_ensure((ymax - ymin) > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
215
216 int y1 = ceil(ymin);
217 int y2 = floor(ymax);
218 int size = y2 - y1 + 3;
219
220 cpl_bivector *points = cpl_bivector_new(size);
221 cpl_vector *y = cpl_bivector_get_x(points);
222 cpl_vector *f = cpl_bivector_get_y(points);
223
224 double fmin = _moo_get_flux(fluxes, ymin);
225 double fmax = _moo_get_flux(fluxes, ymax);
226
227 cpl_vector_set(y, 0, ymin);
228 cpl_vector_set(f, 0, fmin);
229 cpl_vector_set(y, size - 1, ymax);
230 cpl_vector_set(f, size - 1, fmax);
231
232 int i;
233 for (i = y1; i <= y2; i++) {
234 double flux = cpl_vector_get(fluxes, i - 1);
235 cpl_vector_set(y, i - y1 + 1, i);
236 cpl_vector_set(f, i - y1 + 1, flux);
237 }
238
239 return points;
240}
241
242static cpl_bivector *
243_moo_extract_profile_integrate(cpl_vector *fluxes, double ymin, double ymax)
244{
245 cpl_ensure(fluxes, CPL_ERROR_NULL_INPUT, NULL);
246 cpl_ensure((ymax - ymin) > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
247
248 double ycmin;
249 double ycmax;
250 double fmin = _moo_get_flux_integrate_low(fluxes, ymin, &ycmin);
251 double fmax = _moo_get_flux_integrate_up(fluxes, ymax, &ycmax);
252 int y1 = ceil(ycmin);
253 int y2 = floor(ycmax);
254
255 int size = y2 - y1 + 3;
256
257 cpl_bivector *points = cpl_bivector_new(size);
258 cpl_vector *y = cpl_bivector_get_x(points);
259 cpl_vector *f = cpl_bivector_get_y(points);
260
261 cpl_vector_set(y, 0, ycmin);
262 cpl_vector_set(f, 0, fmin);
263 cpl_vector_set(y, size - 1, ycmax);
264 cpl_vector_set(f, size - 1, fmax);
265
266 int i;
267
268 for (i = y1; i <= y2; i++) {
269 double flux = cpl_vector_get(fluxes, i - 1);
270 cpl_vector_set(y, i - y1 + 1, i);
271 cpl_vector_set(f, i - y1 + 1, flux);
272 }
273
274 return points;
275}
276/*----------------------------------------------------------------------------*/
288/*----------------------------------------------------------------------------*/
289static void
290_moo_profile_find_thresh_positions(cpl_vector *fluxes,
291 double centroid_y,
292 double thresh_low,
293 double thresh_up,
294 double *y_low,
295 double *y_up)
296{
297 int size = cpl_vector_get_size(fluxes);
298
299 int centroid_ylow = (int)floor(centroid_y);
300 int centroid_yup = centroid_ylow + 1;
301
302 double centroid_f = _moo_get_flux(fluxes, centroid_y);
303
304 int i = 0;
305 double f1 = centroid_f;
306 double y1 = centroid_y;
307 /*
308 while(f1>thresh_low){
309 y1 = centroid_ylow+i;
310 f2 = f1;
311 f1 = cpl_vector_get(fluxes,y1-1);
312 //cpl_msg_info("test","update with %f at pos %f",f1,y1);
313 i--;
314 }
315 cpl_msg_info("test","find LO f %f for t %f at pos %f and f2 %f",f1,thresh_low,y1,f2);
316 i=0;
317 f1 = centroid_f;
318 f2 = centroid_f;
319 y1 = centroid_y;
320
321 while(f1>thresh_up){
322 y1 = centroid_yup+i;
323 f2 = f1;
324 f1 = cpl_vector_get(fluxes,y1-1);
325 //cpl_msg_info("test","update with %f at pos %f",f1,y1);
326 i++;
327 }
328 cpl_msg_info("test","find UP f %f for t %f at pos %f and f2 %f",f1,thresh_up,y1,f2);
329
330 f1 = centroid_f;
331 f2 = centroid_f;
332 y1 = centroid_y;*/
333 for (i = centroid_yup; i > 0; i--) {
334 double f2 = cpl_vector_get(fluxes, i - 1);
335 if (!isnan(f2)) {
336 if (f2 <= thresh_low) {
337 *y_low = i + (thresh_low - f2) / (f1 - f2) * (y1 - i);
338 if ((isnan(*y_low))) {
339 *y_low = (y1 + i) / 2.0;
340 }
341 break;
342 }
343 f1 = f2;
344 y1 = i;
345 }
346 }
347 f1 = centroid_f;
348 y1 = centroid_y;
349
350 for (i = centroid_ylow; i < size - 1; i++) {
351 double f2 = cpl_vector_get(fluxes, i - 1);
352 if (!isnan(f2)) {
353 if (f2 <= thresh_up) {
354 *y_up = i + (thresh_up - f2) / (f1 - f2) * (y1 - i);
355 if ((isnan(*y_up))) {
356 *y_up = (y1 + i) / 2.0;
357 }
358 break;
359 }
360 f1 = f2;
361 y1 = i;
362 }
363 }
364 // cpl_msg_info("test","find OLD %f %f",*y_low, *y_up);
365}
366
367/*----------------------------------------------------------------------------*/
380/*----------------------------------------------------------------------------*/
381static void
382_moo_profile_find_image_thresh_positions(const cpl_image *fluxes,
383 int x,
384 double centroid_y,
385 double thresh_low,
386 double thresh_up,
387 double *y_low,
388 double *y_up)
389{
390 double f2 = NAN;
391
392 int ny = cpl_image_get_size_y(fluxes);
393 int centroid_ylow = (int)floor(centroid_y);
394 int centroid_yup = centroid_ylow + 1;
395
396 double centroid_f = _moo_get_image_flux(fluxes, x, centroid_y);
397 int i = 0;
398 double f1 = centroid_f;
399 double y1 = centroid_y;
400
401 for (i = centroid_yup; i > 0; i--) {
402 int rej = 0;
403 f2 = cpl_image_get(fluxes, x, i, &rej);
404 if (rej == 0) {
405 if (f2 <= thresh_low) {
406 *y_low = i + (thresh_low - f2) / (f1 - f2) * (y1 - i);
407 if ((isnan(*y_low))) {
408 *y_low = (y1 + i) / 2.0;
409 }
410 break;
411 }
412 f1 = f2;
413 y1 = i;
414 }
415 }
416 f1 = centroid_f;
417 y1 = centroid_y;
418
419 for (i = centroid_ylow; i < ny; i++) {
420 int rej = 0;
421 f2 = cpl_image_get(fluxes, x, i, &rej);
422 if (rej == 0) {
423 if (f2 <= thresh_up) {
424 *y_up = i + (thresh_up - f2) / (f1 - f2) * (y1 - i);
425 if ((isnan(*y_up))) {
426 *y_up = (y1 + i) / 2.0;
427 }
428 break;
429 }
430 f1 = f2;
431 y1 = i;
432 }
433 }
434}
435
436/*----------------------------------------------------------------------------*/
444/*----------------------------------------------------------------------------*/
445static int
446_check_trace_guess(double center, double width)
447{
448 int flag = MOONS_FLAG_GOOD;
449
450 if (isnan(center) || isnan(width)) {
451 flag = MOONS_FLAG_NAN_IN_TRACE_GUESS;
452 }
453 return flag;
454}
455
456/*----------------------------------------------------------------------------*/
466/*----------------------------------------------------------------------------*/
467static int
468_check_bpm(hdrl_image *himg, int x, double center, double width)
469{
470 int flag = MOONS_FLAG_GOOD;
471 const cpl_mask *bpm = hdrl_image_get_mask_const(himg);
472
473 int lly = (int)(center - width / 2);
474 int ury = (int)(center + width / 2);
475
476 cpl_mask *extractm = cpl_mask_extract(bpm, x, lly, x, ury);
477
478 int nbrej = cpl_mask_count(extractm);
479
480 cpl_mask_delete(extractm);
481
482 if (nbrej > 2) {
483 flag = MOONS_FLAG_BADPIX;
484 }
485
486 return flag;
487}
488
489/*----------------------------------------------------------------------------*/
499/*----------------------------------------------------------------------------*/
500static int
501_check_snr(cpl_vector *fluxes,
502 cpl_vector *errs,
503 double centroid_y,
504 double b1_y,
505 double b2_y,
506 double ref_snr,
507 double *snr)
508{
509 int flag = MOONS_FLAG_GOOD;
510
511 double centroid_flux = _moo_get_flux(fluxes, centroid_y);
512 double centroid_err = _moo_get_flux(errs, centroid_y);
513
514 double b1_flux = _moo_get_flux(fluxes, b1_y);
515 double b1_err = _moo_get_flux(errs, b1_y);
516
517 double b2_flux = _moo_get_flux(fluxes, b2_y);
518 double b2_err = _moo_get_flux(errs, b2_y);
519
520 double b_flux = (b1_flux + b2_flux) / 2.0;
521 if (b_flux <= 0) {
522 b_flux = 0;
523 }
524
525 double A = centroid_flux - b_flux;
526 double eA = sqrt(centroid_err * centroid_err +
527 (b1_err * b1_err + b2_err * b2_err) / 4);
528 double snrA = A / eA;
529 *snr = snrA;
530 if (snrA <= ref_snr) {
531 flag = MOONS_FLAG_NON_SIGNIFICANT_FLUX;
532 // cpl_msg_info("test","A/eA = %f/%f = %f",A,eA,A/eA);
533 }
534
535 return flag;
536}
537
538/*----------------------------------------------------------------------------*/
551/*----------------------------------------------------------------------------*/
552static void
553_moo_profile_find_background_flux(cpl_vector *fluxes,
554 double centroid,
555 double width,
556 double frac,
557 double *b_ylow,
558 double *b_yup,
559 double *thresh_low,
560 double *thresh_up)
561{
562 // cpl_msg_info(__func__,"estimate background for centroid %f",centroid);
563 int size = cpl_vector_get_size(fluxes);
564
565 int centroid_y1 = (int)floor(centroid);
566 int centroid_y2 = centroid_y1 + 1;
567 double centroid_f = _moo_get_flux(fluxes, centroid);
568 int i;
569 double b1 = centroid_f;
570 *b_ylow = centroid;
571 int end = centroid_y1 - width;
572
573 if (end < 0) {
574 end = 0;
575 }
576
577 for (i = centroid_y1; i > end; i--) {
578 double v1 = cpl_vector_get(fluxes, i - 1);
579
580 if (v1 < b1) {
581 b1 = v1;
582 *b_ylow = (double)i;
583 }
584 }
585
586 double b2 = centroid_f;
587 *b_yup = centroid;
588
589 end = centroid_y2 + width;
590
591 if (end > size) {
592 end = size;
593 }
594 for (i = centroid_y2; i <= end; i++) {
595 double v1 = cpl_vector_get(fluxes, i - 1);
596
597 if (v1 < b2) {
598 b2 = v1;
599 *b_yup = (double)i;
600 }
601 }
602 *thresh_low = b1 + (centroid_f - b1) * frac;
603 *thresh_up = b2 + (centroid_f - b2) * frac;
604}
605
606/*----------------------------------------------------------------------------*/
619/*----------------------------------------------------------------------------*/
620static void
621_moo_profile_find_image_background_flux(const cpl_image *fluxes,
622 int x,
623 double centroid,
624 double width,
625 double frac,
626 double *b_ylow,
627 double *b_yup,
628 double *thresh_low,
629 double *thresh_up)
630{
631 // cpl_msg_info(__func__,"estimate background for centroid %f",centroid);
632 int ny = cpl_image_get_size_y(fluxes);
633
634 int centroid_y1 = (int)floor(centroid);
635 int centroid_y2 = centroid_y1 + 1;
636 double centroid_f = _moo_get_image_flux(fluxes, x, centroid);
637
638 int i;
639 double b1 = centroid_f;
640 *b_ylow = centroid;
641 int end = centroid_y1 - width;
642
643 if (end < 0) {
644 end = 0;
645 }
646
647 for (i = centroid_y1; i > end; i--) {
648 int rej = 0;
649 double v1 = cpl_image_get(fluxes, x, i, &rej);
650 if (v1 < b1 && rej == 0) {
651 b1 = v1;
652 *b_ylow = (double)i;
653 }
654 }
655
656 double b2 = centroid_f;
657 *b_yup = centroid;
658
659 end = centroid_y2 + width;
660
661 if (end > ny) {
662 end = ny;
663 }
664 for (i = centroid_y2; i <= end; i++) {
665 int rej = 0;
666 double v1 = cpl_image_get(fluxes, x, i, &rej);
667
668 if (v1 < b2 && rej == 0) {
669 b2 = v1;
670 *b_yup = (double)i;
671 }
672 }
673 *thresh_low = b1 + (centroid_f - b1) * frac;
674 *thresh_up = b2 + (centroid_f - b2) * frac;
675}
676
677/*----------------------------------------------------------------------------*/
688/*----------------------------------------------------------------------------*/
689static void
690_moo_detect_x_edges(cpl_table *tracking_table,
691 int hwidth,
692 double min_frac,
693 int *x_min,
694 int *x_max)
695{
696 *x_min = -1;
697 *x_max = -1;
698 int nbgood = 0;
699
700 int size = cpl_table_get_nrow(tracking_table);
701
702 for (int x = 0; x < hwidth; x++) {
703 int flag = cpl_table_get_int(tracking_table,
704 MOO_TRACKING_LOC_TABLE_FLAG, x, NULL);
705 if (flag == 0) {
706 nbgood++;
707 }
708 }
709 double ratio = (double)nbgood / (double)hwidth;
710 for (int x = 0; x < hwidth; x++) {
711 cpl_table_set_double(tracking_table, MOO_TRACKING_LOC_TABLE_XGOOD_RATIO,
712 x, ratio);
713 }
714 if (ratio >= min_frac) {
715 *x_min = 1;
716 }
717
718 if (*x_min == -1) {
719 for (int x = hwidth; x < size - hwidth; x++) {
720 int total = 2 * hwidth + 1;
721 nbgood = 0;
722 for (int j = x - hwidth; j <= x + hwidth; j++) {
723 int flag =
724 cpl_table_get_int(tracking_table,
725 MOO_TRACKING_LOC_TABLE_FLAG, j, NULL);
726 if (flag == 0) {
727 nbgood++;
728 }
729 }
730 ratio = (double)nbgood / (double)total;
731 cpl_table_set_double(tracking_table,
732 MOO_TRACKING_LOC_TABLE_XGOOD_RATIO, x, ratio);
733 if (ratio >= min_frac) {
734 *x_min = x + 1;
735 break;
736 }
737 }
738 }
739
740 if (*x_min != -1) {
741 nbgood = 0;
742 for (int x = size - hwidth; x < size; x++) {
743 int flag = cpl_table_get_int(tracking_table,
744 MOO_TRACKING_LOC_TABLE_FLAG, x, NULL);
745 if (flag == 0) {
746 nbgood++;
747 }
748 }
749 ratio = (double)nbgood / (double)hwidth;
750 for (int x = size - hwidth; x < size; x++) {
751 cpl_table_set_double(tracking_table,
752 MOO_TRACKING_LOC_TABLE_XGOOD_RATIO, x, ratio);
753 }
754
755 if (ratio >= min_frac) {
756 *x_max = size;
757 }
758
759 if (*x_max == -1) {
760 for (int x = size - hwidth - 1; x >= hwidth; x--) {
761 int total = 2 * hwidth + 1;
762 nbgood = 0;
763
764 for (int j = x - hwidth; j <= x + hwidth; j++) {
765 int flag =
766 cpl_table_get_int(tracking_table,
767 MOO_TRACKING_LOC_TABLE_FLAG, j, NULL);
768
769 if (flag == 0) {
770 nbgood++;
771 }
772 }
773 ratio = (double)nbgood / (double)total;
774 cpl_table_set_double(tracking_table,
775 MOO_TRACKING_LOC_TABLE_XGOOD_RATIO, x,
776 ratio);
777 if (ratio >= min_frac) {
778 *x_max = x + 1;
779 break;
780 }
781 }
782 }
783 }
784}
785
786static int
787_moo_localise_row(hdrl_image *himg,
788 int x,
789 double wdiff_lim,
790 double ydiff_lim,
791 float frac,
792 double ref_snr,
793 double *min,
794 double *max,
795 cpl_table *tracking_loc_table,
796 double *last_center,
797 cpl_vector *last_width_vect,
798 double *last_x)
799{
800 int is_invalid = 0;
801
802 double y1, y2, center = NAN, width = NAN;
803 int idx = x - 1;
804
805 cpl_table_set_int(tracking_loc_table, MOO_TRACKING_LOC_TABLE_X, idx, x);
806 double last_width = cpl_vector_get_median_const(last_width_vect);
807 const cpl_image *img = hdrl_image_get_image_const(himg);
808 const cpl_image *error = hdrl_image_get_error_const(himg);
809 const cpl_mask *mask = cpl_image_get_bpm_const(img);
810 cpl_vector *fluxes = cpl_vector_new_from_image_column(img, x);
811 cpl_vector *errs = cpl_vector_new_from_image_column(error, x);
812
813 int size = cpl_vector_get_size(fluxes);
814 for (int i = 1; i < size; i++) {
815 int rej = cpl_mask_get(mask, x, i);
816 if (rej) {
817 cpl_vector_set(fluxes, i - 1, NAN);
818 }
819 }
820 int flag = _check_bpm(himg, x, *last_center, last_width);
821
822 if (flag == MOONS_FLAG_GOOD) {
823 double thresh_low, thresh_up, b1_y, b2_y, snr;
824 _moo_profile_find_background_flux(fluxes, *last_center, last_width,
825 frac, &b1_y, &b2_y, &thresh_low,
826 &thresh_up);
827
828 flag =
829 _check_snr(fluxes, errs, *last_center, b1_y, b2_y, ref_snr, &snr);
830 cpl_table_set_double(tracking_loc_table, MOO_TRACKING_LOC_TABLE_SNR,
831 idx, snr);
832
833 if (flag == MOONS_FLAG_GOOD) {
834 _moo_profile_find_thresh_positions(fluxes, *last_center, thresh_low,
835 thresh_up, &y1, &y2);
836 cpl_errorstate prev_state = cpl_errorstate_get();
837 cpl_bivector *points = _moo_extract_profile(fluxes, y1, y2);
838 if (points != NULL) {
839 moo_barycenter_fit(points, &center, &width);
840 cpl_bivector_delete(points);
841
842 double wdiff = width - last_width;
843 double ydiff =
844 (center - *last_center) / sqrt(fabs(x - *last_x));
845 cpl_table_set_double(tracking_loc_table,
846 MOO_TRACKING_LOC_TABLE_WDIFF, idx, wdiff);
847 cpl_table_set_double(tracking_loc_table,
848 MOO_TRACKING_LOC_TABLE_YDIFF, idx, ydiff);
849 if (fabs(wdiff) < wdiff_lim) {
850 if (fabs(ydiff) < ydiff_lim) {
851 if (center < *min) {
852 *min = center;
853 }
854 if (center > *max) {
855 *max = center;
856 }
857 cpl_table_set_double(tracking_loc_table,
858 MOO_TRACKING_LOC_TABLE_YCENTROID,
859 idx, center);
860 cpl_table_set_double(tracking_loc_table,
861 MOO_TRACKING_LOC_TABLE_YMIN, idx,
862 y1);
863 cpl_table_set_double(tracking_loc_table,
864 MOO_TRACKING_LOC_TABLE_YMAX, idx,
865 y2);
866 cpl_table_set_int(tracking_loc_table,
867 MOO_TRACKING_LOC_TABLE_FLAG, idx,
868 MOONS_FLAG_GOOD);
869 *last_center = center;
870
871 int vsize = cpl_vector_get_size(last_width_vect);
872 for (int iv = 0; iv < vsize - 1; iv++) {
873 double lv = cpl_vector_get(last_width_vect, iv + 1);
874 cpl_vector_set(last_width_vect, iv, lv);
875 }
876 cpl_vector_set(last_width_vect, vsize - 1, width);
877 *last_x = x;
878 }
879 else {
880 cpl_table_set_int(tracking_loc_table,
881 MOO_TRACKING_LOC_TABLE_FLAG, idx,
882 MOONS_FLAG_YDIFF_OUTLIERS);
883
884 is_invalid = 1;
885 }
886 }
887 else {
888 cpl_table_set_int(tracking_loc_table,
889 MOO_TRACKING_LOC_TABLE_FLAG, idx,
890 MOONS_FLAG_WDIFF_OUTLIERS);
891
892 is_invalid = 1;
893 }
894 }
895 else {
896 cpl_errorstate_set(prev_state);
897 cpl_table_set_int(tracking_loc_table,
898 MOO_TRACKING_LOC_TABLE_FLAG, idx,
899 MOONS_FLAG_NOPROFILE);
900 is_invalid = 1;
901 }
902 }
903 else {
904 cpl_table_set_int(tracking_loc_table, MOO_TRACKING_LOC_TABLE_FLAG,
905 idx, MOONS_FLAG_NON_SIGNIFICANT_FLUX);
906 is_invalid = 1;
907 }
908 }
909 else {
910 cpl_table_set_int(tracking_loc_table, MOO_TRACKING_LOC_TABLE_FLAG, idx,
911 MOONS_FLAG_BADPIX);
912 is_invalid = 1;
913 }
914
915 cpl_vector_delete(fluxes);
916 cpl_vector_delete(errs);
917 return is_invalid;
918}
919
920static cpl_error_code
921_moo_localise_tchebychev_fit(moo_loc_single *res,
922 int fibnum,
923 int deg_poly,
924 cpl_table *tracking_table,
925 int xlim_hwin,
926 double xlim_fracmin)
927{
928 cpl_error_code status = CPL_ERROR_NONE;
929
930 int invalid_wlo = 0;
931 int invalid_wup = 0;
932 cpl_image *measured_centroids = res->m_centroids;
933 cpl_image *fit_centroids = res->f_centroids;
934 cpl_image *wlow = res->f_wlow;
935 cpl_image *wup = res->f_wup;
936 cpl_image *mlow = res->m_wlow;
937 cpl_image *mup = res->m_wup;
938 cpl_image *flags = res->flags;
939
940 int nx = cpl_image_get_size_x(measured_centroids);
941
942 for (int i = 1; i <= nx; i++) {
943 double yc =
944 cpl_table_get_double(tracking_table,
945 MOO_TRACKING_LOC_TABLE_YCENTROID, i - 1, NULL);
946 double yl =
947 cpl_table_get_double(tracking_table, MOO_TRACKING_LOC_TABLE_YMIN,
948 i - 1, NULL);
949 double yu =
950 cpl_table_get_double(tracking_table, MOO_TRACKING_LOC_TABLE_YMAX,
951 i - 1, NULL);
952 int flag = cpl_table_get_int(tracking_table,
953 MOO_TRACKING_LOC_TABLE_FLAG, i - 1, NULL);
954 cpl_image_set(measured_centroids, i, fibnum, yc);
955 cpl_image_set(mlow, i, fibnum, yl);
956 cpl_image_set(mup, i, fibnum, yu);
957 cpl_image_set(flags, i, fibnum, flag);
958 cpl_image_set(fit_centroids, i, fibnum, NAN);
959 cpl_image_set(wlow, i, fibnum, NAN);
960 cpl_image_set(wup, i, fibnum, NAN);
961 }
962
963 int xmin, xmax;
964
965 _moo_detect_x_edges(tracking_table, xlim_hwin, xlim_fracmin, &xmin, &xmax);
966
967 if (xmin != -1) {
968 cpl_msg_debug("moo_localise",
969 "Fibre #%d detected on pixel range %d - %d", fibnum, xmin,
970 xmax);
971
972 int *cflag =
973 cpl_table_get_data_int(tracking_table, MOO_TRACKING_LOC_TABLE_FLAG);
974 int *cposx =
975 cpl_table_get_data_int(tracking_table, MOO_TRACKING_LOC_TABLE_X);
976 double *cposy =
977 cpl_table_get_data_double(tracking_table,
978 MOO_TRACKING_LOC_TABLE_YCENTROID);
979
980 cpl_bivector *cpos = cpl_bivector_new(nx);
981 cpl_vector *vx = cpl_bivector_get_x(cpos);
982 cpl_vector *vy = cpl_bivector_get_y(cpos);
983
984 for (int i = 0; i < nx; i++) {
985 cpl_vector_set(vx, i, (double)cposx[i]);
986 cpl_vector_set(vy, i, cposy[i]);
987 }
988
989 double min = moo_vector_get_min(vy, cflag);
990 double max = moo_vector_get_max(vy, cflag);
991
992 moo_tchebychev_fit(cpos, cflag, deg_poly, xmin, xmax, min, max);
993
994 for (int i = xmin; i <= xmax; i++) {
995 double fyc = cpl_vector_get(vy, i - 1);
996 cpl_table_set(tracking_table, MOO_TRACKING_LOC_TABLE_FITYCENTROID,
997 i - 1, fyc);
998 cpl_image_set(fit_centroids, i, fibnum, fyc);
999 }
1000
1001 double *cposylow =
1002 cpl_table_get_data_double(tracking_table,
1003 MOO_TRACKING_LOC_TABLE_YMIN);
1004
1005 for (int i = 0; i < nx; i++) {
1006 cpl_vector_set(vy, i, cposylow[i]);
1007 }
1008 min = moo_vector_get_min(vy, cflag);
1009 max = moo_vector_get_max(vy, cflag);
1010
1011 moo_tchebychev_fit(cpos, cflag, deg_poly, xmin, xmax, min, max);
1012
1013 for (int i = xmin; i <= xmax; i++) {
1014 double yl = cpl_vector_get(vy, i - 1);
1015 double yc =
1016 cpl_table_get(tracking_table,
1017 MOO_TRACKING_LOC_TABLE_FITYCENTROID, i - 1, NULL);
1018 double val = yc - yl;
1019 if (val <= 0) {
1020 invalid_wlo++;
1021 }
1022 cpl_table_set(tracking_table, MOO_TRACKING_LOC_TABLE_FITYMIN, i - 1,
1023 yl);
1024 cpl_image_set(wlow, i, fibnum, val);
1025 }
1026
1027 double *cposyup =
1028 cpl_table_get_data_double(tracking_table,
1029 MOO_TRACKING_LOC_TABLE_YMAX);
1030
1031 for (int i = 0; i < nx; i++) {
1032 cpl_vector_set(vy, i, cposyup[i]);
1033 }
1034 min = moo_vector_get_min(vy, cflag);
1035 max = moo_vector_get_max(vy, cflag);
1036
1037 moo_tchebychev_fit(cpos, cflag, deg_poly, xmin, xmax, min, max);
1038
1039 for (int i = xmin; i <= xmax; i++) {
1040 double yu = cpl_vector_get(vy, i - 1);
1041 double yc =
1042 cpl_table_get(tracking_table,
1043 MOO_TRACKING_LOC_TABLE_FITYCENTROID, i - 1, NULL);
1044 double val = yu - yc;
1045 if (val <= 0) {
1046 invalid_wup++;
1047 }
1048 cpl_table_set(tracking_table, MOO_TRACKING_LOC_TABLE_FITYMAX, i - 1,
1049 yu);
1050 cpl_image_set(wup, i, fibnum, val);
1051 }
1052 cpl_bivector_delete(cpos);
1053 if (invalid_wlo) {
1054 cpl_msg_error("moo_localise",
1055 "Fibre #%d : localisation fitting (polynomial degree "
1056 "%d) failed : negative lower width",
1057 fibnum, deg_poly);
1058 status = CPL_ERROR_ILLEGAL_OUTPUT;
1059 }
1060 if (invalid_wup) {
1061 cpl_msg_error("moo_localise",
1062 "Fibre #%d : localisation fitting (polynomial degree "
1063 "%d) failed : negative upper width",
1064 fibnum, deg_poly);
1065 status = CPL_ERROR_ILLEGAL_OUTPUT;
1066 }
1067 }
1068 else {
1069 cpl_msg_error("moo_localise",
1070 "Fibre #%d : localisation tracking failed", fibnum);
1071 status = CPL_ERROR_ILLEGAL_OUTPUT;
1072 }
1073 return status;
1074}
1075
1076static cpl_error_code
1077_moo_localise_fibre(fibre *f,
1078 hdrl_image *himg,
1079 int cx,
1080 int deg_poly,
1081 double wdiff_lim,
1082 double ydiff_lim,
1083 float frac,
1084 double ref_snr,
1085 int xgap_max,
1086 double goodptsfrac_min,
1087 int xlim_hwin,
1088 double xlim_fracmin,
1089 moo_loc_single *res,
1090 cpl_table **all_tracked)
1091{
1092 cpl_table *tracking_loc_table = NULL;
1093 cpl_error_code status = CPL_ERROR_NONE;
1094 double max = 0;
1095
1096 cpl_msg_indent_more();
1097
1098 int nx = hdrl_image_get_size_x(himg);
1099 int ny = hdrl_image_get_size_y(himg);
1100
1101 double min = (double)ny;
1102
1103 tracking_loc_table = cpl_table_new(nx);
1104 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_FIBNUM,
1105 CPL_TYPE_INT);
1106 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_X,
1107 CPL_TYPE_INT);
1108 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_YCENTROID,
1109 CPL_TYPE_DOUBLE);
1110 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_YMIN,
1111 CPL_TYPE_DOUBLE);
1112 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_YMAX,
1113 CPL_TYPE_DOUBLE);
1114 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_WDIFF,
1115 CPL_TYPE_DOUBLE);
1116 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_YDIFF,
1117 CPL_TYPE_DOUBLE);
1118 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_SNR,
1119 CPL_TYPE_DOUBLE);
1120 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_FLAG,
1121 CPL_TYPE_INT);
1122 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_XGOOD_RATIO,
1123 CPL_TYPE_DOUBLE);
1124 cpl_table_new_column(tracking_loc_table,
1125 MOO_TRACKING_LOC_TABLE_FITYCENTROID, CPL_TYPE_DOUBLE);
1126 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_FITYMIN,
1127 CPL_TYPE_DOUBLE);
1128 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_FITYMAX,
1129 CPL_TYPE_DOUBLE);
1130
1131 for (int i = 0; i < nx; i++) {
1132 cpl_table_set_int(tracking_loc_table, MOO_TRACKING_LOC_TABLE_FIBNUM, i,
1133 f->num);
1134 }
1135 cpl_table_set_int(tracking_loc_table, MOO_TRACKING_LOC_TABLE_X, cx - 1, cx);
1136 cpl_table_set_double(tracking_loc_table, MOO_TRACKING_LOC_TABLE_YCENTROID,
1137 cx - 1, (f->center));
1138 cpl_table_set_double(tracking_loc_table, MOO_TRACKING_LOC_TABLE_YMIN,
1139 cx - 1, (f->ymin));
1140 cpl_table_set_double(tracking_loc_table, MOO_TRACKING_LOC_TABLE_YMAX,
1141 cx - 1, (f->ymax));
1142 cpl_table_set_int(tracking_loc_table, MOO_TRACKING_LOC_TABLE_FLAG, cx - 1,
1143 MOONS_FLAG_GOOD);
1144
1145 double last_center = f->center;
1146 cpl_vector *last_width = cpl_vector_new(3);
1147 cpl_vector_fill(last_width, f->width);
1148
1149 double last_x = cx;
1150 int nb_invalid = 0;
1151 int nb_follow_invalid = 0;
1152 for (int i = cx + 1; i <= nx; i++) {
1153 int is_invalid =
1154 _moo_localise_row(himg, i, wdiff_lim, ydiff_lim, frac, ref_snr,
1155 &min, &max, tracking_loc_table, &last_center,
1156 last_width, &last_x);
1157
1158 if (is_invalid) {
1159 nb_follow_invalid++;
1160 nb_invalid++;
1161 }
1162 else {
1163 nb_follow_invalid = 0;
1164 }
1165 if (nb_follow_invalid > xgap_max) {
1166 for (int j = i + 1; j <= nx; j++) {
1167 nb_invalid++;
1168 cpl_table_set_int(tracking_loc_table, MOO_TRACKING_LOC_TABLE_X,
1169 j - 1, j);
1170 cpl_table_set_int(tracking_loc_table,
1171 MOO_TRACKING_LOC_TABLE_FLAG, j - 1,
1172 MOONS_FLAG_XMAX_GAP);
1173 }
1174 break;
1175 }
1176 }
1177 last_center = f->center;
1178 cpl_vector_fill(last_width, f->width);
1179 last_x = cx;
1180 nb_follow_invalid = 0;
1181
1182 for (int i = cx - 1; i > 0; i--) {
1183 int is_invalid =
1184 _moo_localise_row(himg, i, wdiff_lim, ydiff_lim, frac, ref_snr,
1185 &min, &max, tracking_loc_table, &last_center,
1186 last_width, &last_x);
1187 if (is_invalid) {
1188 nb_follow_invalid++;
1189 nb_invalid++;
1190 }
1191 else {
1192 nb_follow_invalid = 0;
1193 }
1194 if (nb_follow_invalid > xgap_max) {
1195 for (int j = i - 1; j > 0; j--) {
1196 nb_invalid++;
1197 cpl_table_set_int(tracking_loc_table, MOO_TRACKING_LOC_TABLE_X,
1198 j - 1, j);
1199 cpl_table_set_int(tracking_loc_table,
1200 MOO_TRACKING_LOC_TABLE_FLAG, j - 1,
1201 MOONS_FLAG_XMAX_GAP);
1202 }
1203 break;
1204 }
1205 }
1206 cpl_vector_delete(last_width);
1207
1208 cpl_msg_debug("moo_localise", "Fraction of invalid detection %.2f %%",
1209 (double)nb_invalid / (double)nx * 100.);
1210 f->goodfrac = (1. - nb_invalid / (double)nx) * 100.;
1211 cpl_msg_indent_less();
1212 if (f->goodfrac >= goodptsfrac_min) {
1213 status = _moo_localise_tchebychev_fit(res, f->num, deg_poly,
1214 tracking_loc_table, xlim_hwin,
1215 xlim_fracmin);
1216 }
1217 else {
1218 f->health = MOO_FIBRES_TABLE_HEALTH_NEWLY_BROKEN;
1219 }
1220 *all_tracked = tracking_loc_table;
1221 return status;
1222}
1223
1224static int
1225_moo_localise_col_flux_from_guess(hdrl_image *himg,
1226 cpl_table *tracking_loc_table,
1227 int x,
1228 double *yc,
1229 double *width,
1230 double *yl,
1231 double *yu,
1232 const char *method,
1233 double frac,
1234 double ref_snr)
1235{
1236 int flag = MOONS_FLAG_GOOD;
1237 int idx = x - 1;
1238
1239 const cpl_image *img = hdrl_image_get_image_const(himg);
1240 const cpl_image *error = hdrl_image_get_error_const(himg);
1241
1242 cpl_vector *fluxes = cpl_vector_new_from_image_column(img, x);
1243 cpl_vector *errs = cpl_vector_new_from_image_column(error, x);
1244
1245 if (strcmp(method, MOO_LOCALISE_METHOD_BARYCENTER) == 0) {
1246 double thresh_low, thresh_up;
1247 double b1_y, b2_y;
1248
1249 _moo_profile_find_image_background_flux(img, x, *yc, *width, frac,
1250 &b1_y, &b2_y, &thresh_low,
1251 &thresh_up);
1252
1253 _moo_profile_find_image_thresh_positions(img, x, *yc, thresh_low,
1254 thresh_up, yl, yu);
1255
1256 cpl_errorstate prev_state = cpl_errorstate_get();
1257 cpl_bivector *points = _moo_extract_profile_integrate(fluxes, *yl, *yu);
1258
1259 if (points != NULL) {
1260 double snr;
1261 moo_barycenter_fit(points, yc, width);
1262 cpl_bivector_delete(points);
1263 flag = _check_snr(fluxes, errs, *yc, b1_y, b2_y, ref_snr, &snr);
1264 cpl_table_set_double(tracking_loc_table, MOO_TRACKING_LOC_TABLE_SNR,
1265 idx, snr);
1266 }
1267 else {
1268 cpl_errorstate_set(prev_state);
1269 flag = MOONS_FLAG_NOPROFILE;
1270 }
1271 }
1272 else {
1273 cpl_errorstate prev_state = cpl_errorstate_get();
1274 double gc = *yc, gwidth, background = 0, area, sigma = *width / 4.0;
1275 cpl_bivector *points = _moo_extract_profile_integrate(fluxes, *yl, *yu);
1276 /*{
1277 char* name = cpl_sprintf("extractedflux_%d.txt",x);
1278 FILE* test = fopen(name,"w");
1279 cpl_bivector_dump(points,test);
1280 fclose(test);
1281 cpl_free(name);
1282 }*/
1283 cpl_fit_mode fit_pars = CPL_FIT_CENTROID | CPL_FIT_STDEV | CPL_FIT_AREA;
1284 moo_gaussian_fit(points, fit_pars, &gc, &sigma, &background, &area);
1285
1286 if (!cpl_errorstate_is_equal(prev_state)) {
1287 cpl_errorstate_set(prev_state);
1288 flag = MOONS_FLAG_BADPROFILE;
1289 }
1290 else {
1291 double ycval = moo_gaussian_eval(gc, gc, sigma, background, area);
1292 /*{
1293 char* name = cpl_sprintf("modelflux_%d.txt",x);
1294 FILE* test = fopen(name,"w");
1295 fprintf(test,"#y flux\n");
1296 for(double t=-5; t<=5; t+=0.1){
1297 double tycval = moo_gaussian_eval(gc+t,gc,sigma,background,area);
1298 fprintf(test,"%f %f\n",gc+t,tycval);
1299 }
1300 fclose(test);
1301 cpl_free(name);
1302 }*/
1303 double thresh = background + (ycval - background) * frac;
1304 double gyl, gyu;
1305 moo_gaussian_eval_inv(thresh, gc, sigma, background, area, &gyl,
1306 &gyu);
1307 gwidth = gyu - gyl;
1308 /*{
1309 char* name = cpl_sprintf("params_%d.txt",x);
1310 FILE* test = fopen(name,"w");
1311 fprintf(test,"%d %f %f %f %f %f %f\n",x,thresh,gc,gyl,gyu,sigma,background);
1312 fclose(test);
1313 cpl_free(name);
1314 }*/
1315 if (gwidth > 2) {
1316 double thresh_low, thresh_up;
1317 double b1_y, b2_y, snr;
1318
1319 _moo_profile_find_background_flux(fluxes, gc, *width, frac,
1320 &b1_y, &b2_y, &thresh_low,
1321 &thresh_up);
1322
1323 flag = _check_snr(fluxes, errs, gc, b1_y, b2_y, ref_snr, &snr);
1324 *yc = gc;
1325 *width = gwidth;
1326 *yl = gyl;
1327 *yu = gyu;
1328 }
1329 else {
1330 flag = MOONS_FLAG_NARROWPROFILE;
1331 }
1332 }
1333 cpl_bivector_delete(points);
1334 }
1335
1336 cpl_vector_delete(fluxes);
1337 cpl_vector_delete(errs);
1338
1339 return flag;
1340}
1341
1342static int
1343_moo_localise_col_from_guess(hdrl_image *himg,
1344 int x,
1345 double yc,
1346 double wl,
1347 double wu,
1348 cpl_table *tracking_table,
1349 const char *method,
1350 double frac,
1351 double ref_snr)
1352{
1353 double center = yc;
1354 double width = wl + wu;
1355 double yl = yc - wl;
1356 double yu = yc + wu;
1357
1358 int fl = _check_trace_guess(center, width);
1359 if (fl != MOONS_FLAG_GOOD) {
1360 return fl;
1361 }
1362
1363 fl = _check_bpm(himg, x, center, width);
1364 if (fl != MOONS_FLAG_GOOD) {
1365 return fl;
1366 }
1367
1368 fl = _moo_localise_col_flux_from_guess(himg, tracking_table, x, &center,
1369 &width, &yl, &yu, method, frac,
1370 ref_snr);
1371
1372 if (fl == MOONS_FLAG_GOOD) {
1373 cpl_table_set_double(tracking_table, MOO_TRACKING_LOC_TABLE_YCENTROID,
1374 x - 1, center);
1375 cpl_table_set_double(tracking_table, MOO_TRACKING_LOC_TABLE_YMIN, x - 1,
1376 yl);
1377 cpl_table_set_double(tracking_table, MOO_TRACKING_LOC_TABLE_YMAX, x - 1,
1378 yu);
1379 }
1380
1381 return fl;
1382}
1383
1384static int
1385_moo_localise_fibre_from_guess(int fibnum,
1386 hdrl_image *himg,
1387 cpl_image *gcentroid,
1388 cpl_image *gwlo,
1389 cpl_image *gwup,
1390 moo_localise_params *params,
1391 int deg_poly,
1392 double goodptsfrac_min,
1393 double ref_snr,
1394 moo_loc_single *res,
1395 cpl_table **all_tracked)
1396{
1397 int detected = 0;
1398 cpl_table *tracking_loc_table = NULL;
1399
1400 cpl_errorstate prestate = cpl_errorstate_get();
1401 cpl_ensure(himg != NULL, CPL_ERROR_NULL_INPUT, 0);
1402
1403 int xlim_hwin = params->loc_xlim_hwin;
1404 double xlim_fracmin = params->loc_xlim_fracmin;
1405
1406 cpl_msg_indent_more();
1407
1408 cpl_msg_debug("moo_localise", "Localise fibres %d using guess localisation",
1409 fibnum);
1410 int nx = hdrl_image_get_size_x(himg);
1411
1412 tracking_loc_table = cpl_table_new(nx);
1413 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_FIBNUM,
1414 CPL_TYPE_INT);
1415 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_X,
1416 CPL_TYPE_INT);
1417 cpl_table_new_column(tracking_loc_table,
1418 MOO_TRACKING_LOC_TABLE_GUESS_YCENTROID,
1419 CPL_TYPE_DOUBLE);
1420 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_GUESS_WLO,
1421 CPL_TYPE_DOUBLE);
1422 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_GUESS_WUP,
1423 CPL_TYPE_DOUBLE);
1424 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_YCENTROID,
1425 CPL_TYPE_DOUBLE);
1426 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_YMIN,
1427 CPL_TYPE_DOUBLE);
1428 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_YMAX,
1429 CPL_TYPE_DOUBLE);
1430 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_WDIFF,
1431 CPL_TYPE_DOUBLE);
1432 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_YDIFF,
1433 CPL_TYPE_DOUBLE);
1434 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_SNR,
1435 CPL_TYPE_DOUBLE);
1436 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_FLAG,
1437 CPL_TYPE_INT);
1438 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_XGOOD_RATIO,
1439 CPL_TYPE_DOUBLE);
1440 cpl_table_new_column(tracking_loc_table,
1441 MOO_TRACKING_LOC_TABLE_FITYCENTROID, CPL_TYPE_DOUBLE);
1442 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_FITYMIN,
1443 CPL_TYPE_DOUBLE);
1444 cpl_table_new_column(tracking_loc_table, MOO_TRACKING_LOC_TABLE_FITYMAX,
1445 CPL_TYPE_DOUBLE);
1446
1447 for (int i = 0; i < nx; i++) {
1448 cpl_table_set_int(tracking_loc_table, MOO_TRACKING_LOC_TABLE_FIBNUM, i,
1449 fibnum);
1450 }
1451
1452 int nb_invalid = 0;
1453
1454 for (int i = 1; i <= nx; i++) {
1455 int rej;
1456 double yc = cpl_image_get(gcentroid, i, fibnum, &rej);
1457 double wl = cpl_image_get(gwlo, i, fibnum, &rej);
1458 double wu = cpl_image_get(gwup, i, fibnum, &rej);
1459 cpl_table_set_int(tracking_loc_table, MOO_TRACKING_LOC_TABLE_X, i - 1,
1460 i);
1461 cpl_table_set_double(tracking_loc_table,
1462 MOO_TRACKING_LOC_TABLE_GUESS_YCENTROID, i - 1, yc);
1463 cpl_table_set_double(tracking_loc_table,
1464 MOO_TRACKING_LOC_TABLE_GUESS_WLO, i - 1, wl);
1465 cpl_table_set_double(tracking_loc_table,
1466 MOO_TRACKING_LOC_TABLE_GUESS_WUP, i - 1, wu);
1467 int flag = MOONS_FLAG_GOOD;
1468 moo_try_check(flag = _moo_localise_col_from_guess(
1469 himg, i, yc, wl, wu, tracking_loc_table,
1470 params->method, params->relativethresh, ref_snr),
1471 " ");
1472 cpl_table_set_int(tracking_loc_table, MOO_TRACKING_LOC_TABLE_FLAG,
1473 i - 1, flag);
1474
1475 if (flag != MOONS_FLAG_GOOD) {
1476 nb_invalid++;
1477 }
1478 }
1479 cpl_msg_debug("moo_localise", "Fraction of invalid detection %.1f %%",
1480 nb_invalid / (double)nx * 100);
1481 double frac_good = (1 - nb_invalid / (double)nx) * 100;
1482
1483 if (frac_good > goodptsfrac_min) {
1484 _moo_localise_tchebychev_fit(res, fibnum, deg_poly, tracking_loc_table,
1485 xlim_hwin, xlim_fracmin);
1486 detected = 1;
1487 }
1488 else {
1489 cpl_image *measured_centroids = res->m_centroids;
1490 cpl_image *fit_centroids = res->f_centroids;
1491 cpl_image *wlow = res->f_wlow;
1492 cpl_image *wup = res->f_wup;
1493 cpl_image *mlow = res->m_wlow;
1494 cpl_image *mup = res->m_wup;
1495 cpl_image *flags = res->flags;
1496
1497 for (int i = 1; i <= nx; i++) {
1498 int flag =
1499 cpl_table_get_int(tracking_loc_table,
1500 MOO_TRACKING_LOC_TABLE_FLAG, i - 1, NULL);
1501 double yc = cpl_table_get_double(tracking_loc_table,
1502 MOO_TRACKING_LOC_TABLE_YCENTROID,
1503 i - 1, NULL);
1504 double yl =
1505 cpl_table_get_double(tracking_loc_table,
1506 MOO_TRACKING_LOC_TABLE_YMIN, i - 1, NULL);
1507 double yu =
1508 cpl_table_get_double(tracking_loc_table,
1509 MOO_TRACKING_LOC_TABLE_YMAX, i - 1, NULL);
1510 cpl_image_set(measured_centroids, i, fibnum, yc);
1511 cpl_image_set(mlow, i, fibnum, yl);
1512 cpl_image_set(mup, i, fibnum, yu);
1513
1514 cpl_image_set(flags, i, fibnum, flag);
1515 cpl_image_set(fit_centroids, i, fibnum, NAN);
1516 cpl_image_set(wlow, i, fibnum, NAN);
1517 cpl_image_set(wup, i, fibnum, NAN);
1518 }
1519 }
1520
1521moo_try_cleanup:
1522 *all_tracked = tracking_loc_table;
1523 cpl_msg_indent_less();
1524
1525 if (!cpl_errorstate_is_equal(prestate)) {
1526 cpl_errorstate_dump(prestate, CPL_FALSE, cpl_errorstate_dump_one);
1527 // Recover from the error(s) (Reset to prestate))
1528 cpl_errorstate_set(prestate);
1529 }
1530 return detected;
1531}
1532
1533static moo_loc_single *
1534_moo_localise_single_from_guess(moo_single *single,
1535 moo_loc_single *guess,
1536 int nb_total,
1537 int *health,
1538 const char **names,
1539 const int *indexext,
1540 moo_localise_params *params,
1541 moo_detector_type type,
1542 int ntas,
1543 const char *filename,
1544 int degpoly,
1545 double goodptsfrac_min,
1546 double ref_snr,
1547 cpl_array *indexes)
1548{
1549 int nmissing_fibres = 0;
1550 moo_loc_single *res = NULL;
1551 cpl_table **all_tracked = NULL;
1552
1553 cpl_ensure(single != NULL, CPL_ERROR_NULL_INPUT, NULL);
1554 cpl_ensure(guess != NULL, CPL_ERROR_NULL_INPUT, NULL);
1555
1556 cpl_errorstate prestate = cpl_errorstate_get();
1557
1558 cpl_msg_info("moo_localise", "goodptsfrac-min %f", goodptsfrac_min);
1559 hdrl_image *himg = moo_single_get_image(single);
1560 int nx = hdrl_image_get_size_x(himg);
1561
1562 const char *extname = moo_detector_get_extname(type, ntas);
1563
1564 moo_try_check(res = moo_loc_single_create(filename, extname), " ");
1565 res->m_centroids = cpl_image_new(nx, nb_total, CPL_TYPE_DOUBLE);
1566 res->f_centroids = cpl_image_new(nx, nb_total, CPL_TYPE_DOUBLE);
1567 res->m_wlow = cpl_image_new(nx, nb_total, CPL_TYPE_DOUBLE);
1568 res->f_wlow = cpl_image_new(nx, nb_total, CPL_TYPE_DOUBLE);
1569 res->m_wup = cpl_image_new(nx, nb_total, CPL_TYPE_DOUBLE);
1570 res->f_wup = cpl_image_new(nx, nb_total, CPL_TYPE_DOUBLE);
1571 res->flags = cpl_image_new(nx, nb_total, CPL_TYPE_INT);
1572 res->header = cpl_propertylist_new();
1573
1574 cpl_image *gcentroids = moo_loc_single_get_f_centroids(guess);
1575 cpl_image *gwlo = moo_loc_single_get_f_wlo(guess);
1576 cpl_image *gwup = moo_loc_single_get_f_wup(guess);
1577
1578 all_tracked = cpl_calloc(nb_total, sizeof(cpl_table *));
1579#ifdef _OPENMP
1580
1581#pragma omp parallel default(none) \
1582 shared(all_tracked, nb_total, health, res, degpoly, goodptsfrac_min, \
1583 ref_snr, params, gwup, gwlo, gcentroids, himg, nmissing_fibres, \
1584 names, nx, indexes, indexext, single)
1585 {
1586#pragma omp for
1587#endif
1588 for (int f = 1; f <= nb_total; f++) {
1589 //for (int f = 351; f <= 351; f++) {
1590 int idx = cpl_array_get_cplsize(indexes, f - 1, NULL);
1591
1592 if (health[idx] == MOO_FIBRES_TABLE_HEALTH_GOOD) {
1593 int detected =
1594 _moo_localise_fibre_from_guess(f, himg, gcentroids, gwlo,
1595 gwup, params, degpoly,
1596 goodptsfrac_min, ref_snr,
1597 res, &all_tracked[f - 1]);
1598
1599 if (detected == 0) {
1600 cpl_msg_info("moo_localise",
1601 "Bad detection fibre indexext %d with name %s",
1602 indexext[idx], names[idx]);
1603 health[idx] = MOO_FIBRES_TABLE_HEALTH_NEWLY_BROKEN;
1604 }
1605 }
1606 else {
1607 cpl_msg_info("moo_localise",
1608 "Bad health fibre indexext %d with name %s",
1609 indexext[idx], names[idx]);
1610 for (int i = 1; i <= nx; i++) {
1611 cpl_image_set(res->m_centroids, i, f, NAN);
1612 cpl_image_set(res->m_wlow, i, f, NAN);
1613 cpl_image_set(res->m_wup, i, f, NAN);
1614 cpl_image_set(res->flags, i, f, MOONS_FLAG_BROKEN_FIBRE);
1615 cpl_image_set(res->f_centroids, i, f, NAN);
1616 cpl_image_set(res->f_wlow, i, f, NAN);
1617 cpl_image_set(res->f_wup, i, f, NAN);
1618 }
1619 }
1620 }
1621#ifdef _OPENMP
1622 }
1623#endif
1624 for (int f = 0; f < nb_total; f++) {
1625 if (health[f] == MOO_FIBRES_TABLE_HEALTH_NEWLY_BROKEN) {
1626 health[f] = MOO_FIBRES_TABLE_HEALTH_BROKEN;
1627 nmissing_fibres++;
1628 moo_qc_set_missingfib(res->header, nmissing_fibres, names[f]);
1629 }
1630 }
1631#if MOO_DEBUG_LOCALISE_TRACKING
1632 {
1633 char *name = cpl_sprintf("%s_TRACKING_LOC_TABLE.fits", res->extname);
1634 cpl_table *test = NULL;
1635 int first = 0;
1636 for (int i = 0; i < nb_total; i++) {
1637 cpl_table *t = all_tracked[i];
1638 if (t != NULL) {
1639 test = cpl_table_duplicate(t);
1640 first = i + 1;
1641 break;
1642 }
1643 }
1644 if (test != NULL) {
1645 for (int i = first; i < nb_total; i++) {
1646 cpl_table *t = all_tracked[i];
1647 if (t != NULL) {
1648 moo_table_append(test, t);
1649 }
1650 }
1651 cpl_table_save(test, NULL, NULL, name, CPL_IO_CREATE);
1652 cpl_table_delete(test);
1653 }
1654 cpl_free(name);
1655 }
1656#endif
1657 moo_qc_set_nmissingfib(res->header, nmissing_fibres);
1658moo_try_cleanup:
1659 if (all_tracked != NULL) {
1660 for (int i = 0; i < nb_total; i++) {
1661 if (all_tracked[i] != NULL) {
1662 cpl_table_delete(all_tracked[i]);
1663 }
1664 }
1665 cpl_free(all_tracked);
1666 }
1667
1668 if (!cpl_errorstate_is_equal(prestate)) {
1670 res = NULL;
1671 }
1672 return res;
1673}
1674
1675/*----------------------------------------------------------------------------*/
1693/*----------------------------------------------------------------------------*/
1694
1695static moo_loc *
1696_moo_localise_from_guess(moo_det *det,
1697 moo_loc *guess,
1698 moo_localise_params *params,
1699 const char *locname,
1700 int badpix_level)
1701{
1702 cpl_errorstate prestate = cpl_errorstate_get();
1703
1704 cpl_ensure(det != NULL, CPL_ERROR_NULL_INPUT, NULL);
1705 cpl_ensure(guess != NULL, CPL_ERROR_NULL_INPUT, NULL);
1706 cpl_ensure(params != NULL, CPL_ERROR_NULL_INPUT, NULL);
1707
1708 cpl_table *fibres_table = moo_loc_get_fibre_table(guess);
1709 cpl_ensure(fibres_table != NULL, CPL_ERROR_ILLEGAL_INPUT, NULL);
1710
1711 const char *filename = locname;
1712 moo_loc *loc = NULL;
1713 int i, j;
1714
1715 moo_try_check(loc = moo_loc_create(locname), " ");
1716 cpl_msg_info("moo_localise", "Create TRACE localisation");
1717 cpl_msg_indent_more();
1718
1719 cpl_table *loc_fibre_table = NULL;
1720 int *health = NULL;
1721 const int *indexext = NULL;
1722 const char **names = NULL;
1723 cpl_array *indexes = NULL;
1724
1725 loc_fibre_table = cpl_table_duplicate(fibres_table);
1726 moo_try_check(health = cpl_table_get_data_int(loc_fibre_table,
1727 MOO_FIBRES_TABLE_HEALTH),
1728 " ");
1729
1730 moo_try_check(indexext = cpl_table_get_data_int(loc_fibre_table,
1731 MOO_FIBRES_TABLE_INDEXEXT),
1732 " ");
1733
1734 moo_try_check(names =
1735 cpl_table_get_data_string_const(loc_fibre_table,
1736 MOO_FIBRES_TABLE_FIBRE),
1737 " ");
1738
1739 for (i = 1; i <= 2; i++) {
1740 indexes = moo_fibres_table_get_spectro_indexext(loc_fibre_table, i);
1741
1742 int nb_total = cpl_array_get_size(indexes);
1743
1744 for (j = 0; j < 3; j++) {
1745 int idx = (i - 1) * 3 + j;
1746 int polydeg = params->polydeg[idx];
1747 double ref_snr = params->ref_snr[idx];
1748 double goodptsfrac_min = params->goodptsfrac_min[idx] * 100.;
1749 moo_single *s1 = moo_det_load_single(det, j, i, badpix_level);
1750 moo_loc_single *lguess = moo_loc_get_single(guess, j, i);
1751
1752 if (s1 != NULL && lguess != NULL) {
1753 cpl_msg_info("moo_localise", "Localising %d fibres in %s",
1754 nb_total, moo_detector_get_extname(j, i));
1755
1756 moo_loc_single *ls =
1757 _moo_localise_single_from_guess(s1, lguess, nb_total,
1758 health, names, indexext,
1759 params, j, i, filename,
1760 polydeg, goodptsfrac_min,
1761 ref_snr, indexes);
1762
1763 if (ls != NULL) {
1764 moo_loc_single_compute_qc_trace(ls, polydeg, lguess);
1765 moo_loc_add_single(loc, ls, j, i, params->keep_points);
1766 }
1767 }
1768 }
1769 cpl_array_delete(indexes);
1770 indexes = NULL;
1771 }
1772
1773 moo_loc_add_fibre_table(loc, loc_fibre_table);
1774
1775moo_try_cleanup:
1776 cpl_msg_indent_less();
1777
1778 if (!cpl_errorstate_is_equal(prestate)) {
1779 cpl_array_delete(indexes);
1780 cpl_table_delete(loc_fibre_table);
1781 loc_fibre_table = NULL;
1782 moo_loc_delete(loc);
1783 loc = NULL;
1784 }
1785 return loc;
1786}
1787/******************************************************************************/
1788
1789static double
1790_moo_bckg_poly_eval(cpl_polynomial *fit1d, double v)
1791{
1792 cpl_size p0 = 0;
1793 cpl_size p1 = 1;
1794 cpl_size p2 = 2;
1795 cpl_size p3 = 3;
1796 cpl_size p4 = 4;
1797 double c0, c1, c2, c3, c4;
1798 c0 = cpl_polynomial_get_coeff(fit1d, &p0);
1799 c1 = cpl_polynomial_get_coeff(fit1d, &p1);
1800 c2 = cpl_polynomial_get_coeff(fit1d, &p2);
1801 c3 = cpl_polynomial_get_coeff(fit1d, &p3);
1802 c4 = cpl_polynomial_get_coeff(fit1d, &p4);
1803 double b = c0 + v * c1 + v * v * c2 + v * v * v * c3 + v * v * v * v * c4;
1804
1805 return b;
1806}
1807
1808static cpl_error_code
1809_moo_localise_background_fit_rmin(cpl_table *fibre_loc_table, int winhsize)
1810{
1811 cpl_ensure_code(winhsize >= 0, CPL_ERROR_ILLEGAL_INPUT);
1812
1813 double *fluxes =
1814 cpl_table_get_data_double(fibre_loc_table, MOO_FIBRE_LOC_TABLE_FLUX);
1815 double *errs = cpl_table_get_data_double(fibre_loc_table,
1816 MOO_FIBRE_LOC_TABLE_FLUX_ERR);
1817 int ny = cpl_table_get_nrow(fibre_loc_table);
1818 int winsize = 2 * winhsize + 1;
1819
1820 int ib = 0;
1821 for (int i = 0; i < winsize; i++) {
1822 double b = fluxes[i];
1823 if (isnan(fluxes[ib])) {
1824 ib = i;
1825 }
1826 else if (!isnan(b) && fluxes[ib] > b) {
1827 ib = i;
1828 }
1829 }
1830 double b = fluxes[ib];
1831 double be = errs[ib];
1832 for (int i = 0; i < winhsize; i++) {
1833 cpl_table_set_double(fibre_loc_table, MOO_FIBRE_LOC_TABLE_BACKGROUND, i,
1834 b);
1835 cpl_table_set_double(fibre_loc_table,
1836 MOO_FIBRE_LOC_TABLE_BACKGROUND_ERR, i, be);
1837 }
1838 ib = ny - winsize;
1839 for (int i = ny - winsize; i < ny; i++) {
1840 b = fluxes[i];
1841 if (isnan(fluxes[ib])) {
1842 ib = i;
1843 }
1844 else if (!isnan(b) && fluxes[ib] > b) {
1845 ib = i;
1846 }
1847 }
1848 b = fluxes[ib];
1849 be = errs[ib];
1850 for (int i = ny - winhsize; i < ny; i++) {
1851 cpl_table_set_double(fibre_loc_table, MOO_FIBRE_LOC_TABLE_BACKGROUND, i,
1852 b);
1853 cpl_table_set_double(fibre_loc_table,
1854 MOO_FIBRE_LOC_TABLE_BACKGROUND_ERR, i, be);
1855 }
1856 for (int i = winhsize; i < ny - winhsize; i++) {
1857 ib = i - winhsize;
1858 for (int j = i - winhsize; j < i + winhsize; j++) {
1859 b = fluxes[j];
1860 if (isnan(fluxes[ib])) {
1861 ib = j;
1862 }
1863 else if (!isnan(b) && fluxes[ib] > b) {
1864 ib = j;
1865 }
1866 }
1867 b = fluxes[ib];
1868 be = errs[ib];
1869 cpl_table_set_double(fibre_loc_table, MOO_FIBRE_LOC_TABLE_BACKGROUND, i,
1870 b);
1871 cpl_table_set_double(fibre_loc_table,
1872 MOO_FIBRE_LOC_TABLE_BACKGROUND_ERR, i, be);
1873 }
1874 return CPL_ERROR_NONE;
1875}
1876
1877static cpl_error_code
1878_moo_localise_background_fit_poly(cpl_table *fibre_loc_table,
1879 int polydeg,
1880 double klo,
1881 double kup,
1882 int niter)
1883{
1884 cpl_error_code error1d = CPL_ERROR_NONE;
1885 cpl_polynomial *fit1d = NULL;
1886 cpl_polynomial *errfit1d = NULL;
1887 cpl_matrix *samppos1d = NULL;
1888 cpl_vector *fitvals = NULL;
1889 cpl_vector *errvals = NULL;
1890 const cpl_boolean sampsym = CPL_FALSE;
1891 const cpl_size maxdeg1d = polydeg;
1892 double min_thresh_flux = 0.12;
1893 double min_kappa_flux = 2;
1894 double *fluxes =
1895 cpl_table_get_data_double(fibre_loc_table, MOO_FIBRE_LOC_TABLE_FLUX);
1896 double *errs = cpl_table_get_data_double(fibre_loc_table,
1897 MOO_FIBRE_LOC_TABLE_FLUX_ERR);
1898 double *ytab =
1899 cpl_table_get_data_double(fibre_loc_table, MOO_FIBRE_LOC_TABLE_Y);
1900 int *fitted =
1901 cpl_table_get_data_int(fibre_loc_table, MOO_FIBRE_LOC_TABLE_BCKGFITTED);
1902 int ny = cpl_table_get_nrow(fibre_loc_table);
1903 fitvals = cpl_vector_new(ny);
1904 for (int i = 0; i < ny; i++) {
1905 cpl_vector_set(fitvals, i, fluxes[i]);
1906 }
1907 double min_flux =
1908 moo_vector_get_percentile(fitvals, min_thresh_flux) * min_kappa_flux;
1909 cpl_vector_delete(fitvals);
1910 fitvals = NULL;
1911
1912 int nb = 0;
1913
1914 for (int i = 0; i < ny; i++) {
1915 if (fluxes[i] < min_flux) {
1916 fitted[i] = 0;
1917 }
1918 else {
1919 nb++;
1920 }
1921 }
1922
1923 fit1d = cpl_polynomial_new(1);
1924 errfit1d = cpl_polynomial_new(1);
1925 samppos1d = cpl_matrix_new(1, nb);
1926 fitvals = cpl_vector_new(nb);
1927 errvals = cpl_vector_new(nb);
1928 nb = 0;
1929 for (int i = 0; i < ny; i++) {
1930 if (fitted[i] == 1) {
1931 cpl_matrix_set(samppos1d, 0, nb, ytab[i]);
1932 cpl_vector_set(fitvals, nb, fluxes[i]);
1933 cpl_vector_set(errvals, nb, errs[i]);
1934 nb++;
1935 }
1936 }
1937 error1d = cpl_polynomial_fit(fit1d, samppos1d, &sampsym, fitvals, NULL,
1938 CPL_FALSE, NULL, &maxdeg1d);
1939 error1d = cpl_polynomial_fit(errfit1d, samppos1d, &sampsym, errvals, NULL,
1940 CPL_FALSE, NULL, &maxdeg1d);
1941
1942 cpl_vector *vdiff = cpl_vector_new(nb);
1943
1944 for (int i = 0; i < niter; i++) {
1945 nb = 0;
1946 for (int j = 0; j < ny; j++) {
1947 int f = fitted[j];
1948 if (f == 1) {
1949 double v = ytab[j];
1950 double b = _moo_bckg_poly_eval(fit1d, v);
1951 double flux = fluxes[j];
1952 double diff = flux - b;
1953 cpl_vector_set(vdiff, nb, diff);
1954 nb++;
1955 }
1956 }
1957 nb = 0;
1958 double stdev = cpl_vector_get_stdev(vdiff);
1959 cpl_msg_info("test", "niter %d stdev %f", i + 1, stdev);
1960
1961 for (int j = 0; j < ny; j++) {
1962 int f = fitted[j];
1963 if (f == 1) {
1964 double v = ytab[i];
1965 double b = _moo_bckg_poly_eval(fit1d, v);
1966 double flux = fluxes[j];
1967 double diff = flux - b;
1968 if ((diff > kup * stdev) || (diff < -klo * stdev)) {
1969 fitted[j] = 0;
1970 }
1971 else {
1972 nb++;
1973 }
1974 }
1975 }
1976 cpl_polynomial_delete(fit1d);
1977 cpl_polynomial_delete(errfit1d);
1978 cpl_matrix_delete(samppos1d);
1979 cpl_vector_delete(fitvals);
1980 cpl_vector_delete(errvals);
1981 cpl_vector_delete(vdiff);
1982
1983 fit1d = NULL;
1984 errfit1d = NULL;
1985 vdiff = NULL;
1986 samppos1d = NULL;
1987 fitvals = NULL;
1988 errvals = NULL;
1989
1990 vdiff = cpl_vector_new(nb);
1991 fit1d = cpl_polynomial_new(1);
1992 errfit1d = cpl_polynomial_new(1);
1993 samppos1d = cpl_matrix_new(1, nb);
1994 fitvals = cpl_vector_new(nb);
1995 errvals = cpl_vector_new(nb);
1996 nb = 0;
1997
1998 for (int j = 0; j < ny; j++) {
1999 if (fitted[j] == 1) {
2000 cpl_matrix_set(samppos1d, 0, nb, ytab[j]);
2001 cpl_vector_set(fitvals, nb, fluxes[j]);
2002 cpl_vector_set(errvals, nb, errs[j]);
2003 nb++;
2004 }
2005 }
2006 error1d = cpl_polynomial_fit(fit1d, samppos1d, &sampsym, fitvals, NULL,
2007 CPL_FALSE, NULL, &maxdeg1d);
2008 error1d = cpl_polynomial_fit(errfit1d, samppos1d, &sampsym, errvals,
2009 NULL, CPL_FALSE, NULL, &maxdeg1d);
2010 }
2011
2012 for (int i = 0; i < ny; i++) {
2013 double v = ytab[i];
2014 double b = _moo_bckg_poly_eval(fit1d, v);
2015 double be = _moo_bckg_poly_eval(errfit1d, v);
2016 cpl_table_set_double(fibre_loc_table, MOO_FIBRE_LOC_TABLE_BACKGROUND, i,
2017 b);
2018 cpl_table_set_double(fibre_loc_table,
2019 MOO_FIBRE_LOC_TABLE_BACKGROUND_ERR, i, be);
2020 }
2021
2022 cpl_polynomial_delete(fit1d);
2023 cpl_polynomial_delete(errfit1d);
2024 cpl_matrix_delete(samppos1d);
2025 cpl_vector_delete(fitvals);
2026 cpl_vector_delete(errvals);
2027 cpl_vector_delete(vdiff);
2028 return error1d;
2029}
2030
2031static cpl_array *
2032_moo_localise_flag_detected(cpl_table *table, double *max)
2033{
2034 cpl_array *flagged = NULL;
2035
2036 cpl_table_select_all(table);
2037 cpl_table_and_selected_int(table, MOO_FIBRE_LOC_TABLE_FLAG, CPL_EQUAL_TO,
2038 0);
2039 cpl_table *seltable = cpl_table_extract_selected(table);
2040 int size = cpl_table_get_nrow(seltable);
2041 if (size > 0) {
2042 double *fluxes =
2043 cpl_table_get_data_double(seltable, MOO_FIBRE_LOC_TABLE_FLUX);
2044 cpl_vector *vfluxes = cpl_vector_wrap(size, fluxes);
2045 *max = cpl_vector_get_max(vfluxes) * 0.5;
2046
2047 cpl_table_and_selected_double(table, MOO_FIBRE_LOC_TABLE_FLUX,
2048 CPL_GREATER_THAN, *max);
2049 flagged = cpl_table_where_selected(table);
2050 cpl_vector_unwrap(vfluxes);
2051 }
2052 cpl_table_delete(seltable);
2053
2054 return flagged;
2055}
2056
2057static cpl_error_code
2058_moo_localise_detect_fibres(cpl_array *flagged,
2059 cpl_table *fibre_loc_table,
2060 cpl_table *detect_loc_table,
2061 int n)
2062{
2063 cpl_ensure_code(flagged != NULL, CPL_ERROR_NULL_INPUT);
2064
2065 int nb_flagged = cpl_array_get_size(flagged);
2066 int ymin = -1;
2067 int ymax = -1;
2068 int ysize = 0;
2069 int nb = 0;
2070 int nrow = cpl_table_get_nrow(fibre_loc_table);
2071
2072 for (int i = 0; i < nb_flagged; i++) {
2073 int nbsel1 = 0;
2074 int nbsel2 = 0;
2075
2076 int index = cpl_array_get_cplsize(flagged, i, NULL);
2077 cpl_table_set_int(fibre_loc_table, MOO_FIBRE_LOC_TABLE_FLAG, index, n);
2078 int fy = (int)cpl_table_get_double(fibre_loc_table,
2079 MOO_FIBRE_LOC_TABLE_Y, index, NULL);
2080 double flux_y =
2081 cpl_table_get_double(fibre_loc_table, MOO_FIBRE_LOC_TABLE_FLUX,
2082 index, NULL);
2083 cpl_table_select_all(detect_loc_table);
2084 if (index < (nrow - 1)) {
2085 int fy_after = (int)cpl_table_get_double(fibre_loc_table,
2086 MOO_FIBRE_LOC_TABLE_Y,
2087 index + 1, NULL);
2088
2089 nbsel1 = cpl_table_and_selected_int(detect_loc_table,
2090 MOO_DETECT_LOC_TABLE_YMIN,
2091 CPL_EQUAL_TO, fy_after);
2092
2093 if (nbsel1 > 0) {
2094 cpl_array *sel = cpl_table_where_selected(detect_loc_table);
2095 for (int j = 0; j < nbsel1; j++) {
2096 cpl_size idx = cpl_array_get_cplsize(sel, j, NULL);
2097
2098 cpl_table_set_int(detect_loc_table,
2099 MOO_DETECT_LOC_TABLE_YMIN, idx, fy);
2100 cpl_table_set_double(detect_loc_table,
2101 MOO_DETECT_LOC_TABLE_FLUX_YMIN, idx,
2102 flux_y);
2103 }
2104 cpl_array_delete(sel);
2105 }
2106 }
2107
2108 if (index > 0) {
2109 int fy_before = (int)cpl_table_get_double(fibre_loc_table,
2110 MOO_FIBRE_LOC_TABLE_Y,
2111 index - 1, NULL);
2112
2113 cpl_table_select_all(detect_loc_table);
2114 nbsel2 = cpl_table_and_selected_int(detect_loc_table,
2115 MOO_DETECT_LOC_TABLE_YMAX,
2116 CPL_EQUAL_TO, fy_before);
2117
2118 if (nbsel2 > 0) {
2119 cpl_array *sel = cpl_table_where_selected(detect_loc_table);
2120
2121 for (int j = 0; j < nbsel2; j++) {
2122 cpl_size idx = cpl_array_get_cplsize(sel, j, NULL);
2123 cpl_table_set_int(detect_loc_table,
2124 MOO_DETECT_LOC_TABLE_YMAX, idx, fy);
2125 cpl_table_set_double(detect_loc_table,
2126 MOO_DETECT_LOC_TABLE_FLUX_YMAX, idx,
2127 flux_y);
2128 }
2129 cpl_array_delete(sel);
2130 }
2131 }
2132
2133 if (nbsel1 == 0 && nbsel2 == 0) {
2134 if (ymin == -1) {
2135 nb++;
2136 ymin = fy;
2137 ymax = fy;
2138 ysize = 1;
2139 }
2140 else if (fy == (ymin + ysize)) {
2141 if (index < (nrow - 1)) {
2142 int fy_after =
2143 (int)cpl_table_get_double(fibre_loc_table,
2144 MOO_FIBRE_LOC_TABLE_Y,
2145 index + 1, NULL);
2146 int ystep = fy_after - fy;
2147 ymax = fy;
2148 ysize += ystep;
2149 }
2150 else {
2151 ysize++;
2152 }
2153 }
2154 else {
2155 cpl_table_set_size(detect_loc_table, nb);
2156 cpl_table_set_int(detect_loc_table, MOO_DETECT_LOC_TABLE_NUM,
2157 nb - 1, nb);
2158 cpl_table_set_int(detect_loc_table, MOO_DETECT_LOC_TABLE_YMIN,
2159 nb - 1, ymin);
2160 cpl_table_select_all(fibre_loc_table);
2161 cpl_table_and_selected_double(fibre_loc_table,
2162 MOO_FIBRE_LOC_TABLE_Y,
2163 CPL_EQUAL_TO, ymin);
2164 cpl_array *sel = cpl_table_where_selected(fibre_loc_table);
2165 cpl_size idx = cpl_array_get_cplsize(sel, 0, NULL);
2166 cpl_array_delete(sel);
2167 double flux_ymin =
2168 cpl_table_get_double(fibre_loc_table,
2169 MOO_FIBRE_LOC_TABLE_FLUX, idx, NULL);
2170 cpl_table_set_double(detect_loc_table,
2171 MOO_DETECT_LOC_TABLE_FLUX_YMIN, nb - 1,
2172 flux_ymin);
2173 cpl_table_set_int(detect_loc_table, MOO_DETECT_LOC_TABLE_YMAX,
2174 nb - 1, ymax);
2175 cpl_table_select_all(fibre_loc_table);
2176 cpl_table_and_selected_double(fibre_loc_table,
2177 MOO_FIBRE_LOC_TABLE_Y,
2178 CPL_EQUAL_TO, ymax);
2179 sel = cpl_table_where_selected(fibre_loc_table);
2180 idx = cpl_array_get_cplsize(sel, 0, NULL);
2181 cpl_array_delete(sel);
2182
2183 double flux_ymax =
2184 cpl_table_get_double(fibre_loc_table,
2185 MOO_FIBRE_LOC_TABLE_FLUX, idx, NULL);
2186 cpl_table_set_double(detect_loc_table,
2187 MOO_DETECT_LOC_TABLE_FLUX_YMAX, nb - 1,
2188 flux_ymax);
2189 ymin = fy;
2190 ymax = fy;
2191 ysize = 1;
2192 nb++;
2193 }
2194 }
2195 }
2196
2197 if (ymin > -1) {
2198 cpl_table_set_size(detect_loc_table, nb);
2199 cpl_table_set_int(detect_loc_table, MOO_DETECT_LOC_TABLE_NUM, nb - 1,
2200 nb);
2201 cpl_table_set_int(detect_loc_table, MOO_DETECT_LOC_TABLE_YMIN, nb - 1,
2202 ymin);
2203
2204 cpl_table_select_all(fibre_loc_table);
2205 cpl_table_and_selected_double(fibre_loc_table, MOO_FIBRE_LOC_TABLE_Y,
2206 CPL_EQUAL_TO, ymin);
2207 cpl_array *sel = cpl_table_where_selected(fibre_loc_table);
2208 cpl_size idx = cpl_array_get_cplsize(sel, 0, NULL);
2209 cpl_array_delete(sel);
2210 double flux_ymin =
2211 cpl_table_get_double(fibre_loc_table, MOO_FIBRE_LOC_TABLE_FLUX, idx,
2212 NULL);
2213 cpl_table_set_double(detect_loc_table, MOO_DETECT_LOC_TABLE_FLUX_YMIN,
2214 nb - 1, flux_ymin);
2215
2216 cpl_table_set_int(detect_loc_table, MOO_DETECT_LOC_TABLE_YMAX, nb - 1,
2217 ymax);
2218 cpl_table_select_all(fibre_loc_table);
2219 cpl_table_and_selected_double(fibre_loc_table, MOO_FIBRE_LOC_TABLE_Y,
2220 CPL_EQUAL_TO, ymax);
2221 sel = cpl_table_where_selected(fibre_loc_table);
2222 idx = cpl_array_get_cplsize(sel, 0, NULL);
2223 cpl_array_delete(sel);
2224
2225 double flux_ymax =
2226 cpl_table_get_double(fibre_loc_table, MOO_FIBRE_LOC_TABLE_FLUX, idx,
2227 NULL);
2228 cpl_table_set_double(detect_loc_table, MOO_DETECT_LOC_TABLE_FLUX_YMAX,
2229 nb - 1, flux_ymax);
2230 }
2231
2232 return CPL_ERROR_NONE;
2233}
2234
2235static cpl_error_code
2236_moo_localise_band(moo_single *single,
2237 int cx,
2238 int band_width,
2239 const char *backg_method,
2240 int backg_winhsize,
2241 int backg_polydeg,
2242 double backg_clip_kappalow,
2243 double backg_clip_kappaup,
2244 int backg_clip_niter,
2245 double detect_noisemult_thresh,
2246 int detect_niter,
2247 float frac,
2248 int nb_expected,
2249 int *nb_detected,
2250 cpl_table **out_detect_loc_table,
2251 cpl_table **out_fibre_loc_table)
2252{
2253 cpl_table *detect_loc_table = NULL;
2254 // background fit
2255 double klo = backg_clip_kappalow;
2256 double kup = backg_clip_kappaup;
2257 int niter = backg_clip_niter;
2258
2259 int polydeg = backg_polydeg;
2260 // fibre detection
2261 double kthresh = detect_noisemult_thresh;
2262
2263 cpl_ensure_code(single != NULL, CPL_ERROR_NULL_INPUT);
2264
2265 cpl_msg_indent_more();
2266 hdrl_image *himg = moo_single_get_image(single);
2267
2268 int ny = hdrl_image_get_size_y(himg);
2269 int y;
2270
2271 cpl_table *fibre_loc_table = cpl_table_new(ny);
2272 cpl_table_new_column(fibre_loc_table, MOO_FIBRE_LOC_TABLE_Y,
2273 CPL_TYPE_DOUBLE);
2274 cpl_table_new_column(fibre_loc_table, MOO_FIBRE_LOC_TABLE_FLUX,
2275 CPL_TYPE_DOUBLE);
2276 cpl_table_new_column(fibre_loc_table, MOO_FIBRE_LOC_TABLE_FLUX_ERR,
2277 CPL_TYPE_DOUBLE);
2278 cpl_table_new_column(fibre_loc_table, MOO_FIBRE_LOC_TABLE_BAD,
2279 CPL_TYPE_INT);
2280 cpl_table_new_column(fibre_loc_table, MOO_FIBRE_LOC_TABLE_BACKGROUND,
2281 CPL_TYPE_DOUBLE);
2282 cpl_table_new_column(fibre_loc_table, MOO_FIBRE_LOC_TABLE_BACKGROUND_ERR,
2283 CPL_TYPE_DOUBLE);
2284 cpl_table_new_column(fibre_loc_table, MOO_FIBRE_LOC_TABLE_THRESH,
2285 CPL_TYPE_DOUBLE);
2286 cpl_table_new_column(fibre_loc_table, MOO_FIBRE_LOC_TABLE_BCKGFITTED,
2287 CPL_TYPE_INT);
2288 cpl_table_new_column(fibre_loc_table, MOO_FIBRE_LOC_TABLE_FLAG,
2289 CPL_TYPE_INT);
2290
2291 detect_loc_table = cpl_table_new(0);
2292 cpl_table_new_column(detect_loc_table, MOO_DETECT_LOC_TABLE_NUM,
2293 CPL_TYPE_INT);
2294 cpl_table_new_column(detect_loc_table, MOO_DETECT_LOC_TABLE_YMIN,
2295 CPL_TYPE_INT);
2296 cpl_table_new_column(detect_loc_table, MOO_DETECT_LOC_TABLE_YMAX,
2297 CPL_TYPE_INT);
2298 cpl_table_new_column(detect_loc_table, MOO_DETECT_LOC_TABLE_FLUX_YMIN,
2299 CPL_TYPE_DOUBLE);
2300 cpl_table_new_column(detect_loc_table, MOO_DETECT_LOC_TABLE_FLUX_YMAX,
2301 CPL_TYPE_DOUBLE);
2302
2303 for (y = 1; y <= ny; y++) {
2304 hdrl_value val;
2305 hdrl_image *extract = hdrl_image_extract(himg, cx - band_width / 2, y,
2306 cx + band_width / 2, y);
2307
2308 val = hdrl_image_get_median(extract);
2309
2310 cpl_table_set_double(fibre_loc_table, MOO_FIBRE_LOC_TABLE_Y, y - 1,
2311 (double)y);
2312 cpl_table_set_double(fibre_loc_table, MOO_FIBRE_LOC_TABLE_FLUX, y - 1,
2313 val.data);
2314 cpl_table_set_double(fibre_loc_table, MOO_FIBRE_LOC_TABLE_FLUX_ERR,
2315 y - 1, val.error);
2316 cpl_table_set_int(fibre_loc_table, MOO_FIBRE_LOC_TABLE_BAD, y - 1,
2317 isnan(val.data));
2318 cpl_table_set_int(fibre_loc_table, MOO_FIBRE_LOC_TABLE_BCKGFITTED,
2319 y - 1, 1);
2320 cpl_table_set_int(fibre_loc_table, MOO_FIBRE_LOC_TABLE_FLAG, y - 1, 0);
2321 hdrl_image_delete(extract);
2322 }
2323
2324 // filter bad data
2325 cpl_table_select_all(fibre_loc_table);
2326 cpl_table_and_selected_int(fibre_loc_table, MOO_FIBRE_LOC_TABLE_BAD,
2327 CPL_EQUAL_TO, 1);
2328 cpl_table_erase_selected(fibre_loc_table);
2329
2330 ny = cpl_table_get_nrow(fibre_loc_table);
2331 if (strcmp(backg_method, MOO_LOCALISE_BACKG_METHOD_POLYNOMIAL) == 0) {
2332 cpl_msg_info(
2333 "moo_localise",
2334 "Background polynomial (%d degree) fit : kappa (lo %f, up %f) \
2335 niter: %d",
2336 polydeg, klo, kup, niter);
2337
2338 _moo_localise_background_fit_poly(fibre_loc_table, polydeg, klo, kup,
2339 niter);
2340 }
2341 else {
2342 cpl_msg_info("moo_localise",
2343 "Background running median fit (winhsize %d)",
2344 backg_winhsize);
2345
2346 _moo_localise_background_fit_rmin(fibre_loc_table, backg_winhsize);
2347 }
2348
2349
2350 double *backgrounds =
2351 cpl_table_get_data_double(fibre_loc_table,
2352 MOO_FIBRE_LOC_TABLE_BACKGROUND);
2353 double *backgrounds_err =
2354 cpl_table_get_data_double(fibre_loc_table,
2355 MOO_FIBRE_LOC_TABLE_BACKGROUND_ERR);
2356 for (int i = 0; i < ny; i++) {
2357 double t = backgrounds[i] + kthresh * backgrounds_err[i];
2358 cpl_table_set_double(fibre_loc_table, MOO_FIBRE_LOC_TABLE_THRESH, i, t);
2359 }
2360
2361 if (strcmp(backg_method, MOO_LOCALISE_BACKG_METHOD_POLYNOMIAL) == 0) {
2362 for (int n = 1; n <= detect_niter; n++) {
2363 double thresh = 0;
2364 cpl_array *flagged =
2365 _moo_localise_flag_detected(fibre_loc_table, &thresh);
2366
2367 cpl_table_select_all(fibre_loc_table);
2368 int nb_sel = cpl_table_and_selected_int(fibre_loc_table,
2369 MOO_FIBRE_LOC_TABLE_FLAG,
2370 CPL_EQUAL_TO, 0);
2371 int lower =
2372 cpl_table_and_selected_double(fibre_loc_table,
2373 MOO_FIBRE_LOC_TABLE_THRESH,
2374 CPL_GREATER_THAN, thresh);
2375
2376 if (lower > 0) {
2377 cpl_msg_info("test",
2378 "niter %d/%d : find in sel (%d) "
2379 " \
2380 "
2381 "%d threshold points greater than %f",
2382 n, detect_niter, nb_sel, lower, thresh);
2383 cpl_array_delete(flagged);
2384 break;
2385 }
2386 _moo_localise_detect_fibres(flagged, fibre_loc_table,
2387 detect_loc_table, n);
2388 cpl_array_delete(flagged);
2389 }
2390 }
2391 else {
2392 cpl_table_unselect_all(fibre_loc_table);
2393 cpl_table_or_selected(fibre_loc_table, MOO_FIBRE_LOC_TABLE_FLUX,
2394 CPL_GREATER_THAN, MOO_FIBRE_LOC_TABLE_THRESH);
2395 cpl_array *flagged = cpl_table_where_selected(fibre_loc_table);
2396 int nb_peaks = cpl_array_get_size(flagged);
2397 cpl_msg_info("moo_localise",
2398 "Filter peaks using ktresh (%f) : find %d peaks", kthresh,
2399 nb_peaks);
2400 _moo_localise_detect_fibres(flagged, fibre_loc_table, detect_loc_table,
2401 1);
2402 cpl_array_delete(flagged);
2403 }
2404#if MOO_DEBUG_LOCALISE_BAND
2405 {
2406 char *testname = NULL;
2407
2408 if (strcmp(backg_method, MOO_LOCALISE_BACKG_METHOD_POLYNOMIAL) == 0) {
2409 testname = cpl_sprintf("%s_FIB_LOC_TABLE_n%d.fits", single->extname,
2410 niter);
2411 }
2412 else {
2413 testname = cpl_sprintf("%s_FIB_LOC_TABLE_h%d.fits", single->extname,
2414 backg_winhsize);
2415 }
2416 cpl_table_save(fibre_loc_table, NULL, NULL, testname, CPL_IO_CREATE);
2417 cpl_free(testname);
2418 }
2419#endif
2420 cpl_propertylist *slist = cpl_propertylist_new();
2421 cpl_propertylist_append_bool(slist, MOO_DETECT_LOC_TABLE_YMIN, FALSE);
2422 cpl_table_sort(detect_loc_table, slist);
2423 cpl_propertylist_delete(slist);
2424
2425 int nrow = cpl_table_get_nrow(detect_loc_table);
2426 int nbdetected_valid_flux = 0;
2427 for (int i = 0; i < nrow; i++) {
2428 int rej;
2429 int ymin = cpl_table_get_int(detect_loc_table,
2430 MOO_DETECT_LOC_TABLE_YMIN, i, &rej);
2431 int ymax = cpl_table_get_int(detect_loc_table,
2432 MOO_DETECT_LOC_TABLE_YMAX, i, &rej);
2433 if (ymin < ymax) {
2434 nbdetected_valid_flux++;
2435 }
2436 else {
2437 cpl_table_set_invalid(detect_loc_table,
2438 MOO_DETECT_LOC_TABLE_FLUX_YMIN, i);
2439 }
2440 }
2441 cpl_table_erase_invalid(detect_loc_table);
2442
2443 cpl_msg_info(
2444 "moo_localise",
2445 "Number of detected fibres vs. expected valid fibres : %d / %d",
2446 nbdetected_valid_flux, nb_expected);
2447
2448 *nb_detected = nbdetected_valid_flux;
2449 *out_detect_loc_table = detect_loc_table;
2450 *out_fibre_loc_table = fibre_loc_table;
2451 cpl_msg_indent_less();
2452 return CPL_ERROR_NONE;
2453}
2454
2455static fibre *
2456_moo_localise_bandauto(moo_single *single,
2457 int cx,
2458 int band_width,
2459 const char *backg_method,
2460 int backg_winhsize,
2461 int backg_polydeg,
2462 double backg_clip_kappalow,
2463 double backg_clip_kappaup,
2464 int backg_clip_niter,
2465 int detect_niter,
2466 float frac,
2467 int nb_expected,
2468 int *out_nb_detected,
2469 double *out_detected_noisemult_thresh)
2470{
2471 fibre *fibres_tab = NULL;
2472 double low_limit = NAN;
2473 double high_limit = NAN;
2474 int max_niter = 50;
2475 double detect_noisemult_thresh = 1.0;
2476 int nb_detected = 0;
2477 cpl_table *detect_loc_table = NULL;
2478 cpl_table *fibre_loc_table = NULL;
2479 double klo = backg_clip_kappalow;
2480 double kup = backg_clip_kappaup;
2481 int polydeg = backg_polydeg;
2482 cpl_msg_info("moo_localise",
2483 "1) Detect centroid using "
2484 "central band (center=%d,width=%d)",
2485 cx, band_width);
2486 cpl_msg_indent_more();
2487
2488 if (strcmp(backg_method, MOO_LOCALISE_BACKG_METHOD_POLYNOMIAL) == 0) {
2489 cpl_msg_info("moo_localise",
2490 "background method %s "
2491 "background fit with degree %d kappa_lo %f kappa_up "
2492 "%f niter %d",
2493 backg_method, polydeg, klo, kup, backg_clip_niter);
2494 }
2495 else {
2496 cpl_msg_info("moo_localise",
2497 "Estimate background with method %s using winhsize %d",
2498 backg_method, backg_winhsize);
2499 }
2500
2501 for (int niter = 1; niter <= max_niter; niter++) {
2502 cpl_msg_info(__func__, "do niter %d/%d: using %f range[%f,%f]", niter,
2503 max_niter, detect_noisemult_thresh, low_limit, high_limit);
2504 _moo_localise_band(single, cx, band_width, backg_method, backg_winhsize,
2505 backg_polydeg, backg_clip_kappalow,
2506 backg_clip_kappaup, backg_clip_niter,
2507 detect_noisemult_thresh, detect_niter, frac,
2508 nb_expected, &nb_detected, &detect_loc_table,
2509 &fibre_loc_table);
2510
2511 if (nb_detected == nb_expected) {
2512 break;
2513 }
2514 else {
2515 cpl_table_delete(detect_loc_table);
2516 cpl_table_delete(fibre_loc_table);
2517 detect_loc_table = NULL;
2518 fibre_loc_table = NULL;
2519 }
2520 if (nb_detected > nb_expected) {
2521 low_limit = detect_noisemult_thresh;
2522 detect_noisemult_thresh *= 2;
2523 }
2524 else {
2525 high_limit = detect_noisemult_thresh;
2526 detect_noisemult_thresh /= 2;
2527 }
2528 if (!isnan(low_limit) && !isnan(high_limit)) {
2529 detect_noisemult_thresh = 0.5 * (low_limit + high_limit);
2530 }
2531 }
2532 if (nb_detected < nb_expected) {
2533 cpl_msg_error("moo_localise", "Failure in detection mask computation");
2534 char *testname = NULL;
2535
2536 testname = cpl_sprintf("DETECT_LOC_TABLE_%s.fits", single->extname);
2537
2538 cpl_table_save(detect_loc_table, NULL, NULL, testname, CPL_IO_CREATE);
2539 cpl_free(testname);
2540 }
2541 else {
2542 cpl_table_new_column(detect_loc_table, MOO_DETECT_LOC_TABLE_YBCKGMIN,
2543 CPL_TYPE_DOUBLE);
2544 cpl_table_new_column(detect_loc_table, MOO_DETECT_LOC_TABLE_YBCKGMAX,
2545 CPL_TYPE_DOUBLE);
2546 cpl_table_new_column(detect_loc_table,
2547 MOO_DETECT_LOC_TABLE_FLUX_YBCKGMIN,
2548 CPL_TYPE_DOUBLE);
2549 cpl_table_new_column(detect_loc_table,
2550 MOO_DETECT_LOC_TABLE_FLUX_YBCKGMAX,
2551 CPL_TYPE_DOUBLE);
2552 cpl_table_new_column(detect_loc_table, MOO_DETECT_LOC_TABLE_YTMIN,
2553 CPL_TYPE_DOUBLE);
2554 cpl_table_new_column(detect_loc_table, MOO_DETECT_LOC_TABLE_YTMAX,
2555 CPL_TYPE_DOUBLE);
2556 cpl_table_new_column(detect_loc_table, MOO_DETECT_LOC_TABLE_FLUX_YTMIN,
2557 CPL_TYPE_DOUBLE);
2558 cpl_table_new_column(detect_loc_table, MOO_DETECT_LOC_TABLE_FLUX_YTMAX,
2559 CPL_TYPE_DOUBLE);
2560 cpl_table_new_column(detect_loc_table, MOO_DETECT_LOC_TABLE_YBARY,
2561 CPL_TYPE_DOUBLE);
2562 cpl_table_new_column(detect_loc_table, MOO_DETECT_LOC_TABLE_FLUX_YBARY,
2563 CPL_TYPE_DOUBLE);
2564 cpl_table_new_column(detect_loc_table, MOO_DETECT_LOC_TABLE_YWIDTH,
2565 CPL_TYPE_DOUBLE);
2566 cpl_table_new_column(detect_loc_table, MOO_DETECT_LOC_TABLE_FIBNUM,
2567 CPL_TYPE_INT);
2568 fibres_tab = (fibre *)cpl_calloc(nb_detected, sizeof(fibre));
2569
2570 for (int f = 0; f < nb_detected; f++) {
2571 fibres_tab[f].health = MOO_FIBRES_TABLE_HEALTH_GOOD;
2572 }
2573 }
2574 int ny = cpl_table_get_nrow(fibre_loc_table);
2575 double *tfluxes =
2576 cpl_table_get_data_double(fibre_loc_table, MOO_FIBRE_LOC_TABLE_FLUX);
2577 double *tposy =
2578 cpl_table_get_data_double(fibre_loc_table, MOO_FIBRE_LOC_TABLE_Y);
2579 hdrl_image *himg = moo_single_get_image(single);
2580 int size_y = hdrl_image_get_size_y(himg);
2581
2582 cpl_vector *bandflux = cpl_vector_new(size_y);
2583 cpl_vector_fill(bandflux, NAN);
2584 for (int i = 0; i < ny; i++) {
2585 int px = (int)tposy[i];
2586 double flux = tfluxes[i];
2587 cpl_vector_set(bandflux, px - 1, flux);
2588 }
2589 double *fluxes = cpl_vector_get_data(bandflux);
2590 if (fibres_tab != NULL) {
2591 for (int i = 0; i < nb_detected; i++) {
2592 int ymin = cpl_table_get_int(detect_loc_table,
2593 MOO_DETECT_LOC_TABLE_YMIN, i, NULL);
2594 int ymax = cpl_table_get_int(detect_loc_table,
2595 MOO_DETECT_LOC_TABLE_YMAX, i, NULL);
2596 int ysize = ymax - ymin + 1;
2597 cpl_vector *vfluxes = cpl_vector_new(ysize);
2598 cpl_vector *pos = cpl_vector_new(ysize);
2599
2600 for (int j = ymin; j <= ymax; j++) {
2601 double f = fluxes[j - 1];
2602 cpl_vector_set(vfluxes, j - ymin, f);
2603 cpl_vector_set(pos, j - ymin, j);
2604 }
2605
2606 cpl_bivector *points = cpl_bivector_wrap_vectors(pos, vfluxes);
2607 double center = NAN;
2608 double width = NAN;
2609
2610 moo_barycenter_fit(points, &center, &width);
2611
2612 cpl_bivector_unwrap_vectors(points);
2613 cpl_vector_delete(vfluxes);
2614 cpl_vector_delete(pos);
2615
2616 double thresh_low = NAN, thresh_up = NAN, b_ylow = NAN, b_yup,
2617 y1 = NAN, y2 = NAN;
2618 _moo_profile_find_background_flux(bandflux, center, width, frac,
2619 &b_ylow, &b_yup, &thresh_low,
2620 &thresh_up);
2621 _moo_profile_find_thresh_positions(bandflux, center, thresh_low,
2622 thresh_up, &y1, &y2);
2623
2624
2625 cpl_table_set_double(detect_loc_table, MOO_DETECT_LOC_TABLE_YTMIN,
2626 i, y1);
2627 cpl_table_set_double(detect_loc_table, MOO_DETECT_LOC_TABLE_YTMAX,
2628 i, y2);
2629 cpl_table_set_double(detect_loc_table,
2630 MOO_DETECT_LOC_TABLE_YBCKGMIN, i, b_ylow);
2631 cpl_table_set_double(detect_loc_table,
2632 MOO_DETECT_LOC_TABLE_YBCKGMAX, i, b_yup);
2633
2634 double fb_ylow = _moo_get_flux(bandflux, b_ylow);
2635
2636 double fb_yup = _moo_get_flux(bandflux, b_yup);
2637
2638 cpl_table_set_double(detect_loc_table,
2639 MOO_DETECT_LOC_TABLE_FLUX_YBCKGMIN, i,
2640 fb_ylow);
2641 cpl_table_set_double(detect_loc_table,
2642 MOO_DETECT_LOC_TABLE_FLUX_YBCKGMAX, i, fb_yup);
2643 cpl_table_set_double(detect_loc_table,
2644 MOO_DETECT_LOC_TABLE_FLUX_YTMIN, i,
2645 thresh_low);
2646 cpl_table_set_double(detect_loc_table,
2647 MOO_DETECT_LOC_TABLE_FLUX_YTMAX, i, thresh_up);
2648
2649 points = _moo_extract_profile(bandflux, y1, y2);
2650 moo_barycenter_fit(points, &center, &width);
2651
2652 cpl_table_set_double(detect_loc_table, MOO_DETECT_LOC_TABLE_YBARY,
2653 i, center);
2654 double fbary = _moo_get_flux(bandflux, center);
2655 cpl_table_set_double(detect_loc_table,
2656 MOO_DETECT_LOC_TABLE_FLUX_YBARY, i, fbary);
2657 cpl_table_set_double(detect_loc_table, MOO_DETECT_LOC_TABLE_YWIDTH,
2658 i, width);
2659 cpl_bivector_delete(points);
2660
2661 int fibidx = i;
2662 fibres_tab[fibidx].ymin = y1;
2663 fibres_tab[fibidx].ymax = y2;
2664 fibres_tab[fibidx].center = center;
2665 fibres_tab[fibidx].width = width;
2666 int fibnum = fibidx + 1;
2667 fibres_tab[fibidx].num = fibnum;
2668 cpl_table_set_int(detect_loc_table, MOO_DETECT_LOC_TABLE_FIBNUM, i,
2669 fibnum);
2670 }
2671 }
2672#if MOO_DEBUG_LOCALISE_BAND
2673 {
2674 char *testname =
2675 cpl_sprintf("%s_DETECT_LOC_TABLE.fits", single->extname);
2676 cpl_table_save(detect_loc_table, NULL, NULL, testname, CPL_IO_CREATE);
2677 cpl_free(testname);
2678 }
2679#endif
2680 *out_nb_detected = nb_detected;
2681 *out_detected_noisemult_thresh = detect_noisemult_thresh;
2682 cpl_vector_delete(bandflux);
2683 cpl_table_delete(fibre_loc_table);
2684 cpl_table_delete(detect_loc_table);
2685 return fibres_tab;
2686}
2687
2688static moo_loc_single *
2689_moo_localise_single(moo_single *single,
2690 moo_localise_params *params,
2691 cpl_table *loc_fibre_table,
2692 int nb,
2693 moo_detector_type type,
2694 int ntas,
2695 const char *filename,
2696 int degpoly,
2697 double goodptsfrac_min,
2698 cpl_array *indexes,
2699 float *goodfrac)
2700{
2701 moo_loc_single *res = NULL;
2702 fibre *fibres_tab = NULL;
2703 cpl_error_code status = CPL_ERROR_NONE;
2704 int nb_good = 0;
2705 cpl_image *m_centroids = NULL;
2706 cpl_image *f_centroids = NULL;
2707 cpl_image *m_wlow = NULL;
2708 cpl_image *f_wlow = NULL;
2709 cpl_image *m_wup = NULL;
2710 cpl_image *f_wup = NULL;
2711 cpl_image *flags = NULL;
2712 cpl_table **all_tracked = NULL;
2713 cpl_ensure(single != NULL, CPL_ERROR_NULL_INPUT, NULL);
2714 cpl_ensure(loc_fibre_table != NULL, CPL_ERROR_NULL_INPUT, NULL);
2715 cpl_ensure(params != NULL, CPL_ERROR_NULL_INPUT, NULL);
2716
2717 moo_try_check(nb_good = moo_fibres_table_filter_health(loc_fibre_table),
2718 " ");
2719 int *health =
2720 cpl_table_get_data_int(loc_fibre_table, MOO_FIBRES_TABLE_HEALTH);
2721
2722 hdrl_image *himg = moo_single_get_image(single);
2723 cpl_image *img = hdrl_image_get_image(himg);
2724
2725 int didx = type + (ntas - 1) * 3;
2726 int nx = cpl_image_get_size_x(img);
2727 int band_width = params->centralwidth;
2728 int cx = params->centralpos;
2729 const char *backg_method = params->backg_method;
2730
2731 int backg_polydeg = params->backg_polydeg[didx];
2732 int backg_winhsize = params->backg_winhsize[didx];
2733 double backg_clip_kappalow = params->backg_clip_kappalow[didx];
2734 double backg_clip_kappaup = params->backg_clip_kappaup[didx];
2735 int backg_clip_niter = params->backg_clip_niter[didx];
2736 double detect_noisemult_thresh = 1;
2737 int detect_niter = params->detect_niter[didx];
2738 float frac = params->relativethresh;
2739 double ref_snr = params->ref_snr[didx];
2740 int xgap_max = params->xgap_max;
2741 int nb_failed = 0;
2742 int nb_detected = 0;
2743 int nb_broken = 0;
2744 fibres_tab =
2745 _moo_localise_bandauto(single, cx, band_width, backg_method,
2746 backg_winhsize, backg_polydeg,
2747 backg_clip_kappalow, backg_clip_kappaup,
2748 backg_clip_niter, detect_niter, frac, nb_good,
2749 &nb_detected, &detect_noisemult_thresh);
2750 cpl_ensure(fibres_tab != NULL, CPL_ERROR_UNSPECIFIED, NULL);
2751
2752 const char *extname = moo_detector_get_extname(type, ntas);
2753
2754 res = moo_loc_single_create(filename, extname);
2755 res->header = cpl_propertylist_new();
2756 moo_qc_set_qc_detect_noisemult(res->header, detect_noisemult_thresh);
2757 res->m_centroids = cpl_image_new(nx, nb_detected, CPL_TYPE_DOUBLE);
2758 res->f_centroids = cpl_image_new(nx, nb_detected, CPL_TYPE_DOUBLE);
2759 res->m_wlow = cpl_image_new(nx, nb_detected, CPL_TYPE_DOUBLE);
2760 res->f_wlow = cpl_image_new(nx, nb_detected, CPL_TYPE_DOUBLE);
2761 res->m_wup = cpl_image_new(nx, nb_detected, CPL_TYPE_DOUBLE);
2762 res->f_wup = cpl_image_new(nx, nb_detected, CPL_TYPE_DOUBLE);
2763 res->flags = cpl_image_new(nx, nb_detected, CPL_TYPE_INT);
2764
2765 double wdiff_lim = params->wdiff_lim;
2766 double ydiff_lim = params->ydiff_lim;
2767 int xlim_hwin = params->loc_xlim_hwin;
2768 double xlim_fracmin = params->loc_xlim_fracmin;
2769 cpl_msg_info("moo_localise",
2770 "2) Loop on fibre localisation (tracking + fitting)");
2771 cpl_msg_indent_more();
2772 cpl_msg_info("moo_localise", "min_snr %f xgap_max %d goodptsfrac-min %f",
2773 ref_snr, xgap_max, goodptsfrac_min);
2774
2775 all_tracked = cpl_calloc(nb_detected, sizeof(cpl_table *));
2776
2777#ifdef _OPENMP
2778
2779#pragma omp parallel default(none) \
2780 shared(all_tracked, nb_detected, fibres_tab, himg, cx, degpoly, wdiff_lim, \
2781 ydiff_lim, xlim_hwin, xlim_fracmin, frac, res, nx, ref_snr, \
2782 xgap_max, goodptsfrac_min) reduction(+ : nb_failed, nb_broken)
2783 {
2784#pragma omp for
2785#endif
2786 for (int f = 1; f <= nb_detected; f++) {
2787 //for (int f = 504; f <= 504; f++) {
2788 cpl_error_code lstatus = CPL_ERROR_NONE;
2789 fibre *fib = &(fibres_tab[f - 1]);
2790 int num = fib->num;
2791 lstatus =
2792 _moo_localise_fibre(fib, himg, cx, degpoly, wdiff_lim,
2793 ydiff_lim, frac, ref_snr, xgap_max,
2794 goodptsfrac_min, xlim_hwin, xlim_fracmin,
2795 res, &all_tracked[f - 1]);
2796 if (lstatus != CPL_ERROR_NONE) {
2797 nb_failed += 1;
2798 }
2799 else if (fib->health == MOO_FIBRES_TABLE_HEALTH_NEWLY_BROKEN) {
2800 nb_broken += 1;
2801 for (int i = 1; i <= nx; i++) {
2802 cpl_image_set(res->m_centroids, i, num, NAN);
2803 cpl_image_set(res->m_wlow, i, num, NAN);
2804 cpl_image_set(res->m_wup, i, num, NAN);
2805 cpl_image_set(res->flags, i, num, MOONS_FLAG_BROKEN_FIBRE);
2806 cpl_image_set(res->f_centroids, i, num, NAN);
2807 cpl_image_set(res->f_wlow, i, num, NAN);
2808 cpl_image_set(res->f_wup, i, num, NAN);
2809 }
2810 cpl_msg_info("moo_localise",
2811 "New broken fibre %d/%d : goodfrac %f", num,
2812 nb_detected, fib->goodfrac);
2813 }
2814 }
2815#ifdef _OPENMP
2816 }
2817#endif
2818#if MOO_DEBUG_LOCALISE_TRACKING
2819 {
2820 char *name = cpl_sprintf("%s_TRACKING_LOC_TABLE.fits", res->extname);
2821 cpl_table *test = NULL;
2822 int first = 0;
2823 for (int i = 0; i < nb_detected; i++) {
2824 cpl_table *t = all_tracked[i];
2825 if (t != NULL) {
2826 test = cpl_table_duplicate(t);
2827 first = i + 1;
2828 break;
2829 }
2830 }
2831 if (test != NULL) {
2832 for (int i = first; i < nb_detected; i++) {
2833 cpl_table *t = all_tracked[i];
2834 if (t != NULL) {
2835 moo_table_append(test, t);
2836 }
2837 }
2838 cpl_table_save(test, NULL, NULL, name, CPL_IO_CREATE);
2839 cpl_table_delete(test);
2840 }
2841 cpl_free(name);
2842 }
2843#endif
2844
2845 int nb_localise = nb_detected - nb_broken;
2846 cpl_msg_info("moo_localise",
2847 "Number of detected fibres after localisation : %d",
2848 nb_localise);
2849 cpl_msg_indent_less();
2850
2851 if (nb_failed > 0) {
2852 status = CPL_ERROR_UNSPECIFIED;
2853 cpl_error_set(__func__, status);
2854 }
2855 int fib_idx = 0;
2856
2857 if ((nb_good == nb_detected) || (nb_good == nb_localise)) {
2858 m_centroids = cpl_image_new(nx, nb, CPL_TYPE_DOUBLE);
2859 f_centroids = cpl_image_new(nx, nb, CPL_TYPE_DOUBLE);
2860 m_wlow = cpl_image_new(nx, nb, CPL_TYPE_DOUBLE);
2861 f_wlow = cpl_image_new(nx, nb, CPL_TYPE_DOUBLE);
2862 m_wup = cpl_image_new(nx, nb, CPL_TYPE_DOUBLE);
2863 f_wup = cpl_image_new(nx, nb, CPL_TYPE_DOUBLE);
2864 flags = cpl_image_new(nx, nb, CPL_TYPE_INT);
2865
2866 for (int f = 0; f < nb; f++) {
2867 int idx = cpl_array_get_cplsize(indexes, f, NULL);
2868 int h = health[idx];
2869 int num = f + 1;
2870
2871 cpl_table_set_int(loc_fibre_table, MOO_FIBRES_TABLE_INDEXEXT, idx,
2872 num);
2873
2874 if (h == MOO_FIBRES_TABLE_HEALTH_BROKEN) {
2875 for (int i = 1; i <= nx; i++) {
2876 cpl_image_set(m_centroids, i, num, NAN);
2877 cpl_image_set(m_wlow, i, num, NAN);
2878 cpl_image_set(m_wup, i, num, NAN);
2879 cpl_image_set(flags, i, num, MOONS_FLAG_BROKEN_FIBRE);
2880 cpl_image_set(f_centroids, i, num, NAN);
2881 cpl_image_set(f_wlow, i, num, NAN);
2882 cpl_image_set(f_wup, i, num, NAN);
2883 }
2884 }
2885 else {
2886 int fh = fibres_tab[fib_idx].health;
2887 if ((nb_good == nb_detected) &&
2888 (fh == MOO_FIBRES_TABLE_HEALTH_NEWLY_BROKEN)) {
2889 cpl_table_set_int(loc_fibre_table, MOO_FIBRES_TABLE_HEALTH,
2890 idx, fh);
2891 }
2892 else {
2893 while (fibres_tab[fib_idx].health ==
2894 MOO_FIBRES_TABLE_HEALTH_NEWLY_BROKEN) {
2895 fib_idx++;
2896 }
2897 }
2898 int fnum = fibres_tab[fib_idx].num;
2899
2900 goodfrac[idx] = fibres_tab[fib_idx].goodfrac;
2901
2902 for (int i = 1; i <= nx; i++) {
2903 int rej;
2904 double mcentroid =
2905 cpl_image_get(res->m_centroids, i, fnum, &rej);
2906 double fcentroid =
2907 cpl_image_get(res->f_centroids, i, fnum, &rej);
2908 double mwlo = cpl_image_get(res->m_wlow, i, fnum, &rej);
2909 double mwu = cpl_image_get(res->m_wup, i, fnum, &rej);
2910 double fwlo = cpl_image_get(res->f_wlow, i, fnum, &rej);
2911 double fwu = cpl_image_get(res->f_wup, i, fnum, &rej);
2912 double flag = cpl_image_get(res->flags, i, fnum, &rej);
2913 cpl_image_set(m_centroids, i, num, mcentroid);
2914 cpl_image_set(m_wlow, i, num, mwlo);
2915 cpl_image_set(m_wup, i, num, mwu);
2916 cpl_image_set(flags, i, num, flag);
2917 cpl_image_set(f_centroids, i, num, fcentroid);
2918 cpl_image_set(f_wlow, i, num, fwlo);
2919 cpl_image_set(f_wup, i, num, fwu);
2920 }
2921 fib_idx++;
2922 }
2923 }
2924 cpl_image_delete(res->m_centroids);
2925 res->m_centroids = m_centroids;
2926 cpl_image_delete(res->f_centroids);
2927 res->f_centroids = f_centroids;
2928 cpl_image_delete(res->m_wlow);
2929 res->m_wlow = m_wlow;
2930 cpl_image_delete(res->m_wup);
2931 res->m_wup = m_wup;
2932 cpl_image_delete(res->flags);
2933 res->flags = flags;
2934 cpl_image_delete(res->f_wlow);
2935 res->f_wlow = f_wlow;
2936 cpl_image_delete(res->f_wup);
2937 res->f_wup = f_wup;
2938 }
2939 else {
2940 cpl_error_set_message(
2941 "moo_localise", CPL_ERROR_UNSPECIFIED,
2942 "Localise fibres (%d) and expected fibres (%d) doesnt match",
2943 nb_localise, nb_good);
2944 status = CPL_ERROR_UNSPECIFIED;
2945 }
2946
2947 cpl_free(fibres_tab);
2948
2949moo_try_cleanup:
2950 if (all_tracked != NULL) {
2951 for (int i = 0; i < nb_detected; i++) {
2952 if (all_tracked[i] != NULL) {
2953 cpl_table_delete(all_tracked[i]);
2954 }
2955 }
2956 cpl_free(all_tracked);
2957 }
2958 if (status != CPL_ERROR_NONE) {
2960 }
2961 return res;
2962}
2963
2964static moo_loc *
2965_moo_localise_create_guess(moo_det *det,
2966 moo_localise_params *params,
2967 const char *locname,
2968 int badpix_level)
2969{
2970 cpl_array *indexes = NULL;
2971 cpl_errorstate prestate = cpl_errorstate_get();
2972
2973 cpl_ensure(det != NULL, CPL_ERROR_ILLEGAL_INPUT, NULL);
2974 cpl_ensure(params != NULL, CPL_ERROR_ILLEGAL_INPUT, NULL);
2975 cpl_ensure(locname != NULL, CPL_ERROR_ILLEGAL_INPUT, NULL);
2976
2977 cpl_table *fibres_table = moo_det_get_fibre_table(det);
2978 cpl_ensure(fibres_table != NULL, CPL_ERROR_ILLEGAL_INPUT, NULL);
2979
2980 const char *filename = locname;
2981 moo_loc *loc = NULL;
2982
2983 moo_try_check(loc = moo_loc_create(filename), " ");
2984
2985 int i, j;
2986 cpl_msg_info("moo_localise", "Create GUESS localisation");
2987 cpl_msg_indent_more();
2988
2989 cpl_table *loc_fibre_table = cpl_table_duplicate(fibres_table);
2990
2991 loc->fibre_table = loc_fibre_table;
2992 moo_fibres_table_add_locguess_cols(loc_fibre_table);
2993 cpl_table_new_column(loc_fibre_table, MOO_FIBRES_TABLE_INDEXEXT,
2994 CPL_TYPE_INT);
2995 const char *goodfracname[] = { MOO_FIBRES_TABLE_GOODPTSFRAC_RI,
2996 MOO_FIBRES_TABLE_GOODPTSFRAC_YJ,
2997 MOO_FIBRES_TABLE_GOODPTSFRAC_H };
2998
2999 for (i = 1; i <= 2; i++) {
3000 indexes = moo_fibres_table_get_spectro_index(loc_fibre_table, i);
3001 int nbtotal = cpl_array_get_size(indexes);
3002
3003 for (j = 0; j < 3; j++) {
3004 int idx = (i - 1) * 3 + j;
3005 double goodptsfrac_min = params->goodptsfrac_min[idx] * 100.;
3006 int dx = params->polydeg[idx];
3007 moo_single *s1 = moo_det_load_single(det, j, i, badpix_level);
3008 float *goodfrac =
3009 cpl_table_get_data_float(loc_fibre_table, goodfracname[j]);
3010
3011 if (s1 != NULL) {
3012 cpl_msg_info("moo_localise",
3013 "Localising %s : Total number of fibres from "
3014 "FIBRE_TABLE : %d",
3015 moo_detector_get_extname(j, i), nbtotal);
3016 cpl_msg_indent_more();
3017 moo_loc_single *ls = NULL;
3018
3019 moo_try_check(ls = _moo_localise_single(s1, params,
3020 loc_fibre_table,
3021 nbtotal, j, i, filename,
3022 dx, goodptsfrac_min,
3023 indexes, goodfrac),
3024 " ");
3025
3026 if (ls != NULL) {
3027 moo_loc_single_compute_qc_guess(ls, dx);
3028 moo_loc_add_single(loc, ls, j, i, params->keep_points);
3029 }
3030 cpl_msg_indent_less();
3031 }
3032 }
3033
3034 cpl_array_delete(indexes);
3035 }
3036
3037 cpl_msg_indent_less();
3038 cpl_table_select_all(loc_fibre_table);
3039 int nb_newly_broken =
3040 cpl_table_and_selected_int(loc_fibre_table, MOO_FIBRES_TABLE_HEALTH,
3041 CPL_EQUAL_TO,
3042 MOO_FIBRES_TABLE_HEALTH_NEWLY_BROKEN);
3043
3044 if (nb_newly_broken > 0) {
3045 indexes = cpl_table_where_selected(loc_fibre_table);
3046 for (i = 0; i < nb_newly_broken; i++) {
3047 int idx = cpl_array_get_cplsize(indexes, i, NULL);
3048 cpl_table_set_int(loc_fibre_table, MOO_FIBRES_TABLE_HEALTH, idx,
3049 MOO_FIBRES_TABLE_HEALTH_BROKEN);
3050 }
3051 cpl_array_delete(indexes);
3052 }
3053 moo_loc_add_fibre_table(loc, loc_fibre_table);
3054 // dump error from the state
3055
3056moo_try_cleanup:
3057 if (!cpl_errorstate_is_equal(prestate)) {
3058 if (indexes != NULL) {
3059 cpl_array_delete(indexes);
3060 }
3061 moo_loc_delete(loc);
3062 loc = NULL;
3063 }
3064 return loc;
3065}
3068/*----------------------------------------------------------------------------*/
3091/*----------------------------------------------------------------------------*/
3092moo_loc *
3093moo_localise(moo_det *det,
3094 const cpl_frame *guess_loc,
3095 moo_localise_params *params,
3096 const char *locname)
3097{
3098 cpl_ensure(det != NULL, CPL_ERROR_NULL_INPUT, NULL);
3099 cpl_ensure(params != NULL, CPL_ERROR_NULL_INPUT, NULL);
3100
3101 cpl_errorstate prestate = cpl_errorstate_get();
3102
3103 moo_loc *result = NULL;
3104 moo_loc *guess = NULL;
3105
3106 int badpix_level =
3108
3109 if (guess_loc != NULL) {
3110 moo_try_check(guess = moo_loc_load(guess_loc), " ");
3111 moo_try_check(result = _moo_localise_from_guess(det, guess, params,
3112 locname, badpix_level),
3113 " ");
3114 }
3115 else {
3116 moo_try_check(result = _moo_localise_create_guess(det, params, locname,
3117 badpix_level),
3118 " ");
3119 }
3120
3121moo_try_cleanup:
3122 moo_loc_delete(guess);
3123 if (!cpl_errorstate_is_equal(prestate)) {
3124 moo_loc_delete(result);
3125 result = NULL;
3126 }
3127 return result;
3128}
#define MOO_BADPIX_OUTSIDE_DATA_RANGE
Definition: moo_badpix.h:62
#define MOO_BADPIX_HOT
Definition: moo_badpix.h:51
#define MOO_BADPIX_COSMETIC
Definition: moo_badpix.h:57
moo_single * moo_det_load_single(moo_det *self, moo_detector_type type, int num, int level)
Load the type part in DET and return it.
Definition: moo_det.c:197
cpl_table * moo_det_get_fibre_table(moo_det *self)
Get the FIBRE TABLE in DET.
Definition: moo_det.c:424
const char * moo_detector_get_extname(moo_detector_type type, int ntas)
Get the extension name of a detector.
Definition: moo_detector.c:137
enum _moo_detector_type_ moo_detector_type
The type code type.
Definition: moo_detector.h:64
int moo_fibres_table_filter_health(cpl_table *table)
Filter bad health data in fibre table.
cpl_array * moo_fibres_table_get_spectro_indexext(cpl_table *table, int num)
get the index of a spectro in the fibre table sort by spetcro,indexext
cpl_array * moo_fibres_table_get_spectro_index(cpl_table *table, int num)
get the index of a spectro in the fibre table sort by index on the slit
cpl_error_code moo_fibres_table_add_locguess_cols(cpl_table *table)
add localise guess additional columns
void moo_loc_single_delete(moo_loc_single *self)
Delete a moo_loc_single.
cpl_image * moo_loc_single_get_f_wup(moo_loc_single *self)
Get image of width low.
cpl_image * moo_loc_single_get_f_centroids(moo_loc_single *self)
Get image of fit centroids.
moo_loc_single * moo_loc_single_create(const char *filename, const char *extname)
Create a new moo_loc_single from the given LOC filename.
cpl_image * moo_loc_single_get_f_wlo(moo_loc_single *self)
Get image of width low.
moo_loc * moo_loc_create(const char *filename)
Create a new empty LOC filename.
Definition: moo_loc.c:83
moo_loc_single * moo_loc_get_single(moo_loc *self, moo_detector_type type, int ntas)
Get the type part in LOC and return it.
Definition: moo_loc.c:155
cpl_error_code moo_loc_add_fibre_table(moo_loc *self, cpl_table *fibre_table)
Add fibre table to LOC filename and update moo_loc structure.
Definition: moo_loc.c:271
moo_loc * moo_loc_load(const cpl_frame *locframe)
Load a LOC frame and create a moo_loc.
Definition: moo_loc.c:109
cpl_error_code moo_loc_add_single(moo_loc *self, moo_loc_single *single, moo_detector_type type, int ntas, int keep_points)
Add LOC_SINGLE extension to LOC filename and update moo_loc structure.
Definition: moo_loc.c:234
cpl_table * moo_loc_get_fibre_table(moo_loc *self)
Get the FIBRE TABLE in LOC.
Definition: moo_loc.c:306
void moo_loc_delete(moo_loc *self)
Delete a moo_loc.
Definition: moo_loc.c:332
hdrl_image * moo_single_get_image(moo_single *self)
Get the IMAGE part (DATA,ERR) of single DET.
Definition: moo_single.c:330
moo_loc * moo_localise(moo_det *det, const cpl_frame *guess_loc, moo_localise_params *params, const char *locname)
To localise the centroid of fibre spectrum on frames.
cpl_error_code moo_qc_set_missingfib(cpl_propertylist *plist, int num, const char *val)
Set the QC.MISSINGFIB value.
Definition: moo_qc.c:1118
cpl_error_code moo_qc_set_nmissingfib(cpl_propertylist *plist, int val)
Set the QC.NMISSINGFIB value.
Definition: moo_qc.c:1087
cpl_error_code moo_qc_set_qc_detect_noisemult(cpl_propertylist *plist, double val)
Set the QC.DETECT.NOISEMULT value.
Definition: moo_qc.c:1474
cpl_error_code moo_gaussian_eval_inv(double y, double x0, double sigma, double offset, double area, double *x1, double *x2)
Find the x positions of the gaussian at the given y position.
Definition: moo_utils.c:373
double moo_vector_get_min(const cpl_vector *v, int *flags)
Find minimum values in a vector using flags.
Definition: moo_utils.c:979
double moo_gaussian_eval(double x, double x0, double sigma, double offset, double area)
Evaluate the gaussian at the given x position.
Definition: moo_utils.c:348
cpl_error_code moo_gaussian_fit(cpl_bivector *points, cpl_fit_mode fit_pars, double *center, double *width, double *background, double *area)
Fit the data with a gaussian.
Definition: moo_utils.c:309
double moo_vector_get_max(const cpl_vector *v, int *flags)
Find maximum values in a vector using flags.
Definition: moo_utils.c:1003
cpl_error_code moo_tchebychev_fit(cpl_bivector *data, int *flag, int degree, double xmin, double xmax, double ymin, double ymax)
Computes Tchebitchev transformation of data.
Definition: moo_utils.c:880
double moo_vector_get_percentile(cpl_vector *v, double f)
Get percentile of input vector.
Definition: moo_utils.c:1263
cpl_error_code moo_barycenter_fit(cpl_bivector *points, double *center, double *width)
Fit positions using weighted fluxes.
Definition: moo_utils.c:254