CR2RE Pipeline Reference Manual 1.6.2
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/*----------------------------------------------------------------------------*/
1100/*----------------------------------------------------------------------------*/
1102 const cpl_table * slitfu,
1103 int order_idxp,
1104 int oversample)
1105{
1106 cpl_vector * x ;
1107 cpl_vector * y ;
1108 char * colname ;
1109 const double * data ;
1110 cpl_size i, j ;
1111 cpl_fit_mode fit_pars ;
1112 int nrow ;
1113 double qc_fwhm, x0, sigma, area, offset, extr_height;
1114
1115 /* Check Entries */
1116 if (slitfu == NULL) return -1 ;
1117
1118 /* Get the table column name */
1119 colname = cr2res_dfs_SLIT_FUNC_colname(order_idxp, 1);
1120 data = cpl_table_get_data_double_const(slitfu, colname);
1121 cpl_free(colname);
1122 if (data == NULL) {
1123 cpl_msg_warning(__func__, "No slitfunc data: code %d",
1124 cpl_error_get_code());
1125 cpl_error_reset();
1126 return -1;
1127 }
1128
1129 /* Initialise */
1130 //qc_fwhm = -1.0 ;
1131 fit_pars = CPL_FIT_CENTROID + CPL_FIT_STDEV + CPL_FIT_AREA;
1132 offset = 0.;
1133
1134 nrow = cpl_table_get_nrow(slitfu);
1135
1136 /* x is just the element number */
1137 x = cpl_vector_new(nrow);
1138 y = cpl_vector_new(nrow);
1139 for (i = 0; i < nrow; i++){
1140 cpl_vector_set(x, i, i);
1141 cpl_vector_set(y, i, 0);
1142 }
1143
1144 /* remove "strange" values, i.e. nan and unreasonably large values */
1145 /* otherwise the fit will not work */
1146 /* Slitfunc should be normalised to the oversampling rate(?) */
1147 for (j = 0; j < nrow; j++) {
1148 if (isnan(data[j]) | (data[j] > 1)){
1149 cpl_vector_set(y, j, 0);
1150 } else {
1151 cpl_vector_set(y, j, data[j]);
1152 }
1153 }
1154 cpl_vector_fit_gaussian(x, NULL, y, NULL, fit_pars, &x0, &sigma,
1155 &area, &offset, NULL, NULL, NULL);
1156 if (cpl_error_get_code()) {
1157 cpl_msg_warning(__func__, "Failed Fit for the slit PSF") ;
1158 cpl_error_reset() ;
1159 sigma = 0.0 ;
1160 }
1161 qc_fwhm = 2.355 * sigma; // 2.355 = 2 * sqrt(2 * ln(2))
1162
1163 /* Correct for oversampling */
1164 /* nrow is 1+ (extr_height+1)*oversample */
1165 /* and we want the ratio of extr_height/nrow */
1166 extr_height = (nrow-1) / oversample -1;
1167 qc_fwhm *= extr_height / nrow;
1168 cpl_msg_debug(__func__,"extr_height / nrow = %g",extr_height / nrow);
1169
1170 /* Free Memory */
1171 cpl_vector_delete(x);
1172 cpl_vector_delete(y);
1173 return qc_fwhm ;
1174}
1175
1176/*----------------------------------------------------------------------------*/
1182/*----------------------------------------------------------------------------*/
1183int cr2res_qc_numsat(const cpl_frameset * frameset)
1184{
1185 hdrl_image * hima ;
1186 cpl_image * ima ;
1187 double * pima ;
1188 int det_nr, max_nsat, nsat ;
1189 cpl_size i, k, nframes, nx, ny ;
1190
1191 /* Check Inputs */
1192 if (frameset == NULL) return -1 ;
1193
1194 /* Initialise */
1195 max_nsat = 0 ;
1196 nframes = cpl_frameset_get_size(frameset);
1197
1198 for (i = 0; i < nframes; i++) {
1199 const cpl_frame *frame;
1200 const char *fname;
1201 frame = cpl_frameset_get_position_const(frameset, i);
1202 fname = cpl_frame_get_filename(frame);
1203 for (det_nr=1 ; det_nr<=CR2RES_NB_DETECTORS ; det_nr++) {
1204 nsat = 0 ;
1205 hima = cr2res_io_load_image(fname, det_nr) ;
1206 if (hima != NULL) {
1207 ima = hdrl_image_get_image(hima) ;
1208 pima = cpl_image_get_data_double(ima) ;
1209 nx = cpl_image_get_size_x(ima) ;
1210 ny = cpl_image_get_size_y(ima) ;
1211 for (k = 0 ; k<nx*ny ; k++) {
1212 if (pima[k] > CR2RES_DETECTOR_OVEREXP_THRESH) nsat++ ;
1213 }
1214 hdrl_image_delete(hima) ;
1215 } else {
1216 cpl_msg_warning(__func__, "NUMSAT - cannot load detector") ;
1217 cpl_error_reset() ;
1218 }
1219 if (nsat > max_nsat) max_nsat = nsat ;
1220 }
1221 }
1222 return max_nsat ;
1223}
1224
1227/*----------------------------------------------------------------------------*/
1236/*----------------------------------------------------------------------------*/
1237static int cr2res_qc_wave_line_intens(
1238 const cpl_bivector * spec,
1239 double wl,
1240 double * intens,
1241 double * bgd)
1242{
1243 // TODO Thomas / Ansgar
1244 //cpl_plot_bivector("set grid;set xlabel 'Wavelength (nm)';
1245 // set ylabel 'Spec';", "t 'Spectrum' w lines", "",spec) ;
1246 const cpl_vector * wave;
1247 const cpl_vector * flux;
1248 cpl_vector * tmp;
1249 cpl_size pixel_pos;
1250 cpl_size window_size;
1251 cpl_size n_inner, n_outer;
1252 double sum_inner, sum_outer;
1253 double value;
1254
1255 /* Initialise */
1256 *intens = -1.0 ;
1257 *bgd = 0.0 ;
1258
1259 if (spec == NULL) return -1 ;
1260
1261 // TODO: How large should this window be?
1262 window_size = CR2RES_QC_WINDOW / 2;
1263
1264 wave = cpl_bivector_get_x_const(spec);
1265 flux = cpl_bivector_get_y_const(spec);
1266
1267 // Determine pixel pos
1268 // TODO: If we are sure that wave is sorted, we can also use cpl_vector_find
1269 tmp = cpl_vector_duplicate(wave);
1270 cpl_vector_subtract_scalar(tmp, wl);
1271 cpl_vector_multiply(tmp, tmp);
1272 pixel_pos = cpl_vector_get_minpos(tmp);
1273 cpl_vector_delete(tmp);
1274
1275 // If the wavelength value is outside the spectrum
1276 if (pixel_pos == 0 || pixel_pos == cpl_vector_get_size(wave)) return -1.0;
1277
1278 // Sum up the values of the spectrum
1279 // inside the window and outside the window
1280 sum_inner = 0;
1281 sum_outer = 0;
1282 n_inner = 0;
1283 n_outer = 0;
1284 for (cpl_size i = -window_size * 2; i < 2 * window_size; i++)
1285 {
1286 cpl_size k;
1287 k = pixel_pos - i;
1288 if (k < 0 || k >= cpl_vector_get_size(flux)){
1289 continue;
1290 }
1291 value = cpl_vector_get(flux, k);
1292 if (isnan(value)){
1293 continue;
1294 }
1295 if (llabs(i) < window_size){
1296 // Inner sum
1297 n_inner++;
1298 sum_inner += value;
1299 } else {
1300 // Outer sum
1301 n_outer++;
1302 sum_outer += value;
1303 }
1304 }
1305 if (n_inner + n_outer == 0){
1306 // No valid points
1307 return -1 ;
1308 }
1309 // Take the mean
1310 if (n_inner != 0) sum_inner /= n_inner;
1311 if (n_outer != 0) sum_outer /= n_outer;
1312 // return the difference
1313
1314 *intens = sum_inner ;
1315 *bgd = sum_outer ;
1316 return 0 ;
1317}
1318
1319int cr2res_qc_calculate_mean_and_rmsd(cpl_propertylist ***plists, int size, const int *sizes,
1320 const char *ref_keyword, cpl_propertylist *qc_main,
1321 const char *result_avg_keyword, const char *result_rmsd_keyword) {
1322
1323 cpl_errorstate status;
1324
1325 status = cpl_errorstate_get();
1326
1327 double sum = 0.0;
1328 double sum_sq = 0.0;
1329 int count = 0;
1330
1331 for (int i = 0; i < size; i++) {
1332 for (int j = 0; j<sizes[i]; j++){
1333 if (plists[i][j] != NULL) {
1334 double value = cpl_propertylist_get_double(plists[i][j], ref_keyword);
1335 if(!cpl_errorstate_is_equal(status)) {
1336 cpl_msg_debug(__func__, "Cannot get keyword %s : %s", ref_keyword, cpl_error_get_message());
1337 cpl_errorstate_set(status);
1338 continue;
1339 }
1340 sum += value;
1341 sum_sq += value * value;
1342 count++;
1343 }
1344 }
1345 }
1346
1347 if (count > 0) {
1348 double mean = sum / count;
1349
1350 double rmsd = 0.0;
1351
1352 if (count > 1) {
1353 rmsd = sqrt( (count*mean*mean - 2*mean*sum + sum_sq) / count);
1354 }
1355
1356 if (qc_main != NULL) {
1357 cpl_propertylist_append_double(qc_main, result_avg_keyword, mean);
1358 cpl_propertylist_append_double(qc_main, result_rmsd_keyword, rmsd);
1359 }
1360 }
1361 return 0;
1362}
1363
1364int
1365cr2res_qc_dup_mtrlgy_key(cpl_frameset *framelist, cpl_propertylist *plist)
1366{
1367
1368 /*
1369 * Get the first input frame in the input set-of-frames.
1370 * Copied from cpl_dfs_setup_product_header()
1371 */
1372
1373
1374 const cpl_frame *frame;
1375 const cpl_frame *first_frame = NULL;
1376 cpl_frameset_iterator *it = NULL;
1377 cpl_propertylist *met_plist = NULL;
1378
1379 cpl_errorstate status;
1380
1381 it = cpl_frameset_iterator_new(framelist);
1382 frame = cpl_frameset_iterator_get_const(it);
1383
1384 while (frame != NULL) {
1385
1386 if (cpl_frame_get_group(frame) == CPL_FRAME_GROUP_RAW) {
1387 first_frame = frame;
1388 break;
1389 }
1390
1391 status = cpl_errorstate_get();
1392
1393 cpl_frameset_iterator_advance(it, 1);
1394
1395 if (cpl_error_get_code() == CPL_ERROR_ACCESS_OUT_OF_RANGE) {
1396 cpl_errorstate_set(status);
1397 }
1398
1399 frame = cpl_frameset_iterator_get_const(it);
1400 }
1401
1402 if (first_frame == NULL) {
1403 cpl_frameset_iterator_reset(it);
1404 frame = cpl_frameset_iterator_get_const(it);
1405
1406 while (frame != NULL) {
1407
1408 if (cpl_frame_get_group(frame) == CPL_FRAME_GROUP_CALIB) {
1409 first_frame = frame;
1410 break;
1411 }
1412
1413 status = cpl_errorstate_get();
1414
1415 cpl_frameset_iterator_advance(it, 1);
1416
1417 if (cpl_error_get_code() == CPL_ERROR_ACCESS_OUT_OF_RANGE) {
1418 cpl_errorstate_set(status);
1419 }
1420
1421 frame = cpl_frameset_iterator_get_const(it);
1422 }
1423 }
1424
1425 cpl_frameset_iterator_delete(it);
1426 it = NULL;
1427
1428 if (first_frame == NULL) {
1429 cpl_msg_debug(__func__, "No suitable frame found for QC MTRLGY ID in sof.");
1430 return 0;
1431 }
1432
1433
1434 status = cpl_errorstate_get();
1435
1436 met_plist =
1437 cpl_propertylist_load_regexp(cpl_frame_get_filename(first_frame), 0,
1438 CR2RES_HEADER_OCS_MTRLGY, 0);
1439 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1440 cpl_msg_debug(__func__, "Cannot read header for QC MTRLGY ID : %s", cpl_error_get_message());
1441 cpl_errorstate_set(status);
1442 return 0;
1443 }
1444
1445 if (plist != NULL) {
1446 int mtrlgy_st;
1447 mtrlgy_st =
1448 cpl_propertylist_get_bool(met_plist, CR2RES_HEADER_OCS_MTRLGY);
1449 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1450 cpl_msg_debug(__func__, "Cannot get keyword %s : %s",
1451 CR2RES_HEADER_OCS_MTRLGY, cpl_error_get_message());
1452 cpl_errorstate_set(status);
1453 }
1454 else {
1455 if (mtrlgy_st == 0) {
1456 cpl_propertylist_prepend_int(plist, CR2RES_HEADER_QC_MTRLGY_ID,
1457 0);
1458 }
1459 else {
1460 cpl_propertylist_prepend_int(plist, CR2RES_HEADER_QC_MTRLGY_ID,
1461 1);
1462 }
1463 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1464 cpl_msg_debug(__func__, "Cannot write keyword %s : %s",
1465 CR2RES_HEADER_QC_MTRLGY_ID,
1466 cpl_error_get_message());
1467 cpl_errorstate_set(status);
1468 }
1469 }
1470 }
1471
1472 if (met_plist != NULL){
1473 cpl_propertylist_delete(met_plist);
1474 }
1475
1476 return 0;
1477}
1478
1479
1480int
1481cr2res_qc_dup_chip_idx(cpl_propertylist *plist)
1482{
1483
1484 cpl_errorstate status;
1485
1486 status = cpl_errorstate_get();
1487
1488 if (plist != NULL) {
1489 int chip_idx;
1490 char id[6];
1491 chip_idx = cpl_propertylist_get_int(plist, CR2RES_HEADER_CHIP_IDX);
1492 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1493 cpl_msg_debug(__func__, "Cannot get keyword %s : %s",
1494 CR2RES_HEADER_OCS_MTRLGY, cpl_error_get_message());
1495 cpl_errorstate_set(status);
1496 }
1497 else {
1498 if (chip_idx >= 1 && chip_idx <= 3) {
1499 sprintf(id, "CHIP%d", chip_idx);
1500 cpl_propertylist_append_string(plist, CR2RES_HEADER_QC_DET_ID,
1501 id);
1502 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1503 cpl_msg_debug(__func__, "Cannot write keyword %s : %s",
1504 CR2RES_HEADER_QC_DET_ID,
1505 cpl_error_get_message());
1506 cpl_errorstate_set(status);
1507 }
1508 }
1509 else {
1510 cpl_msg_debug(__func__,
1511 "CHIP INDEX not recognized for QC DET ID: %d",
1512 chip_idx);
1513 }
1514 }
1515 }
1516
1517 return 0;
1518}
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:1183
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_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_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:1101
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.