IIINSTRUMENT Pipeline Reference Manual 6.2.5
isaac_spc_jitter.c
1/* $Id: isaac_spc_jitter.c,v 1.94 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.94 $
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 <cpl.h>
37
38#include "irplib_plugin.h"
39#include "irplib_utils.h"
40#include "irplib_stdstar.h"
41#include "irplib_spectrum.h"
42
43#include "isaac_utils.h"
44#include "isaac_wavelength.h"
45#include "isaac_physicalmodel.h"
46#include "isaac_pfits.h"
47#include "isaac_dfs.h"
48
49#include <string.h>
50#include <math.h>
51
52/*-----------------------------------------------------------------------------
53 Define
54 -----------------------------------------------------------------------------*/
55
56#define RECIPE_STRING "isaac_spc_jitter"
57
58#define ISAAC_SPC_JITTER_OFFSET_ERR 10
59
60#define KEYSIZE 512
61
62#define CENT_WL_BAND_Z 0.9
63#define CENT_WL_BAND_SZ 1.06
64#define CENT_WL_BAND_J 1.25
65#define CENT_WL_BAND_H 1.65
66#define CENT_WL_BAND_K 2.2
67#define CENT_WL_BAND_SL 3.78
68#define CENT_WL_BAND_M 4.78
69
70#define ISAAC_MIN(A,B) ((A) < (B) ? (A) : (B))
71
72#define isaac_plot_manpage \
73 "The recipe can produce a number of predefined plots. " \
74 "Zero means that none of the plots are produced, while " \
75 "increasing values (e.g. 1 or 2) increases the number " \
76 "of plots produced. If the plotting fails a warning is " \
77 "produced, and the recipe continues. " \
78 "The default behaviour of the plotting is to use " \
79 "gnuplot (with option -persist). The recipe currently " \
80 "produces 1D-plots using gnuplot commands. The recipe " \
81 "user can control the actual plotting-command used by " \
82 "the recipe to create the plot by setting the " \
83 "environment variable CPL_PLOTTER. Currently, if " \
84 "CPL_PLOTTER " \
85 "is set it must contain the string 'gnuplot'. Setting " \
86 "it to 'cat > my_gnuplot_$$.txt' causes a number of " \
87 "ASCII-files to be created, which each produce a plot " \
88 "when given as standard input to gnuplot (e.g. later " \
89 "or on a different computer). A finer control of the " \
90 "plotting options can be obtained by writing an " \
91 "executable script, e.g. my_gnuplot.pl, that " \
92 "executes gnuplot after setting the desired gnuplot " \
93 "options (e.g. set terminal pslatex color) " \
94 "and then setting CPL_PLOTTER to my_gnuplot.pl. " \
95 "The predefined plots include plotting of images. " \
96 "Images can be plotted not only with gnuplot, but also " \
97 "using the pnm format. This is controlled with the " \
98 "environment variable CPL_IMAGER. If CPL_IMAGER " \
99 "is set to a string that does not contain the word " \
100 "gnuplot, the recipe will generate the plot in pnm " \
101 "format. E.g. setting CPL_IMAGER to " \
102 "'display - &' will produce a gray-scale image " \
103 "using the image viewer display."
104
105
106
107/*-----------------------------------------------------------------------------
108 Private Function prototypes
109 -----------------------------------------------------------------------------*/
110
111static cpl_image ** isaac_spc_jitter_combine(const cpl_frameset *, const char *,
112 const char *, const char *, const char *);
113static cpl_imagelist * isaac_spc_jitter_load(const cpl_frameset *);
114static cpl_vector * isaac_spc_jitter_get_offsets(const cpl_frameset *);
115static int * isaac_spc_jitter_classif(const cpl_vector *, int *);
116static int off_comp(double, double, double);
117static cpl_imagelist * isaac_spc_jitter_saa_groups(cpl_imagelist *,
118 cpl_vector *, int *, int, cpl_vector **);
119static int isaac_spc_jitter_wavecal(const char *, const cpl_image *,
120 const char *, const cpl_frameset *);
121static cpl_imagelist * isaac_spc_jitter_nodded(cpl_imagelist *, cpl_vector *,
122 cpl_vector **);
123static cpl_imagelist * isaac_spc_jitter_distor(cpl_imagelist *, const char *,
124 const char *);
125static double isaac_spc_jitter_refine_offset(const cpl_image *,
126 const cpl_image *);
127static cpl_table * isaac_spc_jitter_extract(const cpl_image *);
128static int isaac_spc_jitter_std(const char *, const char *, const cpl_frame *,
129 cpl_table *, double);
130static cpl_error_code isaac_spc_jitter_flat(cpl_imagelist *, const char *);
131static cpl_error_code isaac_spc_jitter_save(cpl_frameset *, const cpl_image *,
132 const cpl_image *,
133 const cpl_table *,
134 const cpl_parameterlist *);
135
136cpl_recipe_define(isaac_spc_jitter, ISAAC_BINARY_VERSION,
137 "Lars Lundin", PACKAGE_BUGREPORT, "2002,2003, 2008",
138 "ISAAC Spectro jitter recipe",
139 RECIPE_STRING " -- ISAAC spectro jitter recipe\n"
140 "The files listed in the Set Of Frames (sof-file) "
141 "must be tagged:\n"
142 "Observation in nodding mode:\n"
143 "\traw-file.fits "ISAAC_SPC_JITTER_NODOBJ_RAW" or\n"
144 "\traw-file.fits "ISAAC_SPC_JITTER_NODSKY_RAW"\n"
145 "Observation in chopping mode:\n"
146 "\traw-file.fits "ISAAC_SPC_JITTER_CHOP_RAW" or\n"
147 "Calibration (standard star) in nodding mode:\n"
148 "\traw-file.fits "ISAAC_SPC_RESPFUNC_RAW" or\n"
149 "\traw-file.fits "ISAAC_SPC_RESPFUNC_OBJ_RAW" or\n"
150 "\traw-file.fits "ISAAC_SPC_RESPFUNC_SKY_RAW"\n"
151 "\traw-file.fits "ISAAC_SPC_RESPFUNC_FLUX_RAW"\n"
152 "Calibration (standard star) in chopping mode:\n"
153 "\traw-file.fits "ISAAC_SPC_JITTER_CHOP_CAL_RAW"\n"
154 "Calibration files:\n"
155 "\toh.fits "ISAAC_CALPRO_OH_CAT" or\n"
156 "\tflat-file.fits "ISAAC_CALIB_SPFLAT" or\n"
157 "\tflat-file.fits "ISAAC_CALIB_LW_SPFLAT" or\n"
158 "\tarc-file.fits "ISAAC_CALIB_ARC" or\n"
159 "\tarc-file.fits "ISAAC_CALIB_LW_ARC" or\n"
160 "\tstartrace-file.fits "ISAAC_CALIB_STARTRACE" or\n"
161 "\tstartrace-file.fits "ISAAC_CALIB_LW_STARTRACE" or\n"
162 "\tsed-file.fits "ISAAC_CALIB_SED" or\n"
163 "\tstdstars-file.fits "ISAAC_CALIB_STDSTARS"\n");
164
165/*-----------------------------------------------------------------------------
166 Static variables
167 -----------------------------------------------------------------------------*/
168
169static struct {
170 /* Inputs */
171 int arm;
172 int plot;
173 int oddeven;
174 /* wavecal_in : 0 for physical model, 1 for sky, 2 for arc table */
175 int wavecal_in;
176 int wavecal_rej_bottom;
177 int wavecal_rej_top;
178 int wavecal_rej_left;
179 int wavecal_rej_right;
180 int max_offset;
181 int saa_refine;
182 double saa_rej_high;
183 double saa_rej_low;
184 int extr_spec_pos;
185 int extr_spec_width;
186 int extr_sky_hi_width;
187 int extr_sky_lo_width;
188 int extr_sky_hi_dist;
189 int extr_sky_lo_dist;
190 int std_mode;
191 double std_magnitude;
192 /* Outputs */
193 /* wavecal_out : 0 for physical model, 1 for sky, 2 for arc table */
194 int chopping;
195 cpl_vector * throws;
196 cpl_vector * intensities;
197 char filter[KEYSIZE];
198 char filter_ref[KEYSIZE];
199 char * starname;
200 char * sptype;
201 int wavecal_out;
202 double wavecal_cc;
203 double wavecal_a0;
204 double wavecal_a1;
205 double wavecal_a2;
206 double wavecal_a3;
207} isaac_spc_jitter_config;
208
209
210/*-----------------------------------------------------------------------------
211 Functions code
212 -----------------------------------------------------------------------------*/
213
214/*----------------------------------------------------------------------------*/
222/*----------------------------------------------------------------------------*/
223static
224cpl_error_code isaac_spc_jitter_fill_parameterlist(cpl_parameterlist * self)
225{
226 const char * context = PACKAGE "." RECIPE_STRING;
227 cpl_error_code err;
228
229 cpl_ensure_code(self, CPL_ERROR_NULL_INPUT);
230
231 /* Fill the parameters list */
232
233
234 /* --oddeven */
235 err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
236 "oddeven", CPL_FALSE, NULL, context,
237 "Flag to correct the oddeven column "
238 "effect");
239 cpl_ensure_code(!err, err);
240
241 /* --wavecal */
242 err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
243 "wavecal", "sky", NULL, context,
244 "Wavelength calibration method: "
245 "sky, phy or arc");
246 cpl_ensure_code(!err, err);
247
248 /* --wavecal_rej */
249 err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
250 "wavecal_rej", "-1,-1,50,50",
251 "wc_rej", context,
252 "left right bottom top rejections");
253 cpl_ensure_code(!err, err);
254
255 /* --max_offset */
256 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
257 "max_offset", 50, NULL, context,
258 "Maximum allowed offset from the "
259 "physical model [pixel]");
260 cpl_ensure_code(!err, err);
261
262 /* --saa_refine */
263 err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
264 "saa_refine", CPL_TRUE, NULL, context,
265 "Flag to refine the offsets");
266 cpl_ensure_code(!err, err);
267
268 /* --saa_rej */
269 err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
270 "saa_rej", "0.1,0.1", NULL, context,
271 "Low and high rejection fractions "
272 "(rounded down)");
273 cpl_ensure_code(!err, err);
274
275 /* --spec_pos */
276 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
277 "spec_pos", -1, NULL, context,
278 "Spectrum position");
279 cpl_ensure_code(!err, err);
280
281 /* --spec_width */
282 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
283 "spec_width", 10, NULL, context,
284 "Spectrum width");
285 cpl_ensure_code(!err, err);
286
287 /* --sky_hi_width */
288 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
289 "sky_hi_width", 10, NULL, context,
290 "Sky width above the spectrum");
291 cpl_ensure_code(!err, err);
292
293 /* --sky_lo_width */
294 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
295 "sky_lo_width", 10, NULL, context,
296 "Sky width below the spectrum");
297 cpl_ensure_code(!err, err);
298
299 /* --sky_hi_dist */
300 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
301 "sky_hi_dist", -1, NULL, context,
302 "Sky distance above the spectrum");
303 cpl_ensure_code(!err, err);
304
305 /* --sky_lo_dist */
306 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
307 "sky_lo_dist", -1, NULL, context,
308 "Sky distance below the spectrum");
309 cpl_ensure_code(!err, err);
310
311 /* --plot */
312 err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
313 "display", CPL_FALSE, NULL, context,
314 "Ignored. Use --plot instead");
315 cpl_ensure_code(!err, err);
316
317 /* --plot */
318 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
319 "plot", 0, NULL, context,
320 isaac_plot_manpage);
321 cpl_ensure_code(!err, err);
322
323 /* --std_mode */
324 err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
325 "std_mode", CPL_FALSE, "std", context,
326 "Flag for standard star");
327 cpl_ensure_code(!err, err);
328
329 /* --std_magnitude */
330 err = irplib_parameterlist_set_double(self, PACKAGE, RECIPE_STRING,
331 "std_magnitude", -1.0, "mag",
332 context, "Standard star magnitude");
333 cpl_ensure_code(!err, err);
334
335 return CPL_ERROR_NONE;
336}
337
338
339/*----------------------------------------------------------------------------*/
347/*----------------------------------------------------------------------------*/
348static int isaac_spc_jitter(cpl_frameset * framelist,
349 const cpl_parameterlist * parlist)
350{
351 cpl_errorstate prestate = cpl_errorstate_get();
352 const char * sval;
353 const char * flat;
354 const char * arc;
355 const char * startrace;
356 const char * sed;
357 const char * stdstars;
358 const char * oh;
359 const cpl_frame * cur_frame;
360 cpl_frameset * rawframes = NULL;
361 cpl_propertylist * plist = NULL;
362 cpl_image ** combined = NULL;
363 cpl_table * extracted = NULL;
364
365 bug_if(0);
366
367 /* Initialise */
368 isaac_spc_jitter_config.chopping = -1;
369 isaac_spc_jitter_config.wavecal_out = -1;
370 isaac_spc_jitter_config.wavecal_cc = -1.0;
371 isaac_spc_jitter_config.throws = NULL;
372 isaac_spc_jitter_config.intensities = NULL;
373 isaac_spc_jitter_config.filter[0] = (char)0;
374 isaac_spc_jitter_config.filter_ref[0] = (char)0;
375 isaac_spc_jitter_config.starname = NULL;
376 isaac_spc_jitter_config.sptype = NULL;
377 isaac_spc_jitter_config.wavecal_in = -1;
378 isaac_spc_jitter_config.arm = -1;
379
380 /* Retrieve input parameters */
381 /* --wavecal */
382 sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
383 "wavecal");
384 bug_if(sval == NULL);
385
386 if (!strcmp(sval, "phy")) isaac_spc_jitter_config.wavecal_in = 0;
387 else if (!strcmp(sval, "sky")) isaac_spc_jitter_config.wavecal_in = 1;
388 else if (!strcmp(sval, "arc")) isaac_spc_jitter_config.wavecal_in = 2;
389
390 error_if(isaac_spc_jitter_config.wavecal_in < 0,
391 CPL_ERROR_UNSUPPORTED_MODE, "Invalid value for wavecal option: "
392 "%s", sval);
393
394 /* Rejection parameters for wavelength calibration*/
395 sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
396 "wavecal_rej");
397 bug_if(sval == NULL);
398
399 skip_if (sscanf(sval, "%d,%d,%d,%d",
400 &isaac_spc_jitter_config.wavecal_rej_left,
401 &isaac_spc_jitter_config.wavecal_rej_right,
402 &isaac_spc_jitter_config.wavecal_rej_bottom,
403 &isaac_spc_jitter_config.wavecal_rej_top) != 4);
404
405 /* Max offset in pixels */
406 isaac_spc_jitter_config.max_offset
407 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
408 "max_offset");
409
410 /* Oddeven */
411 isaac_spc_jitter_config.oddeven
412 = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
413 "oddeven");
414
415 /* Refine of offsets */
416 isaac_spc_jitter_config.saa_refine
417 = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
418 "saa_refine");
419
420 /* Rejection parameters for SAA */
421 sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
422 "saa_rej");
423 bug_if(sval == NULL);
424
425 skip_if (sscanf(sval, "%lg,%lg",
426 &isaac_spc_jitter_config.saa_rej_low,
427 &isaac_spc_jitter_config.saa_rej_high) != 2);
428
429 /* --spec_pos */
430 isaac_spc_jitter_config.extr_spec_pos
431 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
432 "spec_pos");
433 /* --spec_width */
434 isaac_spc_jitter_config.extr_spec_width
435 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
436 "spec_width");
437 /* --sky_hi_width */
438 isaac_spc_jitter_config.extr_sky_hi_width
439 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
440 "sky_hi_width");
441 /* --sky_lo_width */
442 isaac_spc_jitter_config.extr_sky_lo_width
443 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
444 "sky_lo_width");
445 /* --sky_hi_dist */
446 isaac_spc_jitter_config.extr_sky_hi_dist
447 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
448 "sky_hi_dist");
449 /* --sky_lo_dist */
450 isaac_spc_jitter_config.extr_sky_lo_dist
451 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
452 "sky_lo_dist");
453 /* --plot */
454 isaac_spc_jitter_config.plot
455 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
456 "plot");
457 /* --std */
458 isaac_spc_jitter_config.std_mode
459 = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
460 "std_mode");
461 /* --mag */
462 isaac_spc_jitter_config.std_magnitude
463 = irplib_parameterlist_get_double(parlist, PACKAGE, RECIPE_STRING,
464 "std_magnitude");
465
466 /* Identify the RAW and CALIB frames in the input frameset */
467 skip_if (isaac_dfs_set_groups(framelist));
468
469 /* Retrieve raw frames */
470 if ((rawframes = isaac_extract_frameset(framelist,
471 ISAAC_SPC_JITTER_CHOP_RAW)) != NULL) {
472 } else if ((rawframes = isaac_extract_frameset(framelist,
473 ISAAC_SPC_JITTER_CHOP_CAL_RAW)) != NULL) {
474 } else if ((rawframes = isaac_extract_frameset(framelist,
475 ISAAC_SPC_JITTER_NODOBJ_RAW)) != NULL) {
476 } else if ((rawframes = isaac_extract_frameset(framelist,
477 ISAAC_SPC_RESPFUNC_RAW)) != NULL) {
478 isaac_spc_jitter_config.std_mode = 1;
479 } else if ((rawframes = isaac_extract_frameset(framelist,
480 ISAAC_SPC_RESPFUNC_OBJ_RAW)) != NULL) {
481 isaac_spc_jitter_config.std_mode = 1;
482 } else if ((rawframes = isaac_extract_frameset(framelist,
483 ISAAC_SPC_RESPFUNC_FLUX_RAW)) != NULL) {
484 isaac_spc_jitter_config.std_mode = 1;
485 } else {
486
487 /* These frame types alone are not supported */
488
489 error_if (cpl_frameset_find_const(framelist,
490 ISAAC_SPC_JITTER_NODSKY_RAW),
491 CPL_ERROR_UNSUPPORTED_MODE, "Cannot reduce "
492 ISAAC_SPC_JITTER_NODSKY_RAW "-frames without object frames");
493
494 error_if (cpl_frameset_find_const(framelist,
495 ISAAC_SPC_RESPFUNC_SKY_RAW),
496 CPL_ERROR_UNSUPPORTED_MODE, "Cannot reduce "
497 ISAAC_SPC_RESPFUNC_SKY_RAW "-frames without object frames");
498
499 }
500
501 error_if (rawframes == NULL, CPL_ERROR_DATA_NOT_FOUND,
502 "Cannot find the raw frames in the input list");
503
504 /* Get the arm used (SW or LW) */
505 cur_frame = cpl_frameset_get_position_const(framelist, 0);
506 skip_if(cur_frame == NULL);
507 plist = cpl_propertylist_load(cpl_frame_get_filename(cur_frame), 0);
508 skip_if(plist == NULL);
509 sval = isaac_pfits_get_arm(plist);
510 error_if (sval == NULL, CPL_ERROR_DATA_NOT_FOUND, "cannot get the arm");
511
512 if (sval[0] == 'S') isaac_spc_jitter_config.arm = 1;
513 else if (sval[0] == 'L') isaac_spc_jitter_config.arm = 2;
514
515 error_if (isaac_spc_jitter_config.arm < 0, CPL_ERROR_UNSUPPORTED_MODE,
516 "Unsupported arm: %s", sval);
517
518 /* Get the filter */
519 sval = isaac_pfits_get_filter(plist);
520 if (sval == NULL) {
521 cpl_error_reset();
522 } else {
523 (void)strncpy(isaac_spc_jitter_config.filter, sval, KEYSIZE);
524 isaac_spc_jitter_config.filter[KEYSIZE-1] = (char)0;
525 }
526 cpl_propertylist_empty(plist);
527
528 /* Retrieve calibration data */
529 arc = isaac_extract_filename(framelist, ISAAC_CALIB_ARC);
530 if (arc == NULL)
531 arc = isaac_extract_filename(framelist, ISAAC_CALIB_LW_ARC);
532 flat = isaac_extract_filename(framelist, ISAAC_CALIB_SPFLAT);
533 if (flat == NULL)
534 flat = isaac_extract_filename(framelist, ISAAC_CALIB_LW_SPFLAT);
535 startrace = isaac_extract_filename(framelist, ISAAC_CALIB_STARTRACE);
536 if (startrace == NULL)
537 startrace = isaac_extract_filename(framelist, ISAAC_CALIB_LW_STARTRACE);
538 sed = isaac_extract_filename(framelist, ISAAC_CALIB_SED);
539 stdstars = isaac_extract_filename(framelist, ISAAC_CALIB_STDSTARS);
540 oh = isaac_extract_filename(framelist, ISAAC_CALPRO_OH_CAT);
541
542 /* If arc calibration requested, arc file must be provided */
543 error_if (arc == NULL && isaac_spc_jitter_config.wavecal_in == 2,
544 CPL_ERROR_DATA_NOT_FOUND, "Missing an arc file for the "
545 "arc-based wavelength calibration");
546
547 cpl_msg_info(cpl_func, "Create the combined image");
548 combined = isaac_spc_jitter_combine(rawframes, oh, flat, arc,
549 startrace);
550 skip_if (combined == NULL);
551
552 cpl_msg_info(cpl_func, "Extract the spectrum");
553 extracted = isaac_spc_jitter_extract(combined[0]);
554 if (extracted == NULL || !cpl_errorstate_is_equal(prestate)) {
555 cpl_msg_warning(cpl_func, "Cannot extract the spectrum");
556 if (!cpl_errorstate_is_equal(prestate)) {
557 cpl_errorstate_dump(prestate, CPL_FALSE,
558 irplib_errorstate_dump_warning);
559 cpl_errorstate_set(prestate);
560 }
561 } else if (isaac_spc_jitter_config.std_mode) {
562 /* In standard star mode, compute the efficiency and the conversion */
563 cpl_msg_info(cpl_func, "Compute flux calibration");
564 cur_frame = cpl_frameset_get_position_const(framelist, 0);
565 if (isaac_spc_jitter_std(sed, stdstars, cur_frame, extracted,
566 isaac_spc_jitter_config.std_magnitude)) {
567 cpl_msg_warning(cpl_func, "Cannot compute the flux calibration");
568 if (!cpl_errorstate_is_equal(prestate)) {
569 cpl_errorstate_dump(prestate, CPL_FALSE,
570 irplib_errorstate_dump_warning);
571 cpl_errorstate_set(prestate);
572 }
573 }
574 }
575
576 /* Write the products */
577 cpl_msg_info(cpl_func, "Save the products");
578 skip_if (isaac_spc_jitter_save(framelist, combined[0], combined[1],
579 extracted, parlist));
580
581 end_skip;
582
583 if (combined != NULL) {
584 cpl_image_delete(combined[0]);
585 cpl_image_delete(combined[1]);
586 cpl_free(combined);
587 }
588
589 cpl_table_delete(extracted);
590
591 cpl_vector_delete(isaac_spc_jitter_config.intensities);
592 cpl_vector_delete(isaac_spc_jitter_config.throws);
593
594 cpl_free(isaac_spc_jitter_config.starname);
595 cpl_free(isaac_spc_jitter_config.sptype);
596
597 cpl_propertylist_delete(plist);
598
599 cpl_frameset_delete(rawframes);
600
601 return cpl_error_get_code();
602}
603
604/*----------------------------------------------------------------------------*/
615/*----------------------------------------------------------------------------*/
616static cpl_image ** isaac_spc_jitter_combine(const cpl_frameset * rawframes,
617 const char * oh,
618 const char * flat,
619 const char * arc,
620 const char * startrace)
621{
622 int nilist;
623 cpl_imagelist * ilist = NULL;
624 cpl_vector * offsets = NULL;
625 int * groups = NULL;
626 int ngroups = 0; /* Avoid uninit warning */
627 cpl_imagelist * abba = NULL;
628 cpl_vector * abba_off = NULL;
629 cpl_imagelist * nodded = NULL;
630 cpl_vector * nodded_off_y = NULL;
631 double throw;
632 cpl_vector * nodded_off_x = NULL;
633 cpl_bivector * nodded_offsets = NULL;
634 cpl_image ** combined = NULL;
635 int nima;
636 int i;
637
638 bug_if (rawframes == NULL);
639
640 /* Load the images */
641 cpl_msg_info(cpl_func, "Load the data");
642 ilist = isaac_spc_jitter_load(rawframes);
643 skip_if (ilist == NULL);
644
645 nilist = cpl_imagelist_get_size(ilist);
646
647 /* Apply the odd-even correction */
648 if (isaac_spc_jitter_config.oddeven) {
649 cpl_errorstate prestate = cpl_errorstate_get();
650 cpl_imagelist * corrected = cpl_imagelist_new();
651
652 cpl_msg_info(cpl_func, "Apply the odd-even effect correction");
653 for (i=0; i < nilist; i++) {
654 cpl_image * cur_im
655 = isaac_oddeven_correct(cpl_imagelist_get(ilist, i));
656
657 cpl_msg_info(cpl_func, "Correcting frame %d/%d", i+1, nilist);
658
659 if (cur_im == NULL) break;
660 (void)cpl_imagelist_set(corrected, cur_im, i);
661 }
662
663 if (i == nilist) {
664 /* Odd/even correction successful */
665 cpl_imagelist_delete(ilist);
666 ilist = corrected;
667 } else {
668 cpl_msg_warning(cpl_func, "Odd/even correction failed for "
669 "image %d/%d", i+1, nilist);
670 cpl_imagelist_delete(corrected);
671 if (!cpl_errorstate_is_equal(prestate)) {
672 cpl_errorstate_dump(prestate, CPL_FALSE,
673 irplib_errorstate_dump_warning);
674 cpl_errorstate_set(prestate);
675 }
676 }
677 }
678
679
680 if (isaac_spc_jitter_config.plot > 0) {
681 cpl_plot_image("", "", "", cpl_imagelist_get(ilist, 0));
682 }
683
684 /* Apply the flatfield */
685 if (flat != NULL) {
686 cpl_errorstate prestate = cpl_errorstate_get();
687 cpl_msg_info(cpl_func, "Apply the flatfield correction");
688 if (isaac_spc_jitter_flat(ilist, flat)) {
689 cpl_msg_warning(cpl_func, "cannot apply the flat field");
690 if (!cpl_errorstate_is_equal(prestate)) {
691 cpl_errorstate_dump(prestate, CPL_FALSE,
692 irplib_errorstate_dump_warning);
693 cpl_errorstate_set(prestate);
694 }
695 }
696 }
697
698 if (isaac_spc_jitter_config.plot > 0) {
699 cpl_plot_image("", "", "", cpl_imagelist_get(ilist, 0));
700 }
701 /* Get the offsets */
702 cpl_msg_info(cpl_func, "Get the %d offsets", nilist);
703 offsets = isaac_spc_jitter_get_offsets(rawframes);
704
705 error_if (offsets == NULL, cpl_error_get_code(),
706 "Could not get the offsets");
707
708 /* Classify in groups the a and b images sequence */
709 cpl_msg_info(cpl_func, "Classify in groups");
710 groups = isaac_spc_jitter_classif(offsets, &ngroups);
711 error_if (groups == NULL, cpl_error_get_code(),
712 "Could not classify the data");
713
714 /* Shift and add each group to one image */
715 cpl_msg_info(cpl_func, "Shift and add each group to one image");
716 abba = isaac_spc_jitter_saa_groups(ilist, offsets, groups,
717 ngroups, &abba_off);
718 error_if (abba == NULL, cpl_error_get_code(), "Could not shift and add "
719 "groups");
720
721 /* Compute the wavelength calibration */
722 cpl_msg_info(cpl_func, "Compute the wavelength calibration");
723 error_if (isaac_spc_jitter_wavecal(arc, cpl_imagelist_get(abba, 0), oh,
724 rawframes),
725 cpl_error_get_code(), "Wavelength calibration failed");
726
727 /* Create the nodded images */
728 cpl_msg_info(cpl_func, "Create the nodded images");
729 nodded = isaac_spc_jitter_nodded(abba, abba_off, &nodded_off_y);
730 cpl_imagelist_delete(abba);
731 abba = NULL;
732
733 skip_if (nodded == NULL);
734
735 /* Get the throw offsets from abba_off */
736 nima = cpl_imagelist_get_size(nodded);
737 isaac_spc_jitter_config.throws = cpl_vector_new(nima);
738 if (isaac_spc_jitter_config.chopping == 0) {
739 for (i=0; i<nima/2; i++) {
740 throw = fabs( (cpl_vector_get(abba_off, 2*i))-
741 (cpl_vector_get(abba_off, 2*i+1)));
742 cpl_vector_set(isaac_spc_jitter_config.throws, 2*i, throw);
743 cpl_vector_set(isaac_spc_jitter_config.throws, 2*i+1, throw);
744 }
745 } else {
746 for (i=0; i<nima; i++) {
747 throw = fabs( (cpl_vector_get(abba_off, 2*i))-
748 (cpl_vector_get(abba_off, 2*i+1)));
749 cpl_vector_set(isaac_spc_jitter_config.throws, i, throw);
750 }
751 }
752 cpl_vector_delete(abba_off);
753 abba_off = NULL;
754
755 /* Get the spectra intensities in the nodded images */
756 cpl_msg_info(cpl_func, "Compute the spectra intensities");
757 cpl_msg_indent_more();
758 isaac_spc_jitter_config.intensities = cpl_vector_new(nima);
759 for (i=0; i<nima; i++) {
760 cpl_errorstate prestate = cpl_errorstate_get();
761 cpl_table * extracted
762 = isaac_spc_jitter_extract(cpl_imagelist_get(nodded, i));
763 double intensity;
764
765
766 if (extracted == NULL || !cpl_errorstate_is_equal(prestate)) {
767 cpl_msg_warning(cpl_func,"Cannot extract the spectrum from "
768 "nodded image %d", i+1);
769 cpl_errorstate_dump(prestate, CPL_FALSE,
770 irplib_errorstate_dump_warning);
771 cpl_errorstate_set(prestate);
772 intensity = -1.0;
773 } else {
774 intensity = cpl_table_get_column_mean(extracted,
775 "Extracted_spectrum_value");
776 intensity *= cpl_table_get_nrow(extracted);
777 cpl_table_delete(extracted);
778 cpl_msg_info(cpl_func, "Spectrum intensity %d: %g", i+1,
779 intensity);
780 }
781 cpl_vector_set(isaac_spc_jitter_config.intensities, i, intensity);
782 }
783 cpl_msg_indent_less();
784
785 if (arc || startrace) {
786 cpl_imagelist * nodded_warped;
787 cpl_msg_info(cpl_func, "Correct the distortion on nodded images");
788 cpl_msg_indent_more();
789 nodded_warped = isaac_spc_jitter_distor(nodded, arc, startrace);
790 cpl_msg_indent_less();
791
792 skip_if (nodded_warped == NULL);
793
794 cpl_imagelist_delete(nodded);
795 nodded = nodded_warped;
796 nima = cpl_imagelist_get_size(nodded);
797 }
798
799
800 /* Refine the offsets if requested */
801 if (isaac_spc_jitter_config.saa_refine) {
802 double * pnodded_off_y = cpl_vector_get_data(nodded_off_y);
803 cpl_msg_info(cpl_func, "Refine the %d offsets", nima);
804 for (i=0; i < nima; i++) {
805 const double new_offset
806 = isaac_spc_jitter_refine_offset(cpl_imagelist_get(nodded, 0),
807 cpl_imagelist_get(nodded, i));
808 if (new_offset > 5000) {
809 cpl_msg_debug(cpl_func, "cannot refine the offset - keep %g",
810 pnodded_off_y[i]);
811 } else if (fabs(new_offset-pnodded_off_y[i]) <
812 ISAAC_SPC_JITTER_OFFSET_ERR) {
813 cpl_msg_debug(cpl_func, "refined offset : %g (old was %g)",
814 new_offset, pnodded_off_y[i]);
815 pnodded_off_y[i] = new_offset;
816 } else {
817 cpl_msg_debug(cpl_func,
818 "refined offset %g too different - keep %g",
819 new_offset, pnodded_off_y[i]);
820 }
821 }
822 }
823
824 /* Images Shift and add */
825
826 /* Get the offsets in a bivector */
827 nodded_off_x = cpl_vector_new(nima);
828 bug_if(cpl_vector_fill(nodded_off_x, 0.0));
829 nodded_offsets = cpl_bivector_wrap_vectors(nodded_off_x, nodded_off_y);
830
831 if (nima == 1) {
832
833 combined = cpl_malloc(2 * sizeof(cpl_image*));
834 combined[1] = NULL; /* In case the unset fails */
835
836 combined[0] = cpl_imagelist_unset(nodded, 0);
837 bug_if (combined[0] == NULL);
838
839 combined[1] = cpl_image_new(cpl_image_get_size_x(combined[0]),
840 cpl_image_get_size_y(combined[0]),
841 CPL_TYPE_INT);
842 bug_if (combined[1] == NULL);
843
844 /* Set all pixel values to 1 */
845 bug_if(cpl_image_threshold(combined[1], 1.0, 1.0, 1.0, 1.0));
846
847 } else {
848 /* FIXME: Round-off instead */
849 const int nrejlo = (int)(nima * isaac_spc_jitter_config.saa_rej_low);
850 const int nrejhi = (int)(nima * isaac_spc_jitter_config.saa_rej_high);
851
852 cpl_msg_info(cpl_func, "Apply the shift and add on the %d nodded "
853 "frames (Rejecting %d lowermost, %d uppermost)", nima,
854 nrejlo, nrejhi);
855 combined = cpl_geom_img_offset_saa(nodded, nodded_offsets,
856 CPL_KERNEL_DEFAULT, nrejlo, nrejhi,
857 CPL_GEOM_FIRST, NULL, NULL);
858 }
859
860 skip_if(combined == NULL);
861
862 end_skip;
863
864 cpl_free(groups);
865 cpl_imagelist_delete(ilist);
866 cpl_vector_delete(offsets);
867 cpl_imagelist_delete(abba);
868 cpl_vector_delete(abba_off);
869 cpl_imagelist_delete(nodded);
870 cpl_bivector_unwrap_vectors(nodded_offsets);
871 cpl_vector_delete(nodded_off_x);
872 cpl_vector_delete(nodded_off_y);
873
874 return combined;
875}
876
877/*----------------------------------------------------------------------------*/
885/*----------------------------------------------------------------------------*/
886static cpl_error_code isaac_spc_jitter_flat(cpl_imagelist * self,
887 const char * flat)
888{
889 cpl_image * fim = NULL;
890 cpl_image * big_fim = NULL;
891 const int mx = cpl_image_get_size_x(cpl_imagelist_get(self, 0));
892 const int my = cpl_image_get_size_y(cpl_imagelist_get(self, 0));
893 int nx, ny;
894
895 bug_if (self == NULL);
896 bug_if (flat == NULL);
897
898 /* Load the flat */
899 fim = cpl_image_load(flat, CPL_TYPE_UNSPECIFIED, 0, 0);
900 error_if(fim == NULL, cpl_error_get_code(), "Could not load the flat "
901 "field from %s", flat);
902
903 /* Get flat size */
904 nx = cpl_image_get_size_x(fim);
905 ny = cpl_image_get_size_y(fim);
906
907 error_if(ny != my, CPL_ERROR_INCOMPATIBLE_INPUT, "Flat field Y-size "
908 "%d is incompatible with image Y-size %d", ny, my);
909
910 /* Handle the case where nx is smaller */
911 if (nx != mx) {
912 cpl_propertylist * plist
913 = cpl_propertylist_load_regexp(flat, 0, "ESO DET WIN STARTX", 0);
914 const int lx = (int)isaac_pfits_get_win_startx(plist);
915
916 cpl_propertylist_delete(plist);
917 skip_if (0);
918
919 cpl_msg_info(cpl_func, "Windowing mode: flat between pixels %d "
920 "and %d", lx, ISAAC_MIN(mx, lx + nx - 1));
921
922 if (lx > mx || lx < 1) {
923 cpl_msg_warning(cpl_func, "Cannot apply out of bounds flat field, "
924 "lx=%d > mx=%d", lx, mx);
925 cpl_image_delete(fim);
926 fim = NULL;
927 } else {
928
929 /* Create the big flat image */
930 big_fim = cpl_image_new(mx, my, cpl_image_get_type(fim));
931
932 /* Set all pixel values to 1 */
933 bug_if(cpl_image_threshold(big_fim, 1.0, 1.0, 1.0, 1.0));
934
935 /* Copy the small flat in the big one */
936 bug_if (cpl_image_copy(big_fim, fim, lx, 1));
937
938 cpl_image_delete(fim);
939 fim = big_fim;
940 big_fim = NULL;
941 }
942 }
943
944 if (fim != NULL) {
945
946 /* Threshold all pixels below the "mid-point" of FLT_MIN and 1, and
947 all pixels above the "mid-point" of 1 and FLT_MAX. */
948 bug_if(cpl_image_threshold(fim, sqrt(FLT_MIN), sqrt(FLT_MAX),
949 1.0, 1.0));
950
951 /* Apply the division */
952 error_if (cpl_imagelist_divide_image(self, fim),
953 cpl_error_get_code(), "Could not apply the flat field");
954 }
955
956 end_skip;
957
958 cpl_image_delete(fim);
959 cpl_image_delete(big_fim);
960
961 return 0;
962}
963
964/*----------------------------------------------------------------------------*/
971/*----------------------------------------------------------------------------*/
972static cpl_imagelist * isaac_spc_jitter_load(const cpl_frameset * rawframes)
973{
974 /* Load the propertylist of the first frame to get the data type */
975 const cpl_frame * cur_frame = cpl_frameset_get_position_const(rawframes, 0);
976 cpl_propertylist * plist
977 = cpl_propertylist_load(cpl_frame_get_filename(cur_frame), 0);
978 const char * sval;
979 cpl_imagelist * self = NULL;
980
981
982 skip_if (plist == NULL);
983
984 sval = isaac_pfits_get_frame_type(plist);
985 skip_if (sval == NULL);
986
987 if (!strcmp(sval, "INT")) isaac_spc_jitter_config.chopping = 0;
988 else if (!strcmp(sval, "CUBE1")) isaac_spc_jitter_config.chopping = 1;
989 else {
990 error_if(1, CPL_ERROR_UNSUPPORTED_MODE, "Unsupported frame type: %s",
991 sval);
992 }
993
994 cpl_propertylist_empty(plist);
995
996 /* Load the data */
997 self = cpl_imagelist_load_frameset(rawframes, CPL_TYPE_FLOAT, 1, 0);
998
999 if (isaac_spc_jitter_config.chopping == 1) {
1000 cpl_imagelist * self_tmp
1001 = cpl_imagelist_load_frameset(rawframes, CPL_TYPE_FLOAT, 2, 0);
1002 const cpl_error_code error = cpl_imagelist_subtract(self, self_tmp);
1003
1004 cpl_imagelist_delete(self_tmp);
1005 skip_if(error);
1006 }
1007
1008 end_skip;
1009
1010 cpl_propertylist_delete(plist);
1011
1012 if (cpl_error_get_code()) {
1013 cpl_imagelist_delete(self);
1014 self = NULL;
1015 }
1016
1017 return self;
1018}
1019
1020/*----------------------------------------------------------------------------*/
1027/*----------------------------------------------------------------------------*/
1028static
1029cpl_vector * isaac_spc_jitter_get_offsets(const cpl_frameset * rawframes)
1030{
1031 const int nraw = cpl_frameset_get_size(rawframes);
1032 cpl_vector * offsets = cpl_vector_new(nraw);
1033 cpl_propertylist * plist = NULL;
1034 int i;
1035
1036 bug_if (rawframes == NULL);
1037 bug_if (nraw == 0);
1038
1039
1040 /* Get the rawframes Y offsets */
1041 for (i=0; i < nraw; i++) {
1042 const cpl_frame * cur_frame
1043 = cpl_frameset_get_position_const(rawframes, i);
1044 const char * filename = cpl_frame_get_filename(cur_frame);
1045 double yoff;
1046
1047 skip_if(filename == NULL);
1048
1049 cpl_propertylist_delete(plist);
1050 plist = cpl_propertylist_load_regexp(filename, 0,
1051 "ESO SEQ CUMOFFSETY", 0);
1052
1053 any_if("Could not load propertylist from %s", filename);
1054
1055 yoff = cpl_propertylist_get_double(plist, "ESO SEQ CUMOFFSETY");
1056
1057 any_if("Could not get the offset from %s", filename);
1058
1059 bug_if(cpl_vector_set(offsets, i, yoff));
1060 }
1061
1062 end_skip;
1063
1064 cpl_propertylist_delete(plist);
1065
1066 if (cpl_error_get_code()) {
1067 cpl_vector_delete(offsets);
1068 offsets = NULL;
1069 }
1070
1071 return offsets;
1072}
1073
1074/*----------------------------------------------------------------------------*/
1113/*----------------------------------------------------------------------------*/
1114static int * isaac_spc_jitter_classif(const cpl_vector * offsets,
1115 int * pngroups)
1116{
1117 const int nraw = cpl_vector_get_size(offsets);
1118 const double * pvect = cpl_vector_get_data_const(offsets);
1119 const double offmin = cpl_vector_get_min(offsets);
1120 const double offmax = cpl_vector_get_max(offsets);
1121 const double offset_thresh = 0.5 * (offmin + offmax);
1122 int * groups = cpl_calloc(nraw, sizeof(int));
1123 int last_group;
1124 int i = 0;
1125
1126
1127 bug_if(offsets == NULL);
1128 bug_if(pngroups == NULL);
1129 *pngroups = 0;
1130
1131 /* Separate the offsets in 2 categories */
1132 error_if (offmin >= offmax, CPL_ERROR_DATA_NOT_FOUND,
1133 "The %d offset(s) all have the same value: %g", nraw, pvect[0]);
1134
1135 /* Identify the different A and B groups */
1136
1137 /* Create a look up table to associate the ith obj with the jth frame */
1138 while (i < nraw) {
1139 int j = 0;
1140 /* Count the number of successive '+' or '-' (j) */
1141 while ((i+j < nraw) &&
1142 (!off_comp(pvect[i], pvect[i+j], offset_thresh))) j++;
1143
1144 if (i+j >= nraw) i = nraw;
1145 else {
1146 int l, k = 0;
1147 /* Check if there are j '-' or '+' (k) */
1148 while ((i+j+k < nraw)
1149 && (!off_comp(pvect[i+j], pvect[i+j+k], offset_thresh))
1150 && (k<j)) k++;
1151 last_group = 1;
1152 if (i+j+k < nraw) {
1153 for (l=i+j+k; l<nraw; l++) {
1154 if (off_comp(pvect[i+j], pvect[l], offset_thresh)) {
1155 last_group = 0;
1156 break;
1157 }
1158 }
1159 }
1160 if (last_group == 0) {
1161 for (l=0; l<j; l++) groups[i+l] = *pngroups + 1;
1162 for (l=0; l<k; l++) groups[i+j+l] = *pngroups + 2;
1163 *pngroups += 2;
1164 i += j+k;
1165 } else {
1166 for (l=0; l<j; l++) groups[i+l] = *pngroups + 1;
1167 for (l=0; l<nraw - (i+j); l++) groups[i+j+l] = *pngroups + 2;
1168 *pngroups += 2;
1169 i = nraw;
1170 }
1171 }
1172 }
1173
1174 /* Nb of groups found should be even */
1175 error_if (*pngroups & 1, CPL_ERROR_ILLEGAL_INPUT, "Found an odd number "
1176 "(%d) of groups in the %d offsets", *pngroups, nraw);
1177
1178 end_skip;
1179
1180 if (cpl_error_get_code()) {
1181 cpl_free(groups);
1182 groups = NULL;
1183 }
1184
1185 return groups;
1186}
1187
1188/*----------------------------------------------------------------------------*/
1220/*----------------------------------------------------------------------------*/
1221static cpl_imagelist * isaac_spc_jitter_saa_groups(
1222 cpl_imagelist * ilist,
1223 cpl_vector * offsets,
1224 int * groups,
1225 int ngroups,
1226 cpl_vector ** abba_off)
1227{
1228 cpl_imagelist * abba;
1229 cpl_imagelist * group_list;
1230 cpl_image * tmp_ima;
1231 cpl_image ** combined;
1232 cpl_bivector * group_off;
1233 double * pgroup_off;
1234 double * poffsets;
1235 double * pabba_off;
1236 int nima;
1237 int saa;
1238 int i, j, k;
1239
1240 /* Test entries */
1241 if ((ilist == NULL) || (offsets == NULL) || (groups == NULL)) return NULL;
1242
1243 /* Initialise */
1244 nima = cpl_imagelist_get_size(ilist);
1245 poffsets = cpl_vector_get_data(offsets);
1246
1247 /* Create the output image list */
1248 abba = cpl_imagelist_new();
1249 *abba_off = cpl_vector_new(ngroups);
1250 pabba_off = cpl_vector_get_data(*abba_off);
1251
1252 /* Loop on the groups */
1253 for (i=0; i<ngroups; i++) {
1254 /* Initialise */
1255 saa = 0;
1256 /* Create the group list of images */
1257 group_list = cpl_imagelist_new();
1258 k = 0;
1259 for (j=0; j<nima; j++) {
1260 if (i+1 == groups[j]) {
1261 /* Get the first offset of the group in abba_off */
1262 if (k==0) pabba_off[i] = poffsets[j];
1263 /* To know if we need the saa (shift and add) */
1264 if (fabs(pabba_off[i]-poffsets[j]) > 1e-3) saa = 1;
1265 /* Copy the images of the group in group_list */
1266 tmp_ima = cpl_image_duplicate(cpl_imagelist_get(ilist, j));
1267 cpl_imagelist_set(group_list, tmp_ima, k);
1268 tmp_ima = NULL;
1269 k++;
1270 }
1271 }
1272
1273 if (saa) {
1274 /* Get the offsets of the group in group_off */
1275 group_off = cpl_bivector_new(k);
1276 cpl_vector_fill(cpl_bivector_get_x(group_off), 0.0);
1277 pgroup_off = cpl_bivector_get_y_data(group_off);
1278 k = 0;
1279 for (j=0; j<nima; j++) {
1280 if (i+1 == groups[j]) {
1281 pgroup_off[k] = poffsets[j];
1282 k++;
1283 }
1284 }
1285 cpl_vector_subtract_scalar(cpl_bivector_get_y(group_off),
1286 pabba_off[i]);
1287 /* Shift and add */
1288 cpl_msg_debug(cpl_func, "Apply shift-and-add for group %d", i+1);
1289 if ((combined = cpl_geom_img_offset_saa(group_list,
1290 group_off, CPL_KERNEL_DEFAULT, 0, 0,
1291 CPL_GEOM_FIRST, NULL, NULL)) == NULL) {
1292 cpl_msg_error(cpl_func, "Cannot shift and add group nb %d", i+1);
1293 cpl_imagelist_delete(group_list);
1294 cpl_bivector_delete(group_off);
1295 cpl_imagelist_delete(abba);
1296 cpl_vector_delete(*abba_off);
1297 return NULL;
1298 }
1299 cpl_bivector_delete(group_off);
1300 cpl_image_delete(combined[1]);
1301 cpl_imagelist_set(abba, combined[0], i);
1302 cpl_free(combined);
1303 } else {
1304 /* Averaging */
1305 cpl_msg_debug(cpl_func, "Apply averaging for group %d", i+1);
1306 if ((tmp_ima = cpl_imagelist_collapse_create(group_list)) == NULL) {
1307 cpl_msg_error(cpl_func, "Cannot average group nb %d", i+1);
1308 cpl_imagelist_delete(group_list);
1309 cpl_imagelist_delete(abba);
1310 cpl_vector_delete(*abba_off);
1311 return NULL;
1312 }
1313 cpl_imagelist_set(abba, tmp_ima, i);
1314 }
1315 cpl_imagelist_delete(group_list);
1316 }
1317 return abba;
1318}
1319
1320/*----------------------------------------------------------------------------*/
1330/*----------------------------------------------------------------------------*/
1331static int isaac_spc_jitter_wavecal(const char * arc,
1332 const cpl_image * ima,
1333 const char * oh,
1334 const cpl_frameset * raw)
1335{
1336 cpl_table * arc_tab;
1337 double * phdisprel;
1338 const cpl_frame * cur_frame;
1339 const char * cur_fname;
1340 computed_disprel * disprel;
1341 int order;
1342 double slit_width;
1343
1344 /* Get the wavelength from the arc file */
1345 if (isaac_spc_jitter_config.wavecal_in == 2) {
1346 if (arc == NULL) {
1347 cpl_msg_error(cpl_func,
1348 "Missing arc for the wavelength calibration");
1349 return CPL_ERROR_UNSPECIFIED;
1350 }
1351 cpl_msg_info(cpl_func, "Get the wavelength from the ARC file");
1352 if ((arc_tab = cpl_table_load(arc, 1, 0)) == NULL) {
1353 cpl_msg_error(cpl_func, "Cannot load the arc table");
1354 isaac_spc_jitter_config.wavecal_out = -1;
1355 return CPL_ERROR_UNSPECIFIED;
1356 }
1357 isaac_spc_jitter_config.wavecal_a0 =
1358 cpl_table_get_double(arc_tab, "WL_coefficients", 0, NULL);
1359 isaac_spc_jitter_config.wavecal_a1 =
1360 cpl_table_get_double(arc_tab, "WL_coefficients", 1, NULL);
1361 isaac_spc_jitter_config.wavecal_a2 =
1362 cpl_table_get_double(arc_tab, "WL_coefficients", 2, NULL);
1363 isaac_spc_jitter_config.wavecal_a3 =
1364 cpl_table_get_double(arc_tab, "WL_coefficients", 3, NULL);
1365 cpl_table_delete(arc_tab);
1366 isaac_spc_jitter_config.wavecal_out = 2;
1367 isaac_spc_jitter_config.wavecal_cc = -1.0;
1368 return 0;
1369 }
1370
1371 /* Get the reference frame */
1372 cur_frame = cpl_frameset_get_position_const(raw, 0);
1373 cur_fname = cpl_frame_get_filename(cur_frame);
1374
1375 /* Get the physical model */
1376 cpl_msg_info(cpl_func, "Compute the physical model");
1377 cpl_msg_indent_more();
1378 if ((phdisprel = isaac_get_disprel_estimate(cur_fname, 3)) == NULL) {
1379 cpl_msg_error(cpl_func, "cannot compute the physical model");
1380 isaac_spc_jitter_config.wavecal_out = -1;
1381 cpl_msg_indent_less();
1382 return CPL_ERROR_UNSPECIFIED;
1383 }
1384 cpl_msg_info(cpl_func, "f(x)=%g + %g*x + %g*x^2 + %g*x^3",
1385 phdisprel[0], phdisprel[1], phdisprel[2], phdisprel[3]);
1386 isaac_spc_jitter_config.wavecal_a0 = phdisprel[0];
1387 isaac_spc_jitter_config.wavecal_a1 = phdisprel[1];
1388 isaac_spc_jitter_config.wavecal_a2 = phdisprel[2];
1389 isaac_spc_jitter_config.wavecal_a3 = phdisprel[3];
1390 isaac_spc_jitter_config.wavecal_cc = -1.0;
1391 isaac_spc_jitter_config.wavecal_out = 0;
1392 cpl_msg_indent_less();
1393
1394 /* Compute the wavelength using the sky lines */
1395 if (isaac_spc_jitter_config.wavecal_in == 1) {
1396 /* Compute the slit_width */
1397 if ((slit_width = isaac_get_slitwidth(cur_fname)) == -1) {
1398 cpl_msg_warning(cpl_func, "cannot get the slit width");
1399 cpl_free(phdisprel);
1400 return 0;
1401 }
1402 /* Get the order */
1403 if ((order = isaac_find_order(cur_fname)) == -1) {
1404 cpl_msg_warning(cpl_func, "cannot get the order");
1405 cpl_free(phdisprel);
1406 return 0;
1407 }
1408 /* Compute the wavelength */
1409 cpl_msg_info(cpl_func, "Compute the wavelength with the sky lines");
1410 cpl_msg_indent_more();
1411 if ((disprel = spectro_compute_disprel(ima,
1412 isaac_spc_jitter_config.wavecal_rej_bottom,
1413 isaac_spc_jitter_config.wavecal_rej_top,
1414 isaac_spc_jitter_config.wavecal_rej_left,
1415 isaac_spc_jitter_config.wavecal_rej_right,
1416 isaac_spc_jitter_config.max_offset,
1417 isaac_has_thermal(cur_fname) > 0,
1418 "oh", oh, NULL, NULL, slit_width, order,
1419 (int)(cpl_msg_get_level() == CPL_MSG_DEBUG),
1420 phdisprel)) == NULL) {
1421 cpl_msg_error(cpl_func, "cannot compute the dispersion relation");
1422 cpl_free(phdisprel);
1423 cpl_msg_indent_less();
1424 return 0;
1425 }
1426 cpl_msg_info(cpl_func, "Cross correlation factor: %g", disprel->cc);
1427 cpl_msg_info(cpl_func, "f(x)=%g + %g*x + %g*x^2 + %g*x^3",
1428 disprel->poly[0], disprel->poly[1], disprel->poly[2],
1429 disprel->poly[3]);
1430 isaac_spc_jitter_config.wavecal_a0 = disprel->poly[0];
1431 isaac_spc_jitter_config.wavecal_a1 = disprel->poly[1];
1432 isaac_spc_jitter_config.wavecal_a2 = disprel->poly[2];
1433 isaac_spc_jitter_config.wavecal_a3 = disprel->poly[3];
1434 isaac_spc_jitter_config.wavecal_cc = disprel->cc;
1435 isaac_spc_jitter_config.wavecal_out = 1;
1436 if (disprel->poly != NULL) cpl_free(disprel->poly);
1437 cpl_free(disprel);
1438 cpl_msg_indent_less();
1439 }
1440 cpl_free(phdisprel);
1441 return 0;
1442}
1443
1444/*----------------------------------------------------------------------------*/
1477/*----------------------------------------------------------------------------*/
1478static cpl_imagelist * isaac_spc_jitter_nodded(cpl_imagelist * abba,
1479 cpl_vector * abba_off,
1480 cpl_vector ** nodded_off)
1481{
1482 cpl_imagelist * nodded;
1483 cpl_image * tmp_ima;
1484 int nima;
1485 double * pabba_off;
1486 double * pnodded_off;
1487 double ref_off;
1488 int i;
1489
1490 /* Test entries */
1491 if ((abba == NULL) || (abba_off == NULL)) return NULL;
1492
1493 /* Initialise */
1494 nima = cpl_imagelist_get_size(abba);
1495 if (nima % 2) {
1496 cpl_msg_error(cpl_func, "Number of images should be even");
1497 return NULL;
1498 }
1499
1500 /* Non-chopping case */
1501 if (isaac_spc_jitter_config.chopping == 0) {
1502 /* Create the offsets between the nodded images */
1503 *nodded_off = cpl_vector_duplicate(abba_off);
1504 /* The image list to contain the nodded images */
1505 nodded = cpl_imagelist_new();
1506 for (i=0; i<(nima/2); i++) {
1507 /* a-b */
1508 tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i));
1509 cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i+1));
1510 cpl_imagelist_set(nodded, tmp_ima, 2*i);
1511 /* b-a */
1512 tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i+1));
1513 cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i));
1514 cpl_imagelist_set(nodded, tmp_ima, 2*i+1);
1515 }
1516 /* Chopping case */
1517 } else if (isaac_spc_jitter_config.chopping == 1) {
1518 /* Create the offsets between the nodded images */
1519 *nodded_off = cpl_vector_new(nima/2);
1520 pnodded_off = cpl_vector_get_data(*nodded_off);
1521 pabba_off = cpl_vector_get_data(abba_off);
1522 /* The image list to contain the nodded images */
1523 nodded = cpl_imagelist_new();
1524 for (i=0; i<nima/2; i++) {
1525 if ((pabba_off[0]-pabba_off[1])*(pabba_off[2*i]-pabba_off[2*i+1])
1526 > 0) {
1527 /* ab sequence */
1528 pnodded_off[i] = pabba_off[2*i];
1529 tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i));
1530 cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i+1));
1531 cpl_image_divide_scalar(tmp_ima, 2.0);
1532 cpl_imagelist_set(nodded, tmp_ima, i);
1533 } else {
1534 /* ba sequence */
1535 pnodded_off[i] = pabba_off[2*i+1];
1536 tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i+1));
1537 cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i));
1538 cpl_image_divide_scalar(tmp_ima, 2.0);
1539 cpl_imagelist_set(nodded, tmp_ima, i);
1540 }
1541 }
1542 } else {
1543 cpl_msg_error(cpl_func, "Unsupported chopping mode");
1544 return NULL;
1545 }
1546
1547 /* Subtract the first offset to the others */
1548 ref_off = cpl_vector_get(*nodded_off, 0);
1549 cpl_vector_subtract_scalar(*nodded_off, ref_off);
1550 return nodded;
1551}
1552
1553/*----------------------------------------------------------------------------*/
1562/*----------------------------------------------------------------------------*/
1563static cpl_imagelist * isaac_spc_jitter_distor(
1564 cpl_imagelist * ilist,
1565 const char * arc,
1566 const char * startrace)
1567{
1568 cpl_polynomial * arc_poly;
1569 cpl_polynomial * sttr_poly;
1570 cpl_table * tab;
1571 cpl_size power[2];
1572 cpl_vector * profile;
1573 cpl_imagelist * warped_list;
1574 cpl_image * warped;
1575 int i;
1576
1577 /* Test entries */
1578 if (ilist == NULL) return NULL;
1579 if ((arc == NULL) && (startrace == NULL)) return NULL;
1580
1581 /* Get the arc polynomial */
1582 arc_poly = cpl_polynomial_new(2);
1583 if (arc != NULL) {
1584 cpl_msg_info(cpl_func, "Get the arc distortion from the file");
1585 if ((tab = cpl_table_load(arc, 1, 0)) == NULL) {
1586 cpl_msg_error(cpl_func, "cannot load the arc table");
1587 cpl_polynomial_delete(arc_poly);
1588 return NULL;
1589 }
1590 for (i=0; i<cpl_table_get_nrow(tab); i++) {
1591 if (cpl_table_get_column_type(tab, "Degree_of_x") == CPL_TYPE_INT) {
1592 power[0] = cpl_table_get_int(tab, "Degree_of_x", i, NULL);
1593 power[1] = cpl_table_get_int(tab, "Degree_of_y", i, NULL);
1594 } else {
1595 power[0] = cpl_table_get_double(tab, "Degree_of_x", i, NULL);
1596 power[1] = cpl_table_get_double(tab, "Degree_of_y", i, NULL);
1597 }
1598 cpl_polynomial_set_coeff(arc_poly, power,
1599 cpl_table_get_double(tab, "poly2d_coef", i, NULL));
1600 }
1601 cpl_table_delete(tab);
1602 } else {
1603 cpl_msg_info(cpl_func, "Use the ID polynomial for the arc dist");
1604 power[0] = 1;
1605 power[1] = 0;
1606 cpl_polynomial_set_coeff(arc_poly, power, 1.0);
1607 }
1608
1609 /* Get the startrace polynomial */
1610 sttr_poly = cpl_polynomial_new(2);
1611 if (startrace != NULL) {
1612 cpl_msg_info(cpl_func, "Get the startrace distortion from the file");
1613 if ((tab = cpl_table_load(startrace, 1, 0)) == NULL) {
1614 cpl_msg_error(cpl_func, "cannot load the startrace table");
1615 cpl_polynomial_delete(arc_poly);
1616 cpl_polynomial_delete(sttr_poly);
1617 return NULL;
1618 }
1619 for (i=0; i<cpl_table_get_nrow(tab); i++) {
1620
1621 if (cpl_table_get_column_type(tab, "Degree_of_x") == CPL_TYPE_INT) {
1622 power[0] = cpl_table_get_int(tab, "Degree_of_x", i, NULL);
1623 power[1] = cpl_table_get_int(tab, "Degree_of_y", i, NULL);
1624 } else {
1625 power[0] = cpl_table_get_double(tab, "Degree_of_x", i, NULL);
1626 power[1] = cpl_table_get_double(tab, "Degree_of_y", i, NULL);
1627 }
1628 cpl_polynomial_set_coeff(sttr_poly, power,
1629 cpl_table_get_double(tab, "poly2d_coef", i, NULL));
1630 }
1631 cpl_table_delete(tab);
1632 } else {
1633 cpl_msg_info(cpl_func, "Use the ID polynomial for the startrace dist");
1634 power[0] = 0;
1635 power[1] = 1;
1636 cpl_polynomial_set_coeff(sttr_poly, power, 1.0);
1637 }
1638
1639 /* Create the kernel */
1640 profile = cpl_vector_new(CPL_KERNEL_DEF_SAMPLES);
1641 cpl_vector_fill_kernel_profile(profile, CPL_KERNEL_DEFAULT,
1642 CPL_KERNEL_DEF_WIDTH);
1643
1644 /* Correct the images */
1645 warped_list = cpl_imagelist_new();
1646 for (i=0; i<cpl_imagelist_get_size(ilist); i++) {
1647 warped = cpl_image_duplicate(cpl_imagelist_get(ilist, i));
1648 if (cpl_image_warp_polynomial(warped, cpl_imagelist_get(ilist, i),
1649 arc_poly, sttr_poly, profile, CPL_KERNEL_DEF_WIDTH, profile,
1650 CPL_KERNEL_DEF_WIDTH) != CPL_ERROR_NONE) {
1651 cpl_msg_error(cpl_func, "cannot correct the distortion");
1652 cpl_image_delete(warped);
1653 cpl_polynomial_delete(arc_poly);
1654 cpl_polynomial_delete(sttr_poly);
1655 cpl_vector_delete(profile);
1656 return NULL;
1657 }
1658 cpl_imagelist_set(warped_list, warped, i);
1659 }
1660 cpl_vector_delete(profile);
1661 cpl_polynomial_delete(arc_poly);
1662 cpl_polynomial_delete(sttr_poly);
1663 return warped_list;
1664}
1665
1666/*----------------------------------------------------------------------------*/
1674/*----------------------------------------------------------------------------*/
1675static double isaac_spc_jitter_refine_offset(const cpl_image * ima1,
1676 const cpl_image * ima2)
1677{
1678 double pos1, pos2;
1679
1680 /* Test entries */
1681 if (ima1 == NULL) return 10000.0;
1682 if (ima2 == NULL) return 10000.0;
1683
1684 /* Detect the spectra */
1685 if (irplib_spectrum_find_brightest(ima1, 0.0, NO_SHADOW, 0.0, 0,
1686 &pos1) == -1){
1687 return 10000.0;
1688 }
1689 if (irplib_spectrum_find_brightest(ima2, 0.0, NO_SHADOW, 0.0, 0,
1690 &pos2) == -1){
1691 return 10000.0;
1692 }
1693 return pos1-pos2;
1694}
1695
1696/*----------------------------------------------------------------------------*/
1703/*----------------------------------------------------------------------------*/
1704static cpl_table * isaac_spc_jitter_extract(const cpl_image * combined)
1705{
1706 int lo_dist, hi_dist, lo_width, hi_width, spec_pos;
1707 int nx, ny;
1708 double pos;
1709 int low_side, up_side;
1710 int sky_pos[4];
1711 cpl_vector * sky;
1712 cpl_vector * spec;
1713 cpl_vector * wl;
1714 cpl_image * colfluximg;
1715 double * pspec;
1716 double * psky;
1717 double * pwl;
1718 cpl_table * out;
1719 cpl_bivector * toplot;
1720 int i;
1721
1722 /* Test entries */
1723 if (combined == NULL) return NULL;
1724
1725 /* Initialise */
1726 nx = cpl_image_get_size_x(combined);
1727 ny = cpl_image_get_size_y(combined);
1728 lo_dist = isaac_spc_jitter_config.extr_sky_lo_dist;
1729 hi_dist = isaac_spc_jitter_config.extr_sky_hi_dist;
1730 lo_width = isaac_spc_jitter_config.extr_sky_lo_width;
1731 hi_width = isaac_spc_jitter_config.extr_sky_hi_width;
1732 spec_pos = isaac_spc_jitter_config.extr_spec_pos;
1733
1734 /* Detect the spectrum position if not passed */
1735 if (spec_pos < 0) {
1736 const int nthrow = cpl_vector_get_size(isaac_spc_jitter_config.throws);
1737
1738 if (nthrow < 1) {
1739 cpl_msg_error(cpl_func,
1740 "Need a throw value to detect the spectra !!");
1741 cpl_ensure(0, CPL_ERROR_DATA_NOT_FOUND, NULL);
1742 }
1743
1744 for (i=0; i < nthrow; i++){
1745 const int throw = (int)cpl_vector_get(isaac_spc_jitter_config.throws,
1746 i);
1747 if (irplib_spectrum_find_brightest(combined, throw, TWO_SHADOWS,
1748 0.0, 0, &pos) == 0) break;
1749 if (irplib_spectrum_find_brightest(combined, throw, ONE_SHADOW,
1750 0.0, 0, &pos) == 0) break;
1751 }
1752 if (i == nthrow) {
1753 cpl_msg_error(cpl_func, "Could not detect the spectrum using %d "
1754 "throw(s):", i);
1755#if 0
1756 cpl_vector_dump(isaac_spc_jitter_config.throws, stderr);
1757 cpl_plot_image("", "", "", combined);
1758#endif
1759 cpl_ensure(0, CPL_ERROR_DATA_NOT_FOUND, NULL);
1760 }
1761 spec_pos = (int)pos;
1762 cpl_msg_info(cpl_func, "Spectrum detected at y = %d", spec_pos);
1763 }
1764
1765 /* Set the parameters for the extraction */
1766
1767 /* Spectrum position */
1768 low_side = spec_pos - (int)(isaac_spc_jitter_config.extr_spec_width/2);
1769 up_side = low_side + isaac_spc_jitter_config.extr_spec_width;
1770 if (up_side < low_side) {
1771 (void)cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
1772 "Spectrum zone invalid: low=%d > up=%d",
1773 low_side, up_side);
1774 return NULL;
1775 }
1776 if (low_side < 1) {
1777 (void)cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
1778 "Spectrum zone lower limit too low: "
1779 "%d < 1", low_side);
1780 return NULL;
1781 }
1782 if (up_side > ny) {
1783 (void)cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
1784 "Spectrum zone upper limit too high: "
1785 "%d > ny=%d", up_side, ny);
1786 return NULL;
1787 }
1788
1789 /* Form a 1D single-row-image comprising the column fluxes of the zone */
1790 colfluximg = cpl_image_collapse_window_create(combined, 1, low_side,
1791 nx, up_side, 0);
1792
1793 if (cpl_image_count_rejected(colfluximg) == up_side - low_side + 1) {
1794 (void)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
1795 "Combined image has undefined flux "
1796 "from column %d to %d", low_side, up_side);
1797 cpl_image_delete(colfluximg);
1798 return NULL;
1799 }
1800
1801 /* Residual Sky position */
1802 if (lo_dist < 0) lo_dist = 2*isaac_spc_jitter_config.extr_spec_width;
1803 if (hi_dist < 0) hi_dist = 2*isaac_spc_jitter_config.extr_spec_width;
1804 sky_pos[1] = spec_pos - lo_dist;
1805 sky_pos[0] = sky_pos[1] - lo_width;
1806 sky_pos[2] = spec_pos + hi_dist;
1807 sky_pos[3] = sky_pos[2] + hi_width;
1808
1809 /* Get the sky */
1810 sky = cpl_vector_new(nx);
1811 psky = cpl_vector_get_data(sky);
1812 if (((sky_pos[0] < 1) || (lo_width == 0)) &&
1813 ((sky_pos[3] <= ny) && (hi_width > 0))) {
1814 for (i=0; i<nx; i++) {
1815 psky[i] = cpl_image_get_median_window(combined, i+1,
1816 sky_pos[2], i+1, sky_pos[3]);
1817 }
1818 } else if (((sky_pos[3] > ny) || (hi_width == 0))
1819 && ((sky_pos[0] > 0) && (lo_width > 0))) {
1820 for (i=0; i<nx; i++) {
1821 psky[i] = cpl_image_get_median_window(combined, i+1,
1822 sky_pos[0], i+1, sky_pos[1]);
1823 }
1824 } else if ((lo_width != 0) && (hi_width != 0)
1825 && (sky_pos[0] > 0) && (sky_pos[3] <= ny)) {
1826 for (i=0; i<nx; i++) {
1827 psky[i] = cpl_image_get_median_window(combined, i+1,
1828 sky_pos[2], i+1, sky_pos[3]);
1829 psky[i] += cpl_image_get_median_window(combined, i+1,
1830 sky_pos[0], i+1, sky_pos[1]);
1831 psky[i] /= 2.0;
1832 }
1833 } else {
1834 for (i=0; i<nx; i++) psky[i] = 0.0;
1835 }
1836
1837 /* Estimate the spectrum */
1838 spec = cpl_vector_new(nx);
1839 pspec = cpl_vector_get_data(spec);
1840 for (i=0; i<nx; i++) {
1841 int is_bad = 0;
1842 const double colflux = cpl_image_get(colfluximg, i+1, 1, &is_bad);
1843
1844 if (is_bad) {
1845 pspec[i] = 0.0;
1846 cpl_msg_warning(cpl_func, "Combined image has undefined flux in "
1847 "column %d", i+1);
1848 } else {
1849 pspec[i] = colflux
1850 - psky[i] * isaac_spc_jitter_config.extr_spec_width;
1851 }
1852 }
1853 cpl_image_delete(colfluximg);
1854
1855 /* Get the wavelength */
1856 wl = cpl_vector_new(nx);
1857 pwl = cpl_vector_get_data(wl);
1858 for (i=0; i<nx; i++) {
1859 pwl[i] = isaac_spc_jitter_config.wavecal_a0 +
1860 isaac_spc_jitter_config.wavecal_a1 * (i+1) +
1861 isaac_spc_jitter_config.wavecal_a2 * (i+1) * (i+1) +
1862 isaac_spc_jitter_config.wavecal_a3 * (i+1) * (i+1) * (i+1);
1863 }
1864
1865 /* Plot the spectrum if requested */
1866 if (isaac_spc_jitter_config.plot > 0) {
1867 toplot = cpl_bivector_wrap_vectors(wl, spec);
1868 cpl_plot_bivector(NULL, "t 'Spectrum' w lines", NULL, toplot);
1869 cpl_bivector_unwrap_vectors(toplot);
1870 toplot = cpl_bivector_wrap_vectors(wl, sky);
1871 cpl_plot_bivector(NULL, "t 'Sky' w lines", NULL, toplot);
1872 cpl_bivector_unwrap_vectors(toplot);
1873 }
1874
1875 /* Create and fill the output table */
1876 out = cpl_table_new(nx);
1877 cpl_table_new_column(out, "X_coordinate", CPL_TYPE_DOUBLE);
1878 cpl_table_new_column(out, "Extracted_spectrum_value", CPL_TYPE_DOUBLE);
1879 cpl_table_new_column(out, "Sky_spectrum", CPL_TYPE_DOUBLE);
1880 for (i=0; i<nx; i++) {
1881 cpl_table_set_double(out, "X_coordinate", i, pwl[i]);
1882 cpl_table_set_double(out, "Extracted_spectrum_value", i, pspec[i]);
1883 cpl_table_set_double(out, "Sky_spectrum", i, psky[i]);
1884 }
1885 cpl_vector_delete(wl);
1886 cpl_vector_delete(spec);
1887 cpl_vector_delete(sky);
1888 return out;
1889}
1890
1891/*----------------------------------------------------------------------------*/
1902/*----------------------------------------------------------------------------*/
1903static int isaac_spc_jitter_std(const char * seds_file,
1904 const char * stdstars,
1905 const cpl_frame * frame,
1906 cpl_table * tab,
1907 double mag)
1908{
1909 double surface = CPL_MATH_PI * 400 * 400;
1910 cpl_propertylist * plist;
1911 double dit, ra, dec, magnitude, cent_wl;
1912 isaac_band band;
1913 const int nelem = cpl_table_get_nrow(tab);
1914 cpl_vector * wl;
1915 cpl_vector * spec;
1916 cpl_bivector * spec_biv;
1917 cpl_bivector * sed;
1918 cpl_vector * efficiency;
1919 cpl_vector * mag_zero;
1920 cpl_vector * conversion;
1921 int i;
1922
1923 /* Test entries */
1924 if (seds_file == NULL) return CPL_ERROR_UNSPECIFIED;
1925 if (stdstars == NULL) return CPL_ERROR_UNSPECIFIED;
1926 if (frame == NULL) return CPL_ERROR_UNSPECIFIED;
1927 if (tab == NULL) return CPL_ERROR_UNSPECIFIED;
1928 if (cpl_error_get_code()) return CPL_ERROR_UNSPECIFIED;
1929
1930 /* Get the propertylist */
1931 if ((plist=cpl_propertylist_load(cpl_frame_get_filename(frame),0))==NULL) {
1932 cpl_msg_error(cpl_func, "Cannot load the property list");
1933 return CPL_ERROR_UNSPECIFIED;
1934 }
1935
1936 /* Get DIT */
1937 dit = isaac_pfits_get_dit(plist);
1938 if (cpl_error_get_code()) {
1939 cpl_msg_error(cpl_func, "Cannot get DIT");
1940 cpl_propertylist_delete(plist);
1941 return CPL_ERROR_UNSPECIFIED;
1942 }
1943 cpl_msg_info(cpl_func, "DIT: %g", dit);
1944
1945 /* Get band */
1946 if ((band = isaac_get_associated_filter(isaac_spc_jitter_config.filter))
1947 == ISAAC_BAND_UNKNOWN) {
1948 cpl_msg_error(cpl_func, "Cannot associate the filter to a BB one");
1949 cpl_propertylist_delete(plist);
1950 return CPL_ERROR_UNSPECIFIED;
1951 }
1952 cpl_msg_info(cpl_func, "Band : %s", isaac_std_band_name(band));
1953
1954 /* Get RA / DEC */
1955 ra = isaac_pfits_get_ra(plist);
1956 dec = isaac_pfits_get_dec(plist);
1957 if (cpl_error_get_code()) {
1958 cpl_msg_error(cpl_func, "Cannot get star position");
1959 cpl_propertylist_delete(plist);
1960 return CPL_ERROR_UNSPECIFIED;
1961 }
1962 cpl_msg_info(cpl_func, "RA: %g DEC: %g", ra, dec);
1963
1964 /* Get magnitude */
1965 if (mag < 0) {
1966 /* Reference star */
1967 if (irplib_stdstar_find_star(stdstars, ra, dec,
1968 isaac_std_band_name(isaac_get_bbfilter(isaac_spc_jitter_config.filter)),
1969 "all", &magnitude,
1970 &isaac_spc_jitter_config.starname,
1971 &isaac_spc_jitter_config.sptype,
1972 NULL, NULL, NULL, 2.0)) {
1973 cpl_msg_error(cpl_func, "Cannot find the star in catalogs");
1974 cpl_propertylist_delete(plist);
1975 return CPL_ERROR_UNSPECIFIED;
1976 }
1977 } else {
1978 magnitude = mag;
1979 }
1980 cpl_propertylist_delete(plist);
1981 (void)strncpy(isaac_spc_jitter_config.filter_ref,
1983 (isaac_spc_jitter_config.filter)),
1984 KEYSIZE-1);
1985 cpl_msg_info(cpl_func, "Magnitude: %g", magnitude);
1986 isaac_spc_jitter_config.std_magnitude = magnitude;
1987
1988 /* Get band center */
1989 switch (band) {
1990 case ISAAC_BAND_Z: cent_wl = CENT_WL_BAND_Z; break;
1991 case ISAAC_BAND_SZ: cent_wl = CENT_WL_BAND_SZ; break;
1992 case ISAAC_BAND_J: cent_wl = CENT_WL_BAND_J; break;
1993 case ISAAC_BAND_JBLOCK: cent_wl = CENT_WL_BAND_J; break;
1994 case ISAAC_BAND_SH: cent_wl = CENT_WL_BAND_H; break;
1995 case ISAAC_BAND_SK: cent_wl = CENT_WL_BAND_K; break;
1996 case ISAAC_BAND_SL: cent_wl = CENT_WL_BAND_SL; break;
1997 case ISAAC_BAND_M: cent_wl = CENT_WL_BAND_M; break;
1998 default:
1999 cpl_msg_error(cpl_func, "Unsupported band: %s",
2000 isaac_std_band_name(band));
2001 return CPL_ERROR_UNSPECIFIED;
2002 }
2003 cpl_msg_info(cpl_func, "Center of band : %g microns", cent_wl);
2004
2005 /* Get the SED */
2006 sed = irplib_stdstar_get_sed(seds_file, isaac_spc_jitter_config.sptype);
2007 if (sed == NULL) {
2008 cpl_msg_error(cpl_func, "Cannot get the SED");
2009 return CPL_ERROR_UNSPECIFIED;
2010 }
2011
2012 /* Put the spectrum in a bivector */
2013 wl = cpl_vector_wrap(nelem, cpl_table_get_data_double(tab,
2014 "X_coordinate"));
2015 spec = cpl_vector_wrap(nelem, cpl_table_get_data_double(tab,
2016 "Extracted_spectrum_value"));
2017 spec_biv = cpl_bivector_wrap_vectors(wl, spec);
2018
2019 /* Get the conversion */
2020 if ((conversion = irplib_stdstar_get_conversion(spec_biv, dit, surface,
2021 4.5, magnitude)) == NULL) {
2022 cpl_msg_error(cpl_func, "Cannot get the conversion");
2023 cpl_bivector_unwrap_vectors(spec_biv);
2024 cpl_vector_unwrap(spec);
2025 cpl_vector_unwrap(wl);
2026 cpl_bivector_delete(sed);
2027 return CPL_ERROR_UNSPECIFIED;
2028 }
2029
2030 /* Get the 0 magnitude spectrum */
2031 if ((mag_zero = irplib_stdstar_get_mag_zero(sed,
2032 cpl_bivector_get_x(spec_biv), cent_wl)) == NULL) {
2033 cpl_msg_error(cpl_func, "Cannot get the 0 magnitude spectrum");
2034 cpl_bivector_unwrap_vectors(spec_biv);
2035 cpl_vector_unwrap(spec);
2036 cpl_vector_unwrap(wl);
2037 cpl_bivector_delete(sed);
2038 cpl_vector_delete(conversion);
2039 return CPL_ERROR_UNSPECIFIED;
2040 }
2041 cpl_bivector_unwrap_vectors(spec_biv);
2042 cpl_vector_unwrap(spec);
2043 cpl_vector_unwrap(wl);
2044 cpl_bivector_delete(sed);
2045
2046 /* Set the mag_zero 0 values to 1 */
2047 for (i=0; i<cpl_vector_get_size(mag_zero); i++) {
2048 if (cpl_vector_get(mag_zero, i) < 1e-19) {
2049 cpl_vector_set(mag_zero, i, 1.0);
2050 }
2051 }
2052
2053 /* Get the efficiency */
2054 efficiency = cpl_vector_duplicate(conversion);
2055 if (cpl_vector_divide(efficiency, mag_zero) != CPL_ERROR_NONE) {
2056 cpl_msg_error(cpl_func, "Missing SED info in this wavelength range");
2057 cpl_vector_delete(conversion);
2058 cpl_vector_delete(mag_zero);
2059 cpl_vector_delete(efficiency);
2060 return CPL_ERROR_UNSPECIFIED;
2061 }
2062
2063 /* Set the efficiency to 0 where the mag_zero is 1 */
2064 for (i=0; i<cpl_vector_get_size(mag_zero); i++) {
2065 if (cpl_vector_get(mag_zero, i) == 1.0) {
2066 cpl_vector_set(efficiency, i, 0.0);
2067 }
2068 }
2069 cpl_vector_delete(mag_zero);
2070
2071 /* Create extra columns for the results */
2072 cpl_table_wrap_double(tab, cpl_vector_get_data(efficiency), "Efficiency");
2073 cpl_table_wrap_double(tab, cpl_vector_get_data(conversion), "Conversion");
2074 cpl_vector_unwrap(efficiency);
2075 cpl_vector_unwrap(conversion);
2076
2077 /* Plot the spectra if requested */
2078 if (isaac_spc_jitter_config.plot > 0) {
2079 wl = cpl_vector_wrap(nelem, cpl_table_get_data_double(tab,
2080 "X_coordinate"));
2081 spec = cpl_vector_wrap(nelem, cpl_table_get_data_double(tab,
2082 "Conversion"));
2083 spec_biv = cpl_bivector_wrap_vectors(wl, spec);
2084 cpl_plot_bivector(NULL, "t 'Conversion' w lines",
2085 NULL, spec_biv);
2086 cpl_bivector_unwrap_vectors(spec_biv);
2087 cpl_vector_unwrap(spec);
2088 spec = cpl_vector_wrap(nelem, cpl_table_get_data_double(tab,
2089 "Efficiency"));
2090 spec_biv = cpl_bivector_wrap_vectors(wl, spec);
2091 cpl_plot_bivector(NULL, "t 'Efficiency' w lines", NULL, spec_biv);
2092 cpl_bivector_unwrap_vectors(spec_biv);
2093 cpl_vector_unwrap(spec);
2094 cpl_vector_unwrap(wl);
2095 }
2096
2097 return 0;
2098}
2099
2100/*----------------------------------------------------------------------------*/
2111/*----------------------------------------------------------------------------*/
2112static
2113cpl_error_code isaac_spc_jitter_save(cpl_frameset * set,
2114 const cpl_image * ima,
2115 const cpl_image * contrib,
2116 const cpl_table * tab,
2117 const cpl_parameterlist * parlist)
2118{
2119 /* Get the QC params in qclist */
2120 cpl_propertylist * qclist = cpl_propertylist_new();
2121 cpl_propertylist * paflist = NULL;
2122 const cpl_frame * ref_frame;
2123 char * qc_str = NULL;
2124 const char * procat;
2125 const int nintens
2126 = cpl_vector_get_size(isaac_spc_jitter_config.intensities);
2127 int i;
2128 cpl_propertylist * xtlist = cpl_propertylist_new();
2129
2130 bug_if(cpl_propertylist_append_string(xtlist, "EXTNAME",
2131 "Contribution Map"));
2132 bug_if(contrib == NULL);
2133
2134 /* Add QC parameters */
2135 /* FIXME: Fill this list where the numbers are available */
2136 if (isaac_spc_jitter_config.filter[0] != (char)0)
2137 bug_if(cpl_propertylist_append_string(qclist, "ESO QC FILTER OBS",
2138 isaac_spc_jitter_config.filter));
2139
2140 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISPCO1",
2141 isaac_spc_jitter_config.wavecal_a0));
2142 cpl_propertylist_append_double(qclist, "ESO QC DISPCO2",
2143 isaac_spc_jitter_config.wavecal_a1);
2144 cpl_propertylist_append_double(qclist, "ESO QC DISPCO3",
2145 isaac_spc_jitter_config.wavecal_a2);
2146 cpl_propertylist_append_double(qclist, "ESO QC DISPCO4",
2147 isaac_spc_jitter_config.wavecal_a3);
2148 cpl_propertylist_append_double(qclist, "ESO QC WLEN",
2149 isaac_spc_jitter_config.wavecal_a0 +
2150 isaac_spc_jitter_config.wavecal_a1 * 512 +
2151 isaac_spc_jitter_config.wavecal_a2 * 512 *
2152 512 +
2153 isaac_spc_jitter_config.wavecal_a3 * 512 *
2154 512 * 512);
2155 bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISP XCORR",
2156 isaac_spc_jitter_config.wavecal_cc));
2157 if (isaac_spc_jitter_config.wavecal_out == 0) {
2158 cpl_propertylist_append_string(qclist, "ESO QC WLMETHOD",
2159 "physical model");
2160 } else if (isaac_spc_jitter_config.wavecal_out == 1) {
2161 cpl_propertylist_append_string(qclist, "ESO QC WLMETHOD",
2162 "sky lines");
2163 } else if (isaac_spc_jitter_config.wavecal_out == 2) {
2164 cpl_propertylist_append_string(qclist, "ESO QC WLMETHOD",
2165 "arc file");
2166 }
2167 for (i = 0; i < nintens; i++) {
2168 const double intens
2169 = cpl_vector_get(isaac_spc_jitter_config.intensities, i);
2170
2171 qc_str = cpl_sprintf("ESO QC SPEC INTENS%d", i+1);
2172 cpl_propertylist_append_double(qclist, qc_str, intens);
2173 cpl_free(qc_str);
2174 qc_str = NULL;
2175 }
2176
2177 /* In std mode */
2178 if (isaac_spc_jitter_config.std_mode == 1) {
2179 bug_if(cpl_propertylist_append_string(qclist, "ESO QC STDNAME",
2180 isaac_spc_jitter_config.starname ?
2181 isaac_spc_jitter_config.starname :
2182 ""));
2183 bug_if(cpl_propertylist_append_string(qclist, "ESO QC SPECTYPE",
2184 isaac_spc_jitter_config.sptype ?
2185 isaac_spc_jitter_config.sptype :
2186 ""));
2187 cpl_propertylist_append_double(qclist, "ESO QC STARMAG",
2188 isaac_spc_jitter_config.std_magnitude);
2189 if (isaac_spc_jitter_config.filter_ref[0] != (char)0)
2190 cpl_propertylist_append_string(qclist, "ESO QC FILTER REF",
2191 isaac_spc_jitter_config.filter_ref);
2192 }
2193
2194 /* Change WCS keywords to the computed wavelength solution */
2195 cpl_propertylist_update_double(qclist, "CRVAL1",
2196 isaac_spc_jitter_config.wavecal_a0);
2197 cpl_propertylist_update_double(qclist, "CRVAL2", 1.0);
2198 cpl_propertylist_update_double(qclist, "CRPIX1", 1.0);
2199 cpl_propertylist_update_double(qclist, "CRPIX2", 1.0);
2200 cpl_propertylist_update_double(qclist, "CDELT1",
2201 isaac_spc_jitter_config.wavecal_a1);
2202 cpl_propertylist_update_double(qclist, "CDELT2", 1.0);
2203 cpl_propertylist_update_string(qclist, "CTYPE1", "LINEAR");
2204 cpl_propertylist_update_string(qclist, "CTYPE2", "LINEAR");
2205 if (cpl_propertylist_has(qclist, "CD1_1")) {
2206 cpl_propertylist_update_double(qclist, "CD1_1",
2207 isaac_spc_jitter_config.wavecal_a1);
2208 } else {
2209 cpl_propertylist_insert_after_double(qclist, "CTYPE2", "CD1_1",
2210 isaac_spc_jitter_config.wavecal_a1);
2211 }
2212 if (cpl_propertylist_has(qclist, "CD2_2")) {
2213 cpl_propertylist_update_double(qclist, "CD2_2", 1.0);
2214 } else {
2215 cpl_propertylist_insert_after_double(qclist, "CD1_1", "CD2_2", 1.0);
2216 }
2217
2218 /* Write the image */
2219 procat = isaac_spc_jitter_config.std_mode == 1 ?
2220 ISAAC_SPC_JITTER_COMB_STD : ISAAC_SPC_JITTER_COMB;
2221
2222 irplib_dfs_save_image(set, parlist, set, ima, CPL_BPP_IEEE_FLOAT,
2223 RECIPE_STRING, procat, qclist, NULL,
2224 PACKAGE "/" PACKAGE_VERSION,
2225 RECIPE_STRING "_combined" CPL_DFS_FITS);
2226
2227 /* Append the contribution map */
2228 skip_if (cpl_image_save(contrib, RECIPE_STRING "_combined" CPL_DFS_FITS,
2229 CPL_BPP_16_UNSIGNED, xtlist, CPL_IO_EXTEND));
2230
2231 /* Write the table */
2232 if (tab != NULL) {
2233 const char * procatt = isaac_spc_jitter_config.std_mode == 1 ?
2234 ISAAC_SPC_JITTER_EXTR_STD : ISAAC_SPC_JITTER_EXTR;
2235
2236 irplib_dfs_save_table(set, parlist, set, tab, NULL, RECIPE_STRING,
2237 procatt, qclist, NULL,
2238 PACKAGE "/" PACKAGE_VERSION,
2239 RECIPE_STRING "_extracted" CPL_DFS_FITS);
2240 }
2241
2242 /* Get the reference frame */
2243 ref_frame = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW);
2244
2245 /* Get the keywords for the paf file from the reference file */
2246 paflist = cpl_propertylist_load_regexp(cpl_frame_get_filename(ref_frame),
2247 0, "^(ARCFILE|MJD-OBS|INSTRUME"
2248 "|ESO TPL ID|ESO TPL NEXP"
2249 "|ESO DPR CATG|ESO DPR TECH"
2250 "|ESO DPR TYPE|DATE-OBS"
2251 "|ESO INS GRAT NAME"
2252 "|ESO INS GRAT WLEN"
2253 "|ESO INS OPTI1 ID|ESO OBS ID"
2254 "|ESO OBS TARG NAME)$", 0);
2255 skip_if (paflist == NULL);
2256
2257 /* Copy the QC in paflist */
2258 bug_if(cpl_propertylist_append(paflist, qclist));
2259 cpl_propertylist_empty(qclist);
2260
2261 /* PRO.CATG */
2262 cpl_propertylist_update_string(paflist, CPL_DFS_PRO_CATG, procat);
2263
2264 /* Save the PAF file */
2265 skip_if(cpl_dfs_save_paf("ISAAC", RECIPE_STRING, paflist,
2266 RECIPE_STRING CPL_DFS_PAF));
2267
2268 end_skip;
2269
2270 cpl_propertylist_delete(xtlist);
2271 cpl_propertylist_delete(paflist);
2272 cpl_propertylist_delete(qclist);
2273 cpl_free(qc_str);
2274
2275 return CPL_ERROR_NONE;
2276}
2277
2278/*----------------------------------------------------------------------------*/
2287/*----------------------------------------------------------------------------*/
2288static int off_comp(double off1, double off2, double thresh)
2289{
2290 return (off1 > thresh && off2 < thresh) || (off1 < thresh && off2 > thresh)
2291 ? 1 : 0;
2292}
2293
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
double isaac_pfits_get_win_startx(const cpl_propertylist *plist)
find out the WIN STARTX keyword
Definition: isaac_pfits.c:552
double isaac_pfits_get_ra(const cpl_propertylist *plist)
find out the RA
Definition: isaac_pfits.c:760
double isaac_pfits_get_dit(const cpl_propertylist *plist)
find out the DIT value
Definition: isaac_pfits.c:305
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_frame_type(const cpl_propertylist *plist)
find out the frame type
Definition: isaac_pfits.c:286
double isaac_pfits_get_dec(const cpl_propertylist *plist)
find out the DEC
Definition: isaac_pfits.c:271
double * isaac_get_disprel_estimate(const char *filename, cpl_size poly_deg)
Estimate the instrument wavelength range.
isaac_band isaac_get_bbfilter(const char *f)
Get the broad band filter.
Definition: isaac_utils.c:144
const char * isaac_std_band_name(isaac_band band)
Return a band name.
Definition: isaac_utils.c:243
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
cpl_image * isaac_oddeven_correct(const cpl_image *in)
Correct the odd/even in an image.
Definition: isaac_utils.c:275
const char * isaac_extract_filename(const cpl_frameset *self, const char *tag)
Extract the filename of the first frame of the given tag.
Definition: isaac_utils.c:397
isaac_band isaac_get_associated_filter(const char *f)
Get the broad band filter.
Definition: isaac_utils.c:195