IIINSTRUMENT Pipeline Reference Manual  6.2.2
isaac_img_jitter.c
1 /* $Id: isaac_img_jitter.c,v 1.75 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.75 $
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 <cpl.h>
39 
40 #include "irplib_plugin.h"
41 #include "irplib_utils.h"
42 #include "irplib_calib.h"
43 
44 #include "isaac_utils.h"
45 #include "isaac_pfits.h"
46 #include "isaac_dfs.h"
47 
48 /*-----------------------------------------------------------------------------
49  Define
50  -----------------------------------------------------------------------------*/
51 
52 #define RECIPE_STRING "isaac_img_jitter"
53 
54 #ifndef NEGLIG_OFF_DIFF
55 #define NEGLIG_OFF_DIFF 0.1
56 #endif
57 
58 #define SQR(x) ((x)*(x))
59 
60 #ifdef ISAAC_IMG_ERR_ESTIMATE
61 #ifndef ISAAC_IMG_GAIN
62 /* FIXME: Empirically determined. Use header info (arm dependent) */
63 #define ISAAC_IMG_GAIN 4.5
64 #endif
65 
66 #ifndef ISAAC_IMG_SATURATION_LEVEL
67 /* FIXME: Empirically determined */
68 #define ISAAC_IMG_SATURATION_LEVEL 40000.0
69 #endif
70 #endif
71 
72 
73 /*-----------------------------------------------------------------------------
74  Private Function prototypes
75  -----------------------------------------------------------------------------*/
76 
77 static cpl_image ** isaac_img_jitter_reduce(cpl_frameset *,
78  const cpl_parameterlist *,
79  const cpl_frameset *,
80  const cpl_frameset *,
81  const char *, const char *,
82  const char *, cpl_vector **);
83 static cpl_imagelist ** isaac_img_jitter_load(const cpl_frameset *,
84  const cpl_frameset *);
85 static cpl_vector * isaac_img_jitter_sky(cpl_imagelist **, cpl_imagelist *);
86 static cpl_vector * isaac_img_jitter_sky_running(cpl_imagelist **);
87 static cpl_image ** isaac_img_jitter_saa_nochop(cpl_imagelist *,
88  const cpl_frameset *);
89 static cpl_image ** isaac_img_jitter_saa_chop(cpl_imagelist *,
90  const cpl_frameset *);
91 static int isaac_img_jitter_chopping_classif(cpl_bivector *, int **, int **);
92 static cpl_error_code isaac_img_jitter_sub_row_median(cpl_image *);
93 static cpl_table * isaac_img_jitter_qc(cpl_image *);
94 static double isaac_img_jitter_get_mode(cpl_vector *);
95 static cpl_error_code isaac_img_jitter_save(cpl_frameset *, const cpl_image *,
96  const cpl_image *,
97  const cpl_table *,
98  const cpl_vector *,
99  const cpl_parameterlist *);
100 
101 cpl_recipe_define(isaac_img_jitter, ISAAC_BINARY_VERSION,
102  "Lars Lundin", PACKAGE_BUGREPORT, "2008",
103  "ISAAC imaging jitter recipe",
104  RECIPE_STRING " -- ISAAC imaging jitter recipe.\n"
105  "The files listed in the Set Of Frames (sof-file) "
106  "must be tagged:\n"
107  "raw-file.fits " ISAAC_IMG_JITTER_OBJ_RAW " or\n"
108  "raw-file.fits " ISAAC_IMG_JITTER_SKY_RAW " or\n"
109  "raw-file.fits " ISAAC_IMG_JITTER_CHOP_RAW " or\n"
110  "flat-file.fits " ISAAC_CALIB_FLAT " or\n"
111  "bpm-file.fits " ISAAC_CALIB_BPM " or\n"
112  "dark-file.fits " ISAAC_CALIB_DARK "\n");
113 
114 /*-----------------------------------------------------------------------------
115  Static variables
116  -----------------------------------------------------------------------------*/
117 
118 static struct {
119  /* Inputs */
120  const char * offsets;
121  const char * objects;
122  int oddeven;
123  int sky_minnb;
124  int sky_halfw;
125  int sky_rejmin;
126  int sky_rejmax;
127  int sx;
128  int sy;
129  int mx;
130  int my;
131  cpl_geom_combine comb_meth;
132  int saa_refine;
133  int rej_low;
134  int rej_high;
135  int row_med;
136  int chopping;
137  /* Outputs */
138  double pixscale;
139  double dit;
140  int nb_obj_frames;
141  int nb_sky_frames;
142  int nb_rej_frames;
143  double iq;
144  int nbobjs;
145  double fwhm_pix;
146  double fwhm_arcsec;
147  double fwhm_mode;
148  double angle_med;
149  double ellip_med;
150 } isaac_img_jitter_config;
151 
152 /*-----------------------------------------------------------------------------
153  Functions code
154  -----------------------------------------------------------------------------*/
155 
156 /*----------------------------------------------------------------------------*/
164 /*----------------------------------------------------------------------------*/
165 static
166 cpl_error_code isaac_img_jitter_fill_parameterlist(cpl_parameterlist * self)
167 {
168  const char * context = PACKAGE "." RECIPE_STRING;
169  cpl_error_code err;
170 
171  cpl_ensure_code(self, CPL_ERROR_NULL_INPUT);
172 
173  /* Fill the parameters list */
174 
175  /* --off */
176  err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
177  "offsets", NULL, "off", context,
178  "An optional ASCII specification of the offsets "
179  "in case those in FITS-headers are missing or wrong. "
180  "The file must consist of one line per object FITS-"
181  "file and each line must consist of two "
182  "numbers which represent the shift in pixels of that "
183  "image relative to the first image. The first line "
184  "should thus comprise two zeros. Correct FITS-header "
185  "offsets mean that the i'th X offset can be gotten "
186  "from Xoffset_0 - Xoffset_i, where Xoffset_i is the "
187  "value of ESO SEQ CUMOFFSETX and likewise for Y.");
188  cpl_ensure_code(!err, err);
189 
190  /* --objs */
191  err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
192  "objects", NULL, "objs", context,
193  "objects file");
194  cpl_ensure_code(!err, err);
195 
196  /* --oddeven */
197  err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING, "oddeven",
198  CPL_FALSE, NULL, context, "Flag to "
199  "correct the oddeven column effect");
200  cpl_ensure_code(!err, err);
201 
202  /* --sky_par */
203  err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
204  "sky_par", "10,7,3,3", NULL, context,
205  "Rejection parameters for sky "
206  "filtering");
207  cpl_ensure_code(!err, err);
208 
209  /* --xcorr */
210  err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING, "xcorr",
211  "40,40,65,65", NULL, context, "Cross "
212  "correlation search and measure "
213  "sizes");
214  cpl_ensure_code(!err, err);
215 
216  /* --comb_meth */
217  err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
218  "comb_meth", "union", NULL, context,
219  "union / inter / first");
220  cpl_ensure_code(!err, err);
221 
222  /* --saa_refine */
223  err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
224  "saa_refine", CPL_TRUE, NULL, context,
225  "Flag to refine the offsets");
226  cpl_ensure_code(!err, err);
227 
228  /* --rej */
229  err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING, "rej",
230  "2,2", NULL, context, "Low and high "
231  "number of rejected values");
232  cpl_ensure_code(!err, err);
233 
234  /* --row_med */
235  err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
236  "row_med", CPL_TRUE, NULL, context,
237  "Flag to subtract the median of each "
238  "row");
239  cpl_ensure_code(!err, err);
240 
241  return CPL_ERROR_NONE;
242 }
243 
244 
245 
246 /*----------------------------------------------------------------------------*/
254 /*----------------------------------------------------------------------------*/
255 static int isaac_img_jitter(cpl_frameset * framelist,
256  const cpl_parameterlist * parlist)
257 {
258  const char * sval;
259  const char * badpix;
260  const char * flat;
261  const char * dark;
262  cpl_frameset * objframes = NULL;
263  cpl_frameset * skyframes = NULL;
264  cpl_image ** combined = NULL;
265  cpl_table * objs_stats = NULL;
266  cpl_vector * sky_bg = NULL;
267 
268  bug_if(0);
269 
270  /* Initialise */
271  isaac_img_jitter_config.pixscale = -1.0;
272  isaac_img_jitter_config.dit = -1.0;
273  isaac_img_jitter_config.iq = -1.0;
274  isaac_img_jitter_config.nbobjs = -1;
275  isaac_img_jitter_config.fwhm_pix = -1.0;
276  isaac_img_jitter_config.fwhm_arcsec = -1.0;
277  isaac_img_jitter_config.fwhm_mode = -1.0;
278  isaac_img_jitter_config.offsets = NULL;
279  isaac_img_jitter_config.objects = NULL;
280  isaac_img_jitter_config.nb_obj_frames = 0;
281  isaac_img_jitter_config.nb_rej_frames = 0;
282  isaac_img_jitter_config.nb_sky_frames = 0;
283 
284  /* Retrieve input parameters */
285  /* Offsets */
286  isaac_img_jitter_config.offsets
287  = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
288  "offsets");
289 
290  /* Objects */
291  isaac_img_jitter_config.objects
292  = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
293  "objects");
294 
295  /* Oddeven */
296  isaac_img_jitter_config.oddeven
297  = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
298  "oddeven");
299 
300  /* Rejection parameters for sky filtering */
301  sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
302  "sky_par");
303 
304  bug_if(sval == NULL);
305 
306  skip_if (sscanf(sval, "%d,%d,%d,%d",
307  &isaac_img_jitter_config.sky_minnb,
308  &isaac_img_jitter_config.sky_halfw,
309  &isaac_img_jitter_config.sky_rejmin,
310  &isaac_img_jitter_config.sky_rejmax) != 4);
311 
312  /* Cross correlation windows parameters */
313  sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
314  "xcorr");
315  bug_if(sval == NULL);
316 
317  skip_if (sscanf(sval, "%d,%d,%d,%d",
318  &isaac_img_jitter_config.sx,
319  &isaac_img_jitter_config.sy,
320  &isaac_img_jitter_config.mx,
321  &isaac_img_jitter_config.my) != 4);
322 
323  /* --comb_meth */
324  sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
325  "comb_meth");
326  bug_if(sval == NULL);
327  if (!strcmp(sval, "union"))
328  isaac_img_jitter_config.comb_meth = CPL_GEOM_UNION;
329  else if (!strcmp(sval, "inter"))
330  isaac_img_jitter_config.comb_meth = CPL_GEOM_INTERSECT;
331  else if (!strcmp(sval, "first"))
332  isaac_img_jitter_config.comb_meth = CPL_GEOM_FIRST;
333  else {
334  cpl_msg_error(cpl_func, "Invalid combine method specified");
335  skip_if(1);
336  }
337 
338  /* Refine of offsets */
339  isaac_img_jitter_config.saa_refine
340  = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
341  "saa_refine");
342 
343  /* Number of rejected values in stacking */
344  sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
345  "rej");
346  bug_if(sval == NULL);
347  skip_if (sscanf(sval, "%d,%d",
348  &isaac_img_jitter_config.rej_low,
349  &isaac_img_jitter_config.rej_high) != 2);
350 
351  /* Row median */
352  isaac_img_jitter_config.row_med
353  = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
354  "row_med");
355 
356  /* Identify the RAW and CALIB frames in the input frameset */
357  skip_if (isaac_dfs_set_groups(framelist));
358 
359  /* Retrieve calibration data */
360  flat = isaac_extract_filename(framelist, ISAAC_CALIB_FLAT);
361  dark = isaac_extract_filename(framelist, ISAAC_CALIB_DARK);
362  badpix = isaac_extract_filename(framelist, ISAAC_CALIB_BPM);
363 
364  /* Retrieve raw frames */
365  if ((objframes = isaac_extract_frameset(framelist,
366  ISAAC_IMG_JITTER_OBJ_RAW)) != NULL) {
367  isaac_img_jitter_config.chopping = 0;
368  } else if ((objframes = isaac_extract_frameset(framelist,
369  ISAAC_IMG_JITTER_CHOP_RAW)) != NULL) {
370  isaac_img_jitter_config.chopping = 1;
371  } else {
372  cpl_msg_error(cpl_func, "Cannot find objs frames in the input list");
373  skip_if(1);
374  }
375  skyframes = isaac_extract_frameset(framelist, ISAAC_IMG_JITTER_SKY_RAW);
376 
377  /* Apply the reduction */
378  cpl_msg_info(cpl_func, "Apply the data recombination");
379  cpl_msg_indent_more();
380  if ((combined = isaac_img_jitter_reduce(framelist, parlist, objframes,
381  skyframes, flat,
382  dark, badpix, &sky_bg)) == NULL) {
383  cpl_msg_error(cpl_func, "Cannot recombine the data");
384  cpl_msg_indent_less();
385  skip_if(1);
386  }
387  cpl_msg_indent_less();
388 
389  /* Compute QC parameters from the combined image */
390  cpl_msg_info(cpl_func, "Compute QC parameters from the combined image");
391  cpl_msg_indent_more();
392  if ((objs_stats = isaac_img_jitter_qc(combined[0])) == NULL) {
393  cpl_msg_warning(cpl_func, "Cannot compute all parameters");
394  }
395  cpl_msg_indent_less();
396 
397  /* Save the products */
398  cpl_msg_info(cpl_func, "Save the products");
399  skip_if (isaac_img_jitter_save(framelist, combined[0], combined[1],
400  objs_stats, sky_bg, parlist));
401 
402  end_skip;
403 
404  cpl_frameset_delete(objframes);
405  cpl_frameset_delete(skyframes);
406  if (combined != NULL) {
407  cpl_image_delete(combined[0]);
408  cpl_image_delete(combined[1]);
409  cpl_free(combined);
410  }
411  cpl_table_delete(objs_stats);
412  cpl_vector_delete(sky_bg);
413 
414  return cpl_error_get_code();
415 }
416 
417 /*----------------------------------------------------------------------------*/
428 /*----------------------------------------------------------------------------*/
429 static
430 cpl_image ** isaac_img_jitter_reduce(cpl_frameset * frameset,
431  const cpl_parameterlist * parlist,
432  const cpl_frameset * obj,
433  const cpl_frameset * sky,
434  const char * flat,
435  const char * dark,
436  const char * bpm,
437  cpl_vector ** skybg)
438 {
439 #ifdef ISAAC_IMG_ERR_ESTIMATE
440  cpl_propertylist * qclist;
441  cpl_imagelist * err;
442 #endif
443  cpl_imagelist ** in;
444  cpl_image ** combined;
445  cpl_imagelist * corrected;
446  cpl_image * cur_im;
447  int i;
448 
449  cpl_ensure(frameset != NULL, CPL_ERROR_NULL_INPUT, NULL);
450  cpl_ensure(parlist != NULL, CPL_ERROR_NULL_INPUT, NULL);
451 
452  /* Initialise */
453  *skybg = NULL;
454  combined = NULL;
455 
456  /* Load the input data */
457  cpl_msg_info(cpl_func, "Load the input data");
458  cpl_msg_indent_more();
459  if ((in = isaac_img_jitter_load(obj, sky)) == NULL) {
460  cpl_msg_error(cpl_func, "Cannot load input data");
461  cpl_msg_indent_less();
462  return NULL;
463  }
464  cpl_msg_indent_less();
465 
466  /* Apply the odd-even correction */
467  if (isaac_img_jitter_config.oddeven) {
468  cpl_msg_info(cpl_func, "Apply the odd-even effect correction");
469  cpl_msg_indent_more();
470  corrected = cpl_imagelist_new();
471  for (i=0; i<cpl_imagelist_get_size(in[0]); i++) {
472  cpl_msg_info(cpl_func, "Correct object frame nb %d", i+1);
473  if ((cur_im = isaac_oddeven_correct(
474  cpl_imagelist_get(in[0], i))) == NULL) {
475  cpl_msg_warning(cpl_func,"Problem in odd-even corr. %d",i+1);
476  cpl_imagelist_delete(corrected);
477  corrected = NULL;
478  break;
479  }
480  cpl_imagelist_set(corrected, cur_im, i);
481  }
482  /* Odd/even correction successfull */
483  if (corrected != NULL) {
484  cpl_imagelist_delete(in[0]);
485  in[0] = corrected;
486  }
487  cpl_msg_indent_less();
488  }
489 
490 #ifdef ISAAC_IMG_ERR_ESTIMATE
491  /*----------------------------------------------------------------------------*/
492  /* Save the imagelist before applying the correction */
493 
494  err = cpl_imagelist_duplicate(in[0]);
495 
496  /* Dark correction */
497  if (dark != NULL) {
498  cpl_image * dark_image;
499 
500  cpl_msg_info(cpl_func, "Error propagation: Subtract the dark to the images");
501  /* Load the dark image */
502  if ((dark_image = cpl_image_load(dark, CPL_TYPE_FLOAT, 0, 0)) == NULL) {
503  cpl_msg_error(cpl_func, "Cannot load the dark %s", dark);
504  return NULL;
505  }
506  /* Apply the dark correction to the images */
507  if (cpl_imagelist_subtract_image(err, dark_image)!=CPL_ERROR_NONE) {
508  cpl_msg_error(cpl_func, "Cannot apply the dark to the images");
509  cpl_image_delete(dark_image);
510  return NULL;
511  }
512  cpl_image_delete(dark_image);
513  }
514 
515 
516  /* Apply the bad pixel mask requested */
517  if (bpm != NULL) {
518  cpl_image * bpm_im;
519  cpl_msg_info(cpl_func, "Error propagation: Correct the bad pixels in the images");
520  /* Load the bad pixels image - as double */
521  if ((bpm_im = cpl_image_load(bpm, CPL_TYPE_DOUBLE, 0, 0)) == NULL) {
522  cpl_msg_error(cpl_func, "Cannot load the bad pixel map %s", bpm);
523  return NULL;
524  }
525  /* Invert the map */
526  cpl_image_threshold(bpm_im, 0.4, 0.6, 1, 0);
527 
528  cpl_imagelist_multiply_image(err, bpm_im);
529 
530  /* cpl_image_save(bpm_im,"test.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_CREATE);*/
531  cpl_image_delete(bpm_im);
532  }
533 
534  cpl_imagelist_threshold(err, 1, ISAAC_IMG_SATURATION_LEVEL,
535  FLT_MAX, FLT_MAX);
536  cpl_imagelist_divide_scalar(err, ISAAC_IMG_GAIN);
537  cpl_imagelist_power(err, 0.5);
538 
539  /* Flat-field correction */
540  if (flat != NULL) {
541  cpl_image * flat_image;
542  cpl_msg_info(cpl_func, "Error propagation: Divide the images by the flatfield");
543  /* Load the flat image */
544  if ((flat_image = cpl_image_load(flat, CPL_TYPE_FLOAT, 0, 0)) == NULL) {
545  cpl_msg_error(cpl_func, "Cannot load the flat field %s", flat);
546  return NULL;
547  }
548  /* Apply the flatfield correction to the images */
549  if (cpl_imagelist_divide_image(err, flat_image)!=CPL_ERROR_NONE) {
550  cpl_msg_error(cpl_func, "Cannot apply the flatfield to the images");
551  cpl_image_delete(flat_image);
552  return NULL;
553  }
554  cpl_image_delete(flat_image);
555  }
556  cpl_imagelist_threshold(err, 1, ISAAC_IMG_SATURATION_LEVEL,
557  FLT_MAX, FLT_MAX);
558 
559  /*----------------------------------------------------------------------------*/
560 #endif
561 
562  /* Apply the calibrations */
563  if (flat || dark || bpm) {
564  cpl_msg_info(cpl_func, "Apply the calibrations");
565  cpl_msg_indent_more();
566  if (irplib_flat_dark_bpm_calib(in[0], flat, dark, bpm) == -1) {
567  /* Calibrate the objects */
568  cpl_msg_error(cpl_func, "Cannot calibrate the objects");
569  cpl_imagelist_delete(in[0]);
570  if (in[1]) cpl_imagelist_delete(in[1]);
571  cpl_free(in);
572  cpl_msg_indent_less();
573  return NULL;
574  }
575  if (in[1]) {
576  if (irplib_flat_dark_bpm_calib(in[1], flat, dark, bpm) == -1) {
577  /* Calibrate the sky */
578  cpl_msg_error(cpl_func, "Cannot calibrate the sky");
579  cpl_imagelist_delete(in[0]);
580  if (in[1]) cpl_imagelist_delete(in[1]);
581  cpl_free(in);
582  cpl_msg_indent_less();
583  return NULL;
584  }
585  }
586  cpl_msg_indent_less();
587  }
588 
589 
590 #ifdef ISAAC_IMG_ERR_ESTIMATE
591  /* Save the imagelist as intermediate product */
592 
593  qclist = cpl_propertylist_new();
594 
595  cpl_propertylist_update_string(qclist, CPL_DFS_PRO_CATG, "ISAAC_IMAGELIST");
596  if(cpl_dfs_save_imagelist(frameset,
597  NULL,
598  parlist,
599  frameset,
600  NULL,
601  in[0],
602  CPL_BPP_IEEE_FLOAT,
603  RECIPE_STRING,
604  qclist,
605  NULL,
606  PACKAGE "/" PACKAGE_VERSION,
607  "isaac_img_imagelist.fits")) {
608  /* Propagate the error */
609  (void)cpl_error_set_where(cpl_func);
610  }
611 
612  cpl_propertylist_update_string(qclist, CPL_DFS_PRO_CATG, "ISAAC_IMAGELISTERR");
613  if(cpl_dfs_save_imagelist(frameset,
614  NULL,
615  parlist,
616  frameset,
617  NULL,
618  err,
619  CPL_BPP_IEEE_FLOAT,
620  RECIPE_STRING,
621  qclist,
622  NULL,
623  PACKAGE "/" PACKAGE_VERSION,
624  "isaac_img_imagelist_error.fits")) {
625  /* Propagate the error */
626  (void)cpl_error_set_where(cpl_func);
627  }
628 
629  cpl_propertylist_delete(qclist);
630  cpl_imagelist_delete(err);
631 #endif
632 
633  /* Apply the sky correction only in jitter mode */
634  if (isaac_img_jitter_config.chopping == 0) {
635  cpl_msg_info(cpl_func, "Sky estimation and correction");
636  cpl_msg_indent_more();
637  if ((*skybg = isaac_img_jitter_sky(&(in[0]), in[1])) == NULL) {
638  cpl_msg_error(cpl_func, "Cannot estimate the sky");
639  cpl_imagelist_delete(in[0]);
640  if (in[1]) cpl_imagelist_delete(in[1]);
641  cpl_free(in);
642  cpl_msg_indent_less();
643  return NULL;
644  }
645  cpl_msg_indent_less();
646  }
647  isaac_img_jitter_config.nb_obj_frames = cpl_imagelist_get_size(in[0]);
648  if (in[1] != NULL)
649  isaac_img_jitter_config.nb_sky_frames = cpl_imagelist_get_size(in[1]);
650  if (in[1]) cpl_imagelist_delete(in[1]);
651  in[1] = NULL;
652 
653  /* Apply the shift and add */
654  cpl_msg_info(cpl_func, "Shift and add");
655  cpl_msg_indent_more();
656  if (isaac_img_jitter_config.chopping == 0) {
657  combined = isaac_img_jitter_saa_nochop(in[0], obj);
658  } else if (isaac_img_jitter_config.chopping == 1) {
659  combined = isaac_img_jitter_saa_chop(in[0], obj);
660  }
661  if (combined == NULL) {
662  cpl_msg_error(cpl_func, "Cannot apply the shift and add");
663  cpl_imagelist_delete(in[0]);
664  cpl_free(in);
665  if (*skybg != NULL) cpl_vector_delete(*skybg);
666  *skybg = NULL;
667  cpl_msg_indent_less();
668  return NULL;
669  }
670  cpl_imagelist_delete(in[0]);
671  cpl_free(in);
672  cpl_msg_indent_less();
673 
674  /* Post processing on the combined image */
675  if (isaac_img_jitter_config.row_med) {
676  cpl_msg_info(cpl_func, "Subtract the median from each row");
677  skip_if(isaac_img_jitter_sub_row_median(combined[0]));
678  }
679 
680  end_skip;
681 
682  return combined;
683 }
684 
685 /*----------------------------------------------------------------------------*/
692 /*----------------------------------------------------------------------------*/
693 static cpl_imagelist ** isaac_img_jitter_load(
694  const cpl_frameset * obj,
695  const cpl_frameset * sky)
696 {
697  cpl_imagelist ** isets;
698  cpl_imagelist * chop_b;
699  const cpl_frame * frame;
700  cpl_propertylist * plist;
701  const char * sval;
702 
703  /* Test entries */
704  if (obj == NULL) return NULL;
705 
706  /* Check if ok */
707  cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), NULL);
708 
709  /* Get the frame type pixscale and DIT value */
710  frame = cpl_frameset_get_position_const(obj, 0);
711  cpl_ensure(frame != NULL, cpl_error_get_code(), NULL);
712 
713  plist=cpl_propertylist_load(cpl_frame_get_filename(frame), 0);
714  cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), NULL);
715 
716  isaac_img_jitter_config.pixscale = isaac_pfits_get_pixscale(plist);
717  isaac_img_jitter_config.dit = isaac_pfits_get_dit(plist);
718  sval = isaac_pfits_get_frame_type(plist);
719  if (sval == NULL) {
720  cpl_msg_error(cpl_func, "Could not get frame type for jitter");
721  cpl_propertylist_delete(plist);
722  return NULL;
723  } else if ((isaac_img_jitter_config.chopping==0) && strcmp(sval, "INT")) {
724  cpl_msg_error(cpl_func, "Wrong type for jitter: %s - Should be INT",
725  sval);
726  cpl_propertylist_delete(plist);
727  return NULL;
728  } else if ((isaac_img_jitter_config.chopping==1) && strcmp(sval, "CUBE1")) {
729  cpl_msg_error(cpl_func, "Wrong type for chopping: %s - Should be CUBE1",
730  sval);
731  cpl_propertylist_delete(plist);
732  return NULL;
733  }
734  cpl_propertylist_delete(plist);
735  if (cpl_error_get_code()) {
736  cpl_msg_error(cpl_func, "Missing keyword in FITS header");
737  return NULL;
738  }
739 
740  /* Allocate the image sets */
741  isets = cpl_malloc(2 * sizeof(cpl_imagelist *));
742 
743  /* Check if chop or nochop */
744  if (isaac_img_jitter_config.chopping == 0) {
745  isets[0] = cpl_imagelist_load_frameset(obj, CPL_TYPE_FLOAT, 1, 0);
746  if (sky != NULL)
747  isets[1] = cpl_imagelist_load_frameset(sky, CPL_TYPE_FLOAT, 1, 0);
748  else isets[1] = NULL;
749  } else if (isaac_img_jitter_config.chopping == 1) {
750  isets[1] = NULL;
751  isets[0] = cpl_imagelist_load_frameset(obj, CPL_TYPE_FLOAT, 1, 0);
752  chop_b = cpl_imagelist_load_frameset(obj, CPL_TYPE_FLOAT, 2, 0);
753  cpl_imagelist_subtract(isets[0], chop_b);
754  cpl_imagelist_delete(chop_b);
755  }
756 
757  /* Check if at least the objects are there */
758  if (isets[0] == NULL) {
759  cpl_msg_error(cpl_func, "The objects frames could not be loaded");
760  if (isets[1] != NULL) cpl_imagelist_delete(isets[1]);
761  cpl_free(isets);
762  return NULL;
763  }
764  /* Return */
765  return isets;
766 }
767 
768 /*----------------------------------------------------------------------------*/
775 /*----------------------------------------------------------------------------*/
776 static cpl_vector * isaac_img_jitter_sky(
777  cpl_imagelist ** objs,
778  cpl_imagelist * skys)
779 {
780  cpl_image * sky;
781  cpl_vector * bg;
782  int sky_method;
783  int nframes, nskys;
784  double median;
785  cpl_image * cur_ima;
786  int i;
787 
788  /* Initialise */
789  bg = NULL;
790  nframes = cpl_imagelist_get_size(*objs);
791 
792  /* Decide the sky method */
793  if (isaac_img_jitter_config.sky_minnb > nframes) sky_method = 1;
794  else sky_method = 2;
795 
796  /* Compute the sky frame */
797  if (skys != NULL) {
798  cpl_msg_info(cpl_func, "Median of sky images");
799  /* Get the median of the sky images */
800  nskys = cpl_imagelist_get_size(skys);
801  bg = cpl_vector_new(nskys);
802  for (i=0; i<nskys; i++) {
803  median = cpl_image_get_median(cpl_imagelist_get(skys, i));
804  cpl_vector_set(bg, i, median);
805  }
806  /* Use sky images */
807  if ((sky = cpl_imagelist_collapse_median_create(skys)) == NULL) {
808  cpl_msg_error(cpl_func, "Cannot compute the median of sky images");
809  cpl_vector_delete(bg);
810  return NULL;
811  }
812  /* Correct the objects images */
813  if (cpl_imagelist_subtract_image(*objs, sky) != CPL_ERROR_NONE) {
814  cpl_msg_error(cpl_func, "Cannot corr. the obj images from the sky");
815  cpl_image_delete(sky);
816  cpl_vector_delete(bg);
817  return NULL;
818  }
819  cpl_image_delete(sky);
820  /* Normalise the object planes */
821  for (i=0; i<nframes; i++) {
822  cur_ima = cpl_imagelist_get(*objs, i);
823  median = cpl_image_get_median(cur_ima);
824  cpl_image_subtract_scalar(cur_ima, median);
825  }
826  } else if (sky_method == 1) {
827  cpl_msg_info(cpl_func, "Median of object images");
828  /* Use objs images */
829  if ((sky = cpl_imagelist_collapse_median_create(*objs)) == NULL) {
830  cpl_msg_error(cpl_func, "Cannot compute the median of obj images");
831  return NULL;
832  }
833  /* Correct the objects images */
834  if (cpl_imagelist_subtract_image(*objs, sky) != CPL_ERROR_NONE) {
835  cpl_msg_error(cpl_func, "Cannot corr. the obj images from the sky");
836  cpl_image_delete(sky);
837  return NULL;
838  }
839  /* Create a 1 value vector */
840  bg = cpl_vector_new(1);
841  cpl_vector_set(bg, 0, cpl_image_get_median(sky));
842  cpl_image_delete(sky);
843  /* Normalise the object planes */
844  for (i=0; i<nframes; i++) {
845  cur_ima = cpl_imagelist_get(*objs, i);
846  median = cpl_image_get_median(cur_ima);
847  cpl_image_subtract_scalar(cur_ima, median);
848  }
849  } else if (sky_method == 2) {
850  cpl_msg_info(cpl_func, "Running filter on object images");
851  /* Use objects images */
852  if ((bg = isaac_img_jitter_sky_running(objs)) == NULL) {
853  cpl_msg_error(cpl_func,
854  "Cannot apply the running filter for the sky");
855  return NULL;
856  }
857  }
858  /* Free and return */
859  return bg;
860 }
861 
862 /*----------------------------------------------------------------------------*/
881 /*----------------------------------------------------------------------------*/
882 static cpl_vector * isaac_img_jitter_sky_running(cpl_imagelist ** in)
883 {
884  int rejmin, rejmax, halfw;
885  cpl_imagelist * filtres;
886  int ni, nx, ny, pos;
887  cpl_vector * medians;
888  cpl_image * cur_ima;
889  float * pcur_ima;
890  cpl_image * tmp_ima;
891  float * ptmp_ima;
892  cpl_vector * localwin;
893  int fr_p, to_p, n_curp;
894  cpl_vector * bg;
895  double bg_val, out;
896  float one_med;
897  int i, j, k;
898 
899  /* Test entries */
900  if (in==NULL || *in == NULL) return NULL;
901 
902  /* Initialise */
903  rejmin = isaac_img_jitter_config.sky_rejmin;
904  rejmax = isaac_img_jitter_config.sky_rejmax;
905  halfw = isaac_img_jitter_config.sky_halfw;
906  ni = cpl_imagelist_get_size(*in);
907  cur_ima = cpl_imagelist_get(*in, 0);
908  nx = cpl_image_get_size_x(cur_ima);
909  ny = cpl_image_get_size_y(cur_ima);
910 
911  /* Tests on validity of rejection parameters */
912  if (((rejmin+rejmax)>=halfw) || (halfw<1) || (rejmin<0) || (rejmax<0)) {
913  cpl_msg_error(cpl_func, "cannot run filter with rej parms %d (%d-%d)",
914  halfw, rejmin, rejmax);
915  return NULL;
916  }
917  /* Pre-compute median value in each plane */
918  medians = cpl_vector_new(ni);
919  for (i=0; i<ni; i++) {
920  cur_ima = cpl_imagelist_get(*in, i);
921  cpl_vector_set(medians, i, cpl_image_get_median(cur_ima));
922  }
923  /* Allocate output cube */
924  filtres = cpl_imagelist_new();
925 
926  /* Allocate output bg */
927  bg = cpl_vector_new(ni);
928 
929  /* Main loop over input planes */
930  for (k=0; k<ni; k++) {
931  /* Allocate output plane */
932  tmp_ima = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
933  ptmp_ima = cpl_image_get_data_float(tmp_ima);
934  /* Compute border indices */
935  fr_p = k - halfw;
936  to_p = k + halfw;
937  if (fr_p<0) fr_p=0;
938  if (to_p>(ni-1)) to_p=ni-1;
939 
940  /* Number of valid planes to consider after edge effects */
941  n_curp = to_p - fr_p;
942 
943  /* Allocate local window */
944  localwin = cpl_vector_new(n_curp);
945 
946  bg_val = 0.0;
947  /* Loop over all pixels */
948  for (pos=0; pos<nx*ny; pos++) {
949  /* Fill up local window */
950  j=0;
951  for (i=fr_p; i<=to_p; i++) {
952  if (i!=k) {
953  cur_ima = cpl_imagelist_get(*in, i);
954  pcur_ima = cpl_image_get_data_float(cur_ima);
955  cpl_vector_set(localwin, j,
956  (double)pcur_ima[pos]-cpl_vector_get(medians, i));
957  j++;
958  }
959  }
960  /* Sort window */
961  cpl_vector_sort(localwin, 1);
962  /* Reject min and max, accumulate other pixels */
963  out = 0.0;
964  for (i=rejmin; i<(n_curp-rejmax); i++) {
965  out += cpl_vector_get(localwin, i);
966  }
967  /* Take the mean */
968  out /= (double)(n_curp - rejmin - rejmax);
969  /* Assign value */
970  cur_ima = cpl_imagelist_get(*in, k);
971  pcur_ima = cpl_image_get_data_float(cur_ima);
972  ptmp_ima[pos] = pcur_ima[pos] -
973  (float)(out + cpl_vector_get(medians, k));
974 
975  bg_val += (out+cpl_vector_get(medians, k));
976  }
977  cpl_vector_delete(localwin);
978  cpl_vector_set(bg, k, bg_val/(nx*ny));
979  cpl_imagelist_set(filtres, tmp_ima, k);
980  }
981  cpl_imagelist_delete(*in);
982  cpl_vector_delete(medians);
983 
984  /* Subtract median from each frame */
985  for (i=0; i<ni; i++) {
986  cur_ima = cpl_imagelist_get(filtres, i);
987  one_med = cpl_image_get_median(cur_ima);
988  cpl_image_subtract_scalar(cur_ima, one_med);
989  }
990  *in = filtres;
991  return bg;
992 }
993 
994 /*----------------------------------------------------------------------------*/
1001 /*----------------------------------------------------------------------------*/
1002 static cpl_image ** isaac_img_jitter_saa_nochop(
1003  cpl_imagelist * in,
1004  const cpl_frameset * objframes)
1005 {
1006  const cpl_frame * frame;
1007  cpl_propertylist * plist;
1008  cpl_bivector * offsets_est;
1009  double * offsets_est_x;
1010  double * offsets_est_y;
1011  cpl_bivector * objs;
1012  double * objs_x;
1013  double * objs_y;
1014  cpl_apertures * aperts;
1015  cpl_image ** combined;
1016  cpl_vector * thresh_vect;
1017  cpl_image * diff;
1018  int nfiles;
1019  int nima;
1020  int refine =
1021  isaac_img_jitter_config.saa_refine ? 1 : 0;
1022  int i;
1023 
1024  /* Get the number of images */
1025  nfiles = cpl_imagelist_get_size(in);
1026  if (cpl_frameset_get_size(objframes) != nfiles) {
1027  cpl_msg_error(cpl_func, "Invalid input objects sizes");
1028  return NULL;
1029  }
1030 
1031  /* Get the offsets estimation of each input file pair */
1032  cpl_msg_info(cpl_func, "Get the offsets estimation");
1033  offsets_est = NULL;
1034  if (isaac_img_jitter_config.offsets &&
1035  isaac_img_jitter_config.offsets[0] != (char)0) {
1036  /* A file has been provided on the command line */
1037  offsets_est = cpl_bivector_read(isaac_img_jitter_config.offsets);
1038  if ((offsets_est==NULL)||(cpl_bivector_get_size(offsets_est)!=nfiles)) {
1039  cpl_msg_error(cpl_func, "Cannot get offsets from %s",
1040  isaac_img_jitter_config.offsets);
1041  return NULL;
1042  }
1043  } else {
1044  /* Get the offsets from the header */
1045  offsets_est = cpl_bivector_new(nfiles);
1046  offsets_est_x = cpl_bivector_get_x_data(offsets_est);
1047  offsets_est_y = cpl_bivector_get_y_data(offsets_est);
1048  for (i=0; i<nfiles; i++) {
1049  if (cpl_error_get_code()) {
1050  cpl_bivector_delete(offsets_est);
1051  offsets_est = NULL;
1052  break;
1053  }
1054  /* X and Y offsets */
1055  frame = cpl_frameset_get_position_const(objframes, i);
1056  plist=cpl_propertylist_load(cpl_frame_get_filename(frame),0);
1057  offsets_est_x[i] = -1.0 * isaac_pfits_get_cumoffsetx(plist);
1058  offsets_est_y[i] = -1.0 * isaac_pfits_get_cumoffsety(plist);
1059  cpl_propertylist_delete(plist);
1060  if (cpl_error_get_code()) {
1061  cpl_msg_warning(cpl_func, "Cannot get offsets from header");
1062  cpl_bivector_delete(offsets_est);
1063  offsets_est = NULL;
1064  break;
1065  }
1066  if (i > 0) {
1067  /* Subtract the first offset from all offsets */
1068  offsets_est_x[i] -= offsets_est_x[0];
1069  offsets_est_y[i] -= offsets_est_y[0];
1070  }
1071  }
1072  if (i == nfiles) {
1073  offsets_est_x[0] = offsets_est_y[0] = 0.0;
1074  }
1075  }
1076 
1077  /* Read the provided objects file if provided */
1078  objs = NULL;
1079  if (isaac_img_jitter_config.objects &&
1080  isaac_img_jitter_config.objects[0] != (char)0) {
1081  cpl_msg_info(cpl_func, "Get the user provided correlation objects");
1082  /* A file has been provided on the command line */
1083  objs = cpl_bivector_read(isaac_img_jitter_config.objects);
1084  if (objs==NULL) {
1085  cpl_msg_error(cpl_func, "Cannot get objects from %s",
1086  isaac_img_jitter_config.objects);
1087  if (offsets_est) cpl_bivector_delete(offsets_est);
1088  return NULL;
1089  }
1090  }
1091 
1092  /* Get a correlation point from the difference of the first images */
1093  if (objs == NULL) {
1094  cpl_msg_info(cpl_func, "Get a cross-correlation point");
1095  thresh_vect = cpl_vector_new(4);
1096  cpl_vector_set(thresh_vect, 0, 5.0);
1097  cpl_vector_set(thresh_vect, 1, 2.0);
1098  cpl_vector_set(thresh_vect, 2, 1.0);
1099  cpl_vector_set(thresh_vect, 3, 0.5);
1100  diff = cpl_image_subtract_create(cpl_imagelist_get(in, 0),
1101  cpl_imagelist_get(in, 1));
1102  if ((aperts = cpl_apertures_extract_window(diff, thresh_vect,
1103  200, 200, 800, 800, NULL)) == NULL) {
1104  cpl_msg_error(cpl_func, "Cannot find any cross-correlation point");
1105  if (offsets_est) cpl_bivector_delete(offsets_est);
1106  cpl_vector_delete(thresh_vect);
1107  cpl_image_delete(diff);
1108  return NULL;
1109  }
1110  cpl_image_delete(diff);
1111  cpl_vector_delete(thresh_vect);
1112  cpl_apertures_sort_by_npix(aperts);
1113  objs = cpl_bivector_new(1);
1114  objs_x = cpl_bivector_get_x_data(objs);
1115  objs_y = cpl_bivector_get_y_data(objs);
1116  objs_x[0] = cpl_apertures_get_pos_x(aperts, 1);
1117  objs_y[0] = cpl_apertures_get_pos_y(aperts, 1);
1118  cpl_apertures_delete(aperts);
1119  if (objs == NULL) {
1120  cpl_msg_error(cpl_func, "Cannot find any cross-correlation point");
1121  if (offsets_est) cpl_bivector_delete(offsets_est);
1122  return NULL;
1123  }
1124  cpl_msg_info(cpl_func,
1125  "Correlation point: %g %g\n", objs_x[0], objs_y[0]);
1126  }
1127 
1128  /* Recombine the images */
1129  cpl_msg_info(cpl_func, "Recombine the images set");
1130  cpl_msg_indent_more();
1131  if ((combined = cpl_geom_img_offset_combine(in, offsets_est, refine, objs,
1132  NULL, NULL,
1133  isaac_img_jitter_config.sx,
1134  isaac_img_jitter_config.sy,
1135  isaac_img_jitter_config.mx,
1136  isaac_img_jitter_config.my,
1137  isaac_img_jitter_config.rej_low,
1138  isaac_img_jitter_config.rej_high,
1139  isaac_img_jitter_config.comb_meth)) == NULL) {
1140  cpl_msg_error(cpl_func, "Cannot recombine the images");
1141  if (offsets_est) cpl_bivector_delete(offsets_est);
1142  cpl_bivector_delete(objs);
1143  cpl_msg_indent_less();
1144  return NULL;
1145  }
1146  /* Update QC params */
1147  i = (int)(cpl_image_get_max(combined[1]));
1148  nima = cpl_imagelist_get_size(in);
1149  if ((nima > 3) && (nima>2*
1150  (isaac_img_jitter_config.rej_low+isaac_img_jitter_config.rej_high)))
1151  i += isaac_img_jitter_config.rej_low+isaac_img_jitter_config.rej_high;
1152  isaac_img_jitter_config.nb_rej_frames =
1153  isaac_img_jitter_config.nb_obj_frames - i;
1154  isaac_img_jitter_config.nb_obj_frames = i;
1155  cpl_msg_indent_less();
1156 
1157  /* Free and return */
1158  if (offsets_est) cpl_bivector_delete(offsets_est);
1159  cpl_bivector_delete(objs);
1160  return combined;
1161 }
1162 
1163 
1164 /*----------------------------------------------------------------------------*/
1171 /*----------------------------------------------------------------------------*/
1172 static cpl_image ** isaac_img_jitter_saa_chop(
1173  cpl_imagelist * in,
1174  const cpl_frameset * objframes)
1175 {
1176  const cpl_frame * frame;
1177  cpl_propertylist * plist;
1178  cpl_bivector * offsets_est;
1179  cpl_bivector * offsets_est_nod;
1180  double * offsets_est_x;
1181  double * offsets_est_y;
1182  double * offsets_est_nod_x;
1183  double * offsets_est_nod_y;
1184  cpl_bivector * objs;
1185  cpl_image ** combined;
1186  cpl_vector * thresh_vect;
1187  int nfiles, nb_chop;
1188  int * chop_a;
1189  int * chop_b;
1190  cpl_imagelist * nodded;
1191  cpl_image * tmp_ima;
1192  int refine =
1193  isaac_img_jitter_config.saa_refine ? 1 : 0;
1194  int i;
1195 
1196  /* Get the number of images */
1197  nfiles = cpl_imagelist_get_size(in);
1198  if (cpl_frameset_get_size(objframes) != nfiles) {
1199  cpl_msg_error(cpl_func, "Invalid input objects sizes");
1200  return NULL;
1201  }
1202 
1203  /* Get the offsets estimation of each input file pair */
1204  cpl_msg_info(cpl_func, "Get the offsets estimation");
1205  offsets_est = NULL;
1206  if (isaac_img_jitter_config.offsets &&
1207  isaac_img_jitter_config.offsets[0] != (char)0) {
1208  /* A file has been provided on the command line */
1209  offsets_est = cpl_bivector_read(isaac_img_jitter_config.offsets);
1210  if ((offsets_est==NULL) ||
1211  (cpl_bivector_get_size(offsets_est) != nfiles)) {
1212  cpl_msg_error(cpl_func, "Cannot get offsets from %s",
1213  isaac_img_jitter_config.offsets);
1214  return NULL;
1215  }
1216  offsets_est_x = cpl_bivector_get_x_data(offsets_est);
1217  offsets_est_y = cpl_bivector_get_y_data(offsets_est);
1218  } else {
1219  /* Get the offsets from the header */
1220  offsets_est = cpl_bivector_new(nfiles);
1221  offsets_est_x = cpl_bivector_get_x_data(offsets_est);
1222  offsets_est_y = cpl_bivector_get_y_data(offsets_est);
1223  for (i=0; i<nfiles; i++) {
1224  if (cpl_error_get_code()) {
1225  cpl_bivector_delete(offsets_est);
1226  return NULL;
1227  }
1228  /* X and Y offsets */
1229  frame = cpl_frameset_get_position_const(objframes, i);
1230  plist=cpl_propertylist_load(cpl_frame_get_filename(frame),0);
1231  offsets_est_x[i] = -1.0 * isaac_pfits_get_cumoffsetx(plist);
1232  offsets_est_y[i] = -1.0 * isaac_pfits_get_cumoffsety(plist);
1233  cpl_propertylist_delete(plist);
1234  if (cpl_error_get_code()) {
1235  cpl_msg_warning(cpl_func, "Cannot get offsets from header");
1236  cpl_bivector_delete(offsets_est);
1237  return NULL;
1238  }
1239  }
1240  /* Subtract the first offset to all offsets */
1241  for (i=1; i<nfiles; i++) {
1242  offsets_est_x[i] -= offsets_est_x[0];
1243  offsets_est_y[i] -= offsets_est_y[0];
1244  }
1245  offsets_est_x[0] = offsets_est_y[0] = 0.00;
1246  }
1247 
1248  /* Classify the A and B nodding positions using the offsets */
1249  if ((nb_chop=isaac_img_jitter_chopping_classif(offsets_est,
1250  &chop_a, &chop_b)) == -1) {
1251  cpl_msg_error(cpl_func, "cannot classify chopped frames");
1252  cpl_bivector_delete(offsets_est);
1253  return NULL;
1254  }
1255 
1256  /* Create the nodded frames chop_a-chop_b */
1257  nodded = cpl_imagelist_new();
1258  for (i=0; i<nb_chop; i++) {
1259  tmp_ima = cpl_image_subtract_create(
1260  cpl_imagelist_get(in, chop_a[i]),
1261  cpl_imagelist_get(in, chop_b[i]));
1262  cpl_imagelist_set(nodded, tmp_ima, i);
1263  }
1264 
1265  /* Update the offsets estimations between the nodded frames */
1266  offsets_est_nod = cpl_bivector_new(nb_chop);
1267  offsets_est_nod_x = cpl_bivector_get_x_data(offsets_est_nod);
1268  offsets_est_nod_y = cpl_bivector_get_y_data(offsets_est_nod);
1269  for (i=0; i<nb_chop; i++) {
1270  offsets_est_nod_x[i] = offsets_est_x[chop_a[i]];
1271  offsets_est_nod_y[i] = offsets_est_y[chop_a[i]];
1272  }
1273  cpl_bivector_delete(offsets_est);
1274  cpl_free(chop_a);
1275  cpl_free(chop_b);
1276 
1277  /* Read the provided objects file if provided */
1278  objs = NULL;
1279  if (isaac_img_jitter_config.objects &&
1280  isaac_img_jitter_config.objects[0] != (char)0) {
1281  cpl_msg_info(cpl_func, "Get the user provided correlation objects");
1282  /* A file has been provided on the command line */
1283  objs = cpl_bivector_read(isaac_img_jitter_config.objects);
1284  if (objs==NULL) {
1285  cpl_msg_error(cpl_func, "Cannot get objects from %s",
1286  isaac_img_jitter_config.objects);
1287  cpl_bivector_delete(offsets_est_nod);
1288  cpl_imagelist_delete(nodded);
1289  return NULL;
1290  }
1291  }
1292 
1293  /* Create the vector for the detection thresholds */
1294  thresh_vect = cpl_vector_new(4);
1295  cpl_vector_set(thresh_vect, 0, 5.0);
1296  cpl_vector_set(thresh_vect, 1, 2.0);
1297  cpl_vector_set(thresh_vect, 2, 1.0);
1298  cpl_vector_set(thresh_vect, 3, 0.5);
1299 
1300  /* Recombine the images */
1301  cpl_msg_info(cpl_func, "Recombine the images set");
1302  cpl_msg_indent_more();
1303  if ((combined = cpl_geom_img_offset_combine(nodded, offsets_est_nod,
1304  refine, objs, thresh_vect, NULL,
1305  isaac_img_jitter_config.sx,
1306  isaac_img_jitter_config.sy,
1307  isaac_img_jitter_config.mx,
1308  isaac_img_jitter_config.my,
1309  isaac_img_jitter_config.rej_low,
1310  isaac_img_jitter_config.rej_high,
1311  isaac_img_jitter_config.comb_meth)) == NULL) {
1312  cpl_msg_error(cpl_func, "Cannot recombine the images");
1313  cpl_bivector_delete(offsets_est_nod);
1314  cpl_imagelist_delete(nodded);
1315  if (objs) cpl_bivector_delete(objs);
1316  cpl_vector_delete(thresh_vect);
1317  cpl_msg_indent_less();
1318  return NULL;
1319  }
1320  /* Update QC params */
1321  i = (int)(cpl_image_get_max(combined[1]));
1322  isaac_img_jitter_config.nb_rej_frames =
1323  isaac_img_jitter_config.nb_obj_frames - i;
1324  isaac_img_jitter_config.nb_obj_frames = i;
1325  cpl_msg_indent_less();
1326 
1327  /* Free and return */
1328  cpl_vector_delete(thresh_vect);
1329  cpl_bivector_delete(offsets_est_nod);
1330  cpl_imagelist_delete(nodded);
1331  if (objs) cpl_bivector_delete(objs);
1332  return combined;
1333 }
1334 
1335 /*----------------------------------------------------------------------------*/
1343 /*----------------------------------------------------------------------------*/
1344 static int isaac_img_jitter_chopping_classif(
1345  cpl_bivector * offsets,
1346  int ** chop_a,
1347  int ** chop_b)
1348 {
1349  int nb_obj;
1350  double * offsets_x;
1351  double * offsets_y;
1352  double throw_x,
1353  throw_y;
1354  double * dist;
1355  int * dcount;
1356  int max_count;
1357  int i_max, j_max;
1358  int classified;
1359  int i, j, k, l;
1360 
1361  /* Test entries */
1362  if (offsets==NULL || chop_a==NULL || chop_b==NULL) return CPL_ERROR_UNSPECIFIED;
1363 
1364  /* Initialise */
1365  *chop_a = *chop_b = NULL;
1366 
1367  /* Find number of type_obj frames */
1368  nb_obj = cpl_bivector_get_size(offsets);
1369  offsets_x = cpl_bivector_get_x_data(offsets);
1370  offsets_y = cpl_bivector_get_y_data(offsets);
1371 
1372  /* If no object frame, exit */
1373  if (nb_obj == 0) return CPL_ERROR_UNSPECIFIED;
1374 
1375  /* Odd number of frames ? */
1376  if (nb_obj%2) {
1377  cpl_msg_error(cpl_func, "odd number of frames in input [%d]", nb_obj);
1378  return CPL_ERROR_UNSPECIFIED;
1379  }
1380 
1381  /* Find all distances between offsets and count them */
1382  dist = cpl_calloc(nb_obj*nb_obj, sizeof(double));
1383  dcount = cpl_calloc(nb_obj*nb_obj, sizeof(int));
1384  for (i=0; i<nb_obj; i++) {
1385  for (j=0; j<nb_obj; j++) {
1386  dist[i+j*nb_obj] = sqrt(SQR(offsets_x[i] - offsets_x[j]) +
1387  SQR(offsets_y[i] - offsets_y[j]));
1388  }
1389  }
1390 
1391  for (i=0; i<nb_obj*nb_obj; i++) {
1392  for (j=0; j<nb_obj*nb_obj; j++)
1393  if (fabs(dist[i]-dist[j]) <= NEGLIG_OFF_DIFF) dcount[i] ++;
1394  }
1395 
1396  /* Find Chop offsets as the nonzero distance with maximal occurrence */
1397  max_count = 0;
1398  i_max = 0;
1399  j_max = 0;
1400  for (i=0; i<nb_obj; i++){
1401  for (j=0; j<nb_obj; j++) {
1402  if ((dcount[i+j*nb_obj]>max_count)&&(dist[i+j*nb_obj]>0.5)){
1403  max_count = dcount[i+j*nb_obj];
1404  i_max = i;
1405  j_max = j;
1406  }
1407  }
1408  }
1409 
1410  /* Compute the throw */
1411  throw_x = offsets_x[j_max] - offsets_x[i_max];
1412  throw_y = offsets_y[j_max] - offsets_y[i_max];
1413 
1414  cpl_msg_info(cpl_func, "Typical (%d) non-zero throw is (%g, %g) from %d "
1415  "(%g, %g) to %d (%g, %g)", max_count, throw_x, throw_y,
1416  i_max, offsets_x[i_max], offsets_y[i_max],
1417  j_max, offsets_x[j_max], offsets_y[j_max]);
1418 
1419  /* Free */
1420  cpl_free(dist);
1421  cpl_free(dcount);
1422 
1423  /* Test the throw */
1424  if ((throw_x == 0) && (throw_y == 0)) {
1425  cpl_msg_error(cpl_func, "Throw is equal to 0 - cannot classify");
1426  return CPL_ERROR_UNSPECIFIED;
1427  }
1428 
1429  /* Allocate maximal possible nb of chop frames (worst case: abab)*/
1430  *chop_a = cpl_calloc(nb_obj/2, sizeof(int));
1431  *chop_b = cpl_calloc(nb_obj/2, sizeof(int));
1432 
1433  k = l = 0;
1434  for (i=0; i<nb_obj-1; i++) {
1435  /* Consider the successive pairs of frames */
1436  /* AB ? */
1437  if ((fabs(offsets_x[i]-offsets_x[i+1]+throw_x) < NEGLIG_OFF_DIFF) &&
1438  (fabs(offsets_y[i]-offsets_y[i+1]+throw_y) < NEGLIG_OFF_DIFF)) {
1439  (*chop_a)[k++] = i;
1440  (*chop_b)[l++] = i+1;
1441  /* BA ? */
1442  } else if ((fabs(offsets_x[i]-offsets_x[i+1]-throw_x) <
1443  NEGLIG_OFF_DIFF) &&
1444  (fabs(offsets_y[i]-offsets_y[i+1]-throw_y) <
1445  NEGLIG_OFF_DIFF)) {
1446  (*chop_b)[l++] = i;
1447  (*chop_a)[k++] = i+1;
1448  /* AA or BB ? -> do nothing */
1449  }
1450  }
1451 
1452  cpl_msg_info(cpl_func, "Found %d A- and %d B-frames (out of %d)", k, l,
1453  nb_obj);
1454 
1455  /* Classify the frames not seen until here as rejected */
1456  for (i=0; i<nb_obj; i++) {
1457  classified = 0;
1458  /* For each frame, check if it has been classified */
1459  for (j=0; j < nb_obj/2; j++) {
1460  if ((*chop_a)[j] == i || (*chop_b)[j] == i) classified = 1;
1461  }
1462  if (classified == 0) {
1463  cpl_msg_error(cpl_func, "Frame %d cannot be classified", i+1);
1464  cpl_free(*chop_a);
1465  cpl_free(*chop_b);
1466  *chop_a = *chop_b = NULL;
1467  return CPL_ERROR_UNSPECIFIED;
1468  }
1469  }
1470 
1471  /* There should be as much chop a as chop b frames */
1472  if (k != l) {
1473  cpl_free(*chop_a);
1474  cpl_free(*chop_b);
1475  *chop_a = *chop_b = NULL;
1476  return CPL_ERROR_UNSPECIFIED;
1477  }
1478  return k;
1479 }
1480 
1481 /*----------------------------------------------------------------------------*/
1488 /*----------------------------------------------------------------------------*/
1489 static cpl_error_code isaac_img_jitter_sub_row_median(cpl_image * self)
1490 {
1491  const int nx = cpl_image_get_size_x(self);
1492  const int ny = cpl_image_get_size_y(self);
1493  float * pself = cpl_image_get_data_float(self);
1494  int i, j;
1495 
1496  bug_if(self == NULL);
1497  bug_if(cpl_image_get_type(self) != CPL_TYPE_FLOAT);
1498 
1499 
1500  for (j = 0; j < ny; j++, pself += nx) {
1501  cpl_errorstate prestate = cpl_errorstate_get();
1502  const double median = cpl_image_get_median_window(self, 1, j+1, nx, j+1);
1503 
1504  if (cpl_errorstate_is_equal(prestate)) {
1505  for (i = 0; i < nx; i++) {
1506  pself[i] -= (float)median;
1507  }
1508  } else {
1509  cpl_msg_warning(cpl_func, "Could not subtract median from %d "
1510  "pixel(s) in row %d/%d (%d bad pixel(s))", nx, 1+j,
1511  ny, (int)cpl_image_count_rejected(self));
1512  cpl_errorstate_set(prestate);
1513  }
1514  }
1515 
1516  end_skip;
1517 
1518  return cpl_error_get_code();
1519 }
1520 
1521 /*----------------------------------------------------------------------------*/
1527 /*----------------------------------------------------------------------------*/
1528 static cpl_table * isaac_img_jitter_qc(cpl_image * combined)
1529 {
1530  cpl_vector * thresh_vec;
1531  cpl_apertures * aperts;
1532  int nb_objs;
1533  double angle;
1534  double * fwhms_x;
1535  double * fwhms_y;
1536  cpl_table * out_tab;
1537  cpl_bivector * iqe;
1538  int nb_good;
1539  cpl_vector * fwhms_good;
1540  double * fwhms_good_data;
1541  double f_min, f_max, fr, fx, fy;
1542  int i, j;
1543 
1544  /* Initialise */
1545  double seeing_min_arcsec = 0.1;
1546  double seeing_max_arcsec = 5.0;
1547  double seeing_fwhm_var = 0.2;
1548 
1549  /* Check entries */
1550  if (combined == NULL) return NULL;
1551 
1552  /* Create the vector for the detection thresholds */
1553  thresh_vec = cpl_vector_new(4);
1554  cpl_vector_set(thresh_vec, 0, 5.0);
1555  cpl_vector_set(thresh_vec, 1, 2.0);
1556  cpl_vector_set(thresh_vec, 2, 1.0);
1557  cpl_vector_set(thresh_vec, 3, 0.5);
1558 
1559  /* Detect apertures */
1560  if ((aperts = cpl_apertures_extract(combined, thresh_vec, NULL)) == NULL) {
1561  cpl_msg_error(cpl_func, "Cannot detect any aperture");
1562  cpl_vector_delete(thresh_vec);
1563  return NULL;
1564  }
1565  cpl_vector_delete(thresh_vec);
1566 
1567  /* Number of detected objects */
1568  nb_objs = cpl_apertures_get_size(aperts);
1569  isaac_img_jitter_config.nbobjs = nb_objs;
1570  fwhms_x = cpl_malloc(nb_objs * sizeof(double));
1571  fwhms_y = cpl_malloc(nb_objs * sizeof(double));
1572 
1573  /* Create the output table */
1574  out_tab = cpl_table_new(nb_objs);
1575  cpl_table_new_column(out_tab, "POS_X", CPL_TYPE_DOUBLE);
1576  cpl_table_new_column(out_tab, "POS_Y", CPL_TYPE_DOUBLE);
1577  cpl_table_new_column(out_tab, "ANGLE", CPL_TYPE_DOUBLE);
1578  cpl_table_new_column(out_tab, "FWHM_X", CPL_TYPE_DOUBLE);
1579  cpl_table_new_column(out_tab, "FWHM_Y", CPL_TYPE_DOUBLE);
1580  cpl_table_new_column(out_tab, "ELLIP", CPL_TYPE_DOUBLE);
1581  cpl_table_new_column(out_tab, "FLUX", CPL_TYPE_DOUBLE);
1582  for (i=0; i<nb_objs; i++) {
1583  /* Fill with the already known information */
1584  cpl_table_set_double(out_tab, "POS_X", i,
1585  cpl_apertures_get_centroid_x(aperts, i+1));
1586  cpl_table_set_double(out_tab, "POS_Y", i,
1587  cpl_apertures_get_centroid_y(aperts, i+1));
1588  cpl_table_set_double(out_tab, "FLUX", i,
1589  cpl_apertures_get_flux(aperts, i+1));
1590  /* Compute the FWHM informations */
1591  if ((iqe = cpl_image_iqe(combined,
1592  (int)cpl_apertures_get_centroid_x(aperts, i+1) - 10,
1593  (int)cpl_apertures_get_centroid_y(aperts, i+1) - 10,
1594  (int)cpl_apertures_get_centroid_x(aperts, i+1) + 10,
1595  (int)cpl_apertures_get_centroid_y(aperts, i+1) + 10))==NULL){
1596  cpl_error_reset();
1597  cpl_msg_warning(cpl_func, "Cannot get FWHM for obj at pos %g %g",
1598  cpl_apertures_get_centroid_x(aperts, i+1),
1599  cpl_apertures_get_centroid_y(aperts, i+1));
1600  fwhms_x[i] = -1.0;
1601  fwhms_y[i] = -1.0;
1602  angle = 0.0;
1603  } else {
1604  fwhms_x[i] = cpl_vector_get(cpl_bivector_get_x(iqe), 2);
1605  fwhms_y[i] = cpl_vector_get(cpl_bivector_get_x(iqe), 3);
1606  angle = cpl_vector_get(cpl_bivector_get_x(iqe), 4);
1607  cpl_bivector_delete(iqe);
1608  }
1609  cpl_table_set_double(out_tab, "ANGLE", i, angle);
1610  cpl_table_set_double(out_tab, "FWHM_X", i, fwhms_x[i]);
1611  cpl_table_set_double(out_tab, "FWHM_Y", i, fwhms_y[i]);
1612  if (fwhms_x[i] == 0.0) {
1613  cpl_msg_warning(cpl_func, "Infinite ELLIP for obj at pos %g %g",
1614  cpl_apertures_get_centroid_x(aperts, i+1),
1615  cpl_apertures_get_centroid_y(aperts, i+1));
1616  cpl_table_set_double(out_tab, "ELLIP", i, DBL_MAX);
1617  } else {
1618  cpl_table_set_double(out_tab, "ELLIP", i,
1619  fwhms_y[i] / fwhms_x[i]);
1620  }
1621  }
1622  cpl_apertures_delete(aperts);
1623 
1624  /* Get the number of good values */
1625  nb_good = 0;
1626  for (i=0; i<nb_objs; i++) {
1627  if ((fwhms_x[i] > 0.0) && (fwhms_y[i] > 0.0)) nb_good++;
1628  }
1629  if (nb_good == 0) {
1630  cpl_table_delete(out_tab);
1631  cpl_free(fwhms_x);
1632  cpl_free(fwhms_y);
1633  return NULL;
1634  }
1635 
1636  /* Get the good values */
1637  fwhms_good = cpl_vector_new(nb_good);
1638  fwhms_good_data = cpl_vector_get_data(fwhms_good);
1639  j=0;
1640  for (i=0; i<nb_objs; i++) {
1641  if ((fwhms_x[i] > 0.0) && (fwhms_y[i] > 0.0)) {
1642  fwhms_good_data[j] = (fwhms_x[i]+fwhms_y[i])/2.0;
1643  j++;
1644  }
1645  }
1646 
1647  /* Compute the fwhm */
1648  if (nb_good < 3) {
1649  /* Too few values to compute the median */
1650  isaac_img_jitter_config.fwhm_pix = fwhms_good_data[0];
1651  } else {
1652  /* Compute the median */
1653  isaac_img_jitter_config.fwhm_pix = cpl_vector_get_median_const(fwhms_good);
1654  }
1655  isaac_img_jitter_config.fwhm_arcsec =
1656  isaac_img_jitter_config.fwhm_pix * isaac_img_jitter_config.pixscale;
1657 
1658  /* Compute the mode of the FWHMs */
1659  if (nb_good > 5) {
1660  isaac_img_jitter_config.fwhm_mode=isaac_img_jitter_get_mode(fwhms_good);
1661  isaac_img_jitter_config.fwhm_mode *= isaac_img_jitter_config.pixscale;
1662  }
1663  cpl_vector_delete(fwhms_good);
1664 
1665  /* IQ is the median of the (fwhm_x+fwhm_y/2) of the good stars */
1666  /* Compute f_min and f_max */
1667  f_min = seeing_min_arcsec / isaac_img_jitter_config.pixscale;
1668  f_max = seeing_max_arcsec / isaac_img_jitter_config.pixscale;
1669 
1670  /* Get the number of good values */
1671  nb_good = 0;
1672  for (i=0; i<nb_objs; i++) {
1673  fx = fwhms_x[i];
1674  fy = fwhms_y[i];
1675  fr = 2.0 * fabs(fx-fy) / (fx+fy);
1676  if ((fx > f_min) && (fx < f_max) && (fy > f_min) && (fy < f_max) &&
1677  (fr < seeing_fwhm_var)) nb_good++;
1678  }
1679  if (nb_good == 0) {
1680  cpl_table_delete(out_tab);
1681  cpl_free(fwhms_x);
1682  cpl_free(fwhms_y);
1683  return NULL;
1684  }
1685 
1686  /* Get the good values */
1687  fwhms_good = cpl_vector_new(nb_good);
1688  fwhms_good_data = cpl_vector_get_data(fwhms_good);
1689  j=0;
1690  for (i=0; i<nb_objs; i++) {
1691  fx = fwhms_x[i];
1692  fy = fwhms_y[i];
1693  fr = 2.0 * fabs(fx-fy) / (fx+fy);
1694  if ((fx > f_min) && (fx < f_max) && (fy > f_min) && (fy < f_max) &&
1695  (fr < seeing_fwhm_var)) {
1696  fwhms_good_data[j] = (fx + fy)/2.0;
1697  j++;
1698  }
1699  }
1700  cpl_free(fwhms_x);
1701  cpl_free(fwhms_y);
1702 
1703  /* Compute the fwhm */
1704  if (nb_good < 3) {
1705  /* Too few values to compute the median */
1706  isaac_img_jitter_config.iq = fwhms_good_data[0];
1707  } else {
1708  /* Compute the median */
1709  isaac_img_jitter_config.iq = cpl_vector_get_median_const(fwhms_good);
1710  }
1711  cpl_vector_delete(fwhms_good);
1712  isaac_img_jitter_config.iq *= isaac_img_jitter_config.pixscale;
1713 
1714  isaac_img_jitter_config.angle_med = cpl_table_get_column_median(out_tab,
1715  "ANGLE");
1716  isaac_img_jitter_config.ellip_med = cpl_table_get_column_median(out_tab,
1717  "ELLIP");
1718  return out_tab;
1719 }
1720 
1721 /*----------------------------------------------------------------------------*/
1727 /*----------------------------------------------------------------------------*/
1728 static double isaac_img_jitter_get_mode(cpl_vector * vec)
1729 {
1730  int nb;
1731  int nbins;
1732  double min, max;
1733  double bin_size;
1734  cpl_bivector * hist;
1735  cpl_vector * hist_x;
1736  cpl_vector * hist_y;
1737  double cur_val;
1738  int cur_bin;
1739  double max_val;
1740  int max_bin;
1741  double mode;
1742  int i;
1743 
1744  /* Test entries */
1745  if (vec == NULL) return -1.0;
1746 
1747  /* Initialise */
1748  nb = cpl_vector_get_size(vec);
1749 
1750  /* Create the histogram */
1751  nbins = 10;
1752  min = cpl_vector_get_min(vec);
1753  max = cpl_vector_get_max(vec);
1754  bin_size = (max-min)/nbins;
1755  hist = cpl_bivector_new(nbins);
1756  hist_x = cpl_bivector_get_x(hist);
1757  hist_y = cpl_bivector_get_y(hist);
1758  cpl_vector_fill(hist_x, 0.0);
1759  cpl_vector_fill(hist_y, 0.0);
1760  for (i=0; i<nbins; i++) {
1761  cpl_vector_set(hist_x, i, min + i * bin_size);
1762  }
1763  for (i=0; i<nb; i++) {
1764  cur_val = cpl_vector_get(vec, i);
1765  cur_bin = (int)((cur_val - min) / bin_size);
1766  if (cur_bin >= nbins) cur_bin -= 1.0;
1767  cur_val = cpl_vector_get(hist_y, cur_bin);
1768  cur_val += 1.0;
1769  cpl_vector_set(hist_y, cur_bin, cur_val);
1770  }
1771 
1772  /* Get the mode of the histogram */
1773  max_val = cpl_vector_get(hist_y, 0);
1774  max_bin = 0;
1775  for (i=0; i<nbins; i++) {
1776  cur_val = cpl_vector_get(hist_y, i);
1777  if (cur_val > max_val) {
1778  max_val = cur_val;
1779  max_bin = i;
1780  }
1781  }
1782  mode = cpl_vector_get(hist_x, max_bin);
1783  cpl_bivector_delete(hist);
1784  return mode;
1785 }
1786 
1787 /*----------------------------------------------------------------------------*/
1799 /*----------------------------------------------------------------------------*/
1800 static
1801 cpl_error_code isaac_img_jitter_save(cpl_frameset * set,
1802  const cpl_image * combined,
1803  const cpl_image * contrib,
1804  const cpl_table * objs_stats,
1805  const cpl_vector * sky_bg,
1806  const cpl_parameterlist * parlist)
1807 {
1808  const cpl_frame * ref_frame
1809  = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW);
1810  const char * filename = cpl_frame_get_filename(ref_frame);
1811  const int sz_skybg = sky_bg ? cpl_vector_get_size(sky_bg) : 0;
1812  cpl_propertylist * plist = NULL;
1813  cpl_propertylist * qclist = cpl_propertylist_new();
1814  const char * wcs_reg = "(CRVAL|CRPIX|CTYPE)[0-9]+|(CD)[0-9]+_[0-9]+";
1815  cpl_table * sky_bg_tab = NULL;
1816  int i;
1817 
1818  bug_if(0);
1819  bug_if(combined == NULL);
1820  bug_if(contrib == NULL);
1821  bug_if(parlist == NULL);
1822 
1823  /* Get the QC params in qclist */
1824  if (isaac_img_jitter_config.chopping == 0) {
1825  const char * key = "ESO QC BACKGD INSTMAG";
1826  const double pscale = isaac_img_jitter_config.pixscale;
1827  const double dit = isaac_img_jitter_config.dit;
1828  const double bg_mean = cpl_vector_get_mean(sky_bg);
1829  const double bg_stdev = sz_skybg < 2 ? 0.0
1830  : cpl_vector_get_stdev(sky_bg);
1831 
1832 
1833  bug_if(cpl_propertylist_append_double(qclist, "ESO QC BACKGD MEAN",
1834  bg_mean));
1835  bug_if(cpl_propertylist_append_double(qclist, "ESO QC BACKGD STDEV",
1836  bg_stdev));
1837 
1838  if (pscale * dit != 0.0 && bg_mean / (pscale * pscale * dit) > 0.0) {
1839  const double bg_instmag = -2.5 * log10(bg_mean/(pscale*pscale*dit));
1840 
1841  bug_if(cpl_propertylist_append_double(qclist, key, bg_instmag));
1842  } else {
1843  cpl_msg_warning(cpl_func, "Could not compute %s: dit=%g, pscale=%g, "
1844  "bg_mean=%g", key, dit, pscale, bg_mean);
1845  }
1846  }
1847 
1848  cpl_propertylist_append_int(qclist, "ESO QC NBOBJS",
1849  isaac_img_jitter_config.nbobjs);
1850  cpl_propertylist_append_double(qclist, "ESO QC IQ",
1851  isaac_img_jitter_config.iq);
1852  cpl_propertylist_append_double(qclist, "ESO QC FWHM PIX",
1853  isaac_img_jitter_config.fwhm_pix);
1854  cpl_propertylist_append_double(qclist, "ESO QC FWHM ARCSEC",
1855  isaac_img_jitter_config.fwhm_arcsec);
1856  cpl_propertylist_append_double(qclist, "ESO QC FWHM MODE",
1857  isaac_img_jitter_config.fwhm_mode);
1858  cpl_propertylist_append_int(qclist, "ESO QC NB_OBJ_F",
1859  isaac_img_jitter_config.nb_obj_frames);
1860  cpl_propertylist_append_int(qclist, "ESO QC NB_SKY_F",
1861  isaac_img_jitter_config.nb_sky_frames);
1862  cpl_propertylist_append_int(qclist, "ESO QC NB_REJ_F",
1863  isaac_img_jitter_config.nb_rej_frames);
1864  cpl_propertylist_append_double(qclist, "ESO QC ANGLE MED",
1865  isaac_img_jitter_config.angle_med);
1866  cpl_propertylist_append_double(qclist, "ESO QC ELLIP MED",
1867  isaac_img_jitter_config.ellip_med);
1868  bug_if(0);
1869 
1870  /* Get FITS header from reference file */
1871  plist = cpl_propertylist_load(filename, 0);
1872  skip_if(plist == NULL);
1873 
1874  /* Load the WCS keys */
1875  bug_if(cpl_propertylist_copy_property_regexp(qclist, plist, wcs_reg, 0));
1876 
1877  /* Get the keywords for the paf file */
1878  (void)cpl_propertylist_erase_regexp(plist,
1879  "^(ARCFILE|MJD-OBS|INSTRUME"
1880  "|ESO TPL ID|ESO TPL NEXP"
1881  "|ESO DPR CATG"
1882  "|ESO DPR TECH|ESO DPR TYPE"
1883  "|DATE-OBS|ESO OBS ID"
1884  "|ESO INS PIXSCALE)$", 1);
1885 
1886  /* Write the image */
1887  skip_if(irplib_dfs_save_image(set, parlist, set, combined,
1888  CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
1889  ISAAC_IMG_JITTER_COMB, qclist, NULL,
1890  PACKAGE "/" PACKAGE_VERSION,
1891  RECIPE_STRING CPL_DFS_FITS));
1892  (void)cpl_propertylist_erase_regexp(qclist, wcs_reg, 0);
1893 
1894  /* Append the contribution map */
1895  skip_if (cpl_image_save(contrib, RECIPE_STRING CPL_DFS_FITS,
1896  CPL_BPP_16_UNSIGNED, NULL, CPL_IO_EXTEND));
1897 
1898  if (sky_bg != NULL) {
1899  /* Write the FITS background table */
1900 
1901  /* First create the table from the vector */
1902  sky_bg_tab = cpl_table_new(sz_skybg);
1903 
1904  cpl_table_new_column(sky_bg_tab, "SKY_BG", CPL_TYPE_DOUBLE);
1905 
1906  for (i = 0; i < sz_skybg; i++) {
1907  cpl_table_set_double(sky_bg_tab, "SKY_BG", i,
1908  cpl_vector_get(sky_bg, i));
1909  }
1910 
1911  skip_if(irplib_dfs_save_table(set, parlist, set, sky_bg_tab, NULL,
1912  RECIPE_STRING, ISAAC_IMG_JITTER_BG,
1913  qclist, NULL, PACKAGE "/" PACKAGE_VERSION,
1914  RECIPE_STRING "_bg" CPL_DFS_FITS));
1915  cpl_table_delete(sky_bg_tab);
1916  sky_bg_tab = NULL;
1917  }
1918 
1919  /* Write the FITS table */
1920  if (objs_stats) {
1921  skip_if(irplib_dfs_save_table(set, parlist, set, objs_stats, NULL,
1922  RECIPE_STRING, ISAAC_IMG_JITTER_STARS,
1923  qclist, NULL, PACKAGE "/" PACKAGE_VERSION,
1924  RECIPE_STRING "_stars" CPL_DFS_FITS));
1925  }
1926 
1927  bug_if(cpl_propertylist_append(plist, qclist));
1928  cpl_propertylist_empty(qclist);
1929 
1930  /* PRO.CATG */
1931  cpl_propertylist_update_string(plist, CPL_DFS_PRO_CATG,
1932  ISAAC_IMG_JITTER_COMB);
1933 
1934  /* Save the PAF file */
1935  skip_if (cpl_dfs_save_paf("ISAAC", RECIPE_STRING, plist,
1936  RECIPE_STRING CPL_DFS_PAF));
1937 
1938  end_skip;
1939 
1940  cpl_propertylist_delete(plist);
1941  cpl_propertylist_delete(qclist);
1942  cpl_table_delete(sky_bg_tab);
1943 
1944  return cpl_error_get_code();
1945 }
int isaac_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
Definition: isaac_dfs.c:60
const char * isaac_pfits_get_frame_type(const cpl_propertylist *plist)
find out the frame type
Definition: isaac_pfits.c:286
double isaac_pfits_get_dit(const cpl_propertylist *plist)
find out the DIT value
Definition: isaac_pfits.c:305
double isaac_pfits_get_pixscale(const cpl_propertylist *plist)
find out the pixel scale
Definition: isaac_pfits.c:745
double isaac_pfits_get_cumoffsety(const cpl_propertylist *plist)
find out the cumulative offset in Y
Definition: isaac_pfits.c:211
double isaac_pfits_get_cumoffsetx(const cpl_propertylist *plist)
find out the cumulative offset in X
Definition: isaac_pfits.c:196
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_image * isaac_oddeven_correct(const cpl_image *in)
Correct the odd/even in an image.
Definition: isaac_utils.c:275
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