CR2RE Pipeline Reference Manual 1.6.11
cr2res_extract.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/* Removing this pragma to give significant speedup to cal_flat
21 * Don't think its actually been needed since the original development of
22 * curved extraction. It also isn't recognized by clang and some
23 * versions of gcc.
24 * pragma GCC optimize("O0")
25*/
26
27#ifdef HAVE_CONFIG_H
28#include <config.h>
29#endif
30
31/*-----------------------------------------------------------------------------
32 Includes
33 -----------------------------------------------------------------------------*/
34#include <math.h>
35#include <cpl.h>
36
37#include "irplib_utils.h"
38
39#include "cr2res_dfs.h"
40#include "cr2res_trace.h"
41#include "cr2res_extract.h"
42#include "cr2res_wave.h"
43#include "cr2res_bpm.h"
44
45/*-----------------------------------------------------------------------------
46 Defines
47 -----------------------------------------------------------------------------*/
48
49typedef unsigned char byte;
50#define min(a,b) (((a)<(b))?(a):(b))
51#define max(a,b) (((a)>(b))?(a):(b))
52#define signum(a) (((a)>0)?1:((a)<0)?-1:0)
53#define zeta_index(x, y, z) (z * ncols * nrows) + (y * ncols) + x
54#define mzeta_index(x, y) (y * ncols) + x
55#define xi_index(x, y, z) (z * ncols * ny) + (y * ncols) + x
56
57// Alternative indexing, probably faster
58//#define zeta_index(x, y, z) (x * nrows + y) * 3*(osample+1) + z
59//#define mzeta_index(x, y) (x * nrows) + y
60//#define xi_index(x, y, z) (x * ny + y) * 4 + z
61
62
63typedef struct {
64 int x ;
65 int y ; /* Coordinates of target pixel x,y */
66 double w ; /* Contribution weight <= 1/osample */
67} xi_ref;
68
69typedef struct {
70 int x ;
71 int iy ; /* Contributing subpixel x,iy */
72 double w; /* Contribution weight <= 1/osample */
73} zeta_ref;
74
75/*-----------------------------------------------------------------------------
76 Functions prototypes
77 -----------------------------------------------------------------------------*/
78
79static int cr2res_extract_slit_func_curved(
80 double error_factor,
81 int ncols,
82 int nrows,
83 int osample,
84 double pclip,
85 double * im,
86 double * pix_unc,
87 int * mask,
88 double * ycen,
89 int * ycen_offset,
90 int y_lower_lim,
91 //double * PSF_curve,
92 cpl_polynomial ** slitcurves,
93 int delta_x,
94 double * sL,
95 double * sP,
96 double * model,
97 double * unc,
98 double lambda_sP,
99 double lambda_sL,
100 double sP_stop,
101 int maxiter,
102 double kappa,
103 const double * slit_func_in,
104 double * sP_old,
105 double * l_Aij,
106 double * p_Aij,
107 double * l_bj,
108 double * p_bj,
109 cpl_image * img_mad,
110 xi_ref * xi,
111 zeta_ref * zeta,
112 int * m_zeta) ;
113
114static int cr2res_extract_xi_zeta_tensors(
115 int ncols,
116 int nrows,
117 int ny,
118 double * ycen,
119 const int * ycen_offset,
120 int y_lower_lim,
121 int osample,
122 cpl_polynomial ** slitcurves,
123 xi_ref * xi,
124 zeta_ref * zeta,
125 int * m_zeta) ;
126
127static int cr2res_extract_slitdec_adjust_swath(
128 cpl_vector * ycen,
129 int height,
130 int leny,
131 int sw,
132 int lenx,
133 int dx,
134 cpl_vector ** bins_begin,
135 cpl_vector ** bins_end) ;
136
137static int debug_output(int ncols,
138 int nrows,
139 int osample,
140 double * im,
141 double * pix_unc,
142 int * mask,
143 double * ycen,
144 int * ycen_offset,
145 int y_lower_lim,
146 cpl_polynomial ** slitcurves);
147
148/*----------------------------------------------------------------------------*/
152/*----------------------------------------------------------------------------*/
153
156/*----------------------------------------------------------------------------*/
184/*----------------------------------------------------------------------------*/
186 const hdrl_image * img,
187 const cpl_table * traces,
188 const cpl_table * slit_func_in,
189 const cpl_table * blaze_table_in,
190 float blaze_norm,
191 int reduce_order,
192 int reduce_trace,
193 cr2res_extr_method extr_method,
194 int extr_height,
195 int swath_width,
196 int oversample,
197 double pclip,
198 double smooth_slit,
199 double smooth_spec,
200 int niter,
201 double kappa,
202 double error_factor,
203 int display,
204 int disp_order_idx,
205 int disp_trace,
206 cpl_table ** extracted,
207 cpl_table ** slit_func,
208 hdrl_image ** model_master)
209{
210 cpl_bivector ** spectrum ;
211 double * pspec ;
212 double * pspec_err ;
213 cpl_bivector * blaze_biv ;
214 cpl_bivector * blaze_err_biv ;
215 double * pblaze ;
216 double * pblaze_err ;
217 cpl_vector * tmp_vec ;
218 cpl_vector * slit_func_in_vec ;
219 cpl_vector ** slit_func_vec ;
220 cpl_table * slit_func_loc ;
221 cpl_table * extract_loc ;
222 hdrl_image * model_loc ;
223 hdrl_image * model_loc_one ;
224 double first_nonzero_value, first_nonzero_error,
225 norm_factor, val, err ;
226 int nb_traces, i, j;
227 int badpix;
228 cpl_size x, y, kth;
229 hdrl_value pixval;
230
231 /* Check Entries */
232 if (img == NULL || traces == NULL) return -1 ;
233
234 /* Initialise */
235 nb_traces = cpl_table_get_nrow(traces) ;
236
237 /* Allocate Data containers */
238 spectrum = cpl_malloc(nb_traces * sizeof(cpl_bivector *)) ;
239 slit_func_vec = cpl_malloc(nb_traces * sizeof(cpl_vector *)) ;
240 model_loc = hdrl_image_duplicate(img) ;
241 hdrl_image_mul_scalar(model_loc, (hdrl_value){0.0, 0.0}) ;
242
243 /* Loop over the traces and extract them */
244 for (i=0 ; i<nb_traces ; i++) {
245 /* Initialise */
246 int trace_id;
247 int order;
248 slit_func_vec[i] = NULL ;
249 spectrum[i] = NULL ;
250 model_loc_one = NULL ;
251
252 /* Get Order and trace id */
253 order = cpl_table_get(traces, CR2RES_COL_ORDER, i, NULL) ;
254 trace_id = cpl_table_get(traces, CR2RES_COL_TRACENB, i, NULL) ;
255
256 /* Check if this order needs to be skipped */
257 if (reduce_order > -1 && order != reduce_order) continue ;
258
259 /* Check if this trace needs to be skipped */
260 if (reduce_trace > -1 && trace_id != reduce_trace) continue ;
261
262 cpl_msg_info(__func__, "Process Order %d/Trace %d",order,trace_id) ;
263 cpl_msg_indent_more() ;
264
265 /* Get the input slit_func if available */
266 if (slit_func_in != NULL) {
267 /* Load the proper slit function vector */
268 cr2res_extract_SLIT_FUNC_get_vector(slit_func_in, order,
269 trace_id, &slit_func_in_vec) ;
270 } else {
271 slit_func_in_vec = NULL ;
272 }
273
274 /* Call the Extraction */
275 if (extr_method == CR2RES_EXTR_SUM) {
276 if (cr2res_extract_sum_vert(img, traces, order,
277 trace_id, extr_height, &(slit_func_vec[i]),
278 &(spectrum[i]), &model_loc_one) != 0) {
279 cpl_msg_error(__func__, "Cannot (sum-)extract the trace") ;
280 if (slit_func_in_vec != NULL)
281 cpl_vector_delete(slit_func_in_vec) ;
282 slit_func_vec[i] = NULL ;
283 spectrum[i] = NULL ;
284 model_loc_one = NULL ;
285 cpl_error_reset() ;
286 cpl_msg_indent_less() ;
287 continue ;
288 }
289 } else if (extr_method == CR2RES_EXTR_MEDIAN) {
290 if (cr2res_extract_median(img, traces, order,
291 trace_id, extr_height, &(slit_func_vec[i]),
292 &(spectrum[i]), &model_loc_one) != 0) {
293 cpl_msg_error(__func__, "Cannot (median-)extract the trace") ;
294 if (slit_func_in_vec != NULL)
295 cpl_vector_delete(slit_func_in_vec) ;
296 slit_func_vec[i] = NULL ;
297 spectrum[i] = NULL ;
298 model_loc_one = NULL ;
299 cpl_error_reset() ;
300 cpl_msg_indent_less() ;
301 continue ;
302 }
303 } else if (extr_method == CR2RES_EXTR_TILTSUM) {
304 if (cr2res_extract_sum_tilt(img, traces, order,
305 trace_id, extr_height, &(slit_func_vec[i]),
306 &(spectrum[i]), &model_loc_one) != 0) {
307 cpl_msg_error(__func__, "Cannot (tiltsum-)extract the trace") ;
308 if (slit_func_in_vec != NULL)
309 cpl_vector_delete(slit_func_in_vec) ;
310 slit_func_vec[i] = NULL ;
311 spectrum[i] = NULL ;
312 model_loc_one = NULL ;
313 cpl_error_reset() ;
314 cpl_msg_indent_less() ;
315 continue ;
316 }
317 } else if (extr_method == CR2RES_EXTR_OPT_CURV) {
318 if (cr2res_extract_slitdec_curved(img, traces, slit_func_in_vec,
319 order, trace_id, extr_height, swath_width,
320 oversample, pclip, smooth_slit, smooth_spec,
321 niter, kappa, error_factor,
322 &(slit_func_vec[i]),
323 &(spectrum[i]), &model_loc_one) != 0) {
324 cpl_msg_error(__func__,
325 "Cannot extract order %d, trace %d", order, trace_id) ;
326 if (slit_func_in_vec != NULL)
327 cpl_vector_delete(slit_func_in_vec) ;
328 slit_func_vec[i] = NULL ;
329 spectrum[i] = NULL ;
330 model_loc_one = NULL ;
331 cpl_error_reset() ;
332 cpl_msg_indent_less() ;
333 continue ;
334 }
335 }
336 if (slit_func_in_vec != NULL) cpl_vector_delete(slit_func_in_vec) ;
337
338 /* Correct the blaze if passed */
339 if (blaze_table_in != NULL) {
340 if (cr2res_extract_EXTRACT1D_get_spectrum(blaze_table_in, order,
341 trace_id, &blaze_biv, &blaze_err_biv)) {
342 cpl_msg_warning(__func__,
343 "Cannot Get the Blaze for order/trace:%d/%d - skip",
344 order, trace_id) ;
345 } else {
346 /* The Blaze needs to be 'cleaned from 0s before division */
347 pblaze =
348 cpl_vector_get_data(cpl_bivector_get_y(blaze_biv)) ;
349 pblaze_err =
350 cpl_vector_get_data(cpl_bivector_get_y(blaze_err_biv)) ;
351 first_nonzero_value = first_nonzero_error = 0.0 ;
352 for (j=0 ; j<cpl_bivector_get_size(blaze_biv) ; j++) {
353 if (fabs(pblaze[j])>1e-3) {
354 first_nonzero_value = pblaze[j] ;
355 first_nonzero_error = pblaze_err[j] ;
356 break ;
357 }
358 }
359 if (fabs(first_nonzero_value)<1e-3) {
360 cpl_msg_warning(__func__, "Blaze filled with zeros - skip");
361 } else {
362 for (j=0 ; j<cpl_bivector_get_size(blaze_biv) ; j++) {
363 if (fabs(pblaze[j])<1e-3) {
364 pblaze[j] = first_nonzero_value ;
365 pblaze_err[j] = first_nonzero_error ;
366 }
367 }
368
369 /* Normalize the Blaze, prefer the normalization factor given in
370 * QC FLAT BLAZE NORM if present otherwise revert to trace-wise
371 * 95th percentile normalization
372 */
373
374 if (blaze_norm > 0){
375 norm_factor = blaze_norm;
376 } else {
377 tmp_vec=cpl_vector_duplicate(cpl_bivector_get_y(blaze_biv));
378 kth = (cpl_size)(cpl_bivector_get_size(blaze_biv)*0.95) ;
379 irplib_vector_get_kth(tmp_vec, kth) ;
380 norm_factor = cpl_vector_get(tmp_vec, kth) ;
381 cpl_vector_delete(tmp_vec) ;
382 }
383
384 /* Divide by the Blaze */
385 pspec = cpl_bivector_get_x_data(spectrum[i]) ;
386 pspec_err = cpl_bivector_get_y_data(spectrum[i]);
387 for (j=0 ; j<cpl_bivector_get_size(blaze_biv) ; j++) {
388 if (fabs(pspec[j]) > 1e-3) {
389 /* Apply division by normalized blaze */
390 val = pspec[j] / (pblaze[j]/norm_factor) ;
391
392 /* Error */
393 /* err(a/b)=abs(a/b)sqrt((err_a/a)^2+(err_b/b)^2) */
394 err = fabs(val) * sqrt(((pspec_err[j]*pspec_err[j])/
395 (pspec[j]*pspec[j]))+
396 ((pblaze_err[j]*pblaze_err[j])/
397 (pblaze[j]*pblaze[j])));
398 } else {
399 val = err = 0.0 ;
400 }
401
402 /* Set Results */
403 pspec[j] = val ;
404 pspec_err[j] = err ;
405 }
406 if (cpl_error_get_code()) {
407 cpl_error_reset();
408 cpl_msg_warning(__func__,
409 "Cannot Correct Blaze for order/trace:%d/%d - skip",
410 order, trace_id) ;
411 }
412 }
413 cpl_bivector_delete(blaze_biv) ;
414 cpl_bivector_delete(blaze_err_biv) ;
415 }
416 }
417
418 /* Update the model global image */
419 if (model_loc_one != NULL) {
420 //hdrl_image_add_image(model_loc, model_loc_one) ;
421 for (x = 1; x <= hdrl_image_get_size_x(model_loc); x++){
422 for (y = 1; y <= hdrl_image_get_size_y(model_loc); y++){
423 pixval = hdrl_image_get_pixel(model_loc_one,
424 x, y, &badpix);
425 if (pixval.data != 0 && badpix == 0){
426 hdrl_image_set_pixel(model_loc, x, y, pixval);
427 }
428 }
429 }
430 hdrl_image_delete(model_loc_one) ;
431 }
432
433 /* Plot the Spectrum */
434 if (display && disp_order_idx==order && disp_trace==trace_id) {
435 cpl_plot_vector(
436 "set grid;set xlabel 'pixels';set ylabel 'Flux (ADU)';",
437 "t 'Extracted Spectrum' w lines", "",
438 cpl_bivector_get_x_const(spectrum[i])) ;
439 }
440 cpl_msg_indent_less() ;
441 }
442
443 /* Create the slit_func_tab for the current detector */
444 if ((slit_func_loc = cr2res_extract_SLITFUNC_create(slit_func_vec,
445 traces)) == NULL) {
446 cpl_msg_error(__func__, "Cannot compute the slit function") ;
447 for (i=0 ; i<nb_traces ; i++) {
448 if (slit_func_vec[i] != NULL) cpl_vector_delete(slit_func_vec[i]) ;
449 if (spectrum[i] != NULL) cpl_bivector_delete(spectrum[i]) ;
450 }
451 cpl_free(spectrum) ;
452 cpl_free(slit_func_vec) ;
453 hdrl_image_delete(model_loc) ;
454 return -1;
455 }
456
457 /* Create the extracted_tab for the current detector */
458 if ((extract_loc = cr2res_extract_EXTRACT1D_create(spectrum, traces))
459 == NULL) {
460 for (i=0 ; i<nb_traces ; i++) {
461 if (slit_func_vec[i] != NULL) cpl_vector_delete(slit_func_vec[i]) ;
462 if (spectrum[i] != NULL) cpl_bivector_delete(spectrum[i]) ;
463 }
464 cpl_free(spectrum) ;
465 cpl_free(slit_func_vec) ;
466 hdrl_image_delete(model_loc) ;
467 cpl_table_delete(slit_func_loc);
468 return -1;
469 }
470
471 /* Deallocate Vectors */
472 for (i=0 ; i<nb_traces ; i++) {
473 if (slit_func_vec[i] != NULL) cpl_vector_delete(slit_func_vec[i]) ;
474 if (spectrum[i] != NULL) cpl_bivector_delete(spectrum[i]) ;
475 }
476 cpl_free(spectrum) ;
477 cpl_free(slit_func_vec) ;
478
479 /* Return */
480 *extracted = extract_loc ;
481 *slit_func = slit_func_loc ;
482 *model_master = model_loc;
483 return 0 ;
484}
485
486/*----------------------------------------------------------------------------*/
509/*----------------------------------------------------------------------------*/
511 const hdrl_image * hdrl_in,
512 const cpl_table * trace_tab,
513 int order,
514 int trace_id,
515 int height,
516 cpl_vector ** slit_func,
517 cpl_bivector ** spec,
518 hdrl_image ** model)
519{
520 int * ycen_int;
521 cpl_vector * ycen ;
522 cpl_image * img_tmp;
523 cpl_image * img_1d;
524 const cpl_image * img_in;
525 const cpl_image * err_in;
526 cpl_vector * spc;
527 cpl_vector * slitfu;
528 cpl_vector * sigma;
529 cpl_size lenx, leny;
530 int i, j, y;
531 double trace_cen, trace_height ;
532 cpl_type imtyp;
533
534 /* Check Entries */
535 if (hdrl_in == NULL || trace_tab == NULL) return -1 ;
536
537 img_in = hdrl_image_get_image_const(hdrl_in);
538 err_in = hdrl_image_get_error_const(hdrl_in);
539
540 /* use the same type as input for temp images below */
541 imtyp = cpl_image_get_type(img_in);
542 lenx = cpl_image_get_size_x(img_in);
543 leny = cpl_image_get_size_y(img_in);
544
545 /* Compute height if not given */
546 if (height <= 0) {
547 height = cr2res_trace_get_height(trace_tab, order, trace_id);
548 if (height <= 0) {
549 cpl_msg_error(__func__, "Cannot compute height");
550 return -1;
551 }
552 }
553 /* Get ycen */
554 if ((ycen = cr2res_trace_get_ycen(trace_tab, order,
555 trace_id, lenx)) == NULL) {
556 cpl_msg_error(__func__, "Cannot get ycen");
557 return -1 ;
558 }
559 trace_cen = cpl_vector_get(ycen, cpl_vector_get_size(ycen)/2) ;
560 trace_height = (double)cr2res_trace_get_height(trace_tab, order, trace_id) ;
561 cpl_msg_info(__func__, "Y position of the trace: %g -> %g",
562 trace_cen-(trace_height/2), trace_cen+(trace_height/2)) ;
563
564 img_tmp = cr2res_image_cut_rectify(img_in, ycen, height);
565 if (img_tmp == NULL) {
566 cpl_msg_error(__func__, "Cannot rectify order");
567 cpl_vector_delete(ycen);
568 return -1;
569 }
570
571 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
572 cpl_image_save(img_tmp, "debug_rectorder.fits", imtyp,
573 NULL, CPL_IO_CREATE);
574 }
575 img_1d = cpl_image_collapse_create(img_tmp, 0); // sum of rows
576 spc = cpl_vector_new_from_image_row(img_1d, 1);
577 cpl_image_delete(img_1d);
578
579 img_1d = cpl_image_collapse_create(img_tmp, 1); // sum of columns
580 slitfu = cpl_vector_new_from_image_column(img_1d, 1);
581 cpl_vector_divide_scalar(slitfu, cpl_vector_get_sum(slitfu));
582 cpl_image_delete(img_1d);
583 cpl_image_delete(img_tmp);
584
585 img_tmp = cr2res_image_cut_rectify(err_in, ycen, height);
586 if (img_tmp == NULL) {
587 cpl_msg_error(__func__, "Cannot rectify error");
588 cpl_vector_delete(ycen);
589 return -1;
590 }
591 cpl_image_multiply(img_tmp, img_tmp);
592 img_1d = cpl_image_collapse_create(img_tmp, 0);
593 sigma = cpl_vector_new_from_image_row(img_1d, 1);
594 cpl_vector_sqrt(sigma);
595 cpl_image_delete(img_tmp);
596 cpl_image_delete(img_1d);
597
598 // reconstruct the 2d image with the "model"
599 img_tmp = cpl_image_new(lenx, leny, imtyp);
600 ycen_int = cr2res_vector_get_int(ycen);
601 for (i=1;i<=lenx;i++){
602 for (j=1;j<=height;j++){
603 y = ycen_int[i-1]-(height/2)+j;
604 if ((y <=0) || (y > leny)){ continue; }
605 cpl_image_set(img_tmp, i, y,
606 cpl_vector_get(spc,i-1)*cpl_vector_get(slitfu,j-1) );
607 }
608 }
609 cpl_vector_delete(ycen);
610 cpl_free(ycen_int);
611
612 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
613 cpl_image_save(img_tmp, "debug_model.fits", imtyp,
614 NULL, CPL_IO_CREATE);
615 }
616
617
618 *slit_func = slitfu;
619 *spec = cpl_bivector_wrap_vectors(spc, sigma);
620 *model = hdrl_image_create(img_tmp, NULL);
621 cpl_image_delete(img_tmp);
622
623 if (cpl_error_get_code() != CPL_ERROR_NONE){
624 cpl_msg_error(__func__, "Error in the vertical sum extraction %s",
625 cpl_error_get_where());
626 cpl_error_reset();
627 return -1;
628 } else {
629 return 0;
630 }
631}
632
633/*----------------------------------------------------------------------------*/
657/*----------------------------------------------------------------------------*/
659 const hdrl_image * hdrl_in,
660 const cpl_table * trace_tab,
661 int order,
662 int trace_id,
663 int height,
664 cpl_vector ** slit_func,
665 cpl_bivector ** spec,
666 hdrl_image ** model)
667{
668 int * ycen_int;
669 cpl_vector * ycen ;
670 cpl_image * img_tmp;
671 cpl_image * img_1d;
672 const cpl_image * img_in;
673 const cpl_image * err_in;
674 cpl_vector * spc;
675 cpl_vector * slitfu;
676 cpl_vector * sigma;
677 cpl_size lenx, leny;
678 int i, j;
679 double trace_cen, trace_height ;
680 cpl_type imtyp;
681
682 /* Check Entries */
683 if (hdrl_in == NULL || trace_tab == NULL) return -1 ;
684
685 img_in = hdrl_image_get_image_const(hdrl_in);
686 err_in = hdrl_image_get_error_const(hdrl_in);
687
688 /* use the same type as input for temp images below */
689 imtyp = cpl_image_get_type(img_in);
690 lenx = cpl_image_get_size_x(img_in);
691 leny = cpl_image_get_size_y(img_in);
692
693 /* Compute height if not given */
694 if (height <= 0) {
695 height = cr2res_trace_get_height(trace_tab, order, trace_id);
696 if (height <= 0) {
697 cpl_msg_error(__func__, "Cannot compute height");
698 return -1;
699 }
700 }
701 /* Get ycen */
702 if ((ycen = cr2res_trace_get_ycen(trace_tab, order,
703 trace_id, lenx)) == NULL) {
704 cpl_msg_error(__func__, "Cannot get ycen");
705 return -1 ;
706 }
707 trace_cen = cpl_vector_get(ycen, cpl_vector_get_size(ycen)/2) ;
708 trace_height = (double)cr2res_trace_get_height(trace_tab, order, trace_id) ;
709 cpl_msg_info(__func__, "Y position of the trace: %g -> %g",
710 trace_cen-(trace_height/2), trace_cen+(trace_height/2)) ;
711
712 img_tmp = cr2res_image_cut_rectify(img_in, ycen, height);
713 if (img_tmp == NULL) {
714 cpl_msg_error(__func__, "Cannot rectify order");
715 cpl_vector_delete(ycen);
716 return -1;
717 }
718
719 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
720 cpl_image_save(img_tmp, "debug_rectorder.fits", imtyp,
721 NULL, CPL_IO_CREATE);
722 }
723 img_1d = cpl_image_collapse_median_create(img_tmp, 0, 0, 0); // rows
724 spc = cpl_vector_new_from_image_row(img_1d, 1);
725
726 // Multiply so that scaling matches a vertical sum
727 cpl_vector_multiply_scalar(spc,(double)height);
728 cpl_image_delete(img_1d);
729
730 img_1d = cpl_image_collapse_median_create(img_tmp, 1, 0, 0); // cols
731 slitfu = cpl_vector_new_from_image_column(img_1d, 1);
732 cpl_vector_divide_scalar(slitfu, cpl_vector_get_sum(slitfu));
733 cpl_image_delete(img_1d);
734 cpl_image_delete(img_tmp);
735
736 img_tmp = cr2res_image_cut_rectify(err_in, ycen, height);
737 if (img_tmp == NULL)
738 {
739 cpl_msg_error(__func__, "Cannot rectify error");
740 cpl_vector_delete(ycen);
741 return -1;
742 }
743 cpl_image_multiply(img_tmp, img_tmp);
744 img_1d = cpl_image_collapse_create(img_tmp, 0);
745 sigma = cpl_vector_new_from_image_row(img_1d, 1);
746 cpl_vector_sqrt(sigma);
747 cpl_image_delete(img_tmp);
748 cpl_image_delete(img_1d);
749
750 // reconstruct the 2d image with the "model"
751 img_tmp = cpl_image_new(lenx, leny, imtyp);
752 ycen_int = cr2res_vector_get_int(ycen);
753 for (i=1;i<=lenx;i++){
754 for (j=1;j<=height;j++){
755 cpl_image_set(img_tmp, i, ycen_int[i-1]-(height/2)+j,
756 cpl_vector_get(spc,i-1)*cpl_vector_get(slitfu,j-1) );
757 }
758 }
759 cpl_vector_delete(ycen);
760 cpl_free(ycen_int);
761
762 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
763 cpl_image_save(img_tmp, "debug_model.fits", imtyp,
764 NULL, CPL_IO_CREATE);
765 }
766
767
768 *slit_func = slitfu;
769 *spec = cpl_bivector_wrap_vectors(spc, sigma);
770 *model = hdrl_image_create(img_tmp, NULL);
771 cpl_image_delete(img_tmp);
772
773 return 0;
774}
775
776/*----------------------------------------------------------------------------*/
800/*----------------------------------------------------------------------------*/
802 const hdrl_image * hdrl_in,
803 const cpl_table * trace_tab,
804 int order,
805 int trace_id,
806 int height,
807 cpl_vector ** slit_func,
808 cpl_bivector ** spec,
809 hdrl_image ** model)
810{
811 int * ycen_int;
812 cpl_vector * ycen ;
813 cpl_image * img_tmp;
814 cpl_image * img_1d;
815 const cpl_image * img_in;
816 const cpl_image * err_in;
817 cpl_vector * spc;
818 cpl_vector * slitfu;
819 cpl_vector * sigma;
820 cpl_size lenx, leny;
821 int i, j;
822 double trace_cen, trace_height ;
823 cpl_type imtyp;
824
825 int badpix;
826 double a, b, c, value;
827 cpl_polynomial * slitcurve_A, * slitcurve_B, *slitcurve_C;
828 cpl_bivector * xi, *xt;
829
830 /* Check Entries */
831 if (hdrl_in == NULL || trace_tab == NULL) return -1 ;
832
833 img_in = hdrl_image_get_image_const(hdrl_in);
834 err_in = hdrl_image_get_error_const(hdrl_in);
835
836 /* use the same type as input for temp images below */
837 imtyp = cpl_image_get_type(img_in);
838 lenx = cpl_image_get_size_x(img_in);
839 leny = cpl_image_get_size_y(img_in);
840
841 /* Compute height if not given */
842 if (height <= 0) {
843 height = cr2res_trace_get_height(trace_tab, order, trace_id);
844 if (height <= 0) {
845 cpl_msg_error(__func__, "Cannot compute height");
846 return -1;
847 }
848 }
849 /* Get ycen */
850 if ((ycen = cr2res_trace_get_ycen(trace_tab, order,
851 trace_id, lenx)) == NULL) {
852 cpl_msg_error(__func__, "Cannot get ycen");
853 return -1 ;
854 }
855 trace_cen = cpl_vector_get(ycen, cpl_vector_get_size(ycen)/2) ;
856 trace_height = (double)cr2res_trace_get_height(trace_tab, order, trace_id) ;
857 cpl_msg_info(__func__, "Y position of the trace: %g -> %g",
858 trace_cen-(trace_height/2), trace_cen+(trace_height/2)) ;
859
860 img_tmp = cr2res_image_cut_rectify(img_in, ycen, height);
861 if (img_tmp == NULL) {
862 cpl_msg_error(__func__, "Cannot rectify order");
863 cpl_vector_delete(ycen);
864 return -1;
865 }
866
867 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
868 cpl_image_save(img_tmp, "debug_rectorder.fits", imtyp,
869 NULL, CPL_IO_CREATE);
870 }
871
872 // Fix curvature if existing
873 // def correct_for_curvature(img_order, tilt, shear, xwd):
874 // img_order = np.ma.filled(img_order, 0)
875 // xt = np.arange(img_order.shape[1])
876 // for y, yt in zip(range(xwd[0] + xwd[1]), range(-xwd[0], xwd[1])):
877 // xi = xt + yt * tilt + yt ** 2 * shear
878 // img_order[y] = np.interp(xi, xt, img_order[y])
879 // return img_order
880
881 // Read the slitcurvature from the trace table
882 slitcurve_A = cr2res_get_trace_wave_poly(trace_tab, CR2RES_COL_SLIT_CURV_A,
883 order, trace_id);
884 slitcurve_B = cr2res_get_trace_wave_poly(trace_tab, CR2RES_COL_SLIT_CURV_B,
885 order, trace_id);
886 slitcurve_C = cr2res_get_trace_wave_poly(trace_tab, CR2RES_COL_SLIT_CURV_C,
887 order, trace_id);
888
889 if ((slitcurve_A == NULL) || (slitcurve_B == NULL) || (slitcurve_C == NULL))
890 {
891 cpl_msg_error(__func__,
892 "No (or incomplete) slitcurve data found in trace table");
893 cpl_vector_delete(ycen);
894 cpl_polynomial_delete(slitcurve_A);
895 cpl_polynomial_delete(slitcurve_B);
896 cpl_polynomial_delete(slitcurve_C);
897 return -1;
898 }
899
900
901 // xi is the regular coordinates
902 // xt is the shifted coordinates
903 xi = cpl_bivector_new(lenx);
904 xt = cpl_bivector_new(lenx);
905 for (i = 0; i < lenx; i++){
906 cpl_vector_set(cpl_bivector_get_x(xi), i, i);
907 cpl_vector_set(cpl_bivector_get_x(xt), i, i);
908 cpl_vector_set(cpl_bivector_get_y(xi), i, 0);
909 cpl_vector_set(cpl_bivector_get_y(xt), i, 0);
910 }
911
912 for (i = 0; i < height; i++){
913 int yt = i - height / 2 + 0.5;
914 int yc = cpl_vector_get(ycen, i);
915
916 for (j = 1; j < lenx - 1; j++){
917 //a = cpl_polynomial_eval_1d(slitcurve_A, j, NULL); this is ignored apparently?
918 b = cpl_polynomial_eval_1d(slitcurve_B, j, NULL);
919 c = cpl_polynomial_eval_1d(slitcurve_C, j, NULL);
920
921 // shift polynomial to local frame
922 // a = a - j + yc * b + yc * yc * c;
923 a = 0;
924 b += 2 * yc * c;
925
926 value = j - a - yt * b - yt * yt * c;
927 value = max(min(value, lenx-1), 0);
928 cpl_vector_set(cpl_bivector_get_x(xt), j, value);
929 value = cpl_image_get(img_tmp, j + 1, i + 1, &badpix);
930 if (badpix) value = NAN;
931 cpl_vector_set(cpl_bivector_get_y(xt), j, value);
932 }
933
934 cpl_bivector_interpolate_linear(xi, xt);
935
936 for (j = 0; j < lenx; j++){
937 value = cpl_vector_get(cpl_bivector_get_y(xi), j);
938 cpl_image_set(img_tmp, j+1, i+1, value);
939 if (isnan(value)){
940 cpl_image_set(img_tmp, j+1, i+1, 0);
941 cpl_image_reject(img_tmp, j+1, i+1);
942 }
943 }
944 }
945
946 cpl_bivector_delete(xi);
947 cpl_bivector_delete(xt);
948 cpl_polynomial_delete(slitcurve_A);
949 cpl_polynomial_delete(slitcurve_B);
950 cpl_polynomial_delete(slitcurve_C);
951
952 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
953 cpl_image_save(img_tmp, "debug_img_shifted.fits", imtyp,
954 NULL, CPL_IO_CREATE);
955 }
956
957 // Fill bad pixels with linear approximation
958 // xi is the input coordinates
959 // xt is the target coordinates
960 xi = cpl_bivector_new(height);
961 xt = cpl_bivector_new(height);
962
963 for (j = 0; j < lenx; j++){
964 // We need to set the first and last point in case they are bad pixels and need to be interpolated
965 cpl_vector_set(cpl_bivector_get_x(xi), 0, 0);
966 cpl_vector_set(cpl_bivector_get_y(xi), 0, 0);
967 cpl_vector_set(cpl_bivector_get_x(xi), height-1, height-1);
968 cpl_vector_set(cpl_bivector_get_y(xi), height-1, 0);
969 for (i = 0; i < height; i++){
970 cpl_vector_set(cpl_bivector_get_x(xt), i, i);
971 cpl_vector_set(cpl_bivector_get_y(xt), i, 0);
972
973 value = cpl_image_get(img_tmp, j+1, i+1, &badpix);
974 if (!badpix){
975 cpl_vector_set(cpl_bivector_get_x(xi), i, i);
976 cpl_vector_set(cpl_bivector_get_y(xi), i, value);
977 }
978 }
979 cpl_bivector_interpolate_linear(xt, xi);
980 for (i = 0; i < height; i++){
981 value = cpl_vector_get(cpl_bivector_get_y(xt), i);
982 cpl_image_set(img_tmp, j+1, i+1, value);
983 }
984 }
985
986 cpl_bivector_delete(xi);
987 cpl_bivector_delete(xt);
988
989 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
990 cpl_image_save(img_tmp, "debug_img_shifted_corrected.fits", imtyp,
991 NULL, CPL_IO_CREATE);
992 }
993
994 img_1d = cpl_image_collapse_create(img_tmp, 0); // sum of rows
995 spc = cpl_vector_new_from_image_row(img_1d, 1);
996 cpl_image_delete(img_1d);
997
998 img_1d = cpl_image_collapse_create(img_tmp, 1); // sum of columns
999 slitfu = cpl_vector_new_from_image_column(img_1d, 1);
1000 cpl_vector_divide_scalar(slitfu, cpl_vector_get_sum(slitfu));
1001 cpl_image_delete(img_1d);
1002 cpl_image_delete(img_tmp);
1003
1004 img_tmp = cr2res_image_cut_rectify(err_in, ycen, height);
1005 if (img_tmp == NULL)
1006 {
1007 cpl_msg_error(__func__, "Cannot rectify error");
1008 cpl_vector_delete(ycen);
1009 return -1;
1010 }
1011 cpl_image_multiply(img_tmp, img_tmp);
1012 img_1d = cpl_image_collapse_create(img_tmp, 0);
1013 sigma = cpl_vector_new_from_image_row(img_1d, 1);
1014 cpl_vector_sqrt(sigma);
1015 cpl_image_delete(img_tmp);
1016 cpl_image_delete(img_1d);
1017
1018 // reconstruct the 2d image with the "model"
1019 img_tmp = cpl_image_new(lenx, leny, imtyp);
1020 ycen_int = cr2res_vector_get_int(ycen);
1021 for (i=1;i<=lenx;i++){
1022 for (j=1;j<=height;j++){
1023 cpl_image_set(img_tmp, i, ycen_int[i-1]-(height/2)+j,
1024 cpl_vector_get(spc,i-1)*cpl_vector_get(slitfu,j-1) );
1025 }
1026 }
1027 cpl_vector_delete(ycen);
1028 cpl_free(ycen_int);
1029
1030 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
1031 cpl_image_save(img_tmp, "debug_model.fits", imtyp,
1032 NULL, CPL_IO_CREATE);
1033 }
1034
1035
1036 *slit_func = slitfu;
1037 *spec = cpl_bivector_wrap_vectors(spc, sigma);
1038 *model = hdrl_image_create(img_tmp, NULL);
1039 cpl_image_delete(img_tmp);
1040
1041 return 0;
1042}
1043
1044/*----------------------------------------------------------------------------*/
1051/*----------------------------------------------------------------------------*/
1053 cpl_bivector ** spectrum,
1054 const cpl_table * trace_table)
1055{
1056 cpl_table * out ;
1057 char * col_name ;
1058 const double * pspec ;
1059 const double * perr ;
1060 cpl_vector * wave_vec ;
1061 const double * pwl ;
1062 int nrows, all_null, i, order, trace_id, nb_traces ;
1063
1064 /* Check entries */
1065 if (spectrum == NULL || trace_table == NULL) return NULL ;
1066
1067 /* Initialise */
1068 nb_traces = cpl_table_get_nrow(trace_table) ;
1069
1070 /* Check if all vectors are not null */
1071 all_null = 1 ;
1072 for (i=0 ; i<nb_traces ; i++)
1073 if (spectrum[i] != NULL) {
1074 nrows = cpl_bivector_get_size(spectrum[i]) ;
1075 all_null = 0 ;
1076 }
1077 if (all_null == 1) return NULL ;
1078
1079 /* Check the sizes */
1080 for (i=0 ; i<nb_traces ; i++)
1081 if (spectrum[i] != NULL && cpl_bivector_get_size(spectrum[i]) != nrows)
1082 return NULL ;
1083
1084 /* Create the table */
1085 out = cpl_table_new(nrows);
1086 for (i=0 ; i<nb_traces ; i++) {
1087 order = cpl_table_get(trace_table, CR2RES_COL_ORDER, i, NULL) ;
1088 trace_id = cpl_table_get(trace_table, CR2RES_COL_TRACENB, i, NULL) ;
1089 /* Create SPEC column */
1090 col_name = cr2res_dfs_SPEC_colname(order, trace_id) ;
1091 cpl_table_new_column(out, col_name, CPL_TYPE_DOUBLE);
1092 cpl_free(col_name) ;
1093 /* Create SPEC_ERR column */
1094 col_name = cr2res_dfs_SPEC_ERR_colname(order, trace_id) ;
1095 cpl_table_new_column(out, col_name, CPL_TYPE_DOUBLE);
1096 cpl_free(col_name) ;
1097 /* Create WAVELENGTH column */
1098 col_name = cr2res_dfs_WAVELENGTH_colname(order, trace_id) ;
1099 cpl_table_new_column(out, col_name, CPL_TYPE_DOUBLE);
1100 cpl_free(col_name) ;
1101 }
1102
1103 /* Fill the table */
1104 for (i=0 ; i<nb_traces ; i++) {
1105 order = cpl_table_get(trace_table, CR2RES_COL_ORDER, i, NULL) ;
1106 trace_id = cpl_table_get(trace_table, CR2RES_COL_TRACENB, i, NULL) ;
1107 if (spectrum[i] != NULL) {
1108 pspec = cpl_bivector_get_x_data_const(spectrum[i]) ;
1109 perr = cpl_bivector_get_y_data_const(spectrum[i]);
1110 /* Fill SPEC column */
1111 col_name = cr2res_dfs_SPEC_colname(order, trace_id) ;
1112 cpl_table_copy_data_double(out, col_name, pspec) ;
1113 cpl_free(col_name) ;
1114 /* Fill SPEC_ERR column */
1115 col_name = cr2res_dfs_SPEC_ERR_colname(order, trace_id) ;
1116 cpl_table_copy_data_double(out, col_name, perr) ;
1117 cpl_free(col_name) ;
1118
1119 /* Compute Wavelength column */
1120 wave_vec = cr2res_trace_get_wl(trace_table, order, trace_id,
1121 CR2RES_DETECTOR_SIZE);
1122 if (wave_vec == NULL) {
1123 wave_vec = cpl_vector_new(CR2RES_DETECTOR_SIZE) ;
1124 cpl_vector_fill(wave_vec, 0.0) ;
1125 }
1126 pwl = cpl_vector_get_data(wave_vec) ;
1127
1128 /* Fill WAVELENGTH column */
1129 col_name = cr2res_dfs_WAVELENGTH_colname(order, trace_id) ;
1130 cpl_table_copy_data_double(out, col_name, pwl) ;
1131 cpl_free(col_name) ;
1132 cpl_vector_delete(wave_vec) ;
1133 } else {
1134 /* Fill SPEC column */
1135 col_name = cr2res_dfs_SPEC_colname(order, trace_id) ;
1136 cpl_table_fill_column_window_double(out, col_name, 0, CR2RES_DETECTOR_SIZE, NAN);
1137 cpl_table_set_column_invalid(out, col_name, 0, CR2RES_DETECTOR_SIZE);
1138 cpl_free(col_name) ;
1139 /* Fill SPEC_ERR column */
1140 col_name = cr2res_dfs_SPEC_ERR_colname(order, trace_id) ;
1141 cpl_table_fill_column_window_double(out, col_name, 0, CR2RES_DETECTOR_SIZE, NAN);
1142 cpl_table_set_column_invalid(out, col_name, 0, CR2RES_DETECTOR_SIZE);
1143 cpl_free(col_name) ;
1144 /* Fill WAVELENGTH column */
1145 col_name = cr2res_dfs_WAVELENGTH_colname(order, trace_id) ;
1146 cpl_table_fill_column_window_double(out, col_name, 0, CR2RES_DETECTOR_SIZE, NAN);
1147 cpl_table_set_column_invalid(out, col_name, 0, CR2RES_DETECTOR_SIZE);
1148 cpl_free(col_name) ;
1149 }
1150 }
1151 return out ;
1152}
1153
1154/*----------------------------------------------------------------------------*/
1161/*----------------------------------------------------------------------------*/
1163 cpl_vector ** slit_func,
1164 const cpl_table * trace_table)
1165{
1166 cpl_table * out ;
1167 char * col_name ;
1168 const double * pslit ;
1169 int nrows, nrows_max, all_null, i, order, trace_id,
1170 nb_traces ;
1171
1172 /* Check entries */
1173 if (slit_func == NULL || trace_table == NULL) return NULL ;
1174
1175 /* Initialise */
1176 nrows_max = -1 ;
1177 nb_traces = cpl_table_get_nrow(trace_table) ;
1178
1179 /* Check that all vectors are not null */
1180 all_null = 1 ;
1181 for (i=0 ; i<nb_traces ; i++)
1182 if (slit_func[i] != NULL) {
1183 nrows = cpl_vector_get_size(slit_func[i]) ;
1184 if (nrows > nrows_max) nrows_max = nrows ;
1185 all_null = 0 ;
1186 }
1187 if (all_null == 1) return NULL ;
1188
1189 /* Resize all vectors to nrows_max, otherwise cpl_table_copy_data_double
1190 accesses values outside the vector*/
1191 for (i = 0; i < nb_traces; i++)
1192 if (slit_func[i] != NULL)
1193 {
1194 nrows = cpl_vector_get_size(slit_func[i]);
1195 cpl_vector_set_size(slit_func[i], nrows_max);
1196 for (int j = nrows; j < nrows_max; j++)
1197 {
1198 cpl_vector_set(slit_func[i], j, 0.0);
1199 }
1200 }
1201
1202 /* Create the table */
1203 out = cpl_table_new(nrows_max);
1204 for (i=0 ; i<nb_traces ; i++) {
1205 order = cpl_table_get(trace_table, CR2RES_COL_ORDER, i, NULL) ;
1206 trace_id = cpl_table_get(trace_table, CR2RES_COL_TRACENB, i, NULL) ;
1207 col_name = cr2res_dfs_SLIT_FUNC_colname(order, trace_id) ;
1208 cpl_table_new_column(out, col_name, CPL_TYPE_DOUBLE);
1209 cpl_free(col_name) ;
1210 }
1211
1212 /* Fill the table */
1213 for (i=0 ; i<nb_traces ; i++) {
1214 if (slit_func[i] != NULL) {
1215 order = cpl_table_get(trace_table, CR2RES_COL_ORDER, i, NULL) ;
1216 trace_id = cpl_table_get(trace_table, CR2RES_COL_TRACENB, i, NULL) ;
1217 pslit = cpl_vector_get_data_const(slit_func[i]) ;
1218 col_name = cr2res_dfs_SLIT_FUNC_colname(order, trace_id) ;
1219 cpl_table_copy_data_double(out, col_name, pslit) ;
1220 cpl_free(col_name) ;
1221 } else {
1222 order = cpl_table_get(trace_table, CR2RES_COL_ORDER, i, NULL) ;
1223 trace_id = cpl_table_get(trace_table, CR2RES_COL_TRACENB, i, NULL) ;
1224 col_name = cr2res_dfs_SLIT_FUNC_colname(order, trace_id) ;
1225 cpl_table_fill_column_window_double(out, col_name, 0, nrows_max, NAN);
1226 cpl_table_set_column_invalid(out, col_name, 0, nrows_max);
1227 cpl_free(col_name) ;
1228 }
1229 }
1230 return out ;
1231}
1232
1233/*----------------------------------------------------------------------------*/
1243/*----------------------------------------------------------------------------*/
1245 const cpl_table * tab,
1246 int order,
1247 int trace_nb,
1248 cpl_bivector ** spec,
1249 cpl_bivector ** spec_err)
1250{
1251 char * spec_name ;
1252 char * wave_name ;
1253 char * spec_err_name ;
1254 const double * pspec ;
1255 const double * pwave ;
1256 const double * pspec_err ;
1257 double * pxspec ;
1258 double * pyspec ;
1259 double * pxspec_err ;
1260 double * pyspec_err ;
1261 int i, tab_size ;
1262
1263 /* Check entries */
1264 if (tab == NULL || spec == NULL || spec_err == NULL) return -1 ;
1265
1266 /* Get the Spectrum */
1267 spec_name = cr2res_dfs_SPEC_colname(order, trace_nb) ;
1268 if ((pspec = cpl_table_get_data_double_const(tab, spec_name)) == NULL) {
1269 cpl_msg_error(__func__, "Cannot find the spectrum") ;
1270 cpl_free(spec_name) ;
1271 return -1 ;
1272 }
1273 cpl_free(spec_name) ;
1274
1275 /* Get the Wavelength */
1276 wave_name = cr2res_dfs_WAVELENGTH_colname(order, trace_nb) ;
1277 if ((pwave = cpl_table_get_data_double_const(tab, wave_name)) == NULL) {
1278 cpl_msg_error(__func__, "Cannot find the wavelength") ;
1279 cpl_free(wave_name) ;
1280 return -1 ;
1281 }
1282 cpl_free(wave_name) ;
1283
1284 /* Get the Spectrum Error */
1285 spec_err_name = cr2res_dfs_SPEC_ERR_colname(order, trace_nb) ;
1286 if ((pspec_err = cpl_table_get_data_double_const(tab, spec_err_name))
1287 == NULL) {
1288 cpl_msg_error(__func__, "Cannot find the spectrum error") ;
1289 cpl_free(spec_err_name) ;
1290 return -1 ;
1291 }
1292 cpl_free(spec_err_name) ;
1293
1294 /* Create the output */
1295 tab_size = cpl_table_get_nrow(tab) ;
1296 *spec = cpl_bivector_new(tab_size) ;
1297 *spec_err = cpl_bivector_new(tab_size) ;
1298 pxspec = cpl_bivector_get_x_data(*spec) ;
1299 pyspec = cpl_bivector_get_y_data(*spec) ;
1300 pxspec_err = cpl_bivector_get_x_data(*spec_err) ;
1301 pyspec_err = cpl_bivector_get_y_data(*spec_err) ;
1302 for (i=0 ; i<tab_size ; i++) {
1303 pxspec[i] = pwave[i] ;
1304 pyspec[i] = pspec[i] ;
1305 pxspec_err[i] = pwave[i] ;
1306 pyspec_err[i] = pspec_err[i] ;
1307 }
1308 return 0 ;
1309}
1310
1311/*----------------------------------------------------------------------------*/
1320/*----------------------------------------------------------------------------*/
1322 const cpl_table * tab,
1323 int order,
1324 int trace_nb,
1325 cpl_vector ** vec)
1326{
1327 char * vec_name ;
1328 const double * ptab ;
1329 double * pvec ;
1330 int i, tab_size ;
1331
1332 /* Check entries */
1333 if (tab == NULL || vec == NULL) return -1 ;
1334
1335 /* Get the Vector */
1336 vec_name = cr2res_dfs_SLIT_FUNC_colname(order, trace_nb) ;
1337 if ((ptab = cpl_table_get_data_double_const(tab, vec_name)) == NULL) {
1338 cpl_msg_error(__func__, "Cannot find the slit_func") ;
1339 cpl_free(vec_name) ;
1340 cpl_error_reset() ;
1341 *vec = NULL ;
1342 return -1 ;
1343 }
1344 cpl_free(vec_name) ;
1345
1346 /* Create the output */
1347 tab_size = cpl_table_get_nrow(tab) ;
1348 *vec = cpl_vector_new(tab_size) ;
1349 pvec = cpl_vector_get_data(*vec) ;
1350 for (i=0 ; i<tab_size ; i++) pvec[i] = ptab[i] ;
1351
1352 return 0 ;
1353}
1354
1355/*----------------------------------------------------------------------------*/
1392/*----------------------------------------------------------------------------*/
1394 const hdrl_image * img_hdrl,
1395 const cpl_table * trace_tab,
1396 const cpl_vector * slit_func_vec_in,
1397 int order,
1398 int trace_id,
1399 int height,
1400 int swath,
1401 int oversample,
1402 double pclip,
1403 double smooth_slit,
1404 double smooth_spec,
1405 int niter,
1406 double kappa,
1407 double error_factor,
1408 cpl_vector ** slit_func,
1409 cpl_bivector ** spec,
1410 hdrl_image ** model)
1411{
1412 double * ycen_rest;
1413 double * ycen_sw;
1414 int * ycen_offset_sw;
1415 double * slitfu_sw_data;
1416 double * model_sw;
1417 const double * slit_func_in;
1418 int * mask_sw;
1419 const cpl_image * img_in;
1420 const cpl_image * err_in;
1421 cpl_image * img_sw;
1422 cpl_image * err_sw;
1423 cpl_image * img_rect;
1424 cpl_image * err_rect;
1425 cpl_image * model_rect;
1426 cpl_vector * ycen ;
1427 cpl_image * img_out;
1428 cpl_vector * slitfu_sw;
1429 cpl_vector * unc_sw;
1430 cpl_vector * spc;
1431 cpl_vector * slitfu;
1432 cpl_vector * weights_sw;
1433 cpl_vector * tmp_vec;
1434 cpl_vector * bins_begin;
1435 cpl_vector * bins_end;
1436 cpl_vector * unc_decomposition;
1437 cpl_size lenx, leny, pow;
1438 cpl_type imtyp;
1439 cpl_polynomial *slitcurve_A, *slitcurve_B, *slitcurve_C;
1440 cpl_polynomial ** slitcurves_sw;
1441 hdrl_image * model_out;
1442 cpl_bivector * spectrum_loc;
1443 double * sP_old;
1444 double * l_Aij;
1445 double * p_Aij;
1446 double * l_bj;
1447 double * p_bj;
1448 cpl_image * img_mad;
1449 xi_ref * xi;
1450 zeta_ref * zeta;
1451 int * m_zeta;
1452 char * path;
1453 double pixval, errval;
1454 double trace_cen, trace_height;
1455 int i, j, k, nswaths, col, x, y, ny_os,
1456 badpix, delta_x;
1457 int ny, nx;
1458
1459
1460 /* Check Entries */
1461 if (img_hdrl == NULL || trace_tab == NULL) return -1 ;
1462
1463 if (smooth_slit == 0.0) {
1464 cpl_msg_error(__func__, "Slit-smoothing cannot be 0.0");
1465 return -1;
1466 } else if (smooth_slit < 0.1) {
1467 cpl_msg_warning(__func__, "Slit-smoothing unreasonably small");
1468 } else if (smooth_slit > 100.0) {
1469 cpl_msg_warning(__func__, "Slit-smoothing unreasonably big");
1470 }
1471 if (oversample < 3){
1472 cpl_msg_error(__func__, "Oversampling too small");
1473 return -1;
1474 } else if (oversample > 15) {
1475 cpl_msg_warning(__func__, "Large oversampling, runtime will be long");
1476 }
1477 if (niter < 5){
1478 cpl_msg_warning(__func__,
1479 "Allowing at least 5 iterations is recommended.");
1480 }
1481 if (kappa < 4){
1482 cpl_msg_warning(__func__,
1483 "Rejecting outliers < 4 sigma risks making good data.");
1484 }
1485 img_in = hdrl_image_get_image_const(img_hdrl);
1486 err_in = hdrl_image_get_error_const(img_hdrl);
1487
1488 /* Initialise */
1489 imtyp = cpl_image_get_type(img_in);
1490 lenx = cpl_image_get_size_x(img_in);
1491 leny = cpl_image_get_size_y(img_in);
1492
1493 /* Compute height if not given */
1494 if (height <= 0) {
1495 height = cr2res_trace_get_height(trace_tab, order, trace_id);
1496 if (height <= 0) {
1497 cpl_msg_error(__func__, "Cannot compute height");
1498 return -1;
1499 }
1500 }
1501 if (height > leny){
1502 height = leny;
1503 cpl_msg_warning(__func__,
1504 "Given height larger than image, clipping height");
1505 }
1506
1507 /* Get ycen */
1508 if ((ycen = cr2res_trace_get_ycen(trace_tab, order,
1509 trace_id, lenx)) == NULL) {
1510 cpl_msg_error(__func__, "Cannot get ycen");
1511 return -1 ;
1512 }
1513 trace_cen = cpl_vector_get(ycen, cpl_vector_get_size(ycen)/2) ;
1514 trace_height = (double)cr2res_trace_get_height(trace_tab, order, trace_id) ;
1515 cpl_msg_info(__func__, "Y position of the trace: %g -> %g",
1516 trace_cen-(trace_height/2), trace_cen+(trace_height/2)) ;
1517 if (trace_cen-(height/2) < 0.0 ||
1518 trace_cen+(height/2) > CR2RES_DETECTOR_SIZE) {
1519 cpl_msg_error(__func__, "Extraction outside detector edges impossible");
1520 cpl_vector_delete(ycen);
1521 return -1;
1522 }
1523
1524 // Get cut-out rectified order
1525 img_rect = cr2res_image_cut_rectify(img_in, ycen, height);
1526 if (img_rect == NULL){
1527 cpl_msg_error(__func__, "Cannot rectify order");
1528 cpl_vector_delete(ycen);
1529 return -1;
1530 }
1531 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
1532 cpl_image_save(img_rect, "debug_rectorder_curved.fits", imtyp,
1533 NULL, CPL_IO_CREATE);
1534 }
1535 err_rect = cr2res_image_cut_rectify(err_in, ycen, height);
1536 ycen_rest = cr2res_vector_get_rest(ycen);
1537
1538 /* Retrieve the polynomials that describe the slit tilt and curvature*/
1539 slitcurve_A = cr2res_get_trace_wave_poly(trace_tab, CR2RES_COL_SLIT_CURV_A,
1540 order, trace_id);
1541 slitcurve_B = cr2res_get_trace_wave_poly(trace_tab, CR2RES_COL_SLIT_CURV_B,
1542 order, trace_id);
1543 slitcurve_C = cr2res_get_trace_wave_poly(trace_tab, CR2RES_COL_SLIT_CURV_C,
1544 order, trace_id);
1545 if ((slitcurve_A == NULL) || (slitcurve_B == NULL) || (slitcurve_C == NULL))
1546 {
1547 cpl_msg_error(__func__,
1548 "No (or incomplete) slitcurve data found in trace table");
1549 cpl_vector_delete(ycen);
1550 cpl_free(ycen_rest) ;
1551 cpl_image_delete(err_rect) ;
1552 cpl_image_delete(img_rect) ;
1553 cpl_polynomial_delete(slitcurve_A);
1554 cpl_polynomial_delete(slitcurve_B);
1555 cpl_polynomial_delete(slitcurve_C);
1556 return -1;
1557 }
1558
1559 /* Maximum horizontal shift in detector pixels due to slit image curv. */
1560 delta_x=0;
1561 for (i=1; i<=lenx; i+=swath/2){
1562 double delta_tmp, a, b, c, yc;
1563 /* Do a coarse sweep through the order and evaluate the slitcurve */
1564 /* polynomials at +- height/2, update the value. */
1565 /* Note: The index i is subtracted from a because the polys have */
1566 /* their origin at the edge of the full frame */
1567 //a = cpl_polynomial_eval_1d(slitcurve_A, i, NULL); this is ignored apparently?
1568 b = cpl_polynomial_eval_1d(slitcurve_B, i, NULL);
1569 c = cpl_polynomial_eval_1d(slitcurve_C, i, NULL);
1570 yc = cpl_vector_get(ycen, i-1);
1571
1572 // Shift polynomial to local frame
1573 // We fix a to 0, see comment later on, when we create the
1574 // polynomials for the extraction
1575 a = 0;
1576 b += 2 * yc * c;
1577
1578 delta_tmp = max( fabs(a + (c*height/2. + b)*height/2.),
1579 fabs(a + (c*height/-2. + b)*height/-2.));
1580 if (delta_tmp > delta_x) delta_x = (int)ceil(delta_tmp);
1581 }
1582 delta_x += 1;
1583 cpl_msg_debug(__func__, "Max delta_x from slit curv: %d pix.", delta_x);
1584
1585 if (delta_x >= swath / 4){
1586 cpl_msg_error(__func__,
1587 "Curvature is larger than the swath, try again with a larger swath size");
1588 cpl_vector_delete(ycen);
1589 cpl_free(ycen_rest) ;
1590 cpl_image_delete(err_rect) ;
1591 cpl_image_delete(img_rect) ;
1592 cpl_polynomial_delete(slitcurve_A);
1593 cpl_polynomial_delete(slitcurve_B);
1594 cpl_polynomial_delete(slitcurve_C);
1595 return -1;
1596 }
1597
1598 /* Number of rows after oversampling */
1599 ny_os = oversample*(height+1) +1;
1600 if ((swath = cr2res_extract_slitdec_adjust_swath(ycen, height, leny, swath,
1601 lenx, delta_x, &bins_begin, &bins_end)) == -1){
1602 cpl_msg_error(__func__, "Cannot calculate swath size");
1603 cpl_vector_delete(ycen);
1604 cpl_free(ycen_rest) ;
1605 cpl_image_delete(err_rect) ;
1606 cpl_image_delete(img_rect) ;
1607 cpl_polynomial_delete(slitcurve_A);
1608 cpl_polynomial_delete(slitcurve_B);
1609 cpl_polynomial_delete(slitcurve_C);
1610 return -1;
1611 }
1612 nswaths = cpl_vector_get_size(bins_begin);
1613
1614 /* Use existing slitfunction if given */
1615 slit_func_in = NULL;
1616 if (slit_func_vec_in != NULL) {
1617 cpl_size size;
1618 size = cpl_vector_get_size(slit_func_vec_in);
1619 if (size == ny_os){
1620 slit_func_in = cpl_vector_get_data_const(slit_func_vec_in);
1621 } else {
1622 cpl_msg_warning(__func__, "Ignoring the given slit_func since it is"
1623 " of the wrong size, expected %i but got %lli points.",
1624 ny_os, size);
1625 }
1626 }
1627
1628 /* Allocate */
1629 mask_sw = cpl_malloc(height * swath*sizeof(int));
1630 model_sw = cpl_malloc(height * swath*sizeof(double));
1631 unc_sw = cpl_vector_new(swath);
1632 img_sw = cpl_image_new(swath, height, CPL_TYPE_DOUBLE);
1633 err_sw = cpl_image_new(swath, height, CPL_TYPE_DOUBLE);
1634 ycen_sw = cpl_malloc(swath*sizeof(double));
1635 ycen_offset_sw = cpl_malloc(swath * sizeof(int));
1636
1637 slitcurves_sw = cpl_malloc(swath * sizeof(cpl_polynomial*));
1638 for (i=0; i<swath; i++) slitcurves_sw[i]= cpl_polynomial_new(1);
1639
1640 // Local versions of return data
1641 slitfu = cpl_vector_new(ny_os);
1642 spectrum_loc = cpl_bivector_new(lenx);
1643 spc = cpl_bivector_get_x(spectrum_loc);
1644 unc_decomposition = cpl_bivector_get_y(spectrum_loc);
1645 for (j=0; j<lenx ; j++){
1646 cpl_vector_set(spc, j, 0.);
1647 cpl_vector_set(unc_decomposition, j, 0.);
1648 }
1649 model_out = hdrl_image_new(lenx, leny);
1650 img_out = hdrl_image_get_image(model_out);
1651 model_rect = cpl_image_new(lenx, height, CPL_TYPE_DOUBLE);
1652
1653 // Work vectors
1654 slitfu_sw = cpl_vector_new(ny_os);
1655 for (j=0; j < ny_os; j++) cpl_vector_set(slitfu_sw, j, 0);
1656 slitfu_sw_data = cpl_vector_get_data(slitfu_sw);
1657 weights_sw = cpl_vector_new(swath);
1658 for (i = 0; i < swath; i++) cpl_vector_set(weights_sw, i, 0);
1659
1660 /* Pre-calculate the weights for overlapping swaths*/
1661 for (i=delta_x; i < swath/2; i++) {
1662 j = i - delta_x + 1;
1663 cpl_vector_set(weights_sw, i, j);
1664 cpl_vector_set(weights_sw, swath - i - 1, j);
1665 }
1666 // normalize such that max(w)=1
1667 cpl_vector_divide_scalar(weights_sw, swath/2 - delta_x + 1);
1668
1669 // assert cpl_vector_get_sum(weights_sw) == swath / 2 - delta_x
1670 // Assign memory for extract_curved algorithm
1671 // Since the arrays always have the same size, we can reuse allocated memory
1672 ny = oversample * (height + 1) + 1;
1673 nx = 4 * delta_x + 1;
1674 if(nx < 3) nx = 3;
1675
1676 sP_old = cpl_malloc(swath * sizeof(double));
1677 l_Aij = cpl_malloc(ny * (4*oversample+1) * sizeof(double));
1678 p_Aij = cpl_malloc(swath * nx * sizeof(double));
1679 l_bj = cpl_malloc(ny * sizeof(double));
1680 p_bj = cpl_malloc(swath * sizeof(double));
1681 img_mad = cpl_image_new(swath, height, CPL_TYPE_DOUBLE);
1682
1683 /*
1684 Convolution tensor telling the coordinates of detector pixels on which
1685 {x, iy} element falls and the corresponding projections. [ncols][ny][4]
1686 */
1687 xi = cpl_malloc(swath * ny * 4 * sizeof(xi_ref));
1688
1689 /* Convolution tensor telling the coordinates of subpixels {x, iy}
1690 contributing to detector pixel {x, y}. [ncols][nrows][3*(osample+1)]
1691 */
1692 zeta = cpl_malloc(swath * height * 3 * (oversample + 1)
1693 * sizeof(zeta_ref));
1694
1695 /* The actual number of contributing elements in zeta [ncols][nrows] */
1696 m_zeta = cpl_malloc(swath * height * sizeof(int));
1697
1698 for (i = 0; i < nswaths; i++) {
1699 double *img_sw_data;
1700 double *err_sw_data;
1701 double *spec_sw_data;
1702 double *unc_sw_data;
1703
1704 cpl_image *img_tmp;
1705 cpl_vector *spec_sw;
1706 cpl_vector *spec_tmp;
1707
1708 int sw_start, sw_end, y_lower_limit;
1709
1710 double img_sum;
1711
1712 sw_start = cpl_vector_get(bins_begin, i);
1713 sw_end = cpl_vector_get(bins_end, i);
1714
1715 /* Prepare swath cut-outs and auxiliary data */
1716 for(col=1; col<=swath; col++){ // col is x-index in swath
1717 x = sw_start + col; // coords in large image
1718
1719 /* prepare signal, error and mask */
1720 for(y=1;y<=height;y++){
1721 errval = cpl_image_get(err_rect, x, y, &badpix);
1722 if (isnan(errval) || badpix){
1723 // default to errval of 1 instead of 0
1724 // this avoids division by 0
1725 errval = 1;
1726 }
1727 pixval = cpl_image_get(img_rect, x, y, &badpix);
1728 if (isnan(pixval) || badpix){
1729 // We set bad pixels to neg. infinity, to make sure they are
1730 // rejected in the extraction
1731 // The algorithm does not like NANs!
1732 badpix = 1;
1733 pixval = -DBL_MAX;
1734 errval = 1;
1735 }
1736 cpl_image_set(img_sw, col, y, pixval);
1737 cpl_image_set(err_sw, col, y, errval);
1738 if (badpix){
1739 // Reject the pixel here, so it is not used for the initial
1740 // guess of the spectrum
1741 cpl_image_reject(img_sw, col, y);
1742 }
1743
1744 // raw index for mask, start with 0!
1745 j = (y-1)*swath + (col-1) ;
1746 // The mask value is inverted for the extraction
1747 // 1 for good pixel and 0 for bad pixel
1748 mask_sw[j] = !badpix;
1749 }
1750
1751 /* set slit curvature polynomials */
1752 /* subtract col because we want origin relative to here */
1753 pow = 2;
1754 cpl_polynomial_set_coeff(slitcurves_sw[col-1], &pow,
1755 cpl_polynomial_eval_1d(slitcurve_C, x, NULL));
1756 pow = 1;
1757 cpl_polynomial_set_coeff(slitcurves_sw[col-1], &pow,
1758 cpl_polynomial_eval_1d(slitcurve_B, x, NULL));
1759 pow = 0;
1760 cpl_polynomial_set_coeff(slitcurves_sw[col-1], &pow,
1761 cpl_polynomial_eval_1d(slitcurve_A, x, NULL) - x);
1762
1763 // Shift polynomial to local frame
1764 // -------------------------------
1765 // The slit curvature has been determined in the global reference
1766 // frame, with the a coefficient set to 0 in the local frame.
1767 // The following transformation will shift it into the local frame
1768 // again and should result in a = 0.
1769 // a - x + yc * b + yc * yc * c
1770 // However this only works, as long as ycen
1771 // is the same ycen that was used for the slitcurvature. If e.g. we
1772 // switch traces, then ycen will change and a will be unequal 0.
1773 // in fact a will be the offset due to the curvature between the
1774 // old ycen and the new. This will then cause an offset in the
1775 // pixels used for the extraction, so that all traces will have the
1776 // same spectrum, with no relative offsets.
1777 // Which would be great, if we didn't have an offset in the
1778 // wavelength calibration of the different traces.
1779 // Therefore we force a to be 0 in the local frame regardless of
1780 // ycen. For the extraction we only need the b and c coefficient
1781 // anyways.
1782 // Note that this means, we use the curvature a few pixels offset.
1783 // Usually this is no problem, since it only varies slowly over the
1784 // order.
1785 cpl_polynomial_shift_1d(slitcurves_sw[col-1], 0,
1786 cpl_vector_get(ycen, x-1));
1787 cpl_polynomial_set_coeff(slitcurves_sw[col-1], &pow, 0);
1788 }
1789
1790 for (j=0; j< height * swath; j++) model_sw[j] = 0;
1791 img_sw_data = cpl_image_get_data_double(img_sw);
1792 err_sw_data = cpl_image_get_data_double(err_sw);
1793 unc_sw_data = cpl_vector_get_data(unc_sw);
1794 // First guess for the spectrum
1795 // img_tmp = cpl_image_collapse_median_create(img_sw, 0, 0, 0);
1796 img_tmp = cpl_image_collapse_median_create(img_sw, 0, 0, 0);
1797 spec_tmp = cpl_vector_new_from_image_row(img_tmp, 1);
1798 cpl_vector_multiply_scalar(spec_tmp,
1799 (double)cpl_image_get_size_y(img_sw));
1800 spec_sw = cpl_vector_filter_median_create(spec_tmp, 1);
1801 cpl_vector_delete(spec_tmp);
1802 cpl_image_delete(img_tmp);
1803 spec_sw_data = cpl_vector_get_data(spec_sw);
1804
1805 for (j=sw_start;j<sw_end;j++){
1806 ycen_sw[j-sw_start] = ycen_rest[j];
1807 ycen_offset_sw[j-sw_start] = (int) cpl_vector_get(ycen, j);
1808 }
1809 y_lower_limit = height / 2;
1810
1811 img_tmp = cpl_image_wrap_int(swath, height, mask_sw);
1812 img_sum = cpl_image_get_flux(img_tmp);
1813 if (img_sum < 0.5 * swath*height){
1814 cpl_msg_error(__func__,
1815 "Only %.0f %% of pixels not masked, cannot extract",
1816 100*img_sum/(swath*height));
1817 cpl_image_unwrap(img_tmp);
1818 cpl_vector_delete(spec_sw);
1819 break;
1820 }
1821 if (cpl_msg_get_level() == CPL_MSG_DEBUG)
1822 {
1823 cpl_image_save(img_tmp, "debug_mask_before_sw.fits", CPL_TYPE_INT, NULL, CPL_IO_CREATE);
1824 cpl_vector_save(spec_sw, "debug_spc_initial_guess.fits",
1825 CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
1826 }
1827 cpl_image_unwrap(img_tmp);
1828
1829 /* Finally ready to call the slit-decomp */
1830 cr2res_extract_slit_func_curved(error_factor, swath, height, oversample, pclip,
1831 img_sw_data, err_sw_data, mask_sw, ycen_sw, ycen_offset_sw,
1832 y_lower_limit, slitcurves_sw, delta_x, slitfu_sw_data,
1833 spec_sw_data, model_sw, unc_sw_data, smooth_spec, smooth_slit,
1834 5.e-5, niter, kappa, slit_func_in, sP_old, l_Aij, p_Aij, l_bj,
1835 p_bj, img_mad, xi, zeta, m_zeta);
1836
1837 // add up slit-functions, divide by nswaths below to get average
1838 if (i==0) cpl_vector_copy(slitfu,slitfu_sw);
1839 else cpl_vector_add(slitfu,slitfu_sw);
1840
1841 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
1842 path = cpl_sprintf("debug_spc_%i.fits", i);
1843 cpl_vector_save(spec_sw, path , CPL_TYPE_DOUBLE, NULL,
1844 CPL_IO_CREATE);
1845 cpl_free(path);
1846
1847 path = cpl_sprintf("debug_mask_%i.fits", i);
1848 img_tmp = cpl_image_wrap_int(swath, height, mask_sw);
1849 cpl_image_save(img_tmp, path, CPL_TYPE_INT, NULL, CPL_IO_CREATE);
1850 cpl_free(path);
1851 cpl_image_unwrap(img_tmp);
1852
1853 tmp_vec = cpl_vector_wrap(swath, ycen_sw);
1854 path = cpl_sprintf("debug_ycen_%i.fits", i);
1855 cpl_vector_save(tmp_vec, path, CPL_TYPE_DOUBLE, NULL,
1856 CPL_IO_CREATE);
1857 cpl_vector_unwrap(tmp_vec);
1858 cpl_free(path);
1859
1860 cpl_vector_save(weights_sw, "debug_weights.fits", CPL_TYPE_DOUBLE,
1861 NULL, CPL_IO_CREATE);
1862 path = cpl_sprintf("debug_slitfu_%i.fits", i);
1863 cpl_vector_save(slitfu_sw, path, CPL_TYPE_DOUBLE,
1864 NULL, CPL_IO_CREATE);
1865 cpl_free(path);
1866
1867 path = cpl_sprintf("debug_model_%i.fits", i);
1868 img_tmp = cpl_image_wrap_double(swath, height, model_sw);
1869 cpl_image_save(img_tmp, path, CPL_TYPE_DOUBLE,
1870 NULL, CPL_IO_CREATE);
1871 cpl_image_unwrap(img_tmp);
1872 cpl_free(path);
1873
1874 path = cpl_sprintf("debug_img_sw_%i.fits", i);
1875 cpl_image_save(img_sw, path, CPL_TYPE_DOUBLE, NULL,
1876 CPL_IO_CREATE);
1877 cpl_free(path);
1878
1879 path = cpl_sprintf("debug_img_mad_%i.fits", i);
1880 cpl_image_save(img_mad, path, CPL_TYPE_DOUBLE, NULL,
1881 CPL_IO_CREATE);
1882 cpl_free(path);
1883 }
1884
1885 // The last bins are shifted, overwriting the first k values
1886 // this is the same amount the bin was shifted to the front before
1887 // (when creating the bins)
1888 // The duplicate values in the vector will not matter as they are
1889 // not used below
1890 if ((i == nswaths - 1) && (i != 0)){
1891 k = cpl_vector_get(bins_end, i-1) -
1892 cpl_vector_get(bins_begin, i) - swath / 2 - delta_x;
1893
1894 for (j = 0; j < swath - k; j++){
1895 cpl_vector_set(spec_sw, j, cpl_vector_get(spec_sw, j + k));
1896 cpl_vector_set(unc_sw, j, cpl_vector_get(unc_sw, j + k));
1897 for (y = 0; y < height; y++)
1898 model_sw[y * swath + j] = model_sw[y * swath + j + k];
1899 }
1900 sw_start = cpl_vector_get(bins_begin, i-1) + swath / 2 - delta_x;
1901 cpl_vector_set(bins_begin, i, sw_start);
1902 // for the following k's
1903 cpl_vector_set(bins_end, i, lenx);
1904 }
1905
1906 if (nswaths==1) ; // no weighting if only one swath
1907 else if (i==0){ // first and last half swath are not weighted
1908 for (j = 0; j < delta_x; j++)
1909 {
1910 cpl_vector_set(spec_sw, j, 0);
1911 cpl_vector_set(unc_sw, j, 0.);
1912 for (y = 0; y < height; y++) model_sw[y * swath + j] = 0;
1913 }
1914 for (j = swath/2; j < swath; j++) {
1915 cpl_vector_set(spec_sw, j,
1916 cpl_vector_get(spec_sw,j) * cpl_vector_get(weights_sw,j));
1917 cpl_vector_set(unc_sw, j,
1918 cpl_vector_get(unc_sw, j) * cpl_vector_get(weights_sw, j));
1919 for (y = 0; y < height; y++) {
1920 model_sw[y * swath + j] *= cpl_vector_get(weights_sw, j);
1921 }
1922 }
1923 } else if (i == nswaths - 1) {
1924 for (j = sw_end-sw_start-1; j >= sw_end-sw_start-delta_x-1; j--)
1925 {
1926 cpl_vector_set(spec_sw, j, 0);
1927 cpl_vector_set(unc_sw, j, 0);
1928 for (y = 0; y < height; y++) model_sw[y * swath + j] = 0;
1929 }
1930 for (j = 0; j < swath / 2; j++) {
1931 cpl_vector_set(spec_sw, j,
1932 cpl_vector_get(spec_sw,j) * cpl_vector_get(weights_sw,j));
1933 cpl_vector_set(unc_sw, j,
1934 cpl_vector_get(unc_sw,j) * cpl_vector_get(weights_sw,j));
1935 for (y = 0; y < height; y++) {
1936 model_sw[y * swath + j] *= cpl_vector_get(weights_sw,j);
1937 }
1938 }
1939 } else {
1940 /* Multiply by weights and add to output array */
1941 cpl_vector_multiply(spec_sw, weights_sw);
1942 cpl_vector_multiply(unc_sw, weights_sw);
1943 for (y = 0; y < height; y++) {
1944 for (j = 0; j < swath; j++){
1945 model_sw[y * swath + j] *= cpl_vector_get(weights_sw,j);
1946 }
1947 }
1948 }
1949
1950 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
1951 img_tmp = cpl_image_wrap_double(swath, height, model_sw);
1952 cpl_image_save(img_tmp, "debug_model_after_sw.fits", CPL_TYPE_DOUBLE,
1953 NULL, CPL_IO_CREATE);
1954 cpl_image_unwrap(img_tmp);
1955 }
1956
1957 // Save swath to output vector
1958 for (j=sw_start;j<sw_end;j++) {
1959 cpl_vector_set(spc, j,
1960 cpl_vector_get(spec_sw, j-sw_start) + cpl_vector_get(spc, j));
1961 // just add weighted errors (instead of squared sum)
1962 // as they are not independent
1963 cpl_vector_set(unc_decomposition, j,
1964 cpl_vector_get(unc_sw, j - sw_start)
1965 + cpl_vector_get(unc_decomposition, j));
1966
1967 for(y = 0; y < height; y++){
1968 cpl_image_set(model_rect, j+1, y+1,
1969 cpl_image_get(model_rect, j+1, y+1, &badpix)
1970 + model_sw[y * swath + j - sw_start]);
1971 if (badpix) cpl_image_reject(model_rect, j+1, y+1);
1972 }
1973 }
1974
1975 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
1976 cpl_image_save(model_rect, "debug_model_after_merge.fits",
1977 CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
1978 }
1979
1980 cpl_vector_delete(spec_sw);
1981 } // End loop over swaths
1982
1983 // divide by nswaths to make the slitfu into the average over all swaths.
1984 cpl_vector_divide_scalar(slitfu, nswaths);
1985
1986 // Deallocate loop memory
1987 cpl_image_delete(img_mad);
1988 cpl_free(sP_old);
1989 cpl_free(l_Aij);
1990 cpl_free(p_Aij);
1991 cpl_free(l_bj);
1992 cpl_free(p_bj);
1993
1994 cpl_free(xi);
1995 cpl_free(zeta);
1996 cpl_free(m_zeta);
1997
1998 cpl_image_delete(img_rect);
1999 cpl_image_delete(err_rect);
2000 cpl_image_delete(img_sw);
2001 cpl_image_delete(err_sw);
2002
2003 cpl_free(mask_sw);
2004 cpl_free(model_sw);
2005 cpl_vector_delete(unc_sw);
2006 cpl_free(ycen_rest);
2007 cpl_free(ycen_sw);
2008 cpl_free(ycen_offset_sw);
2009
2010 cpl_vector_delete(bins_begin);
2011 cpl_vector_delete(bins_end);
2012 cpl_vector_delete(slitfu_sw);
2013 cpl_vector_delete(weights_sw);
2014
2015 cpl_polynomial_delete(slitcurve_A);
2016 cpl_polynomial_delete(slitcurve_B);
2017 cpl_polynomial_delete(slitcurve_C);
2018 for (i=0; i<swath; i++) cpl_polynomial_delete(slitcurves_sw[i]);
2019 cpl_free(slitcurves_sw);
2020
2021 // insert model_rect into large frame
2022 if (cr2res_image_insert_rect(model_rect, ycen, img_out) == -1) {
2023 // Cancel
2024 cpl_msg_error(__func__, "failed to reinsert model swath into model image");
2025 cpl_image_delete(model_rect);
2026 hdrl_image_delete(model_out);
2027 cpl_vector_delete(ycen);
2028 cpl_bivector_delete(spectrum_loc);
2029 cpl_vector_delete(slitfu);
2030 return -1;
2031 }
2032
2033 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
2034 cpl_image_save(model_rect, "debug_model_rect.fits", CPL_TYPE_DOUBLE,
2035 NULL, CPL_IO_CREATE);
2036 cpl_image_save(img_out, "debug_model_all.fits", CPL_TYPE_DOUBLE,
2037 NULL, CPL_IO_CREATE);
2038 cpl_vector_save(spc, "debug_spc_all.fits", CPL_TYPE_DOUBLE,
2039 NULL, CPL_IO_CREATE);
2040 }
2041
2042 cpl_image_delete(model_rect);
2043 cpl_vector_delete(ycen);
2044
2045 if (cpl_error_get_code() != CPL_ERROR_NONE){
2046 cpl_msg_error(__func__,
2047 "Something went wrong in the extraction. Error Code: %i, loc: %s",
2048 cpl_error_get_code(), cpl_error_get_where());
2049 cpl_error_reset();
2050 cpl_vector_delete(slitfu);
2051 cpl_bivector_delete(spectrum_loc);
2052 hdrl_image_delete(model_out);
2053 return -1;
2054 }
2055
2056 *slit_func = slitfu;
2057 *spec = spectrum_loc;
2058 *model = model_out;
2059 return 0;
2060}
2061
2062
2063/*-------------------------------------------------------------------------*/
2064/*-------------------- EXTRACT 2d ------------------------------*/
2065/*-------------------------------------------------------------------------*/
2066
2067/*-------------------------------------------------------------------------*/
2079/*--------------------------------------------------------------------------*/
2081 const hdrl_image * img,
2082 const cpl_table * traces,
2083 int reduce_order,
2084 int reduce_trace,
2085 cpl_table ** extracted)
2086{
2087 cpl_bivector ** spectrum ;
2088 cpl_bivector ** position ;
2089 cpl_vector ** wavelength ;
2090 cpl_vector ** slit_fraction ;
2091 cpl_table * extract_loc ;
2092 cpl_image * wavemap;
2093 cpl_image * slitmap;
2094 int nb_traces, i, npoints ;
2095
2096 /* Check Entries */
2097 if (img == NULL || traces == NULL) return -1 ;
2098
2099 /* Initialise */
2100 nb_traces = cpl_table_get_nrow(traces) ;
2101 npoints = CR2RES_DETECTOR_SIZE * CR2RES_DETECTOR_SIZE / nb_traces;
2102
2103 /* Allocate Data containers */
2104 spectrum = cpl_malloc(nb_traces * sizeof(cpl_bivector *)) ;
2105 position = cpl_malloc(nb_traces * sizeof(cpl_bivector *)) ;
2106 wavelength = cpl_malloc(nb_traces * sizeof(cpl_vector *)) ;
2107 slit_fraction = cpl_malloc(nb_traces * sizeof(cpl_vector *)) ;
2108
2109 // Calculate wavelength and slitfunction map once
2110 if (cr2res_slit_pos_image(traces, &slitmap, &wavemap) != 0)
2111 {
2112 cpl_msg_error(__func__,
2113 "Could not create wavelength / slit_fraction image");
2114 cpl_free(spectrum);
2115 cpl_free(position);
2116 cpl_free(wavelength);
2117 cpl_free(slit_fraction);
2118 return -1;
2119 }
2120
2121 /* Loop over the traces and extract them */
2122 for (i=0 ; i<nb_traces ; i++) {
2123 /* Initialise */
2124 spectrum[i] = NULL ;
2125 position[i] = NULL ;
2126 wavelength[i] = NULL ;
2127 slit_fraction[i] = NULL ;
2128
2129 int order, trace_id;
2130
2131 /* Get Order and trace id */
2132 order = cpl_table_get(traces, CR2RES_COL_ORDER, i, NULL) ;
2133 trace_id = cpl_table_get(traces, CR2RES_COL_TRACENB, i, NULL) ;
2134
2135 /* Check if this order needs to be skipped */
2136 if (reduce_order > -1 && order != reduce_order) continue ;
2137
2138 /* Check if this trace needs to be skipped */
2139 if (reduce_trace > -1 && trace_id != reduce_trace) continue ;
2140
2141 cpl_msg_info(__func__, "Process Order %d/Trace %d",order,trace_id) ;
2142 cpl_msg_indent_more() ;
2143
2144 /* Call the Extraction */
2145 if (cr2res_extract2d_trace(img, traces, order, trace_id,
2146 npoints, wavemap, slitmap,
2147 &(spectrum[i]), &(position[i]), &(wavelength[i]),
2148 &(slit_fraction[i])) != 0) {
2149 cpl_msg_error(__func__, "Cannot extract2d the trace") ;
2150 spectrum[i] = NULL ;
2151 position[i] = NULL ;
2152 wavelength[i] = NULL ;
2153 slit_fraction[i] = NULL ;
2154 cpl_error_reset() ;
2155 cpl_msg_indent_less() ;
2156 continue ;
2157 }
2158 cpl_msg_indent_less() ;
2159 }
2160
2161 /* Create the extracted_tab for the current detector */
2162 extract_loc = cr2res_extract_EXTRACT2D_create(spectrum, position,
2163 wavelength, slit_fraction, traces) ;
2164
2165 /* Deallocate Vectors */
2166 for (i=0 ; i<nb_traces ; i++) {
2167 if (spectrum[i] != NULL) cpl_bivector_delete(spectrum[i]) ;
2168 if (position[i] != NULL) cpl_bivector_delete(position[i]) ;
2169 if (wavelength[i] != NULL) cpl_vector_delete(wavelength[i]) ;
2170 if (slit_fraction[i] != NULL) cpl_vector_delete(slit_fraction[i]) ;
2171 }
2172 cpl_free(spectrum) ;
2173 cpl_free(position) ;
2174 cpl_free(wavelength) ;
2175 cpl_free(slit_fraction) ;
2176 cpl_image_delete(wavemap);
2177 cpl_image_delete(slitmap);
2178
2179 /* Return */
2180 *extracted = extract_loc ;
2181 return 0 ;
2182}
2183
2184/*----------------------------------------------------------------------------*/
2203/*----------------------------------------------------------------------------*/
2205 const hdrl_image * in,
2206 const cpl_table * trace_tab,
2207 int order,
2208 int trace_id,
2209 int npoints,
2210 const cpl_image * wavemap,
2211 const cpl_image * slitmap,
2212 cpl_bivector ** spectrum,
2213 cpl_bivector ** position,
2214 cpl_vector ** wavelength,
2215 cpl_vector ** slit_fraction)
2216{
2217 cpl_bivector * spectrum_local ;
2218 cpl_vector * spectrum_flux ;
2219 cpl_vector * spectrum_error ;
2220 cpl_bivector * position_local ;
2221 cpl_vector * position_x;
2222 cpl_vector * position_y;
2223 cpl_vector * wavelength_local ;
2224 cpl_vector * slit_fraction_local ;
2225 const cpl_array * lower_array;
2226 const cpl_array * upper_array;
2227 cpl_polynomial * lower_poly;
2228 cpl_polynomial * upper_poly;
2229 cpl_vector * lower;
2230 cpl_vector * upper;
2231 cpl_vector * x;
2232
2233 int k, bad_pix;
2234 cpl_size i, j, row;
2235 double flux, err;
2236
2237 /* Check Entries */
2238 if (in==NULL || trace_tab==NULL || spectrum==NULL || position==NULL
2239 || wavelength==NULL || slit_fraction==NULL) return -1 ;
2240
2241 if ((k = cr2res_get_trace_table_index(trace_tab, order, trace_id)) == -1)
2242 {
2243 cpl_msg_error(__func__, "Order and/or Trace not found in trace table");
2244 return -1;
2245 }
2246
2247 // Step 0: Initialise output arrays
2248 wavelength_local = cpl_vector_new(npoints);
2249 slit_fraction_local = cpl_vector_new(npoints);
2250 position_x = cpl_vector_new(npoints);
2251 position_y = cpl_vector_new(npoints);
2252 spectrum_flux = cpl_vector_new(npoints);
2253 spectrum_error = cpl_vector_new(npoints);
2254
2255 // Step 1: Figure out pixels in the current trace
2256 // i.e. everything between upper and lower in trace_wave
2257
2258 // The x coordinate of the detector
2259 x = cpl_vector_new(CR2RES_DETECTOR_SIZE);
2260 for (i = 0; i < CR2RES_DETECTOR_SIZE; i++) cpl_vector_set(x, i, i + 1);
2261
2262 lower_array = cpl_table_get_array(trace_tab, CR2RES_COL_LOWER, k);
2263 upper_array = cpl_table_get_array(trace_tab, CR2RES_COL_UPPER, k);
2264 lower_poly = cr2res_convert_array_to_poly(lower_array);
2265 upper_poly = cr2res_convert_array_to_poly(upper_array);
2266 lower = cr2res_polynomial_eval_vector(lower_poly, x);
2267 upper = cr2res_polynomial_eval_vector(upper_poly, x);
2268
2269 // Step 2: Iterate over pixels in the given trace
2270 // and fill the vectors
2271 row = -1;
2272 for (i = 0; i < CR2RES_DETECTOR_SIZE; i++)
2273 {
2274 for (j = cpl_vector_get(lower, i); j < cpl_vector_get(upper, i); j++)
2275 {
2276 /* Protect the case where the trace goes out of the det */
2277 if (j<1 || j>CR2RES_DETECTOR_SIZE) continue ;
2278 row++;
2279 cpl_vector_set(position_x, row, i +1);
2280 cpl_vector_set(position_y, row, j);
2281 flux = cpl_image_get(hdrl_image_get_image_const(in), i + 1, j,
2282 &bad_pix);
2283 err = cpl_image_get(hdrl_image_get_error_const(in), i + 1, j,
2284 &bad_pix);
2285 cpl_vector_set(spectrum_flux, row, flux);
2286 cpl_vector_set(spectrum_error, row, err);
2287
2288 // Set wavelength
2289 cpl_vector_set(wavelength_local, row, cpl_image_get(
2290 wavemap, i + 1, j, &bad_pix));
2291 // Set Slitfraction
2292 cpl_vector_set(slit_fraction_local, row, cpl_image_get(
2293 slitmap, i + 1, j, &bad_pix));
2294 }
2295 }
2296
2297 // Step 3: resize output
2298 for (i = row; i < npoints; i++){
2299 cpl_vector_set(position_x, i, NAN);
2300 cpl_vector_set(position_y, i, NAN);
2301 cpl_vector_set(spectrum_flux, i, NAN);
2302 cpl_vector_set(spectrum_error, i, NAN);
2303 cpl_vector_set(wavelength_local, i, NAN);
2304 cpl_vector_set(slit_fraction_local, i, NAN);
2305 }
2306
2307 position_local = cpl_bivector_wrap_vectors(position_x, position_y);
2308 spectrum_local = cpl_bivector_wrap_vectors(spectrum_flux, spectrum_error);
2309
2310 cpl_polynomial_delete(upper_poly);
2311 cpl_polynomial_delete(lower_poly);
2312 cpl_vector_delete(upper);
2313 cpl_vector_delete(lower);
2314 cpl_vector_delete(x);
2315
2316 *spectrum = spectrum_local ;
2317 *position = position_local ;
2318 *wavelength = wavelength_local ;
2319 *slit_fraction = slit_fraction_local ;
2320 return 0;
2321}
2322
2323/*----------------------------------------------------------------------------*/
2333/*----------------------------------------------------------------------------*/
2335 cpl_bivector ** spectrum,
2336 cpl_bivector ** position,
2337 cpl_vector ** wavelength,
2338 cpl_vector ** slit_fraction,
2339 const cpl_table * trace_table)
2340{
2341 cpl_table * out ;
2342 char * col_name ;
2343 const double * pspec ;
2344 const double * perr ;
2345 const double * pxposition ;
2346 const double * pyposition ;
2347 const double * pwave ;
2348 const double * pslit_frac ;
2349 int nrows, all_null, i, order, trace_id, nb_traces ;
2350
2351 /* Check entries */
2352 if (spectrum==NULL || trace_table==NULL || position==NULL ||
2353 wavelength==NULL || slit_fraction==NULL)
2354 return NULL ;
2355
2356 /* Initialise */
2357 nb_traces = cpl_table_get_nrow(trace_table) ;
2358
2359 /* Check if all vectors are not null */
2360 all_null = 1 ;
2361 for (i=0 ; i<nb_traces ; i++)
2362 if (spectrum[i] != NULL) {
2363 nrows = cpl_bivector_get_size(spectrum[i]) ;
2364 all_null = 0 ;
2365 }
2366 if (all_null == 1) return NULL ;
2367
2368 /* Check the sizes */
2369 for (i=0 ; i<nb_traces ; i++)
2370 if (spectrum[i] != NULL && cpl_bivector_get_size(spectrum[i]) != nrows)
2371 return NULL ;
2372
2373 /* Create the table */
2374 out = cpl_table_new(nrows);
2375 for (i=0 ; i<nb_traces ; i++) {
2376 order = cpl_table_get(trace_table, CR2RES_COL_ORDER, i, NULL) ;
2377 trace_id = cpl_table_get(trace_table, CR2RES_COL_TRACENB, i, NULL) ;
2378 /* Create SPEC column */
2379 col_name = cr2res_dfs_SPEC_colname(order, trace_id) ;
2380 cpl_table_new_column(out, col_name, CPL_TYPE_DOUBLE);
2381 cpl_free(col_name) ;
2382 /* Create SPEC_ERR column */
2383 col_name = cr2res_dfs_SPEC_ERR_colname(order, trace_id) ;
2384 cpl_table_new_column(out, col_name, CPL_TYPE_DOUBLE);
2385 cpl_free(col_name) ;
2386 /* Create WAVELENGTH column */
2387 col_name = cr2res_dfs_WAVELENGTH_colname(order, trace_id) ;
2388 cpl_table_new_column(out, col_name, CPL_TYPE_DOUBLE);
2389 cpl_free(col_name) ;
2390 /* Create POSITIONX column */
2391 col_name = cr2res_dfs_POSITIONX_colname(order, trace_id) ;
2392 cpl_table_new_column(out, col_name, CPL_TYPE_DOUBLE);
2393 cpl_free(col_name) ;
2394 /* Create POSITIONY column */
2395 col_name = cr2res_dfs_POSITIONY_colname(order, trace_id) ;
2396 cpl_table_new_column(out, col_name, CPL_TYPE_DOUBLE);
2397 cpl_free(col_name) ;
2398 /* Create SLIT_FRACTION column */
2399 col_name = cr2res_dfs_SLIT_FRACTION_colname(order, trace_id) ;
2400 cpl_table_new_column(out, col_name, CPL_TYPE_DOUBLE);
2401 cpl_free(col_name) ;
2402 }
2403
2404 /* Fill the table */
2405 for (i=0 ; i<nb_traces ; i++) {
2406 if (spectrum[i]!=NULL && position[i]!=NULL &&
2407 wavelength[i]!=NULL && slit_fraction[i]!=NULL) {
2408 order = cpl_table_get(trace_table, CR2RES_COL_ORDER, i, NULL) ;
2409 trace_id = cpl_table_get(trace_table, CR2RES_COL_TRACENB, i, NULL) ;
2410 pspec = cpl_bivector_get_x_data_const(spectrum[i]) ;
2411 perr = cpl_bivector_get_y_data_const(spectrum[i]);
2412 pxposition = cpl_bivector_get_x_data_const(position[i]) ;
2413 pyposition = cpl_bivector_get_y_data_const(position[i]) ;
2414 pwave = cpl_vector_get_data_const(wavelength[i]) ;
2415 pslit_frac = cpl_vector_get_data_const(slit_fraction[i]) ;
2416 /* Fill SPEC column */
2417 col_name = cr2res_dfs_SPEC_colname(order, trace_id) ;
2418 cpl_table_copy_data_double(out, col_name, pspec) ;
2419 cpl_free(col_name) ;
2420 /* Fill SPEC_ERR column */
2421 col_name = cr2res_dfs_SPEC_ERR_colname(order, trace_id) ;
2422 cpl_table_copy_data_double(out, col_name, perr) ;
2423 cpl_free(col_name) ;
2424 /* Fill WAVELENGTH column */
2425 col_name = cr2res_dfs_WAVELENGTH_colname(order, trace_id) ;
2426 cpl_table_copy_data_double(out, col_name, pwave) ;
2427 cpl_free(col_name) ;
2428 /* Fill POSITIONX column */
2429 col_name = cr2res_dfs_POSITIONX_colname(order, trace_id) ;
2430 cpl_table_copy_data_double(out, col_name, pxposition) ;
2431 cpl_free(col_name) ;
2432 /* Fill POSITIONY column */
2433 col_name = cr2res_dfs_POSITIONY_colname(order, trace_id) ;
2434 cpl_table_copy_data_double(out, col_name, pyposition) ;
2435 cpl_free(col_name) ;
2436 /* Fill SLIT_FRACTION column */
2437 col_name = cr2res_dfs_SLIT_FRACTION_colname(order, trace_id) ;
2438 cpl_table_copy_data_double(out, col_name, pslit_frac) ;
2439 cpl_free(col_name) ;
2440 }
2441 }
2442 return out ;
2443}
2444
2448/*----------------------------------------------------------------------------*/
2478/*----------------------------------------------------------------------------*/
2479static int cr2res_extract_xi_zeta_tensors(
2480 int ncols,
2481 int nrows,
2482 int ny,
2483 double * ycen,
2484 const int * ycen_offset,
2485 int y_lower_lim,
2486 int osample,
2487 cpl_polynomial ** slitcurves,
2488 xi_ref * xi,
2489 zeta_ref * zeta,
2490 int * m_zeta)
2491{
2492 int x, xx, y, yy, ix, ix1, ix2, iy, m;
2493 double step, delta, w;
2494 step = 1.e0 / osample;
2495
2496 /* Clean xi */
2497 for (x = 0; x < ncols; x++)
2498 {
2499 for (iy = 0; iy < ny; iy++)
2500 {
2501 for (m = 0; m < 4; m++)
2502 {
2503 xi[xi_index(x, iy, m)].x = -1;
2504 xi[xi_index(x, iy, m)].y = -1;
2505 xi[xi_index(x, iy, m)].w = 0.;
2506 }
2507 }
2508 }
2509
2510 /* Clean zeta */
2511 for (x = 0; x < ncols; x++)
2512 {
2513 for (y = 0; y < nrows; y++)
2514 {
2515 m_zeta[mzeta_index(x, y)] = 0;
2516 for (ix = 0; ix < 3 * (osample + 1); ix++)
2517 {
2518 zeta[zeta_index(x, y, ix)].x = -1;
2519 zeta[zeta_index(x, y, ix)].iy = -1;
2520 zeta[zeta_index(x, y, ix)].w = 0.;
2521 }
2522 }
2523 }
2524
2525 /*
2526 Construct the xi and zeta tensors. They contain pixel references and contribution.
2527 values going from a given subpixel to other pixels (xi) and coming from other subpixels
2528 to a given detector pixel (zeta).
2529 Note, that xi and zeta are used in the equations for sL, sP and for the model but they
2530 do not involve the data, only the geometry. Thus it can be pre-computed once.
2531 */
2532 for (x = 0; x < ncols; x++)
2533 {
2534 int iy1, iy2;
2535 double d1, d2, dy;
2536 /*
2537 I promised to reconsider the initial offset. Here it is. For the original layout
2538 (no column shifts and discontinuities in ycen) there is pixel y that contains the
2539 central line yc. There are two options here (by construction of ycen that can be 0
2540 but cannot be 1): (1) yc is inside pixel y and (2) yc falls at the boundary between
2541 pixels y and y-1. yc cannot be at the boundary of pixels y+1 and y because we would
2542 select y+1 to be pixel y in that case.
2543
2544 Next we need to define starting and ending indices iy for sL subpixels that contribute
2545 to pixel y. I call them iy1 and iy2. For both cases we assume osample+1 subpixels covering
2546 pixel y (weird). So for case 1 iy1 will be (y-1)*osample and iy2 == y*osample. Special
2547 treatment of the boundary subpixels will compensate for introducing extra subpixel in
2548 case 1. In case 2 things are more logical: iy1=(yc-y)*osample+(y-1)*osample;
2549 iy2=(y+1-yc)*osample)+(y-1)*osample. ycen is yc-y making things simpler. Note also that
2550 the same pattern repeats for all rows: we only need to initialize iy1 and iy2 and keep
2551 incrementing them by osample.
2552 */
2553
2554 iy2 = osample - floor(ycen[x] * osample);
2555 iy1 = iy2 - osample;
2556
2557 /*
2558 Handling partial subpixels cut by detector pixel rows is again tricky. Here we have three
2559 cases (mostly because of the decision to assume that we always have osample+1 subpixels
2560 per one detector pixel). Here d1 is the fraction of the subpixel iy1 inside detector pixel y.
2561 d2 is then the fraction of subpixel iy2 inside detector pixel y. By definition d1+d2==step.
2562 Case 1: ycen falls on the top boundary of each detector pixel (ycen == 1). Here we conclude
2563 that the first subpixel is fully contained inside pixel y and d1 is set to step.
2564 Case 2: ycen falls on the bottom boundary of each detector pixel (ycen == 0). Here we conclude
2565 that the first subpixel is totally outside of pixel y and d1 is set to 0.
2566 Case 3: ycen falls inside of each pixel (0>ycen>1). In this case d1 is set to the fraction of
2567 the first step contained inside of each pixel.
2568 And BTW, this also means that central line coincides with the upper boundary of subpixel iy2
2569 when the y loop reaches pixel y_lower_lim. In other words:
2570
2571 dy=(iy-(y_lower_lim+ycen[x])*osample)*step-0.5*step
2572 */
2573
2574 d1 = fmod(ycen[x], step);
2575 if (d1 == 0)
2576 d1 = step;
2577 d2 = step - d1;
2578
2579 /*
2580 The final hurdle for 2D slit decomposition is to construct two 3D reference tensors. We proceed
2581 similar to 1D case except that now each iy subpixel can be shifted left or right following
2582 the curvature of the slit image on the detector. We assume for now that each subpixel is
2583 exactly 1 detector pixel wide. This may not be exactly true if the curvature changes across
2584 the focal plane but will deal with it when the necessity will become apparent. For now we
2585 just assume that a shift delta the weight w assigned to subpixel iy is divided between
2586 ix1=int(delta) and ix2=int(delta)+signum(delta) as (1-|delta-ix1|)*w and |delta-ix1|*w.
2587
2588 The curvature is given by a quadratic polynomial evaluated from an approximation for column
2589 x: delta = PSF_curve[x][0] + PSF_curve[x][1] * (y-yc[x]) + PSF_curve[x][2] * (y-yc[x])^2.
2590 It looks easy except that y and yc are set in the global detector coordinate system rather than
2591 in the shifted and cropped swath passed to slit_func_2d. One possible solution I will try here
2592 is to modify PSF_curve before the call such as:
2593 delta = PSF_curve'[x][0] + PSF_curve'[x][1] * (y'-ycen[x]) + PSF_curve'[x][2] * (y'-ycen[x])^2
2594 where y' = y - floor(yc).
2595 */
2596
2597 /* Define initial distance from ycen */
2598 /* It is given by the center of the first */
2599 /* subpixel falling into pixel y_lower_lim */
2600 dy = ycen[x] - floor((y_lower_lim + ycen[x]) / step) * step - step;
2601
2602 /*
2603 Now we go detector pixels x and y incrementing subpixels looking for their contributions
2604 to the current and adjacent pixels. Note that the curvature/tilt of the projected slit
2605 image could be so large that subpixel iy may no contribute to column x at all. On the
2606 other hand, subpixels around ycen by definition must contribute to pixel x,y.
2607 3rd index in xi refers corners of pixel xx,y: 0:LL, 1:LR, 2:UL, 3:UR.
2608 */
2609 for (y = 0; y < nrows; y++) {
2610 iy1 += osample; // Bottom subpixel falling in row y
2611 iy2 += osample; // Top subpixel falling in row y
2612 dy -= step;
2613 for (iy = iy1; iy <= iy2; iy++) {
2614 if (iy == iy1) w = d1;
2615 else if (iy == iy2) w = d2;
2616 else w = step;
2617 dy += step;
2618 delta = cpl_polynomial_eval_1d(slitcurves[x], dy - ycen[x], NULL);
2619 ix1 = delta;
2620 ix2 = ix1 + signum(delta);
2621
2622 /* Three cases: subpixel on the bottom boundary of row y, intermediate subpixels and top boundary */
2623
2624 if (iy == iy1) /* Case A: Subpixel iy is entering detector row y */
2625 {
2626 if (ix1 < ix2) /* Subpixel iy shifts to the right from column x */
2627 {
2628 if (x + ix1 >= 0 && x + ix2 < ncols)
2629 {
2630 xx = x + ix1; /* Upper right corner of subpixel iy */
2631 yy = y + ycen_offset[x] - ycen_offset[xx];
2632 xi[xi_index(x, iy, 3)].x = xx;
2633 xi[xi_index(x, iy, 3)].y = yy;
2634 xi[xi_index(x, iy, 3)].w = w - fabs(delta - ix1) * w;
2635 // xx>=0 && xx<ncols is already given by the loop condition
2636 if (xx < ncols && yy >= 0 && yy < nrows && xi[xi_index(x, iy, 3)].w > 0)
2637 {
2638 m = m_zeta[mzeta_index(xx, yy)];
2639 zeta[zeta_index(xx, yy, m)].x = x;
2640 zeta[zeta_index(xx, yy, m)].iy = iy;
2641 zeta[zeta_index(xx, yy, m)].w = xi[xi_index(x, iy, 3)].w;
2642 m_zeta[mzeta_index(xx, yy)]++;
2643 }
2644 xx = x + ix2; /* Upper left corner of subpixel iy */
2645 // This offset is required because the iy subpixel
2646 // is going to contribute to the yy row in xx column
2647 // of detector pixels where yy and y are in the same
2648 // row. In the packed array this is not necessarily true.
2649 // Instead, what we know is that:
2650 // y+ycen_offset[x] == yy+ycen_offset[xx]
2651 yy = y + ycen_offset[x] - ycen_offset[xx];
2652
2653 xi[xi_index(x, iy, 2)].x = xx;
2654 xi[xi_index(x, iy, 2)].y = yy;
2655 xi[xi_index(x, iy, 2)].w = fabs(delta - ix1) * w;
2656 if (xx >= 0 && yy >= 0 && yy < nrows && xi[xi_index(x, iy, 2)].w > 0)
2657 {
2658 m = m_zeta[mzeta_index(xx, yy)];
2659 zeta[zeta_index(xx, yy, m)].x = x;
2660 zeta[zeta_index(xx, yy, m)].iy = iy;
2661 zeta[zeta_index(xx, yy, m)].w = xi[xi_index(x, iy, 2)].w;
2662 m_zeta[mzeta_index(xx, yy)]++;
2663 }
2664 }
2665 }
2666 else if (ix1 > ix2) /* Subpixel iy shifts to the left from column x */
2667 {
2668 if (x + ix2 >= 0 && x + ix1 < ncols)
2669 {
2670 xx = x + ix2; /* Upper left corner of subpixel iy */
2671 yy = y + ycen_offset[x] - ycen_offset[xx];
2672 xi[xi_index(x, iy, 2)].x = xx;
2673 xi[xi_index(x, iy, 2)].y = yy;
2674 xi[xi_index(x, iy, 2)].w = fabs(delta - ix1) * w;
2675 if (xx < ncols && yy >= 0 && yy < nrows && xi[xi_index(x, iy, 2)].w > 0)
2676 {
2677 m = m_zeta[mzeta_index(xx, yy)];
2678 zeta[zeta_index(xx, yy, m)].x = x;
2679 zeta[zeta_index(xx, yy, m)].iy = iy;
2680 zeta[zeta_index(xx, yy, m)].w = xi[xi_index(x, iy, 2)].w;
2681 m_zeta[mzeta_index(xx, yy)]++;
2682 }
2683 xx = x + ix1; /* Upper right corner of subpixel iy */
2684 yy = y + ycen_offset[x] - ycen_offset[xx];
2685 xi[xi_index(x, iy, 3)].x = xx;
2686 xi[xi_index(x, iy, 3)].y = yy;
2687 xi[xi_index(x, iy, 3)].w = w - fabs(delta - ix1) * w;
2688 if (xx >= 0 && yy >= 0 && yy < nrows && xi[xi_index(x, iy, 3)].w > 0)
2689 {
2690 m = m_zeta[mzeta_index(xx, yy)];
2691 zeta[zeta_index(xx, yy, m)].x = x;
2692 zeta[zeta_index(xx, yy, m)].iy = iy;
2693 zeta[zeta_index(xx, yy, m)].w = xi[xi_index(x, iy, 3)].w;
2694 m_zeta[mzeta_index(xx, yy)]++;
2695 }
2696 }
2697 }
2698 else
2699 {
2700 if (x + ix1 >= 0 && x + ix1 < ncols)
2701 {
2702 xx = x + ix1; /* Subpixel iy stays inside column x */
2703 yy = y + ycen_offset[x] - ycen_offset[xx];
2704 xi[xi_index(x, iy, 2)].x = xx;
2705 xi[xi_index(x, iy, 2)].y = yy;
2706 xi[xi_index(x, iy, 2)].w = w;
2707 if (yy >= 0 && yy < nrows && w > 0)
2708 {
2709 m = m_zeta[mzeta_index(xx, yy)];
2710 zeta[zeta_index(xx, yy, m)].x = x;
2711 zeta[zeta_index(xx, yy, m)].iy = iy;
2712 zeta[zeta_index(xx, yy, m)].w = w;
2713 m_zeta[mzeta_index(xx, yy)]++;
2714 }
2715 }
2716 }
2717 }
2718 else if (iy == iy2) /* Case C: Subpixel iy is leaving detector row y */
2719 {
2720 if (ix1 < ix2) /* Subpixel iy shifts to the right from column x */
2721 {
2722 if (x + ix1 >= 0 && x + ix2 < ncols)
2723 {
2724 xx = x + ix1; /* Bottom right corner of subpixel iy */
2725 yy = y + ycen_offset[x] - ycen_offset[xx];
2726 xi[xi_index(x, iy, 1)].x = xx;
2727 xi[xi_index(x, iy, 1)].y = yy;
2728 xi[xi_index(x, iy, 1)].w = w - fabs(delta - ix1) * w;
2729 if (xx < ncols && yy >= 0 && yy < nrows && xi[xi_index(x, iy, 1)].w > 0)
2730 {
2731 m = m_zeta[mzeta_index(xx, yy)];
2732 zeta[zeta_index(xx, yy, m)].x = x;
2733 zeta[zeta_index(xx, yy, m)].iy = iy;
2734 zeta[zeta_index(xx, yy, m)].w = xi[xi_index(x, iy, 1)].w;
2735 m_zeta[mzeta_index(xx, yy)]++;
2736 }
2737 xx = x + ix2; /* Bottom left corner of subpixel iy */
2738 yy = y + ycen_offset[x] - ycen_offset[xx];
2739 xi[xi_index(x, iy, 0)].x = xx;
2740 xi[xi_index(x, iy, 0)].y = yy;
2741 xi[xi_index(x, iy, 0)].w = fabs(delta - ix1) * w;
2742 if (xx >= 0 && yy >= 0 && yy < nrows && xi[xi_index(x, iy, 0)].w > 0)
2743 {
2744 m = m_zeta[mzeta_index(xx, yy)];
2745 zeta[zeta_index(xx, yy, m)].x = x;
2746 zeta[zeta_index(xx, yy, m)].iy = iy;
2747 zeta[zeta_index(xx, yy, m)].w = xi[xi_index(x, iy, 0)].w;
2748 m_zeta[mzeta_index(xx, yy)]++;
2749 }
2750 }
2751 }
2752 else if (ix1 > ix2) /* Subpixel iy shifts to the left from column x */
2753 {
2754 if (x + ix2 >= 0 && x + ix1 < ncols)
2755 {
2756 xx = x + ix2; /* Bottom left corner of subpixel iy */
2757 yy = y + ycen_offset[x] - ycen_offset[xx];
2758 xi[xi_index(x, iy, 0)].x = xx;
2759 xi[xi_index(x, iy, 0)].y = yy;
2760 xi[xi_index(x, iy, 0)].w = fabs(delta - ix1) * w;
2761 if (xx < ncols && yy >= 0 && yy < nrows && xi[xi_index(x, iy, 0)].w > 0)
2762 {
2763 m = m_zeta[mzeta_index(xx, yy)];
2764 zeta[zeta_index(xx, yy, m)].x = x;
2765 zeta[zeta_index(xx, yy, m)].iy = iy;
2766 zeta[zeta_index(xx, yy, m)].w = xi[xi_index(x, iy, 0)].w;
2767 m_zeta[mzeta_index(xx, yy)]++;
2768 }
2769 xx = x + ix1; /* Bottom right corner of subpixel iy */
2770 yy = y + ycen_offset[x] - ycen_offset[xx];
2771 xi[xi_index(x, iy, 1)].x = xx;
2772 xi[xi_index(x, iy, 1)].y = yy;
2773 xi[xi_index(x, iy, 1)].w = w - fabs(delta - ix1) * w;
2774 if (xx >= 0 && yy >= 0 && yy < nrows && xi[xi_index(x, iy, 1)].w > 0)
2775 {
2776 m = m_zeta[mzeta_index(xx, yy)];
2777 zeta[zeta_index(xx, yy, m)].x = x;
2778 zeta[zeta_index(xx, yy, m)].iy = iy;
2779 zeta[zeta_index(xx, yy, m)].w = xi[xi_index(x, iy, 1)].w;
2780 m_zeta[mzeta_index(xx, yy)]++;
2781 }
2782 }
2783 }
2784 else /* Subpixel iy stays inside column x */
2785 {
2786 if (x + ix1 >= 0 && x + ix1 < ncols)
2787 {
2788 xx = x + ix1;
2789 yy = y + ycen_offset[x] - ycen_offset[xx];
2790 xi[xi_index(x, iy, 0)].x = xx;
2791 xi[xi_index(x, iy, 0)].y = yy;
2792 xi[xi_index(x, iy, 0)].w = w;
2793 if (yy >= 0 && yy < nrows && w > 0)
2794 {
2795 m = m_zeta[mzeta_index(xx, yy)];
2796 zeta[zeta_index(xx, yy, m)].x = x;
2797 zeta[zeta_index(xx, yy, m)].iy = iy;
2798 zeta[zeta_index(xx, yy, m)].w = w;
2799 m_zeta[mzeta_index(xx, yy)]++;
2800 }
2801 }
2802 }
2803 }
2804 else /* CASE B: Subpixel iy is fully inside detector row y */
2805 {
2806 if (ix1 < ix2) /* Subpixel iy shifts to the right from column x */
2807 {
2808 if (x + ix1 >= 0 && x + ix2 < ncols)
2809 {
2810 xx = x + ix1; /* Bottom right corner of subpixel iy */
2811 yy = y + ycen_offset[x] - ycen_offset[xx];
2812 xi[xi_index(x, iy, 1)].x = xx;
2813 xi[xi_index(x, iy, 1)].y = yy;
2814 xi[xi_index(x, iy, 1)].w = w - fabs(delta - ix1) * w;
2815 if (xx < ncols && yy >= 0 && yy < nrows && xi[xi_index(x, iy, 1)].w > 0)
2816 {
2817 m = m_zeta[mzeta_index(xx, yy)];
2818 zeta[zeta_index(xx, yy, m)].x = x;
2819 zeta[zeta_index(xx, yy, m)].iy = iy;
2820 zeta[zeta_index(xx, yy, m)].w = xi[xi_index(x, iy, 1)].w;
2821 m_zeta[mzeta_index(xx, yy)]++;
2822 }
2823 xx = x + ix2; /* Bottom left corner of subpixel iy */
2824 yy = y + ycen_offset[x] - ycen_offset[xx];
2825 xi[xi_index(x, iy, 0)].x = xx;
2826 xi[xi_index(x, iy, 0)].y = yy;
2827 xi[xi_index(x, iy, 0)].w = fabs(delta - ix1) * w;
2828 if (xx >= 0 && yy >= 0 && yy < nrows && xi[xi_index(x, iy, 0)].w > 0)
2829 {
2830 m = m_zeta[mzeta_index(xx, yy)];
2831 zeta[zeta_index(xx, yy, m)].x = x;
2832 zeta[zeta_index(xx, yy, m)].iy = iy;
2833 zeta[zeta_index(xx, yy, m)].w = xi[xi_index(x, iy, 0)].w;
2834 m_zeta[mzeta_index(xx, yy)]++;
2835 }
2836 }
2837 }
2838 else if (ix1 > ix2) /* Subpixel iy shifts to the left from column x */
2839 {
2840 if (x + ix2 >= 0 && x + ix1 < ncols)
2841 {
2842 xx = x + ix2; /* Bottom right corner of subpixel iy */
2843 yy = y + ycen_offset[x] - ycen_offset[xx];
2844 xi[xi_index(x, iy, 1)].x = xx;
2845 xi[xi_index(x, iy, 1)].y = yy;
2846 xi[xi_index(x, iy, 1)].w = fabs(delta - ix1) * w;
2847 if (xx < ncols && yy >= 0 && yy < nrows && xi[xi_index(x, iy, 1)].w > 0)
2848 {
2849 m = m_zeta[mzeta_index(xx, yy)];
2850 zeta[zeta_index(xx, yy, m)].x = x;
2851 zeta[zeta_index(xx, yy, m)].iy = iy;
2852 zeta[zeta_index(xx, yy, m)].w = xi[xi_index(x, iy, 1)].w;
2853 m_zeta[mzeta_index(xx, yy)]++;
2854 }
2855 xx = x + ix1; /* Bottom left corner of subpixel iy */
2856 yy = y + ycen_offset[x] - ycen_offset[xx];
2857 xi[xi_index(x, iy, 0)].x = xx;
2858 xi[xi_index(x, iy, 0)].y = yy;
2859 xi[xi_index(x, iy, 0)].w = w - fabs(delta - ix1) * w;
2860 if (xx >= 0 && yy >= 0 && yy < nrows && xi[xi_index(x, iy, 0)].w > 0)
2861 {
2862 m = m_zeta[mzeta_index(xx, yy)];
2863 zeta[zeta_index(xx, yy, m)].x = x;
2864 zeta[zeta_index(xx, yy, m)].iy = iy;
2865 zeta[zeta_index(xx, yy, m)].w = xi[xi_index(x, iy, 0)].w;
2866 m_zeta[mzeta_index(xx, yy)]++;
2867 }
2868 }
2869 }
2870 else /* Subpixel iy stays inside column x */
2871 {
2872 if (x + ix2 >= 0 && x + ix2 < ncols)
2873 {
2874 xx = x + ix2;
2875 yy = y + ycen_offset[x] - ycen_offset[xx];
2876 xi[xi_index(x, iy, 0)].x = xx;
2877 xi[xi_index(x, iy, 0)].y = yy;
2878 xi[xi_index(x, iy, 0)].w = w;
2879 if (yy >= 0 && yy < nrows && w > 0)
2880 {
2881 m = m_zeta[mzeta_index(xx, yy)];
2882 zeta[zeta_index(xx, yy, m)].x = x;
2883 zeta[zeta_index(xx, yy, m)].iy = iy;
2884 zeta[zeta_index(xx, yy, m)].w = w;
2885 m_zeta[mzeta_index(xx, yy)]++;
2886 }
2887 }
2888 }
2889 }
2890 }
2891 }
2892 }
2893 return 0;
2894}
2895
2896/*----------------------------------------------------------------------------*/
2923/*----------------------------------------------------------------------------*/
2924static int cr2res_extract_slit_func_curved(
2925 double error_factor,
2926 int ncols,
2927 int nrows,
2928 int osample,
2929 double pclip,
2930 double * im,
2931 double * pix_unc,
2932 int * mask,
2933 double * ycen,
2934 int * ycen_offset,
2935 int y_lower_lim,
2936 cpl_polynomial ** slitcurves,
2937 int delta_x,
2938 double * sL,
2939 double * sP,
2940 double * model,
2941 double * unc,
2942 double lambda_sP,
2943 double lambda_sL,
2944 double sP_stop,
2945 int maxiter,
2946 double kappa,
2947 const double * slit_func_in,
2948 double * sP_old,
2949 double * l_Aij,
2950 double * p_Aij,
2951 double * l_bj,
2952 double * p_bj,
2953 cpl_image * img_mad,
2954 xi_ref * xi,
2955 zeta_ref * zeta,
2956 int * m_zeta)
2957{
2958 int x, xx, xxx, y, yy, iy, jy, n, m, ny, nx;
2959 double norm, lambda, diag_tot, ww, www, sP_change, sP_med;
2960 double tmp, sLmax, sum;
2961 int info, iter;
2962 cpl_vector *tmp_vec;
2963
2964 /* The size of the sL array. */
2965 /* Extra osample is because ycen can be between 0 and 1. */
2966 ny = osample * (nrows + 1) + 1;
2967 nx = 4 * delta_x + 1;
2968 if (nx < 3)
2969 nx = 3;
2970
2971 cr2res_extract_xi_zeta_tensors(ncols, nrows, ny, ycen, ycen_offset,
2972 y_lower_lim, osample, slitcurves, xi, zeta,
2973 m_zeta);
2974
2975 // If a slit func is given, use that instead of recalculating it
2976 if (slit_func_in != NULL) {
2977 // Normalize the input just in case
2978 norm = 0.e0;
2979 for (iy = 0; iy < ny; iy++) {
2980 sL[iy] = slit_func_in[iy];
2981 norm += sL[iy];
2982 }
2983 norm /= osample;
2984 for (iy = 0; iy < ny; iy++)
2985 sL[iy] /= norm;
2986 }
2987
2988 /* Resetting the mask and img values for outliers and NaN */
2989 /* for (y = 0; y < nrows; y++) {
2990 for (x = 0; x < ncols; x++) {
2991 mask[y * ncols + x] = 1;
2992 if(im[y * ncols + x] < -1.e3) {
2993 mask[y * ncols + x] = 0;
2994 //im[y * ncols + x] = 0.e0;
2995 }
2996 }
2997 }
2998*/
2999 int nclip = (int)(ncols * nrows * pclip / 100);
3000 if (nclip > 0)
3001 {
3002 if (nclip > ncols * nrows / 2)
3003 nclip = (ncols * nrows / 2) - 1;
3004 cpl_vector *im_vec = cpl_vector_wrap(ncols * nrows, im);
3005 cpl_vector *pos_vec = cpl_vector_new(ncols * nrows);
3006 for (x = 0; x < ncols; x++)
3007 {
3008 for (y = 0; y < nrows; y++)
3009 {
3010 cpl_vector_set(pos_vec, y * ncols + x, y * ncols + x);
3011 }
3012 }
3013 cpl_bivector *im_in_bvec = cpl_bivector_wrap_vectors(pos_vec, im_vec);
3014 cpl_bivector *im_sort_bvec = cpl_bivector_new(ncols * nrows);
3015 cpl_bivector_sort(im_sort_bvec, im_in_bvec, CPL_SORT_ASCENDING, CPL_SORT_BY_Y);
3016 cpl_bivector_unwrap_vectors(im_in_bvec);
3017 cpl_vector_unwrap(im_vec);
3018 cpl_vector_delete(pos_vec);
3019
3020 cpl_vector *pos_sort_vec = cpl_bivector_get_x(im_sort_bvec);
3021
3022 int ii = 0, mm = 0;
3023 while (mm < nclip)
3024 {
3025 int pos = (int)cpl_vector_get(pos_sort_vec, ii);
3026 if (mask[pos] != 0)
3027 {
3028 mask[pos] = 0;
3029 mm++;
3030 }
3031 ii++;
3032 }
3033
3034 ii = ncols * nrows - 1;
3035 mm = 0;
3036 while (mm < nclip)
3037 {
3038 int pos = (int)cpl_vector_get(pos_sort_vec, ii);
3039 if (mask[pos] != 0)
3040 {
3041 mask[pos] = 0;
3042 mm++;
3043 }
3044 ii--;
3045 }
3046 cpl_bivector_delete(im_sort_bvec);
3047 pos_sort_vec = NULL;
3048 }
3049
3050 /* Loop through sL , sP reconstruction until convergence is reached */
3051 iter = 0;
3052 // cost = 0; Not used without cost_old?
3053 do {
3054 //cost_old = cost; this is not used apparently?
3055 double cost, sigma;
3056 int isum;
3057 if (slit_func_in == NULL) {
3058 /* Compute slit function sL */
3059 /* Prepare the RHS and the matrix */
3060 for (iy = 0; iy < ny; iy++) {
3061 l_bj[iy] = 0.e0;
3062 /* Clean RHS */
3063 for (jy = 0; jy <= 4 * osample; jy++)
3064 l_Aij[iy + ny * jy] = 0.e0;
3065 }
3066 /* Fill in SLE arrays for slit function */
3067 diag_tot = 0.e0;
3068 for (iy = 0; iy < ny; iy++) {
3069 for (x = 0; x < ncols; x++) {
3070 for (n = 0; n < 4; n++) {
3071 ww = xi[xi_index(x, iy, n)].w;
3072 if (ww > 0) {
3073 xx = xi[xi_index(x, iy, n)].x;
3074 yy = xi[xi_index(x, iy, n)].y;
3075 if (xx >= 0 && xx < ncols && yy >= 0 &&
3076 yy < nrows) {
3077 if (m_zeta[mzeta_index(xx, yy)] > 0) {
3078 for (m = 0; m < m_zeta[mzeta_index(xx, yy)];
3079 m++) {
3080 xxx = zeta[zeta_index(xx, yy, m)].x;
3081 jy = zeta[zeta_index(xx, yy, m)].iy;
3082 www = zeta[zeta_index(xx, yy, m)].w;
3083 if (jy - iy + 2 * osample >= 0)
3084 l_Aij[iy + ny * (jy - iy +
3085 2 * osample)] +=
3086 sP[xxx] * sP[x] * www * ww *
3087 mask[yy * ncols + xx];
3088 }
3089 l_bj[iy] += im[yy * ncols + xx] *
3090 mask[yy * ncols + xx] * sP[x] *
3091 ww;
3092 }
3093 }
3094 }
3095 }
3096 }
3097 diag_tot += fabs(l_Aij[iy + ny * 2 * osample]);
3098 }
3099 /* Scale regularization parameters */
3100 lambda = lambda_sL * diag_tot / ny;
3101 /* Add regularization parts for the SLE matrix */
3102 /* Main diagonal */
3103 l_Aij[ny * 2 * osample] += lambda;
3104 /* Upper diagonal */
3105 l_Aij[ny * (2 * osample + 1)] -= lambda;
3106 for (iy = 1; iy < ny - 1; iy++) {
3107 /* Lower diagonal */
3108 l_Aij[iy + ny * (2 * osample - 1)] -= lambda;
3109 /* Main diagonal */
3110 l_Aij[iy + ny * 2 * osample] += lambda * 2.e0;
3111 /* Upper diagonal */
3112 l_Aij[iy + ny * (2 * osample + 1)] -= lambda;
3113 }
3114 /* Lower diagonal */
3115 l_Aij[ny - 1 + ny * (2 * osample - 1)] -= lambda;
3116 /* Main diagonal */
3117 l_Aij[ny - 1 + ny * 2 * osample] += lambda;
3118
3119 /* Solve the system of equations */
3120 info = cr2res_extract_slitdec_bandsol(l_Aij, l_bj, ny,
3121 4 * osample + 1, lambda);
3122 if (info)
3123 cpl_msg_error(__func__, "info(sL)=%d\n", info);
3124
3125 /* Normalize the slit function */
3126 norm = 0.e0;
3127 for (iy = 0; iy < ny; iy++) {
3128 sL[iy] = l_bj[iy];
3129 norm += fabs(sL[iy]);
3130 }
3131 norm /= osample;
3132 for (iy = 0; iy < ny; iy++)
3133 sL[iy] /= norm;
3134 }
3135
3136 /* Compute spectrum sP */
3137 for (x = 0; x < ncols; x++) {
3138 for (xx = 0; xx < nx; xx++)
3139 p_Aij[xx * ncols + x] = 0.;
3140 p_bj[x] = 0;
3141 }
3142 for (x = 0; x < ncols; x++) {
3143 for (iy = 0; iy < ny; iy++) {
3144 for (n = 0; n < 4; n++) {
3145 ww = xi[xi_index(x, iy, n)].w;
3146 if (ww > 0) {
3147 xx = xi[xi_index(x, iy, n)].x;
3148 yy = xi[xi_index(x, iy, n)].y;
3149 if (xx >= 0 && xx < ncols && yy >= 0 && yy < nrows) {
3150 if (m_zeta[mzeta_index(xx, yy)] > 0) {
3151 for (m = 0; m < m_zeta[mzeta_index(xx, yy)];
3152 m++) {
3153 xxx = zeta[zeta_index(xx, yy, m)].x;
3154 jy = zeta[zeta_index(xx, yy, m)].iy;
3155 www = zeta[zeta_index(xx, yy, m)].w;
3156 p_Aij[x +
3157 ncols * (xxx - x + 2 * delta_x)] +=
3158 sL[jy] * sL[iy] * www * ww *
3159 mask[yy * ncols + xx];
3160 }
3161 p_bj[x] += im[yy * ncols + xx] *
3162 mask[yy * ncols + xx] * sL[iy] * ww;
3163 }
3164 }
3165 }
3166 }
3167 }
3168 }
3169
3170 /* Save the previous iteration spectrum */
3171 for (x = 0; x < ncols; x++)
3172 sP_old[x] = sP[x];
3173
3174 lambda = 1;
3175 if (lambda_sP > 0.e0) {
3176 lambda = lambda_sP; /* Scale regularization parameter */
3177 p_Aij[ncols * (2 * delta_x)] += lambda; /* Main diagonal */
3178 p_Aij[ncols * (2 * delta_x + 1)] -= lambda; /* Upper diagonal */
3179 for (x = 1; x < ncols - 1; x++) {
3180 /* Lower diagonal */
3181 p_Aij[x + ncols * (2 * delta_x - 1)] -= lambda;
3182 /* Main diagonal */
3183 p_Aij[x + ncols * (2 * delta_x)] += lambda * 2.e0;
3184 /* Upper diagonal */
3185 p_Aij[x + ncols * (2 * delta_x + 1)] -= lambda;
3186 }
3187 /* Lower diagonal */
3188 p_Aij[ncols - 1 + ncols * (2 * delta_x - 1)] -= lambda;
3189 /* Main diagonal */
3190 p_Aij[ncols - 1 + ncols * (2 * delta_x)] += lambda;
3191 }
3192
3193 /* Solve the system of equations */
3194 info = cr2res_extract_slitdec_bandsol(p_Aij, p_bj, ncols, nx, lambda);
3195 if (info)
3196 cpl_msg_error(__func__, "info(sP)=%d\n", info);
3197
3198 for (x = 0; x < ncols; x++)
3199 sP[x] = p_bj[x]; /* New Spectrum vector */
3200
3201
3202 /* Compute median value of the spectrum for normalisation purpose */
3203 tmp_vec = cpl_vector_wrap(ncols, sP);
3204 sP_med = fabs(cpl_vector_get_median_const(tmp_vec));
3205 cpl_vector_unwrap(tmp_vec);
3206
3207 /* Compute the change in the spectrum */
3208 sP_change = 0.e0;
3209 for (x = 0; x < ncols; x++) {
3210 if (fabs(sP[x] - sP_old[x]) > sP_change)
3211 sP_change = fabs(sP[x] - sP_old[x]);
3212 }
3213
3214 if ((isnan(sP[0]) || (sP[ncols / 2] == 0)) &&
3215 (cpl_msg_get_level() == CPL_MSG_DEBUG)) {
3216 debug_output(ncols, nrows, osample, im, pix_unc, mask, ycen,
3217 ycen_offset, y_lower_lim, slitcurves);
3218 cpl_msg_error(__func__, "Swath failed");
3219 }
3220
3221 /* Compute the model */
3222 for (y = 0; y < nrows * ncols; y++) {
3223 model[y] = 0.;
3224 }
3225 for (y = 0; y < nrows; y++) {
3226 for (x = 0; x < ncols; x++) {
3227 for (m = 0; m < m_zeta[mzeta_index(x, y)]; m++) {
3228 xx = zeta[zeta_index(x, y, m)].x;
3229 iy = zeta[zeta_index(x, y, m)].iy;
3230 ww = zeta[zeta_index(x, y, m)].w;
3231 model[y * ncols + x] += sP[xx] * sL[iy] * ww;
3232 }
3233 }
3234 }
3235 /* Compare model and data */
3236 // We use a simple standard deviation here (which is NOT robust to
3237 // outliers), since it is less strict than a more robust measurement
3238 // (e.g. MAD) would be. Initial problems in the guess will be more
3239 // easily be fixed this way. We would mask them away otherwise.
3240 // On the other hand the std may get to large and might fail to remove
3241 // outliers sufficiently in some circumstances.
3242
3243 cost = 0.e0;
3244 sum = 0.e0;
3245 isum = 0;
3246 for (y = 0; y < nrows; y++) {
3247 for (x = delta_x; x < ncols - delta_x; x++) {
3248 if (mask[y * ncols + x]) {
3249 tmp = model[y * ncols + x] - im[y * ncols + x];
3250 sum += tmp * tmp;
3251 tmp /= max(pix_unc[y * ncols + x], 1);
3252 cost += tmp * tmp;
3253 isum++;
3254 }
3255 }
3256 }
3257 cost /= (isum - (ncols + ny));
3258 sigma = sqrt(sum / isum);
3259
3260 /* Adjust the mask marking outliers */
3261 for (y = 0; y < nrows; y++) {
3262 for (x = delta_x; x < ncols - delta_x; x++) {
3263 if (fabs(model[y * ncols + x] - im[y * ncols + x]) >
3264 kappa * sigma)
3265 mask[y * ncols + x] = 0;
3266 else
3267 mask[y * ncols + x] = 1;
3268 }
3269 }
3270
3271 for (y = 0; y < nrows; y++) {
3272 for (x = delta_x; x < ncols - delta_x; x++) {
3273 cpl_image_set(img_mad, x + 1, y + 1,
3274 (model[y * ncols + x] - im[y * ncols + x]));
3275 if ((mask[y * ncols + x] == 0) || (im[y * ncols + x] == 0))
3276 cpl_image_reject(img_mad, x + 1, y + 1);
3277 }
3278 }
3279
3280 cpl_msg_debug(
3281 __func__,
3282 "Iter: %i, Sigma: %f, Cost: %f, sP_change: %f, sP_lim: %f", iter,
3283 sigma, cost, sP_change, sP_stop * sP_med);
3284
3285 iter++;
3286 } while (iter == 1 ||
3287 (iter <= maxiter
3288 // && fabs(cost - cost_old) > sP_stop));
3289 && sP_change > sP_stop * sP_med));
3290
3291 if (iter == maxiter && sP_change > sP_stop * sP_med)
3292 cpl_msg_warning(
3293 __func__,
3294 "Maximum number of %d iterations reached without converging.",
3295 maxiter);
3296
3297 /* Flip sign if converged in negative direction */
3298 sum = 0.0;
3299 for (y = 0; y < ny; y++)
3300 sum += sL[y];
3301 if (sum < 0.0) {
3302 for (y = 0; y < ny; y++)
3303 sL[y] *= -1.0;
3304 for (x = 0; x < ncols; x++)
3305 sP[x] *= -1.0;
3306 sum *= -1.0;
3307 }
3308 tmp_vec = cpl_vector_wrap(ny, sL);
3309 sLmax = cpl_vector_get_max(tmp_vec);
3310 cpl_vector_unwrap(tmp_vec);
3311 cpl_msg_debug(__func__,
3312 "sL-sum, sLmax, osample, nrows, ny: %g, %g, %d, %d, %d", sum,
3313 sLmax, osample, nrows, ny);
3314
3315
3316 /*
3317 for (x = 0; x < ncols; x++) {
3318 double msum;
3319
3320 unc[x] = 0.0;
3321 msum = 0.0;
3322 sum = 0.0;
3323 for (y = 0; y < nrows; y++) {
3324 if (mask[y * ncols + x]) {
3325 msum += (im[y * ncols + x] * model[y * ncols + x]) *
3326 mask[y * ncols + x];
3327 sum += (model[y * ncols + x] * model[y * ncols + x]) *
3328 mask[y * ncols + x];
3329 }
3330 }
3331 if (msum != 0){
3332 // This can give NaNs if m/sum is less than zero, i.e. low/no flux
3333 // due to ignoring background flux.
3334 unc[x] = sqrt(fabs(sP[x]) * fabs(sum) / fabs(msum) / error_factor);
3335 } else {
3336 // Fix bad value to NaN as Phase3 doesn't allow Inf.
3337 unc[x] = NAN;
3338 }
3339 }
3340 */
3341 if (error_factor == -1)
3342 {
3343 // Uncertainty calculation, following Horne 1986.
3344 for (x = 0; x < ncols; x++)
3345 {
3346 double num_sum;
3347 double den_sum;
3348 double model_sum = 0.0;
3349
3350 unc[x] = 0.0;
3351 num_sum = 0.0;
3352 den_sum = 0.0;
3353 for (y = 0; y < nrows; y++)
3354 {
3355 model_sum += model[y * ncols + x];
3356 }
3357 for (y = 0; y < nrows; y++)
3358 {
3359 double model_norm = model[y * ncols + x] / model_sum;
3360 num_sum += model_norm * mask[y * ncols + x];
3361 den_sum += (model_norm * model_norm) * mask[y * ncols + x] / (pix_unc[y * ncols + x] * pix_unc[y * ncols + x]);
3362 }
3363 if (den_sum != 0)
3364 {
3365 unc[x] = sqrt(fabs(num_sum / den_sum));
3366 }
3367 else
3368 {
3369 unc[x] = NAN;
3370 }
3371 }
3372 }
3373 else
3374 {
3375 // Uncertainty calculation only using total object flux, needs later correction.
3376 for (x = 0; x < ncols; x++)
3377 {
3378 double msum;
3379
3380 unc[x] = 0.0;
3381 msum = 0.0;
3382 sum = 0.0;
3383 for (y = 0; y < nrows; y++)
3384 {
3385 if (mask[y * ncols + x])
3386 {
3387 msum += (im[y * ncols + x] * model[y * ncols + x]) *
3388 mask[y * ncols + x];
3389 sum += (model[y * ncols + x] * model[y * ncols + x]) *
3390 mask[y * ncols + x];
3391 }
3392 }
3393 if (msum != 0)
3394 {
3395 // This can give NaNs if m/sum is less than zero, i.e. low/no flux
3396 // due to ignoring background flux.
3397 unc[x] = sqrt(fabs(sP[x]) * fabs(sum) / fabs(msum) / error_factor);
3398 }
3399 else
3400 {
3401 // Fix bad value to NaN as Phase3 doesn't allow Inf.
3402 unc[x] = NAN;
3403 }
3404 }
3405 }
3406 return 0;
3407}
3408
3409/*----------------------------------------------------------------------------*/
3435/*----------------------------------------------------------------------------*/
3436int cr2res_extract_slitdec_bandsol(
3437 double * a,
3438 double * r,
3439 int n,
3440 int nd,
3441 double lambda)
3442{
3443 double aa;
3444 int i, j, k;
3445
3446 //if(fmod(nd,2)==0) return -1;
3447
3448 /* Forward sweep */
3449 for(i=0; i<n-1; i++)
3450 {
3451 aa=a[i+n*(nd/2)];
3452 if(aa==0.e0) aa = lambda; //return -3;
3453 r[i]/=aa;
3454 for(j=0; j<nd; j++) a[i+j*n]/=aa;
3455 for(j=1; j<min(nd/2+1,n-i); j++)
3456 {
3457 aa=a[i+j+n*(nd/2-j)];
3458 r[i+j]-=r[i]*aa;
3459 for(k=0; k<n*(nd-j); k+=n) a[i+j+k]-=a[i+k+n*j]*aa;
3460 }
3461 }
3462
3463 /* Backward sweep */
3464 aa = a[n-1+n*(nd/2)];
3465 if (aa == 0) aa = lambda; //return -4;
3466 r[n-1]/=aa;
3467 for(i=n-1; i>0; i--)
3468 {
3469 for(j=1; j<=min(nd/2,i); j++){
3470 r[i-j]-=r[i]*a[i-j+n*(nd/2+j)];
3471 }
3472 aa = a[i-1+n*(nd/2)];
3473 if(aa==0.e0) aa = lambda; //return -5;
3474
3475 r[i-1]/=aa;
3476 }
3477
3478 aa = a[n*(nd/2)];
3479 if(aa==0.e0) aa = lambda; //return -6;
3480 r[0]/=aa;
3481 return 0;
3482}
3483
3484/*----------------------------------------------------------------------------*/
3495/*----------------------------------------------------------------------------*/
3496static int cr2res_extract_slitdec_adjust_swath(
3497 cpl_vector * ycen,
3498 int height,
3499 int leny,
3500 int sw,
3501 int lenx,
3502 int dx,
3503 cpl_vector ** bins_begin,
3504 cpl_vector ** bins_end)
3505{
3506 if (sw <= 0 || lenx <= 0) return -1;
3507 if (bins_begin == NULL || bins_end == NULL) return -1;
3508 if (ycen == NULL) return -1;
3509
3510 // special case only one swath
3511 if (sw==CR2RES_DETECTOR_SIZE){
3512 *bins_begin = cpl_vector_new(1);
3513 *bins_end = cpl_vector_new(1);
3514 cpl_vector_set(*bins_begin, 0, 0);
3515 cpl_vector_set(*bins_end, 0, CR2RES_DETECTOR_SIZE);
3516 return CR2RES_DETECTOR_SIZE;
3517 }
3518
3519 int nbin, nx, i = 0;
3520 double step = 0;
3521 int start = 0, end = lenx;
3522 // Setting them as int, makes this comparable to using ycen_int
3523 int ymin, ymax;
3524 int * ycen_int = cr2res_vector_get_int(ycen);
3525
3526 for (i=0; i < lenx; i++){
3527 ymin = ycen_int[i] - (height/2);
3528 ymax = ycen_int[i] + (height/2) + height%2 ;
3529 if (!((ymax <= 1) || (ymin > leny))){
3530 start = i;
3531 break;
3532 }
3533 start = lenx;
3534 }
3535 for (i = lenx - 1; i >= 0; i--){
3536 ymin = ycen_int[i] - (height/2);
3537 ymax = ycen_int[i] + (height/2) + height%2 ;
3538 if (!((ymax <= 1) || (ymin > leny))){
3539 end = i + 1;
3540 break;
3541 }
3542 end = 0;
3543 }
3544 cpl_free(ycen_int);
3545 nx = end - start;
3546 if (nx <= 0){
3547 // No valid points in this order
3548 return -1;
3549 }
3550
3551 if (sw > nx - 2 * dx) {
3552 sw = nx - 2 * dx;
3553 if (sw % 2 == 1) sw -= 1;
3554 } else if (sw % 2 == 1) sw += 1;
3555
3556 // Calculate number of bins
3557 nbin = 2 * ((nx - 2 * dx) / sw);
3558 if ((nx - 2 * dx) % sw > sw / 2) nbin++;
3559 if (nbin < 1) nbin = 1;
3560
3561 // Step / 2, to get half width swaths
3562 step = sw / 2;
3563 *bins_begin = cpl_vector_new(nbin);
3564 *bins_end = cpl_vector_new(nbin);
3565
3566 // boundaries of bins
3567 for(i = 0; i < nbin; i++)
3568 {
3569 int bin;
3570 bin = start + min(i * step, nx - sw - 2 * dx);
3571 cpl_vector_set(*bins_begin, i, bin);
3572 cpl_vector_set(*bins_end, i, bin + sw + 2 * dx);
3573 cpl_msg_debug(__func__, "Swath %d goes from %d to %d.", i, bin,
3574 bin + sw + 2 * dx);
3575 }
3576 return sw + 2 * dx;
3577}
3578
3579static int debug_output(
3580 int ncols,
3581 int nrows,
3582 int osample,
3583 double * im,
3584 double * pix_unc,
3585 int * mask,
3586 double * ycen,
3587 int * ycen_offset,
3588 int y_lower_lim,
3589 cpl_polynomial ** slitcurves)
3590{
3591 cpl_image * img;
3592 cpl_vector * vec;
3593 cpl_propertylist * pl;
3594
3595 pl = cpl_propertylist_new();
3596 cpl_propertylist_append_int(pl, "osample", osample);
3597 cpl_propertylist_append_int(pl, "y_lower_lim", y_lower_lim);
3598
3599 img = cpl_image_wrap_double(ncols, nrows, im);
3600 cpl_image_save(img, "debug_image_at_error.fits", CPL_TYPE_DOUBLE, pl,
3601 CPL_IO_CREATE);
3602 cpl_image_unwrap(img);
3603
3604 img = cpl_image_wrap_int(ncols, nrows, mask);
3605 cpl_image_save(img, "debug_mask_after_error.fits", CPL_TYPE_INT, NULL,
3606 CPL_IO_CREATE);
3607 cpl_image_unwrap(img);
3608
3609 img = cpl_image_wrap_double(ncols, nrows, pix_unc);
3610 cpl_image_save(img, "debug_unc_at_error.fits", CPL_TYPE_DOUBLE, NULL,
3611 CPL_IO_CREATE);
3612 cpl_image_unwrap(img);
3613
3614 vec = cpl_vector_wrap(ncols, ycen);
3615 cpl_vector_save(vec, "debug_ycen_after_error.fits", CPL_TYPE_DOUBLE, NULL,
3616 CPL_IO_CREATE);
3617 cpl_vector_unwrap(vec);
3618
3619 vec = cpl_vector_new(ncols);
3620 for (int i = 0; i < ncols; i++) cpl_vector_set(vec, i, ycen_offset[i]);
3621 cpl_vector_save(vec, "debug_offset_after_error.fits", CPL_TYPE_INT, NULL,
3622 CPL_IO_CREATE);
3623 cpl_vector_delete(vec);
3624
3625 img = cpl_image_new(ncols, 3, CPL_TYPE_DOUBLE);
3626 for (cpl_size i = 0; i < ncols; i++){
3627 for (cpl_size j = 0; j < 3 ; j++){
3628 cpl_image_set(img, i+1, j+1,
3629 cpl_polynomial_get_coeff(slitcurves[i], &j));
3630 }
3631 }
3632 cpl_image_save(img, "debug_slitcurves_at_error.fits", CPL_TYPE_DOUBLE,
3633 NULL, CPL_IO_CREATE);
3634 cpl_image_delete(img);
3635
3636 cpl_propertylist_delete(pl);
3637
3638 return 0;
3639}
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_POSITIONY_colname(int order_idx, int trace)
Get the POSITIONY table column name for a given order/trace.
Definition: cr2res_dfs.c:468
char * cr2res_dfs_SLIT_FRACTION_colname(int order_idx, int trace)
Get the SLIT_FRACTION table column name for a given order/trace.
Definition: cr2res_dfs.c:486
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
char * cr2res_dfs_POSITIONX_colname(int order_idx, int trace)
Get the POSITIONX table column name for a given order/trace.
Definition: cr2res_dfs.c:450
cpl_table * cr2res_extract_EXTRACT1D_create(cpl_bivector **spectrum, const cpl_table *trace_table)
Create the extract 1D table to be saved.
int cr2res_extract_SLIT_FUNC_get_vector(const cpl_table *tab, int order, int trace_nb, cpl_vector **vec)
Get a vector from the SLIT_FUNC table.
int cr2res_extract_median(const hdrl_image *hdrl_in, const cpl_table *trace_tab, int order, int trace_id, int height, cpl_vector **slit_func, cpl_bivector **spec, hdrl_image **model)
Simple extraction function with the median.
int cr2res_extract_sum_tilt(const hdrl_image *hdrl_in, const cpl_table *trace_tab, int order, int trace_id, int height, cpl_vector **slit_func, cpl_bivector **spec, hdrl_image **model)
Simple extraction function with curvature correction.
cpl_table * cr2res_extract_EXTRACT2D_create(cpl_bivector **spectrum, cpl_bivector **position, cpl_vector **wavelength, cpl_vector **slit_fraction, const cpl_table *trace_table)
Create the extract 2D table to be saved.
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.
int cr2res_extract_sum_vert(const hdrl_image *hdrl_in, const cpl_table *trace_tab, int order, int trace_id, int height, cpl_vector **slit_func, cpl_bivector **spec, hdrl_image **model)
Simple extraction function.
int cr2res_extract2d_trace(const hdrl_image *in, const cpl_table *trace_tab, int order, int trace_id, int npoints, const cpl_image *wavemap, const cpl_image *slitmap, cpl_bivector **spectrum, cpl_bivector **position, cpl_vector **wavelength, cpl_vector **slit_fraction)
Extraction2d function.
cpl_table * cr2res_extract_SLITFUNC_create(cpl_vector **slit_func, const cpl_table *trace_table)
Create the slit functions table to be saved.
int cr2res_extract_slitdec_curved(const hdrl_image *img_hdrl, const cpl_table *trace_tab, const cpl_vector *slit_func_vec_in, int order, int trace_id, int height, int swath, int oversample, double pclip, double smooth_slit, double smooth_spec, int niter, double kappa, double error_factor, cpl_vector **slit_func, cpl_bivector **spec, hdrl_image **model)
Extract optimally (slit-decomposition) with polynomial slit.
int cr2res_extract_traces(const hdrl_image *img, const cpl_table *traces, const cpl_table *slit_func_in, const cpl_table *blaze_table_in, float blaze_norm, int reduce_order, int reduce_trace, cr2res_extr_method extr_method, int extr_height, int swath_width, int oversample, double pclip, double smooth_slit, double smooth_spec, int niter, double kappa, double error_factor, int display, int disp_order_idx, int disp_trace, cpl_table **extracted, cpl_table **slit_func, hdrl_image **model_master)
Extracts all the passed traces at once.
int cr2res_extract2d_traces(const hdrl_image *img, const cpl_table *traces, int reduce_order, int reduce_trace, cpl_table **extracted)
Extract2d all the passed traces at once.
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
int cr2res_trace_get_height(const cpl_table *trace, cpl_size order_idx, cpl_size trace_nb)
Computes the average height (pix) of an order, from trace polys.
Definition: cr2res_trace.c:805
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
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
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
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
int * cr2res_vector_get_int(const cpl_vector *ycen)
Definition: cr2res_utils.c:230
cpl_polynomial * cr2res_convert_array_to_poly(const cpl_array *arr)
Convert an array to polynomial.
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_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_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
hdrl_value hdrl_image_get_pixel(const hdrl_image *self, cpl_size xpos, cpl_size ypos, int *pis_rejected)
get pixel values of hdrl_image
Definition: hdrl_image.c:559
cpl_error_code hdrl_image_set_pixel(hdrl_image *self, cpl_size xpos, cpl_size ypos, hdrl_value value)
set pixel values of hdrl_image
Definition: hdrl_image.c:594
cpl_error_code hdrl_image_mul_scalar(hdrl_image *self, hdrl_value value)
Elementwise multiplication of an image with a scalar.
hdrl_image * hdrl_image_duplicate(const hdrl_image *himg)
copy hdrl_image
Definition: hdrl_image.c:391
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
const cpl_image * hdrl_image_get_error_const(const hdrl_image *himg)
get error as cpl image
Definition: hdrl_image.c:144
hdrl_image * hdrl_image_create(const cpl_image *image, const cpl_image *error)
create a new hdrl_image from to existing images by copying them
Definition: hdrl_image.c:295
cpl_image * hdrl_image_get_image(hdrl_image *himg)
get data as cpl image
Definition: hdrl_image.c:105
const cpl_image * hdrl_image_get_image_const(const hdrl_image *himg)
get data as cpl image
Definition: hdrl_image.c:118
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