IIINSTRUMENT Pipeline Reference Manual 6.2.5
isaac_spc_startrace.c
1/* $Id: isaac_spc_startrace.c,v 1.51 2013-03-12 08:06:48 llundin Exp $
2 *
3 * This file is part of the ISAAC Pipeline
4 * Copyright (C) 2002,2003 European Southern Observatory
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
19 */
20
21/*
22 * $Author: llundin $
23 * $Date: 2013-03-12 08:06:48 $
24 * $Revision: 1.51 $
25 * $Name: not supported by cvs2svn $
26 */
27
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31
32/*-----------------------------------------------------------------------------
33 Includes
34 -----------------------------------------------------------------------------*/
35
36#include <math.h>
37#include <float.h>
38#include <cpl.h>
39
40#include "irplib_plugin.h"
41#include "irplib_utils.h"
42#include "irplib_spectrum.h"
43
44#include "isaac_utils.h"
45#include "isaac_pfits.h"
46#include "isaac_dfs.h"
47
48/*-----------------------------------------------------------------------------
49 Define
50 -----------------------------------------------------------------------------*/
51
52#define RECIPE_STRING "isaac_spc_startrace"
53
54#define Z_LR_LEFT_REJ 300
55#define Z_LR_RIGHT_REJ 325
56#define SZ_LR_LEFT_REJ 300
57#define SZ_LR_RIGHT_REJ 325
58#define J_LR_LEFT_REJ 200
59#define J_LR_RIGHT_REJ 200
60#define SH_LR_LEFT_REJ 150
61#define SH_LR_RIGHT_REJ 175
62#define SK_LR_LEFT_REJ 150
63#define SK_LR_RIGHT_REJ 175
64#define MR_LEFT_REJ 30
65#define MR_RIGHT_REJ 30
66
67/*-----------------------------------------------------------------------------
68 Functions prototypes
69 -----------------------------------------------------------------------------*/
70
71static cpl_error_code isaac_spc_startrace_reduce(cpl_frameset *,
72 const cpl_frameset *,
73 const cpl_matrix *, char,
74 const cpl_parameterlist *);
75
76static cpl_size * isaac_spc_startrace_resol(cpl_frameset *);
77static cpl_imagelist * isaac_spc_startrace_load(const cpl_frameset *);
78static cpl_matrix * isaac_spc_startrace_starpos(const cpl_frameset *);
79static cpl_polynomial * isaac_spc_startrace_shape(cpl_image *, double, char,
80 double *);
81static cpl_polynomial * isaac_spc_startrace_distor(cpl_polynomial **,
82 cpl_vector *, int, int);
83static cpl_error_code isaac_spc_startrace_save(cpl_frameset *,
84 const cpl_table *,
85 const cpl_matrix *,
86 const cpl_vector *,
87 cpl_polynomial **,
88 const cpl_frameset *,
89 char,
90 const cpl_parameterlist *);
91
92
93cpl_recipe_define(isaac_spc_startrace, ISAAC_BINARY_VERSION,
94 "Lars Lundin", PACKAGE_BUGREPORT, "2002, 2003, 2008",
95 "ISAAC Spectro startrace recipe",
96 RECIPE_STRING " -- ISAAC Spectro startrace recipe\n"
97 "The files listed in the Set Of Frames (sof-file) "
98 "must be tagged:\n"
99 "raw-file.fits "ISAAC_SPC_STARTRACE_IM_RAW" or\n"
100 "raw-file.fits "ISAAC_SPC_STARTRACE_SP_RAW"\n"
101 "Given N imaging frames, the spectro frames must consist of "
102 "N (or zero) low resolution frames and "
103 "N (or zero) medium resolution frames.");
104
105/*-----------------------------------------------------------------------------
106 Static variables
107 -----------------------------------------------------------------------------*/
108
109static struct {
110 /* Inputs */
111 cpl_size degree;
112 int spec_width;
113 int reject_left;
114 int reject_right;
115 int display;
116 /* Outputs */
117 int arm;
118 isaac_band band;
119 double corr_is1;
120 double corr_is2;
121 double corr_is3;
122 double shapes_fit_q;
123 double dist1;
124 double distx;
125 double disty;
126 double distxy;
127 double distxx;
128 double distyy;
129} isaac_spc_startrace_config;
130
131/*-----------------------------------------------------------------------------
132 Functions code
133 -----------------------------------------------------------------------------*/
134
135/*----------------------------------------------------------------------------*/
143/*----------------------------------------------------------------------------*/
144static
145cpl_error_code isaac_spc_startrace_fill_parameterlist(cpl_parameterlist * self)
146{
147 const char * context = PACKAGE "." RECIPE_STRING;
148 cpl_error_code err;
149
150 cpl_ensure_code(self, CPL_ERROR_NULL_INPUT);
151
152 /* Fill the parameters list */
153
154 /* --degree */
155 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
156 "degree", 3, "deg",
157 context, "polynomial degree");
158 cpl_ensure_code(!err, err);
159
160 /* --spec_width */
161 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
162 "spectrum_width", 40, "spec_width",
163 context, "spectrum width");
164 cpl_ensure_code(!err, err);
165
166 /* --reject_left */
167 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
168 "reject_left", -1, NULL,
169 context, "left part rejection");
170 cpl_ensure_code(!err, err);
171
172 /* --reject_right */
173 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
174 "reject_right", -1, NULL,
175 context, "right part rejection");
176 cpl_ensure_code(!err, err);
177
178 /* --display */
179 err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
180 "display", CPL_FALSE, NULL, context,
181 "Flag to make plots");
182 cpl_ensure_code(!err, err);
183
184 return CPL_ERROR_NONE;
185}
186
187
188/*----------------------------------------------------------------------------*/
196/*----------------------------------------------------------------------------*/
197static int isaac_spc_startrace(cpl_frameset * framelist,
198 const cpl_parameterlist * parlist)
199{
200 const char * sval;
201 cpl_size * labels = NULL;
202 const cpl_frame * cur_frame;
203 cpl_propertylist * plist = NULL;
204 cpl_frameset * imframes = NULL;
205 cpl_frameset * spframes = NULL;
206 cpl_frameset * spframes_lr = NULL;
207 cpl_frameset * spframes_mr = NULL;
208 cpl_matrix * star_pos = NULL;
209 int ndone = 0;
210
211
212 bug_if(0);
213
214 /* Retrieve input parameters */
215
216 /* Polynomial degree */
217 isaac_spc_startrace_config.degree
218 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
219 "degree");
220 /* Spectrum width */
221 isaac_spc_startrace_config.spec_width
222 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
223 "spectrum_width");
224 /* Rejection parameters */
225 isaac_spc_startrace_config.reject_left
226 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
227 "reject_left");
228 isaac_spc_startrace_config.reject_right
229 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
230 "reject_right");
231 /* Display */
232 isaac_spc_startrace_config.display
233 = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
234 "display");
235
236 /* Identify the RAW and CALIB frames in the input frameset */
237 skip_if (isaac_dfs_set_groups(framelist));
238
239 /* Get the arm used (SW or LW) */
240 cur_frame = cpl_frameset_get_position_const(framelist,0);
241 error_if(cur_frame == NULL, CPL_ERROR_DATA_NOT_FOUND,
242 "Could not get 1st frame from frameset");
243 plist = cpl_propertylist_load(cpl_frame_get_filename(cur_frame), 0);
244 any_if("Could not load propertylist from 1st frame");
245
246 sval = isaac_pfits_get_arm(plist);
247 any_if("Could not get the arm");
248
249 if (sval[0] == 'S') {
250 isaac_spc_startrace_config.arm = 1;
251 } else if (sval[0] == 'L') {
252 isaac_spc_startrace_config.arm = 2;
253 } else {
254 error_if(1, CPL_ERROR_UNSUPPORTED_MODE, "Unsupported arm: %s", sval);
255 }
256
257 /* Get the band */
258 sval = isaac_pfits_get_filter(plist);
259 any_if("Could not get the filter");
260
261 isaac_spc_startrace_config.band = isaac_get_bbfilter(sval);
262 any_if("Could not get the band");
263
264 cpl_propertylist_empty(plist);
265
266 /* Retrieve raw frames */
267 imframes = isaac_extract_frameset(framelist, ISAAC_SPC_STARTRACE_IM_RAW);
268 error_if(imframes == NULL, CPL_ERROR_DATA_NOT_FOUND, "Could not find the "
269 "imframes in the input list");
270
271 spframes = isaac_extract_frameset(framelist, ISAAC_SPC_STARTRACE_SP_RAW);
272 error_if(spframes == NULL, CPL_ERROR_DATA_NOT_FOUND, "Could not find the "
273 "spframes in the input list");
274
275 /* Separate LR and MR spectra */
276 labels = isaac_spc_startrace_resol(spframes);
277 error_if(labels == NULL, cpl_error_get_code(), "Could not differentiate "
278 "LR and MR");
279
280 spframes_lr = cpl_frameset_extract(spframes, labels, 1);
281 spframes_mr = cpl_frameset_extract(spframes, labels, 2);
282 cpl_free(labels);
283 labels = NULL;
284
285 /* Get the star positions */
286 cpl_msg_info(cpl_func, "Get the star positions");
287 star_pos = isaac_spc_startrace_starpos(imframes);
288 error_if(star_pos == NULL, cpl_error_get_code(), "Could not find star the "
289 "positions");
290
291 cpl_frameset_delete(imframes);
292 imframes = NULL;
293
294 error_if (spframes_lr == NULL && spframes_mr == NULL,
295 CPL_ERROR_UNSUPPORTED_MODE, "The %d spectro frames are not LR "
296 "nor MR", (int)cpl_frameset_get_size(spframes));
297 cpl_frameset_delete(spframes);
298 spframes = NULL;
299
300 if (spframes_lr != NULL) {
301 cpl_errorstate prestate = cpl_errorstate_get();
302 /* Reduction in LR */
303 cpl_msg_info(cpl_func, "Reducing the LR spectra");
304 if (isaac_spc_startrace_reduce(framelist, spframes_lr, star_pos,
305 'L', parlist)) {
306 irplib_error_recover(prestate, "Could not reduce the LR spectra");
307 } else {
308 ndone++;
309 }
310 cpl_frameset_delete(spframes_lr);
311 spframes_lr = NULL;
312 }
313 if (spframes_mr != NULL) {
314 cpl_errorstate prestate = cpl_errorstate_get();
315 /* Reduction in MR */
316 cpl_msg_info(cpl_func, "Reducing the MR spectra");
317 if (isaac_spc_startrace_reduce(framelist, spframes_mr, star_pos,
318 'M', parlist)) {
319 irplib_error_recover(prestate, "Could not reduce the MR spectra");
320 } else {
321 ndone++;
322 }
323 cpl_frameset_delete(spframes_mr);
324 spframes_mr = NULL;
325 }
326
327 error_if(!ndone, CPL_ERROR_ILLEGAL_INPUT, "Could not reduce the spectra");
328
329 end_skip;
330
331 cpl_free(labels);
332 cpl_propertylist_delete(plist);
333 cpl_frameset_delete(imframes);
334 cpl_frameset_delete(spframes);
335 cpl_frameset_delete(spframes_lr);
336 cpl_frameset_delete(spframes_mr);
337 cpl_matrix_delete(star_pos);
338
339 return cpl_error_get_code();
340}
341
342/*----------------------------------------------------------------------------*/
353/*----------------------------------------------------------------------------*/
354static
355cpl_error_code isaac_spc_startrace_reduce(cpl_frameset * framelist,
356 const cpl_frameset * spframes,
357 const cpl_matrix * star_pos,
358 char resol,
359 const cpl_parameterlist * parlist)
360{
361 /* Load the input images */
362 cpl_imagelist * ilist = isaac_spc_startrace_load(spframes);
363 const int nframes = cpl_frameset_get_size(spframes);
364 cpl_vector * spec_pos = cpl_vector_new(nframes);
365 double * pspec_pos = cpl_vector_get_data(spec_pos);
366 cpl_polynomial * corresp = cpl_polynomial_new(1);
367 cpl_polynomial ** shapes = cpl_calloc(nframes, sizeof(cpl_polynomial*));
368 cpl_vector * fit_q = cpl_vector_new(nframes);
369 double * pfit_q = cpl_vector_get_data(fit_q);
370 const int nx = cpl_image_get_size_x(cpl_imagelist_get(ilist, 0));
371 cpl_polynomial * distor = NULL;
372 cpl_table * out_tab = NULL;
373 cpl_size power[2];
374 const cpl_size maxdeg = 2;
375 cpl_size i;
376
377 bug_if(0);
378 bug_if(framelist == NULL);
379 bug_if(star_pos == NULL);
380 bug_if(parlist == NULL);
381
382 error_if(cpl_matrix_get_ncol(star_pos) != nframes,
383 CPL_ERROR_INCOMPATIBLE_INPUT, "Number of spectro frames (%d) "
384 "differ from number of star positions (%d)", nframes,
385 (int)cpl_matrix_get_ncol(star_pos));
386
387 /* Find the spectra positions */
388 for (i=0; i<nframes; i++) {
389 const cpl_image * image = cpl_imagelist_get_const(ilist, i);
390 const double mean = cpl_image_get_mean(image);
391 const double min_bright = 20.0 * mean;
392
393 error_if (irplib_spectrum_find_brightest(image, 0, NO_SHADOW,
394 min_bright, 0, &(pspec_pos[i])),
395 cpl_error_get_code(), "Could not detect spectrum in frame %d "
396 "of %d with mean flux=%g", (int)i+1, nframes, mean);
397 }
398
399 /* Compute spectra / star correspondance */
400 error_if (cpl_polynomial_fit(corresp, star_pos, NULL, spec_pos, NULL,
401 CPL_FALSE, NULL, &maxdeg), cpl_error_get_code(),
402 "Could not fit a %d degree polynomial to the %d positions",
403 (int)maxdeg, nframes);
404
405 /* Store the result coefficients */
406 i = 0;
407 isaac_spc_startrace_config.corr_is1 = cpl_polynomial_get_coeff(corresp, &i);
408 i = 1;
409 isaac_spc_startrace_config.corr_is2 = cpl_polynomial_get_coeff(corresp, &i);
410 i = 2;
411 isaac_spc_startrace_config.corr_is3 = cpl_polynomial_get_coeff(corresp, &i);
412 cpl_polynomial_delete(corresp);
413 corresp = NULL;
414
415 /* Compute the spectra shapes */
416 for (i=0; i<nframes; i++) {
417 shapes[i] = isaac_spc_startrace_shape(cpl_imagelist_get(ilist, i),
418 cpl_vector_get(spec_pos, i),
419 resol,
420 &(pfit_q[i]));
421
422 error_if (shapes[i] == NULL, cpl_error_get_code(), "Could not get the "
423 "shape of frame %d of %d", (int)i+1, nframes);
424
425 cpl_msg_info(cpl_func, "Spectrum %d : Y = %g; Fit mse = %g", (int)i+1,
426 cpl_vector_get(spec_pos, i), pfit_q[i]);
427 }
428 isaac_spc_startrace_config.shapes_fit_q = cpl_vector_get_median_const(fit_q);
429 cpl_vector_delete(fit_q);
430 fit_q = NULL;
431 cpl_imagelist_delete(ilist);
432 ilist = NULL;
433
434 /* Compute the 2d distortion */
435 distor = isaac_spc_startrace_distor(shapes, spec_pos, nframes, nx);
436 error_if (distor == NULL, cpl_error_get_code(), "Could not compute the "
437 "distortion");
438
439 /* Create the table */
440 out_tab = cpl_table_new(6);
441 cpl_table_new_column(out_tab, "Degree_of_x", CPL_TYPE_INT);
442 cpl_table_new_column(out_tab, "Degree_of_y", CPL_TYPE_INT);
443 cpl_table_new_column(out_tab, "poly2d_coef", CPL_TYPE_DOUBLE);
444 power[0] = 0; power[1] = 0;
445 cpl_table_set_int(out_tab, "Degree_of_x", 0, power[0]);
446 cpl_table_set_int(out_tab, "Degree_of_y", 0, power[1]);
447 isaac_spc_startrace_config.dist1 = cpl_polynomial_get_coeff(distor, power);
448 cpl_table_set_double(out_tab, "poly2d_coef", 0,
449 isaac_spc_startrace_config.dist1);
450 power[0] = 1; power[1] = 0;
451 cpl_table_set_int(out_tab, "Degree_of_x", 1, power[0]);
452 cpl_table_set_int(out_tab, "Degree_of_y", 1, power[1]);
453 isaac_spc_startrace_config.distx = cpl_polynomial_get_coeff(distor, power);
454 cpl_table_set_double(out_tab, "poly2d_coef", 1,
455 isaac_spc_startrace_config.distx);
456 power[0] = 0; power[1] = 1;
457 cpl_table_set_int(out_tab, "Degree_of_x", 2, power[0]);
458 cpl_table_set_int(out_tab, "Degree_of_y", 2, power[1]);
459 isaac_spc_startrace_config.disty = cpl_polynomial_get_coeff(distor, power);
460 cpl_table_set_double(out_tab, "poly2d_coef", 2,
461 isaac_spc_startrace_config.disty);
462 power[0] = 1; power[1] = 1;
463 cpl_table_set_int(out_tab, "Degree_of_x", 3, power[0]);
464 cpl_table_set_int(out_tab, "Degree_of_y", 3, power[1]);
465 isaac_spc_startrace_config.distxy = cpl_polynomial_get_coeff(distor, power);
466 cpl_table_set_double(out_tab, "poly2d_coef", 3,
467 isaac_spc_startrace_config.distxy);
468 power[0] = 2; power[1] = 0;
469 cpl_table_set_int(out_tab, "Degree_of_x", 4, power[0]);
470 cpl_table_set_int(out_tab, "Degree_of_y", 4, power[1]);
471 isaac_spc_startrace_config.distxx = cpl_polynomial_get_coeff(distor, power);
472 cpl_table_set_double(out_tab, "poly2d_coef", 4,
473 isaac_spc_startrace_config.distxx);
474 power[0] = 0; power[1] = 2;
475 cpl_table_set_int(out_tab, "Degree_of_x", 5, power[0]);
476 cpl_table_set_int(out_tab, "Degree_of_y", 5, power[1]);
477 isaac_spc_startrace_config.distyy = cpl_polynomial_get_coeff(distor, power);
478 cpl_table_set_double(out_tab, "poly2d_coef", 5,
479 isaac_spc_startrace_config.distyy);
480
481 cpl_polynomial_delete(distor);
482 distor = NULL;
483
484 /* Display result */
485 cpl_msg_info(cpl_func,
486 "Distortion : Y(x,y) = a + bx + cy + dxy + exx + fyy");
487 cpl_msg_info(cpl_func, "a = %g", isaac_spc_startrace_config.dist1);
488 cpl_msg_info(cpl_func, "b = %g", isaac_spc_startrace_config.distx);
489 cpl_msg_info(cpl_func, "c = %g", isaac_spc_startrace_config.disty);
490 cpl_msg_info(cpl_func, "d = %g", isaac_spc_startrace_config.distxy);
491 cpl_msg_info(cpl_func, "e = %g", isaac_spc_startrace_config.distxx);
492 cpl_msg_info(cpl_func, "f = %g", isaac_spc_startrace_config.distyy);
493
494 /* Write the product */
495 skip_if (isaac_spc_startrace_save(framelist, out_tab, star_pos, spec_pos,
496 shapes, spframes, resol, parlist));
497
498 end_skip;
499
500 cpl_polynomial_delete(distor);
501 cpl_vector_delete(fit_q);
502 cpl_polynomial_delete(corresp);
503 if (shapes != NULL) {
504 for (i = 0; i < nframes; i++) cpl_polynomial_delete(shapes[i]);
505 cpl_free(shapes);
506 }
507 cpl_vector_delete(spec_pos);
508 cpl_imagelist_delete(ilist);
509 cpl_table_delete(out_tab);
510
511 return cpl_error_get_code();
512}
513
514/*----------------------------------------------------------------------------*/
522/*----------------------------------------------------------------------------*/
523static cpl_size * isaac_spc_startrace_resol(cpl_frameset * spframes)
524{
525 int nframes;
526 cpl_size * labels;
527 cpl_frame * cur_frame;
528 cpl_propertylist * plist;
529 const char * sval;
530 int i;
531
532 /* Test entries */
533 if (spframes == NULL) return NULL;
534
535 /* Initialise */
536 nframes = cpl_frameset_get_size(spframes);
537
538 /* Create output array */
539 labels = (cpl_size*)cpl_malloc(nframes * sizeof(*labels));
540
541 /* Loop on the frames */
542 for (i=0; i<nframes; i++) {
543 cur_frame = cpl_frameset_get_position(spframes, i);
544 plist=cpl_propertylist_load(cpl_frame_get_filename(cur_frame), 0);
545 /* Get the resolution */
546 if ((sval = isaac_pfits_get_resolution(plist)) == NULL) {
547 cpl_free(labels);
548 cpl_msg_error(cpl_func,"cannot get the resolution");
549 return NULL;
550 }
551 if (sval[0]=='L') labels[i] = 1;
552 else if (sval[0]=='M') labels[i] = 2;
553 else labels[i] = 0;
554 cpl_propertylist_delete(plist);
555 }
556 return labels;
557}
558
559/*----------------------------------------------------------------------------*/
566/*----------------------------------------------------------------------------*/
567static cpl_matrix * isaac_spc_startrace_starpos(const cpl_frameset * imframes)
568{
569 int nframes;
570 cpl_matrix * ypositions;
571 cpl_apertures * objects;
572 double * ypos;
573 cpl_imagelist * ilist;
574 int i;
575
576 /* Test entries */
577 if (imframes == NULL) return NULL;
578
579 /* Load the input images */
580 if ((ilist = isaac_spc_startrace_load(imframes)) == NULL) return NULL;
581
582 /* Initialise */
583 nframes = cpl_frameset_get_size(imframes);
584
585 /* Create bivector */
586 ypositions = cpl_matrix_new(1, nframes);
587 ypos = cpl_matrix_get_data(ypositions);
588
589 /* Loop on the frames */
590 for (i=0; i<nframes; i++) {
591 double xpos;
592 if ((objects = cpl_apertures_extract_sigma(cpl_imagelist_get(ilist, i),
593 2.0)) == NULL) {
594 cpl_msg_error(cpl_func, "cannot detect any object");
595 cpl_matrix_delete(ypositions);
596 cpl_imagelist_delete(ilist);
597 return NULL;
598 }
599 cpl_apertures_sort_by_flux(objects);
600 xpos = cpl_apertures_get_centroid_x(objects, 1);
601 ypos[i] = cpl_apertures_get_centroid_y(objects, 1);
602 cpl_apertures_delete(objects);
603 cpl_msg_info(cpl_func, "Image %d: Position (%g, %g)", i+1,xpos, ypos[i]);
604 }
605 cpl_imagelist_delete(ilist);
606 return ypositions;
607}
608
609/*----------------------------------------------------------------------------*/
616/*----------------------------------------------------------------------------*/
617static cpl_imagelist * isaac_spc_startrace_load(const cpl_frameset * inframes)
618{
619 cpl_imagelist * ilist;
620 int nframes;
621 cpl_image * tmp_im;
622 int i;
623
624 /* Test entries */
625 if (inframes == NULL) return NULL;
626
627 /* Initialise */
628 nframes = cpl_frameset_get_size(inframes);
629
630 /* Load the images */
631 if ((ilist = cpl_imagelist_load_frameset(inframes, CPL_TYPE_FLOAT, 1,
632 0)) == NULL) return NULL;
633
634 /* In LW that's it */
635 if (isaac_spc_startrace_config.arm == 2) return ilist;
636
637 /* In SW, the frames are subtracted to remove the background */
638 tmp_im = cpl_image_duplicate(cpl_imagelist_get(ilist, 0));
639 for (i=0; i<nframes-1; i++) {
640 if (cpl_image_subtract(cpl_imagelist_get(ilist, i),
641 cpl_imagelist_get(ilist, i+1)) != CPL_ERROR_NONE) {
642 cpl_msg_error(cpl_func, "cannot subtract images");
643 cpl_imagelist_delete(ilist);
644 cpl_image_delete(tmp_im);
645 return NULL;
646 }
647 }
648 /* Handle last frame */
649 if (cpl_image_subtract(cpl_imagelist_get(ilist, nframes-1),
650 tmp_im) != CPL_ERROR_NONE) {
651 cpl_msg_error(cpl_func, "cannot subtract images");
652 cpl_imagelist_delete(ilist);
653 cpl_image_delete(tmp_im);
654 return NULL;
655 }
656 cpl_image_delete(tmp_im);
657
658 /* Set negative pixels to 0 */
659 cpl_imagelist_threshold(ilist, 0.0, DBL_MAX, 0.0, 0.0);
660
661 return ilist;
662}
663
664/*----------------------------------------------------------------------------*/
674/*----------------------------------------------------------------------------*/
675static cpl_polynomial * isaac_spc_startrace_shape(
676 cpl_image * in,
677 double ypos,
678 char resol,
679 double * fit_quality)
680{
681 int reject_left, reject_right;
682 cpl_image * filtered;
683 int low_side, up_side;
684 cpl_mask * kernel;
685 cpl_matrix * fit_x;
686 cpl_vector * fit_y;
687 double * pfit_x;
688 double * pfit_y;
689 cpl_polynomial * fitted;
690 cpl_bivector * toplot;
691 int i;
692 int nsamples;
693 const cpl_boolean sampsym = CPL_TRUE; /* fit_x is symmetric */
694
695 /* Check entries */
696 if ((in == NULL) || (ypos < 0) || (fit_quality == NULL)) return NULL;
697
698 /* Initialise */
699 reject_left = isaac_spc_startrace_config.reject_left;
700 reject_right = isaac_spc_startrace_config.reject_right;
701 low_side = (int)(ypos - (isaac_spc_startrace_config.spec_width)/2);
702 up_side = low_side + isaac_spc_startrace_config.spec_width;
703
704 /* Test spectrum position */
705 if ((low_side < 1) || (up_side > cpl_image_get_size_y(in))) {
706 cpl_msg_error(cpl_func, "spectrum too close to the image border");
707 return NULL;
708 }
709
710 /* Get rejection parameters */
711 if (isaac_spc_startrace_config.arm == 1) {
712 /* SW */
713 if (reject_left < 0) {
714 if (resol == 'M') reject_left = MR_LEFT_REJ;
715 else if (resol == 'L') {
716 switch (isaac_spc_startrace_config.band) {
717 case ISAAC_BAND_Z: reject_left = Z_LR_LEFT_REJ; break;
718 case ISAAC_BAND_SZ: reject_left = SZ_LR_LEFT_REJ; break;
719 case ISAAC_BAND_JBLOCK:
720 case ISAAC_BAND_J: reject_left = J_LR_LEFT_REJ; break;
721 case ISAAC_BAND_SH: reject_left = SH_LR_LEFT_REJ; break;
722 case ISAAC_BAND_SK: reject_left = SK_LR_LEFT_REJ; break;
723 default:
724 cpl_msg_warning(cpl_func, "unsupported filter");
725 reject_left = 0;
726 break;
727 }
728 }
729 }
730 if (reject_right < 0) {
731 if (resol == 'M') reject_right = MR_RIGHT_REJ;
732 else if (resol == 'L') {
733 switch (isaac_spc_startrace_config.band) {
734 case ISAAC_BAND_Z: reject_right = Z_LR_RIGHT_REJ; break;
735 case ISAAC_BAND_SZ: reject_right = SZ_LR_RIGHT_REJ;break;
736 case ISAAC_BAND_JBLOCK:
737 case ISAAC_BAND_J: reject_right = J_LR_RIGHT_REJ; break;
738 case ISAAC_BAND_SH: reject_right = SH_LR_RIGHT_REJ;break;
739 case ISAAC_BAND_SK: reject_right = SK_LR_RIGHT_REJ;break;
740 default:
741 cpl_msg_warning(cpl_func, "unsupported filter");
742 reject_right = 0;
743 break;
744 }
745 }
746 }
747 } else if (isaac_spc_startrace_config.arm == 2) {
748 /* LW */
749 if (reject_left < 0) reject_left = 150;
750 if (reject_right < 0) reject_right = 150;
751
752 } else {
753 cpl_msg_error(cpl_func, "Unrecognized mode - abort");
754 return NULL;
755 }
756
757 /* Filter the image */
758 kernel = cpl_mask_new(3, 3);
759 cpl_mask_not(kernel);
760 filtered = cpl_image_new(cpl_image_get_size_x(in), cpl_image_get_size_y(in),
761 cpl_image_get_type(in));
762 if (cpl_image_filter_mask(filtered, in, kernel, CPL_FILTER_MEDIAN,
763 CPL_BORDER_FILTER)) {
764 cpl_msg_error(cpl_func, "cannot filter the image");
765 cpl_mask_delete(kernel);
766 return NULL;
767 }
768 cpl_mask_delete(kernel);
769
770 /* Fill the vector to fit */
771 nsamples = cpl_image_get_size_x(in) - reject_right - reject_left;
772 fit_x = cpl_matrix_new(1, nsamples);
773 pfit_x = cpl_matrix_get_data(fit_x);
774 fit_y = cpl_vector_new(nsamples);
775 pfit_y = cpl_vector_get_data(fit_y);
776 for (i=0; i < nsamples; i++) {
777 pfit_x[i] = (double)(i+1+reject_left);
778 pfit_y[i] = cpl_image_get_centroid_y_window(filtered, i+1+reject_left,
779 low_side, i+1+reject_left, up_side);
780 }
781 cpl_image_delete(filtered);
782
783 /* Apply the fit */
784 fitted = cpl_polynomial_new(1);
785 if (cpl_polynomial_fit(fitted, fit_x, &sampsym, fit_y, NULL, CPL_FALSE,
786 NULL, &(isaac_spc_startrace_config.degree))) {
787 cpl_msg_error(cpl_func, "cannot fit the shape");
788 cpl_polynomial_delete(fitted);
789 cpl_matrix_delete(fit_x);
790 cpl_vector_delete(fit_y);
791 return NULL;
792 }
793
794 /* Display if requested */
795 if (isaac_spc_startrace_config.display) {
796 cpl_vector * vfit_x
797 = cpl_vector_wrap(nsamples, pfit_x);
798 toplot = cpl_bivector_wrap_vectors(vfit_x, fit_y);
799 cpl_plot_bivector(NULL, NULL, NULL, toplot);
800 cpl_bivector_unwrap_vectors(toplot);
801 (void)cpl_vector_unwrap(vfit_x);
802 }
803
804 cpl_vector_fill_polynomial_fit_residual(fit_y, fit_y, NULL, fitted,
805 fit_x, NULL);
806 *fit_quality = cpl_vector_product(fit_y, fit_y) / nsamples;
807
808 /* Display if requested */
809 if (isaac_spc_startrace_config.display) {
810 cpl_vector * vfit_x
811 = cpl_vector_wrap(nsamples, pfit_x);
812 toplot = cpl_bivector_wrap_vectors(vfit_x, fit_y);
813 for (i=0; i<nsamples; i++) {
814 pfit_y[i] = cpl_polynomial_eval_1d(fitted, pfit_x[i], NULL);
815 }
816 cpl_plot_bivector(NULL, NULL, NULL, toplot);
817 cpl_bivector_unwrap_vectors(toplot);
818 (void)cpl_vector_unwrap(vfit_x);
819 }
820
821 /* Free and return */
822 cpl_matrix_delete(fit_x);
823 cpl_vector_delete(fit_y);
824 return fitted;
825}
826
827/*----------------------------------------------------------------------------*/
837/*----------------------------------------------------------------------------*/
838static cpl_polynomial * isaac_spc_startrace_distor(
839 cpl_polynomial ** shapes,
840 cpl_vector * spec_pos,
841 int nshapes,
842 int nx)
843{
844 cpl_polynomial * distor;
845 cpl_matrix * xy_vec;
846 double * x_data;
847 double * y_data;
848 cpl_vector * z_vec;
849 double * z_data;
850 int nb_xpoints, npoints;
851 int pos;
852 int i, j;
853 const cpl_size maxdeg = 2;
854
855 /* Initialise */
856 nb_xpoints = 20;
857 npoints = nb_xpoints * nshapes;
858
859 /* Prepare the surface */
860 xy_vec = cpl_matrix_new(2, npoints);
861 x_data = cpl_matrix_get_data(xy_vec);
862 y_data = x_data + npoints;
863 z_vec = cpl_vector_new(npoints);
864 z_data = cpl_vector_get_data(z_vec);
865 for (j=0; j<nshapes; j++) {
866 for (i=0; i<nb_xpoints; i++) {
867 pos = i + j*nb_xpoints;
868 x_data[pos] = nx * (i+1) / nb_xpoints;
869 y_data[pos] = cpl_vector_get(spec_pos, j);
870 z_data[pos] = cpl_polynomial_eval_1d(shapes[j], x_data[pos], NULL);
871 }
872 }
873
874 /* Apply the fit */
875 distor = cpl_polynomial_new(2);
876 if (cpl_polynomial_fit(distor, xy_vec, NULL, z_vec, NULL, CPL_FALSE, NULL,
877 &maxdeg)) {
878 cpl_msg_error(cpl_func, "cannot fit the distortion");
879 cpl_matrix_delete(xy_vec);
880 cpl_vector_delete(z_vec);
881 cpl_polynomial_delete(distor);
882 return NULL;
883 }
884 cpl_matrix_delete(xy_vec);
885 cpl_vector_delete(z_vec);
886
887 return distor;
888}
889
890/*----------------------------------------------------------------------------*/
904/*----------------------------------------------------------------------------*/
905static
906cpl_error_code isaac_spc_startrace_save(cpl_frameset * set_tot,
907 const cpl_table * tab,
908 const cpl_matrix * star_pos,
909 const cpl_vector * spec_pos,
910 cpl_polynomial ** shapes,
911 const cpl_frameset * set,
912 char resol,
913 const cpl_parameterlist * parlist)
914{
915 cpl_propertylist * plist;
916 cpl_propertylist * qclist;
917 cpl_propertylist * paflist;
918 const cpl_frame * ref_frame;
919 char colname[128];
920 cpl_table * shapes_table;
921 cpl_table * pos_table;
922 const char * procatt;
923 const char * procat;
924 char * filename;
925 int i;
926
927 /* Get the QC params in qclist */
928 qclist = cpl_propertylist_new();
929
930 /* Add QC parameters */
931 cpl_propertylist_append_double(qclist, "ESO QC CORR_IS1",
932 isaac_spc_startrace_config.corr_is1);
933 cpl_propertylist_append_double(qclist, "ESO QC CORR_IS2",
934 isaac_spc_startrace_config.corr_is2);
935 cpl_propertylist_append_double(qclist, "ESO QC CORR_IS3",
936 isaac_spc_startrace_config.corr_is3);
937 cpl_propertylist_append_double(qclist, "ESO QC FITMSE",
938 isaac_spc_startrace_config.shapes_fit_q);
939 cpl_propertylist_append_double(qclist, "ESO QC DIST1",
940 isaac_spc_startrace_config.dist1);
941 cpl_propertylist_append_double(qclist, "ESO QC DISTX",
942 isaac_spc_startrace_config.distx);
943 cpl_propertylist_append_double(qclist, "ESO QC DISTY",
944 isaac_spc_startrace_config.disty);
945 cpl_propertylist_append_double(qclist, "ESO QC DISTXY",
946 isaac_spc_startrace_config.distxy);
947 cpl_propertylist_append_double(qclist, "ESO QC DISTXX",
948 isaac_spc_startrace_config.distxx);
949 cpl_propertylist_append_double(qclist, "ESO QC DISTYY",
950 isaac_spc_startrace_config.distyy);
951
952 /* Write the distortion table */
953 procatt = isaac_spc_startrace_config.arm == 1
954 ? ISAAC_SPC_STARTRACE_SW_RES : ISAAC_SPC_STARTRACE_LW_RES;
955 filename = cpl_sprintf("isaac_spc_startrace_2dpoly_%cR.fits", resol);
956 irplib_dfs_save_table(set_tot,
957 parlist,
958 set,
959 tab,
960 NULL,
961 "isaac_spc_startrace",
962 procatt,
963 qclist,
964 NULL,
965 PACKAGE "/" PACKAGE_VERSION,
966 filename);
967 cpl_free(filename);
968
969 /* Save the positions table */
970 pos_table = cpl_table_new(cpl_matrix_get_ncol(star_pos));
971
972 /* star_pos is _not_ modified */
973 cpl_table_wrap_double(pos_table, cpl_matrix_get_data((cpl_matrix*)star_pos),
974 "Star_positions");
975 /* spec_pos is _not_ modified */
976 cpl_table_wrap_double(pos_table, cpl_vector_get_data((cpl_vector*)spec_pos),
977 "Spec_positions");
978
979 procat = isaac_spc_startrace_config.arm == 1
980 ? ISAAC_SPC_STARTRACE_SW_POS : ISAAC_SPC_STARTRACE_LW_POS;
981 filename = cpl_sprintf("isaac_spc_startrace_positions_%cR.fits", resol);
982 irplib_dfs_save_table(set_tot,
983 parlist,
984 set,
985 tab,
986 NULL,
987 "isaac_spc_startrace",
988 procat,
989 qclist,
990 NULL,
991 PACKAGE "/" PACKAGE_VERSION,
992 filename);
993 cpl_free(filename);
994
995 (void)cpl_table_unwrap(pos_table, "Star_positions");
996 (void)cpl_table_unwrap(pos_table, "Spec_positions");
997 cpl_table_delete(pos_table);
998
999 /* Save the shapes table */
1000 shapes_table = cpl_table_new(isaac_spc_startrace_config.degree + 1);
1001 for (i=0; i<cpl_vector_get_size(spec_pos); i++) {
1002 sprintf(colname, "Spec_%d", i+1);
1003 cpl_table_new_column(shapes_table, colname, CPL_TYPE_DOUBLE);
1004 }
1005 for (i=0; i<cpl_vector_get_size(spec_pos); i++) {
1006 cpl_size j;
1007 sprintf(colname, "Spec_%d", i+1);
1008 for (j=0; j<isaac_spc_startrace_config.degree + 1; j++) {
1009 cpl_table_set_double(shapes_table, colname, j,
1010 cpl_polynomial_get_coeff(shapes[i], &j));
1011 }
1012 }
1013 procat = isaac_spc_startrace_config.arm == 1 ?
1014 ISAAC_SPC_STARTRACE_SW_SHAPE : ISAAC_SPC_STARTRACE_LW_SHAPE;
1015 filename = cpl_sprintf("isaac_spc_startrace_shapes_%cR.fits", resol);
1016 irplib_dfs_save_table(set_tot,
1017 parlist,
1018 set,
1019 tab,
1020 NULL,
1021 "isaac_spc_startrace",
1022 procat,
1023 qclist,
1024 NULL,
1025 PACKAGE "/" PACKAGE_VERSION,
1026 filename);
1027 cpl_free(filename);
1028 cpl_table_delete(shapes_table);
1029
1030 /* Get the reference frame */
1031 ref_frame = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW);
1032
1033 /* Get FITS header from reference file */
1034 if ((plist=cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
1035 0)) == NULL) {
1036 cpl_msg_error(cpl_func, "getting header from reference frame");
1037 cpl_propertylist_delete(qclist);
1038 return CPL_ERROR_UNSPECIFIED;
1039 }
1040
1041 /* Get the keywords for the paf file */
1042 paflist = cpl_propertylist_new();
1043 cpl_propertylist_copy_property_regexp(paflist, plist,
1044 "^(ARCFILE|MJD-OBS|INSTRUME|ESO TPL ID|ESO TPL NEXP|ESO DPR CATG|"
1045 "ESO DPR TECH|ESO DPR TYPE|DATE-OBS|ESO INS GRAT NAME|"
1046 "ESO OCS SELECT-ARM)$", 0);
1047 cpl_propertylist_delete(plist);
1048
1049 /* Copy the QC in paflist */
1050 cpl_propertylist_copy_property_regexp(paflist, qclist, ".", 0);
1051 cpl_propertylist_delete(qclist);
1052
1053 /* PRO.CATG */
1054 cpl_propertylist_update_string(paflist, CPL_DFS_PRO_CATG, procatt);
1055
1056 /* Save the PAF file */
1057 filename = cpl_sprintf("isaac_spc_startrace_%cR.paf", resol);
1058 cpl_dfs_save_paf("ISAAC",
1059 "isaac_spc_startrace",
1060 paflist,
1061 filename);
1062 cpl_free(filename);
1063 cpl_propertylist_delete(paflist);
1064 return 0;
1065}
1066
int isaac_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
Definition: isaac_dfs.c:60
const char * isaac_pfits_get_filter(const cpl_propertylist *plist)
find out the filter
Definition: isaac_pfits.c:880
const char * isaac_pfits_get_arm(const cpl_propertylist *plist)
find out the arm which is active
Definition: isaac_pfits.c:106
const char * isaac_pfits_get_resolution(const cpl_propertylist *plist)
find out the resolution
Definition: isaac_pfits.c:775
isaac_band isaac_get_bbfilter(const char *f)
Get the broad band filter.
Definition: isaac_utils.c:144
cpl_frameset * isaac_extract_frameset(const cpl_frameset *self, const char *tag)
Extract the frames with the given tag from a frameset.
Definition: isaac_utils.c:356