IIINSTRUMENT Pipeline Reference Manual 4.4.12
naco_spc_jitter.c
1/* $Id: naco_spc_jitter.c,v 1.16 2009-05-12 12:43:43 llundin Exp $
2 *
3 * This file is part of the NACO 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: 2009-05-12 12:43:43 $
24 * $Revision: 1.16 $
25 * $Name: not supported by cvs2svn $
26 */
27
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31
32/* FIXME */
33/*
34 - Physical model missing
35 - Wavelength calibration missing
36 - Spectrum detection fails because spectrum not on the whole detector
37*/
38
39/*-----------------------------------------------------------------------------
40 Includes
41 -----------------------------------------------------------------------------*/
42
43#include <math.h>
44#include <cpl.h>
45
46#include "irplib_utils.h"
47#include "irplib_std.h"
48#include "irplib_spectrum.h"
49
50#include "naco_utils.h"
51#include "naco_physicalmodel.h"
52#include "naco_wavelength.h"
53#include "naco_pfits.h"
54#include "naco_dfs.h"
55
56/*-----------------------------------------------------------------------------
57 Define
58 -----------------------------------------------------------------------------*/
59
60#define NACO_SPC_JITTER_OFFSET_ERR 10
61
62/*-----------------------------------------------------------------------------
63 Functions prototypes
64 -----------------------------------------------------------------------------*/
65
66static int naco_spc_jitter_create(cpl_plugin *);
67static int naco_spc_jitter_exec(cpl_plugin *);
68static int naco_spc_jitter_destroy(cpl_plugin *);
69static int naco_spc_jitter(cpl_parameterlist *, cpl_frameset *);
70static cpl_image ** naco_spc_jitter_combine(cpl_frameset *, char *, char *,
71 char *);
72static cpl_vector * naco_spc_jitter_get_offsets(cpl_frameset *);
73static int * naco_spc_jitter_classif(cpl_vector *, int *);
74static int off_comp(double, double, double);
75static cpl_imagelist * naco_spc_jitter_saa_groups(cpl_imagelist *,
76 cpl_vector *, int *, int, cpl_vector **);
77static int naco_spc_jitter_wavecal(char *, cpl_image *, cpl_frameset *);
78static cpl_imagelist * naco_spc_jitter_nodded(cpl_imagelist *, cpl_vector *,
79 cpl_vector **);
80static cpl_imagelist * naco_spc_jitter_distor(cpl_imagelist *, char *);
81static double naco_spc_jitter_refine_offset(cpl_image *, cpl_image *);
82static cpl_table * naco_spc_jitter_extract(cpl_image *);
83static int naco_spc_jitter_save(const cpl_image *, const cpl_table *,
84 cpl_parameterlist *, cpl_frameset *);
85
86/*-----------------------------------------------------------------------------
87 Static variables
88 -----------------------------------------------------------------------------*/
89
90static struct {
91 /* Inputs */
92 int display;
93 /* wavecal_in : 0 for physical model, 1 for sky, 2 for arc table */
94 int wavecal_in;
95 int wavecal_rej_bottom;
96 int wavecal_rej_top;
97 int wavecal_rej_left;
98 int wavecal_rej_right;
99 int saa_refine;
100 double saa_rej_high;
101 double saa_rej_low;
102 int extr_spec_pos;
103 int extr_spec_width;
104 int extr_sky_ri_width;
105 int extr_sky_le_width;
106 int extr_sky_ri_dist;
107 int extr_sky_le_dist;
108 /* Outputs */
109 /* wavecal_out : 0 for physical model, 1 for sky, 2 for arc table */
110 cpl_vector * throws;
111 int wavecal_out;
112 double wavecal_cc;
113 double wavecal_a0;
114 double wavecal_a1;
115 double wavecal_a2;
116 double wavecal_a3;
117} naco_spc_jitter_config;
118
119static char naco_spc_jitter_description[] =
120"naco_spc_jitter -- NACO spectro jitter recipe\n"
121"The files listed in the Set Of Frames (sof-file) must be tagged:\n"
122"raw-file.fits "NACO_SPC_JITTER_RAW" or\n"
123"flat-file.fits "NACO_CALIB_SPFLAT" or\n"
124"arc-file.fits "NACO_CALIB_ARC" or\n"
125"arc_wl-file.fits "NACO_CALIB_ARC_WL"\n";
126
127/*----------------------------------------------------------------------------*/
131/*----------------------------------------------------------------------------*/
132
133/*-----------------------------------------------------------------------------
134 Functions code
135 -----------------------------------------------------------------------------*/
136
137/*----------------------------------------------------------------------------*/
145/*----------------------------------------------------------------------------*/
146int cpl_plugin_get_info(cpl_pluginlist * list)
147{
148 cpl_recipe * recipe = cpl_calloc(1, sizeof(*recipe));
149 cpl_plugin * plugin = &recipe->interface;
150
151 cpl_plugin_init(plugin,
152 CPL_PLUGIN_API,
153 NACO_BINARY_VERSION,
154 CPL_PLUGIN_TYPE_RECIPE,
155 "naco_spc_jitter",
156 "Spectro jitter recipe",
157 naco_spc_jitter_description,
158 "Yves Jung",
159 "yjung@eso.org",
160 cpl_get_license(PACKAGE_NAME, "2002, 2003, 2005"),
161 naco_spc_jitter_create,
162 naco_spc_jitter_exec,
163 naco_spc_jitter_destroy);
164
165 cpl_pluginlist_append(list, plugin);
166
167 return 0;
168}
169
170/*----------------------------------------------------------------------------*/
179/*----------------------------------------------------------------------------*/
180static int naco_spc_jitter_create(cpl_plugin * plugin)
181{
182 cpl_recipe * recipe;
183 cpl_parameter * p;
184
185 /* Get the recipe out of the plugin */
186 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
187 recipe = (cpl_recipe *)plugin;
188 else return -1;
189
190 /* Create the parameters list in the cpl_recipe object */
191 recipe->parameters = cpl_parameterlist_new();
192
193 /* Fill the parameters list */
194 /* --wavecal */
195 p = cpl_parameter_new_value("naco.naco_spc_jitter.wavecal",
196 CPL_TYPE_STRING, "Wavelength method: phy or sky",
197 "naco.naco_spc_jitter", "sky");
198 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wavecal");
199 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
200 cpl_parameterlist_append(recipe->parameters, p);
201 /* --wavecal_rej */
202 p = cpl_parameter_new_value("naco.naco_spc_jitter.wavecal_rej",
203 CPL_TYPE_STRING, "left right bottom top rejections",
204 "naco.naco_spc_jitter", "-1 -1 50 50");
205 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wc_rej");
206 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
207 cpl_parameterlist_append(recipe->parameters, p);
208 /* --saa_refine */
209 p = cpl_parameter_new_value("naco.naco_spc_jitter.saa_refine",
210 CPL_TYPE_BOOL, "flag to refine the offsets",
211 "naco.naco_spc_jitter", TRUE);
212 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "saa_refine");
213 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
214 cpl_parameterlist_append(recipe->parameters, p);
215 /* --saa_rej */
216 p = cpl_parameter_new_value("naco.naco_spc_jitter.saa_rej",
217 CPL_TYPE_STRING, "low and high rejections in percent",
218 "naco.naco_spc_jitter", "0.1 0.1");
219 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "saa_rej");
220 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
221 cpl_parameterlist_append(recipe->parameters, p);
222 /* --spec_pos */
223 p = cpl_parameter_new_value("naco.naco_spc_jitter.spec_pos",
224 CPL_TYPE_INT, "spectrum position", "naco.naco_spc_jitter", -1);
225 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "spec_pos");
226 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
227 cpl_parameterlist_append(recipe->parameters, p);
228 /* --spec_width */
229 p = cpl_parameter_new_value("naco.naco_spc_jitter.spec_width",
230 CPL_TYPE_INT, "spectrum width", "naco.naco_spc_jitter", 10);
231 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "spec_width");
232 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
233 cpl_parameterlist_append(recipe->parameters, p);
234 /* --sky_ri_width */
235 p = cpl_parameter_new_value("naco.naco_spc_jitter.sky_ri_width",
236 CPL_TYPE_INT, "sky width right to the spectrum",
237 "naco.naco_spc_jitter", 10);
238 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sky_ri_width");
239 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
240 cpl_parameterlist_append(recipe->parameters, p);
241 /* --sky_le_width */
242 p = cpl_parameter_new_value("naco.naco_spc_jitter.sky_le_width",
243 CPL_TYPE_INT, "sky width left to the spectrum",
244 "naco.naco_spc_jitter", 10);
245 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sky_le_width");
246 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
247 cpl_parameterlist_append(recipe->parameters, p);
248 /* --sky_ri_dist */
249 p = cpl_parameter_new_value("naco.naco_spc_jitter.sky_ri_dist",
250 CPL_TYPE_INT, "sky distance right to the spectrum",
251 "naco.naco_spc_jitter", -1);
252 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sky_ri_dist");
253 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
254 cpl_parameterlist_append(recipe->parameters, p);
255 /* --sky_le_dist */
256 p = cpl_parameter_new_value("naco.naco_spc_jitter.sky_le_dist",
257 CPL_TYPE_INT, "sky distance left to the spectrum",
258 "naco.naco_spc_jitter", -1);
259 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sky_le_dist");
260 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
261 cpl_parameterlist_append(recipe->parameters, p);
262 /* --display */
263 p = cpl_parameter_new_value("naco.naco_spc_jitter.display",
264 CPL_TYPE_BOOL, "flag to make plots", "naco.naco_spc_jitter",
265 FALSE);
266 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "display");
267 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
268 cpl_parameterlist_append(recipe->parameters, p);
269 return 0;
270}
271
272/*----------------------------------------------------------------------------*/
278/*----------------------------------------------------------------------------*/
279static int naco_spc_jitter_exec(cpl_plugin * plugin)
280{
281 cpl_recipe * recipe;
282
283 /* Get the recipe out of the plugin */
284 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
285 recipe = (cpl_recipe *)plugin;
286 else return -1;
287
288 return naco_spc_jitter(recipe->parameters, recipe->frames);
289}
290
291/*----------------------------------------------------------------------------*/
297/*----------------------------------------------------------------------------*/
298static int naco_spc_jitter_destroy(cpl_plugin * plugin)
299{
300 cpl_recipe * recipe;
301
302 /* Get the recipe out of the plugin */
303 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
304 recipe = (cpl_recipe *)plugin;
305 else return -1;
306
307 cpl_parameterlist_delete(recipe->parameters);
308 return 0;
309}
310
311/*----------------------------------------------------------------------------*/
318/*----------------------------------------------------------------------------*/
319static int naco_spc_jitter(
320 cpl_parameterlist * parlist,
321 cpl_frameset * framelist)
322{
323 const char * fctid = "naco_spc_jitter";
324 cpl_parameter * par;
325 cpl_propertylist * plist;
326 const char * sval;
327 int * labels;
328 int nlabels;
329 cpl_frameset * rawframes;
330 char * flat;
331 char * arc;
332 char * arc_wl;
333 cpl_frame * cur_frame;
334 char * tag;
335 cpl_frameset * cur_set;
336 cpl_image ** combined;
337 cpl_table * extracted;
338 int i;
339
340 /* Initialise */
341 par = NULL;
342 rawframes = NULL;
343 arc = NULL;
344 arc_wl = NULL;
345 flat = NULL;
346 naco_spc_jitter_config.wavecal_out = -1;
347 naco_spc_jitter_config.wavecal_cc = -1.0;
348 naco_spc_jitter_config.throws = NULL;
349
350 /* Retrieve input parameters */
351 /* --wavecal */
352 par = cpl_parameterlist_find(parlist, "naco.naco_spc_jitter.wavecal");
353 sval = cpl_parameter_get_string(par);
354 if (!strcmp(sval, "phy")) naco_spc_jitter_config.wavecal_in = 0;
355 else if (!strcmp(sval, "sky")) naco_spc_jitter_config.wavecal_in = 1;
356 else {
357 cpl_msg_error(fctid, "Invalid value for wavecal option");
358 return -1;
359 }
360 /* Rejection parameters for wavelength calibration*/
361 par = cpl_parameterlist_find(parlist, "naco.naco_spc_jitter.wavecal_rej");
362 sval = cpl_parameter_get_string(par);
363 if (sscanf(sval, "%d %d %d %d",
364 &naco_spc_jitter_config.wavecal_rej_left,
365 &naco_spc_jitter_config.wavecal_rej_right,
366 &naco_spc_jitter_config.wavecal_rej_bottom,
367 &naco_spc_jitter_config.wavecal_rej_top) != 4) {
368 return -1;
369 }
370 /* Refine of offsets */
371 par = cpl_parameterlist_find(parlist, "naco.naco_spc_jitter.saa_refine");
372 naco_spc_jitter_config.saa_refine = cpl_parameter_get_bool(par);
373
374 /* Rejection parameters for SAA */
375 par = cpl_parameterlist_find(parlist, "naco.naco_spc_jitter.saa_rej");
376 sval = cpl_parameter_get_string(par);
377 if (sscanf(sval, "%lg %lg",
378 &naco_spc_jitter_config.saa_rej_low,
379 &naco_spc_jitter_config.saa_rej_high) != 2) {
380 return -1;
381 }
382
383 /* --spec_pos */
384 par=cpl_parameterlist_find(parlist,"naco.naco_spc_jitter.spec_pos");
385 naco_spc_jitter_config.extr_spec_pos = cpl_parameter_get_int(par);
386 /* --spec_width */
387 par=cpl_parameterlist_find(parlist,"naco.naco_spc_jitter.spec_width");
388 naco_spc_jitter_config.extr_spec_width = cpl_parameter_get_int(par);
389 /* --sky_ri_width */
390 par=cpl_parameterlist_find(parlist,"naco.naco_spc_jitter.sky_ri_width");
391 naco_spc_jitter_config.extr_sky_ri_width = cpl_parameter_get_int(par);
392 /* --sky_le_width */
393 par=cpl_parameterlist_find(parlist,"naco.naco_spc_jitter.sky_le_width");
394 naco_spc_jitter_config.extr_sky_le_width = cpl_parameter_get_int(par);
395 /* --sky_ri_dist */
396 par=cpl_parameterlist_find(parlist,"naco.naco_spc_jitter.sky_ri_dist");
397 naco_spc_jitter_config.extr_sky_ri_dist = cpl_parameter_get_int(par);
398 /* --sky_le_dist */
399 par=cpl_parameterlist_find(parlist,"naco.naco_spc_jitter.sky_le_dist");
400 naco_spc_jitter_config.extr_sky_le_dist = cpl_parameter_get_int(par);
401 /* Display */
402 par = cpl_parameterlist_find(parlist, "naco.naco_spc_jitter.display");
403 naco_spc_jitter_config.display = cpl_parameter_get_bool(par);
404
405 /* Identify the RAW and CALIB frames in the input frameset */
406 if (naco_dfs_set_groups(framelist)) {
407 cpl_msg_error(fctid, "Cannot identify RAW and CALIB frames");
408 return -1;
409 }
410
411 /* Labelise the input frames according to their tags */
412 if ((labels = cpl_frameset_labelise(framelist, irplib_compare_tags,
413 &nlabels)) == NULL) {
414 cpl_msg_error(fctid, "Cannot labelise the input frames");
415 return -1;
416 }
417
418 /* For each label */
419 for (i=0 ; i<nlabels ; i++) {
420 cur_set = cpl_frameset_extract(framelist, labels, i);
421 cur_frame = cpl_frameset_get_position(cur_set, 0);
422 tag = (char*)cpl_frame_get_tag(cur_frame);
423 if (!strcmp(tag, NACO_SPC_JITTER_RAW)) {
424 /* Raw frames */
425 rawframes = cpl_frameset_duplicate(cur_set);
426 } else if (!strcmp(tag, NACO_CALIB_SPFLAT)) {
427 /* Flat */
428 if (flat == NULL)
429 flat = cpl_strdup(cpl_frame_get_filename(cur_frame));
430 } else if (!strcmp(tag, NACO_CALIB_ARC)) {
431 /* Arc */
432 if (arc == NULL)
433 arc = cpl_strdup(cpl_frame_get_filename(cur_frame));
434 } else if (!strcmp(tag, NACO_CALIB_ARC_WL)) {
435 /* Arc for wl */
436 naco_spc_jitter_config.wavecal_in = 2;
437 if (arc_wl == NULL)
438 arc_wl = cpl_strdup(cpl_frame_get_filename(cur_frame));
439 }
440 cpl_frameset_delete(cur_set);
441 }
442 cpl_free(labels);
443
444 /* The raw frames must be there */
445 if (rawframes == NULL) {
446 cpl_msg_error(fctid, "Cannot find the raw frames in the input list");
447 if (flat) cpl_free(flat);
448 if (arc) cpl_free(arc);
449 if (arc_wl) cpl_free(arc_wl);
450 return -1;
451 }
452
453 /* Create the combined image */
454 cpl_msg_info(fctid, "Create the combined image");
455 cpl_msg_indent_more();
456 if ((combined = naco_spc_jitter_combine(rawframes, flat, arc,
457 arc_wl)) == NULL) {
458 cpl_msg_error(fctid, "Cannot combine the images");
459 if (flat) cpl_free(flat);
460 if (arc) cpl_free(arc);
461 if (arc_wl) cpl_free(arc_wl);
462 cpl_frameset_delete(rawframes);
463 if (naco_spc_jitter_config.throws)
464 cpl_vector_delete(naco_spc_jitter_config.throws);
465 cpl_msg_indent_less();
466 return -1;
467 }
468 cpl_frameset_delete(rawframes);
469 if (flat) cpl_free(flat);
470 if (arc) cpl_free(arc);
471 if (arc_wl) cpl_free(arc_wl);
472 cpl_msg_indent_less();
473
474 /* Extract the spectrum */
475 cpl_msg_info(fctid, "Extract the spectrum");
476 cpl_msg_indent_more();
477 if ((extracted = naco_spc_jitter_extract(combined[0])) == NULL) {
478 cpl_msg_error(fctid, "Cannot extract the spectrum");
479 }
480 if (naco_spc_jitter_config.throws)
481 cpl_vector_delete(naco_spc_jitter_config.throws);
482 cpl_msg_indent_less();
483
484 /* Write the products */
485 cpl_msg_info(fctid, "Save the products");
486 cpl_msg_indent_more();
487 if (naco_spc_jitter_save(combined[0], extracted, parlist,
488 framelist) == -1) {
489 cpl_msg_error(fctid, "Cannot save the products");
490 cpl_image_delete(combined[0]);
491 cpl_image_delete(combined[1]);
492 cpl_free(combined);
493 cpl_table_delete(extracted);
494 cpl_msg_indent_less();
495 return -1;
496 }
497 cpl_table_delete(extracted);
498 cpl_image_delete(combined[0]);
499 cpl_image_delete(combined[1]);
500 cpl_free(combined);
501 cpl_msg_indent_less();
502
503 return 0;
504}
505
506/*----------------------------------------------------------------------------*/
515/*----------------------------------------------------------------------------*/
516static cpl_image ** naco_spc_jitter_combine(
517 cpl_frameset * rawframes,
518 char * flat,
519 char * arc,
520 char * arc_wl)
521{
522 const char * fctid = "naco_spc_jitter_combine";
523 cpl_imagelist * ilist;
524 cpl_imagelist * corrected;
525 cpl_image * cur_im;
526 cpl_image * tmp_im;
527 cpl_vector * offsets;
528 int * groups;
529 int ngroups;
530 cpl_imagelist * abba;
531 cpl_vector * abba_off = NULL; /* If only abba gets allocated */
532 cpl_imagelist * nodded;
533 cpl_vector * nodded_off_x;
534 cpl_vector * nodded_off_y;
535 double throw;
536 cpl_table * extracted;
537 double intensity;
538 double * pnodded_off_x;
539 cpl_imagelist * nodded_warped;
540 cpl_bivector * nodded_offsets;
541 cpl_image ** combined;
542 int nima;
543 double new_offset;
544 int i;
545
546 /* Test entries */
547 if (rawframes == NULL) return NULL;
548
549 /* Load the images */
550 cpl_msg_info(fctid, "Load the data");
551 cpl_msg_indent_more();
552 if ((ilist = cpl_imagelist_load_frameset(rawframes, CPL_TYPE_FLOAT,
553 1, 0)) == NULL) {
554 cpl_msg_error(fctid, "cannot load the data");
555 cpl_msg_indent_less();
556 return NULL;
557 }
558 cpl_msg_indent_less();
559
560 /* Apply the flafield */
561 if (flat != NULL) {
562 cpl_msg_info(fctid, "Apply the flatfield correction");
563 if ((tmp_im = cpl_image_load(flat, CPL_TYPE_FLOAT, 0, 0)) == NULL) {
564 cpl_msg_warning(fctid, "cannot load the flat field");
565 } else {
566 if (cpl_imagelist_divide_image(ilist, tmp_im) != CPL_ERROR_NONE) {
567 cpl_msg_warning(fctid, "cannot apply the flat field");
568 }
569 cpl_image_delete(tmp_im);
570 }
571 }
572
573 /* Get the offsets */
574 cpl_msg_info(fctid, "Get the offsets");
575 if ((offsets = naco_spc_jitter_get_offsets(rawframes)) == NULL) {
576 cpl_msg_error(fctid, "cannot get the offsets");
577 cpl_imagelist_delete(ilist);
578 return NULL;
579 }
580
581 /* Classify in groups the a and b images sequence */
582 cpl_msg_info(fctid, "Classify in groups");
583 cpl_msg_indent_more();
584 if ((groups = naco_spc_jitter_classif(offsets, &ngroups)) == NULL) {
585 cpl_msg_error(fctid, "cannot classify the data");
586 cpl_imagelist_delete(ilist);
587 cpl_vector_delete(offsets);
588 cpl_msg_indent_less();
589 return NULL;
590 }
591 cpl_msg_indent_less();
592
593 /* Shift and add each group to one image */
594 cpl_msg_info(fctid, "Shift and add each group to one image");
595 cpl_msg_indent_more();
596 if ((abba = naco_spc_jitter_saa_groups(ilist, offsets, groups,
597 ngroups, &abba_off)) == NULL) {
598 cpl_msg_error(fctid, "cannot shift and add groups");
599 cpl_imagelist_delete(ilist);
600 cpl_vector_delete(offsets);
601 cpl_free(groups);
602 cpl_msg_indent_less();
603 cpl_vector_delete(abba_off);
604 return NULL;
605 }
606 cpl_imagelist_delete(ilist);
607 cpl_free(groups);
608 cpl_vector_delete(offsets);
609 cpl_msg_indent_less();
610
611 /* Compute the wavelength calibration */
612 /*
613 cpl_msg_info(fctid, "Compute the wavelength calibration");
614 cpl_msg_indent_more();
615 if (naco_spc_jitter_wavecal(arc_wl, cpl_imagelist_get(abba, 0),
616 rawframes) == -1) {
617 cpl_msg_error(fctid, "cannot compute the wavelength");
618 cpl_imagelist_delete(abba);
619 cpl_vector_delete(abba_off);
620 cpl_msg_indent_less();
621 return NULL;
622 }
623 cpl_msg_indent_less();
624 */
625
626 /* Create the nodded images */
627 cpl_msg_info(fctid, "Create the nodded images");
628 cpl_msg_indent_more();
629 if ((nodded = naco_spc_jitter_nodded(abba, abba_off,
630 &nodded_off_x))==NULL) {
631 cpl_msg_error(fctid, "cannot create the nodded images");
632 cpl_imagelist_delete(abba);
633 cpl_vector_delete(abba_off);
634 cpl_msg_indent_less();
635 return NULL;
636 }
637 cpl_imagelist_delete(abba);
638 cpl_msg_indent_less();
639
640 /* Get the throw offsets from abba_off */
641 nima = cpl_imagelist_get_size(nodded);
642 naco_spc_jitter_config.throws = cpl_vector_new(nima);
643 for (i=0 ; i<nima/2 ; i++) {
644 throw = fabs( (cpl_vector_get(abba_off, 2*i))-
645 (cpl_vector_get(abba_off, 2*i+1)));
646 cpl_vector_set(naco_spc_jitter_config.throws, 2*i, throw);
647 cpl_vector_set(naco_spc_jitter_config.throws, 2*i+1, throw);
648 }
649 cpl_vector_delete(abba_off);
650
651 /* Distortion correction */
652 if (arc) {
653 cpl_msg_info(fctid, "Correct the distortion on nodded images");
654 cpl_msg_indent_more();
655 if ((nodded_warped = naco_spc_jitter_distor(nodded, arc)) == NULL) {
656 cpl_msg_error(fctid, "cannot correct the distortion");
657 cpl_imagelist_delete(nodded);
658 cpl_vector_delete(nodded_off_x);
659 cpl_msg_indent_less();
660 return NULL;
661 }
662 cpl_imagelist_delete(nodded);
663 nodded = nodded_warped;
664 cpl_msg_indent_less();
665 }
666
667 /* Refine the offsets if requested */
668 if (naco_spc_jitter_config.saa_refine) {
669 cpl_msg_info(fctid, "Refine the offsets");
670 pnodded_off_x = cpl_vector_get_data(nodded_off_x);
671 for (i=0 ; i<cpl_imagelist_get_size(nodded) ; i++) {
672 new_offset = naco_spc_jitter_refine_offset(
673 cpl_imagelist_get(nodded, 0),
674 cpl_imagelist_get(nodded, i));
675 if (new_offset > 5000) {
676 cpl_msg_debug(fctid, "cannot refine the offset - keep %g",
677 pnodded_off_x[i]);
678 } else {
679 if (fabs(new_offset-pnodded_off_x[i]) <
680 NACO_SPC_JITTER_OFFSET_ERR) {
681 cpl_msg_debug(fctid, "refined offset : %g (old was %g)",
682 new_offset, pnodded_off_x[i]);
683 pnodded_off_x[i] = new_offset;
684 } else {
685 cpl_msg_debug(fctid,
686 "refined offset %g too different - keep %g",
687 new_offset, pnodded_off_x[i]);
688 }
689 }
690 }
691 }
692
693 /* Images combination */
694 /* Get the offsets in a bivector */
695 nodded_off_y = cpl_vector_duplicate(nodded_off_x);
696 cpl_vector_fill(nodded_off_y, 0.0);
697 nodded_offsets = cpl_bivector_wrap_vectors(nodded_off_x, nodded_off_y);
698 /* Shift and add */
699 cpl_msg_info(fctid, "Apply the shift and add on the nodded frames");
700 nima = cpl_imagelist_get_size(nodded);
701 if ((combined = cpl_geom_img_offset_saa(nodded, nodded_offsets,
702 CPL_KERNEL_DEFAULT,
703 (int)(naco_spc_jitter_config.saa_rej_low * nima),
704 (int)(naco_spc_jitter_config.saa_rej_high * nima),
705 CPL_GEOM_FIRST, NULL, NULL)) == NULL) {
706 cpl_msg_error(fctid, "Cannot shift and add group");
707 cpl_imagelist_delete(nodded);
708 cpl_bivector_unwrap_vectors(nodded_offsets);
709 cpl_vector_delete(nodded_off_x);
710 cpl_vector_delete(nodded_off_y);
711 return NULL;
712 }
713 cpl_imagelist_delete(nodded);
714 cpl_bivector_unwrap_vectors(nodded_offsets);
715 cpl_vector_delete(nodded_off_x);
716 cpl_vector_delete(nodded_off_y);
717 return combined;
718}
719
720/*----------------------------------------------------------------------------*/
726/*----------------------------------------------------------------------------*/
727static cpl_vector * naco_spc_jitter_get_offsets(cpl_frameset * rawframes)
728{
729 const char * fctid = "naco_spc_jitter_get_offsets";
730 cpl_vector * offsets;
731 double * pvect;
732 int nraw;
733 cpl_frame * cur_frame;
734 cpl_propertylist * plist;
735 int i;
736
737 /* Test entries */
738 if (rawframes == NULL) return NULL;
739
740 /* Initialise */
741 nraw = cpl_frameset_get_size(rawframes);
742
743 /* Get the rawframes X offsets */
744 offsets = cpl_vector_new(nraw);
745 pvect = cpl_vector_get_data(offsets);
746 for (i=0 ; i<nraw ; i++) {
747 cur_frame = cpl_frameset_get_position(rawframes, i);
748 if ((plist=cpl_propertylist_load(cpl_frame_get_filename(cur_frame),
749 0)) == NULL) {
750 cpl_msg_error(fctid, "cannot get property list");
751 cpl_vector_delete(offsets);
752 return NULL;
753 }
754 pvect[i] = -1 * naco_pfits_get_cumoffsetx(plist);
755 if (cpl_error_get_code()) {
756 cpl_msg_error(fctid, "cannot get the offset from the header");
757 cpl_vector_delete(offsets);
758 cpl_propertylist_delete(plist);
759 return NULL;
760 }
761 cpl_propertylist_delete(plist);
762 }
763 return offsets;
764}
765
766/*----------------------------------------------------------------------------*/
804/*----------------------------------------------------------------------------*/
805static int * naco_spc_jitter_classif(
806 cpl_vector * offsets,
807 int * ngroups)
808{
809 const char * fctid = "naco_spc_jitter_classif";
810 double * pvect;
811 int nraw;
812 double offset_thresh;
813 cpl_vector * tmp_vec;
814 int * groups;
815 int last_group;
816 int i, j, k, l;
817
818 /* Test entries */
819 if (offsets == NULL) return NULL;
820
821 /* Initialise */
822 nraw = cpl_vector_get_size(offsets);
823
824 /* Separate the offsets in 2 categories */
825 tmp_vec = cpl_vector_duplicate(offsets);
826 cpl_vector_sort(tmp_vec, 1);
827 pvect = cpl_vector_get_data(tmp_vec);
828 if (pvect[0] == pvect[nraw-1]) {
829 cpl_msg_error(fctid, "Only one offset in the list - abort");
830 cpl_vector_delete(tmp_vec);
831 return NULL;
832 }
833 offset_thresh = (pvect[0] + pvect[nraw-1]) / 2.0;
834 cpl_vector_delete(tmp_vec);
835
836 /* Identify the different A and B groups */
837 pvect = cpl_vector_get_data(offsets);
838 *ngroups = 0;
839 groups = cpl_calloc(nraw, sizeof(int));
840
841 /* Create a look up table to associate the ith obj with the jth frame */
842 i = 0;
843 while (i < nraw) {
844 j = 0;
845 /* Count the number of successive '+' or '-' (j) */
846 while ((i+j<nraw) &&
847 (!off_comp(pvect[i], pvect[i+j], offset_thresh))) j++;
848
849 if (i+j >= nraw) i = nraw;
850 else {
851 k = 0;
852 /* Check if there are j '-' or '+' (k) */
853 while ((i+j+k < nraw)
854 && (!off_comp(pvect[i+j], pvect[i+j+k], offset_thresh))
855 && (k<j)) k++;
856 last_group = 1;
857 if (i+j+k < nraw) {
858 for (l=i+j+k ; l<nraw ; l++) {
859 if (off_comp(pvect[i+j], pvect[l], offset_thresh)) {
860 last_group = 0;
861 break;
862 }
863 }
864 }
865 if (last_group == 0) {
866 for (l=0 ; l<j ; l++) groups[i+l] = *ngroups + 1;
867 for (l=0 ; l<k ; l++) groups[i+j+l] = *ngroups + 2;
868 *ngroups += 2;
869 i += j+k;
870 } else {
871 for (l=0 ; l<j ; l++) groups[i+l] = *ngroups + 1;
872 for (l=0 ; l<nraw - (i+j) ; l++) groups[i+j+l] =*ngroups + 2;
873 *ngroups += 2;
874 i = nraw;
875 }
876 }
877 }
878
879 /* Nb of groups found should be even */
880 if (*ngroups % 2) {
881 cpl_msg_error(fctid, "Odd number of groups found");
882 cpl_free(groups);
883 return NULL;
884 }
885
886 return groups;
887}
888
889/*----------------------------------------------------------------------------*/
920/*----------------------------------------------------------------------------*/
921static cpl_imagelist * naco_spc_jitter_saa_groups(
922 cpl_imagelist * ilist,
923 cpl_vector * offsets,
924 int * groups,
925 int ngroups,
926 cpl_vector ** abba_off)
927{
928 const char * fctid = "naco_spc_jitter_saa_groups";
929 cpl_imagelist * abba;
930 cpl_imagelist * group_list;
931 cpl_image * tmp_ima;
932 cpl_image ** combined;
933 cpl_bivector * group_off;
934 double * pgroup_off;
935 double * poffsets;
936 double * pabba_off;
937 int nima;
938 int saa;
939 int i, j, k;
940
941 /* Test entries */
942 if ((ilist == NULL) || (offsets == NULL) || (groups == NULL)) return NULL;
943
944 /* Initialise */
945 nima = cpl_imagelist_get_size(ilist);
946 poffsets = cpl_vector_get_data(offsets);
947
948 /* Create the output image list */
949 abba = cpl_imagelist_new();
950 *abba_off = cpl_vector_new(ngroups);
951 pabba_off = cpl_vector_get_data(*abba_off);
952
953 /* Loop on the groups */
954 for (i=0 ; i<ngroups ; i++) {
955 /* Initialise */
956 saa = 0;
957 /* Create the group list of images */
958 group_list = cpl_imagelist_new();
959 k = 0;
960 for (j=0 ; j<nima ; j++) {
961 if (i+1 == groups[j]) {
962 /* Get the first offset of the group in abba_off */
963 if (k==0) pabba_off[i] = poffsets[j];
964 /* To know if we need the saa (shift and add) */
965 if (fabs(pabba_off[i]-poffsets[j]) > 1e-3) saa = 1;
966 /* Copy the images of the group in group_list */
967 tmp_ima = cpl_image_duplicate(cpl_imagelist_get(ilist, j));
968 cpl_imagelist_set(group_list, tmp_ima, k);
969 tmp_ima = NULL;
970 k++;
971 }
972 }
973
974 if (saa) {
975 /* Get the offsets of the group in group_off */
976 group_off = cpl_bivector_new(k);
977 cpl_vector_fill(cpl_bivector_get_y(group_off), 0.0);
978 pgroup_off = cpl_bivector_get_x_data(group_off);
979 k = 0;
980 for (j=0 ; j<nima ; j++) {
981 if (i+1 == groups[j]) {
982 pgroup_off[k] = poffsets[j];
983 k++;
984 }
985 }
986 cpl_vector_subtract_scalar(cpl_bivector_get_x(group_off),
987 pabba_off[i]);
988 /* Shift and add */
989 cpl_msg_debug(fctid, "Apply shift-and-add for group %d", i+1);
990 if ((combined = cpl_geom_img_offset_saa(group_list,
991 group_off, CPL_KERNEL_DEFAULT, 0, 0,
992 CPL_GEOM_FIRST)) == NULL) {
993 cpl_msg_error(fctid, "Cannot shift and add group nb %d", i+1);
994 cpl_imagelist_delete(group_list);
995 cpl_bivector_delete(group_off);
996 cpl_imagelist_delete(abba);
997 cpl_vector_delete(*abba_off);
998 return NULL;
999 }
1000 cpl_bivector_delete(group_off);
1001 cpl_image_delete(combined[1]);
1002 cpl_imagelist_set(abba, combined[0], i);
1003 cpl_free(combined);
1004 } else {
1005 /* Averaging */
1006 cpl_msg_debug(fctid, "Apply averaging for group %d", i+1);
1007 if ((tmp_ima = cpl_imagelist_collapse_create(group_list)) == NULL) {
1008 cpl_msg_error(fctid, "Cannot average group nb %d", i+1);
1009 cpl_imagelist_delete(group_list);
1010 cpl_imagelist_delete(abba);
1011 cpl_vector_delete(*abba_off);
1012 return NULL;
1013 }
1014 cpl_imagelist_set(abba, tmp_ima, i);
1015 }
1016 cpl_imagelist_delete(group_list);
1017 }
1018 return abba;
1019}
1020
1021/*----------------------------------------------------------------------------*/
1029/*----------------------------------------------------------------------------*/
1030static int naco_spc_jitter_wavecal(
1031 char * arc,
1032 cpl_image * ima,
1033 cpl_frameset * raw)
1034{
1035 const char * fctid = "naco_spc_jitter_wavecal";
1036 cpl_table * arc_tab;
1037 double * phdisprel;
1038 cpl_frame * cur_frame;
1039 const char * cur_fname;
1040 computed_disprel * disprel;
1041 int order;
1042 double slit_width;
1043
1044 /* Get the wavelength from the arc file */
1045 if (arc) {
1046 cpl_msg_info(fctid, "Get the wavelength from the ARC file");
1047 if ((arc_tab = cpl_table_load(arc, 1, 0)) == NULL) {
1048 cpl_msg_error(fctid, "Cannot load the arc table");
1049 naco_spc_jitter_config.wavecal_out = -1;
1050 return -1;
1051 }
1052 naco_spc_jitter_config.wavecal_a0 =
1053 cpl_table_get_double(arc_tab, "WL_coefficients", 0, NULL);
1054 naco_spc_jitter_config.wavecal_a1 =
1055 cpl_table_get_double(arc_tab, "WL_coefficients", 1, NULL);
1056 naco_spc_jitter_config.wavecal_a2 =
1057 cpl_table_get_double(arc_tab, "WL_coefficients", 2, NULL);
1058 naco_spc_jitter_config.wavecal_a3 =
1059 cpl_table_get_double(arc_tab, "WL_coefficients", 3, NULL);
1060 cpl_table_delete(arc_tab);
1061 naco_spc_jitter_config.wavecal_out = 2;
1062 naco_spc_jitter_config.wavecal_cc = -1.0;
1063 return 0;
1064 }
1065
1066 /* Get the reference frame */
1067 cur_frame = cpl_frameset_get_position(raw, 0);
1068 cur_fname = cpl_frame_get_filename(cur_frame);
1069
1070 /* Get the physical model */
1071 cpl_msg_info(fctid, "Compute the physical model");
1072 cpl_msg_indent_more();
1073 if ((phdisprel = naco_get_disprel_estimate(cur_fname, 3)) == NULL) {
1074 cpl_msg_error(fctid, "cannot compute the physical model");
1075 naco_spc_jitter_config.wavecal_out = -1;
1076 cpl_msg_indent_less();
1077 return -1;
1078 }
1079 cpl_msg_info(fctid, "f(x)=%g + %g*x + %g*x^2 + %g*x^3",
1080 phdisprel[0], phdisprel[1], phdisprel[2], phdisprel[3]);
1081 naco_spc_jitter_config.wavecal_a0 = phdisprel[0];
1082 naco_spc_jitter_config.wavecal_a1 = phdisprel[1];
1083 naco_spc_jitter_config.wavecal_a2 = phdisprel[2];
1084 naco_spc_jitter_config.wavecal_a3 = phdisprel[3];
1085 naco_spc_jitter_config.wavecal_cc = -1.0;
1086 naco_spc_jitter_config.wavecal_out = 0;
1087 cpl_msg_indent_less();
1088
1089 /* Compute the wavelength using the sky lines */
1090 if (naco_spc_jitter_config.wavecal_in == 1) {
1091 /* Compute the slit_width */
1092 if ((slit_width = naco_get_slitwidth(cur_fname)) == -1) {
1093 cpl_msg_warning(fctid, "cannot get the slit width");
1094 cpl_free(phdisprel);
1095 return 0;
1096 }
1097 /* Get the order */
1098 if ((order = naco_find_order(cur_fname)) == -1) {
1099 cpl_msg_warning(fctid, "cannot get the order");
1100 cpl_free(phdisprel);
1101 return 0;
1102 }
1103 /* Compute the wavelength */
1104 cpl_msg_info(fctid, "Compute the wavelength with the sky lines");
1105 cpl_msg_indent_more();
1106 if ((disprel = naco_spectro_compute_disprel(ima,
1107 naco_spc_jitter_config.wavecal_rej_bottom,
1108 naco_spc_jitter_config.wavecal_rej_top,
1109 naco_spc_jitter_config.wavecal_rej_left,
1110 naco_spc_jitter_config.wavecal_rej_right,
1111 naco_has_thermal(cur_fname) > 0,
1112 "oh", slit_width, order,
1113 (int)(cpl_msg_get_level() == CPL_MSG_DEBUG),
1114 phdisprel)) == NULL) {
1115 cpl_msg_error(fctid, "cannot compute the dispersion relation");
1116 cpl_free(phdisprel);
1117 cpl_msg_indent_less();
1118 return 0;
1119 }
1120 cpl_msg_info(fctid, "Cross correlation factor: %g", disprel->cc);
1121 cpl_msg_info(fctid, "f(x)=%g + %g*x + %g*x^2 + %g*x^3",
1122 disprel->poly[0], disprel->poly[1], disprel->poly[2],
1123 disprel->poly[3]);
1124 naco_spc_jitter_config.wavecal_a0 = disprel->poly[0];
1125 naco_spc_jitter_config.wavecal_a1 = disprel->poly[1];
1126 naco_spc_jitter_config.wavecal_a2 = disprel->poly[2];
1127 naco_spc_jitter_config.wavecal_a3 = disprel->poly[3];
1128 naco_spc_jitter_config.wavecal_cc = disprel->cc;
1129 naco_spc_jitter_config.wavecal_out = 1;
1130 if (disprel->poly != NULL) cpl_free(disprel->poly);
1131 cpl_free(disprel);
1132 cpl_msg_indent_less();
1133 }
1134 cpl_free(phdisprel);
1135 return 0;
1136}
1137
1138/*----------------------------------------------------------------------------*/
1170/*----------------------------------------------------------------------------*/
1171static cpl_imagelist * naco_spc_jitter_nodded(
1172 cpl_imagelist * abba,
1173 cpl_vector * abba_off,
1174 cpl_vector ** nodded_off)
1175{
1176 const char * fctid = "naco_spc_jitter_nodded";
1177 cpl_imagelist * nodded;
1178 cpl_image * tmp_ima;
1179 int nima;
1180 double * pabba_off;
1181 double * pnodded_off;
1182 double ref_off;
1183 int i;
1184
1185 /* Test entries */
1186 if ((abba == NULL) || (abba_off == NULL)) return NULL;
1187
1188 /* Initialise */
1189 nima = cpl_imagelist_get_size(abba);
1190 if (nima % 2) {
1191 cpl_msg_error(fctid, "Number of images should be even");
1192 return NULL;
1193 }
1194
1195 /* Create the offsets between the nodded images */
1196 *nodded_off = cpl_vector_duplicate(abba_off);
1197 /* The image list to contain the nodded images */
1198 nodded = cpl_imagelist_new();
1199 for (i=0 ; i<(nima/2) ; i++) {
1200 /* a-b */
1201 tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i));
1202 cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i+1));
1203 cpl_imagelist_set(nodded, tmp_ima, 2*i);
1204 /* b-a */
1205 tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i+1));
1206 cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i));
1207 cpl_imagelist_set(nodded, tmp_ima, 2*i+1);
1208 }
1209
1210 /* Subtract the first offset to the others */
1211 ref_off = cpl_vector_get(*nodded_off, 0);
1212 cpl_vector_subtract_scalar(*nodded_off, ref_off);
1213 return nodded;
1214}
1215
1216/*----------------------------------------------------------------------------*/
1223/*----------------------------------------------------------------------------*/
1224static cpl_imagelist * naco_spc_jitter_distor(
1225 cpl_imagelist * ilist,
1226 char * arc)
1227{
1228 const char * fctid = "naco_spc_jitter_distor";
1229 cpl_polynomial * arc_poly;
1230 cpl_polynomial * sttr_poly;
1231 cpl_table * tab;
1232 int pow[2];
1233 cpl_vector * profile;
1234 cpl_imagelist * warped_list;
1235 cpl_image * warped;
1236 int i;
1237
1238 /* Test entries */
1239 if (ilist == NULL) return NULL;
1240 if (arc == NULL) return NULL;
1241
1242 /* Get the arc polynomial */
1243 arc_poly = cpl_polynomial_new(2);
1244 if (arc != NULL) {
1245 cpl_msg_info(fctid, "Get the arc distortion from the file");
1246 if ((tab = cpl_table_load(arc, 1, 0)) == NULL) {
1247 cpl_msg_error(fctid, "cannot load the arc table");
1248 cpl_polynomial_delete(arc_poly);
1249 return NULL;
1250 }
1251 for (i=0 ; i<cpl_table_get_nrow(tab) ; i++) {
1252 pow[0] = cpl_table_get_int(tab, "Degree_of_x", i, NULL);
1253 pow[1] = cpl_table_get_int(tab, "Degree_of_y", i, NULL);
1254 cpl_polynomial_set_coeff(arc_poly, pow,
1255 cpl_table_get_double(tab, "poly2d_coef", i, NULL));
1256 }
1257 cpl_table_delete(tab);
1258 } else {
1259 cpl_msg_info(fctid, "Use the ID polynomial for the arc dist");
1260 pow[0] = 1;
1261 pow[1] = 0;
1262 cpl_polynomial_set_coeff(arc_poly, pow, 1.0);
1263 }
1264
1265 /* Get the startrace polynomial */
1266 sttr_poly = cpl_polynomial_new(2);
1267 cpl_msg_info(fctid, "Use the ID polynomial for the startrace dist");
1268 pow[0] = 0;
1269 pow[1] = 1;
1270 cpl_polynomial_set_coeff(sttr_poly, pow, 1.0);
1271
1272 /* Create the kernel */
1273 profile = cpl_vector_new(CPL_KERNEL_DEF_SAMPLES);
1274 cpl_vector_fill_kernel_profile(profile, CPL_KERNEL_DEFAULT,
1275 CPL_KERNEL_DEF_WIDTH);
1276
1277 /* Correct the images */
1278 warped_list = cpl_imagelist_new();
1279 for (i=0 ; i<cpl_imagelist_get_size(ilist) ; i++) {
1280 warped = cpl_image_duplicate(cpl_imagelist_get(ilist, i));
1281 if (cpl_image_warp_polynomial(warped, cpl_imagelist_get(ilist, i),
1282 arc_poly, sttr_poly, profile, CPL_KERNEL_DEF_WIDTH, profile,
1283 CPL_KERNEL_DEF_WIDTH) != CPL_ERROR_NONE) {
1284 cpl_msg_error(fctid, "cannot correct the distortion");
1285 cpl_image_delete(warped);
1286 cpl_polynomial_delete(arc_poly);
1287 cpl_polynomial_delete(sttr_poly);
1288 cpl_vector_delete(profile);
1289 return NULL;
1290 }
1291 cpl_imagelist_set(warped_list, warped, i);
1292 }
1293 cpl_vector_delete(profile);
1294 cpl_polynomial_delete(arc_poly);
1295 cpl_polynomial_delete(sttr_poly);
1296 return warped_list;
1297}
1298
1299/*----------------------------------------------------------------------------*/
1306/*----------------------------------------------------------------------------*/
1307static double naco_spc_jitter_refine_offset(
1308 cpl_image * ima1,
1309 cpl_image * ima2)
1310{
1311 double pos1, pos2;
1312
1313 /* Test entries */
1314 if (ima1 == NULL) return 10000.0;
1315 if (ima2 == NULL) return 10000.0;
1316
1317 /* Detect the spectra */
1318 if (irplib_spectrum_find_brightest(ima1, 0.0, NO_SHADOW, 0.0, 1,
1319 &pos1) == -1){
1320 return 10000.0;
1321 }
1322 if (irplib_spectrum_find_brightest(ima2, 0.0, NO_SHADOW, 0.0, 1,
1323 &pos2) == -1){
1324 return 10000.0;
1325 }
1326 return pos1-pos2;
1327}
1328
1329/*----------------------------------------------------------------------------*/
1335/*----------------------------------------------------------------------------*/
1336static cpl_table * naco_spc_jitter_extract(cpl_image * combined)
1337{
1338 const char * fctid = "naco_spc_jitter_extract";
1339 int le_dist, ri_dist, le_width, ri_width, spec_pos;
1340 int nx, ny;
1341 double pos;
1342 int le_side, ri_side;
1343 int sky_pos[4];
1344 cpl_vector * sky;
1345 cpl_vector * spec;
1346 cpl_vector * wl;
1347 double * pspec;
1348 double * psky;
1349 double * pwl;
1350 cpl_table * out;
1351 cpl_bivector * toplot;
1352 int throw;
1353 int res;
1354 int i;
1355
1356 /* Test entries */
1357 if (combined == NULL) return NULL;
1358
1359 /* Initialise */
1360 nx = cpl_image_get_size_x(combined);
1361 ny = cpl_image_get_size_y(combined);
1362 le_dist = naco_spc_jitter_config.extr_sky_le_dist;
1363 ri_dist = naco_spc_jitter_config.extr_sky_ri_dist;
1364 le_width = naco_spc_jitter_config.extr_sky_le_width;
1365 ri_width = naco_spc_jitter_config.extr_sky_ri_width;
1366 spec_pos = naco_spc_jitter_config.extr_spec_pos;
1367
1368 /* Detect the spectrum position if not passed */
1369 if (spec_pos < 0) {
1370 if (naco_spc_jitter_config.throws == NULL) {
1371 cpl_msg_error(fctid, "Need a throw value to detect the spectra !!");
1372 return NULL;
1373 }
1374
1375 for (i=0 ; i<cpl_vector_get_size(naco_spc_jitter_config.throws) ; i++){
1376 throw = (int)cpl_vector_get(naco_spc_jitter_config.throws, i);
1377 if ((res = irplib_spectrum_find_brightest(combined, throw,
1378 TWO_SHADOWS, 0.0, 1, &pos)) == 0) break;
1379 if ((res = irplib_spectrum_find_brightest(combined, throw,
1380 ONE_SHADOW, 0.0, 1, &pos)) == 0) break;
1381 }
1382 if (res != 0) {
1383 cpl_msg_error(fctid, "Cannot detect the spectrum");
1384 return NULL;
1385 }
1386 spec_pos = (int)pos;
1387 cpl_msg_info(fctid, "Spectrum detected at x = %d", spec_pos);
1388 }
1389
1390 /* Set the parameters for the extraction */
1391
1392 /* Spectrum position */
1393 le_side = spec_pos - (int)(naco_spc_jitter_config.extr_spec_width/2);
1394 ri_side = le_side + naco_spc_jitter_config.extr_spec_width;
1395 if ((le_side < 1) || (ri_side > nx)) {
1396 cpl_msg_error(fctid, "Spectrum zone falls outside the image");
1397 return NULL;
1398 }
1399 /* Residual Sky position */
1400 if (le_dist < 0) le_dist = 2 * naco_spc_jitter_config.extr_spec_width;
1401 if (ri_dist < 0) ri_dist = 2 * naco_spc_jitter_config.extr_spec_width;
1402 sky_pos[1] = spec_pos - le_dist;
1403 sky_pos[0] = sky_pos[1] - le_width;
1404 sky_pos[2] = spec_pos + ri_dist;
1405 sky_pos[3] = sky_pos[2] + ri_width;
1406
1407 /* Get the sky */
1408 sky = cpl_vector_new(nx);
1409 psky = cpl_vector_get_data(sky);
1410 if (((sky_pos[0] < 1) || (le_width == 0)) &&
1411 ((sky_pos[3] <= nx) && (ri_width > 0))) {
1412 for (i=0 ; i<ny ; i++) {
1413 psky[i] = cpl_image_get_median_window(combined, sky_pos[2], i+1,
1414 sky_pos[3], i+1);
1415 }
1416 } else if (((sky_pos[3] > nx) || (ri_width == 0))
1417 && ((sky_pos[0] > 0) && (le_width > 0))) {
1418 for (i=0 ; i<ny ; i++) {
1419 psky[i] = cpl_image_get_median_window(combined, sky_pos[0], i+1,
1420 sky_pos[1], i+1);
1421 }
1422 } else if ((le_width != 0) && (ri_width != 0)
1423 && (sky_pos[0] > 0) && (sky_pos[3] <= nx)) {
1424 for (i=0 ; i<ny ; i++) {
1425 psky[i] = cpl_image_get_median_window(combined, sky_pos[2], i+1,
1426 sky_pos[3], i+1);
1427 psky[i] += cpl_image_get_median_window(combined, sky_pos[0], i+1,
1428 sky_pos[1], i+1);
1429 psky[i] /= 2.0;
1430 }
1431 } else {
1432 psky[i] = 0.0;
1433 }
1434
1435 /* Estimate the spectrum */
1436 spec = cpl_vector_new(ny);
1437 pspec = cpl_vector_get_data(spec);
1438 for (i=0 ; i<ny ; i++) {
1439 pspec[i] = cpl_image_get_flux_window(combined, le_side, i+1, ri_side,
1440 i+1);
1441 pspec[i] -= psky[i] * naco_spc_jitter_config.extr_spec_width;
1442 }
1443
1444 /* Get the wavelength */
1445 wl = cpl_vector_new(ny);
1446 pwl = cpl_vector_get_data(wl);
1447 for (i=0 ; i<ny ; i++) {
1448 pwl[i] = i+1;
1449 /*
1450 pwl[i] = naco_spc_jitter_config.wavecal_a0 +
1451 naco_spc_jitter_config.wavecal_a1 * (i+1) +
1452 naco_spc_jitter_config.wavecal_a2 * (i+1) * (i+1) +
1453 naco_spc_jitter_config.wavecal_a3 * (i+1) * (i+1) * (i+1);
1454 */
1455 }
1456
1457 /* Plot the spectrum if requested */
1458 if (naco_spc_jitter_config.display) {
1459 toplot = cpl_bivector_wrap_vectors(wl, spec);
1460 cpl_plot_bivector(NULL, "t 'Spectrum' w lines", NULL, toplot);
1461 cpl_bivector_unwrap_vectors(toplot);
1462 toplot = cpl_bivector_wrap_vectors(wl, sky);
1463 cpl_plot_bivector(NULL, "t 'Sky' w lines", NULL, toplot);
1464 cpl_bivector_unwrap_vectors(toplot);
1465 }
1466
1467 /* Create and fill the output table */
1468 out = cpl_table_new(nx);
1469 cpl_table_new_column(out, "Y_coordinate", CPL_TYPE_DOUBLE);
1470 cpl_table_new_column(out, "Extracted_spectrum_value", CPL_TYPE_DOUBLE);
1471 cpl_table_new_column(out, "Sky_spectrum", CPL_TYPE_DOUBLE);
1472 for (i=0 ; i<nx ; i++) {
1473 cpl_table_set_double(out, "Y_coordinate", i, pwl[i]);
1474 cpl_table_set_double(out, "Extracted_spectrum_value", i, pspec[i]);
1475 cpl_table_set_double(out, "Sky_spectrum", i, psky[i]);
1476 }
1477 cpl_vector_delete(wl);
1478 cpl_vector_delete(spec);
1479 cpl_vector_delete(sky);
1480 return out;
1481}
1482
1483/*----------------------------------------------------------------------------*/
1492/*----------------------------------------------------------------------------*/
1493static int naco_spc_jitter_save(
1494 const cpl_image * ima,
1495 const cpl_table * tab,
1496 cpl_parameterlist * parlist,
1497 cpl_frameset * set)
1498{
1499 const char * fctid = "naco_spc_jitter_save";
1500 char name_o[512];
1501 FILE * paf;
1502 cpl_propertylist * plist;
1503 cpl_propertylist * qclist;
1504 cpl_propertylist * paflist;
1505 cpl_frame * ref_frame;
1506 cpl_frame * product_frame;
1507 char qc_str[128];
1508 int i;
1509
1510 /* Get the reference frame */
1511 ref_frame = cpl_frameset_get_position(set, 0);
1512
1513 /********************/
1514 /* Write the image */
1515 /********************/
1516 /* Set the file name */
1517 sprintf(name_o, "naco_spc_jitter_combined.fits");
1518 cpl_msg_info(fctid, "Writing %s" , name_o);
1519
1520 /* Get FITS header from reference file */
1521 if ((plist=cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
1522 0)) == NULL) {
1523 cpl_msg_error(fctid, "getting header from reference frame");
1524 return -1;
1525 }
1526
1527 /* Get the keywords for the paf file */
1528 paflist = cpl_propertylist_new();
1529 cpl_propertylist_copy_property_regexp(paflist, plist,
1530 "^(ARCFILE|MJD-OBS|INSTRUME|ESO TPL ID|ESO TPL NEXP|ESO DPR CATG|"
1531 "ESO DPR TECH|ESO DPR TYPE|DATE-OBS|ESO INS GRAT NAME|"
1532 "ESO INS GRAT WLEN|ESO INS OPTI1 ID|ESO OBS ID|ESO OBS TARG NAME)$", 0);
1533
1534 /* Create product frame */
1535 product_frame = cpl_frame_new();
1536 cpl_frame_set_filename(product_frame, name_o);
1537 cpl_frame_set_tag(product_frame, NACO_SPC_JITTER_COMB);
1538 cpl_frame_set_type(product_frame, CPL_FRAME_TYPE_IMAGE);
1539 cpl_frame_set_group(product_frame, CPL_FRAME_GROUP_PRODUCT);
1540 cpl_frame_set_level(product_frame, CPL_FRAME_LEVEL_FINAL);
1541
1542 /* Add DataFlow keywords */
1543 if (cpl_dfs_setup_product_header(plist, product_frame, set, parlist,
1544 "naco_spc_jitter", PACKAGE "/" PACKAGE_VERSION,
1545 "PRO-1.15") != CPL_ERROR_NONE) {
1546 cpl_msg_warning(fctid, "Problem in the product DFS-compliance");
1547 cpl_error_reset();
1548 }
1549
1550 /* Add QC parameters */
1551 cpl_propertylist_append_double(plist, "ESO QC DISPCO1",
1552 naco_spc_jitter_config.wavecal_a0);
1553 cpl_propertylist_append_double(plist, "ESO QC DISPCO2",
1554 naco_spc_jitter_config.wavecal_a1);
1555 cpl_propertylist_append_double(plist, "ESO QC DISPCO3",
1556 naco_spc_jitter_config.wavecal_a2);
1557 cpl_propertylist_append_double(plist, "ESO QC DISPCO4",
1558 naco_spc_jitter_config.wavecal_a3);
1559 cpl_propertylist_append_double(plist, "ESO QC WLEN",
1560 naco_spc_jitter_config.wavecal_a0 +
1561 naco_spc_jitter_config.wavecal_a1 * 512 +
1562 naco_spc_jitter_config.wavecal_a2 * 512 * 512 +
1563 naco_spc_jitter_config.wavecal_a3 * 512 * 512 * 512);
1564 cpl_propertylist_append_double(plist, "ESO QC DISP XCORR",
1565 naco_spc_jitter_config.wavecal_cc);
1566 if (naco_spc_jitter_config.wavecal_out == 0) {
1567 cpl_propertylist_append_string(plist, "ESO QC WLMETHOD",
1568 "physical model");
1569 } else if (naco_spc_jitter_config.wavecal_out == 1) {
1570 cpl_propertylist_append_string(plist, "ESO QC WLMETHOD",
1571 "sky lines");
1572 } else if (naco_spc_jitter_config.wavecal_out == 2) {
1573 cpl_propertylist_append_string(plist, "ESO QC WLMETHOD",
1574 "arc file");
1575 }
1576
1577 /* Get the QC params in qclist and keys for paf in paflist */
1578 qclist = cpl_propertylist_new();
1579 cpl_propertylist_copy_property_regexp(qclist, plist, "ESO QC", 0);
1580
1581 /* Change WCS keywords to the computed wavelength solution */
1582 cpl_propertylist_update_double(plist, "CRVAL1",
1583 naco_spc_jitter_config.wavecal_a0);
1584 cpl_propertylist_update_double(plist, "CRVAL2", 1.0);
1585 cpl_propertylist_update_double(plist, "CRPIX1", 1.0);
1586 cpl_propertylist_update_double(plist, "CRPIX2", 1.0);
1587 cpl_propertylist_update_double(plist, "CDELT1",
1588 naco_spc_jitter_config.wavecal_a1);
1589 cpl_propertylist_update_double(plist, "CDELT2", 1.0);
1590 cpl_propertylist_update_string(plist, "CTYPE1", "LINEAR");
1591 cpl_propertylist_update_string(plist, "CTYPE2", "LINEAR");
1592 cpl_propertylist_insert_after_double(plist, "CTYPE2", "CD1_1",
1593 naco_spc_jitter_config.wavecal_a1);
1594 cpl_propertylist_insert_after_double(plist, "CD1_1", "CD1_2", 1.0);
1595
1596 /* Save the file */
1597 cpl_image_save(ima, name_o, CPL_BPP_DEFAULT, plist, CPL_IO_DEFAULT);
1598 cpl_propertylist_delete(plist);
1599
1600 /* Log the saved file in the input frameset */
1601 cpl_frameset_insert(set, product_frame);
1602
1603 if (tab != NULL) {
1604 /********************/
1605 /* Write the table */
1606 /********************/
1607 /* Set the file name */
1608 sprintf(name_o, "naco_spc_jitter_extracted.tfits");
1609 cpl_msg_info(fctid, "Writing %s" , name_o);
1610
1611 /* Get FITS header from reference file */
1612 if ((plist=cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
1613 0)) == NULL) {
1614 cpl_msg_error(fctid, "getting header from reference frame");
1615 cpl_propertylist_delete(paflist);
1616 cpl_propertylist_delete(qclist);
1617 return -1;
1618 }
1619
1620 /* Create product frame */
1621 product_frame = cpl_frame_new();
1622 cpl_frame_set_filename(product_frame, name_o);
1623 cpl_frame_set_tag(product_frame, NACO_SPC_JITTER_EXTR);
1624 cpl_frame_set_type(product_frame, CPL_FRAME_TYPE_TABLE);
1625 cpl_frame_set_group(product_frame, CPL_FRAME_GROUP_PRODUCT);
1626 cpl_frame_set_level(product_frame, CPL_FRAME_LEVEL_FINAL);
1627
1628 /* Add DataFlow keywords */
1629 if (cpl_dfs_setup_product_header(plist, product_frame, set, parlist,
1630 "naco_spc_jitter", PACKAGE "/" PACKAGE_VERSION,
1631 "PRO-1.15") != CPL_ERROR_NONE){
1632 cpl_msg_warning(fctid, "Problem in the product DFS-compliance");
1633 cpl_error_reset();
1634 }
1635
1636 /* Save the file */
1637 cpl_table_save(tab, plist, NULL, name_o, CPL_IO_DEFAULT);
1638 cpl_propertylist_delete(plist);
1639
1640 /* Log the saved file in the input frameset */
1641 cpl_frameset_insert(set, product_frame);
1642 }
1643
1644 /**********************************/
1645 /* THE PAF FILE FOR QC PARAMETERS */
1646 /**********************************/
1647
1648 /* Set the file name */
1649 sprintf(name_o, "naco_spc_jitter.paf");
1650 cpl_msg_info(fctid, "Writing %s" , name_o);
1651
1652 /* Create the default PAF header */
1653 if ((paf = irplib_paf_print_header(name_o,
1654 "NACO/naco_spc_jitter",
1655 "QC file")) == NULL) {
1656 cpl_msg_error(fctid, "cannot open file [%s] for output", name_o);
1657 cpl_propertylist_delete(paflist);
1658 cpl_propertylist_delete(qclist);
1659 return -1;
1660 }
1661
1662 /* Dump the keywords in PAF */
1663 if (irplib_propertylist_dump_paf(paflist, paf) != CPL_ERROR_NONE) {
1664 cpl_msg_error(fctid, "cannot dump the keys in PAF file");
1665 cpl_propertylist_delete(paflist);
1666 cpl_propertylist_delete(qclist);
1667 fclose(paf);
1668 return -1;
1669 }
1670 cpl_propertylist_delete(paflist);
1671
1672 /* Dump the QC keywords in PAF */
1673 if (irplib_propertylist_dump_paf(qclist, paf) != CPL_ERROR_NONE) {
1674 cpl_msg_error(fctid, "cannot dump the QC keys in PAF file");
1675 cpl_propertylist_delete(qclist);
1676 fclose(paf);
1677 return -1;
1678 }
1679 cpl_propertylist_delete(qclist);
1680 fclose(paf);
1681
1682 /* Return */
1683 return 0;
1684}
1685
1686/*----------------------------------------------------------------------------*/
1694/*----------------------------------------------------------------------------*/
1695static int off_comp(double off1, double off2, double thresh)
1696{
1697 if (((off1>thresh) && (off2<thresh)) || ((off1<thresh) && (off2>thresh)))
1698 return 1;
1699 else return 0;
1700}
int naco_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
Definition: naco_dfs.c:62
double naco_pfits_get_cumoffsetx(const cpl_propertylist *self)
find out the cumulative offset in X
Definition: naco_pfits.c:95
double * naco_get_disprel_estimate(const char *filename, int poly_deg)
Estimate the instrument wavelength range.
computed_disprel * naco_spectro_compute_disprel(const cpl_image *in, int discard_lo, int discard_hi, int discard_le, int discard_ri, int remove_thermal, const char *table_name, double slit_width, int order, int output_ascii, double *phdisprel)
Compute a 3rd degree dispersion relation.