CR2RE Pipeline Reference Manual 1.6.7
cr2res_utils.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#include <time.h>
31
32#include <cpl.h>
33
34#include "irplib_wcs.h"
35
36#include "cr2res_utils.h"
37#include "cr2res_io.h"
38#include "cr2res_pfits.h"
39#include "cr2res_dfs.h"
40#include "cr2res_extract.h"
41#include "cr2res_trace.h"
42
43
44/*----------------------------------------------------------------------------*/
48/*----------------------------------------------------------------------------*/
49#define max(a,b) (((a)>(b))?(a):(b))
52/*----------------------------------------------------------------------------*/
57/*----------------------------------------------------------------------------*/
59{
60 double mjd_obs ;
61 int hours, minutes, seconds, day, month, year;
62 time_t now;
63
64 /* Get the time for MJD-OBS */
65 time(&now);
66 struct tm *local = localtime(&now);
67 hours = local->tm_hour; // get hours since midnight (0-23)
68 minutes = local->tm_min; // get minutes passed after the hour (0-59)
69 seconds = local->tm_sec; // get seconds passed after minute (0-59)
70 day = local->tm_mday; // get day of month (1 to 31)
71 month = local->tm_mon + 1; // get month of year (0 to 11)
72 year = local->tm_year + 1900; // get year since 1900
73 /* printf("%d %d %d %d %d %d\n", hours, minutes, seconds, day,
74 * month, year) ; */
75 irplib_wcs_mjd_from_iso8601(&mjd_obs, year, month, day, hours,
76 minutes, seconds) ;
77
78 return mjd_obs ;
79}
80
81/*----------------------------------------------------------------------------*/
88/*----------------------------------------------------------------------------*/
89int cr2res_order_idx_to_real(int order_idx, int order_zp)
90{
91 return order_zp + order_idx - 1;
92}
93
94/*----------------------------------------------------------------------------*/
101/*----------------------------------------------------------------------------*/
102int cr2res_order_real_to_idx(int order_real, int order_zp)
103{
104 return order_real - order_zp + 1;
105}
106
107/*----------------------------------------------------------------------------*/
120/*----------------------------------------------------------------------------*/
121double cr2res_ra_hms2deg(int hh, int mm, double ss)
122{
123 return 15.0 * cr2res_dec_hms2deg(hh, mm, ss);
124}
125
126/*----------------------------------------------------------------------------*/
138/*----------------------------------------------------------------------------*/
139double cr2res_dec_hms2deg(int dd, int mm, double ss)
140{
141 return ((double)ss/60.0 + (double)mm)/60.0 + dd;
142}
143
144/*----------------------------------------------------------------------------*/
151/*----------------------------------------------------------------------------*/
152int cr2res_format_setting(char * setting_id)
153{
154 int i, len ;
155
156 /* Check entries */
157 if (setting_id == NULL) return -1 ;
158
159 len = strlen(setting_id) ;
160 for (i=0 ; i<len ; i++) if (setting_id[i] == '/') setting_id[i] = '_' ;
161 return 0;
162}
163
164/*----------------------------------------------------------------------------*/
170/*----------------------------------------------------------------------------*/
171int cr2res_is_short_wavelength(const char * setting_id)
172{
173 /* Check entries */
174 if (setting_id == NULL) return -1 ;
175
176 if (setting_id[0] == 'H' || setting_id[0] == 'J' ||
177 setting_id[0] == 'K' || setting_id[0] == 'Y')
178 return 1;
179 return 0 ;
180}
181
182/*----------------------------------------------------------------------------*/
189/*----------------------------------------------------------------------------*/
190int cr2res_format_setting2(char * setting_id)
191{
192 int i, len ;
193
194 /* Check entries */
195 if (setting_id == NULL) return -1 ;
196
197 len = strlen(setting_id) ;
198 for (i=0 ; i<len ; i++) if (setting_id[i] == '_') setting_id[i] = '/' ;
199 return 0;
200}
201
202/*----------------------------------------------------------------------------*/
211/*----------------------------------------------------------------------------*/
212double cr2res_vector_get_mad(cpl_vector * invec, double *mad)
213{
214 cpl_image * img;
215 double median;
216 img = cpl_image_wrap_double(1,cpl_vector_get_size(invec),
217 cpl_vector_get_data(invec));
218 median = cpl_image_get_mad(img, mad);
219 cpl_image_unwrap(img);
220 return median;
221}
222
223/*----------------------------------------------------------------------------*/
229/*----------------------------------------------------------------------------*/
231 const cpl_vector * ycen)
232{
233 int * ycen_int;
234 int i, lenx;
235
236 if (ycen == NULL) return NULL;
237
238 lenx = cpl_vector_get_size(ycen);
239 ycen_int = cpl_malloc(lenx*sizeof(int));
240 for (i=0 ; i<lenx ; i++){
241 ycen_int[i] = (int)cpl_vector_get(ycen,i);
242 }
243 return ycen_int;
244}
245
246/*----------------------------------------------------------------------------*/
252/*----------------------------------------------------------------------------*/
254 const cpl_vector * ycen)
255{
256 double * ycen_rest;
257 int i, lenx ;
258
259 if (ycen == NULL) return NULL;
260
261 lenx = cpl_vector_get_size(ycen);
262 ycen_rest = cpl_malloc(lenx*sizeof(double));
263 for (i=0 ; i<lenx ; i++){
264 ycen_rest[i] = fmod( cpl_vector_get(ycen,i), 1.0) ;
265 }
266 return ycen_rest;
267}
268
269
270/*----------------------------------------------------------------------------*/
277/*----------------------------------------------------------------------------*/
279 const cpl_table * extracta,
280 const cpl_table * extractb)
281{
282 cpl_table * extractc ;
283 cpl_array * col_names ;
284 char * err_col ;
285 char * wave_col ;
286 hdrl_spectrum1D_wave_scale scale ;
287 hdrl_spectrum1D * a_spec ;
288 hdrl_spectrum1D * b_spec ;
289 hdrl_spectrum1D * c_spec ;
290 hdrl_spectrum1D_wavelength spec_wav ;
291 hdrl_parameter * params ;
292 double * p_flux ;
293 double * p_err ;
294 cpl_size ncols, i, j, sz, sz_a, sz_b ;
295 int trace_nb, order, increasing_values ;
296
297 /* Check Inputs */
298 if (extracta == NULL || extractb == NULL) return NULL ;
299
300 /* Initialise */
301 scale = hdrl_spectrum1D_wave_scale_linear;
302 extractc = cpl_table_duplicate(extracta) ;
303
304 /* Get the column names */
305 col_names = cpl_table_get_column_names(extractc);
306 ncols = cpl_table_get_ncol(extractc) ;
307
308 /* Loop on the columns */
309 for (i=0 ; i<ncols ; i++) {
310
311 const char * col_name ;
312 char * col_type ;
313 col_name = cpl_array_get_string(col_names, i);
314 col_type = cr2res_dfs_SPEC_colname_parse(col_name, &order,
315 &trace_nb) ;
316 if (col_type != NULL && !strcmp(col_type, CR2RES_COL_SPEC_SUFFIX)) {
317 /* This is a SPEC column, let's interpolate */
318
319 /* Get the wavelength column name */
320 wave_col = cr2res_dfs_WAVELENGTH_colname(order,trace_nb) ;
321 err_col = cr2res_dfs_SPEC_ERR_colname(order,trace_nb) ;
322
323 /* Get the A spectrum */
324 a_spec = hdrl_spectrum1D_convert_from_table(extracta,
325 col_name, wave_col, err_col, NULL, scale);
326
327 /* Get the B spectrum */
328 b_spec = hdrl_spectrum1D_convert_from_table(extractb,
329 col_name, wave_col, err_col, NULL, scale);
330
331 /* Check */
332 if (a_spec == NULL || b_spec == NULL) {
333 cpl_msg_error(__func__, "Cannot create HDRL spectra - abort") ;
334 cpl_free(wave_col) ;
335 cpl_free(err_col);
336 cpl_free(col_type) ;
337 cpl_array_delete(col_names) ;
338 cpl_table_delete(extractc) ;
339 return NULL ;
340 }
341 sz_a = hdrl_spectrum1D_get_size(a_spec) ;
342 sz_b = hdrl_spectrum1D_get_size(b_spec) ;
343 /* Check */
344 if (sz_a != sz_b) {
345 cpl_msg_error(__func__,
346 "a and b spectra have diff. sizes - abort") ;
347 hdrl_spectrum1D_delete(&a_spec);
348 hdrl_spectrum1D_delete(&b_spec);
349 cpl_free(wave_col) ;
350 cpl_free(err_col);
351 cpl_free(col_type) ;
352 cpl_array_delete(col_names) ;
353 cpl_table_delete(extractc) ;
354 return NULL ;
355 }
356
357 /* Check if the Wavelengths are increasing */
358 increasing_values = 1 ;
359 for (j=1 ; j<sz_a ; j++) {
360 hdrl_data_t vala1 =
361 hdrl_spectrum1D_get_wavelength_value(a_spec, j-1, NULL) ;
362 hdrl_data_t vala2 =
363 hdrl_spectrum1D_get_wavelength_value(a_spec, j, NULL) ;
364 hdrl_data_t valb1 =
365 hdrl_spectrum1D_get_wavelength_value(b_spec, j-1, NULL) ;
366 hdrl_data_t valb2 =
367 hdrl_spectrum1D_get_wavelength_value(b_spec, j, NULL) ;
368 if (vala1 >= vala2 || valb1 >=valb2) {
369 increasing_values = 0 ;
370 break ;
371 }
372 }
373 if (increasing_values == 0) {
374 cpl_msg_warning(__func__,
375 "Column %s - Values should increase - abort",
376 wave_col) ;
377 hdrl_spectrum1D_delete(&a_spec);
378 hdrl_spectrum1D_delete(&b_spec);
379 cpl_free(wave_col) ;
380 cpl_free(err_col);
381 if (col_type != NULL) cpl_free(col_type) ;
382 /* Set the column to 0 */
383 p_flux = cpl_table_get_data_double(extractc, col_name) ;
384 sz = cpl_table_get_nrow(extractc) ;
385 for (j = 0; j < sz; j++) p_flux[j]= 0.0;
386 continue ;
387 }
388
389 /* Resample B on A wavelengths */
390 spec_wav = hdrl_spectrum1D_get_wavelength(a_spec);
392 hdrl_spectrum1D_interp_akima);
393 c_spec = hdrl_spectrum1D_resample(b_spec, &spec_wav, params);
394 hdrl_parameter_delete(params);
395 hdrl_spectrum1D_delete(&b_spec);
396
397 /* Check */
398 if (c_spec == NULL) {
399 cpl_msg_error(__func__,"Cannot resample HDRL spectra - abort") ;
400 cpl_free(wave_col) ;
401 cpl_free(err_col);
402 if (col_type != NULL) cpl_free(col_type) ;
403 cpl_array_delete(col_names) ;
404 hdrl_spectrum1D_delete(&a_spec);
405 cpl_table_delete(extractc) ;
406 return NULL ;
407 }
408
409 /* Sum up */
410 hdrl_spectrum1D_add_spectrum(c_spec, a_spec) ;
411 hdrl_spectrum1D_delete(&a_spec);
412
413 /* Update the table with the result */
414 // construct the name of the error column based on the spec column
415 p_flux = cpl_table_get_data_double(extractc, col_name) ;
416 if ((p_err = cpl_table_get_data_double(extractc, err_col))
417 == NULL) {
418 // Add the column if it doesn't exists
419 cpl_error_reset();
420 cpl_table_new_column(extractc, err_col, CPL_TYPE_DOUBLE);
421 p_err = cpl_table_get_data_double(extractc, err_col) ;
422 }
423 sz = cpl_table_get_nrow(extractc) ;
424 if (sz != hdrl_spectrum1D_get_size(c_spec)) {
425 cpl_msg_error(__func__, "Wrong size - abort") ;
426 hdrl_spectrum1D_delete(&c_spec);
427 cpl_free(wave_col) ;
428 cpl_free(err_col);
429 if (col_type != NULL) cpl_free(col_type) ;
430 cpl_array_delete(col_names) ;
431 cpl_table_delete(extractc) ;
432 return NULL ;
433 }
434 for (j = 0; j < sz; j++) {
435 p_flux[j] = hdrl_spectrum1D_get_flux_value(c_spec, j, NULL).data;
436 p_err[j] = hdrl_spectrum1D_get_flux_value(c_spec, j, NULL).error;
437 }
438 hdrl_spectrum1D_delete(&c_spec);
439 cpl_free(wave_col) ;
440 cpl_free(err_col);
441 }
442 if (col_type != NULL) cpl_free(col_type) ;
443 }
444 cpl_array_delete(col_names) ;
445
446 return extractc ;
447}
448
449
450/*----------------------------------------------------------------------------*/
460/*----------------------------------------------------------------------------*/
461cpl_polynomial * cr2res_fit_interorder(
462 cpl_image * img,
463 cpl_table * trace_wave,
464 cpl_size order_x,
465 cpl_size order_y)
466{
467
468 if (img == NULL || trace_wave == NULL) return NULL;
469 if (order_x < 0 || order_y < 0) return NULL;
470
471 //Step 1: identify areas inbetween traces
472
473 cpl_size order_idx;
474 cpl_size trace1 = 1;
475 cpl_size trace2 = 2; // if decker, set to 2, otherwise 1
476
477 const cpl_array *lower;
478 const cpl_array *upper;
479 cpl_size power = 0;
480 cpl_polynomial *poly_lower = NULL; //lower border of image
481 cpl_polynomial *poly_upper = NULL;
482
483 int nb_order_idx_values;
484 int * order_idx_values = cr2res_trace_get_order_idx_values(trace_wave,
485 &nb_order_idx_values);
486 int * porder_idx_values;
487 int * ptraces;
488
489 double y_lower, y_upper;
490 int c = 0; //counter for number of data points
491
492 cpl_matrix *samppos = cpl_matrix_new(2, cpl_image_get_size_x(img) *
493 cpl_image_get_size_y(img));
494 cpl_vector *fitvals = cpl_vector_new(cpl_image_get_size_x(img) *
495 cpl_image_get_size_y(img));
496 cpl_vector *x = cpl_vector_new(1);
497
498 double value;
499 int pis_rejected = 0;
500
501 // get array for order
502 // find location of order and trace
503 int nrows = cpl_table_get_nrow(trace_wave);
504 int k;
505 porder_idx_values = cpl_table_get_data_int(trace_wave, CR2RES_COL_ORDER);
506 ptraces = cpl_table_get_data_int(trace_wave, CR2RES_COL_TRACENB);
507
508 for(int m = 0; m <= nb_order_idx_values; m++) {
509 // the last time is above the topmost border
510 if (m != nb_order_idx_values) order_idx = order_idx_values[m];
511 else {
512 // find maximum order
513 order_idx = order_idx_values[0];
514 for(int t = 1; t < nb_order_idx_values; t++) {
515 if (order_idx_values[t] > order_idx)
516 order_idx = order_idx_values[t];
517 }
518 order_idx ++ ;
519 }
520
521 // lower = upper boundary of order_idx-1, or 0 if order_idx-1 = 0
522 // upper = lower boundary of order_idx, or max_img of order_idx = max
523 for (k=0 ; k<nrows ; k++) {
524 /* If order found */
525 if (porder_idx_values[k] == order_idx-1 && ptraces[k] == trace2) {
526 /* Get the polynomial*/
527 lower = cpl_table_get_array(trace_wave, CR2RES_COL_UPPER, k);
528 poly_lower = cr2res_convert_array_to_poly(lower);
529 break;
530 }
531 }
532 for (k=0 ; k<nrows ; k++) {
533 if (porder_idx_values[k] == order_idx && ptraces[k] == trace1) {
534 /* Get the polynomial*/
535 upper = cpl_table_get_array(trace_wave,CR2RES_COL_LOWER, k);
536 poly_upper = cr2res_convert_array_to_poly(upper);
537 break;
538 }
539 }
540
541 // if no order found use bottom of image
542 if (poly_lower == NULL) {
543 poly_lower = cpl_polynomial_new(1);
544 cpl_polynomial_set_coeff(poly_lower, &power, 1);
545 }
546 // if no order found, use top of image
547 if (poly_upper == NULL) {
548 poly_upper = cpl_polynomial_new(1);
549 cpl_polynomial_set_coeff(poly_upper, &power,
550 cpl_image_get_size_y(img));
551 }
552
553 // loop over image and set data points outside of traces
554
555 for(cpl_size i = 1; i < cpl_image_get_size_x(img)-1; i++) {
556 cpl_vector_set(x, 0, (double)i);
557 y_lower = cpl_polynomial_eval(poly_lower, x);
558 y_upper = cpl_polynomial_eval(poly_upper, x);
559
560 for(cpl_size j = y_lower; j < y_upper; j++) {
561 value = cpl_image_get(img, i, j, &pis_rejected);
562 if (pis_rejected == 0){
563 cpl_matrix_set(samppos, 0, c, (double)i);
564 cpl_matrix_set(samppos, 1, c, (double)j);
565
566 cpl_vector_set(fitvals, c, value);
567 c++;
568 }
569 }
570 }
571 cpl_polynomial_delete(poly_lower);
572 poly_lower = NULL;
573 cpl_polynomial_delete(poly_upper);
574 poly_upper = NULL;
575 }
576
577 // readjust size, to number of data points
578 cpl_matrix_set_size(samppos, 2, c);
579 cpl_vector_set_size(fitvals, c);
580
581 //Step 2: fit 2d polynomial
582 // 2d result polynomial
583 cpl_polynomial *fit = cpl_polynomial_new(2);
584 //Matrix of p sample positions, with d rows and p columns
585 //const cpl_matrix *samppos = mat;
586 //NULL, or d booleans, true iff the sampling is symmetric
587 const cpl_boolean *sampsym = NULL;
588 //cpl_vector *fitvals = vec; //Vector of the p values to fit
589 //Uncertainties of the sampled values, or NULL for all ones
590 const cpl_vector *fitsigm = NULL;
591 //True iff there is a fitting degree per dimension
592 const cpl_boolean dimdeg = TRUE;
593 //Pointer to 1 or d minimum fitting degree(s), or NULL
594 const cpl_size * mindeg = NULL;
595 //Pointer to 1 or d maximum fitting degree(s), at least mindeg
596 const cpl_size maxdeg[] = {order_x, order_y};
597
598 cpl_error_code ec = cpl_polynomial_fit(fit, samppos, sampsym, fitvals,
599 fitsigm, dimdeg, mindeg, maxdeg);
600
601 cpl_free(order_idx_values);
602 cpl_matrix_delete(samppos);
603 cpl_vector_delete(fitvals);
604 cpl_vector_delete(x);
605 if (ec == CPL_ERROR_NONE) return fit;
606 else {
607 cpl_free(fit);
608 return NULL;
609 }
610}
611
612/*----------------------------------------------------------------------------*/
626/*----------------------------------------------------------------------------*/
628 const cpl_table * trace_wave,
629 cpl_polynomial *** coef_slit,
630 cpl_polynomial *** coef_wave,
631 int * size)
632{
633
634 if (trace_wave == NULL || coef_slit == NULL ||
635 coef_wave == NULL || size == NULL) return -1;
636
637 cpl_vector * x;
638 cpl_polynomial * wave;
639 cpl_polynomial * line[3];
640 const cpl_array * slit;
641 const cpl_array * curv_b;
642 const cpl_array * curv_c;
643 cpl_polynomial * curv_poly_b;
644 cpl_polynomial * curv_poly_c;
645 int * order_idx_values;
646 int * traces;
647 const cpl_size maxdeg = 2;
648 int i, j, k, n, m;
649 int trace;
650 double px, py, pw, ps;
651 double pcb, pcc, pc_offset;
652 int nb_order_idx_values, nb_traces;
653 cpl_error_code errcode;
654 double ycen;
655
656 // pixels x, only one because thats the same for all traces
657 x = cpl_vector_new(CR2RES_DETECTOR_SIZE);
658 for (i = 0; i < CR2RES_DETECTOR_SIZE; i++)
659 cpl_vector_set(x, i, i+1);
660
661 order_idx_values = cr2res_trace_get_order_idx_values(trace_wave,
662 &nb_order_idx_values);
663
664 // Initialize the new polynomials
665 *coef_wave = cpl_malloc(nb_order_idx_values * sizeof(cpl_polynomial*));
666 *coef_slit = cpl_malloc(nb_order_idx_values * sizeof(cpl_polynomial*));
667 for (i=0; i < nb_order_idx_values; i++) {
668 (*coef_wave)[i] = cpl_polynomial_new(2);
669 (*coef_slit)[i] = cpl_polynomial_new(2);
670 }
671 *size = nb_order_idx_values;
672
673 for (i = 0; i < nb_order_idx_values; i++) {
674 cpl_matrix *matrix_xy;
675 cpl_matrix *matrix_wd;
676 cpl_vector *vec_w;
677 cpl_vector *vec_s;
678 cpl_polynomial *poly;
679
680 int row;
681 int order_idx;
682 order_idx = order_idx_values[i];
683 // For each trace of this order
684 traces = cr2res_get_trace_numbers(trace_wave, order_idx, &nb_traces);
685
686 row = -1;
687 matrix_xy = cpl_matrix_new(2, CR2RES_DETECTOR_SIZE * nb_traces * 3);
688 matrix_wd = cpl_matrix_new(2, CR2RES_DETECTOR_SIZE * nb_traces * 3);
689 vec_w = cpl_vector_new(CR2RES_DETECTOR_SIZE * nb_traces * 3);
690 vec_s = cpl_vector_new(CR2RES_DETECTOR_SIZE * nb_traces * 3);
691
692 for (j = 0; j < nb_traces; j++) {
693 trace = traces[j];
694 k = cr2res_get_trace_table_index(trace_wave, order_idx, trace);
695 line[0] = cr2res_get_trace_wave_poly(trace_wave, CR2RES_COL_LOWER,
696 order_idx, trace);
697 line[1] = cr2res_get_trace_wave_poly(trace_wave, CR2RES_COL_ALL,
698 order_idx, trace);
699 line[2] = cr2res_get_trace_wave_poly(trace_wave, CR2RES_COL_UPPER,
700 order_idx, trace);
701
702 wave = cr2res_get_trace_wave_poly(trace_wave, CR2RES_COL_WAVELENGTH,
703 order_idx, trace);
704 slit = cpl_table_get_array(trace_wave, CR2RES_COL_SLIT_FRACTION, k);
705
706 curv_b = cpl_table_get_array(trace_wave, CR2RES_COL_SLIT_CURV_B, k);
707 curv_c = cpl_table_get_array(trace_wave, CR2RES_COL_SLIT_CURV_C, k);
708
709 curv_poly_b = cr2res_convert_array_to_poly(curv_b);
710 curv_poly_c = cr2res_convert_array_to_poly(curv_c);
711
712 // calculate polynomials for all traces
713 for (n = 0; n < CR2RES_DETECTOR_SIZE; n++) {
714 // For each of the three edges (upper, all, lower) of a trace
715 for (m = 0; m < 3; m++){
716 row++;
717 px = cpl_vector_get(x, n);
718 py = cpl_polynomial_eval_1d(line[m], px, NULL);
719
720 // Calculate the curvature offset at this point
721 pcb = cpl_polynomial_eval_1d(curv_poly_b, px, NULL);
722 pcc = cpl_polynomial_eval_1d(curv_poly_c, px, NULL);
723 // Shift the polynomial to the local reference frame
724 ycen = cpl_polynomial_eval_1d(line[1], px, NULL);
725 pcb += 2 * ycen * pcc;
726 pc_offset = (pcc*(py - ycen) + pcb) * (py - ycen);
727 cpl_msg_debug(__func__, "pc_offset: %g %g %g %g %g",
728 pc_offset, pcb, pcc, ycen, py);
729 pw = cpl_polynomial_eval_1d(wave, px - pc_offset, NULL);
730 ps = cpl_array_get_double(slit, m, NULL);
731
732 cpl_matrix_set(matrix_xy, 0, row, px);
733 cpl_matrix_set(matrix_xy, 1, row, py);
734 cpl_matrix_set(matrix_wd, 0, row, pw);
735 cpl_matrix_set(matrix_wd, 1, row, py);
736 cpl_vector_set(vec_w, row, pw);
737 cpl_vector_set(vec_s, row, ps);
738 }
739 }
740
741 cpl_polynomial_delete(line[0]);
742 cpl_polynomial_delete(line[1]);
743 cpl_polynomial_delete(line[2]);
744 cpl_polynomial_delete(curv_poly_b);
745 cpl_polynomial_delete(curv_poly_c);
746 cpl_polynomial_delete(wave);
747 }
748
749 // fit 2D wavelengths
750 poly = (*coef_wave)[i];
751 errcode = cpl_polynomial_fit(poly, matrix_xy, NULL, vec_w,
752 NULL, FALSE, NULL, &maxdeg);
753 if (errcode != CPL_ERROR_NONE){
754 cpl_msg_error(__func__, "Polynomial fit failed with error: %s", cpl_error_get_message());
755 cpl_error_reset();
756 for (i=0; i < nb_order_idx_values; i++) {
757 cpl_polynomial_delete((*coef_wave)[i]);
758 cpl_polynomial_delete((*coef_slit)[i]);
759 }
760 cpl_free(*coef_wave);
761 cpl_free(*coef_slit);
762 cpl_matrix_delete(matrix_xy);
763 cpl_matrix_delete(matrix_wd);
764 cpl_vector_delete(vec_s);
765 cpl_vector_delete(vec_w);
766 cpl_free(traces);
767 cpl_vector_delete(x);
768 cpl_free(order_idx_values);
769 *coef_wave = NULL;
770 *coef_slit = NULL;
771 *size = 0;
772 return -1;
773 }
774
775 poly = (*coef_slit)[i];
776 errcode = cpl_polynomial_fit(poly, matrix_wd, NULL, vec_s,
777 NULL, FALSE, NULL, &maxdeg);
778 if (errcode != CPL_ERROR_NONE){
779 cpl_msg_error(__func__, "Polynomial fit failed with error: %s", cpl_error_get_message());
780 cpl_error_reset();
781 for (i=0; i < nb_order_idx_values; i++) {
782 cpl_polynomial_delete((*coef_wave)[i]);
783 cpl_polynomial_delete((*coef_slit)[i]);
784 }
785 cpl_free(*coef_wave);
786 cpl_free(*coef_slit);
787 cpl_matrix_delete(matrix_xy);
788 cpl_matrix_delete(matrix_wd);
789 cpl_vector_delete(vec_s);
790 cpl_vector_delete(vec_w);
791 cpl_free(traces);
792 cpl_vector_delete(x);
793 cpl_free(order_idx_values);
794 *coef_wave = NULL;
795 *coef_slit = NULL;
796 *size = 0;
797 return -1;
798 }
799 cpl_matrix_delete(matrix_xy);
800 cpl_matrix_delete(matrix_wd);
801 cpl_vector_delete(vec_s);
802 cpl_vector_delete(vec_w);
803 cpl_free(traces);
804 }
805
806 // delete cpl pointers
807 cpl_vector_delete(x);
808 cpl_free(order_idx_values);
809
810 // Just check if anything went wrong in general
811 if (cpl_error_get_code() != CPL_ERROR_NONE){
812 for (i=0; i < nb_order_idx_values; i++) {
813 cpl_polynomial_delete((*coef_wave)[i]);
814 cpl_polynomial_delete((*coef_slit)[i]);
815 }
816 cpl_free(*coef_wave);
817 cpl_free(*coef_slit);
818 *coef_wave = NULL;
819 *coef_slit = NULL;
820 *size = 0;
821 cpl_msg_error(__func__, "ERROR: %s", cpl_error_get_message());
822 cpl_error_reset();
823 return -1;
824 }
825
826 return 0;
827}
828
829/*----------------------------------------------------------------------------*/
840/*----------------------------------------------------------------------------*/
842 const cpl_table * trace_wave,
843 cpl_image ** slitpos,
844 cpl_image ** wavelength)
845{
846 if (trace_wave == NULL || slitpos == NULL || wavelength == NULL) return -1;
847
848 double w, s;
849 int i, k, x, y, nb_order_idx_values;
850 cpl_vector * vec_xy;
851 cpl_vector * vec_wd;
852 cpl_polynomial ** coef_slit;
853 cpl_polynomial ** coef_wave;
854
855 if (cr2res_slit_pos(trace_wave, &coef_slit, &coef_wave, &nb_order_idx_values)){
856 return -1;
857 }
858
859 // Create outut images
860 *slitpos = cpl_image_new(CR2RES_DETECTOR_SIZE, CR2RES_DETECTOR_SIZE,
861 CPL_TYPE_DOUBLE);
862 *wavelength = cpl_image_new(CR2RES_DETECTOR_SIZE, CR2RES_DETECTOR_SIZE,
863 CPL_TYPE_DOUBLE);
864
865 vec_xy = cpl_vector_new(2);
866 vec_wd = cpl_vector_new(2);
867
868 for (k = 0; k < nb_order_idx_values; k++) {
869 for (x=1; x <= CR2RES_DETECTOR_SIZE; x++) {
870 for (y=1; y <= CR2RES_DETECTOR_SIZE; y++) {
871 cpl_vector_set(vec_xy, 0, (double)x);
872 cpl_vector_set(vec_xy, 1, (double)y);
873 w = cpl_polynomial_eval(coef_wave[k], vec_xy);
874
875 cpl_vector_set(vec_wd, 0, w);
876 cpl_vector_set(vec_wd, 1, (double)y);
877 s = cpl_polynomial_eval(coef_slit[k], vec_wd);
878
879 if ((s >= 0) && (s <= 1)) {
880 cpl_image_set(*slitpos, x, y, s);
881 cpl_image_set(*wavelength, x, y, w);
882 }
883 }
884 }
885 }
886
887 for (i=0; i < nb_order_idx_values; i++){
888 cpl_polynomial_delete(coef_wave[i]);
889 cpl_polynomial_delete(coef_slit[i]);
890 }
891 cpl_free(coef_slit);
892 cpl_free(coef_wave);
893 cpl_vector_delete(vec_wd);
894 cpl_vector_delete(vec_xy);
895 return 0;
896}
897
898/*----------------------------------------------------------------------------*/
906/*----------------------------------------------------------------------------*/
908 const cpl_image * img_in,
909 const cpl_vector * ycen,
910 int height)
911{
912 cpl_image * img_out;
913 cpl_image * img_1d;
914 cpl_type imtyp;
915 cpl_size lenx, leny;
916 int * ycen_int;
917 int i, j;
918 int empty_bottom = 0;
919
920 if (img_in == NULL || ycen == NULL || height < 1) return NULL;
921
922 imtyp = cpl_image_get_type(img_in);
923 lenx = cpl_image_get_size_x(img_in);
924 leny = cpl_image_get_size_y(img_in);
925 ycen_int = cr2res_vector_get_int(ycen);
926 img_out = cpl_image_new(lenx, height, imtyp);
927
928 /* Loop over columns, cut out around ycen, insert into img_out*/
929 for (i = 1; i <= lenx; i++) { // All image indx start at 1!
930
931 int ymin, ymax;
932 /* treat edge cases, summing over shorter column where needed*/
933 ymin = ycen_int[i-1]-(height/2);
934 ymax = ycen_int[i-1]+(height/2) + height%2 ;
935 if ((ymax <= 1) || (ymin > leny)) {
936 // Trace is completely out of bounds, skip this column
937 // set it to 0 and mark as bad pixels
938 for (j = 1; j <= height; j++){
939 cpl_image_set(img_out, i, j, NAN);
940 cpl_image_reject(img_out, i, j);
941 }
942 continue;
943 }
944 if (ymin < 1) {
945 empty_bottom = 1 - ymin; // save for later insertion
946 ymin = 1;
947 }
948 if (ymax > leny)
949 ymax = leny; // Simply stop when we reach the top.
950 if (ymax <= ymin) {
951 cpl_msg_error(__func__,"Unreasonable borders in column %i",i);
952 cpl_free(ycen_int);
953 cpl_image_delete(img_out);
954 return NULL;
955 }
956
957 /* Cut out and insert */
958 img_1d = cpl_image_extract(img_in, i, ymin, i, ymax);
959 cpl_image_copy(img_out, img_1d, i, 1+empty_bottom);
960 if (cpl_error_get_code() != CPL_ERROR_NONE) {
961 cpl_msg_error(__func__,
962 "Cannot extract and copy column %d, %d %d %d, %s",
963 i, ymin, ymax, empty_bottom, cpl_error_get_where());
964 cpl_free(ycen_int);
965 cpl_image_delete(img_out);
966 if (img_1d != NULL) cpl_image_delete(img_1d);
967 cpl_error_reset();
968 return NULL;
969 }
970 cpl_image_delete(img_1d);
971 }
972 cpl_free(ycen_int);
973 return img_out;
974}
975
976/*----------------------------------------------------------------------------*/
983/*----------------------------------------------------------------------------*/
985 const cpl_image * rect_in,
986 const cpl_vector * ycen,
987 cpl_image * img_out)
988{
989 cpl_image * img_1d;
990 cpl_size lenx, leny, height;
991 int * ycen_int;
992 int i, j;
993
994 if (rect_in == NULL || ycen == NULL || img_out == NULL) return -1;
995
996 lenx = cpl_image_get_size_x(img_out);
997 leny = cpl_image_get_size_y(img_out);
998 height = cpl_image_get_size_y(rect_in);
999 if (cpl_image_get_size_x(rect_in) != lenx) {
1000 cpl_msg_error(__func__, "Length of rect and img need to be the same");
1001 return -1;
1002 }
1003
1004 ycen_int = cr2res_vector_get_int(ycen);
1005
1006 for (i=1;i<=lenx;i++){ // All image indices start at 1!
1007 int ymin, ymax;
1008 int empty_bottom;
1009 empty_bottom = 0;
1010 /* treat edge cases, shorten column where needed*/
1011 ymin = ycen_int[i-1]-(height/2);
1012 ymax = ycen_int[i-1]+(height/2) + height%2 ;
1013 if ((ymax <= 1) || (ymin > leny)) {
1014 // Trace is completely out of bounds, skip this column
1015 // set it to 0 and mark as bad pixels 257 1754
1016 for (j = 1; j <= height; j++){
1017 cpl_image_set(img_out, i, j, NAN);
1018 cpl_image_reject(img_out, i, j);
1019 }
1020 continue;
1021 }
1022 if (ymin < 1) {
1023 empty_bottom = 1 - ymin; // save for later insertion
1024 ymin = 1;
1025 }
1026 if (ymax > leny)
1027 ymax = leny; // Simply stop when we reach the top.
1028 if (ymax <= ymin) {
1029 cpl_msg_error(__func__, "Unreasonable borders in column %i", i);
1030 cpl_free(ycen_int);
1031 return -1;
1032 }
1033
1034 img_1d = cpl_image_extract(rect_in, i, empty_bottom+1, i, height);
1035 cpl_image_copy(img_out, img_1d, i, ymin);
1036 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1037 cpl_msg_error(__func__, "Cannot re-insert column %d, %d %d %d, %s",
1038 i, ymin, ymax, empty_bottom, cpl_error_get_where());
1039 cpl_free(ycen_int);
1040 cpl_error_reset();
1041 if (img_1d != NULL) cpl_image_delete(img_1d);
1042 return -1;
1043 }
1044 cpl_image_delete(img_1d);
1045 }
1046 cpl_free(ycen_int);
1047 return 0;
1048}
1049
1050/*----------------------------------------------------------------------------*/
1058/*----------------------------------------------------------------------------*/
1060 const cpl_polynomial * poly,
1061 const cpl_vector * vec)
1062{
1063 int i;
1064 cpl_size nx;
1065 cpl_vector * outvec;
1066
1067 if (poly == NULL || vec == NULL) return NULL;
1068
1069 nx = cpl_vector_get_size(vec);
1070 outvec = cpl_vector_new(nx);
1071 for (i=0; i<nx; i++){
1072 cpl_vector_set(outvec, i,
1073 cpl_polynomial_eval_1d(poly, cpl_vector_get(vec,i), NULL));
1074 }
1075 return outvec;
1076}
1077
1078/*----------------------------------------------------------------------------*/
1088/*----------------------------------------------------------------------------*/
1090 const cpl_vector * invector,
1091 int smooth,
1092 double thresh)
1093{
1094 cpl_vector * smoothed;
1095
1096 if (invector == NULL || smooth < 0) return NULL;
1097
1098 smoothed = cpl_vector_filter_median_create(invector, (smooth/2)+1);
1099 cpl_vector_subtract(smoothed, invector);
1100 cpl_vector_add_scalar(smoothed, thresh);
1101 cpl_vector_multiply_scalar(smoothed, -1.0);
1102 return smoothed;
1103}
1104
1105/*----------------------------------------------------------------------------*/
1111/*----------------------------------------------------------------------------*/
1112char * cr2res_get_base_name(const char *filename)
1113{
1114 char *p ;
1115 if (filename == NULL) return NULL;
1116
1117 p = strrchr (filename, '/');
1118 return p ? p + 1 : (char *) filename;
1119}
1120
1121/*----------------------------------------------------------------------------*/
1127/*----------------------------------------------------------------------------*/
1128char * cr2res_get_root_name(const char * filename)
1129{
1130 static char path[4096+1];
1131 char * lastdot ;
1132 if (filename == NULL) return NULL;
1133
1134 if (strlen(filename)>4096) return NULL ;
1135 memset(path, 0, 4096);
1136 strcpy(path, filename);
1137 lastdot = strrchr(path, '.');
1138 if (lastdot == NULL) return path ;
1139 if ((!strcmp(lastdot, ".fits")) || (!strcmp(lastdot, ".FITS")) ||
1140 (!strcmp(lastdot, ".dat")) || (!strcmp(lastdot, ".DAT")) ||
1141 (!strcmp(lastdot, ".paf")) || (!strcmp(lastdot, ".PAF")) ||
1142 (!strcmp(lastdot, ".txt")) || (!strcmp(lastdot, ".TXT")) ||
1143 (!strcmp(lastdot, ".ascii")) || (!strcmp(lastdot, ".ASCII")))
1144 {
1145 lastdot[0] = (char)0;
1146 }
1147 return path ;
1148}
1149#ifdef CR2RES_UNUSED
1150/*----------------------------------------------------------------------------*/
1157/*----------------------------------------------------------------------------*/
1158const char * cr2res_extract_filename(
1159 const cpl_frameset * in,
1160 const char * tag)
1161{
1162 const cpl_frame * cur_frame ;
1163
1164 /* Get the frame */
1165 if ((cur_frame = cpl_frameset_find_const(in, tag)) == NULL) return NULL ;
1166 return cpl_frame_get_filename(cur_frame) ;
1167}
1168#endif
1169/*----------------------------------------------------------------------------*/
1178/*----------------------------------------------------------------------------*/
1180 const cpl_frameset * in,
1181 const char * tag)
1182{
1183 cpl_frameset * out ;
1184 cpl_frame * loc_frame ;
1185 int nbframes;
1186 int i ;
1187
1188 /* Test entries */
1189 if (in == NULL) return NULL ;
1190 if (tag == NULL) return NULL ;
1191
1192 /* Initialise */
1193 nbframes = cpl_frameset_get_size(in) ;
1194
1195 /* Count the frames with the tag */
1196 if ((cpl_frameset_count_tags(in, tag)) == 0) return NULL ;
1197
1198 /* Create the output frameset */
1199 out = cpl_frameset_new() ;
1200
1201 /* Loop on the requested frames and store them in out */
1202 for (i=0 ; i<nbframes ; i++) {
1203 const cpl_frame * cur_frame ;
1204 cur_frame = cpl_frameset_get_position_const(in, i) ;
1205 if (!strcmp(cpl_frame_get_tag(cur_frame), tag)) {
1206 loc_frame = cpl_frame_duplicate(cur_frame) ;
1207 cpl_frameset_insert(out, loc_frame) ;
1208 }
1209 }
1210 return out ;
1211}
1212
1213/*----------------------------------------------------------------------------*/
1223/*----------------------------------------------------------------------------*/
1225 const cpl_frameset * in,
1226 const char ** tags,
1227 int ntags)
1228{
1229 cpl_frameset * out ;
1230 cpl_frame * loc_frame ;
1231 int nbframes;
1232 int i, j ;
1233
1234 /* Test entries */
1235 if (in == NULL) return NULL ;
1236 if (tags == NULL) return NULL ;
1237 if (ntags < 1) return NULL ;
1238
1239 /* Initialise */
1240 nbframes = cpl_frameset_get_size(in) ;
1241
1242 /* Create the output frameset */
1243 out = cpl_frameset_new() ;
1244
1245 /* Loop on the requested frames and store them in out */
1246 for (i=0 ; i<nbframes ; i++) {
1247 const cpl_frame * cur_frame ;
1248 int match ;
1249 cur_frame = cpl_frameset_get_position_const(in, i) ;
1250 match = 0 ;
1251 for (j=0 ; j<ntags ; j++) {
1252 if (!strcmp(cpl_frame_get_tag(cur_frame), tags[j]))
1253 match = 1 ;
1254 }
1255 if (match) {
1256 loc_frame = cpl_frame_duplicate(cur_frame) ;
1257 cpl_frameset_insert(out, loc_frame) ;
1258 }
1259 }
1260
1261 /* If no frame is valid, return NULL rather than an empty list */
1262 if (cpl_frameset_get_size(out) == 0) {
1263 cpl_frameset_delete(out) ;
1264 return NULL ;
1265 }
1266 return out ;
1267}
1268
1269/*----------------------------------------------------------------------------*/
1275/*----------------------------------------------------------------------------*/
1276char * cr2res_decker_print_position(cr2res_decker dpos)
1277{
1278 char * out ;
1279
1280 /* Initialise */
1281 out = NULL ;
1282
1283 if (dpos == CR2RES_DECKER_INVALID) {
1284 out = cpl_strdup("INVALID") ;
1285 } else if (dpos == CR2RES_DECKER_NONE) {
1286 out = cpl_strdup("NONE") ;
1287 } else if (dpos == CR2RES_DECKER_1_3) {
1288 out = cpl_strdup("1_3") ;
1289 } else if (dpos == CR2RES_DECKER_2_4) {
1290 out = cpl_strdup("2_4") ;
1291 } else {
1292 out = cpl_strdup("Unknown Decker Code") ;
1293 }
1294 return out ;
1295}
1296
1297/*----------------------------------------------------------------------------*/
1304/*----------------------------------------------------------------------------*/
1305cpl_polynomial * cr2res_convert_array_to_poly(const cpl_array * arr)
1306{
1307 cpl_polynomial * out ;
1308 cpl_size i ;
1309
1310 /* Test entries */
1311 if (arr == NULL) return NULL ;
1312
1313 /* Create Output poly */
1314 out = cpl_polynomial_new(1) ;
1315
1316 /* Fill it */
1317 for (i=0 ; i<cpl_array_get_size(arr) ; i++) {
1318 double val ;
1319 val = cpl_array_get(arr, i, NULL) ;
1320 if (isnan(val)) {
1321 cpl_polynomial_delete(out) ;
1322 return NULL ;
1323 }
1324 cpl_polynomial_set_coeff(out, &i, cpl_array_get(arr, i, NULL)) ;
1325 }
1326
1327 return out ;
1328}
1329
1330/*----------------------------------------------------------------------------*/
1338/*----------------------------------------------------------------------------*/
1340 const cpl_polynomial * poly,
1341 int size)
1342{
1343 cpl_array * out ;
1344 cpl_size degree, i ;
1345
1346 /* Test entries */
1347 if (poly == NULL || size < 1) return NULL ;
1348
1349 /* Initialise */
1350 degree = cpl_polynomial_get_degree(poly) ;
1351
1352 /* Check */
1353 if (size < degree+1) {
1354 cpl_msg_error(__func__,
1355 "The requested array size is too small for the polynomial") ;
1356 return NULL ;
1357 }
1358
1359 /* Create Output array */
1360 out = cpl_array_new(size, CPL_TYPE_DOUBLE) ;
1361 cpl_array_fill_window(out, 0, size, 0.0) ;
1362
1363 /* Fill it */
1364 for (i=0 ; i<=degree ; i++) {
1365 cpl_array_set(out, i, cpl_polynomial_get_coeff(poly, &i)) ;
1366 }
1367 return out ;
1368}
1369
1370// Remove an element from a vector, the data is modified and resized
1371int cr2res_vector_erase_element(cpl_vector * vector, cpl_size pos)
1372{
1373 cpl_size i, n;
1374
1375 if (vector == NULL) return -1;
1376
1377 n = cpl_vector_get_size(vector);
1378 if (pos >= n || pos < 0) return -1;
1379
1380 // we shift all elements past pos one step to the left
1381 for (i = pos; i < n - 1; i++){
1382 cpl_vector_set(vector, i, cpl_vector_get(vector, i + 1));
1383 }
1384 // and then remove the last element in the vector
1385 cpl_vector_set_size(vector, n-1);
1386 return 0;
1387}
1388
1389// applies the absolute to each element
1390int cr2res_vector_abs(cpl_vector * vector){
1391 cpl_size i;
1392
1393 if (vector == NULL) return 0;
1394
1395 for (i = 0; i < cpl_vector_get_size(vector); i++){
1396 cpl_vector_set(vector, i,
1397 fabs(cpl_vector_get(vector, i)));
1398 }
1399 return 0;
1400}
1401
1402/* This function is copied from HDRLDEMO -> should not be changed */
1403/* It could be added in HDRL */
1404/*----------------------------------------------------------------------------*/
1425/*----------------------------------------------------------------------------*/
1427 const cpl_image * ima_data,
1428 const double gain,
1429 const double ron,
1430 cpl_image ** ima_errs)
1431{
1432 cpl_ensure_code(ima_data, CPL_ERROR_NULL_INPUT);
1433 cpl_ensure_code(ima_errs, CPL_ERROR_NULL_INPUT);
1434 cpl_ensure_code(gain > 0., CPL_ERROR_ILLEGAL_INPUT);
1435 cpl_ensure_code(ron > -1e-5, CPL_ERROR_ILLEGAL_INPUT);
1436
1437 *ima_errs = cpl_image_duplicate(ima_data);
1438 /* set negative values (= zero measurable electrons) to read out noise */
1439 cpl_image_threshold(*ima_errs, 0., DBL_MAX, ron, ron);
1440 cpl_image_divide_scalar(*ima_errs, gain);
1441 cpl_image_add_scalar(*ima_errs, ron * ron);
1442 cpl_image_power(*ima_errs, 0.5);
1443
1444 return cpl_error_get_code();
1445}
1446
1447/*----------------------------------------------------------------------------*/
1457/*----------------------------------------------------------------------------*/
1459 const cpl_bivector * extracted_spec,
1460 const cpl_bivector * catalog,
1461 const char * title,
1462 double wmin,
1463 double wmax)
1464{
1465 cpl_bivector ** bivectors ;
1466 double * p0x ;
1467 double * p0y ;
1468 double * p1x ;
1469 double * p1y ;
1470 cpl_bivector * tmp_biv0 ;
1471 cpl_bivector * tmp_biv1 ;
1472 double rate ;
1473 int n0, n1;
1474
1475 /* Check entries */
1476 if (extracted_spec==NULL||catalog==NULL||title==NULL)
1477 return -1 ;
1478
1479 /* Initialise */
1480 n0 = n1 = 0 ;
1481
1482 /* Create bivectors */
1483 bivectors = cpl_malloc(2*sizeof(cpl_bivector*)) ;
1484 bivectors[0] = cpl_bivector_duplicate(extracted_spec) ;
1485 bivectors[1] = cpl_bivector_duplicate(catalog) ;
1486
1487 /* Sort the bivectors - Should not be necessary */
1488 cpl_bivector_sort(bivectors[0], bivectors[0], CPL_SORT_ASCENDING,
1489 CPL_SORT_BY_X);
1490 p0x = cpl_bivector_get_x_data(bivectors[0]) ;
1491 p0y = cpl_bivector_get_y_data(bivectors[0]) ;
1492 cpl_bivector_sort(bivectors[1], bivectors[1], CPL_SORT_ASCENDING,
1493 CPL_SORT_BY_X);
1494 p1x = cpl_bivector_get_x_data(bivectors[1]) ;
1495 p1y = cpl_bivector_get_y_data(bivectors[1]) ;
1496
1497 /* Shrink bivectors to wmin-wmax only if requested */
1498 if (wmin > 0.0 && wmax > 0.0 && wmax > wmin) {
1499 int i ;
1500 /* Count the bins falling in the wished interval */
1501 for (i=0 ; i<cpl_bivector_get_size(bivectors[0]) ; i++)
1502 if (p0x[i] >= wmin && p0x[i] <= wmax) n0++ ;
1503 for (i=0 ; i<cpl_bivector_get_size(bivectors[1]) ; i++)
1504 if (p1x[i] >= wmin && p1x[i] <= wmax) n1++ ;
1505
1506 if (n0 > 0 && n1 > 0) {
1507 double *ptmp_biv0x;
1508 double *ptmp_biv0y;
1509 double *ptmp_biv1x;
1510 double *ptmp_biv1y;
1511 /* Allocate the smaller bivectors */
1512 tmp_biv0 = cpl_bivector_new(n0) ;
1513 ptmp_biv0x = cpl_bivector_get_x_data(tmp_biv0) ;
1514 ptmp_biv0y = cpl_bivector_get_y_data(tmp_biv0) ;
1515 n0 = 0 ;
1516 for (i=0 ; i<cpl_bivector_get_size(bivectors[0]) ; i++)
1517 if (p0x[i] >= wmin && p0x[i] <= wmax) {
1518 ptmp_biv0x[n0] = p0x[i] ;
1519 ptmp_biv0y[n0] = p0y[i] ;
1520 n0++ ;
1521 }
1522 tmp_biv1 = cpl_bivector_new(n1) ;
1523 ptmp_biv1x = cpl_bivector_get_x_data(tmp_biv1) ;
1524 ptmp_biv1y = cpl_bivector_get_y_data(tmp_biv1) ;
1525 n1 = 0 ;
1526 for (i=0 ; i<cpl_bivector_get_size(bivectors[1]) ; i++)
1527 if (p1x[i] >= wmin && p1x[i] <= wmax) {
1528 ptmp_biv1x[n1] = p1x[i] ;
1529 ptmp_biv1y[n1] = p1y[i] ;
1530 n1++ ;
1531 }
1532 cpl_bivector_delete(bivectors[0]) ;
1533 cpl_bivector_delete(bivectors[1]) ;
1534
1535 bivectors[0] = tmp_biv0 ;
1536 bivectors[1] = tmp_biv1 ;
1537 }
1538 }
1539
1540 /* Adjust the signal */
1541 rate = -1* fabs(10*cpl_vector_get_mean(cpl_bivector_get_y(bivectors[0])) /
1542 cpl_vector_get_mean(cpl_bivector_get_y(bivectors[1]))) ;
1543 cpl_vector_multiply_scalar(cpl_bivector_get_y(bivectors[1]), rate) ;
1544
1545 /* Plot */
1546 if (cpl_bivector_get_size(bivectors[0]) > 0 &&
1547 cpl_bivector_get_size(bivectors[1]) > 0) {
1548
1549 char ** options = cpl_malloc(2*sizeof(char*)) ;
1550 options[0] = cpl_sprintf("t '1-Extracted %s' w lines", title) ;
1551 options[1] = "t '2-Catalog' w impulses" ;
1552 cpl_plot_bivectors("set grid;set xlabel 'Wavelength (nm)';",
1553 (const char **)options,
1554 "", (const cpl_bivector **)bivectors, 2);
1555 cpl_free(options[0]) ;
1556 cpl_free(options) ;
1557 }
1558
1559 /* Free */
1560 cpl_bivector_delete(bivectors[0]) ;
1561 cpl_bivector_delete(bivectors[1]) ;
1562 cpl_free(bivectors) ;
1563 return 0 ;
1564}
1565#ifdef CR2RES_UNUSED
1566/*
1567 opt_filter_1d performs optimal filtering of a 1D double array. The mandatory parameters
1568 are the data array Yarg, the output array Result, the filtering parameter Lam1 and the
1569 array of Options.
1570 Options is a 3-element integer array indicating the presence of optional parameters Xarg
1571 (x argument of the data array), Weights (weights of the data points) and Lam2 (filtering
1572 parameter for the 2nd derivatives). Xarg, if present, must be sorted in ascending or descending
1573 order. Absent parameters can by replaced with NULL at the calling.
1574*/
1575
1576/*----------------------------------------------------------------------------*/
1592/*----------------------------------------------------------------------------*/
1593int cr2res_util_optimal_filter_1d(
1594 const double * Yarg,
1595 double Lam1,
1596 double * Result,
1597 int n,
1598 int Options[],
1599 const double * Xarg,
1600 const double * Weights,
1601 double Lam2)
1602{
1603 int i, flag_x, flag_w, flag_lam2;
1604 double *aij, *bj;
1605
1606 flag_x =(Options[0])?1:0; // Flags for optional parameters
1607 flag_w =(Options[1])?1:0;
1608 flag_lam2=(Options[2])?1:0;
1609
1610 if(flag_x) // Xarg is present
1611 {
1612 int nzero;
1613 double *dx;
1614 dx=(double *)cpl_malloc((n-1)*sizeof(double));
1615 nzero=0;
1616 for(i=0; i<n-1; i++)
1617 {
1618 dx[i]=Xarg[i+1]-Xarg[i];
1619 if(dx[i]>0.) nzero++; // Check that Xarg is sorted one way
1620 else if(dx[i]<0.) nzero--; // or the other
1621 }
1622
1623 if(abs(nzero)!=n-1) // Xarg is present but not sorted
1624 {
1625 cpl_free(dx);
1626 return 8;
1627 }
1628
1629 if(flag_lam2)
1630 {
1631 double *ddx2;
1632 ddx2=(double *)cpl_malloc((n-2)*sizeof(double));
1633 for(i=0; i<n-2; i++)
1634 {
1635 ddx2[i]=(Xarg[i+2]-Xarg[i])*0.5;
1636 ddx2[i]*=ddx2[i];
1637 }
1638
1639 aij=(double *)cpl_malloc(n*5*sizeof(double));
1640 bj =(double *)cpl_malloc(n* sizeof(double));
1641//
1642// 2nd lower subdiagonal
1643 aij[0]=aij[1]=0.;
1644 for(i=0; i<n-2; i++) aij[i+2]=Lam2/(dx[i]*dx[i+1]*ddx2[i]);
1645//
1646// Lower subdiagonal
1647 aij[n]=0.;
1648 for(i=0; i<n-1; i++) aij[n+i+1] =-Lam1/(dx[i]*dx[i]);
1649 for(i=0; i<n-2; i++)
1650 {
1651 aij[n+i+1]-= Lam2/(dx[i ]*dx[i ]*ddx2[i])
1652 +Lam2/(dx[i ]*dx[i+1]*ddx2[i]);
1653 aij[n+i+2]-= Lam2/(dx[i+1]*dx[i+1]*ddx2[i])
1654 +Lam2/(dx[i ]*dx[i+1]*ddx2[i]);
1655 }
1656
1657//
1658// Main diagonal
1659 if(flag_w) for(i=0; i<n; i++) aij[2*n+i]=Weights[i];
1660 else for(i=0; i<n; i++) aij[2*n+i]=1.;
1661
1662 for(i=0; i<n-1; i++) aij[2*n+i ]+=Lam1/(dx[i]*dx[i]);
1663
1664 for(i=0; i<n-1; i++) aij[2*n+i+1]+=Lam1/(dx[i]*dx[i]);
1665
1666 for(i=0; i<n-2; i++)
1667 {
1668 double dddd;
1669 aij[2*n+i ]+=Lam2/(dx[i ]*dx[i ]*ddx2[i]);
1670 dddd=1./dx[i]+1./dx[i+1]; dddd*=dddd;
1671 aij[2*n+i+1]+=Lam2*dddd/ddx2[i];
1672 aij[2*n+i+2]+=Lam2/(dx[i+1]*dx[i+1]*ddx2[i]);
1673 }
1674
1675//
1676// Upper subdiagonal
1677 for(i=0; i<n-1; i++) aij[3*n+i]=-Lam1/(dx[i]*dx[i]);
1678 aij[4*n-1]=0.;
1679
1680 for(i=0; i<n-2; i++)
1681 {
1682 aij[3*n+i ]-= Lam2/(dx[i ]*dx[i ]*ddx2[i])
1683 +Lam2/(dx[i ]*dx[i+1]*ddx2[i]);
1684 aij[3*n+i+1]-= Lam2/(dx[i+1]*dx[i+1]*ddx2[i])
1685 +Lam2/(dx[i ]*dx[i+1]*ddx2[i]);
1686 }
1687
1688//
1689// 2nd upper subdiagonal
1690 for(i=0; i<n-2; i++) aij[4*n+i]=Lam2/(dx[i+1]*dx[i]*ddx2[i]);
1691 aij[5*n-2]=aij[5*n-1]=0.;
1692
1693//
1694// RHS
1695 if(flag_w) for(i=0; i<n; i++) bj[i]=Yarg[i]*Weights[i];
1696 else for(i=0; i<n; i++) bj[i]=Yarg[i];
1697
1698 cr2res_extract_slitdec_bandsol(aij, bj, n, 5, Lam1); // Solve the band diagonal SLE
1699 for(i=0; i<n; i++) Result[i]=bj[i]; // Copy results
1700
1701 cpl_free(bj);
1702 cpl_free(aij);
1703 cpl_free(ddx2);
1704 cpl_free(dx);
1705 return CPL_ERROR_NONE;
1706 }
1707 else // No 2nd derivative filtering
1708 {
1709 aij=(double *)cpl_malloc(n*3*sizeof(double));
1710 bj =(double *)cpl_malloc(n* sizeof(double));
1711//
1712// Lower subdiagonal
1713 aij[0]=0.;
1714 for(i=0; i<n-1; i++) aij[i+1]=-Lam1/(dx[i]*dx[i]);
1715
1716//
1717// Main diagonal
1718 if(flag_w) for(i=0; i<n; i++) aij[n+i]=Weights[i];
1719 else for(i=0; i<n; i++) aij[n+i]=1.;
1720
1721 for(i=0; i<n-1; i++) aij[n+i ]+=Lam1/(dx[i]*dx[i]);
1722 for(i=0; i<n-1; i++) aij[n+i+1]+=Lam1/(dx[i]*dx[i]);
1723
1724//
1725// Upper subdiagonal
1726 for(i=0; i<n-1; i++) aij[2*n+i]=-Lam1/(dx[i]*dx[i]);
1727 aij[3*n-1]=0.;
1728
1729//
1730// RHS
1731 if(flag_w) for(i=0; i<n; i++) bj[i]=Yarg[i]*Weights[i];
1732 else for(i=0; i<n; i++) bj[i]=Yarg[i];
1733
1734 cr2res_extract_slitdec_bandsol(aij, bj, n, 3, Lam1); // Solve the band diagonal SLE
1735 for(i=0; i<n; i++) Result[i]=bj[i]; // Copy results
1736
1737 cpl_free(bj);
1738 cpl_free(aij);
1739 cpl_free(dx);
1740 return CPL_ERROR_NONE;
1741 }
1742 }
1743 else // No Xarg is set
1744 {
1745 if(flag_lam2)
1746 {
1747 aij=(double *)cpl_malloc(n*5*sizeof(double));
1748 bj =(double *)cpl_malloc(n* sizeof(double));
1749//
1750// 2nd lower subdiagonal
1751 aij[0]=aij[1]=0.;
1752 for(i=0; i<n-2; i++) aij[i+2]=Lam2;
1753
1754//
1755// Lower subdiagonal
1756 aij[n]=0.;
1757 for(i=0; i<n-1; i++) aij[n+i+1]=-Lam1;
1758 for(i=0; i<n-2; i++) aij[n+i+1]-=2*Lam2;
1759 for(i=0; i<n-2; i++) aij[n+i+2]-=2*Lam2;
1760
1761//
1762// Main diagonal
1763 if(flag_w) for(i=0; i<n; i++) aij[2*n+i]=Weights[i];
1764 else for(i=0; i<n; i++) aij[2*n+i]=1.;
1765 for(i=0; i<n-1; i++) aij[2*n+i ]+=Lam1;
1766 for(i=0; i<n-1; i++) aij[2*n+i+1]+=Lam1;
1767 for(i=0; i<n-2; i++) aij[2*n+i ]+=Lam2;
1768 for(i=0; i<n-2; i++) aij[2*n+i+1]+=Lam2*4;
1769 for(i=0; i<n-2; i++) aij[2*n+i+2]+=Lam2;
1770
1771//
1772// Upper subdiagonal
1773 for(i=0; i<n-1; i++) aij[3*n+i]=-Lam1;
1774 aij[4*n-1]=0.;
1775 for(i=0; i<n-2; i++) aij[3*n+i ]-=Lam2*2;
1776 for(i=0; i<n-2; i++) aij[3*n+i+1]-=Lam2*2;
1777
1778//
1779// 2nd lower subdiagonal
1780 for(i=0; i<n-2; i++) aij[4*n+i]=Lam2;
1781 aij[5*n-2]=aij[5*n-1]=0.;
1782
1783//
1784// RHS
1785 if(flag_w) for(i=0; i<n; i++) bj[i]=Yarg[i]*Weights[i];
1786 else for(i=0; i<n; i++) bj[i]=Yarg[i];
1787
1788 cr2res_extract_slitdec_bandsol(aij, bj, n, 5, Lam1); // Solve the band diagonal SLE
1789 for(i=0; i<n; i++) Result[i]=bj[i]; // Copy results
1790
1791 cpl_free(bj);
1792 cpl_free(aij);
1793 return CPL_ERROR_NONE;
1794 }
1795 else // No 2nd derivative filtering
1796 {
1797 aij=(double *)cpl_malloc(n*3*sizeof(double));
1798 bj =(double *)cpl_malloc(n* sizeof(double));
1799//
1800// Lower subdiagonal
1801 aij[0]=0.;
1802 for(i=0; i<n-1; i++) aij[i+1]=-Lam1;
1803
1804//
1805// Main diagonal
1806 if(flag_w) for(i=0; i<n; i++) aij[n+i]=Weights[i];
1807 else for(i=0; i<n; i++) aij[n+i]=1.;
1808
1809 for(i=0; i<n-1; i++) aij[n+i ]+=Lam1;
1810 for(i=0; i<n-1; i++) aij[n+i+1]+=Lam1;
1811
1812//
1813// Upper subdiagonal
1814 for(i=0; i<n-1; i++) aij[2*n+i]=-Lam1;
1815 aij[3*n-1]=0.;
1816
1817//
1818// RHS
1819 if(flag_w) for(i=0; i<n; i++) bj[i]=Yarg[i]*Weights[i];
1820 else for(i=0; i<n; i++) bj[i]=Yarg[i];
1821
1822 cr2res_extract_slitdec_bandsol(aij, bj, n, 3, Lam1); // Solve the band diagonal SLE
1823 for(i=0; i<n; i++) Result[i]=bj[i]; // Copy filtered vector to Result
1824
1825 cpl_free(bj);
1826 cpl_free(aij);
1827 return CPL_ERROR_NONE;
1828 }
1829 }
1830}
1831#endif
1832#define aij_index(x, y) ((y) * n) + (x)
1833#define w_index(x, y) ((y) * nx) + (x)
1834
1835/*----------------------------------------------------------------------------*/
1847/*----------------------------------------------------------------------------*/
1849 const cpl_image * img,
1850 const cpl_image * weight,
1851 double lam_x,
1852 double lam_y)
1853{
1854 cpl_size nx, ny, i, j, k;
1855 int n, ndiag ;
1856 double * aij;
1857 const double * weight_data;
1858 cpl_image * rhs_image;
1859 double * rhs;
1860
1861 nx = cpl_image_get_size_x(img);
1862 ny = cpl_image_get_size_y(img);
1863 n = nx * ny;
1864 ndiag = 2 * nx + 1;
1865
1866 lam_x = fabs(lam_x);
1867 lam_y = fabs(lam_y);
1868
1869 weight_data = cpl_image_get_data_double_const(weight);
1870 // aij=dblarr(n, ndiag)
1871 aij = cpl_malloc(n * ndiag * sizeof(double));
1872 // aij[0, nx] = weight[0, 0] + lam_x + lam_y
1873 aij[aij_index(0, nx)] = weight_data[w_index(0, 0)] + lam_x + lam_y;
1874 // aij[1:nx-1, nx] = weight[1:nx-1, 0] +2 * lam_x + lam_y
1875 for (i = 1; i < nx; i++)
1876 {
1877 aij[aij_index(i, nx)] = weight_data[w_index(i, 0)] + 2 * lam_x + lam_y;
1878 }
1879 // aij[nx:n-nx-1,nx]=reform(weight[*,1:ny-2],nx*(ny-2L))+2.d0*(lam_x+lam_y)
1880 k = nx;
1881 for (i = 0; i < nx; i++)
1882 {
1883 for (j = 1; j < ny-2; j++){
1884 aij[aij_index(k, nx)] = weight_data[w_index(i, j)]
1885 + 2 * lam_x + 2 * lam_y;
1886 k++;
1887 }
1888 }
1889 // aij[n-nx:n-2,nx]= weight[0:nx-2,ny-1] + 2 * lam_x + lam_y
1890 j = 0;
1891 for (i = n - nx; i < n - 1; i++)
1892 {
1893 aij[aij_index(i, nx)] = weight_data[w_index(j, ny-1)]
1894 + 2 * lam_x + lam_y;
1895 j++;
1896 }
1897 // aij[n-1,nx] = weight[nx-1,ny-1]+lam_x+lam_y
1898 aij[aij_index(n-1, nx)] = weight_data[w_index(nx-1, ny-1)] + lam_x + lam_y;
1899 for (i = 1; i < n; i++)
1900 {
1901 // aij[1:n-1, nx-1]=-lam_x
1902 aij[aij_index(i, nx-1)] = -1 * lam_x;
1903 // aij[0:n-2, nx+1]=-lam_x
1904 aij[aij_index(i-1, nx+1)] = -1 * lam_x;
1905 }
1906
1907 for (i = 0; i < ny-1; i++)
1908 {
1909 // ind = lindgen(ny-1) * nx + nx + nx * n
1910 j = i * nx + nx + nx * n;
1911 // aij[ind-1] = aij[ind-1] - lam_x
1912 aij[j-1] = aij[j - 1] - lam_x;
1913 // aij[ind ] = aij[ind] - lam_x
1914 aij[j] = aij[j] - lam_x;
1915 }
1916 for (i = 0; i < ny - 1; i++){
1917 // ind = lindgen(ny-1) * nx + nx
1918 j = i * nx + nx;
1919 // aij[ind-1,nx+1] = 0
1920 aij[aij_index(j - 1, nx + 1)] = 0;
1921 // aij[ind, nx-1] = 0
1922 aij[aij_index(j, nx - 1)] = 0;
1923 }
1924 // aij[nx:n-1, 0] = -lam_y
1925 for (i = nx; i < n; i++)
1926 {
1927 aij[aij_index(i, 0)] = -lam_y;
1928 }
1929 // aij[0:n-nx-1, ndiag-1] = -lam_y
1930 for (i = 0; i < n - nx; i++)
1931 {
1932 aij[aij_index(i, ndiag - 1)] = -lam_y;
1933 }
1934
1935 rhs_image = cpl_image_multiply_create(img, weight);
1936 rhs = cpl_image_get_data_double(rhs_image);
1937
1938 cr2res_extract_slitdec_bandsol(aij, rhs, n, ndiag, max(lam_x, lam_y));
1939 cpl_free(aij);
1940
1941 return rhs_image;
1942}
1943
1944#undef aij_index
1945#undef w_index
1946
1947/*
1948
1949def _scale(x, y):
1950 # Normalize x and y to avoid huge numbers
1951 # Mean 0, Variation 1
1952 offset_x, offset_y = np.mean(x), np.mean(y)
1953 norm_x, norm_y = np.std(x), np.std(y)
1954 if norm_x == 0:
1955 norm_x = 1
1956 if norm_y == 0:
1957 norm_y = 1
1958 x = (x - offset_x) / norm_x
1959 y = (y - offset_y) / norm_y
1960 return x, y, (norm_x, norm_y), (offset_x, offset_y)
1961
1962
1963def _unscale(x, y, norm, offset):
1964 x = x * norm[0] + offset[0]
1965 y = y * norm[1] + offset[1]
1966 return x, y
1967
1968def polyfit2d(
1969 x, y, z, degree=1, max_degree=None, scale=True, plot=False, plot_title=None
1970):
1971 """A simple 2D polynomial fit to data x, y, z
1972 The polynomial can be evaluated with numpy.polynomial.polynomial.polyval2d
1973
1974 Parameters
1975 ----------
1976 x : array[n]
1977 x coordinates
1978 y : array[n]
1979 y coordinates
1980 z : array[n]
1981 data values
1982 degree : int, optional
1983 degree of the polynomial fit (default: 1)
1984 max_degree : {int, None}, optional
1985 if given the maximum combined degree of the coefficients is limited to this value
1986 scale : bool, optional
1987 Wether to scale the input arrays x and y to mean 0 and variance 1, to avoid numerical overflows.
1988 Especially useful at higher degrees. (default: True)
1989 plot : bool, optional
1990 wether to plot the fitted surface and data (slow) (default: False)
1991
1992 Returns
1993 -------
1994 coeff : array[degree+1, degree+1]
1995 the polynomial coefficients in numpy 2d format, i.e. coeff[i, j] for x**i * y**j
1996 """
1997 # Flatten input
1998 x = np.asarray(x).ravel()
1999 y = np.asarray(y).ravel()
2000 z = np.asarray(z).ravel()
2001
2002 # Removed masked values
2003 mask = ~(np.ma.getmask(z) | np.ma.getmask(x) | np.ma.getmask(y))
2004 x, y, z = x[mask].ravel(), y[mask].ravel(), z[mask].ravel()
2005
2006 if scale:
2007 x, y, norm, offset = _scale(x, y)
2008
2009 # Create combinations of degree of x and y
2010 # usually: [(0, 0), (1, 0), (0, 1), (1, 1), (2, 0), ....]
2011 if np.isscalar(degree):
2012 degree = (int(degree), int(degree))
2013 assert len(degree) == 2, "Only 2D polynomials can be fitted"
2014 degree = [int(degree[0]), int(degree[1])]
2015 # idx = [[i, j] for i, j in product(range(degree[0] + 1), range(degree[1] + 1))]
2016 coeff = np.zeros((degree[0] + 1, degree[1] + 1))
2017 idx = _get_coeff_idx(coeff)
2018
2019 # Calculate elements 1, x, y, x*y, x**2, y**2, ...
2020 A = polyvander2d(x, y, degree)
2021
2022 # We only want the combinations with maximum order COMBINED power
2023 if max_degree is not None:
2024 mask = idx[:, 0] + idx[:, 1] <= int(max_degree)
2025 idx = idx[mask]
2026 A = A[:, mask]
2027
2028 # Do least squares fit
2029 C, *_ = lstsq(A, z)
2030
2031 # Reorder coefficients into numpy compatible 2d array
2032 for k, (i, j) in enumerate(idx):
2033 coeff[i, j] = C[k]
2034
2035 # # Backup copy of coeff
2036 if scale:
2037 coeff = polyscale2d(coeff, *norm, copy=False)
2038 coeff = polyshift2d(coeff, *offset, copy=False)
2039
2040 if plot: # pragma: no cover
2041 if scale:
2042 x, y = _unscale(x, y, norm, offset)
2043 plot2d(x, y, z, coeff, title=plot_title)
2044
2045 return coeff
2046*/
2047
2048/*----------------------------------------------------------------------------*/
2062/*----------------------------------------------------------------------------*/
2063cpl_polynomial * cr2res_polyfit_2d_loc(
2064 const cpl_vector * x,
2065 const cpl_vector * y,
2066 const cpl_vector * z,
2067 const cpl_matrix * degree)
2068{
2069 cpl_size npoints, ndegrees;
2070 double norm_x, norm_y;
2071 double coef;
2072 cpl_size i, j;
2073
2074 cpl_polynomial * poly;
2075 cpl_vector * xhat, * yhat, *zhat;
2076 cpl_matrix * mh, * mz;
2077 cpl_matrix * mcoef;
2078 cpl_size power[2];
2079
2080 if (x == NULL || y == NULL || z == NULL || degree == NULL) return NULL;
2081
2082 npoints = cpl_vector_get_size(x);
2083 if (cpl_vector_get_size(y) != npoints || cpl_vector_get_size(z) != npoints){
2084 // All vectors need to be the same size
2085 cpl_msg_error(__func__, "Vectors in polyfit2d are not of the same size");
2086 return NULL;
2087 }
2088 ndegrees = cpl_matrix_get_nrow(degree);
2089 if (ndegrees <= 0){
2090 cpl_msg_error(__func__, "No fit degrees passed to polyfit2d");
2091 return NULL;
2092 }
2093
2094 // Normalize x and y to avoid huge numbers
2095 // Mean 0, Variation 1
2096 // offset_x = cpl_vector_get_mean(x);
2097 // offset_y = cpl_vector_get_mean(y);
2098 // norm_x = cpl_vector_get_stdev(x);
2099 // norm_y = cpl_vector_get_stdev(y);
2100 // We normalize to 0 and 1
2101 // this only works well when the regular scale is 0 to N
2102 // which we do have for a detector
2103 // TODO: figure out how to correct for an offset
2104 norm_x = cpl_vector_get_max(x);
2105 norm_y = cpl_vector_get_max(y);
2106 if (norm_x == 0) norm_x = 1;
2107 if (norm_y == 0) norm_y = 1;
2108
2109 xhat = cpl_vector_duplicate(x);
2110 yhat = cpl_vector_duplicate(y);
2111
2112 // cpl_vector_subtract_scalar(xhat, offset_x);
2113 cpl_vector_divide_scalar(xhat, norm_x);
2114
2115 // cpl_vector_subtract_scalar(yhat, offset_y);
2116 cpl_vector_divide_scalar(yhat, norm_y);
2117
2118 // Create the Vandermode Matrix A
2119 // Calculate elements 1, x, y, x*y, x**2, y**2, ...
2120 const double * xdata, *ydata;
2121 double xdegree, ydegree;
2122 mh = cpl_matrix_new(npoints, ndegrees);
2123
2124 xdata = cpl_vector_get_data_const(xhat);
2125 ydata = cpl_vector_get_data_const(yhat);
2126
2127
2128 for (i = 0; i < ndegrees; i++)
2129 {
2130 xdegree = cpl_matrix_get(degree, i, 0);
2131 ydegree = cpl_matrix_get(degree, i, 1);
2132
2133 for (j = 0; j < npoints; j++)
2134 {
2135 cpl_matrix_set(mh, j, i, pow(xdata[j], xdegree) * pow(ydata[j], ydegree));
2136 }
2137 }
2138
2139 // Wrap the z vector in a matrix
2140 // Copy it to avoid the const classifier
2141 zhat = cpl_vector_duplicate(z);
2142 mz = cpl_matrix_wrap(npoints, 1, cpl_vector_get_data(zhat));
2143
2144 /* Solve XA=B by a least-square solution (aka pseudo-inverse). */
2145 mcoef = cpl_matrix_solve_svd(mh, mz);
2146
2147 cpl_matrix_unwrap(mz);
2148 cpl_matrix_delete(mh);
2149
2150 // reset the scale
2151 for (i = 0; i < ndegrees; i++){
2152 xdegree = cpl_matrix_get(degree, i, 0);
2153 ydegree = cpl_matrix_get(degree, i, 1);
2154
2155 coef = cpl_matrix_get(mcoef, i, 0);
2156 coef /= pow(norm_x, xdegree) * pow(norm_y, ydegree);
2157 cpl_matrix_set(mcoef, i, 0, coef);
2158 }
2159
2160
2161 // turn coefficients into a polynomial
2162 poly = cpl_polynomial_new(2);
2163 for (i = 0; i < ndegrees; i++)
2164 {
2165 power[0] = cpl_matrix_get(degree, i, 0);
2166 power[1] = cpl_matrix_get(degree, i, 1);
2167 coef = cpl_matrix_get(mcoef, i, 0);
2168 cpl_polynomial_set_coeff(poly, power, coef);
2169 }
2170
2171 cpl_vector_delete(xhat);
2172 cpl_vector_delete(yhat);
2173 cpl_vector_delete(zhat);
2174 cpl_matrix_delete(mcoef);
2175
2176
2177 return poly;
2178}
2179
2180cpl_polynomial * cr2res_polyfit_2d(
2181 const cpl_vector * x,
2182 const cpl_vector * y,
2183 const cpl_vector * z,
2184 const cpl_size degree[2]
2185){
2186
2187 cpl_matrix * deg;
2188 cpl_polynomial * result;
2189 cpl_size ndegrees = degree[0] * degree[1] + 1;
2190 cpl_size max_degree = max(degree[0], degree[1]);
2191 cpl_size i, j, n;
2192
2193 deg = cpl_matrix_new(ndegrees, 2);
2194
2195 n = 0;
2196 for (i = 0; i < degree[0]; i++)
2197 {
2198 for (j = 0; j < degree[1]; j++)
2199 {
2200 if (i + j > max_degree) continue;
2201 cpl_matrix_set(deg, n, 0, i);
2202 cpl_matrix_set(deg, n, 1, j);
2203 n++;
2204 }
2205 }
2206
2207 cpl_matrix_set_size(deg, n, 2);
2208
2209 result = cr2res_polyfit_2d_loc(x, y, z, deg);
2210 cpl_matrix_delete(deg);
2211 return result;
2212}
2213
2214/*----------------------------------------------------------------------------*/
2222/*----------------------------------------------------------------------------*/
2224 const cpl_table * blaze,
2225 int * ngood,
2226 double * blaze_tot)
2227{
2228 cpl_array * col_names ;
2229 const double * pspec ;
2230 cpl_size ncols, i, j, nrows;
2231
2232 /* Check Inputs */
2233 if (blaze == NULL) return 1.0 ;
2234
2235 /* Get the column names */
2236 col_names = cpl_table_get_column_names(blaze);
2237 ncols = cpl_table_get_ncol(blaze) ;
2238 if (ncols < 9){
2239 cpl_array_delete(col_names) ;
2240 return 1.0 ;
2241 }
2242
2243 /* Loop on the columns */
2244 *ngood = 0;
2245 *blaze_tot = 0;
2246
2247 for (i = 0; i < ncols; i++) {
2248 char *col_type;
2249 const char *col_name;
2250 int trace_nb, order ;
2251 col_name = cpl_array_get_string(col_names, i);
2252 col_type = cr2res_dfs_SPEC_colname_parse(col_name, &order,
2253 &trace_nb) ;
2254 if (col_type != NULL && !strcmp(col_type, CR2RES_COL_SPEC_SUFFIX)) {
2255 /* This is a SPEC column */
2256
2257 /* Access the data */
2258 pspec = cpl_table_get_data_double_const(blaze, col_name) ;
2259
2260 nrows = cpl_table_get_nrow(blaze) ;
2261 for (j=0 ; j<nrows ; j++) {
2262 if (pspec[j] > 0) {
2263 (*blaze_tot) += pspec[j] ;
2264 (*ngood)++;
2265 }
2266 }
2267 }
2268 if (col_type != NULL) cpl_free(col_type) ;
2269 }
2270 cpl_array_delete(col_names) ;
2271
2272 if(*ngood == 0)
2273 return 1.0;
2274
2275 return *blaze_tot / *ngood ;
2276}
2277
2278#define SECONDS_TO_DAYS 1.157407e-5
2279/*----------------------------------------------------------------------------*/
2288/*----------------------------------------------------------------------------*/
2289double cr2res_utils_get_center_mjd(const cpl_frameset * frameset)
2290{
2291 cpl_size nframes = 0;
2292 cpl_size i;
2293 double total, total_weight;
2294
2295 const char exptime_name[] = "EXPTIME";
2296 const char mjd_mid_name[] = "MJD-OBS";
2297
2298 if (frameset == NULL) return -1;
2299
2300
2301 total = 0;
2302 total_weight = 0;
2303
2304 // Iterate over all frames in the framelist
2305 nframes = cpl_frameset_get_size(frameset);
2306 for ( i = 0; i < nframes; i++)
2307 {
2308 const cpl_frame * frame;
2309 cpl_propertylist * pl;
2310 double exptime, mjd;
2311 const char * fname;
2312 // load the header from the frame
2313 frame = cpl_frameset_get_position_const(frameset, i);
2314 fname = cpl_frame_get_filename(frame);
2315 pl = cpl_propertylist_load(fname, 0);
2316 if (pl == NULL){
2317 cpl_msg_error(__func__, "Could not read file %s", fname);
2318 cpl_error_reset();
2319 return -1;
2320 }
2321
2322 // load the two properties from the header we care about
2323 // abort the whole function if we can't find them
2324 mjd = cpl_propertylist_get_double(pl, mjd_mid_name);
2325 if (mjd == 0){
2326 cpl_msg_error(__func__, "Property %s not found in file %s", mjd_mid_name, fname);
2327 cpl_propertylist_delete(pl);
2328 cpl_error_reset();
2329 return -1;
2330 }
2331 exptime = cpl_propertylist_get_double(pl, exptime_name);
2332 if (exptime <= 0){
2333 cpl_msg_error(__func__, "Property %s not found in file %s", exptime_name, fname);
2334 cpl_propertylist_delete(pl);
2335 cpl_error_reset();
2336 return -1;
2337 }
2338 cpl_propertylist_delete(pl);
2339
2340 // MJD is the start of the observation, but we want the middle
2341 mjd += exptime / 2.0 * SECONDS_TO_DAYS;
2342
2343 // weighted mean maths
2344 total += mjd * exptime;
2345 total_weight += exptime;
2346 }
2347
2348 // normalize by total weights
2349 total /= total_weight;
2350 return total;
2351}
2352
2353/*----------------------------------------------------------------------------*/
2361/*----------------------------------------------------------------------------*/
2362const char * cr2res_get_license(void)
2363{
2364 const char * cr2res_license =
2365 "This file is part of the CR2RES Instrument Pipeline\n"
2366 "Copyright (C) 2002,2003 European Southern Observatory\n"
2367 "\n"
2368 "This program is free software; you can redistribute it and/or modify\n"
2369 "it under the terms of the GNU General Public License as published by\n"
2370 "the Free Software Foundation; either version 2 of the License, or\n"
2371 "(at your option) any later version.\n"
2372 "\n"
2373 "This program is distributed in the hope that it will be useful,\n"
2374 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2375 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
2376 "GNU General Public License for more details.\n"
2377 "\n"
2378 "You should have received a copy of the GNU General Public License\n"
2379 "along with this program; if not, write to the Free Software\n"
2380 "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, \n"
2381 "MA 02111-1307 USA" ;
2382 return cr2res_license ;
2383}
2384
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
cpl_size cr2res_get_trace_table_index(const cpl_table *trace_wave, int order_idx, int trace_nb)
Get the index in a TRACE_WAVE table.
Definition: cr2res_trace.c:652
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_polynomial * cr2res_get_trace_wave_poly(const cpl_table *trace_wave, const char *poly_column, int order_idx, int trace_nb)
Get a polynomial from a TRACE_WAVE table.
Definition: cr2res_trace.c:685
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
double cr2res_mjd_obs_now(void)
Get the current MJD-OBS.
Definition: cr2res_utils.c:58
int cr2res_format_setting2(char *setting_id)
Format the setting.
Definition: cr2res_utils.c:190
int cr2res_format_setting(char *setting_id)
Format the setting.
Definition: cr2res_utils.c:152
double cr2res_ra_hms2deg(int hh, int mm, double ss)
Convert the RA from hh mm ss to degrees.
Definition: cr2res_utils.c:121
cpl_image * cr2res_image_cut_rectify(const cpl_image *img_in, const cpl_vector *ycen, int height)
Cut a bent order into a rectangle, shifting columns.
Definition: cr2res_utils.c:907
char * cr2res_decker_print_position(cr2res_decker dpos)
Get the decker position string for display.
int * cr2res_vector_get_int(const cpl_vector *ycen)
Definition: cr2res_utils.c:230
cpl_error_code cr2res_detector_shotnoise_model(const cpl_image *ima_data, const double gain, const double ron, cpl_image **ima_errs)
compute photon count error in [ADU]
cpl_polynomial * cr2res_fit_interorder(cpl_image *img, cpl_table *trace_wave, cpl_size order_x, cpl_size order_y)
Fit a 2D Polynomial to the interorder regions.
Definition: cr2res_utils.c:461
double cr2res_dec_hms2deg(int dd, int mm, double ss)
Convert the DEC from dd mm ss to degrees.
Definition: cr2res_utils.c:139
double cr2res_vector_get_mad(cpl_vector *invec, double *mad)
Get MAD from a vector.
Definition: cr2res_utils.c:212
cpl_polynomial * cr2res_convert_array_to_poly(const cpl_array *arr)
Convert an array to polynomial.
cpl_vector * cr2res_threshold_spec(const cpl_vector *invector, int smooth, double thresh)
Find the regions with over-average values in a vector.
double * cr2res_vector_get_rest(const cpl_vector *ycen)
Definition: cr2res_utils.c:253
cpl_vector * cr2res_polynomial_eval_vector(const cpl_polynomial *poly, const cpl_vector *vec)
Evaluate a polynomial on a vector.
int cr2res_order_idx_to_real(int order_idx, int order_zp)
Convert the order_idx into order_real.
Definition: cr2res_utils.c:89
double cr2res_utils_get_center_mjd(const cpl_frameset *frameset)
Calculate the middle of the exposures in the frameset.
cpl_array * cr2res_convert_poly_to_array(const cpl_polynomial *poly, int size)
Convert a polynomial to array.
double cr2res_util_blaze_stat(const cpl_table *blaze, int *ngood, double *blaze_tot)
Computes the average of the blaze.
cpl_image * cr2res_util_optimal_filter_2d(const cpl_image *img, const cpl_image *weight, double lam_x, double lam_y)
Apply the optimal filter in the 2D case.
int cr2res_is_short_wavelength(const char *setting_id)
Identify Short Wavelength.
Definition: cr2res_utils.c:171
char * cr2res_get_root_name(const char *filename)
Find out the root part of a basename (name without extension).
int cr2res_plot_wavecal_result(const cpl_bivector *extracted_spec, const cpl_bivector *catalog, const char *title, double wmin, double wmax)
Plot the spectrum with the catalog.
cpl_frameset * cr2res_extract_frameset_several_tags(const cpl_frameset *in, const char **tags, int ntags)
Extract the frames whose tag is within a list from a frameset.
cpl_table * cr2res_combine_extracted(const cpl_table *extracta, const cpl_table *extractb)
Combine two extracted spectra by resampling one to the other's WL.
Definition: cr2res_utils.c:278
int cr2res_slit_pos_image(const cpl_table *trace_wave, cpl_image **slitpos, cpl_image **wavelength)
get a image of the slitposition (and wavelength) along the slit
Definition: cr2res_utils.c:841
int cr2res_slit_pos(const cpl_table *trace_wave, cpl_polynomial ***coef_slit, cpl_polynomial ***coef_wave, int *size)
Create the polynomials needed to calculate the slit pos and wavelength at any point x,...
Definition: cr2res_utils.c:627
int cr2res_order_real_to_idx(int order_real, int order_zp)
Convert the order_real into order_idx.
Definition: cr2res_utils.c:102
cpl_frameset * cr2res_extract_frameset(const cpl_frameset *in, const char *tag)
Extract the frames with the given tag from a frameset.
int cr2res_image_insert_rect(const cpl_image *rect_in, const cpl_vector *ycen, cpl_image *img_out)
Re-insert a rectangular cut-out of an order into the full frame.
Definition: cr2res_utils.c:984
char * cr2res_get_base_name(const char *filename)
Find out the base name of a file (i.e. without prefix path)
cpl_polynomial * cr2res_polyfit_2d_loc(const cpl_vector *x, const cpl_vector *y, const cpl_vector *z, const cpl_matrix *degree)
Perform a 2D polynomial fit f(x, y) = z.
const char * cr2res_get_license(void)
Get the pipeline copyright and license.
void hdrl_parameter_delete(hdrl_parameter *obj)
shallow delete of a parameter
hdrl_spectrum1D * hdrl_spectrum1D_resample(const hdrl_spectrum1D *self, const hdrl_spectrum1D_wavelength *waves, const hdrl_parameter *par)
resample a hdrl_spectrum1D on the wavelengths contained in waves
hdrl_parameter * hdrl_spectrum1D_resample_interpolate_parameter_create(const hdrl_spectrum1D_interpolation_method method)
constructor for the hdrl_parameter in the case of interpolation
cpl_size hdrl_spectrum1D_get_size(const hdrl_spectrum1D *self)
hdrl_spectrum1D getter for size
void hdrl_spectrum1D_delete(hdrl_spectrum1D **p_self)
hdrl_spectrum1D destructor
hdrl_spectrum1D * hdrl_spectrum1D_convert_from_table(const cpl_table *self, const char *flux_col_name, const char *wavelength_col_name, const char *flux_e_col_name, const char *flux_bpm_col_name, hdrl_spectrum1D_wave_scale scale)
convert a table to a spectrum
cpl_error_code hdrl_spectrum1D_add_spectrum(hdrl_spectrum1D *self, const hdrl_spectrum1D *other)
sum two spectra
hdrl_spectrum1D_wavelength hdrl_spectrum1D_get_wavelength(const hdrl_spectrum1D *self)
hdrl_spectrum1D getter for wavelengths
hdrl_data_t hdrl_spectrum1D_get_wavelength_value(const hdrl_spectrum1D *self, int idx, int *rej)
hdrl_spectrum1D getter for a wavelength value
hdrl_value hdrl_spectrum1D_get_flux_value(const hdrl_spectrum1D *self, int idx, int *rej)
hdrl_spectrum1D getter for a flux value