CR2RE Pipeline Reference Manual 1.6.10
cr2res_qc.c
1/*
2 * This file is part of the CR2RES Pipeline
3 * Copyright (C) 2002,2003 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 St, Fifth Floor, Boston, MA 02111-1307 USA
18 */
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24/*-----------------------------------------------------------------------------
25 Includes
26 -----------------------------------------------------------------------------*/
27
28#include <string.h>
29#include <math.h>
30
31#include <cpl.h>
32#include "hdrl.h"
33
34#include "cr2res_qc.h"
35#include "cr2res_qc_lines.h"
36#include "cr2res_trace.h"
37#include "cr2res_dfs.h"
38#include "cr2res_extract.h"
39#include "cr2res_io.h"
40#include "cr2res_calib.h"
41#include "cr2res_detlin.h"
42#include "cr2res_wave.h"
43#include "cr2res_pfits.h"
44
45/*-----------------------------------------------------------------------------
46 Functions prototypes
47 -----------------------------------------------------------------------------*/
48
49static int cr2res_qc_wave_line_intens(
50 const cpl_bivector * spec,
51 double wl,
52 double * intens,
53 double * bgd) ;
54
55/*----------------------------------------------------------------------------*/
59/*----------------------------------------------------------------------------*/
60
63/*----------------------------------------------------------------------------*/
73/*----------------------------------------------------------------------------*/
75 const cpl_image * ima1,
76 const cpl_image * ima2,
77 int hsize,
78 int nsamples,
79 int ndit)
80{
81 cpl_image * ima ;
82 double norm, ron ;
83
84 /* Test entries */
85 if (ima1 == NULL || ima2 == NULL || ndit < 1) return -1.0 ;
86
87 /* Compute norm */
88 norm = 0.5 * ndit ;
89 norm = sqrt(norm) ;
90
91 /* Subtraction */
92 if ((ima = cpl_image_subtract_create(ima2, ima1)) == NULL) return -1.0 ;
93
94 /* RON measurement */
95 cpl_flux_get_noise_window(ima, NULL, hsize, nsamples, &ron, NULL) ;
96 cpl_image_delete(ima) ;
97 return norm*ron ;
98}
99
100/*----------------------------------------------------------------------------*/
110/*----------------------------------------------------------------------------*/
112 const hdrl_imagelist * hdrl_coeffs,
113 double * meda,
114 double * medb,
115 double * medc,
116 double * meda_err)
117{
118 double qc_meda, qc_medb, qc_medc, qc_meda_err ;
119
120 /* Check Entries */
121 if (hdrl_coeffs==NULL || meda==NULL || medb==NULL || medc==NULL ||
122 meda_err==NULL)
123 return -1 ;
124
125 qc_meda = cpl_image_get_median(
126 hdrl_image_get_image(hdrl_imagelist_get(hdrl_coeffs, 0))) ;
127 qc_medb = cpl_image_get_median(
128 hdrl_image_get_image(hdrl_imagelist_get(hdrl_coeffs, 1))) ;
129 qc_medc = cpl_image_get_median(
130 hdrl_image_get_image(hdrl_imagelist_get(hdrl_coeffs, 2))) ;
131 qc_meda_err = cpl_image_get_median(
132 hdrl_image_get_error(hdrl_imagelist_get(hdrl_coeffs, 0))) ;
133
134 if (cpl_error_get_code()) return -1 ;
135
136 if (isnan(qc_meda) || isnan(qc_medb) || isnan(qc_medc)) return -1 ;
137 if (isnan(qc_meda_err)) qc_meda_err = -1.0 ;
138
139 *meda = qc_meda ;
140 *medb = qc_medb ;
141 *medc = qc_medc ;
142 *meda_err = qc_meda_err ;
143 return 0 ;
144}
145
146
147/*----------------------------------------------------------------------------*/
155/*----------------------------------------------------------------------------*/
157 const hdrl_imagelist * hdrl_coeffs,
158 double bpm_thresh,
159 cpl_mask ** outmask,
160 double * min_level,
161 double * max_level)
162{
163 double qc_detlin_median, qc_detlin_min, qc_detlin_max ;
164 int width, height;
165 hdrl_image * img;
166 hdrl_value value = {CR2RES_NONLIN_LEVEL, 0};
167 cpl_mask * tmpmask;
168
169
170 /* Check Entries */
171 if (hdrl_coeffs==NULL || min_level==NULL || max_level==NULL) return -1.0 ;
172
173 /* Initialise */
174 //qc_detlin_median = -1.0 ;
175 //qc_detlin_min = -1.0 ;
176 //qc_detlin_max = -1.0 ;
177
178 // Apply detlin correction on an image with constant value
179 width = hdrl_image_get_size_x(hdrl_imagelist_get(hdrl_coeffs, 0));
180 height = hdrl_image_get_size_y(hdrl_imagelist_get(hdrl_coeffs, 0));
181 img = hdrl_image_new(width, height);
182 hdrl_image_add_scalar(img, value);
183 cr2res_detlin_correct(img, hdrl_coeffs);
184 // mask the Nan values, that exist in the out of order pixels
185 // as well as bad pixels and wherever detlin failed
186 hdrl_image_reject_value(img, CPL_VALUE_NAN);
187
188 if (cpl_msg_get_level() == CPL_MSG_DEBUG){
189 cpl_image_save(
190 hdrl_image_get_image(img), "debug_qccorrection.fits",
191 CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
192 }
193
194 tmpmask = cpl_mask_new(width, height);
195 cpl_mask_threshold_image(tmpmask, hdrl_image_get_image(img),
196 (double)CR2RES_NONLIN_LEVEL,
197 (double)CR2RES_NONLIN_LEVEL * (1.0 + (bpm_thresh/100)),
198 CPL_BINARY_0);
199 hdrl_image_reject_from_mask(img, tmpmask);
200 cpl_mask_delete(tmpmask);
201
202 // Then determine the median of that corrected image
203 qc_detlin_median = cpl_image_get_median(hdrl_image_get_image(img));
204 qc_detlin_min = cpl_image_get_min(hdrl_image_get_image(img)) ;
205 qc_detlin_max = cpl_image_get_max(hdrl_image_get_image(img)) ;
206
207 tmpmask = cpl_mask_duplicate(hdrl_image_get_mask(img));
208 cpl_msg_info(__func__, "BPM has %d pix rejected",
209 (int)cpl_mask_count(tmpmask));
211
212 if (isnan(qc_detlin_median) ||
213 isnan(qc_detlin_min) ||
214 isnan(qc_detlin_max)) {
215 cpl_mask_delete(tmpmask);
216 return -1.0 ;
217 }
218
219 *min_level = qc_detlin_min ;
220 *max_level = qc_detlin_max ;
221 *outmask = tmpmask;
222 return qc_detlin_median ;
223}
224
225/*----------------------------------------------------------------------------*/
234/*----------------------------------------------------------------------------*/
236 const cpl_table * tw,
237 int ** order_nb,
238 double ** order_pos,
239 int * nbvals)
240{
241 int * order_idx_vals ;
242 const cpl_array * slit_frac ;
243 int * order_nb_loc ;
244 double * order_pos_loc ;
245 int i, j, cur_order, nb_order_idx_vals, n_full ;
246 cpl_size nrows ;
247
248 /* Check Entries */
249 if (tw == NULL || order_nb==NULL || order_pos==NULL || nbvals==NULL)
250 return -1 ;
251
252 /* Initialise */
253 *nbvals = 0 ;
254 *order_nb = NULL ;
255 *order_pos = NULL ;
256 nrows = cpl_table_get_nrow(tw) ;
257 if (nrows <= 0) return 0 ;
258
259 /* Get the list of different orders */
260 order_idx_vals = cr2res_trace_get_order_idx_values(tw, &nb_order_idx_vals) ;
261
262 /* Count the number of full slit orders in tw */
263 n_full = 0 ;
264 /* Loop on the different orders */
265 for (i=0 ; i<nb_order_idx_vals ; i++) {
266 cur_order = order_idx_vals[i] ;
267 /* Search an open slit of this order */
268 for (j=0 ; j<nrows ; j++) {
269 if (cpl_table_get(tw, CR2RES_COL_ORDER, j, NULL) == cur_order) {
270 slit_frac = cpl_table_get_array(tw, CR2RES_COL_SLIT_FRACTION,j);
271 if (cr2res_trace_slit_fraction_info(slit_frac, NULL) ==
272 CR2RES_DECKER_NONE) {
273 n_full++ ;
274 /* Go to next order */
275 break ;
276 }
277 }
278 }
279 }
280
281 /* Allocate output arrays */
282 order_nb_loc = cpl_malloc(n_full * sizeof(int)) ;
283 order_pos_loc = cpl_malloc(n_full * sizeof(double)) ;
284
285 /* Fill the arrays */
286 n_full = 0 ;
287
288 /* Loop on the different orders */
289 for (i=0 ; i<nb_order_idx_vals ; i++) {
290 cur_order = order_idx_vals[i] ;
291
292 /* Search an open slit of this order */
293 for (j=0 ; j<nrows ; j++) {
294 if (cpl_table_get(tw, CR2RES_COL_ORDER, j, NULL) == cur_order) {
295 slit_frac = cpl_table_get_array(tw, CR2RES_COL_SLIT_FRACTION,j);
296 if (cr2res_trace_slit_fraction_info(slit_frac, NULL) ==
297 CR2RES_DECKER_NONE) {
298 order_nb_loc[n_full] = cur_order ;
299 order_pos_loc[n_full] = cr2res_trace_get_trace_ypos(tw, j);
300 cpl_msg_debug(__func__, "Order %d Pos : %g",
301 order_nb_loc[n_full], order_pos_loc[n_full]) ;
302 n_full++ ;
303 /* Go to next order */
304 break ;
305 }
306 }
307 }
308 }
309 cpl_free(order_idx_vals);
310
311 /* Return */
312 *nbvals = n_full ;
313 *order_nb = order_nb_loc ;
314 *order_pos = order_pos_loc ;
315 return 0 ;
316}
317
318/*----------------------------------------------------------------------------*/
324/*----------------------------------------------------------------------------*/
326 const cpl_table * trace)
327{
328 cpl_array * array;
329 int * order_idx_values, nb_order_idx_values, central_order_idx, i;
330 int * traces, nb_traces;
331 double qc_trace_center_y ;
332
333 /* Check Entries */
334 if (trace == NULL) return -1.0 ;
335
336 /* Initialise */
337 qc_trace_center_y = 0;
338 // Step 1: find central order
339 order_idx_values = cr2res_trace_get_order_idx_values((cpl_table*) trace,
340 &nb_order_idx_values);
341 array = cpl_array_wrap_int(order_idx_values, nb_order_idx_values);
342
343/* TODO : Is the median really the CENTRAL order ?? */
344 central_order_idx = cpl_array_get_median(array);
345 cpl_array_unwrap(array);
346
347 // Step 2: Sum all traces together
348 traces = cr2res_get_trace_numbers(trace, central_order_idx, &nb_traces);
349 for (i = 0; i < nb_traces; i++) {
350 cpl_vector * vector;
351 vector = cr2res_trace_get_ycen(trace, central_order_idx, traces[i],
352 CR2RES_DETECTOR_SIZE);
353 qc_trace_center_y += cpl_vector_get_mean(vector);
354 cpl_vector_delete(vector);
355 }
356
357 // Step 3: take the mean
358 qc_trace_center_y /= nb_traces;
359
360 cpl_free(order_idx_values);
361 cpl_free(traces);
362
363 return qc_trace_center_y ;
364}
365
366/*----------------------------------------------------------------------------*/
374/*----------------------------------------------------------------------------*/
376 const cpl_table * extracted)
377{
378 cpl_array * col_names ;
379 char * err_col ;
380 const double * pspec ;
381 const double * pspec_err ;
382 cpl_vector * snrs ;
383 cpl_vector * meds ;
384 double snr, med ;
385 cpl_size ncols, i, j, nrows, nmeds ;
386 int trace_nb, order ;
387
388 /* Check Inputs */
389 if (extracted == NULL) return -1.0 ;
390
391 /* Get the column names */
392 col_names = cpl_table_get_column_names(extracted);
393 ncols = cpl_table_get_ncol(extracted) ;
394 if (ncols < 9){
395 cpl_array_delete(col_names) ;
396 return -1.0 ;
397 }
398
399 /* Loop on the columns */
400 nmeds = 0 ;
401 meds = cpl_vector_new(ncols);
402
403 for (i = 0; i < ncols; i++) {
404 char *col_type;
405 const char *col_name;
406 col_name = cpl_array_get_string(col_names, i);
407 col_type = cr2res_dfs_SPEC_colname_parse(col_name, &order,
408 &trace_nb) ;
409 if (col_type != NULL && !strcmp(col_type, CR2RES_COL_SPEC_SUFFIX)) {
410 /* This is a SPEC column */
411 /* Get the error column name */
412 err_col = cr2res_dfs_SPEC_ERR_colname(order,trace_nb) ;
413
414 /* Access the data */
415 pspec = cpl_table_get_data_double_const(extracted, col_name) ;
416 pspec_err = cpl_table_get_data_double_const(extracted, err_col) ;
417
418 nrows = cpl_table_get_nrow(extracted) ;
419 snrs = cpl_vector_new(nrows) ;
420 for (j=0 ; j<nrows ; j++) {
421 snr = 0.0 ;
422 if (fabs(pspec_err[j]) > 1e-3) {
423 snr = pspec[j]/pspec_err[j] ;
424 }
425 cpl_vector_set(snrs, j, snr) ;
426 }
427 cpl_vector_set(meds, nmeds, cpl_vector_get_median(snrs)) ;
428 nmeds++ ;
429 cpl_vector_delete(snrs) ;
430 cpl_free(err_col);
431 }
432 if (col_type != NULL) cpl_free(col_type) ;
433 }
434 cpl_array_delete(col_names) ;
435
436 cpl_vector_set_size(meds, nmeds);
437 med = cpl_vector_get_median(meds) ;
438 cpl_vector_delete(meds);
439
440 // The slit is 180 pixels long -> SNR/pixel needs to divide by sqrt(180)
441 return med/sqrt(180) ;
442}
443
444/*----------------------------------------------------------------------------*/
451/*----------------------------------------------------------------------------*/
453 const cpl_table * tw,
454 int order_idx)
455{
456 cpl_vector * wls ;
457 double wl_central ;
458
459 /* Get the wavelengths */
460 if ((wls = cr2res_trace_get_wl(tw, order_idx, CR2RES_QC_TRACE,
461 CR2RES_DETECTOR_SIZE)) == NULL) {
462 cpl_msg_warning(__func__,
463 "QC CENTWL - cannot find wl solution for order/trace %d/%d",
464 order_idx, CR2RES_QC_TRACE) ;
465 return -1.0 ;
466 }
467 wl_central = cpl_vector_get(wls, (int)(CR2RES_DETECTOR_SIZE/2)) ;
468 cpl_vector_delete(wls) ;
469 return wl_central ;
470}
471
472/*----------------------------------------------------------------------------*/
479/*----------------------------------------------------------------------------*/
481 const cpl_table * tw,
482 int order_idx)
483{
484 cpl_vector * wls ;
485 double wl_disp ;
486 int nbins ;
487
488 if (tw == NULL) return -1.0 ;
489
490 /* Get the wavelengths */
491 if ((wls = cr2res_trace_get_wl(tw, order_idx, CR2RES_QC_TRACE,
492 CR2RES_DETECTOR_SIZE)) == NULL) {
493 cpl_msg_warning(__func__,
494 "QC DISPWL - cannot find wl solution for order/trace %d/%d",
495 order_idx, CR2RES_QC_TRACE) ;
496 return -1.0 ;
497 }
498 nbins = cpl_vector_get_size(wls) ;
499 wl_disp = (cpl_vector_get(wls, nbins-1) - cpl_vector_get(wls, 0)) / nbins;
500 cpl_vector_delete(wls) ;
501 return wl_disp ;
502}
503
504/*----------------------------------------------------------------------------*/
511/*----------------------------------------------------------------------------*/
512cpl_vector * cr2res_qc_lines_collect(double wmin, double wmax)
513{
514 cpl_vector * lines ;
515 int i, nb_found ;
516
517 /* Initialise */
518 nb_found = 0 ;
519
520 /* Find the Interesting lines */
521 for (i=0 ; i< QC_LINES_NUMBER ; i++)
522 if (qc_lines[i] > wmin && qc_lines[i] < wmax) nb_found++ ;
523
524 if (nb_found == 0) return NULL ;
525
526 /* Allocate the container */
527 lines = cpl_vector_new(nb_found);
528
529 /* Fill with the good lines */
530 nb_found = 0 ;
531 for (i=0 ; i< QC_LINES_NUMBER ; i++)
532 if (qc_lines[i] > wmin && qc_lines[i] < wmax)
533 cpl_vector_set(lines, nb_found++, qc_lines[i]) ;
534 return lines;
535}
536
537/*----------------------------------------------------------------------------*/
545/*----------------------------------------------------------------------------*/
547 const cpl_bivector * spec,
548 double wl,
549 double * peak_height)
550{
551 // TODO Thomas / Ansgar
552 //cpl_plot_bivector("set grid;set xlabel 'Wavelength (nm)';
553 // set ylabel 'Spec';", "t 'Spectrum' w lines", "",spec) ;
554 const cpl_vector * wave;
555 const cpl_vector * flux;
556 cpl_vector * unc;
557 cpl_vector * result;
558 cpl_vector * tmp;
559 cpl_size pixel_pos;
560 cpl_size window_width;
561 double fwhm ;
562
563 /* Check Entries */
564 if (spec == NULL || peak_height == NULL) return -1.0;
565
566 /* Initialise */
567 *peak_height = -1.0 ;
568
569 wave = cpl_bivector_get_x_const(spec);
570 flux = cpl_bivector_get_y_const(spec);
571 unc = NULL;
572 result = NULL;
573 // TODO: what should the size of the window be?
574 window_width = CR2RES_QC_WINDOW;
575
576 // Determine pixel pos
577 tmp = cpl_vector_duplicate(wave);
578 cpl_vector_subtract_scalar(tmp, wl);
579 cpl_vector_multiply(tmp, tmp);
580 pixel_pos = cpl_vector_get_minpos(tmp);
581 cpl_vector_delete(tmp);
582
583 // If the wavelength value is outside the spectrum
584 if (pixel_pos == 0 || pixel_pos == cpl_vector_get_size(wave)) return -1.0;
585
586 // Fit the line with a gaussian
587 //if (cr2res_wave_fit_single_line(flux, unc, pixel_pos, window_width, 1, 1,
588 if (cr2res_wave_fit_single_line(flux, unc, pixel_pos, window_width, 1, 0,
589 &result)){
590 // Could not determine the line fit
591 cpl_error_reset();
592 return -1.0 ;
593 }
594
595 // Get the FWHM from the results
596 // and multiply with the conversion factor from sigma to FWHM
597 fwhm = cpl_vector_get(result, 1);
598 fwhm = fwhm * 2.355;
599
600 *peak_height = cpl_vector_get(result, 2) ;
601 cpl_vector_delete(result);
602 return fwhm ;
603}
604
605/*----------------------------------------------------------------------------*/
611/*----------------------------------------------------------------------------*/
613 const cpl_bivector * spec)
614{
615 cpl_bivector * intens_bgd ;
616 cpl_vector * ref_lines ;
617 double * pintens,
618 * pbgs ;
619
620 double wmin, wmax;
621
622 int i, nall ;
623
624 /* Get the reference lines */
625 wmin = cpl_vector_get(cpl_bivector_get_x_const(spec), 0);
626 wmax = cpl_vector_get(cpl_bivector_get_x_const(spec),
627 cpl_bivector_get_size(spec)-1) ;
628 ref_lines = cr2res_qc_lines_collect(wmin, wmax) ;
629 if (ref_lines == NULL) return NULL ;
630
631 /* Loop on the lines */
632 nall = cpl_vector_get_size(ref_lines);
633 intens_bgd = cpl_bivector_new(nall) ;
634 pintens = cpl_bivector_get_x_data(intens_bgd) ;
635 pbgs = cpl_bivector_get_y_data(intens_bgd) ;
636 for (i=0 ; i < nall ; i++) {
637 double curr_refline;
638 curr_refline = cpl_vector_get(ref_lines, i) ;
639 cr2res_qc_wave_line_intens(spec, curr_refline,
640 &(pintens[i]), &(pbgs[i]));
641 cpl_msg_debug(__func__, "Ref : %g, intens: %g, Bgd : %g",
642 curr_refline, pintens[i], pbgs[i]) ;
643 }
644 cpl_vector_delete(ref_lines) ;
645
646 return intens_bgd;
647}
648
649/*----------------------------------------------------------------------------*/
655/*----------------------------------------------------------------------------*/
657 const cpl_bivector * spec)
658{
659 cpl_vector * ref_lines ;
660 cpl_vector * ref_lines_intens ;
661 double wmin, wmax, intens_med, intens, bgd;
662 int i, n, nall ;
663
664 /* Get the reference lines */
665 wmin = cpl_vector_get(cpl_bivector_get_x_const(spec), 0);
666 wmax = cpl_vector_get(cpl_bivector_get_x_const(spec),
667 cpl_bivector_get_size(spec)-1) ;
668 ref_lines = cr2res_qc_lines_collect(wmin, wmax) ;
669 if (ref_lines == NULL) return -1.0 ;
670
671 //cpl_vector_dump(ref_lines, stdout) ;
672
673 /* Loop on the lines */
674 n = 0;
675 nall = cpl_vector_get_size(ref_lines);
676 ref_lines_intens = cpl_vector_new(nall) ;
677 for (i=0 ; i < nall ; i++) {
678 cr2res_qc_wave_line_intens(spec, cpl_vector_get(ref_lines, i),
679 &intens, &bgd);
680 if (intens-bgd > 0.0) {
681 cpl_vector_set(ref_lines_intens, n, intens-bgd);
682 n++;
683 }
684 }
685 cpl_vector_delete(ref_lines) ;
686 if (n == 0){
687 cpl_vector_delete(ref_lines_intens) ;
688 return -1.0 ;
689 }
690 cpl_vector_set_size(ref_lines_intens, n);
691 cpl_msg_info(__func__,
692 "Using %i of %i lines to estimate Intensity", n, nall);
693
694
695 /* Compute the median */
696 intens_med = cpl_vector_get_median(ref_lines_intens) ;
697 cpl_vector_delete(ref_lines_intens) ;
698
699 return intens_med ;
700}
701
702/*----------------------------------------------------------------------------*/
709/*----------------------------------------------------------------------------*/
711 const cpl_bivector * spec,
712 double * wl)
713{
714 cpl_vector * ref_lines ;
715 cpl_vector * ref_lines_fwhm ;
716 cpl_vector * ref_lines_pos ;
717 double wmin, wmax, peak_height, min_fwhm_val,
718 min_fwhm_pos;
719 cpl_size idx ;
720 int i, n, nall;
721
722 /* Check Entries */
723 if (spec == NULL || wl == NULL) return -1.0 ;
724
725 /* Initialise */
726 *wl = -1.0 ;
727
728 /* Get the reference lines */
729 wmin = cpl_vector_get(cpl_bivector_get_x_const(spec), 0);
730 wmax = cpl_vector_get(cpl_bivector_get_x_const(spec),
731 cpl_bivector_get_size(spec)-1) ;
732 ref_lines = cr2res_qc_lines_collect(wmin, wmax) ;
733 if (ref_lines == NULL) return -1.0 ;
734
735 //cpl_vector_dump(ref_lines, stdout) ;
736
737 /* Loop on the lines */
738 n = 0;
739 nall = cpl_vector_get_size(ref_lines);
740 ref_lines_fwhm = cpl_vector_new(nall) ;
741 ref_lines_pos = cpl_vector_new(nall) ;
742 for (i=0 ; i<cpl_vector_get_size(ref_lines) ; i++) {
743 double fwhm;
744 fwhm = cr2res_qc_wave_line_fwhm(spec, cpl_vector_get(ref_lines, i),
745 &peak_height);
746 /*
747 printf("---> Line %g nm / PEAK %g / FWHM %g\n",
748 cpl_vector_get(ref_lines, i), peak_height, fwhm) ;
749 */
750
751 if (fwhm > 0.1 && fwhm < CR2RES_QC_WINDOW && peak_height > 0
752 && peak_height<CR2RES_SATURATED_LINES_THRESH) {
753 cpl_vector_set(ref_lines_fwhm, n, fwhm);
754 cpl_vector_set(ref_lines_pos, n, cpl_vector_get(ref_lines, i));
755 n++;
756 }
757 }
758 cpl_vector_delete(ref_lines) ;
759 if (n == 0){
760 cpl_vector_delete(ref_lines_fwhm) ;
761 cpl_vector_delete(ref_lines_pos) ;
762 return -1.0;
763 }
764 cpl_vector_set_size(ref_lines_fwhm, n);
765 cpl_vector_set_size(ref_lines_pos, n);
766
767 /* Return the smallest FWHM and its position */
768 idx = cpl_vector_get_minpos(ref_lines_fwhm) ;
769 if (idx < 0) {
770 cpl_vector_delete(ref_lines_fwhm) ;
771 cpl_vector_delete(ref_lines_pos) ;
772 return -1.0 ;
773 }
774 min_fwhm_val = cpl_vector_get(ref_lines_fwhm, idx) ;
775 min_fwhm_pos = cpl_vector_get(ref_lines_pos, idx) ;
776 cpl_vector_delete(ref_lines_fwhm) ;
777 cpl_vector_delete(ref_lines_pos) ;
778
779 cpl_msg_info(__func__, "Using the smallest FWHM %g of line at %g nm",
780 min_fwhm_val, min_fwhm_pos) ;
781
782 /* Return */
783 *wl = min_fwhm_pos ;
784 return min_fwhm_val ;
785}
786
787/*----------------------------------------------------------------------------*/
795/*----------------------------------------------------------------------------*/
797 const cpl_image * ima,
798 const cpl_table * tw,
799 int order_idx)
800{
801 cpl_image * labels ;
802 const double * pima ;
803 int * plabel ;
804 int i, j, nb_over, nb_total ;
805
806 /* Check Entries */
807 if (ima == NULL || tw == NULL) return -1.0 ;
808 if (cpl_image_get_size_x(ima) != CR2RES_DETECTOR_SIZE ||
809 cpl_image_get_size_y(ima) != CR2RES_DETECTOR_SIZE) {
810 return -1.0 ;
811 }
812 pima = cpl_image_get_data_double_const(ima) ;
813
814 /* Create Label image */
815 labels = cr2res_trace_gen_image((cpl_table *)tw, CR2RES_DETECTOR_SIZE,
816 CR2RES_DETECTOR_SIZE);
817 plabel = cpl_image_get_data_int(labels) ;
818
819 nb_over = nb_total = 0 ;
820 /* Loop on th pixels */
821 for (j=0 ; j<CR2RES_DETECTOR_SIZE ; j++) {
822 for (i=0 ; i<CR2RES_DETECTOR_SIZE ; i++) {
823 if (plabel[i+j*CR2RES_DETECTOR_SIZE] == order_idx &&
824 !cpl_image_is_rejected(ima, i+1, j+1)) {
825 nb_total++ ;
826 if (pima[i+j*CR2RES_DETECTOR_SIZE] >
827 CR2RES_DETECTOR_OVEREXP_THRESH) {
828 nb_over ++ ;
829 }
830 }
831 }
832 }
833 cpl_image_delete(labels) ;
834 if (nb_total == 0) return -1.0 ;
835 return (double)nb_over/(double)nb_total ;
836}
837
838/*----------------------------------------------------------------------------*/
844/*----------------------------------------------------------------------------*/
846 const cpl_table * extracted)
847{
848 double qc_signal ;
849 char * colname;
850 double * data;
851 cpl_vector * vector, *vector2;
852 int nrows, size;
853
854 /* Check Entries */
855 if (extracted == NULL) return -1.0 ;
856
857 /* Initialise */
858 //qc_signal = -1.0 ;
859 colname = cr2res_dfs_SPEC_colname(CR2RES_QC_ORDER, CR2RES_QC_TRACE);
860 data = cpl_table_get_data_double((cpl_table*) extracted, colname);
861 cpl_free(colname);
862
863 if (cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) {
864 // QC order or trace not found in the table
865 cpl_error_reset();
866 return -1;
867 }
868
869 nrows = cpl_table_get_nrow(extracted);
870 size = CR2RES_QC_SIZE;
871 if (nrows < size) size = nrows;
872
873 vector = cpl_vector_wrap(nrows, data);
874 vector2 = cpl_vector_extract(vector, (nrows - size)/ 2, (nrows + size)
875 / 2 - 1, 1);
876 qc_signal = cpl_vector_get_median(vector2);
877
878 cpl_vector_unwrap(vector);
879 cpl_vector_delete(vector2);
880
881 return qc_signal ;
882}
883
884/*----------------------------------------------------------------------------*/
891/*----------------------------------------------------------------------------*/
893 const cpl_table * extracted,
894 char * setting)
895{
896 double qc_flux ;
897 char * colname;
898 double * ext_data;
899 double * wl_data;
900 double wl_start, wl_stop ;
901 cpl_vector * vector, *vector2;
902 int nrows, wl_start_index, wl_stop_index, i ;
903
904 /* Check Entries */
905 if (extracted == NULL) return -1.0 ;
906
907 /* Initialise */
908 //qc_flux = -1.0 ;
909 wl_start = -1.0 ;
910 wl_stop = -1 ;
911 nrows = cpl_table_get_nrow(extracted);
912
913 /* Get the wl boundaries */
914 if (!strcmp(setting, "Y1029")) {
915 wl_start = 1087.3 ;
916 wl_stop = -1 ;
917 } else if (!strcmp(setting, "H1559")) {
918 wl_start = 1504.8 ;
919 wl_stop = -1 ;
920 } else if (!strcmp(setting, "K2217")) {
921 wl_start = 2205.0 ;
922 wl_stop = -1 ;
923 } else if (!strcmp(setting, "L3377")) {
924 wl_start = 3828.70 ;
925 wl_stop = 3829.30 ;
926 } else if (!strcmp(setting, "M4266")) {
927 wl_start = 3953.00 ;
928 wl_stop = 3953.90 ;
929 } else if (!strcmp(setting, "Y1028")) {
930 wl_start = 1045.70 ;
931 wl_stop = 1047.00 ;
932 } else if (!strcmp(setting, "J1228")) {
933 wl_start = 1245.50 ;
934 wl_stop = 1246.40 ;
935 } else if (!strcmp(setting, "H1567")) {
936 wl_start = 1695.20 ;
937 wl_stop = 1696.20 ;
938 } else if (!strcmp(setting, "K2148")) {
939 wl_start = 2312.60 ;
940 wl_stop = 2313.30 ;
941 }
942
943 if (wl_start < 0.0) {
944 cpl_msg_info(__func__,
945 "QC Standard Flux : No WL specified for setting %s", setting) ;
946 return -1.0 ;
947 }
948
949 /* Get the Data */
950 colname = cr2res_dfs_SPEC_colname(CR2RES_QC_ORDER, CR2RES_QC_TRACE);
951 ext_data = cpl_table_get_data_double((cpl_table*) extracted, colname);
952 cpl_free(colname);
953 colname = cr2res_dfs_WAVELENGTH_colname(CR2RES_QC_ORDER, CR2RES_QC_TRACE);
954 wl_data = cpl_table_get_data_double((cpl_table*) extracted, colname);
955 cpl_free(colname);
956 if (cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) {
957 cpl_error_reset();
958 return -1;
959 }
960
961 wl_start_index = -1 ;
962 for (i=0 ; i<nrows ; i++) {
963 if (wl_data[i] > wl_start && wl_start_index < 0) {
964 wl_start_index = i ;
965 break ;
966 }
967 }
968 wl_stop_index = -1;
969 if (wl_stop > 0.0) {
970 for (i=0 ; i<nrows ; i++) {
971 if (wl_data[i] < wl_stop && wl_stop_index < 0) {
972 wl_stop_index = i ;
973 break ;
974 }
975 }
976 } else {
977 wl_stop_index = wl_start_index + CR2RES_QC_SIZE ;
978 }
979
980 if (wl_start_index < 0 || wl_stop_index >= cpl_table_get_nrow(extracted)) {
981 cpl_msg_warning(__func__,
982 "QC Standard Flux : Specified WL out of range %g-%g",
983 wl_start, wl_stop) ;
984 return -1.0 ;
985 }
986 cpl_msg_info(__func__,
987 "QC STD FLUX : Trace %d Order %d WL start %g, idx range: [%d-%d]",
988 CR2RES_QC_TRACE, CR2RES_QC_ORDER, wl_start, wl_start_index,
989 wl_stop_index) ;
990
991 vector = cpl_vector_wrap(nrows, ext_data);
992 vector2 = cpl_vector_extract(vector, wl_start_index, wl_stop_index, 1) ;
993 qc_flux = cpl_vector_get_mean(vector2);
994 cpl_vector_unwrap(vector);
995 cpl_vector_delete(vector2);
996
997 return qc_flux ;
998}
999
1000/*----------------------------------------------------------------------------*/
1009/*----------------------------------------------------------------------------*/
1011 const cpl_table * tw,
1012 const cpl_table * extracted,
1013 int ** out_order_idx_values,
1014 int * out_nb_order_idx_values)
1015{
1016 int * order_idx_values ;
1017 int nb_order_idx_values ;
1018 cpl_bivector * my_spec,
1019 * my_spec_err ;
1020 double * snrs ;
1021 int i;
1022
1023 /* Check Entries */
1024 if (tw==NULL || extracted==NULL || out_order_idx_values==NULL ||
1025 out_nb_order_idx_values==NULL) return NULL ;
1026
1027 /* Get the number of orders from TW table */
1028 order_idx_values = cr2res_trace_get_order_idx_values(tw,
1029 &nb_order_idx_values) ;
1030
1031 /* Allocate the output arrays */
1032 snrs = cpl_malloc(nb_order_idx_values * sizeof(double)) ;
1033
1034 /* Loop on the orders */
1035 for (i=0 ; i<nb_order_idx_values ; i++) {
1036 /* Compute the SNR */
1038 order_idx_values[i], 1, &my_spec, &my_spec_err) == 0) {
1039 snrs[i] = cr2res_qc_compute_snr(
1040 cpl_bivector_get_y(my_spec),
1041 cpl_bivector_get_y(my_spec_err));
1042 cpl_bivector_delete(my_spec);
1043 cpl_bivector_delete(my_spec_err);
1044 }
1045 else
1046 {
1047 snrs[i] = -1.0 ;
1048 }
1049 }
1050
1051 *out_order_idx_values = order_idx_values ;
1052 *out_nb_order_idx_values = nb_order_idx_values ;
1053 return snrs ;
1054}
1055
1056
1057/*----------------------------------------------------------------------------*/
1064/*----------------------------------------------------------------------------*/
1065double cr2res_qc_compute_snr(cpl_vector * spec,
1066 cpl_vector * err)
1067{
1068 double snr;
1069 cpl_vector *snr_spec;
1070 cpl_vector *myerr;
1071 int j;
1072
1073 snr_spec = cpl_vector_duplicate(spec);
1074 myerr = cpl_vector_duplicate(err);
1075 /* Clean the error to avoid division by 0.0 */
1076 for (j=0 ; j<cpl_vector_get_size(myerr) ; j++) {
1077 double err_val;
1078 err_val = cpl_vector_get(myerr,j) ;
1079 if (fabs(err_val) < 1e-3 || isnan(err_val)) {
1080 cpl_vector_set(myerr, j, 1.0) ;
1081 //cpl_vector_set(snr_spec, j, 0.0);
1082 }
1083 }
1084 cpl_vector_divide(snr_spec, myerr) ;
1085
1086 snr = cpl_vector_get_median(snr_spec) ;
1087 if (isnan(snr)) snr = -1.0 ;
1088 cpl_vector_delete(snr_spec) ;
1089 cpl_vector_delete(myerr) ;
1090 return snr;
1091}
1092
1093/*----------------------------------------------------------------------------*/
1102/*----------------------------------------------------------------------------*/
1104 const cpl_table * tw,
1105 const cpl_table * extracted,
1106 int ** out_order_idx_values,
1107 int * out_nb_order_idx_values)
1108{
1109 int * order_idx_values ;
1110 int nb_order_idx_values ;
1111 cpl_bivector * my_spec,
1112 * my_spec_err ;
1113 double * snrs ;
1114 int i;
1115
1116 /* Check Entries */
1117 if (tw==NULL || extracted==NULL || out_order_idx_values==NULL ||
1118 out_nb_order_idx_values==NULL) return NULL ;
1119
1120 /* Get the number of orders from TW table */
1121 order_idx_values = cr2res_trace_get_order_idx_values(tw,
1122 &nb_order_idx_values) ;
1123
1124 /* Allocate the output arrays */
1125 snrs = cpl_malloc(nb_order_idx_values * sizeof(double)) ;
1126
1127 /* Loop on the orders */
1128 for (i=0 ; i<nb_order_idx_values ; i++) {
1129 /* Compute the SNR */
1131 order_idx_values[i], 1, &my_spec, &my_spec_err) == 0) {
1132 snrs[i] = cr2res_qc_compute_der_snr(
1133 cpl_bivector_get_y(my_spec),
1134 cpl_bivector_get_y(my_spec_err));
1135 cpl_bivector_delete(my_spec);
1136 cpl_bivector_delete(my_spec_err);
1137 }
1138 else
1139 {
1140 snrs[i] = -1.0 ;
1141 }
1142 }
1143
1144 *out_order_idx_values = order_idx_values ;
1145 *out_nb_order_idx_values = nb_order_idx_values ;
1146 return snrs ;
1147}
1148
1149/*----------------------------------------------------------------------------*/
1156/*----------------------------------------------------------------------------*/
1157double cr2res_qc_compute_der_snr(cpl_vector * spec,
1158 cpl_vector * err)
1159{
1160 cpl_vector *filt_spec;
1161
1162 int filt_spec_size;
1163
1164 filt_spec = cpl_vector_new(cpl_vector_get_size(spec));
1165
1166 filt_spec_size = 0;
1167 for (int j=0 ; j<cpl_vector_get_size(err) ; j++) {
1168 double err_val;
1169 double spec_val;
1170 err_val = cpl_vector_get(err,j) ;
1171 spec_val = cpl_vector_get(spec,j) ;
1172 if (!(isnan(spec_val) || isnan(err_val) || spec_val==0.0)) {
1173 cpl_vector_set(filt_spec, filt_spec_size, spec_val);
1174 filt_spec_size++;
1175 }
1176 }
1177
1178 if (filt_spec_size > 4) {
1179 cpl_vector_set_size(filt_spec, filt_spec_size);
1180
1181 cpl_vector *abs_diff = cpl_vector_new(filt_spec_size - 4);
1182
1183 for (int i = 2; i < filt_spec_size - 2; i++) {
1184 cpl_vector_set(abs_diff, i - 2, fabs(2.0 * cpl_vector_get(filt_spec, i) - cpl_vector_get(filt_spec, i - 2) - cpl_vector_get(filt_spec, i + 2)));
1185 }
1186
1187 double signal = cpl_vector_get_median(filt_spec);
1188 double noise = 0.6052697 * cpl_vector_get_median(abs_diff);
1189
1190 cpl_vector_delete(abs_diff);
1191 cpl_vector_delete(filt_spec);
1192
1193 return signal / noise;
1194 } else {
1195 cpl_vector_delete(filt_spec) ;
1196 return -1.0;
1197 }
1198}
1199
1200/*----------------------------------------------------------------------------*/
1207/*----------------------------------------------------------------------------*/
1209 const cpl_table * slitfu,
1210 int order_idxp,
1211 int oversample)
1212{
1213 cpl_vector * x ;
1214 cpl_vector * y ;
1215 char * colname ;
1216 const double * data ;
1217 cpl_size i, j ;
1218 cpl_fit_mode fit_pars ;
1219 int nrow ;
1220 double qc_fwhm, x0, sigma, area, offset, extr_height;
1221
1222 /* Check Entries */
1223 if (slitfu == NULL) return -1 ;
1224
1225 /* Get the table column name */
1226 colname = cr2res_dfs_SLIT_FUNC_colname(order_idxp, 1);
1227 data = cpl_table_get_data_double_const(slitfu, colname);
1228 cpl_free(colname);
1229 if (data == NULL) {
1230 cpl_msg_warning(__func__, "No slitfunc data: code %d",
1231 cpl_error_get_code());
1232 cpl_error_reset();
1233 return -1;
1234 }
1235
1236 /* Initialise */
1237 //qc_fwhm = -1.0 ;
1238 fit_pars = CPL_FIT_CENTROID + CPL_FIT_STDEV + CPL_FIT_AREA;
1239 offset = 0.;
1240
1241 nrow = cpl_table_get_nrow(slitfu);
1242
1243 /* x is just the element number */
1244 x = cpl_vector_new(nrow);
1245 y = cpl_vector_new(nrow);
1246 for (i = 0; i < nrow; i++){
1247 cpl_vector_set(x, i, i);
1248 cpl_vector_set(y, i, 0);
1249 }
1250
1251 /* remove "strange" values, i.e. nan and unreasonably large values */
1252 /* otherwise the fit will not work */
1253 /* Slitfunc should be normalised to the oversampling rate(?) */
1254 for (j = 0; j < nrow; j++) {
1255 if (isnan(data[j]) | (data[j] > 1)){
1256 cpl_vector_set(y, j, 0);
1257 } else {
1258 cpl_vector_set(y, j, data[j]);
1259 }
1260 }
1261 cpl_vector_fit_gaussian(x, NULL, y, NULL, fit_pars, &x0, &sigma,
1262 &area, &offset, NULL, NULL, NULL);
1263 if (cpl_error_get_code()) {
1264 cpl_msg_warning(__func__, "Failed Fit for the slit PSF") ;
1265 cpl_error_reset() ;
1266 sigma = 0.0 ;
1267 }
1268 qc_fwhm = 2.355 * sigma; // 2.355 = 2 * sqrt(2 * ln(2))
1269
1270 /* Correct for oversampling */
1271 /* nrow is 1+ (extr_height+1)*oversample */
1272 /* and we want the ratio of extr_height/nrow */
1273 extr_height = (nrow-1) / oversample -1;
1274 qc_fwhm *= extr_height / nrow;
1275 cpl_msg_debug(__func__,"extr_height / nrow = %g",extr_height / nrow);
1276
1277 /* Free Memory */
1278 cpl_vector_delete(x);
1279 cpl_vector_delete(y);
1280 return qc_fwhm ;
1281}
1282
1283/*----------------------------------------------------------------------------*/
1289/*----------------------------------------------------------------------------*/
1290int cr2res_qc_numsat(const cpl_frameset * frameset)
1291{
1292 hdrl_image * hima ;
1293 cpl_image * ima ;
1294 double * pima ;
1295 int det_nr, max_nsat, nsat ;
1296 cpl_size i, k, nframes, nx, ny ;
1297
1298 /* Check Inputs */
1299 if (frameset == NULL) return -1 ;
1300
1301 /* Initialise */
1302 max_nsat = 0 ;
1303 nframes = cpl_frameset_get_size(frameset);
1304
1305 for (i = 0; i < nframes; i++) {
1306 const cpl_frame *frame;
1307 const char *fname;
1308 frame = cpl_frameset_get_position_const(frameset, i);
1309 fname = cpl_frame_get_filename(frame);
1310 for (det_nr=1 ; det_nr<=CR2RES_NB_DETECTORS ; det_nr++) {
1311 nsat = 0 ;
1312 hima = cr2res_io_load_image(fname, det_nr) ;
1313 if (hima != NULL) {
1314 ima = hdrl_image_get_image(hima) ;
1315 pima = cpl_image_get_data_double(ima) ;
1316 nx = cpl_image_get_size_x(ima) ;
1317 ny = cpl_image_get_size_y(ima) ;
1318 for (k = 0 ; k<nx*ny ; k++) {
1319 if (pima[k] > CR2RES_DETECTOR_OVEREXP_THRESH) nsat++ ;
1320 }
1321 hdrl_image_delete(hima) ;
1322 } else {
1323 cpl_msg_warning(__func__, "NUMSAT - cannot load detector") ;
1324 cpl_error_reset() ;
1325 }
1326 if (nsat > max_nsat) max_nsat = nsat ;
1327 }
1328 }
1329 return max_nsat ;
1330}
1331
1334/*----------------------------------------------------------------------------*/
1343/*----------------------------------------------------------------------------*/
1344static int cr2res_qc_wave_line_intens(
1345 const cpl_bivector * spec,
1346 double wl,
1347 double * intens,
1348 double * bgd)
1349{
1350 // TODO Thomas / Ansgar
1351 //cpl_plot_bivector("set grid;set xlabel 'Wavelength (nm)';
1352 // set ylabel 'Spec';", "t 'Spectrum' w lines", "",spec) ;
1353 const cpl_vector * wave;
1354 const cpl_vector * flux;
1355 cpl_vector * tmp;
1356 cpl_size pixel_pos;
1357 cpl_size window_size;
1358 cpl_size n_inner, n_outer;
1359 double sum_inner, sum_outer;
1360 double value;
1361
1362 /* Initialise */
1363 *intens = -1.0 ;
1364 *bgd = 0.0 ;
1365
1366 if (spec == NULL) return -1 ;
1367
1368 // TODO: How large should this window be?
1369 window_size = CR2RES_QC_WINDOW / 2;
1370
1371 wave = cpl_bivector_get_x_const(spec);
1372 flux = cpl_bivector_get_y_const(spec);
1373
1374 // Determine pixel pos
1375 // TODO: If we are sure that wave is sorted, we can also use cpl_vector_find
1376 tmp = cpl_vector_duplicate(wave);
1377 cpl_vector_subtract_scalar(tmp, wl);
1378 cpl_vector_multiply(tmp, tmp);
1379 pixel_pos = cpl_vector_get_minpos(tmp);
1380 cpl_vector_delete(tmp);
1381
1382 // If the wavelength value is outside the spectrum
1383 if (pixel_pos == 0 || pixel_pos == cpl_vector_get_size(wave)) return -1.0;
1384
1385 // Sum up the values of the spectrum
1386 // inside the window and outside the window
1387 sum_inner = 0;
1388 sum_outer = 0;
1389 n_inner = 0;
1390 n_outer = 0;
1391 for (cpl_size i = -window_size * 2; i < 2 * window_size; i++)
1392 {
1393 cpl_size k;
1394 k = pixel_pos - i;
1395 if (k < 0 || k >= cpl_vector_get_size(flux)){
1396 continue;
1397 }
1398 value = cpl_vector_get(flux, k);
1399 if (isnan(value)){
1400 continue;
1401 }
1402 if (llabs(i) < window_size){
1403 // Inner sum
1404 n_inner++;
1405 sum_inner += value;
1406 } else {
1407 // Outer sum
1408 n_outer++;
1409 sum_outer += value;
1410 }
1411 }
1412 if (n_inner + n_outer == 0){
1413 // No valid points
1414 return -1 ;
1415 }
1416 // Take the mean
1417 if (n_inner != 0) sum_inner /= n_inner;
1418 if (n_outer != 0) sum_outer /= n_outer;
1419 // return the difference
1420
1421 *intens = sum_inner ;
1422 *bgd = sum_outer ;
1423 return 0 ;
1424}
1425
1426int cr2res_qc_calculate_mean_and_rmsd(cpl_propertylist ***plists, int size, const int *sizes,
1427 const char *ref_keyword, cpl_propertylist *qc_main,
1428 const char *result_avg_keyword, const char *result_rmsd_keyword) {
1429
1430 cpl_errorstate status;
1431
1432 status = cpl_errorstate_get();
1433
1434 double sum = 0.0;
1435 double sum_sq = 0.0;
1436 int count = 0;
1437
1438 for (int i = 0; i < size; i++) {
1439 for (int j = 0; j<sizes[i]; j++){
1440 if (plists[i][j] != NULL) {
1441 double value = cpl_propertylist_get_double(plists[i][j], ref_keyword);
1442 if(!cpl_errorstate_is_equal(status)) {
1443 cpl_msg_debug(__func__, "Cannot get keyword %s : %s", ref_keyword, cpl_error_get_message());
1444 cpl_errorstate_set(status);
1445 continue;
1446 }
1447 sum += value;
1448 sum_sq += value * value;
1449 count++;
1450 }
1451 }
1452 }
1453
1454 if (count > 0) {
1455 double mean = sum / count;
1456
1457 double rmsd = 0.0;
1458
1459 if (count > 1) {
1460 rmsd = sqrt( (count*mean*mean - 2*mean*sum + sum_sq) / count);
1461 }
1462
1463 if (qc_main != NULL) {
1464 cpl_propertylist_append_double(qc_main, result_avg_keyword, mean);
1465 cpl_propertylist_append_double(qc_main, result_rmsd_keyword, rmsd);
1466 }
1467 }
1468 return 0;
1469}
1470
1471int
1472cr2res_qc_dup_mtrlgy_key(cpl_frameset *framelist, cpl_propertylist *plist)
1473{
1474
1475 /*
1476 * Get the first input frame in the input set-of-frames.
1477 * Copied from cpl_dfs_setup_product_header()
1478 */
1479
1480
1481 const cpl_frame *frame;
1482 const cpl_frame *first_frame = NULL;
1483 cpl_frameset_iterator *it = NULL;
1484 cpl_propertylist *met_plist = NULL;
1485
1486 cpl_errorstate status;
1487
1488 it = cpl_frameset_iterator_new(framelist);
1489 frame = cpl_frameset_iterator_get_const(it);
1490
1491 while (frame != NULL) {
1492
1493 if (cpl_frame_get_group(frame) == CPL_FRAME_GROUP_RAW) {
1494 first_frame = frame;
1495 break;
1496 }
1497
1498 status = cpl_errorstate_get();
1499
1500 cpl_frameset_iterator_advance(it, 1);
1501
1502 if (cpl_error_get_code() == CPL_ERROR_ACCESS_OUT_OF_RANGE) {
1503 cpl_errorstate_set(status);
1504 }
1505
1506 frame = cpl_frameset_iterator_get_const(it);
1507 }
1508
1509 if (first_frame == NULL) {
1510 cpl_frameset_iterator_reset(it);
1511 frame = cpl_frameset_iterator_get_const(it);
1512
1513 while (frame != NULL) {
1514
1515 if (cpl_frame_get_group(frame) == CPL_FRAME_GROUP_CALIB) {
1516 first_frame = frame;
1517 break;
1518 }
1519
1520 status = cpl_errorstate_get();
1521
1522 cpl_frameset_iterator_advance(it, 1);
1523
1524 if (cpl_error_get_code() == CPL_ERROR_ACCESS_OUT_OF_RANGE) {
1525 cpl_errorstate_set(status);
1526 }
1527
1528 frame = cpl_frameset_iterator_get_const(it);
1529 }
1530 }
1531
1532 cpl_frameset_iterator_delete(it);
1533 it = NULL;
1534
1535 if (first_frame == NULL) {
1536 cpl_msg_debug(__func__, "No suitable frame found for QC MTRLGY ID in sof.");
1537 return 0;
1538 }
1539
1540
1541 status = cpl_errorstate_get();
1542
1543 met_plist =
1544 cpl_propertylist_load_regexp(cpl_frame_get_filename(first_frame), 0,
1545 CR2RES_HEADER_OCS_MTRLGY, 0);
1546 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1547 cpl_msg_debug(__func__, "Cannot read header for QC MTRLGY ID : %s", cpl_error_get_message());
1548 cpl_errorstate_set(status);
1549 return 0;
1550 }
1551
1552 if (plist != NULL) {
1553 int mtrlgy_st;
1554 mtrlgy_st =
1555 cpl_propertylist_get_bool(met_plist, CR2RES_HEADER_OCS_MTRLGY);
1556 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1557 cpl_msg_debug(__func__, "Cannot get keyword %s : %s",
1558 CR2RES_HEADER_OCS_MTRLGY, cpl_error_get_message());
1559 cpl_errorstate_set(status);
1560 }
1561 else {
1562 if (mtrlgy_st == 0) {
1563 cpl_propertylist_prepend_int(plist, CR2RES_HEADER_QC_MTRLGY_ID,
1564 0);
1565 }
1566 else {
1567 cpl_propertylist_prepend_int(plist, CR2RES_HEADER_QC_MTRLGY_ID,
1568 1);
1569 }
1570 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1571 cpl_msg_debug(__func__, "Cannot write keyword %s : %s",
1572 CR2RES_HEADER_QC_MTRLGY_ID,
1573 cpl_error_get_message());
1574 cpl_errorstate_set(status);
1575 }
1576 }
1577 }
1578
1579 if (met_plist != NULL){
1580 cpl_propertylist_delete(met_plist);
1581 }
1582
1583 return 0;
1584}
1585
1586
1587int
1588cr2res_qc_dup_chip_idx(cpl_propertylist *plist)
1589{
1590
1591 cpl_errorstate status;
1592
1593 status = cpl_errorstate_get();
1594
1595 if (plist != NULL) {
1596 int chip_idx;
1597 char id[6];
1598 chip_idx = cpl_propertylist_get_int(plist, CR2RES_HEADER_CHIP_IDX);
1599 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1600 cpl_msg_debug(__func__, "Cannot get keyword %s : %s",
1601 CR2RES_HEADER_OCS_MTRLGY, cpl_error_get_message());
1602 cpl_errorstate_set(status);
1603 }
1604 else {
1605 if (chip_idx >= 1 && chip_idx <= 3) {
1606 sprintf(id, "CHIP%d", chip_idx);
1607 cpl_propertylist_append_string(plist, CR2RES_HEADER_QC_DET_ID,
1608 id);
1609 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1610 cpl_msg_debug(__func__, "Cannot write keyword %s : %s",
1611 CR2RES_HEADER_QC_DET_ID,
1612 cpl_error_get_message());
1613 cpl_errorstate_set(status);
1614 }
1615 }
1616 else {
1617 cpl_msg_debug(__func__,
1618 "CHIP INDEX not recognized for QC DET ID: %d",
1619 chip_idx);
1620 }
1621 }
1622 }
1623
1624 return 0;
1625}
int cr2res_detlin_correct(hdrl_image *in, const hdrl_imagelist *detlin)
Apply the detector linearity correction.
Definition: cr2res_detlin.c:71
char * cr2res_dfs_SLIT_FUNC_colname(int order_idx, int trace)
Get the SLIT_FUNC table column name for a given order/trace.
Definition: cr2res_dfs.c:432
char * cr2res_dfs_SPEC_ERR_colname(int order_idx, int trace)
Get the ERR column name for a given order/trace.
Definition: cr2res_dfs.c:414
char * cr2res_dfs_WAVELENGTH_colname(int order_idx, int trace)
Get the WAVELENGTH column name for a given order/trace.
Definition: cr2res_dfs.c:396
char * cr2res_dfs_SPEC_colname_parse(const char *colname, int *order_idx, int *trace)
Parse a column name ORDER_TRACE_TYPE format.
Definition: cr2res_dfs.c:505
char * cr2res_dfs_SPEC_colname(int order_idx, int trace)
Get the SPEC column name for a given order/trace.
Definition: cr2res_dfs.c:378
int cr2res_extract_EXTRACT1D_get_spectrum(const cpl_table *tab, int order, int trace_nb, cpl_bivector **spec, cpl_bivector **spec_err)
Get a Spectrum and its error from the EXTRACT_1D table.
hdrl_image * cr2res_io_load_image(const char *in, int detector)
Load an hdrl image from a image file.
Definition: cr2res_io.c:704
double cr2res_qc_overexposed(const cpl_image *ima, const cpl_table *tw, int order_idx)
Computes the Overexposed fraction.
Definition: cr2res_qc.c:796
int cr2res_qc_numsat(const cpl_frameset *frameset)
Calculate the number of saturated pixels.
Definition: cr2res_qc.c:1290
double cr2res_qc_flat_s2n(const cpl_table *extracted)
Computes the S2N on the flat.
Definition: cr2res_qc.c:375
double cr2res_qc_wave_resol_fwhm(const cpl_bivector *spec, double *wl)
Computes the lines Fwhm and return the smallest.
Definition: cr2res_qc.c:710
double * cr2res_qc_der_snr(const cpl_table *tw, const cpl_table *extracted, int **out_order_idx_values, int *out_nb_order_idx_values)
Computes the DER SNR of several spectra.
Definition: cr2res_qc.c:1103
double cr2res_qc_wave_lamp_effic(const cpl_bivector *spec)
Computes the lamp efficiency.
Definition: cr2res_qc.c:656
double cr2res_dark_qc_ron(const cpl_image *ima1, const cpl_image *ima2, int hsize, int nsamples, int ndit)
The Read Out Noise computation.
Definition: cr2res_qc.c:74
int cr2res_qc_detlin_stat(const hdrl_imagelist *hdrl_coeffs, double *meda, double *medb, double *medc, double *meda_err)
Computes the detlin coeffs statѕ
Definition: cr2res_qc.c:111
double cr2res_qc_obs_nodding_signal(const cpl_table *extracted)
Computes the integrated flux over part of the spectrum.
Definition: cr2res_qc.c:845
double cr2res_qc_wave_central(const cpl_table *tw, int order_idx)
Computes the central WLEN of a given order.
Definition: cr2res_qc.c:452
int cr2res_qc_flat_order_positions(const cpl_table *tw, int **order_nb, double **order_pos, int *nbvals)
Compute the central orders positions.
Definition: cr2res_qc.c:235
double cr2res_qc_wave_line_fwhm(const cpl_bivector *spec, double wl, double *peak_height)
Computes one line Fwhm.
Definition: cr2res_qc.c:546
double cr2res_qc_flat_trace_center_y(const cpl_table *trace)
Computes the mean Y coord of the central order.
Definition: cr2res_qc.c:325
double cr2res_qc_compute_der_snr(cpl_vector *spec, cpl_vector *err)
Computes the DER SNR of one spectrum.
Definition: cr2res_qc.c:1157
double cr2res_qc_wave_disp(const cpl_table *tw, int order_idx)
Computes the dispersion of a given order.
Definition: cr2res_qc.c:480
double cr2res_qc_obs_nodding_standard_flux(const cpl_table *extracted, char *setting)
Computes the standard flux over part of the spectrum.
Definition: cr2res_qc.c:892
cpl_bivector * cr2res_qc_lines_intens_bgd(const cpl_bivector *spec)
Computes the lines intensities / background.
Definition: cr2res_qc.c:612
double * cr2res_qc_snr(const cpl_table *tw, const cpl_table *extracted, int **out_order_idx_values, int *out_nb_order_idx_values)
Computes the SNR of several spectra.
Definition: cr2res_qc.c:1010
cpl_vector * cr2res_qc_lines_collect(double wmin, double wmax)
Collect lines between 2 wavelengths.
Definition: cr2res_qc.c:512
double cr2res_qc_detlin(const hdrl_imagelist *hdrl_coeffs, double bpm_thresh, cpl_mask **outmask, double *min_level, double *max_level)
Computes the detlin median non linearity.
Definition: cr2res_qc.c:156
double cr2res_qc_compute_snr(cpl_vector *spec, cpl_vector *err)
Computes the SNR of one spectrum.
Definition: cr2res_qc.c:1065
double cr2res_qc_obs_slit_psf(const cpl_table *slitfu, int order_idxp, int oversample)
Computes the FWHM of the PSF along the slit for a given order.
Definition: cr2res_qc.c:1208
cpl_vector * cr2res_trace_get_ycen(const cpl_table *trace, int order_idx, int trace_nb, int size)
Retrieves the middle (All) polynomial from trace table and evaluates.
Definition: cr2res_trace.c:769
cpl_image * cr2res_trace_gen_image(cpl_table *trace, int nx, int ny)
Make an image out of the trace solution.
Definition: cr2res_trace.c:362
double cr2res_trace_get_trace_ypos(const cpl_table *traces, int idx)
Compute the y position of the trace.
Definition: cr2res_trace.c:923
cr2res_decker cr2res_trace_slit_fraction_info(const cpl_array *slit_frac, int *up_or_down)
Get a standard slit fraction information.
int * cr2res_get_trace_numbers(const cpl_table *trace_wave, int order_idx, int *nb_traces)
Get the trace numbers for a specified order_idx.
Definition: cr2res_trace.c:517
cpl_vector * cr2res_trace_get_wl(const cpl_table *trace_wave, int order_idx, int trace_nb, int size)
Get the Wavelength vector from a TRACE_WAVE table.
Definition: cr2res_trace.c:730
int * cr2res_trace_get_order_idx_values(const cpl_table *trace, int *nb_order_idx_values)
Count and return the different order_idx values from a TW table.
Definition: cr2res_trace.c:431
cpl_error_code hdrl_image_reject_value(hdrl_image *self, cpl_value mode)
Reject pixels with the specified special value(s)
Definition: hdrl_image.c:477
cpl_error_code hdrl_image_reject_from_mask(hdrl_image *self, const cpl_mask *map)
set bpm of hdrl_image
Definition: hdrl_image.c:407
cpl_mask * hdrl_image_get_mask(hdrl_image *himg)
get cpl bad pixel mask from image
Definition: hdrl_image.c:157
cpl_error_code hdrl_image_add_scalar(hdrl_image *self, hdrl_value value)
Elementwise addition of a scalar to an image.
cpl_image * hdrl_image_get_error(hdrl_image *himg)
get error as cpl image
Definition: hdrl_image.c:131
cpl_size hdrl_image_get_size_y(const hdrl_image *self)
return size of Y dimension of image
Definition: hdrl_image.c:540
cpl_size hdrl_image_get_size_x(const hdrl_image *self)
return size of X dimension of image
Definition: hdrl_image.c:525
cpl_image * hdrl_image_get_image(hdrl_image *himg)
get data as cpl image
Definition: hdrl_image.c:105
hdrl_image * hdrl_image_new(cpl_size nx, cpl_size ny)
create new zero filled hdrl image
Definition: hdrl_image.c:311
void hdrl_image_delete(hdrl_image *himg)
delete hdrl_image
Definition: hdrl_image.c:379
hdrl_image * hdrl_imagelist_get(const hdrl_imagelist *himlist, cpl_size inum)
Get an image from a list of images.