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