IIINSTRUMENT Pipeline Reference Manual  4.4.10
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_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 /*----------------------------------------------------------------------------*/
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 = 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 /*----------------------------------------------------------------------------*/
727 static 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 /*----------------------------------------------------------------------------*/
805 static 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 /*----------------------------------------------------------------------------*/
921 static 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 /*----------------------------------------------------------------------------*/
1030 static 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 /*----------------------------------------------------------------------------*/
1171 static 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 /*----------------------------------------------------------------------------*/
1224 static 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 /*----------------------------------------------------------------------------*/
1307 static 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 /*----------------------------------------------------------------------------*/
1336 static 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 /*----------------------------------------------------------------------------*/
1493 static 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 /*----------------------------------------------------------------------------*/
1695 static 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 }
naco_pfits_get_cumoffsetx
double naco_pfits_get_cumoffsetx(const cpl_propertylist *self)
find out the cumulative offset in X
Definition: naco_pfits.c:95
naco_spectro_compute_disprel
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.
Definition: naco_wavelength.c:122
naco_get_disprel_estimate
double * naco_get_disprel_estimate(const char *filename, int poly_deg)
Estimate the instrument wavelength range.
Definition: naco_physicalmodel.c:70
naco_dfs_set_groups
int naco_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
Definition: naco_dfs.c:62