NACO Pipeline Reference Manual  4.4.0
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 
66 static int naco_spc_jitter_create(cpl_plugin *);
67 static int naco_spc_jitter_exec(cpl_plugin *);
68 static int naco_spc_jitter_destroy(cpl_plugin *);
69 static int naco_spc_jitter(cpl_parameterlist *, cpl_frameset *);
70 static cpl_image ** naco_spc_jitter_combine(cpl_frameset *, char *, char *,
71  char *);
72 static cpl_vector * naco_spc_jitter_get_offsets(cpl_frameset *);
73 static int * naco_spc_jitter_classif(cpl_vector *, int *);
74 static int off_comp(double, double, double);
75 static cpl_imagelist * naco_spc_jitter_saa_groups(cpl_imagelist *,
76  cpl_vector *, int *, int, cpl_vector **);
77 static int naco_spc_jitter_wavecal(char *, cpl_image *, cpl_frameset *);
78 static cpl_imagelist * naco_spc_jitter_nodded(cpl_imagelist *, cpl_vector *,
79  cpl_vector **);
80 static cpl_imagelist * naco_spc_jitter_distor(cpl_imagelist *, char *);
81 static double naco_spc_jitter_refine_offset(cpl_image *, cpl_image *);
82 static cpl_table * naco_spc_jitter_extract(cpl_image *);
83 static int naco_spc_jitter_save(const cpl_image *, const cpl_table *,
84  cpl_parameterlist *, cpl_frameset *);
85 
86 /*-----------------------------------------------------------------------------
87  Static variables
88  -----------------------------------------------------------------------------*/
89 
90 static 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 
119 static 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 /*----------------------------------------------------------------------------*/
146 int 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 /*----------------------------------------------------------------------------*/
180 static 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 /*----------------------------------------------------------------------------*/
279 static 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 /*----------------------------------------------------------------------------*/
298 static 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 /*----------------------------------------------------------------------------*/
319 static 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_frame(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 /*----------------------------------------------------------------------------*/
516 static 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;
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  return NULL;
604  }
605  cpl_imagelist_delete(ilist);
606  cpl_free(groups);
607  cpl_vector_delete(offsets);
608  cpl_msg_indent_less();
609 
610  /* Compute the wavelength calibration */
611  /*
612  cpl_msg_info(fctid, "Compute the wavelength calibration");
613  cpl_msg_indent_more();
614  if (naco_spc_jitter_wavecal(arc_wl, cpl_imagelist_get(abba, 0),
615  rawframes) == -1) {
616  cpl_msg_error(fctid, "cannot compute the wavelength");
617  cpl_imagelist_delete(abba);
618  cpl_vector_delete(abba_off);
619  cpl_msg_indent_less();
620  return NULL;
621  }
622  cpl_msg_indent_less();
623  */
624 
625  /* Create the nodded images */
626  cpl_msg_info(fctid, "Create the nodded images");
627  cpl_msg_indent_more();
628  if ((nodded = naco_spc_jitter_nodded(abba, abba_off,
629  &nodded_off_x))==NULL) {
630  cpl_msg_error(fctid, "cannot create the nodded images");
631  cpl_imagelist_delete(abba);
632  cpl_vector_delete(abba_off);
633  cpl_msg_indent_less();
634  return NULL;
635  }
636  cpl_imagelist_delete(abba);
637  cpl_msg_indent_less();
638 
639  /* Get the throw offsets from abba_off */
640  nima = cpl_imagelist_get_size(nodded);
641  naco_spc_jitter_config.throws = cpl_vector_new(nima);
642  for (i=0 ; i<nima/2 ; i++) {
643  throw = fabs( (cpl_vector_get(abba_off, 2*i))-
644  (cpl_vector_get(abba_off, 2*i+1)));
645  cpl_vector_set(naco_spc_jitter_config.throws, 2*i, throw);
646  cpl_vector_set(naco_spc_jitter_config.throws, 2*i+1, throw);
647  }
648  cpl_vector_delete(abba_off);
649 
650  /* Distortion correction */
651  if (arc) {
652  cpl_msg_info(fctid, "Correct the distortion on nodded images");
653  cpl_msg_indent_more();
654  if ((nodded_warped = naco_spc_jitter_distor(nodded, arc)) == NULL) {
655  cpl_msg_error(fctid, "cannot correct the distortion");
656  cpl_imagelist_delete(nodded);
657  cpl_vector_delete(nodded_off_x);
658  cpl_msg_indent_less();
659  return NULL;
660  }
661  cpl_imagelist_delete(nodded);
662  nodded = nodded_warped;
663  cpl_msg_indent_less();
664  }
665 
666  /* Refine the offsets if requested */
667  if (naco_spc_jitter_config.saa_refine) {
668  cpl_msg_info(fctid, "Refine the offsets");
669  pnodded_off_x = cpl_vector_get_data(nodded_off_x);
670  for (i=0 ; i<cpl_imagelist_get_size(nodded) ; i++) {
671  new_offset = naco_spc_jitter_refine_offset(
672  cpl_imagelist_get(nodded, 0),
673  cpl_imagelist_get(nodded, i));
674  if (new_offset > 5000) {
675  cpl_msg_debug(fctid, "cannot refine the offset - keep %g",
676  pnodded_off_x[i]);
677  } else {
678  if (fabs(new_offset-pnodded_off_x[i]) <
679  NACO_SPC_JITTER_OFFSET_ERR) {
680  cpl_msg_debug(fctid, "refined offset : %g (old was %g)",
681  new_offset, pnodded_off_x[i]);
682  pnodded_off_x[i] = new_offset;
683  } else {
684  cpl_msg_debug(fctid,
685  "refined offset %g too different - keep %g",
686  new_offset, pnodded_off_x[i]);
687  }
688  }
689  }
690  }
691 
692  /* Images combination */
693  /* Get the offsets in a bivector */
694  nodded_off_y = cpl_vector_duplicate(nodded_off_x);
695  cpl_vector_fill(nodded_off_y, 0.0);
696  nodded_offsets = cpl_bivector_wrap_vectors(nodded_off_x, nodded_off_y);
697  /* Shift and add */
698  cpl_msg_info(fctid, "Apply the shift and add on the nodded frames");
699  nima = cpl_imagelist_get_size(nodded);
700  if ((combined = cpl_geom_img_offset_saa(nodded, nodded_offsets,
701  CPL_KERNEL_DEFAULT,
702  (int)(naco_spc_jitter_config.saa_rej_low * nima),
703  (int)(naco_spc_jitter_config.saa_rej_high * nima),
704  CPL_GEOM_FIRST, NULL, NULL)) == NULL) {
705  cpl_msg_error(fctid, "Cannot shift and add group");
706  cpl_imagelist_delete(nodded);
707  cpl_bivector_unwrap_vectors(nodded_offsets);
708  cpl_vector_delete(nodded_off_x);
709  cpl_vector_delete(nodded_off_y);
710  return NULL;
711  }
712  cpl_imagelist_delete(nodded);
713  cpl_bivector_unwrap_vectors(nodded_offsets);
714  cpl_vector_delete(nodded_off_x);
715  cpl_vector_delete(nodded_off_y);
716  return combined;
717 }
718 
719 /*----------------------------------------------------------------------------*/
725 /*----------------------------------------------------------------------------*/
726 static cpl_vector * naco_spc_jitter_get_offsets(cpl_frameset * rawframes)
727 {
728  const char * fctid = "naco_spc_jitter_get_offsets";
729  cpl_vector * offsets;
730  double * pvect;
731  int nraw;
732  cpl_frame * cur_frame;
733  cpl_propertylist * plist;
734  int i;
735 
736  /* Test entries */
737  if (rawframes == NULL) return NULL;
738 
739  /* Initialise */
740  nraw = cpl_frameset_get_size(rawframes);
741 
742  /* Get the rawframes X offsets */
743  offsets = cpl_vector_new(nraw);
744  pvect = cpl_vector_get_data(offsets);
745  for (i=0 ; i<nraw ; i++) {
746  cur_frame = cpl_frameset_get_frame(rawframes, i);
747  if ((plist=cpl_propertylist_load(cpl_frame_get_filename(cur_frame),
748  0)) == NULL) {
749  cpl_msg_error(fctid, "cannot get property list");
750  cpl_vector_delete(offsets);
751  return NULL;
752  }
753  pvect[i] = -1 * naco_pfits_get_cumoffsetx(plist);
754  if (cpl_error_get_code()) {
755  cpl_msg_error(fctid, "cannot get the offset from the header");
756  cpl_vector_delete(offsets);
757  cpl_propertylist_delete(plist);
758  return NULL;
759  }
760  cpl_propertylist_delete(plist);
761  }
762  return offsets;
763 }
764 
765 /*----------------------------------------------------------------------------*/
803 /*----------------------------------------------------------------------------*/
804 static int * naco_spc_jitter_classif(
805  cpl_vector * offsets,
806  int * ngroups)
807 {
808  const char * fctid = "naco_spc_jitter_classif";
809  double * pvect;
810  int nraw;
811  double offset_thresh;
812  cpl_vector * tmp_vec;
813  int * groups;
814  int last_group;
815  int i, j, k, l;
816 
817  /* Test entries */
818  if (offsets == NULL) return NULL;
819 
820  /* Initialise */
821  nraw = cpl_vector_get_size(offsets);
822 
823  /* Separate the offsets in 2 categories */
824  tmp_vec = cpl_vector_duplicate(offsets);
825  cpl_vector_sort(tmp_vec, 1);
826  pvect = cpl_vector_get_data(tmp_vec);
827  if (pvect[0] == pvect[nraw-1]) {
828  cpl_msg_error(fctid, "Only one offset in the list - abort");
829  cpl_vector_delete(tmp_vec);
830  return NULL;
831  }
832  offset_thresh = (pvect[0] + pvect[nraw-1]) / 2.0;
833  cpl_vector_delete(tmp_vec);
834 
835  /* Identify the different A and B groups */
836  pvect = cpl_vector_get_data(offsets);
837  *ngroups = 0;
838  groups = cpl_calloc(nraw, sizeof(int));
839 
840  /* Create a look up table to associate the ith obj with the jth frame */
841  i = 0;
842  while (i < nraw) {
843  j = 0;
844  /* Count the number of successive '+' or '-' (j) */
845  while ((i+j<nraw) &&
846  (!off_comp(pvect[i], pvect[i+j], offset_thresh))) j++;
847 
848  if (i+j >= nraw) i = nraw;
849  else {
850  k = 0;
851  /* Check if there are j '-' or '+' (k) */
852  while ((i+j+k < nraw)
853  && (!off_comp(pvect[i+j], pvect[i+j+k], offset_thresh))
854  && (k<j)) k++;
855  last_group = 1;
856  if (i+j+k < nraw) {
857  for (l=i+j+k ; l<nraw ; l++) {
858  if (off_comp(pvect[i+j], pvect[l], offset_thresh)) {
859  last_group = 0;
860  break;
861  }
862  }
863  }
864  if (last_group == 0) {
865  for (l=0 ; l<j ; l++) groups[i+l] = *ngroups + 1;
866  for (l=0 ; l<k ; l++) groups[i+j+l] = *ngroups + 2;
867  *ngroups += 2;
868  i += j+k;
869  } else {
870  for (l=0 ; l<j ; l++) groups[i+l] = *ngroups + 1;
871  for (l=0 ; l<nraw - (i+j) ; l++) groups[i+j+l] =*ngroups + 2;
872  *ngroups += 2;
873  i = nraw;
874  }
875  }
876  }
877 
878  /* Nb of groups found should be even */
879  if (*ngroups % 2) {
880  cpl_msg_error(fctid, "Odd number of groups found");
881  cpl_free(groups);
882  return NULL;
883  }
884 
885  return groups;
886 }
887 
888 /*----------------------------------------------------------------------------*/
919 /*----------------------------------------------------------------------------*/
920 static cpl_imagelist * naco_spc_jitter_saa_groups(
921  cpl_imagelist * ilist,
922  cpl_vector * offsets,
923  int * groups,
924  int ngroups,
925  cpl_vector ** abba_off)
926 {
927  const char * fctid = "naco_spc_jitter_saa_groups";
928  cpl_imagelist * abba;
929  cpl_imagelist * group_list;
930  cpl_image * tmp_ima;
931  cpl_image ** combined;
932  cpl_bivector * group_off;
933  double * pgroup_off;
934  double * poffsets;
935  double * pabba_off;
936  int nima;
937  int saa;
938  int i, j, k;
939 
940  /* Test entries */
941  if ((ilist == NULL) || (offsets == NULL) || (groups == NULL)) return NULL;
942 
943  /* Initialise */
944  nima = cpl_imagelist_get_size(ilist);
945  poffsets = cpl_vector_get_data(offsets);
946 
947  /* Create the output image list */
948  abba = cpl_imagelist_new();
949  *abba_off = cpl_vector_new(ngroups);
950  pabba_off = cpl_vector_get_data(*abba_off);
951 
952  /* Loop on the groups */
953  for (i=0 ; i<ngroups ; i++) {
954  /* Initialise */
955  saa = 0;
956  /* Create the group list of images */
957  group_list = cpl_imagelist_new();
958  k = 0;
959  for (j=0 ; j<nima ; j++) {
960  if (i+1 == groups[j]) {
961  /* Get the first offset of the group in abba_off */
962  if (k==0) pabba_off[i] = poffsets[j];
963  /* To know if we need the saa (shift and add) */
964  if (fabs(pabba_off[i]-poffsets[j]) > 1e-3) saa = 1;
965  /* Copy the images of the group in group_list */
966  tmp_ima = cpl_image_duplicate(cpl_imagelist_get(ilist, j));
967  cpl_imagelist_set(group_list, tmp_ima, k);
968  tmp_ima = NULL;
969  k++;
970  }
971  }
972 
973  if (saa) {
974  /* Get the offsets of the group in group_off */
975  group_off = cpl_bivector_new(k);
976  cpl_vector_fill(cpl_bivector_get_y(group_off), 0.0);
977  pgroup_off = cpl_bivector_get_x_data(group_off);
978  k = 0;
979  for (j=0 ; j<nima ; j++) {
980  if (i+1 == groups[j]) {
981  pgroup_off[k] = poffsets[j];
982  k++;
983  }
984  }
985  cpl_vector_subtract_scalar(cpl_bivector_get_x(group_off),
986  pabba_off[i]);
987  /* Shift and add */
988  cpl_msg_debug(fctid, "Apply shift-and-add for group %d", i+1);
989  if ((combined = cpl_geom_img_offset_saa(group_list,
990  group_off, CPL_KERNEL_DEFAULT, 0, 0,
991  CPL_GEOM_FIRST)) == NULL) {
992  cpl_msg_error(fctid, "Cannot shift and add group nb %d", i+1);
993  cpl_imagelist_delete(group_list);
994  cpl_bivector_delete(group_off);
995  cpl_imagelist_delete(abba);
996  cpl_vector_delete(*abba_off);
997  return NULL;
998  }
999  cpl_bivector_delete(group_off);
1000  cpl_image_delete(combined[1]);
1001  cpl_imagelist_set(abba, combined[0], i);
1002  cpl_free(combined);
1003  } else {
1004  /* Averaging */
1005  cpl_msg_debug(fctid, "Apply averaging for group %d", i+1);
1006  if ((tmp_ima = cpl_imagelist_collapse_create(group_list)) == NULL) {
1007  cpl_msg_error(fctid, "Cannot average group nb %d", i+1);
1008  cpl_imagelist_delete(group_list);
1009  cpl_imagelist_delete(abba);
1010  cpl_vector_delete(*abba_off);
1011  return NULL;
1012  }
1013  cpl_imagelist_set(abba, tmp_ima, i);
1014  }
1015  cpl_imagelist_delete(group_list);
1016  }
1017  return abba;
1018 }
1019 
1020 /*----------------------------------------------------------------------------*/
1028 /*----------------------------------------------------------------------------*/
1029 static int naco_spc_jitter_wavecal(
1030  char * arc,
1031  cpl_image * ima,
1032  cpl_frameset * raw)
1033 {
1034  const char * fctid = "naco_spc_jitter_wavecal";
1035  cpl_table * arc_tab;
1036  double * phdisprel;
1037  cpl_frame * cur_frame;
1038  const char * cur_fname;
1039  computed_disprel * disprel;
1040  int order;
1041  double slit_width;
1042 
1043  /* Get the wavelength from the arc file */
1044  if (arc) {
1045  cpl_msg_info(fctid, "Get the wavelength from the ARC file");
1046  if ((arc_tab = cpl_table_load(arc, 1, 0)) == NULL) {
1047  cpl_msg_error(fctid, "Cannot load the arc table");
1048  naco_spc_jitter_config.wavecal_out = -1;
1049  return -1;
1050  }
1051  naco_spc_jitter_config.wavecal_a0 =
1052  cpl_table_get_double(arc_tab, "WL_coefficients", 0, NULL);
1053  naco_spc_jitter_config.wavecal_a1 =
1054  cpl_table_get_double(arc_tab, "WL_coefficients", 1, NULL);
1055  naco_spc_jitter_config.wavecal_a2 =
1056  cpl_table_get_double(arc_tab, "WL_coefficients", 2, NULL);
1057  naco_spc_jitter_config.wavecal_a3 =
1058  cpl_table_get_double(arc_tab, "WL_coefficients", 3, NULL);
1059  cpl_table_delete(arc_tab);
1060  naco_spc_jitter_config.wavecal_out = 2;
1061  naco_spc_jitter_config.wavecal_cc = -1.0;
1062  return 0;
1063  }
1064 
1065  /* Get the reference frame */
1066  cur_frame = cpl_frameset_get_frame(raw, 0);
1067  cur_fname = cpl_frame_get_filename(cur_frame);
1068 
1069  /* Get the physical model */
1070  cpl_msg_info(fctid, "Compute the physical model");
1071  cpl_msg_indent_more();
1072  if ((phdisprel = naco_get_disprel_estimate(cur_fname, 3)) == NULL) {
1073  cpl_msg_error(fctid, "cannot compute the physical model");
1074  naco_spc_jitter_config.wavecal_out = -1;
1075  cpl_msg_indent_less();
1076  return -1;
1077  }
1078  cpl_msg_info(fctid, "f(x)=%g + %g*x + %g*x^2 + %g*x^3",
1079  phdisprel[0], phdisprel[1], phdisprel[2], phdisprel[3]);
1080  naco_spc_jitter_config.wavecal_a0 = phdisprel[0];
1081  naco_spc_jitter_config.wavecal_a1 = phdisprel[1];
1082  naco_spc_jitter_config.wavecal_a2 = phdisprel[2];
1083  naco_spc_jitter_config.wavecal_a3 = phdisprel[3];
1084  naco_spc_jitter_config.wavecal_cc = -1.0;
1085  naco_spc_jitter_config.wavecal_out = 0;
1086  cpl_msg_indent_less();
1087 
1088  /* Compute the wavelength using the sky lines */
1089  if (naco_spc_jitter_config.wavecal_in == 1) {
1090  /* Compute the slit_width */
1091  if ((slit_width = naco_get_slitwidth(cur_fname)) == -1) {
1092  cpl_msg_warning(fctid, "cannot get the slit width");
1093  cpl_free(phdisprel);
1094  return 0;
1095  }
1096  /* Get the order */
1097  if ((order = naco_find_order(cur_fname)) == -1) {
1098  cpl_msg_warning(fctid, "cannot get the order");
1099  cpl_free(phdisprel);
1100  return 0;
1101  }
1102  /* Compute the wavelength */
1103  cpl_msg_info(fctid, "Compute the wavelength with the sky lines");
1104  cpl_msg_indent_more();
1105  if ((disprel = naco_spectro_compute_disprel(ima,
1106  naco_spc_jitter_config.wavecal_rej_bottom,
1107  naco_spc_jitter_config.wavecal_rej_top,
1108  naco_spc_jitter_config.wavecal_rej_left,
1109  naco_spc_jitter_config.wavecal_rej_right,
1110  naco_has_thermal(cur_fname) > 0,
1111  "oh", slit_width, order,
1112  (int)(cpl_msg_get_level() == CPL_MSG_DEBUG),
1113  phdisprel)) == NULL) {
1114  cpl_msg_error(fctid, "cannot compute the dispersion relation");
1115  cpl_free(phdisprel);
1116  cpl_msg_indent_less();
1117  return 0;
1118  }
1119  cpl_msg_info(fctid, "Cross correlation factor: %g", disprel->cc);
1120  cpl_msg_info(fctid, "f(x)=%g + %g*x + %g*x^2 + %g*x^3",
1121  disprel->poly[0], disprel->poly[1], disprel->poly[2],
1122  disprel->poly[3]);
1123  naco_spc_jitter_config.wavecal_a0 = disprel->poly[0];
1124  naco_spc_jitter_config.wavecal_a1 = disprel->poly[1];
1125  naco_spc_jitter_config.wavecal_a2 = disprel->poly[2];
1126  naco_spc_jitter_config.wavecal_a3 = disprel->poly[3];
1127  naco_spc_jitter_config.wavecal_cc = disprel->cc;
1128  naco_spc_jitter_config.wavecal_out = 1;
1129  if (disprel->poly != NULL) cpl_free(disprel->poly);
1130  cpl_free(disprel);
1131  cpl_msg_indent_less();
1132  }
1133  cpl_free(phdisprel);
1134  return 0;
1135 }
1136 
1137 /*----------------------------------------------------------------------------*/
1169 /*----------------------------------------------------------------------------*/
1170 static cpl_imagelist * naco_spc_jitter_nodded(
1171  cpl_imagelist * abba,
1172  cpl_vector * abba_off,
1173  cpl_vector ** nodded_off)
1174 {
1175  const char * fctid = "naco_spc_jitter_nodded";
1176  cpl_imagelist * nodded;
1177  cpl_image * tmp_ima;
1178  int nima;
1179  double * pabba_off;
1180  double * pnodded_off;
1181  double ref_off;
1182  int i;
1183 
1184  /* Test entries */
1185  if ((abba == NULL) || (abba_off == NULL)) return NULL;
1186 
1187  /* Initialise */
1188  nima = cpl_imagelist_get_size(abba);
1189  if (nima % 2) {
1190  cpl_msg_error(fctid, "Number of images should be even");
1191  return NULL;
1192  }
1193 
1194  /* Create the offsets between the nodded images */
1195  *nodded_off = cpl_vector_duplicate(abba_off);
1196  /* The image list to contain the nodded images */
1197  nodded = cpl_imagelist_new();
1198  for (i=0 ; i<(nima/2) ; i++) {
1199  /* a-b */
1200  tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i));
1201  cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i+1));
1202  cpl_imagelist_set(nodded, tmp_ima, 2*i);
1203  /* b-a */
1204  tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i+1));
1205  cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i));
1206  cpl_imagelist_set(nodded, tmp_ima, 2*i+1);
1207  }
1208 
1209  /* Subtract the first offset to the others */
1210  ref_off = cpl_vector_get(*nodded_off, 0);
1211  cpl_vector_subtract_scalar(*nodded_off, ref_off);
1212  return nodded;
1213 }
1214 
1215 /*----------------------------------------------------------------------------*/
1222 /*----------------------------------------------------------------------------*/
1223 static cpl_imagelist * naco_spc_jitter_distor(
1224  cpl_imagelist * ilist,
1225  char * arc)
1226 {
1227  const char * fctid = "naco_spc_jitter_distor";
1228  cpl_polynomial * arc_poly;
1229  cpl_polynomial * sttr_poly;
1230  cpl_table * tab;
1231  int pow[2];
1232  cpl_vector * profile;
1233  cpl_imagelist * warped_list;
1234  cpl_image * warped;
1235  int i;
1236 
1237  /* Test entries */
1238  if (ilist == NULL) return NULL;
1239  if (arc == NULL) return NULL;
1240 
1241  /* Get the arc polynomial */
1242  arc_poly = cpl_polynomial_new(2);
1243  if (arc != NULL) {
1244  cpl_msg_info(fctid, "Get the arc distortion from the file");
1245  if ((tab = cpl_table_load(arc, 1, 0)) == NULL) {
1246  cpl_msg_error(fctid, "cannot load the arc table");
1247  cpl_polynomial_delete(arc_poly);
1248  return NULL;
1249  }
1250  for (i=0 ; i<cpl_table_get_nrow(tab) ; i++) {
1251  pow[0] = cpl_table_get_int(tab, "Degree_of_x", i, NULL);
1252  pow[1] = cpl_table_get_int(tab, "Degree_of_y", i, NULL);
1253  cpl_polynomial_set_coeff(arc_poly, pow,
1254  cpl_table_get_double(tab, "poly2d_coef", i, NULL));
1255  }
1256  cpl_table_delete(tab);
1257  } else {
1258  cpl_msg_info(fctid, "Use the ID polynomial for the arc dist");
1259  pow[0] = 1;
1260  pow[1] = 0;
1261  cpl_polynomial_set_coeff(arc_poly, pow, 1.0);
1262  }
1263 
1264  /* Get the startrace polynomial */
1265  sttr_poly = cpl_polynomial_new(2);
1266  cpl_msg_info(fctid, "Use the ID polynomial for the startrace dist");
1267  pow[0] = 0;
1268  pow[1] = 1;
1269  cpl_polynomial_set_coeff(sttr_poly, pow, 1.0);
1270 
1271  /* Create the kernel */
1272  profile = cpl_vector_new(CPL_KERNEL_DEF_SAMPLES);
1273  cpl_vector_fill_kernel_profile(profile, CPL_KERNEL_DEFAULT,
1274  CPL_KERNEL_DEF_WIDTH);
1275 
1276  /* Correct the images */
1277  warped_list = cpl_imagelist_new();
1278  for (i=0 ; i<cpl_imagelist_get_size(ilist) ; i++) {
1279  warped = cpl_image_duplicate(cpl_imagelist_get(ilist, i));
1280  if (cpl_image_warp_polynomial(warped, cpl_imagelist_get(ilist, i),
1281  arc_poly, sttr_poly, profile, CPL_KERNEL_DEF_WIDTH, profile,
1282  CPL_KERNEL_DEF_WIDTH) != CPL_ERROR_NONE) {
1283  cpl_msg_error(fctid, "cannot correct the distortion");
1284  cpl_image_delete(warped);
1285  cpl_polynomial_delete(arc_poly);
1286  cpl_polynomial_delete(sttr_poly);
1287  cpl_vector_delete(profile);
1288  return NULL;
1289  }
1290  cpl_imagelist_set(warped_list, warped, i);
1291  }
1292  cpl_vector_delete(profile);
1293  cpl_polynomial_delete(arc_poly);
1294  cpl_polynomial_delete(sttr_poly);
1295  return warped_list;
1296 }
1297 
1298 /*----------------------------------------------------------------------------*/
1305 /*----------------------------------------------------------------------------*/
1306 static double naco_spc_jitter_refine_offset(
1307  cpl_image * ima1,
1308  cpl_image * ima2)
1309 {
1310  double pos1, pos2;
1311 
1312  /* Test entries */
1313  if (ima1 == NULL) return 10000.0;
1314  if (ima2 == NULL) return 10000.0;
1315 
1316  /* Detect the spectra */
1317  if (irplib_spectrum_find_brightest(ima1, 0.0, NO_SHADOW, 0.0, 1,
1318  &pos1) == -1){
1319  return 10000.0;
1320  }
1321  if (irplib_spectrum_find_brightest(ima2, 0.0, NO_SHADOW, 0.0, 1,
1322  &pos2) == -1){
1323  return 10000.0;
1324  }
1325  return pos1-pos2;
1326 }
1327 
1328 /*----------------------------------------------------------------------------*/
1334 /*----------------------------------------------------------------------------*/
1335 static cpl_table * naco_spc_jitter_extract(cpl_image * combined)
1336 {
1337  const char * fctid = "naco_spc_jitter_extract";
1338  int le_dist, ri_dist, le_width, ri_width, spec_pos;
1339  int nx, ny;
1340  double pos;
1341  int le_side, ri_side;
1342  int sky_pos[4];
1343  cpl_vector * sky;
1344  cpl_vector * spec;
1345  cpl_vector * wl;
1346  double * pspec;
1347  double * psky;
1348  double * pwl;
1349  cpl_table * out;
1350  cpl_bivector * toplot;
1351  int throw;
1352  int res;
1353  int i;
1354 
1355  /* Test entries */
1356  if (combined == NULL) return NULL;
1357 
1358  /* Initialise */
1359  nx = cpl_image_get_size_x(combined);
1360  ny = cpl_image_get_size_y(combined);
1361  le_dist = naco_spc_jitter_config.extr_sky_le_dist;
1362  ri_dist = naco_spc_jitter_config.extr_sky_ri_dist;
1363  le_width = naco_spc_jitter_config.extr_sky_le_width;
1364  ri_width = naco_spc_jitter_config.extr_sky_ri_width;
1365  spec_pos = naco_spc_jitter_config.extr_spec_pos;
1366 
1367  /* Detect the spectrum position if not passed */
1368  if (spec_pos < 0) {
1369  if (naco_spc_jitter_config.throws == NULL) {
1370  cpl_msg_error(fctid, "Need a throw value to detect the spectra !!");
1371  return NULL;
1372  }
1373 
1374  for (i=0 ; i<cpl_vector_get_size(naco_spc_jitter_config.throws) ; i++){
1375  throw = (int)cpl_vector_get(naco_spc_jitter_config.throws, i);
1376  if ((res = irplib_spectrum_find_brightest(combined, throw,
1377  TWO_SHADOWS, 0.0, 1, &pos)) == 0) break;
1378  if ((res = irplib_spectrum_find_brightest(combined, throw,
1379  ONE_SHADOW, 0.0, 1, &pos)) == 0) break;
1380  }
1381  if (res != 0) {
1382  cpl_msg_error(fctid, "Cannot detect the spectrum");
1383  return NULL;
1384  }
1385  spec_pos = (int)pos;
1386  cpl_msg_info(fctid, "Spectrum detected at x = %d", spec_pos);
1387  }
1388 
1389  /* Set the parameters for the extraction */
1390 
1391  /* Spectrum position */
1392  le_side = spec_pos - (int)(naco_spc_jitter_config.extr_spec_width/2);
1393  ri_side = le_side + naco_spc_jitter_config.extr_spec_width;
1394  if ((le_side < 1) || (ri_side > nx)) {
1395  cpl_msg_error(fctid, "Spectrum zone falls outside the image");
1396  return NULL;
1397  }
1398  /* Residual Sky position */
1399  if (le_dist < 0) le_dist = 2 * naco_spc_jitter_config.extr_spec_width;
1400  if (ri_dist < 0) ri_dist = 2 * naco_spc_jitter_config.extr_spec_width;
1401  sky_pos[1] = spec_pos - le_dist;
1402  sky_pos[0] = sky_pos[1] - le_width;
1403  sky_pos[2] = spec_pos + ri_dist;
1404  sky_pos[3] = sky_pos[2] + ri_width;
1405 
1406  /* Get the sky */
1407  sky = cpl_vector_new(nx);
1408  psky = cpl_vector_get_data(sky);
1409  if (((sky_pos[0] < 1) || (le_width == 0)) &&
1410  ((sky_pos[3] <= nx) && (ri_width > 0))) {
1411  for (i=0 ; i<ny ; i++) {
1412  psky[i] = cpl_image_get_median_window(combined, sky_pos[2], i+1,
1413  sky_pos[3], i+1);
1414  }
1415  } else if (((sky_pos[3] > nx) || (ri_width == 0))
1416  && ((sky_pos[0] > 0) && (le_width > 0))) {
1417  for (i=0 ; i<ny ; i++) {
1418  psky[i] = cpl_image_get_median_window(combined, sky_pos[0], i+1,
1419  sky_pos[1], i+1);
1420  }
1421  } else if ((le_width != 0) && (ri_width != 0)
1422  && (sky_pos[0] > 0) && (sky_pos[3] <= nx)) {
1423  for (i=0 ; i<ny ; i++) {
1424  psky[i] = cpl_image_get_median_window(combined, sky_pos[2], i+1,
1425  sky_pos[3], i+1);
1426  psky[i] += cpl_image_get_median_window(combined, sky_pos[0], i+1,
1427  sky_pos[1], i+1);
1428  psky[i] /= 2.0;
1429  }
1430  } else {
1431  psky[i] = 0.0;
1432  }
1433 
1434  /* Estimate the spectrum */
1435  spec = cpl_vector_new(ny);
1436  pspec = cpl_vector_get_data(spec);
1437  for (i=0 ; i<ny ; i++) {
1438  pspec[i] = cpl_image_get_flux_window(combined, le_side, i+1, ri_side,
1439  i+1);
1440  pspec[i] -= psky[i] * naco_spc_jitter_config.extr_spec_width;
1441  }
1442 
1443  /* Get the wavelength */
1444  wl = cpl_vector_new(ny);
1445  pwl = cpl_vector_get_data(wl);
1446  for (i=0 ; i<ny ; i++) {
1447  pwl[i] = i+1;
1448  /*
1449  pwl[i] = naco_spc_jitter_config.wavecal_a0 +
1450  naco_spc_jitter_config.wavecal_a1 * (i+1) +
1451  naco_spc_jitter_config.wavecal_a2 * (i+1) * (i+1) +
1452  naco_spc_jitter_config.wavecal_a3 * (i+1) * (i+1) * (i+1);
1453  */
1454  }
1455 
1456  /* Plot the spectrum if requested */
1457  if (naco_spc_jitter_config.display) {
1458  toplot = cpl_bivector_wrap_vectors(wl, spec);
1459  cpl_plot_bivector(NULL, "t 'Spectrum' w lines", NULL, toplot);
1460  cpl_bivector_unwrap_vectors(toplot);
1461  toplot = cpl_bivector_wrap_vectors(wl, sky);
1462  cpl_plot_bivector(NULL, "t 'Sky' w lines", NULL, toplot);
1463  cpl_bivector_unwrap_vectors(toplot);
1464  }
1465 
1466  /* Create and fill the output table */
1467  out = cpl_table_new(nx);
1468  cpl_table_new_column(out, "Y_coordinate", CPL_TYPE_DOUBLE);
1469  cpl_table_new_column(out, "Extracted_spectrum_value", CPL_TYPE_DOUBLE);
1470  cpl_table_new_column(out, "Sky_spectrum", CPL_TYPE_DOUBLE);
1471  for (i=0 ; i<nx ; i++) {
1472  cpl_table_set_double(out, "Y_coordinate", i, pwl[i]);
1473  cpl_table_set_double(out, "Extracted_spectrum_value", i, pspec[i]);
1474  cpl_table_set_double(out, "Sky_spectrum", i, psky[i]);
1475  }
1476  cpl_vector_delete(wl);
1477  cpl_vector_delete(spec);
1478  cpl_vector_delete(sky);
1479  return out;
1480 }
1481 
1482 /*----------------------------------------------------------------------------*/
1491 /*----------------------------------------------------------------------------*/
1492 static int naco_spc_jitter_save(
1493  const cpl_image * ima,
1494  const cpl_table * tab,
1495  cpl_parameterlist * parlist,
1496  cpl_frameset * set)
1497 {
1498  const char * fctid = "naco_spc_jitter_save";
1499  char name_o[512];
1500  FILE * paf;
1501  cpl_propertylist * plist;
1502  cpl_propertylist * qclist;
1503  cpl_propertylist * paflist;
1504  cpl_frame * ref_frame;
1505  cpl_frame * product_frame;
1506  char qc_str[128];
1507  int i;
1508 
1509  /* Get the reference frame */
1510  ref_frame = cpl_frameset_get_frame(set, 0);
1511 
1512  /********************/
1513  /* Write the image */
1514  /********************/
1515  /* Set the file name */
1516  sprintf(name_o, "naco_spc_jitter_combined.fits");
1517  cpl_msg_info(fctid, "Writing %s" , name_o);
1518 
1519  /* Get FITS header from reference file */
1520  if ((plist=cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
1521  0)) == NULL) {
1522  cpl_msg_error(fctid, "getting header from reference frame");
1523  return -1;
1524  }
1525 
1526  /* Get the keywords for the paf file */
1527  paflist = cpl_propertylist_new();
1528  cpl_propertylist_copy_property_regexp(paflist, plist,
1529  "^(ARCFILE|MJD-OBS|INSTRUME|ESO TPL ID|ESO TPL NEXP|ESO DPR CATG|"
1530  "ESO DPR TECH|ESO DPR TYPE|DATE-OBS|ESO INS GRAT NAME|"
1531  "ESO INS GRAT WLEN|ESO INS OPTI1 ID|ESO OBS ID|ESO OBS TARG NAME)$", 0);
1532 
1533  /* Create product frame */
1534  product_frame = cpl_frame_new();
1535  cpl_frame_set_filename(product_frame, name_o);
1536  cpl_frame_set_tag(product_frame, NACO_SPC_JITTER_COMB);
1537  cpl_frame_set_type(product_frame, CPL_FRAME_TYPE_IMAGE);
1538  cpl_frame_set_group(product_frame, CPL_FRAME_GROUP_PRODUCT);
1539  cpl_frame_set_level(product_frame, CPL_FRAME_LEVEL_FINAL);
1540 
1541  /* Add DataFlow keywords */
1542  if (cpl_dfs_setup_product_header(plist, product_frame, set, parlist,
1543  "naco_spc_jitter", PACKAGE "/" PACKAGE_VERSION,
1544  "PRO-1.15") != CPL_ERROR_NONE) {
1545  cpl_msg_warning(fctid, "Problem in the product DFS-compliance");
1546  cpl_error_reset();
1547  }
1548 
1549  /* Add QC parameters */
1550  cpl_propertylist_append_double(plist, "ESO QC DISPCO1",
1551  naco_spc_jitter_config.wavecal_a0);
1552  cpl_propertylist_append_double(plist, "ESO QC DISPCO2",
1553  naco_spc_jitter_config.wavecal_a1);
1554  cpl_propertylist_append_double(plist, "ESO QC DISPCO3",
1555  naco_spc_jitter_config.wavecal_a2);
1556  cpl_propertylist_append_double(plist, "ESO QC DISPCO4",
1557  naco_spc_jitter_config.wavecal_a3);
1558  cpl_propertylist_append_double(plist, "ESO QC WLEN",
1559  naco_spc_jitter_config.wavecal_a0 +
1560  naco_spc_jitter_config.wavecal_a1 * 512 +
1561  naco_spc_jitter_config.wavecal_a2 * 512 * 512 +
1562  naco_spc_jitter_config.wavecal_a3 * 512 * 512 * 512);
1563  cpl_propertylist_append_double(plist, "ESO QC DISP XCORR",
1564  naco_spc_jitter_config.wavecal_cc);
1565  if (naco_spc_jitter_config.wavecal_out == 0) {
1566  cpl_propertylist_append_string(plist, "ESO QC WLMETHOD",
1567  "physical model");
1568  } else if (naco_spc_jitter_config.wavecal_out == 1) {
1569  cpl_propertylist_append_string(plist, "ESO QC WLMETHOD",
1570  "sky lines");
1571  } else if (naco_spc_jitter_config.wavecal_out == 2) {
1572  cpl_propertylist_append_string(plist, "ESO QC WLMETHOD",
1573  "arc file");
1574  }
1575 
1576  /* Get the QC params in qclist and keys for paf in paflist */
1577  qclist = cpl_propertylist_new();
1578  cpl_propertylist_copy_property_regexp(qclist, plist, "ESO QC", 0);
1579 
1580  /* Change WCS keywords to the computed wavelength solution */
1581  cpl_propertylist_update_double(plist, "CRVAL1",
1582  naco_spc_jitter_config.wavecal_a0);
1583  cpl_propertylist_update_double(plist, "CRVAL2", 1.0);
1584  cpl_propertylist_update_double(plist, "CRPIX1", 1.0);
1585  cpl_propertylist_update_double(plist, "CRPIX2", 1.0);
1586  cpl_propertylist_update_double(plist, "CDELT1",
1587  naco_spc_jitter_config.wavecal_a1);
1588  cpl_propertylist_update_double(plist, "CDELT2", 1.0);
1589  cpl_propertylist_update_string(plist, "CTYPE1", "LINEAR");
1590  cpl_propertylist_update_string(plist, "CTYPE2", "LINEAR");
1591  cpl_propertylist_insert_after_double(plist, "CTYPE2", "CD1_1",
1592  naco_spc_jitter_config.wavecal_a1);
1593  cpl_propertylist_insert_after_double(plist, "CD1_1", "CD1_2", 1.0);
1594 
1595  /* Save the file */
1596  cpl_image_save(ima, name_o, CPL_BPP_DEFAULT, plist, CPL_IO_DEFAULT);
1597  cpl_propertylist_delete(plist);
1598 
1599  /* Log the saved file in the input frameset */
1600  cpl_frameset_insert(set, product_frame);
1601 
1602  if (tab != NULL) {
1603  /********************/
1604  /* Write the table */
1605  /********************/
1606  /* Set the file name */
1607  sprintf(name_o, "naco_spc_jitter_extracted.tfits");
1608  cpl_msg_info(fctid, "Writing %s" , name_o);
1609 
1610  /* Get FITS header from reference file */
1611  if ((plist=cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
1612  0)) == NULL) {
1613  cpl_msg_error(fctid, "getting header from reference frame");
1614  cpl_propertylist_delete(paflist);
1615  cpl_propertylist_delete(qclist);
1616  return -1;
1617  }
1618 
1619  /* Create product frame */
1620  product_frame = cpl_frame_new();
1621  cpl_frame_set_filename(product_frame, name_o);
1622  cpl_frame_set_tag(product_frame, NACO_SPC_JITTER_EXTR);
1623  cpl_frame_set_type(product_frame, CPL_FRAME_TYPE_TABLE);
1624  cpl_frame_set_group(product_frame, CPL_FRAME_GROUP_PRODUCT);
1625  cpl_frame_set_level(product_frame, CPL_FRAME_LEVEL_FINAL);
1626 
1627  /* Add DataFlow keywords */
1628  if (cpl_dfs_setup_product_header(plist, product_frame, set, parlist,
1629  "naco_spc_jitter", PACKAGE "/" PACKAGE_VERSION,
1630  "PRO-1.15") != CPL_ERROR_NONE){
1631  cpl_msg_warning(fctid, "Problem in the product DFS-compliance");
1632  cpl_error_reset();
1633  }
1634 
1635  /* Save the file */
1636  cpl_table_save(tab, plist, NULL, name_o, CPL_IO_DEFAULT);
1637  cpl_propertylist_delete(plist);
1638 
1639  /* Log the saved file in the input frameset */
1640  cpl_frameset_insert(set, product_frame);
1641  }
1642 
1643  /**********************************/
1644  /* THE PAF FILE FOR QC PARAMETERS */
1645  /**********************************/
1646 
1647  /* Set the file name */
1648  sprintf(name_o, "naco_spc_jitter.paf");
1649  cpl_msg_info(fctid, "Writing %s" , name_o);
1650 
1651  /* Create the default PAF header */
1652  if ((paf = irplib_paf_print_header(name_o,
1653  "NACO/naco_spc_jitter",
1654  "QC file")) == NULL) {
1655  cpl_msg_error(fctid, "cannot open file [%s] for output", name_o);
1656  cpl_propertylist_delete(paflist);
1657  cpl_propertylist_delete(qclist);
1658  return -1;
1659  }
1660 
1661  /* Dump the keywords in PAF */
1662  if (irplib_propertylist_dump_paf(paflist, paf) != CPL_ERROR_NONE) {
1663  cpl_msg_error(fctid, "cannot dump the keys in PAF file");
1664  cpl_propertylist_delete(paflist);
1665  cpl_propertylist_delete(qclist);
1666  fclose(paf);
1667  return -1;
1668  }
1669  cpl_propertylist_delete(paflist);
1670 
1671  /* Dump the QC keywords in PAF */
1672  if (irplib_propertylist_dump_paf(qclist, paf) != CPL_ERROR_NONE) {
1673  cpl_msg_error(fctid, "cannot dump the QC keys in PAF file");
1674  cpl_propertylist_delete(qclist);
1675  fclose(paf);
1676  return -1;
1677  }
1678  cpl_propertylist_delete(qclist);
1679  fclose(paf);
1680 
1681  /* Return */
1682  return 0;
1683 }
1684 
1685 /*----------------------------------------------------------------------------*/
1693 /*----------------------------------------------------------------------------*/
1694 static int off_comp(double off1, double off2, double thresh)
1695 {
1696  if (((off1>thresh) && (off2<thresh)) || ((off1<thresh) && (off2>thresh)))
1697  return 1;
1698  else return 0;
1699 }
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
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.
int irplib_spectrum_find_brightest(const cpl_image *in, int offset, spec_shadows shadows, double min_bright, int orient, double *pos)
Finds the brightest spectrum in an image.
int irplib_compare_tags(cpl_frame *frame1, cpl_frame *frame2)
Comparison function to identify different input frames.
double * naco_get_disprel_estimate(const char *filename, int poly_deg)
Estimate the instrument wavelength range.