IIINSTRUMENT Pipeline Reference Manual  6.2.2
isaac_spc_arc.c
1 /* $Id: isaac_spc_arc.c,v 1.58 2013-03-12 08:06:48 llundin Exp $
2  *
3  * This file is part of the ISAAC Pipeline
4  * Copyright (C) 2002,2003 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: llundin $
23  * $Date: 2013-03-12 08:06:48 $
24  * $Revision: 1.58 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 /*-----------------------------------------------------------------------------
33  Includes
34  -----------------------------------------------------------------------------*/
35 
36 #include <string.h>
37 #include <math.h>
38 #include <float.h>
39 #include <cpl.h>
40 
41 #include "irplib_plugin.h"
42 #include "irplib_utils.h"
43 #include "irplib_distortion.h"
44 
45 #include "isaac_utils.h"
46 #include "isaac_wavelength.h"
47 #include "isaac_physicalmodel.h"
48 #include "isaac_pfits.h"
49 #include "isaac_dfs.h"
50 
51 /*-----------------------------------------------------------------------------
52  Define
53  -----------------------------------------------------------------------------*/
54 
55 #define RECIPE_STRING "isaac_spc_arc"
56 
57 #define ISAAC_ARC_SATURATION 20000
58 
59 /*-----------------------------------------------------------------------------
60  Functions prototypes
61  -----------------------------------------------------------------------------*/
62 
63 static int isaac_spc_arc_reduce_sw(cpl_frameset *, const cpl_parameterlist *,
64  const char *, const char *, cpl_frameset *);
65 static int isaac_spc_arc_reduce_lw(cpl_frameset *, const cpl_parameterlist *,
66  const char *, const char *, cpl_frameset *);
67 static cpl_table * isaac_spc_arc_compute(const cpl_image *, const char *,
68  const char *, const char *, const char *, cpl_table **, cpl_image **);
69 static int isaac_spc_arc_save(const cpl_table *, const cpl_table *,
70  const cpl_image *, const char *, cpl_frameset *,
71  const cpl_parameterlist *, cpl_frameset *);
72 static int isaac_spc_arc_compare(const cpl_frame *, const cpl_frame *);
73 static int * isaac_spc_arc_find_lamps(cpl_frameset *);
74 static int isaac_is_xenon_lamp_active(const cpl_propertylist *);
75 static int isaac_is_argon_lamp_active(const cpl_propertylist *);
76 
77 
78 cpl_recipe_define(isaac_spc_arc, ISAAC_BINARY_VERSION,
79  "Lars Lundin", PACKAGE_BUGREPORT, "2002, 2003, 2008",
80  "ISAAC Spectro arc recipe",
81  RECIPE_STRING " -- ISAAC Spectro arc recipe\n"
82  "The files listed in the Set Of Frames (sof-file) "
83  "must be tagged:\n"
84  "raw-file.fits "ISAAC_SPC_ARC_RAW" or\n"
85  "xe-cat.fits "ISAAC_CALPRO_XE_CAT" or\n"
86  "ar-cat.fits "ISAAC_CALPRO_AR_CAT"\n");
87 
88 
89 /*-----------------------------------------------------------------------------
90  Static variables
91  -----------------------------------------------------------------------------*/
92 
93 static struct {
94  /* Inputs */
95  int rej_left;
96  int rej_right;
97  int rej_bottom;
98  int rej_top;
99  int sub_dark;
100  int arc_max_width;
101  int max_offset;
102  double arc_kappa;
103  int out_corr;
104  /* Outputs */
105  int set_nb;
106  int pair_nb;
107  int nb_saturated;
108  int arm;
109  char resol;
110  double disprel_cc;
111  int disprel_clines;
112  int disprel_dlines;
113  double disprel_rms;
114  double disprel_offset;
115  double fwhm_med;
116  int fwhm_good;
117 } isaac_spc_arc_config;
118 
119 /*-----------------------------------------------------------------------------
120  Functions code
121  -----------------------------------------------------------------------------*/
122 
123 /*----------------------------------------------------------------------------*/
131 /*----------------------------------------------------------------------------*/
132 static
133 cpl_error_code isaac_spc_arc_fill_parameterlist(cpl_parameterlist * self)
134 {
135  const char * context = PACKAGE "." RECIPE_STRING;
136  cpl_error_code err;
137 
138  cpl_ensure_code(self, CPL_ERROR_NULL_INPUT);
139 
140  /* Fill the parameters list */
141 
142  /* --rejected */
143  err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
144  "rejected", "-1,-1,100,100", "rej",
145  context,
146  "left right bottom top rejections");
147  cpl_ensure_code(!err, err);
148 
149  /* --subdark */
150  err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
151  "subdark", CPL_FALSE, NULL, context,
152  "Flag to subtract the dark");
153  cpl_ensure_code(!err, err);
154 
155  /* --arc_max_w */
156  err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
157  "arc_max_w", 33, NULL, context,
158  "Maximum arc width allowed in pixels");
159  cpl_ensure_code(!err, err);
160 
161  /* --max_offset */
162  err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
163  "max_offset", 50, NULL, context,
164  "Maximum offset from the physical "
165  "model allowed in pixels");
166  cpl_ensure_code(!err, err);
167 
168  /* --arc_kappa */
169  err = irplib_parameterlist_set_double(self, PACKAGE, RECIPE_STRING,
170  "arc_kappa", 0.33, NULL, context,
171  "kappa for the threshold used for "
172  "arcs detection");
173  cpl_ensure_code(!err, err);
174 
175  /* --out_corr */
176  err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
177  "out_corr", CPL_FALSE, NULL, context,
178  "Flag to output corrected images");
179  cpl_ensure_code(!err, err);
180 
181  return CPL_ERROR_NONE;
182 }
183 
184 /*----------------------------------------------------------------------------*/
191 /*----------------------------------------------------------------------------*/
192 static int isaac_spc_arc(cpl_frameset * framelist,
193  const cpl_parameterlist * parlist)
194 {
195  const char * sval;
196  cpl_size * labels = NULL;
197  cpl_size nlabels = 0;
198  const char * xe;
199  const char * ar;
200  cpl_propertylist * plist = NULL;
201  cpl_frameset * arcframes = NULL;
202  cpl_frameset * arc_one = NULL;
203  int i;
204 
205  /* Retrieve input parameters */
206  /* Rejection parameters */
207  sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
208  "rejected");
209  skip_if(sval == NULL);
210  error_if (sscanf(sval, "%d,%d,%d,%d",
211  &isaac_spc_arc_config.rej_left,
212  &isaac_spc_arc_config.rej_right,
213  &isaac_spc_arc_config.rej_bottom,
214  &isaac_spc_arc_config.rej_top) != 4,
215  CPL_ERROR_DATA_NOT_FOUND, "Parameter not in format %s: %s",
216  "%d,%d,%d,%d", sval);
217 
218  /* Output corrected images */
219  isaac_spc_arc_config.out_corr
220  = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
221  "out_corr");
222  /* Dark subtraction */
223  isaac_spc_arc_config.sub_dark
224  = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
225  "subdark");
226 
227  /* Arc max width in pixels */
228  isaac_spc_arc_config.arc_max_width
229  = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
230  "arc_max_w");
231 
232  /* Max offset in pixels */
233  isaac_spc_arc_config.max_offset
234  = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
235  "max_offset");
236  /* Arc detection kappa */
237  isaac_spc_arc_config.arc_kappa
238  = irplib_parameterlist_get_double(parlist, PACKAGE, RECIPE_STRING,
239  "arc_kappa");
240 
241  /* Identify the RAW and CALIB frames in the input frameset */
242  skip_if (isaac_dfs_set_groups(framelist));
243 
244  /* Retrieve raw frames */
245  arcframes = isaac_extract_frameset(framelist, ISAAC_SPC_ARC_RAW);
246  error_if (arcframes == NULL, CPL_ERROR_DATA_NOT_FOUND,
247  "No frames are tagged %s", ISAAC_SPC_ARC_RAW);
248 
249  /* Retrieve calibration data */
250  xe = isaac_extract_filename(framelist, ISAAC_CALPRO_XE_CAT);
251  error_if (xe == NULL, CPL_ERROR_DATA_NOT_FOUND,
252  "Xe catalogue not found");
253 
254  ar = isaac_extract_filename(framelist, ISAAC_CALPRO_AR_CAT);
255  error_if (ar == NULL, CPL_ERROR_DATA_NOT_FOUND,
256  "Ar catalogue not found");
257 
258  /* Labelise all input frames */
259  labels = cpl_frameset_labelise(arcframes, isaac_spc_arc_compare, &nlabels);
260  any_if ("Could not labelise input frames (nlabels=%d)", (int)nlabels);
261 
262  /* Extract settings and reduce each of them */
263  for (i=0; i < nlabels; i++) {
264  const cpl_frame * cur_frame;
265  const char * filename;
266  int error;
267 
268  /* Reduce data set nb i */
269  cpl_msg_info(cpl_func, "Reducing data set %d of %d", i+1, (int)nlabels);
270  isaac_spc_arc_config.set_nb = i+1;
271  cpl_frameset_delete(arc_one);
272  arc_one = cpl_frameset_extract(arcframes, labels, i);
273 
274  /* Get the arm used (SW or LW) */
275  cur_frame = cpl_frameset_get_position(arc_one, 0);
276  filename = cpl_frame_get_filename(cur_frame);
277  cpl_propertylist_delete(plist);
278  plist = cpl_propertylist_load(filename, 0);
279  sval = isaac_pfits_get_arm(plist);
280  any_if ("Could not get the arm from %s in set %d of %d", filename,
281  i+1, (int)nlabels);
282 
283  if (sval[0] == 'S') {
284  isaac_spc_arc_config.arm = 1;
285  } else if (sval[0] == 'L') {
286  isaac_spc_arc_config.arm = 2;
287  } else {
288  isaac_spc_arc_config.arm = 0;
289  error_if(1, CPL_ERROR_UNSUPPORTED_MODE,
290  "Unsupported arm in %s in set %d of %d: %s", filename,
291  i+1, (int)nlabels, sval);
292  }
293 
294  /* Get the resolution */
295  sval = isaac_pfits_get_resolution(plist);
296  any_if ("Could not get the resolution from %s in set %d of %d",
297  filename, i+1, (int)nlabels);
298 
299  if (sval[0]=='L') isaac_spc_arc_config.resol = 'L';
300  else if (sval[0]=='M') isaac_spc_arc_config.resol = 'M';
301  else isaac_spc_arc_config.resol = 'U';
302  cpl_propertylist_empty(plist);
303 
304  error = isaac_spc_arc_config.arm == 1 ?
305  /* SW mode */
306  isaac_spc_arc_reduce_sw(arc_one, parlist, ar, xe, framelist) :
307  /* LW mode */
308  isaac_spc_arc_reduce_lw(arc_one, parlist, ar, xe, framelist);
309 
310  error_if(error, cpl_error_get_code(),
311  "Could not reduce set %d of %d", i+1, (int)nlabels);
312  }
313 
314  end_skip;
315 
316  cpl_frameset_delete(arc_one);
317  cpl_frameset_delete(arcframes);
318  cpl_free(labels);
319  cpl_propertylist_delete(plist);
320 
321  return cpl_error_get_code();
322 }
323 
324 /*----------------------------------------------------------------------------*/
334 /*----------------------------------------------------------------------------*/
335 static int isaac_spc_arc_reduce_sw(
336  cpl_frameset * arcframes,
337  const cpl_parameterlist * parlist,
338  const char * ar,
339  const char * xe,
340  cpl_frameset * set_tot)
341 {
342  int * lamps;
343  int nframes;
344  char lines_table[16];
345  cpl_frame * cur_frame;
346  const char * cur_fname;
347  cpl_image * xenon;
348  cpl_image * argon;
349  cpl_image * xe_ar;
350  cpl_image * dark;
351  cpl_image * to_compute;
352  cpl_table * arcs_fwhm;
353  cpl_image * out_corr;
354  cpl_table * out_table;
355  int i;
356 
357  /* Initialise */
358  nframes = cpl_frameset_get_size(arcframes);
359  isaac_spc_arc_config.pair_nb = 0;
360  to_compute = NULL;
361 
362  /* Look for each file which lamp is activated */
363  /* lamps[i]==0 ---> frame i : lamps off */
364  /* lamps[i]==1 ---> frame i : Xenon lamp on */
365  /* lamps[i]==2 ---> frame i : Argon lamp on */
366  /* lamps[i]==3 ---> frame i : Arg and Xe lamps on */
367  if ((lamps=isaac_spc_arc_find_lamps(arcframes)) == NULL) {
368  cpl_msg_error(cpl_func, "in finding the activated lamps");
369  return CPL_ERROR_UNSPECIFIED;
370  }
371 
372  /* Get the images */
373  xenon = argon = xe_ar = dark = NULL;
374  for (i=0; i<nframes; i++) {
375  cur_frame = cpl_frameset_get_position(arcframes, i);
376  cur_fname = cpl_frame_get_filename(cur_frame);
377  if ((lamps[i] == 0) && (dark == NULL)) {
378  cpl_msg_info(cpl_func, "Dark image: [%s]", cur_fname);
379  dark = cpl_image_load(cur_fname, CPL_TYPE_FLOAT, 0, 0);
380  } else if ((lamps[i] == 1) && (xenon == NULL)) {
381  cpl_msg_info(cpl_func, "Xenon lamp: [%s]", cur_fname);
382  xenon = cpl_image_load(cur_fname, CPL_TYPE_FLOAT, 0, 0);
383  } else if ((lamps[i] == 2) && (argon == NULL)) {
384  cpl_msg_info(cpl_func, "Argon lamp: [%s]", cur_fname);
385  argon = cpl_image_load(cur_fname, CPL_TYPE_FLOAT, 0, 0);
386  } else if ((lamps[i] == 3) && (xe_ar == NULL)) {
387  cpl_msg_info(cpl_func, "Xenon+Argon lamp: [%s]", cur_fname);
388  xe_ar = cpl_image_load(cur_fname, CPL_TYPE_FLOAT, 0, 0);
389  }
390  }
391  cpl_free(lamps);
392 
393  /* All lamps are switched off */
394  if (!xenon && !argon && !xe_ar) {
395  cpl_msg_error(cpl_func, "neither xenon nor argon lamp activated");
396  if (dark) cpl_image_delete(dark);
397  return CPL_ERROR_UNSPECIFIED;
398  }
399 
400  /* Get the first file name */
401  cur_frame = cpl_frameset_get_position(arcframes, 0);
402  cur_fname = cpl_frame_get_filename(cur_frame);
403 
404  /* Reduction in LR */
405  if (isaac_spc_arc_config.resol == 'L') {
406  cpl_msg_info(cpl_func, "Low resolution");
407 
408  /* Xenon lines */
409  if (xenon) {
410  if (dark) to_compute = cpl_image_subtract_create(xenon, dark);
411  else to_compute = cpl_image_duplicate(xenon);
412  cpl_image_delete(xenon);
413  strcpy(lines_table, "Xe");
414 
415  /* Apply the reduction */
416  cpl_msg_info(cpl_func, "Apply the reduction");
417  isaac_spc_arc_config.pair_nb ++;
418  cpl_msg_indent_more();
419  if ((out_table = isaac_spc_arc_compute(to_compute, cur_fname,
420  lines_table, ar, xe, &arcs_fwhm,
421  &out_corr)) == NULL) {
422  cpl_msg_error(cpl_func, "arc reduction computation failed");
423  cpl_image_delete(to_compute);
424  } else {
425  /* Save the products */
426  cpl_image_delete(to_compute);
427  cpl_msg_info(cpl_func, "Save the products");
428  isaac_spc_arc_save(out_table, arcs_fwhm, out_corr, lines_table,
429  arcframes, parlist, set_tot);
430  cpl_table_delete(out_table);
431  if (arcs_fwhm) cpl_table_delete(arcs_fwhm);
432  if (out_corr) cpl_image_delete(out_corr);
433  }
434  cpl_msg_indent_less();
435  }
436 
437  /* Argon lines */
438  if (argon) {
439  if (dark) to_compute = cpl_image_subtract_create(argon, dark);
440  else to_compute = cpl_image_duplicate(argon);
441  cpl_image_delete(argon);
442  strcpy(lines_table, "Ar");
443 
444  /* Apply the reduction */
445  cpl_msg_info(cpl_func, "Apply the reduction");
446  isaac_spc_arc_config.pair_nb ++;
447  cpl_msg_indent_more();
448  if ((out_table = isaac_spc_arc_compute(to_compute, cur_fname,
449  lines_table, ar, xe, &arcs_fwhm,
450  &out_corr)) == NULL) {
451  cpl_msg_error(cpl_func, "arc reduction computation failed");
452  cpl_image_delete(to_compute);
453  } else {
454  /* Save the products */
455  cpl_image_delete(to_compute);
456  cpl_msg_info(cpl_func, "Save the products");
457  isaac_spc_arc_save(out_table, arcs_fwhm, out_corr, lines_table,
458  arcframes, parlist, set_tot);
459  cpl_table_delete(out_table);
460  if (arcs_fwhm) cpl_table_delete(arcs_fwhm);
461  if (out_corr) cpl_image_delete(out_corr);
462  }
463  cpl_msg_indent_less();
464  }
465 
466  /* Xenon+Argon lines */
467  if (xe_ar) {
468  if (dark) to_compute = cpl_image_subtract_create(xe_ar, dark);
469  else to_compute = cpl_image_duplicate(xe_ar);
470  cpl_image_delete(xe_ar);
471  strcpy(lines_table, "Xe+Ar");
472 
473  /* Apply the reduction */
474  cpl_msg_info(cpl_func, "Apply the reduction");
475  isaac_spc_arc_config.pair_nb ++;
476  cpl_msg_indent_more();
477  if ((out_table = isaac_spc_arc_compute(to_compute, cur_fname,
478  lines_table, ar, xe, &arcs_fwhm,
479  &out_corr)) == NULL) {
480  cpl_msg_error(cpl_func, "arc reduction computation failed");
481  cpl_image_delete(to_compute);
482  } else {
483  /* Save the products */
484  cpl_image_delete(to_compute);
485  cpl_msg_info(cpl_func, "Save the products");
486  isaac_spc_arc_save(out_table, arcs_fwhm, out_corr, lines_table,
487  arcframes, parlist, set_tot);
488  cpl_table_delete(out_table);
489  if (arcs_fwhm) cpl_table_delete(arcs_fwhm);
490  if (out_corr) cpl_image_delete(out_corr);
491  }
492  cpl_msg_indent_less();
493  }
494 
495  } else if (isaac_spc_arc_config.resol == 'M') {
496  cpl_msg_info(cpl_func, "Medium resolution");
497  /* Get the input image */
498  if (xenon && argon) {
499  if (dark) {
500  cpl_image_subtract(xenon, dark);
501  cpl_image_subtract(argon, dark);
502  to_compute = cpl_image_add_create(xenon, argon);
503  } else to_compute = cpl_image_add_create(xenon, argon);
504  cpl_image_delete(xenon);
505  cpl_image_delete(argon);
506  strcpy(lines_table, "Xe+Ar");
507  } else if (xenon) {
508  if (dark) to_compute = cpl_image_subtract_create(xenon, dark);
509  else to_compute = cpl_image_duplicate(xenon);
510  cpl_image_delete(xenon);
511  strcpy(lines_table, "Xe");
512  } else if (argon) {
513  if (dark) to_compute = cpl_image_subtract_create(argon, dark);
514  else to_compute = cpl_image_duplicate(argon);
515  cpl_image_delete(argon);
516  strcpy(lines_table, "Ar");
517  } else if (xe_ar) {
518  if (dark) to_compute = cpl_image_subtract_create(xe_ar, dark);
519  else to_compute = cpl_image_duplicate(xe_ar);
520  cpl_image_delete(xe_ar);
521  strcpy(lines_table, "Xe+Ar");
522  }
523 
524  /* Apply the reduction */
525  cpl_msg_info(cpl_func, "Apply the reduction");
526  isaac_spc_arc_config.pair_nb ++;
527  cpl_msg_indent_more();
528  if ((out_table = isaac_spc_arc_compute(to_compute, cur_fname,
529  lines_table, ar, xe, &arcs_fwhm,
530  &out_corr)) == NULL) {
531  cpl_msg_error(cpl_func, "arc reduction computation failed");
532  cpl_image_delete(to_compute);
533  } else {
534  /* Save the products */
535  cpl_image_delete(to_compute);
536  cpl_msg_info(cpl_func, "Save the products");
537  isaac_spc_arc_save(out_table, arcs_fwhm, out_corr, lines_table,
538  arcframes, parlist, set_tot);
539  cpl_table_delete(out_table);
540  if (arcs_fwhm) cpl_table_delete(arcs_fwhm);
541  if (out_corr) cpl_image_delete(out_corr);
542  }
543  cpl_msg_indent_less();
544  }
545 
546  if (dark) cpl_image_delete(dark);
547 
548  return 0;
549 }
550 
551 /*----------------------------------------------------------------------------*/
561 /*----------------------------------------------------------------------------*/
562 static int isaac_spc_arc_reduce_lw(
563  cpl_frameset * arcframes,
564  const cpl_parameterlist * parlist,
565  const char * ar,
566  const char * xe,
567  cpl_frameset * set_tot)
568 {
569  int * lamps;
570  int nframes;
571  char lines_table[16];
572  cpl_frame * cur_frame;
573  const char * cur_fname;
574  cpl_image * to_compute;
575  cpl_image * dark;
576  cpl_table * arcs_fwhm;
577  cpl_image * out_corr;
578  cpl_table * out_table;
579  cpl_boolean did_reduce = CPL_FALSE;
580  int i;
581 
582  /* Initialise */
583  nframes = cpl_frameset_get_size(arcframes);
584 
585  /* The number of frames must be even */
586  if (nframes % 2) {
587  cpl_msg_error(cpl_func, "An even nb of frames expected in input %d",
588  nframes);
589  return CPL_ERROR_UNSPECIFIED;
590  }
591 
592  /* Look for each file which lamp is activated */
593  /* lamps[i]==0 ---> frame i : lamps off */
594  /* lamps[i]==1 ---> frame i : Xenon lamp on */
595  /* lamps[i]==2 ---> frame i : Argon lamp on */
596  /* lamps[i]==3 ---> frame i : Arg and Xe lamps on */
597  if ((lamps=isaac_spc_arc_find_lamps(arcframes)) == NULL) {
598  cpl_msg_error(cpl_func, "in finding the activated lamps");
599  return CPL_ERROR_UNSPECIFIED;
600  }
601 
602  /* Loop on the pairs */
603  for (i=0; i<nframes/2; i++) {
604  isaac_spc_arc_config.pair_nb = i+1;
605  /* Load the image */
606  cur_frame = cpl_frameset_get_position(arcframes, 2*i);
607  cur_fname = cpl_frame_get_filename(cur_frame);
608  if ((to_compute = cpl_image_load(cur_fname,CPL_TYPE_FLOAT,0,0))==NULL){
609  cpl_msg_error(cpl_func, "Could not load frame %s", cur_fname);
610  cpl_free(lamps);
611  }
612  cpl_msg_info(cpl_func, "Pair %d: Lamp and dark identification", i+1);
613  switch (lamps[2*i]) {
614  /* Xenon lamp */
615  case 1:
616  strcpy(lines_table, "Xe");
617  cpl_msg_info(cpl_func, "Xenon lamp: [%s]", cur_fname);
618  break;
619  /* Argon lamp */
620  case 2:
621  strcpy(lines_table, "Ar");
622  cpl_msg_info(cpl_func, "Argon lamp: [%s]", cur_fname);
623  break;
624  /* Xenon+Argon lamp */
625  case 3:
626  strcpy(lines_table, "Xe+Ar");
627  cpl_msg_info(cpl_func, "Xenon+Argon lamp: [%s]", cur_fname);
628  break;
629  default:
630  cpl_image_delete(to_compute);
631  cpl_msg_info(cpl_func, "Lamps are off. Next pair...");
632  continue;
633  }
634 
635  /* Get the dark if present */
636  if (lamps[2*i+1] == 0) {
637  cur_frame = cpl_frameset_get_position(arcframes, 2*i+1);
638  cur_fname = cpl_frame_get_filename(cur_frame);
639  dark = cpl_image_load(cur_fname, CPL_TYPE_FLOAT, 0, 0);
640  cpl_image_subtract(to_compute, dark);
641  cpl_image_delete(dark);
642  cpl_msg_info(cpl_func, "Dark frame : [%s]", cur_fname);
643  } else {
644  cpl_msg_info(cpl_func, "No dark frame");
645  }
646 
647  /* Get the file name */
648  cur_frame = cpl_frameset_get_position(arcframes, 2*i);
649  cur_fname = cpl_frame_get_filename(cur_frame);
650 
651  /* Apply the reduction */
652  cpl_msg_info(cpl_func, "Apply the reduction");
653  cpl_msg_indent_more();
654  if ((out_table = isaac_spc_arc_compute(to_compute, cur_fname,
655  lines_table, ar, xe, &arcs_fwhm,
656  &out_corr)) == NULL) {
657  cpl_msg_error(cpl_func, "arc reduction computation failed");
658  cpl_image_delete(to_compute);
659  } else {
660  /* Save the products */
661  cpl_image_delete(to_compute);
662  cpl_msg_info(cpl_func, "Save the products");
663  isaac_spc_arc_save(out_table, arcs_fwhm, out_corr, lines_table,
664  arcframes, parlist, set_tot);
665  cpl_table_delete(out_table);
666  if (arcs_fwhm) cpl_table_delete(arcs_fwhm);
667  if (out_corr) cpl_image_delete(out_corr);
668  if (!cpl_error_get_code()) did_reduce = CPL_TRUE;
669  }
670  cpl_msg_indent_less();
671  }
672 
673  /* Free and return */
674  cpl_free(lamps);
675  cpl_ensure_code(did_reduce, CPL_ERROR_ILLEGAL_INPUT);
676 
677  return cpl_error_set_where(cpl_func); /* Propagate error, if any */
678 }
679 
680 /*----------------------------------------------------------------------------*/
693 /*----------------------------------------------------------------------------*/
694 static cpl_table * isaac_spc_arc_compute(
695  const cpl_image * in,
696  const char * in_name,
697  const char * lines_table,
698  const char * ar,
699  const char * xe,
700  cpl_table ** arcs_fwhm,
701  cpl_image ** out_corr)
702 {
703  cpl_table * out_tab;
704  int xmin, ymin, xmax, ymax;
705  int nx, ny;
706  cpl_mask * saturation_map;
707  double slit_width;
708  int order;
709  cpl_polynomial * distor_poly;
710  cpl_polynomial * poly2d_id;
711  cpl_vector * profile;
712  cpl_image * in_corr;
713  cpl_apertures * arcs;
714  double * phdisprel;
715  computed_disprel * disprel;
716  cpl_size power[2];
717  double fwhm_x, fwhm_y;
718  cpl_vector * fwhm_valid;
719  int i;
720 
721  /* Initialise */
722  nx = cpl_image_get_size_x(in);
723  ny = cpl_image_get_size_y(in);
724  *arcs_fwhm = NULL;
725  *out_corr = NULL;
726 
727  /* Define zone */
728  xmin = 1;
729  xmax = nx;
730  ymin = isaac_spc_arc_config.rej_bottom + 1;
731  ymax = ny - isaac_spc_arc_config.rej_top;
732 
733  /* Compute the number of saturated pixels */
734  saturation_map = cpl_mask_threshold_image_create(in, ISAAC_ARC_SATURATION,
735  DBL_MAX);
736  if (saturation_map != NULL) {
737  isaac_spc_arc_config.nb_saturated = cpl_mask_count(saturation_map);
738  cpl_mask_delete(saturation_map);
739  } else {
740  isaac_spc_arc_config.nb_saturated = 0;
741  }
742 
743  /* Distortion estimation */
744  cpl_msg_info(cpl_func, "Estimate the distortion");
745  cpl_msg_indent_more();
746  if ((distor_poly = irplib_distortion_estimate(in, xmin, ymin, xmax, ymax,
747  isaac_spc_arc_config.sub_dark, ISAAC_ARC_SATURATION,
748  isaac_spc_arc_config.arc_max_width,
749  isaac_spc_arc_config.arc_kappa, 2, &arcs)) == NULL) {
750  cpl_msg_error(cpl_func, "Could not estimage distortion");
751  cpl_msg_indent_less();
752  return NULL;
753  }
754  cpl_msg_indent_less();
755 
756  /* Distortion correction */
757  cpl_msg_info(cpl_func, "Correct the distortion");
758  cpl_msg_indent_more();
759  in_corr = cpl_image_duplicate(in);
760 
761  /* Create the identity polynomial */
762  poly2d_id = cpl_polynomial_new(2);
763  power[0] = 0; power[1] = 1;
764  cpl_polynomial_set_coeff(poly2d_id, power, 1.0);
765 
766  /* Create the kernel */
767  profile = cpl_vector_new(CPL_KERNEL_DEF_SAMPLES);
768  cpl_vector_fill_kernel_profile(profile, CPL_KERNEL_DEFAULT,
769  CPL_KERNEL_DEF_WIDTH);
770 
771  /* Apply the distortion */
772  if (cpl_image_warp_polynomial(in_corr, in, distor_poly,
773  poly2d_id, profile, CPL_KERNEL_DEF_WIDTH, profile,
774  CPL_KERNEL_DEF_WIDTH) != CPL_ERROR_NONE) {
775  cpl_msg_error(cpl_func, "Could not correct the distortion");
776  cpl_image_delete(in_corr);
777  cpl_polynomial_delete(poly2d_id);
778  cpl_polynomial_delete(distor_poly);
779  cpl_vector_delete(profile);
780  cpl_msg_indent_less();
781  return NULL;
782  }
783  cpl_polynomial_delete(poly2d_id);
784  cpl_vector_delete(profile);
785  cpl_msg_indent_less();
786 
787  /* Compute the FWHM of the detected arcs */
788  cpl_msg_info(cpl_func, "Compute the FWHM of the detected arcs");
789  /* Create the fwhms table */
790  *arcs_fwhm = cpl_table_new(cpl_apertures_get_size(arcs));
791  cpl_table_new_column(*arcs_fwhm, "XPOS", CPL_TYPE_DOUBLE);
792  cpl_table_new_column(*arcs_fwhm, "FWHM", CPL_TYPE_DOUBLE);
793  cpl_table_new_column(*arcs_fwhm, "FLUX", CPL_TYPE_DOUBLE);
794  /* Compute the fwhms */
795  isaac_spc_arc_config.fwhm_good = 0;
796  for (i=0; i<cpl_apertures_get_size(arcs); i++) {
797  cpl_table_set_double(*arcs_fwhm, "XPOS", i,
798  cpl_apertures_get_centroid_x(arcs, i+1));
799  cpl_table_set_double(*arcs_fwhm, "FLUX", i,
800  cpl_apertures_get_flux(arcs, i+1));
801  if (cpl_image_get_fwhm(in_corr, cpl_apertures_get_centroid_x(arcs, i+1),
802  512, &fwhm_x, &fwhm_y) != CPL_ERROR_NONE) {
803  cpl_msg_warning(cpl_func, "Could not get the FWHM");
804  cpl_error_reset();
805  }
806  cpl_table_set_double(*arcs_fwhm, "FWHM", i, fwhm_x);
807  if (fwhm_x > 0) isaac_spc_arc_config.fwhm_good ++;
808  }
809  cpl_apertures_delete(arcs);
810 
811  /* Compute the median of the good fwhms */
812  if (isaac_spc_arc_config.fwhm_good > 0) {
813  fwhm_valid = cpl_vector_new(isaac_spc_arc_config.fwhm_good);
814  isaac_spc_arc_config.fwhm_good = 0;
815  for (i=0; i<cpl_table_get_nrow(*arcs_fwhm); i++) {
816  fwhm_x = cpl_table_get_double(*arcs_fwhm, "FWHM", i, NULL);
817  if (fwhm_x > 0) {
818  cpl_vector_set(fwhm_valid, isaac_spc_arc_config.fwhm_good,
819  fwhm_x);
820  isaac_spc_arc_config.fwhm_good ++;
821  }
822  }
823  isaac_spc_arc_config.fwhm_med = cpl_vector_get_median_const(fwhm_valid);
824  cpl_vector_delete(fwhm_valid);
825  } else isaac_spc_arc_config.fwhm_med = 0.0;
826 
827  /* Wavelength calibration */
828 
829  /* Compute the slit_width */
830  if ((slit_width = isaac_get_slitwidth(in_name)) == -1) {
831  cpl_msg_error(cpl_func, "Could not get the slit width");
832  cpl_polynomial_delete(distor_poly);
833  cpl_image_delete(in_corr);
834  cpl_table_delete(*arcs_fwhm);
835  *arcs_fwhm = NULL;
836  return NULL;
837  }
838 
839  /* Get the order */
840  if ((order = isaac_find_order(in_name)) == -1) {
841  cpl_msg_error(cpl_func, "Could not get the order");
842  cpl_polynomial_delete(distor_poly);
843  cpl_image_delete(in_corr);
844  cpl_table_delete(*arcs_fwhm);
845  *arcs_fwhm = NULL;
846  return NULL;
847  }
848 
849  /* First estimation using a physical model */
850  cpl_msg_info(cpl_func, "Compute the physical model");
851  cpl_msg_indent_more();
852  if ((phdisprel = isaac_get_disprel_estimate(in_name, 3)) == NULL) {
853  cpl_msg_error(cpl_func, "Could not estimate the dispersion relation");
854  cpl_polynomial_delete(distor_poly);
855  cpl_image_delete(in_corr);
856  cpl_table_delete(*arcs_fwhm);
857  *arcs_fwhm = NULL;
858  cpl_msg_indent_less();
859  return NULL;
860  }
861  cpl_msg_info(cpl_func, "f(x)=%g + %g*x + %g*x^2 + %g*x^3",
862  phdisprel[0], phdisprel[1], phdisprel[2], phdisprel[3]);
863  cpl_msg_indent_less();
864 
865  /* Compute the dispersion relation */
866  cpl_msg_info(cpl_func, "Compute the dispersion relation");
867  cpl_msg_indent_more();
868  if ((disprel = spectro_compute_disprel(in_corr,
869  isaac_spc_arc_config.rej_bottom,
870  isaac_spc_arc_config.rej_top,
871  isaac_spc_arc_config.rej_left,
872  isaac_spc_arc_config.rej_right,
873  isaac_spc_arc_config.max_offset,
874  isaac_has_thermal(in_name) > 0,
875  lines_table, NULL, ar, xe, slit_width, order,
876  (int)(cpl_msg_get_level() == CPL_MSG_DEBUG),
877  phdisprel)) == NULL) {
878  cpl_msg_error(cpl_func, "Could not compute the dispersion relation");
879  cpl_polynomial_delete(distor_poly);
880  cpl_image_delete(in_corr);
881  cpl_free(phdisprel);
882  cpl_table_delete(*arcs_fwhm);
883  *arcs_fwhm = NULL;
884  cpl_msg_indent_less();
885  return NULL;
886  }
887  if (isaac_spc_arc_config.out_corr) {
888  *out_corr = in_corr;
889  in_corr = NULL;
890  } else {
891  cpl_image_delete(in_corr);
892  }
893  cpl_free(phdisprel);
894  cpl_msg_info(cpl_func, "Cross correlation factor: %g", disprel->cc);
895  cpl_msg_info(cpl_func, "f(x)=%g + %g*x + %g*x^2 + %g*x^3",
896  disprel->poly[0], disprel->poly[1], disprel->poly[2],
897  disprel->poly[3]);
898  cpl_msg_indent_less();
899 
900  /* Create the output table and store the relevant information */
901  out_tab = cpl_table_new(6);
902 
903  /* Fill distortion polynomial */
904  cpl_table_new_column(out_tab, "Degree_of_x", CPL_TYPE_INT);
905  cpl_table_new_column(out_tab, "Degree_of_y", CPL_TYPE_INT);
906  cpl_table_new_column(out_tab, "poly2d_coef", CPL_TYPE_DOUBLE);
907  power[0] = 0; power[1] = 0;
908  cpl_table_set_int(out_tab, "Degree_of_x", 0, power[0]);
909  cpl_table_set_int(out_tab, "Degree_of_y", 0, power[1]);
910  cpl_table_set_double(out_tab, "poly2d_coef", 0,
911  cpl_polynomial_get_coeff(distor_poly, power));
912  power[0] = 1; power[1] = 0;
913  cpl_table_set_int(out_tab, "Degree_of_x", 1, power[0]);
914  cpl_table_set_int(out_tab, "Degree_of_y", 1, power[1]);
915  cpl_table_set_double(out_tab, "poly2d_coef", 1,
916  cpl_polynomial_get_coeff(distor_poly, power));
917  power[0] = 0; power[1] = 1;
918  cpl_table_set_int(out_tab, "Degree_of_x", 2, power[0]);
919  cpl_table_set_int(out_tab, "Degree_of_y", 2, power[1]);
920  cpl_table_set_double(out_tab, "poly2d_coef", 2,
921  cpl_polynomial_get_coeff(distor_poly, power));
922  power[0] = 1; power[1] = 1;
923  cpl_table_set_int(out_tab, "Degree_of_x", 3, power[0]);
924  cpl_table_set_int(out_tab, "Degree_of_y", 3, power[1]);
925  cpl_table_set_double(out_tab, "poly2d_coef", 3,
926  cpl_polynomial_get_coeff(distor_poly, power));
927  power[0] = 2; power[1] = 0;
928  cpl_table_set_int(out_tab, "Degree_of_x", 4, power[0]);
929  cpl_table_set_int(out_tab, "Degree_of_y", 4, power[1]);
930  cpl_table_set_double(out_tab, "poly2d_coef", 4,
931  cpl_polynomial_get_coeff(distor_poly, power));
932  power[0] = 0; power[1] = 2;
933  cpl_table_set_int(out_tab, "Degree_of_x", 5, power[0]);
934  cpl_table_set_int(out_tab, "Degree_of_y", 5, power[1]);
935  cpl_table_set_double(out_tab, "poly2d_coef", 5,
936  cpl_polynomial_get_coeff(distor_poly, power));
937 
938  /* Fill dispersion relation */
939  cpl_table_new_column(out_tab, "WL_coefficients", CPL_TYPE_DOUBLE);
940  cpl_table_set_double(out_tab, "WL_coefficients", 0, disprel->poly[0]);
941  cpl_table_set_double(out_tab, "WL_coefficients", 1, disprel->poly[1]);
942  cpl_table_set_double(out_tab, "WL_coefficients", 2, disprel->poly[2]);
943  cpl_table_set_double(out_tab, "WL_coefficients", 3, disprel->poly[3]);
944  cpl_table_set_double(out_tab, "WL_coefficients", 4, 0.0);
945  cpl_table_set_double(out_tab, "WL_coefficients", 5, 0.0);
946  isaac_spc_arc_config.disprel_cc = disprel->cc;
947  isaac_spc_arc_config.disprel_clines = disprel->clines;
948  isaac_spc_arc_config.disprel_dlines = disprel->dlines;
949  isaac_spc_arc_config.disprel_rms = disprel->rms;
950  isaac_spc_arc_config.disprel_offset = disprel->offset;
951 
952  /* Free and return */
953  cpl_polynomial_delete(distor_poly);
954  if (disprel->poly != NULL) cpl_free(disprel->poly);
955  cpl_free(disprel);
956  return out_tab;
957 }
958 
959 /*----------------------------------------------------------------------------*/
971 /*----------------------------------------------------------------------------*/
972 static int isaac_spc_arc_save(
973  const cpl_table * tab,
974  const cpl_table * fwhms,
975  const cpl_image * corr,
976  const char * lines_table,
977  cpl_frameset * set,
978  const cpl_parameterlist * parlist,
979  cpl_frameset * set_tot)
980 {
981  cpl_propertylist * plist;
982  cpl_propertylist * qclist;
983  cpl_propertylist * paflist;
984  const cpl_frame * ref_frame;
985  const char * sval;
986  char qc_str[128];
987  const char * procat = isaac_spc_arc_config.arm == 1
988  ? ISAAC_SPC_ARC_SW_RES : ISAAC_SPC_ARC_LW_RES;
989  char * filename;
990  int i;
991 
992 
993  /* Get the QC params in qclist */
994  qclist = cpl_propertylist_new();
995 
996  /* Get the reference frame */
997  ref_frame = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW);
998  if ((plist=cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
999  0)) == NULL) {
1000  cpl_msg_error(cpl_func, "getting header from reference frame");
1001  cpl_propertylist_delete(qclist);
1002  return CPL_ERROR_UNSPECIFIED;
1003  }
1004  /* Test the status */
1005  if (cpl_error_get_code()) {
1006  cpl_propertylist_delete(qclist);
1007  cpl_propertylist_delete(plist);
1008  return CPL_ERROR_UNSPECIFIED;
1009  }
1010  sval = isaac_pfits_get_filter(plist);
1011  if (cpl_error_get_code()) cpl_error_reset();
1012  else cpl_propertylist_append_string(qclist, "ESO QC FILTER OBS", sval);
1013  cpl_propertylist_delete(plist);
1014  cpl_propertylist_append_string(qclist, "ESO QC LAMP", lines_table);
1015  cpl_propertylist_append_double(qclist, "ESO QC DISP XCORR",
1016  isaac_spc_arc_config.disprel_cc);
1017  cpl_propertylist_append_int(qclist, "ESO QC DISP NUMCAT",
1018  isaac_spc_arc_config.disprel_clines);
1019  cpl_propertylist_append_int(qclist, "ESO QC DISP NUMMATCH",
1020  isaac_spc_arc_config.disprel_dlines);
1021  cpl_propertylist_append_double(qclist, "ESO QC DISP STDEV",
1022  isaac_spc_arc_config.disprel_rms);
1023  cpl_propertylist_append_double(qclist, "ESO QC DISP OFFSET",
1024  isaac_spc_arc_config.disprel_offset);
1025  cpl_propertylist_append_double(qclist, "ESO QC DISPCO1",
1026  cpl_table_get_double(tab, "WL_coefficients", 0, NULL));
1027  cpl_propertylist_append_double(qclist, "ESO QC DISPCO2",
1028  cpl_table_get_double(tab, "WL_coefficients", 1, NULL));
1029  cpl_propertylist_append_double(qclist, "ESO QC DISPCO3",
1030  cpl_table_get_double(tab, "WL_coefficients", 2, NULL));
1031  cpl_propertylist_append_double(qclist, "ESO QC DISPCO4",
1032  cpl_table_get_double(tab, "WL_coefficients", 3, NULL));
1033  cpl_propertylist_append_double(qclist, "ESO QC DIST1",
1034  cpl_table_get_double(tab, "poly2d_coef", 0, NULL));
1035  cpl_propertylist_append_double(qclist, "ESO QC DISTX",
1036  cpl_table_get_double(tab, "poly2d_coef", 1, NULL));
1037  cpl_propertylist_append_double(qclist, "ESO QC DISTY",
1038  cpl_table_get_double(tab, "poly2d_coef", 2, NULL));
1039  cpl_propertylist_append_double(qclist, "ESO QC DISTXY",
1040  cpl_table_get_double(tab, "poly2d_coef", 3, NULL));
1041  cpl_propertylist_append_double(qclist, "ESO QC DISTXX",
1042  cpl_table_get_double(tab, "poly2d_coef", 4, NULL));
1043  cpl_propertylist_append_double(qclist, "ESO QC DISTYY",
1044  cpl_table_get_double(tab, "poly2d_coef", 5, NULL));
1045  cpl_propertylist_append_int(qclist, "ESO QC SATUR NBPIX",
1046  isaac_spc_arc_config.nb_saturated);
1047  cpl_propertylist_append_double(qclist, "ESO QC WLEN",
1048  (double)(cpl_table_get_double(tab, "WL_coefficients", 0, NULL) +
1049  512*cpl_table_get_double(tab, "WL_coefficients", 1, NULL) +
1050  512*512*cpl_table_get_double(tab, "WL_coefficients", 2, NULL) +
1051  512*512*512*cpl_table_get_double(tab, "WL_coefficients", 3, NULL)));
1052 
1053  if (fwhms) {
1054  cpl_propertylist_append_int(qclist, "ESO QC ARCS NUM",
1055  cpl_table_get_nrow(fwhms));
1056  for(i=0; i<cpl_table_get_nrow(fwhms); i++) {
1057  sprintf(qc_str, "ESO QC ARCS%d XPOS", i+1);
1058  cpl_propertylist_append_double(qclist, qc_str,
1059  cpl_table_get_double(fwhms, "XPOS", i, NULL));
1060  sprintf(qc_str, "ESO QC ARCS%d FWHM", i+1);
1061  cpl_propertylist_append_double(qclist, qc_str,
1062  cpl_table_get_double(fwhms, "FWHM", i, NULL));
1063  sprintf(qc_str, "ESO QC ARCS%d FLUX", i+1);
1064  cpl_propertylist_append_double(qclist, qc_str,
1065  cpl_table_get_double(fwhms, "FLUX", i, NULL));
1066  }
1067  cpl_propertylist_append_int(qclist, "ESO QC ARCS NUMGOOD",
1068  isaac_spc_arc_config.fwhm_good);
1069  cpl_propertylist_append_double(qclist, "ESO QC FWHM MED",
1070  isaac_spc_arc_config.fwhm_med);
1071  }
1072 
1073 
1074  /* Write the arc table */
1075  filename = cpl_sprintf("isaac_spc_arc_set%d_pair%d.fits",
1076  isaac_spc_arc_config.set_nb, isaac_spc_arc_config.pair_nb);
1077  irplib_dfs_save_table(set_tot,
1078  parlist,
1079  set,
1080  tab,
1081  NULL,
1082  "isaac_spc_arc",
1083  procat,
1084  qclist,
1085  NULL,
1086  PACKAGE "/" PACKAGE_VERSION,
1087  filename);
1088  cpl_free(filename);
1089 
1090  /* Write the corrected image */
1091  if (corr) {
1092  const char * procatc = isaac_spc_arc_config.arm == 1
1093  ? ISAAC_SPC_ARC_SW_CORR : ISAAC_SPC_ARC_LW_CORR;
1094  filename = cpl_sprintf("isaac_spc_arc_set%d_pair%d_corr.fits",
1095  isaac_spc_arc_config.set_nb, isaac_spc_arc_config.pair_nb);
1096  irplib_dfs_save_image(set_tot,
1097  parlist,
1098  set,
1099  corr,
1100  CPL_BPP_IEEE_FLOAT,
1101  "isaac_spc_arc",
1102  procatc,
1103  qclist,
1104  NULL,
1105  PACKAGE "/" PACKAGE_VERSION,
1106  filename);
1107  cpl_free(filename);
1108  }
1109 
1110  /* Get the reference frame */
1111  ref_frame = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW);
1112 
1113  /* Get FITS header from reference file */
1114  if ((plist=cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
1115  0)) == NULL) {
1116  cpl_msg_error(cpl_func, "getting header from reference frame");
1117  cpl_propertylist_delete(qclist);
1118  return CPL_ERROR_UNSPECIFIED;
1119  }
1120 
1121  /* Get the keywords for the paf file */
1122  paflist = cpl_propertylist_new();
1123  cpl_propertylist_copy_property_regexp(paflist, plist,
1124  "^(ARCFILE|MJD-OBS|INSTRUME|ESO TPL ID|ESO TPL NEXP|ESO DPR CATG|"
1125  "ESO DPR TECH|ESO DPR TYPE|DATE-OBS|ESO INS GRAT NAME|"
1126  "ESO INS GRAT WLEN|ESO INS GRAT ORDER|ESO INS MODE|"
1127  "ESO INS OPTI1 ID)$", 0);
1128  cpl_propertylist_delete(plist);
1129 
1130  /* Copy the QC in paflist */
1131  cpl_propertylist_copy_property_regexp(paflist, qclist, ".", 0);
1132  cpl_propertylist_delete(qclist);
1133 
1134  /* PRO.CATG */
1135  cpl_propertylist_update_string(paflist, CPL_DFS_PRO_CATG, procat);
1136 
1137  /* Save the PAF file */
1138  filename = cpl_sprintf("isaac_spc_arc_set%d_pair%d.paf",
1139  isaac_spc_arc_config.set_nb, isaac_spc_arc_config.pair_nb);
1140  cpl_dfs_save_paf("ISAAC",
1141  "isaac_spc_arc",
1142  paflist,
1143  filename);
1144  cpl_free(filename);
1145  cpl_propertylist_delete(paflist);
1146  return 0;
1147 }
1148 
1149 /*----------------------------------------------------------------------------*/
1156 /*----------------------------------------------------------------------------*/
1157 static int isaac_spc_arc_compare(const cpl_frame * frame1,
1158  const cpl_frame * frame2)
1159 {
1160  int comparison = 1;
1161  const char * file1 = cpl_frame_get_filename(frame1);
1162  const char * file2 = cpl_frame_get_filename(frame2);
1163  cpl_propertylist * plist1 = NULL;
1164  cpl_propertylist * plist2 = NULL;
1165  const char * sval1,
1166  * sval2;
1167  double dval1, dval2;
1168 
1169  bug_if(frame1 == NULL);
1170  bug_if(frame2 == NULL);
1171 
1172  /* Get property lists */
1173  plist1 = cpl_propertylist_load(file1, 0);
1174  any_if("Could not load header from 1st frame %s", file1);
1175 
1176  plist2 = cpl_propertylist_load(file2, 0);
1177  any_if("Could not load header from 2nd frame %s", file2);
1178 
1179  /* Compare the slit used */
1180  sval1 = isaac_pfits_get_opti1_id(plist1);
1181  any_if("Could not get slit from 1st frame %s", file1);
1182 
1183  sval2 = isaac_pfits_get_opti1_id(plist2);
1184  any_if("Could not get slit from 2nd frame %s", file2);
1185 
1186  if (strcmp(sval1, sval2)) comparison = 0;
1187 
1188  /* Compare the resolution */
1189  sval1 = isaac_pfits_get_resolution(plist1);
1190  any_if("Could not get resolution from 1st frame %s", file1);
1191 
1192  sval2 = isaac_pfits_get_resolution(plist2);
1193  any_if("Could not get resolution from 2nd frame %s", file2);
1194 
1195  if (strcmp(sval1, sval2)) comparison = 0;
1196 
1197  /* Compare the central wavelength */
1198  dval1 = isaac_pfits_get_wlen(plist1);
1199  any_if("Could not get wavelength from 1st frame %s", file1);
1200 
1201  dval2 = isaac_pfits_get_wlen(plist2);
1202  any_if("Could not get wavelength from 2nd frame %s", file2);
1203 
1204  if (fabs(dval1-dval2) > 1e-4) comparison = 0;
1205 
1206  end_skip;
1207 
1208  cpl_propertylist_delete(plist1);
1209  cpl_propertylist_delete(plist2);
1210 
1211  return cpl_error_get_code() ? -1 : comparison;
1212 }
1213 
1214 /*----------------------------------------------------------------------------*/
1221 /*----------------------------------------------------------------------------*/
1222 static int * isaac_spc_arc_find_lamps(cpl_frameset * fset)
1223 {
1224  int * lamps;
1225  int nframes;
1226  cpl_frame * cur_frame;
1227  cpl_propertylist * plist;
1228  int xenon, argon;
1229  int i;
1230 
1231  /* Check entries */
1232  if (fset == NULL) return NULL;
1233 
1234  /* Initialise */
1235  nframes = cpl_frameset_get_size(fset);
1236  xenon = argon = 0;
1237 
1238  /* Allocate the output array */
1239  lamps = cpl_malloc(nframes * sizeof(int));
1240 
1241  for (i=0; i<nframes; i++) {
1242  cur_frame = cpl_frameset_get_position(fset, i);
1243  plist=cpl_propertylist_load(cpl_frame_get_filename(cur_frame), 0);
1244  xenon = isaac_is_xenon_lamp_active(plist);
1245  argon = isaac_is_argon_lamp_active(plist);
1246  cpl_propertylist_delete(plist);
1247  if ((argon != 0 && argon != 1) || (xenon != 0 && xenon != 1)) {
1248  cpl_msg_error(cpl_func, "Could not check which lamp is on");
1249  cpl_free(lamps);
1250  return NULL;
1251  }
1252  if (xenon == 1) {
1253  if (argon == 1) lamps[i] = 3;
1254  else if (argon == 0) lamps[i] = 1;
1255  } else if (xenon == 0 ) {
1256  if (argon == 1) lamps[i] = 2;
1257  else if (argon == 0) lamps[i] = 0;
1258  }
1259  }
1260 
1261  /* Free and return */
1262  return lamps;
1263 }
1264 
1265 /*----------------------------------------------------------------------------*/
1271 /*----------------------------------------------------------------------------*/
1272 static int isaac_is_argon_lamp_active(const cpl_propertylist * plist)
1273 {
1274  int status1, status2;
1275 
1276  /* Test error */
1277  if (cpl_error_get_code()) return CPL_ERROR_UNSPECIFIED;
1278  status1 = isaac_pfits_get_lamp1_status(plist);
1279  if (cpl_error_get_code()) return CPL_ERROR_UNSPECIFIED;
1280  if (status1 == 1) {
1281  /* Still has to verify that shutter is open */
1282  status2 = isaac_pfits_get_calshut_status(plist);
1283  if (cpl_error_get_code()) {
1284  cpl_error_reset();
1285  return 1;
1286  }
1287  if (status2 == 1) return 1;
1288  }
1289  return 0;
1290 }
1291 
1292 /*----------------------------------------------------------------------------*/
1298 /*----------------------------------------------------------------------------*/
1299 static int isaac_is_xenon_lamp_active(const cpl_propertylist * plist)
1300 {
1301  int status1, status2;
1302 
1303  /* Test error */
1304  if (cpl_error_get_code()) return CPL_ERROR_UNSPECIFIED;
1305  status1 = isaac_pfits_get_lamp2_status(plist);
1306  if (cpl_error_get_code()) return CPL_ERROR_UNSPECIFIED;
1307  if (status1 == 1) {
1308  /* Still has to verify that shutter is open */
1309  status2 = isaac_pfits_get_calshut_status(plist);
1310  if (cpl_error_get_code()) {
1311  cpl_error_reset();
1312  return 1;
1313  }
1314  if (status2 == 1) return 1;
1315  }
1316  return 0;
1317 }
1318 
1319 
int isaac_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
Definition: isaac_dfs.c:60
int isaac_pfits_get_lamp1_status(const cpl_propertylist *plist)
find out the lamp1 status
Definition: isaac_pfits.c:462
int isaac_pfits_get_lamp2_status(const cpl_propertylist *plist)
find out the lamp2 status
Definition: isaac_pfits.c:492
const char * isaac_pfits_get_opti1_id(const cpl_propertylist *plist)
find out the OPTI1.ID key
Definition: isaac_pfits.c:700
int isaac_pfits_get_calshut_status(const cpl_propertylist *plist)
find out the shutter status
Definition: isaac_pfits.c:121
double isaac_pfits_get_wlen(const cpl_propertylist *plist)
find out the central wavelength
Definition: isaac_pfits.c:865
const char * isaac_pfits_get_arm(const cpl_propertylist *plist)
find out the arm which is active
Definition: isaac_pfits.c:106
const char * isaac_pfits_get_resolution(const cpl_propertylist *plist)
find out the resolution
Definition: isaac_pfits.c:775
const char * isaac_pfits_get_filter(const cpl_propertylist *plist)
find out the filter
Definition: isaac_pfits.c:880
double * isaac_get_disprel_estimate(const char *filename, cpl_size poly_deg)
Estimate the instrument wavelength range.
const char * isaac_extract_filename(const cpl_frameset *self, const char *tag)
Extract the filename of the first frame of the given tag.
Definition: isaac_utils.c:397
cpl_frameset * isaac_extract_frameset(const cpl_frameset *self, const char *tag)
Extract the frames with the given tag from a frameset.
Definition: isaac_utils.c:356