HAWKI Pipeline Reference Manual  1.8.12
hawki_sci_jitter.c
1 /* $Id: hawki_sci_jitter.c,v 1.34 2013/01/15 09:58:25 cgarcia Exp $
2  *
3  * This file is part of the HAWKI 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: cgarcia $
23  * $Date: 2013/01/15 09:58:25 $
24  * $Revision: 1.34 $
25  * $Name: hawki-1_8_12 $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 /*-----------------------------------------------------------------------------
33  Includes
34  -----------------------------------------------------------------------------*/
35 
36 #include <math.h>
37 #include <cpl.h>
38 #include <string.h>
39 
40 #include "irplib_utils.h"
41 #include "irplib_calib.h"
42 
43 #include "hawki_utils.h"
44 #include "hawki_calib.h"
45 #include "hawki_load.h"
46 #include "hawki_save.h"
47 #include "hawki_pfits.h"
48 #include "hawki_dfs.h"
49 #include "hawki_saa.h"
50 #include "hawki_bkg.h"
51 #include "hawki_distortion.h"
52 #include "hawki_properties_tel.h"
53 #include "hawki_image_stats.h"
54 #include "hawki_obj_det.h"
55 
56 /*-----------------------------------------------------------------------------
57  Define
58  -----------------------------------------------------------------------------*/
59 
60 #define NEGLIG_OFF_DIFF 0.1
61 #define SQR(x) ((x)*(x))
62 
63 /*-----------------------------------------------------------------------------
64  Functions prototypes
65  -----------------------------------------------------------------------------*/
66 
67 #ifdef __cplusplus
68 extern "C"
69 #endif
70 int cpl_plugin_get_info(cpl_pluginlist * list);
71 
72 static int hawki_sci_jitter_create(cpl_plugin *) ;
73 static int hawki_sci_jitter_exec(cpl_plugin *) ;
74 static int hawki_sci_jitter_destroy(cpl_plugin *) ;
75 static int hawki_sci_jitter(cpl_parameterlist *, cpl_frameset *) ;
76 
77 static int hawki_sci_jitter_retrieve_input_param
78 (cpl_parameterlist * parlist);
79 static cpl_image ** hawki_sci_jitter_reduce
80 (cpl_frameset * jitters,
81  cpl_frameset * sky,
82  const char * flat,
83  const char * dark,
84  const char * bpm,
85  cpl_table ** bkg_stats);
86 static int hawki_sci_jitter_sky
87 (cpl_imagelist * jitters,
88  cpl_imagelist * skys,
89  cpl_table ** bkg_stats,
90  int idet);
91 static int hawki_sci_jitter_sky_running
92 (cpl_imagelist * in,
93  cpl_table ** bkg_stats,
94  int idet);
95 static cpl_image ** hawki_sci_jitter_saa(cpl_imagelist **, cpl_bivector *,
96  double *, double *);
97 static int hawki_sci_jitter_qc
98 (cpl_frameset * science_frames,
99  cpl_image ** combined,
100  cpl_table ** obj_charac);
101 static int hawki_sci_jitter_read_calib
102 (const char * flat,
103  const char * dark,
104  const char * bpm,
105  cpl_image ** flat_image,
106  cpl_image ** dark_image,
107  cpl_image ** bpm_image,
108  int idet);
109 static int hawki_sci_jitter_save
110 (cpl_image ** combined,
111  cpl_image * stitched,
112  cpl_table ** objs_charac,
113  cpl_table ** raw_jitter_stats,
114  cpl_table ** bkg_stats,
115  const cpl_table * raw_obj_tel_info,
116  cpl_frameset * science_frames,
117  cpl_frameset * calib_frames,
118  cpl_parameterlist * parlist,
119  cpl_frameset * set);
120 int hawki_sci_jitter_whole_image_algo
121 (cpl_frameset * obj,
122  cpl_table ** raw_jitter_stats,
123  cpl_table * raw_obj_tel_info,
124  cpl_parameterlist * parlist,
125  cpl_frameset * recipe_set);
126 int hawki_sci_jitter_save_stats
127 (cpl_table ** raw_jitter_stats,
128  cpl_table * raw_obj_tel_info,
129  cpl_frameset * jitter_frames,
130  cpl_parameterlist * parlist,
131  cpl_frameset * recipe_set);
132 
133 /*-----------------------------------------------------------------------------
134  Static variables
135  -----------------------------------------------------------------------------*/
136 
137 static struct
138 {
139  /* Inputs */
140  const char * offsets ;
141  const char * objects ;
142  int offset_max ;
143  int sky_minnb ;
144  int sky_halfw ;
145  int sky_rejmin ;
146  int sky_rejmax ;
147  int refine ;
148  int sx ;
149  int sy ;
150  int mx ;
151  int my ;
152  int borders ;
153  cpl_geom_combine comb_meth ;
154  int rej_low ;
155  int rej_high ;
156  int max_njitter;
157 } hawki_sci_jitter_config;
158 
159 static struct
160 {
161  /* Outputs */
162  double pixscale;
163  double dit;
164  double mean_airmass;
165  double iq[HAWKI_NB_DETECTORS];
166  int nbobjs[HAWKI_NB_DETECTORS];
167  double fwhm_pix[HAWKI_NB_DETECTORS];
168  double fwhm_arcsec[HAWKI_NB_DETECTORS];
169  double fwhm_mode[HAWKI_NB_DETECTORS];
170  double combined_pos_x[HAWKI_NB_DETECTORS];
171  double combined_pos_y[HAWKI_NB_DETECTORS];
172  double combined_cumoffset_x[HAWKI_NB_DETECTORS];
173  double combined_cumoffset_y[HAWKI_NB_DETECTORS];
174  int ncomb[HAWKI_NB_DETECTORS];
175 } hawki_sci_jitter_output;
176 
177 static char hawki_sci_jitter_description[] =
178 "hawki_sci_jitter -- hawki imaging jitter recipe.\n\n"
179 "The input of the recipe files listed in the Set Of Frames (sof-file)\n"
180 "must be tagged as:\n"
181 "raw-file.fits "HAWKI_IMG_JITTER_RAW" or\n"
182 "raw-file.fits "HAWKI_IMG_JITTER_SKY_RAW" or\n"
183 "flat-file.fits "HAWKI_CALPRO_FLAT" or\n"
184 "dark-file.fits "HAWKI_CALPRO_DARK" \n"
185 "bpm-file.fits "HAWKI_CALPRO_BPM"\n"
186 "distortion_x-file.fits "HAWKI_CALPRO_DISTORTION_X"\n"
187 "distortion_y-file.fits "HAWKI_CALPRO_DISTORTION_Y"\n\n"
188 "The recipe creates as an output:\n"
189 "hawki_sci_jitter.fits ("HAWKI_CALPRO_COMBINED")\n"
190 "hawki_sci_jitter_stitched.fits ("HAWKI_CALPRO_STITCHED")\n"
191 "hawki_sci_jitter_stars.fits ("HAWKI_CALPRO_OBJ_PARAM"): Detected objects properties\n"
192 "hawki_sci_jitter_stats.fits ("HAWKI_CALPRO_JITTER_STATS"): Stats of the individual images\n"
193 "hawki_sci_jitter_bkg_stats.fits ("HAWKI_CALPRO_JITTER_BKG_STATS"): Statistics on the bkg\n\n"
194 "The recipe performs the following steps:\n"
195 "1) Frame statistics\n"
196 "2) Basic reduction (using "HAWKI_CALPRO_FLAT" and "HAWKI_CALPRO_BPM")\n"
197 "3) Background computation (the algorithm depends on parameter --sky_par) \n"
198 "4) Offset refinement (uses parameters --off, --refine and --xcorr)\n"
199 "5) Stacking of jitter frames (uses --comb_meth, --rej,\n"
200 " --offset_max, --borders, --max_njitter)\n"
201 "6) Stitching of the four detectors into one image\n"
202 "7) Object detection in the stacked image\n\n"
203 "Return code:\n"
204 "esorex exits with an error code of 0 if the recipe completes successfully\n"
205 "or 1 otherwise";
206 
207 /*-----------------------------------------------------------------------------
208  Functions code
209  -----------------------------------------------------------------------------*/
210 
211 /*----------------------------------------------------------------------------*/
219 /*----------------------------------------------------------------------------*/
220 int cpl_plugin_get_info(cpl_pluginlist * list)
221 {
222  cpl_recipe * recipe = cpl_calloc(1, sizeof(*recipe)) ;
223  cpl_plugin * plugin = &recipe->interface ;
224 
225  cpl_plugin_init(plugin,
226  CPL_PLUGIN_API,
227  HAWKI_BINARY_VERSION,
228  CPL_PLUGIN_TYPE_RECIPE,
229  "hawki_sci_jitter",
230  "Jitter recipe",
231  hawki_sci_jitter_description,
232  "Cesar Enrique Garcia",
233  PACKAGE_BUGREPORT,
235  hawki_sci_jitter_create,
236  hawki_sci_jitter_exec,
237  hawki_sci_jitter_destroy) ;
238 
239  cpl_pluginlist_append(list, plugin) ;
240 
241  return 0;
242 }
243 
244 /*----------------------------------------------------------------------------*/
253 /*----------------------------------------------------------------------------*/
254 static int hawki_sci_jitter_create(cpl_plugin * plugin)
255 {
256  cpl_recipe * recipe ;
257  cpl_parameter * p ;
258 
259  /* Get the recipe out of the plugin */
260  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
261  recipe = (cpl_recipe *)plugin ;
262  else return -1 ;
263 
264  /* Create the parameters list in the cpl_recipe object */
265  recipe->parameters = cpl_parameterlist_new() ;
266  if (recipe->parameters == NULL)
267  return 1;
268 
269  /* Fill the parameters list */
270  /* --offsets */
271  p = cpl_parameter_new_value("hawki.hawki_sci_jitter.offsets",
272  CPL_TYPE_STRING, "offsets file", "hawki.hawki_sci_jitter", NULL) ;
273  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "offsets") ;
274  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
275  cpl_parameterlist_append(recipe->parameters, p) ;
276 
277  /* --objects */
278  p = cpl_parameter_new_value("hawki.hawki_sci_jitter.objects",
279  CPL_TYPE_STRING, "objects file", "hawki.hawki_sci_jitter", NULL) ;
280  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "objects") ;
281  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
282  cpl_parameterlist_append(recipe->parameters, p) ;
283 
284  /* --offset_max */
285  p = cpl_parameter_new_value("hawki.hawki_sci_jitter.offset_max",
286  CPL_TYPE_INT,
287  "Maximum offset allowed",
288  "hawki.hawki_sci_jitter",
289  1500) ;
290  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "offset_max") ;
291  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
292  cpl_parameterlist_append(recipe->parameters, p) ;
293 
294  /* --sky_par */
295  p = cpl_parameter_new_value("hawki.hawki_sci_jitter.sky_par",
296  CPL_TYPE_STRING,
297  "Rejection parameters for sky filtering",
298  "hawki.hawki_sci_jitter",
299  "10,7,3,3") ;
300  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sky_par") ;
301  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
302  cpl_parameterlist_append(recipe->parameters, p) ;
303 
304  /* --refine */
305  p = cpl_parameter_new_value("hawki.hawki_sci_jitter.refine",
306  CPL_TYPE_BOOL, "refine offsets", "hawki.hawki_sci_jitter",
307  FALSE);
308  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "refine") ;
309  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
310  cpl_parameterlist_append(recipe->parameters, p) ;
311 
312  /* --xcorr */
313  p = cpl_parameter_new_value("hawki.hawki_sci_jitter.xcorr",
314  CPL_TYPE_STRING,
315  "Cross correlation search and measure sizes",
316  "hawki.hawki_sci_jitter",
317  "20,20,25,25") ;
318  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "xcorr") ;
319  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
320  cpl_parameterlist_append(recipe->parameters, p) ;
321 
322  /* --comb_meth */
323  p = cpl_parameter_new_value("hawki.hawki_sci_jitter.comb_meth",
324  CPL_TYPE_STRING, "union / inter / first", "hawki.hawki_sci_jitter",
325  "union") ;
326  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "comb_meth") ;
327  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
328  cpl_parameterlist_append(recipe->parameters, p) ;
329 
330  /* --rej */
331  p = cpl_parameter_new_value("hawki.hawki_sci_jitter.rej",
332  CPL_TYPE_STRING,
333  "Low and high number of rejected values",
334  "hawki.hawki_sci_jitter",
335  "1,1") ;
336  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rej") ;
337  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
338  cpl_parameterlist_append(recipe->parameters, p) ;
339 
340  /* --borders */
341  p = cpl_parameter_new_value("hawki.hawki_sci_jitter.borders",
342  CPL_TYPE_INT,
343  "Borders rejected",
344  "hawki.hawki_sci_jitter",
345  4) ;
346  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "borders") ;
347  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
348  cpl_parameterlist_append(recipe->parameters, p) ;
349 
350  /* --max_njitter */
351  p = cpl_parameter_new_value("hawki.hawki_sci_jitter.max_njitter",
352  CPL_TYPE_INT,
353  "Maximum numbers of jitter frames to combine",
354  "hawki.hawki_sci_jitter",
355  -1);
356  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "max_njitter");
357  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
358  cpl_parameterlist_append(recipe->parameters, p);
359 
360  /* Return */
361  return 0;
362 }
363 
364 /*----------------------------------------------------------------------------*/
370 /*----------------------------------------------------------------------------*/
371 static int hawki_sci_jitter_exec(cpl_plugin * plugin)
372 {
373  cpl_recipe * recipe ;
374 
375  /* Get the recipe out of the plugin */
376  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
377  recipe = (cpl_recipe *)plugin ;
378  else return -1 ;
379 
380  /* Issue a banner */
382 
383  return hawki_sci_jitter(recipe->parameters, recipe->frames) ;
384 }
385 
386 /*----------------------------------------------------------------------------*/
392 /*----------------------------------------------------------------------------*/
393 static int hawki_sci_jitter_destroy(cpl_plugin * plugin)
394 {
395  cpl_recipe * recipe ;
396 
397  /* Get the recipe out of the plugin */
398  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
399  recipe = (cpl_recipe *)plugin ;
400  else return -1 ;
401 
402  cpl_parameterlist_delete(recipe->parameters) ;
403  return 0 ;
404 }
405 
406 /*----------------------------------------------------------------------------*/
413 /*----------------------------------------------------------------------------*/
414 static int hawki_sci_jitter(
415  cpl_parameterlist * parlist,
416  cpl_frameset * framelist)
417 {
418  const char * flat;
419  const char * dark;
420  const char * bpm;
421  const cpl_frame * distx;
422  const cpl_frame * disty;
423  cpl_frameset * jitterframes ;
424  cpl_frameset * skyframes ;
425  cpl_frameset * science_frames;
426  cpl_frameset * calib_frames;
427  cpl_image ** combined ;
428  cpl_table ** obj_charac;
429  cpl_table ** raw_jitter_stats;
430  cpl_table ** bkg_stats;
431  cpl_table * raw_obj_tel_info;
432  cpl_image * stitched ;
433  int i;
434 
435  /* Initialise */
436  for (i=0 ; i<HAWKI_NB_DETECTORS ; i++)
437  {
438  hawki_sci_jitter_output.iq[i] = -1.0 ;
439  hawki_sci_jitter_output.nbobjs[i] = -1 ;
440  hawki_sci_jitter_output.fwhm_pix[i] = -1.0 ;
441  hawki_sci_jitter_output.fwhm_arcsec[i] = -1.0 ;
442  hawki_sci_jitter_output.fwhm_mode[i] = -1.0 ;
443  hawki_sci_jitter_output.combined_pos_x[i] = -1.0 ;
444  hawki_sci_jitter_output.combined_pos_y[i] = -1.0 ;
445  hawki_sci_jitter_output.combined_cumoffset_x[i] = -1.0 ;
446  hawki_sci_jitter_output.combined_cumoffset_y[i] = -1.0 ;
447  }
448  hawki_sci_jitter_output.pixscale = -1.0 ;
449  hawki_sci_jitter_output.dit = -1.0 ;
450  hawki_sci_jitter_config.offsets = NULL ;
451  hawki_sci_jitter_config.objects = NULL ;
452  calib_frames = cpl_frameset_new();
453 
454  /* Retrieve input parameters */
455  if(hawki_sci_jitter_retrieve_input_param(parlist))
456  {
457  cpl_msg_error(cpl_func, "Wrong parameters");
458  cpl_frameset_delete(calib_frames);
459  return -1;
460  }
461 
462  /* Identify the RAW and CALIB frames in the input frameset */
463  if (hawki_dfs_set_groups(framelist)) {
464  cpl_msg_error(cpl_func, "Cannot identify RAW and CALIB frames") ;
465  cpl_frameset_delete(calib_frames);
466  return -1 ;
467  }
468 
469  /* Retrieve calibration data */
470  flat = hawki_extract_first_filename(framelist, HAWKI_CALPRO_FLAT) ;
471  dark = hawki_extract_first_filename(framelist, HAWKI_CALPRO_DARK);
472  bpm = hawki_extract_first_filename(framelist, HAWKI_CALPRO_BPM) ;
473  distx = cpl_frameset_find_const(framelist, HAWKI_CALPRO_DISTORTION_X);
474  disty = cpl_frameset_find_const(framelist, HAWKI_CALPRO_DISTORTION_Y);
475  if((distx == NULL && disty !=NULL) || (distx != NULL && disty ==NULL))
476  {
477  cpl_msg_error(cpl_func, "Both distortion in X (%s) and Y (%s) must be provided",
478  HAWKI_CALPRO_DISTORTION_X, HAWKI_CALPRO_DISTORTION_Y);
479  cpl_frameset_delete(calib_frames);
480  return -1 ;
481  }
482  if(flat)
483  cpl_frameset_insert(calib_frames, cpl_frame_duplicate(
484  cpl_frameset_find_const(framelist, HAWKI_CALPRO_FLAT)));
485  if(dark)
486  cpl_frameset_insert(calib_frames, cpl_frame_duplicate(
487  cpl_frameset_find_const(framelist, HAWKI_CALPRO_DARK)));
488  if(bpm)
489  cpl_frameset_insert(calib_frames, cpl_frame_duplicate(
490  cpl_frameset_find_const(framelist, HAWKI_CALPRO_BPM)));
491  if(distx)
492  {
493  cpl_frameset_insert(calib_frames, cpl_frame_duplicate(distx));
494  cpl_frameset_insert(calib_frames, cpl_frame_duplicate(disty));
495  }
496 
497 
498  /* Retrieve raw frames */
499  jitterframes = hawki_extract_frameset(framelist, HAWKI_IMG_JITTER_RAW) ;
500  if (jitterframes == NULL) {
501  cpl_msg_error(cpl_func, "Cannot find jitter frames in the input list (%s)",
502  HAWKI_IMG_JITTER_RAW);
503  cpl_frameset_delete(calib_frames);
504  return -1 ;
505  }
506  science_frames = cpl_frameset_duplicate(jitterframes);
507  skyframes = hawki_extract_frameset(framelist, HAWKI_IMG_JITTER_SKY_RAW) ;
508  if (skyframes != NULL)
509  {
510  int isky;
511  for(isky = 0; isky< cpl_frameset_get_size(skyframes); ++isky)
512  cpl_frameset_insert(science_frames,
513  cpl_frame_duplicate(cpl_frameset_get_frame(skyframes, isky)));
514  }
515 
516  /* Create the statistics table */
517  raw_jitter_stats = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_table *));
518  for( i=0 ; i<HAWKI_NB_DETECTORS ; i++)
519  {
520  raw_jitter_stats[i] = cpl_table_new(cpl_frameset_get_size(jitterframes));
521  }
522  hawki_image_stats_initialize(raw_jitter_stats);
523  bkg_stats = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_table *));
524  for( i=0 ; i<HAWKI_NB_DETECTORS ; i++)
525  {
526  bkg_stats[i] = cpl_table_new(cpl_frameset_get_size(jitterframes));
527  }
528  hawki_image_stats_initialize(bkg_stats);
529 
530  /* Create the telescope statistics parameters from the raw images */
531  raw_obj_tel_info = cpl_table_new(cpl_frameset_get_size(jitterframes));
532  /* Add the proper columns of the pcs table */
533  if(hawki_prop_tel_initialize(raw_obj_tel_info))
534  {
535  cpl_msg_error(cpl_func,"Could not initialize the pcs table");
536  cpl_frameset_delete(jitterframes) ;
537  for( i=0 ; i<HAWKI_NB_DETECTORS ; i++)
538  {
539  cpl_table_delete(raw_jitter_stats[i]) ;
540  cpl_table_delete(bkg_stats[i]) ;
541  }
542  cpl_free(raw_jitter_stats) ;
543  cpl_free(bkg_stats) ;
544  cpl_table_delete(raw_obj_tel_info);
545  if (skyframes) cpl_frameset_delete(skyframes) ;
546  cpl_frameset_delete(calib_frames);
547  cpl_msg_indent_less() ;
548  return -1;
549  }
550 
551  /* Do the algorithms that need the whole image */
552  hawki_sci_jitter_whole_image_algo(jitterframes,
553  raw_jitter_stats,
554  raw_obj_tel_info,
555  parlist,
556  framelist);
557 
558  /* Apply the reduction */
559  /* Do the algorithms that can be applied to subsection of the images */
560  cpl_msg_info(cpl_func, "Apply the data combination") ;
561  cpl_msg_indent_more() ;
562  if ((combined = hawki_sci_jitter_reduce(jitterframes, skyframes, flat, dark,
563  bpm, bkg_stats)) == NULL)
564  {
565  cpl_msg_error(cpl_func, "Cannot recombine the data");
566  cpl_frameset_delete(jitterframes);
567  for( i=0 ; i<HAWKI_NB_DETECTORS ; i++)
568  {
569  cpl_table_delete(raw_jitter_stats[i]) ;
570  cpl_table_delete(bkg_stats[i]) ;
571  }
572  cpl_free(raw_jitter_stats) ;
573  cpl_free(bkg_stats) ;
574  cpl_table_delete(raw_obj_tel_info);
575  if (skyframes) cpl_frameset_delete(skyframes) ;
576  cpl_frameset_delete(calib_frames);
577  cpl_msg_indent_less() ;
578  return -1 ;
579  }
580  cpl_msg_indent_less() ;
581 
582  /* Compute QC parameters from the combined image */
583  cpl_msg_info(cpl_func, "Compute QC parameters from the combined images") ;
584  cpl_msg_indent_more() ;
585  obj_charac = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_table*)) ;
586  for (i=0 ; i<HAWKI_NB_DETECTORS ; i++)
587  {
588  obj_charac[i] = cpl_table_new(0);
589  }
590  if ((hawki_sci_jitter_qc(jitterframes, combined, obj_charac)) != 0)
591  {
592  cpl_msg_warning(cpl_func, "Cannot compute all parameters") ;
593  }
594  cpl_msg_indent_less();
595  cpl_frameset_delete(jitterframes);
596  if (skyframes) cpl_frameset_delete(skyframes);
597 
598 
599  /* Correct for the distortion */
600  if (distx && disty)
601  {
602  cpl_msg_info(cpl_func, "Applying the distortion correction") ;
603  cpl_msg_indent_more() ;
604  if (hawki_distortion_correct_alldetectors(combined, distx, disty) == -1)
605  {
606  cpl_msg_error(cpl_func, "Cannot correct the distortion") ;
607  for (i=0 ; i<HAWKI_NB_DETECTORS ; i++)
608  cpl_image_delete(combined[i]) ;
609  cpl_free(combined) ;
610  if (obj_charac) {
611  for (i=0 ; i<HAWKI_NB_DETECTORS ; i++)
612  cpl_table_delete(obj_charac[i]) ;
613  cpl_free(obj_charac);
614  }
615  cpl_table_delete(raw_obj_tel_info);
616  for( i=0 ; i<HAWKI_NB_DETECTORS ; i++)
617  {
618  cpl_table_delete(raw_jitter_stats[i]);
619  cpl_table_delete(bkg_stats[i]);
620  }
621  cpl_free(raw_jitter_stats);
622  cpl_free(bkg_stats);
623  cpl_frameset_delete(calib_frames);
624  cpl_frameset_delete(science_frames);
625  cpl_msg_indent_less() ;
626  return -1;
627  }
628  cpl_msg_indent_less() ;
629  }
630 
631  /* Compute the stitched image */
632  cpl_msg_info(cpl_func, "Compute the stiched image") ;
633  if ((stitched = hawki_images_stitch(combined,
634  hawki_sci_jitter_output.combined_pos_x,
635  hawki_sci_jitter_output.combined_pos_y)) == NULL)
636  {
637  cpl_msg_error(cpl_func, "Cannot stitch the images") ;
638  for (i=0 ; i<HAWKI_NB_DETECTORS ; i++)
639  cpl_image_delete(combined[i]) ;
640  cpl_free(combined) ;
641  if (obj_charac) {
642  for (i=0 ; i<HAWKI_NB_DETECTORS ; i++)
643  cpl_table_delete(obj_charac[i]) ;
644  cpl_free(obj_charac);
645  }
646  cpl_table_delete(raw_obj_tel_info);
647  for( i=0 ; i<HAWKI_NB_DETECTORS ; i++)
648  {
649  cpl_table_delete(raw_jitter_stats[i]);
650  cpl_table_delete(bkg_stats[i]);
651  }
652  cpl_free(raw_jitter_stats);
653  cpl_free(bkg_stats);
654  cpl_frameset_delete(calib_frames);
655  cpl_frameset_delete(science_frames);
656  return -1;
657  }
658 
659  /* Save the products */
660  cpl_msg_info(cpl_func, "Save the products") ;
661  cpl_msg_indent_more() ;
662  if (hawki_sci_jitter_save(combined, stitched, obj_charac,
663  raw_jitter_stats, bkg_stats,
664  raw_obj_tel_info,
665  science_frames,
666  calib_frames,
667  parlist, framelist) == -1)
668  cpl_msg_warning(cpl_func,"Some data could not be saved. "
669  "Check permisions or disk space");
670 
671  /* Return */
672  for (i=0 ; i<HAWKI_NB_DETECTORS ; i++)
673  cpl_image_delete(combined[i]) ;
674  cpl_free(combined) ;
675  if (obj_charac) {
676  for (i=0 ; i<HAWKI_NB_DETECTORS ; i++)
677  cpl_table_delete(obj_charac[i]) ;
678  cpl_free(obj_charac);
679  }
680  if (stitched) cpl_image_delete(stitched) ;
681  cpl_table_delete(raw_obj_tel_info);
682  for( i=0 ; i<HAWKI_NB_DETECTORS ; i++)
683  {
684  cpl_table_delete(raw_jitter_stats[i]);
685  cpl_table_delete(bkg_stats[i]);
686  }
687  cpl_free(raw_jitter_stats);
688  cpl_free(bkg_stats);
689  cpl_frameset_delete(calib_frames);
690  cpl_frameset_delete(science_frames);
691  cpl_msg_indent_less() ;
692 
693  /* Return */
694  if (cpl_error_get_code())
695  {
696  cpl_msg_error(cpl_func,
697  "HAWK-I pipeline could not recover from previous errors");
698  return -1 ;
699  }
700  else return 0 ;
701 }
702 
703 int hawki_sci_jitter_retrieve_input_param
704 (cpl_parameterlist * parlist)
705 {
706  cpl_parameter * par ;
707  const char * sval ;
708  par = NULL ;
709  par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.offsets");
710  hawki_sci_jitter_config.offsets = cpl_parameter_get_string(par);
711  par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.objects");
712  hawki_sci_jitter_config.objects = cpl_parameter_get_string(par);
713  par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.offset_max");
714  hawki_sci_jitter_config.offset_max = cpl_parameter_get_int(par);
715  par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.sky_par");
716  sval = cpl_parameter_get_string(par);
717  if (sscanf(sval, "%d,%d,%d,%d",
718  &hawki_sci_jitter_config.sky_minnb,
719  &hawki_sci_jitter_config.sky_halfw,
720  &hawki_sci_jitter_config.sky_rejmin,
721  &hawki_sci_jitter_config.sky_rejmax)!=4)
722  {
723  return -1;
724  }
725  par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.xcorr");
726  sval = cpl_parameter_get_string(par);
727  if (sscanf(sval, "%d,%d,%d,%d",
728  &hawki_sci_jitter_config.sx,
729  &hawki_sci_jitter_config.sy,
730  &hawki_sci_jitter_config.mx,
731  &hawki_sci_jitter_config.my)!=4)
732  {
733  return -1;
734  }
735  par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.refine");
736  hawki_sci_jitter_config.refine = cpl_parameter_get_bool(par);
737  par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.comb_meth");
738  sval = cpl_parameter_get_string(par);
739  if (!strcmp(sval, "union"))
740  hawki_sci_jitter_config.comb_meth = CPL_GEOM_UNION;
741  else if (!strcmp(sval, "inter"))
742  hawki_sci_jitter_config.comb_meth = CPL_GEOM_INTERSECT;
743  else if (!strcmp(sval, "first"))
744  hawki_sci_jitter_config.comb_meth = CPL_GEOM_FIRST;
745  else
746  {
747  cpl_msg_error(cpl_func, "Invalid combine method specified");
748  return -1;
749  }
750  par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.borders");
751  hawki_sci_jitter_config.borders = cpl_parameter_get_int(par);
752  par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.rej");
753  sval = cpl_parameter_get_string(par);
754  if (sscanf(sval, "%d,%d",
755  &hawki_sci_jitter_config.rej_low,
756  &hawki_sci_jitter_config.rej_high)!=2)
757  {
758  return -1;
759  }
760  par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.max_njitter");
761  hawki_sci_jitter_config.max_njitter = cpl_parameter_get_int(par);
762  return 0;
763 }
764 
765 
766 
767 /*----------------------------------------------------------------------------*/
778 /*----------------------------------------------------------------------------*/
779 static cpl_image ** hawki_sci_jitter_reduce
780 (cpl_frameset * jitters,
781  cpl_frameset * sky,
782  const char * flat,
783  const char * dark,
784  const char * bpm,
785  cpl_table ** bkg_stats)
786 {
787  cpl_frame * frame ;
788  cpl_propertylist * plist ;
789  cpl_image ** comb_chip ;
790  cpl_image ** combined ;
791  cpl_bivector * offsets ;
792  cpl_vector * offset_x_sort;
793  cpl_vector * offset_y_sort;
794  double * offs_est_x ;
795  double * offs_est_y ;
796  double off_0_x;
797  double off_0_y;
798  double max_x, max_y ;
799  int idet;
800  int ioff;
801 
802  /* Get the header infos */
803  frame = cpl_frameset_get_frame(jitters, 0) ;
804  plist=cpl_propertylist_load(cpl_frame_get_filename(frame), 0) ;
805  hawki_sci_jitter_output.pixscale = hawki_pfits_get_pixscale(plist) ;
806  hawki_sci_jitter_output.dit = hawki_pfits_get_dit(plist) ;
807  cpl_propertylist_delete(plist) ;
808  if (cpl_error_get_code()) {
809  cpl_msg_error(cpl_func, "Missing keyword in FITS header") ;
810  return NULL ;
811  }
812 
813  /* Check that DIT/NDIT and NDSAMPLES are the same for all the frames */
817  {
818  cpl_msg_error(__func__, "Not all input science have the same "
819  "DIT/NDIT/NDSAMPLES values");
820  cpl_msg_indent_less() ;
821  return NULL;
822  }
823 
824  /* Check that pointing is the same for all the frames */
827  {
828  cpl_msg_error(__func__, "Not all input science frames belong to the "
829  "same pointing/target. Check keywords TEL TARG ALPHA/DELTA");
830  cpl_msg_indent_less() ;
831  return NULL;
832  }
833 
834  /* Get the offsets */
835  if ((offsets = hawki_get_header_tel_offsets(jitters)) == NULL) {
836  cpl_msg_error(cpl_func, "Cannot load the offsets") ;
837  return NULL ;
838  }
839  offs_est_x = cpl_bivector_get_x_data(offsets) ;
840  offs_est_y = cpl_bivector_get_y_data(offsets) ;
841 
842  /* Print the header offsets */
843  for (ioff=0 ; ioff<cpl_bivector_get_size(offsets) ; ioff++) {
844  cpl_msg_info(cpl_func, "Telescope offsets (Frame %d): %g %g", ioff+1,
845  offs_est_x[ioff], offs_est_y[ioff]) ;
846  }
847 
848  /* Subtract the first offset to all offsets */
849  off_0_x = -offs_est_x[0]; // This is to get the cpl convention
850  off_0_y = -offs_est_y[0];
851  for (ioff=1 ; ioff<cpl_bivector_get_size(offsets) ; ioff++)
852  {
853  offs_est_x[ioff] -= offs_est_x[0] ;
854  offs_est_y[ioff] -= offs_est_y[0] ;
855  }
856  offs_est_x[0] = offs_est_y[0] = 0.00 ;
857 
858  /* Check if the max offset is not too big */
859  /* The criteria is that for a given frame, the closest frame cannot be
860  * further than hawki_sci_jitter_config.offset_max (in both dimensions) */
861  offset_x_sort = cpl_vector_duplicate(cpl_bivector_get_x(offsets));
862  offset_y_sort = cpl_vector_duplicate(cpl_bivector_get_y(offsets));
863  cpl_vector_sort(offset_x_sort, +1);
864  cpl_vector_sort(offset_y_sort, +1);
865  for (ioff=0 ; ioff<cpl_bivector_get_size(offsets) - 1 ; ioff++)
866  {
867  double diff_x, diff_y;
868  diff_x = cpl_vector_get(offset_x_sort,ioff+1)-cpl_vector_get(offset_x_sort,ioff);
869  cpl_vector_set(offset_x_sort, ioff, diff_x);
870  diff_y = cpl_vector_get(offset_y_sort,ioff+1)-cpl_vector_get(offset_y_sort,ioff);
871  cpl_vector_set(offset_y_sort, ioff, diff_y);
872  }
873  cpl_vector_set(offset_x_sort, cpl_bivector_get_size(offsets)-1, 0.);
874  cpl_vector_set(offset_y_sort, cpl_bivector_get_size(offsets)-1, 0.);
875  max_x = cpl_vector_get_max(offset_x_sort);
876  max_y = cpl_vector_get_max(offset_y_sort);
877  cpl_vector_delete(offset_x_sort);
878  cpl_vector_delete(offset_y_sort);
879 
880  if (max_x > hawki_sci_jitter_config.offset_max ||
881  max_y > hawki_sci_jitter_config.offset_max)
882  {
883  cpl_msg_error(cpl_func, "Sorry, no support for frames further than %d from its closest neighbour",
884  hawki_sci_jitter_config.offset_max) ;
885  cpl_bivector_delete(offsets);
886  return NULL ;
887  }
888 
889  /* Create output object */
890  combined = cpl_malloc(HAWKI_NB_DETECTORS*sizeof(cpl_image*)) ;
891 
892  /* Loop on the detectors */
893  for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
894  {
895  cpl_frameset * selected_jitter;
896  cpl_bivector * selected_offsets;
897  cpl_image * flat_ima = NULL;
898  cpl_image * dark_ima = NULL;
899  cpl_image * bpm_ima = NULL;
900  cpl_imagelist * in = NULL;
901  cpl_imagelist * in_sky = NULL;
902  int nrejected;
903 
904  cpl_msg_info(cpl_func, "Combine chip number %d", idet+1) ;
905  cpl_msg_indent_more() ;
906 
907  /* Apply frame selection based on offset values */
908  selected_jitter = cpl_frameset_duplicate(jitters);
909  selected_offsets = cpl_bivector_duplicate(offsets);
910  if(hawki_sci_jitter_config.max_njitter != -1)
911  {
912  if(hawki_sci_jitter_config.max_njitter <
913  cpl_frameset_get_size(selected_jitter))
914  {
915  while(cpl_frameset_get_size(selected_jitter) >
916  hawki_sci_jitter_config.max_njitter)
917  {
918  int irm = cpl_frameset_get_size(selected_jitter) - 1;
919  cpl_frameset_erase_frame
920  (selected_jitter,
921  cpl_frameset_get_frame(selected_jitter,irm));
922  }
923  cpl_vector_set_size(cpl_bivector_get_x(selected_offsets),
924  hawki_sci_jitter_config.max_njitter);
925  cpl_vector_set_size(cpl_bivector_get_y(selected_offsets),
926  hawki_sci_jitter_config.max_njitter);
927  }
928  }
929  hawki_sci_jitter_output.ncomb[idet] =
930  cpl_frameset_get_size(selected_jitter);
931  nrejected = cpl_frameset_get_size(selected_jitter) -
932  cpl_frameset_get_size(jitters);
933  if(nrejected != 0)
934  cpl_msg_info(cpl_func,"%d frames reject due to large offsets",
935  nrejected);
936 
937 
938  /* Load the input data */
939  cpl_msg_info(cpl_func, "Load the input data") ;
940  cpl_msg_indent_more() ;
941  if ((in = hawki_load_detector(selected_jitter,
942  idet+1, CPL_TYPE_FLOAT)) == NULL) {
943  cpl_msg_error(cpl_func, "Cannot load chip %d", idet+1) ;
944  cpl_free(combined) ;
945  cpl_bivector_delete(offsets) ;
946  cpl_msg_indent_less() ;
947  cpl_msg_indent_less() ;
948  return NULL ;
949  }
950  if (sky) {
951  if ((in_sky = hawki_load_detector(sky, idet+1, CPL_TYPE_FLOAT)) == NULL)
952  {
953  cpl_msg_warning(cpl_func, "Cannot load sky for chip %d",idet+1);
954  }
955  } else in_sky = NULL ;
956  cpl_msg_indent_less() ;
957 
958  /* Read the calibrations */
959  cpl_msg_info(cpl_func, "Load the calibration data") ;
960  if(hawki_sci_jitter_read_calib(flat, dark, bpm,
961  &flat_ima, &dark_ima, &bpm_ima,
962  idet) != 0)
963  {
964  cpl_msg_error(cpl_func, "Cannot read some of the calibrations");
965  cpl_imagelist_delete(in);
966  cpl_free(combined);
967  if (in_sky) cpl_imagelist_delete(in_sky);
968  cpl_bivector_delete(offsets);
969  cpl_msg_indent_less();
970  cpl_msg_indent_less();
971  return NULL ;
972  }
973 
974  /* Apply the calibrations */
975  if (flat || dark || bpm )
976  {
977  cpl_msg_info(cpl_func, "Apply the calibrations") ;
978  cpl_msg_indent_more() ;
979  /* Basic calibration of the OBJECTS */
981  (in, flat_ima, dark_ima, bpm_ima) == -1)
982  {
983  cpl_msg_error(cpl_func, "Cannot calibrate the objects") ;
984  cpl_imagelist_delete(in) ;
985  cpl_free(combined) ;
986  if (in_sky) cpl_imagelist_delete(in_sky) ;
987  cpl_bivector_delete(offsets) ;
988  cpl_image_delete(flat_ima);
989  cpl_image_delete(dark_ima);
990  cpl_image_delete(bpm_ima);
991  cpl_msg_indent_less() ;
992  cpl_msg_indent_less() ;
993  return NULL ;
994  }
995  /* Basic calibration of the SKY */
996  if (in_sky) {
998  (in_sky, flat_ima, dark_ima, bpm_ima) == -1)
999  {
1000  cpl_msg_warning(cpl_func, "Cannot calibrate the sky") ;
1001  cpl_imagelist_delete(in_sky) ;
1002  in_sky = NULL ;
1003  }
1004  }
1005  cpl_msg_indent_less() ;
1006  }
1007  cpl_image_delete(flat_ima);
1008  cpl_image_delete(dark_ima);
1009  cpl_image_delete(bpm_ima);
1010 
1011  /* Apply the sky correction */
1012  cpl_msg_info(cpl_func, "Sky estimation and correction") ;
1013  cpl_msg_indent_more() ;
1014  if (hawki_sci_jitter_sky(in, in_sky, bkg_stats, idet) == -1)
1015  {
1016  cpl_msg_error(cpl_func, "Cannot estimate the sky") ;
1017  cpl_imagelist_delete(in) ;
1018  if (in_sky) cpl_imagelist_delete(in_sky) ;
1019  cpl_free(combined) ;
1020  cpl_bivector_delete(offsets) ;
1021  cpl_msg_indent_less() ;
1022  cpl_msg_indent_less() ;
1023  return NULL ;
1024  }
1025  if (in_sky) cpl_imagelist_delete(in_sky) ;
1026  cpl_msg_indent_less() ;
1027 
1028  /* Apply the shift and add */
1029  cpl_msg_info(cpl_func, "Shift and stacking") ;
1030  cpl_msg_indent_more() ;
1031  comb_chip = hawki_sci_jitter_saa(&in, selected_offsets,
1032  &(hawki_sci_jitter_output.combined_pos_x[idet]),
1033  &(hawki_sci_jitter_output.combined_pos_y[idet])) ;
1034  hawki_sci_jitter_output.combined_cumoffset_x[idet] =
1035  hawki_sci_jitter_output.combined_pos_x[idet] - off_0_x;
1036  hawki_sci_jitter_output.combined_cumoffset_y[idet] =
1037  hawki_sci_jitter_output.combined_pos_y[idet] - off_0_y;
1038  if (comb_chip == NULL) {
1039  cpl_msg_error(cpl_func, "Cannot apply the shift and add") ;
1040  cpl_imagelist_delete(in) ;
1041  cpl_free(combined) ;
1042  cpl_bivector_delete(offsets) ;
1043  cpl_msg_indent_less() ;
1044  cpl_msg_indent_less() ;
1045  return NULL ;
1046  }
1047  cpl_imagelist_delete(in) ;
1048  cpl_msg_indent_less() ;
1049 
1050  /* Put the results in the image list */
1051  combined[idet] = comb_chip[0] ;
1052  cpl_image_delete(comb_chip[1]) ;
1053  cpl_free(comb_chip) ;
1054  cpl_msg_indent_less() ;
1055 
1056  /* Free */
1057  cpl_frameset_delete(selected_jitter);
1058  cpl_bivector_delete(selected_offsets);
1059  }
1060  cpl_bivector_delete(offsets) ;
1061 
1062  return combined ;
1063 }
1064 
1065 /*----------------------------------------------------------------------------*/
1072 /*----------------------------------------------------------------------------*/
1073 static int hawki_sci_jitter_sky
1074 (cpl_imagelist * objs,
1075  cpl_imagelist * skys,
1076  cpl_table ** bkg_stats,
1077  int idet)
1078 {
1079  cpl_image * sky ;
1080  int nframes;
1081  double median ;
1082  cpl_image * cur_ima ;
1083  int i ;
1084 
1085  /* Initialise */
1086  nframes = cpl_imagelist_get_size(objs) ;
1087 
1088  /* Compute the sky frame */
1089  if (skys != NULL) {
1090  cpl_msg_info(cpl_func, "Median of sky images") ;
1091  /* Use sky images */
1092  if ((sky = cpl_imagelist_collapse_median_create(skys)) == NULL) {
1093  cpl_msg_error(cpl_func, "Cannot compute the median of sky images") ;
1094  return -1;
1095  }
1096 
1097  /* Statistics on the background */
1098  if(bkg_stats != NULL)
1099  {
1100  cpl_table_set_size(bkg_stats[idet], 1);
1102  (bkg_stats, sky,
1103  1,
1104  1,
1105  cpl_image_get_size_x(sky),
1106  cpl_image_get_size_y(sky),
1107  idet, 0);
1108  }
1109 
1110  /* Correct the objects images */
1111  if (cpl_imagelist_subtract_image(objs, sky) != CPL_ERROR_NONE) {
1112  cpl_msg_error(cpl_func, "Cannot corr. the obj images from the sky");
1113  cpl_image_delete(sky) ;
1114  return -1;
1115  }
1116  cpl_image_delete(sky) ;
1117  /* Normalise the object planes */
1118  for (i=0 ; i<nframes ; i++) {
1119  cur_ima = cpl_imagelist_get(objs, i) ;
1120  median = cpl_image_get_median(cur_ima) ;
1121  cpl_image_subtract_scalar(cur_ima, median) ;
1122  }
1123  } else if (hawki_sci_jitter_config.sky_minnb > nframes) {
1124  cpl_msg_info(cpl_func, "Median of object images") ;
1125  /* Use objs images */
1126  if ((sky = cpl_imagelist_collapse_median_create(objs)) == NULL) {
1127  cpl_msg_error(cpl_func, "Cannot compute the median of obj images") ;
1128  return -1;
1129  }
1130 
1131  /* Statistics on the background */
1132  if(bkg_stats != NULL)
1133  {
1134  cpl_table_set_size(bkg_stats[idet], 1);
1136  (bkg_stats, sky,
1137  1,
1138  1,
1139  cpl_image_get_size_x(sky),
1140  cpl_image_get_size_y(sky),
1141  idet, 0);
1142  }
1143 
1144  /* Correct the objects images */
1145  if (cpl_imagelist_subtract_image(objs, sky) != CPL_ERROR_NONE) {
1146  cpl_msg_error(cpl_func, "Cannot corr. the obj images from the sky");
1147  cpl_image_delete(sky) ;
1148  return -1;
1149  }
1150  /* Normalise the object planes */
1151  for (i=0 ; i<nframes ; i++) {
1152  cur_ima = cpl_imagelist_get(objs, i) ;
1153  median = cpl_image_get_median(cur_ima) ;
1154  cpl_image_subtract_scalar(cur_ima, median) ;
1155  }
1156  /* Delete sky image */
1157  cpl_image_delete(sky) ;
1158  } else {
1159  cpl_msg_info(cpl_func, "Computing running median on jitter images") ;
1160  /* Use objects images */
1161  if (hawki_sci_jitter_sky_running(objs, bkg_stats, idet) == -1)
1162  {
1163  cpl_msg_error(cpl_func,
1164  "Cannot apply the running median");
1165  return -1;
1166  }
1167  }
1168  return 0;
1169 }
1170 
1171 /*----------------------------------------------------------------------------*/
1190 /*----------------------------------------------------------------------------*/
1191 static int hawki_sci_jitter_sky_running
1192 (cpl_imagelist * in,
1193  cpl_table ** bkg_stats,
1194  int idet)
1195 {
1196  int rejmin, rejmax, halfw;
1197  cpl_imagelist * result_buffer;
1198  int ni, nx, ny;
1199  cpl_vector * medians;
1200  cpl_image * cur_ima;
1201  cpl_image * tmp_ima;
1202  double one_med;
1203  int i, k;
1204  int first_buffered = 0;
1205  int next_not_to_be_used;
1206 
1207  /* Test entries */
1208  if (in==NULL) return -1;
1209 
1210  /* Initialise */
1211  rejmin = hawki_sci_jitter_config.sky_rejmin ;
1212  rejmax = hawki_sci_jitter_config.sky_rejmax ;
1213  halfw = hawki_sci_jitter_config.sky_halfw ;
1214  ni = cpl_imagelist_get_size(in) ;
1215  cur_ima = cpl_imagelist_get(in, 0) ;
1216  nx = cpl_image_get_size_x(cur_ima) ;
1217  ny = cpl_image_get_size_y(cur_ima) ;
1218 
1219  /* Tests on validity of rejection parameters */
1220  if (((rejmin+rejmax)>=halfw) || (halfw<1) || (rejmin<0) || (rejmax<0)) {
1221  cpl_msg_error(cpl_func, "cannot compute running median with "
1222  "rejection parameters %d (%d-%d)",
1223  halfw, rejmin, rejmax);
1224  return -1;
1225  }
1226  /* Pre-compute median value in each plane */
1227  medians = cpl_vector_new(ni) ;
1228  for (i=0 ; i<ni ; i++) {
1229  cur_ima = cpl_imagelist_get(in, i) ;
1230  cpl_vector_set(medians, i, cpl_image_get_median(cur_ima)) ;
1231  }
1232  /* Allocate output cube */
1233  result_buffer = cpl_imagelist_new() ;
1234 
1235  /* Allocate output bg stats */
1236  cpl_table_set_size(bkg_stats[idet], ni);
1237 
1238  /* Main loop over input planes */
1239  for (k=0 ; k<ni ; k++)
1240  {
1241  cpl_image * bkg;
1242 
1243  /* Create the background image, to later compute stats */
1244  bkg = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1245 
1246  hawki_bkg_from_running_mean
1247  (in, medians, k, halfw, rejmin, rejmax, bkg);
1248 
1249  /* Subtract the background from the current image */
1250  tmp_ima = cpl_image_subtract_create(cpl_imagelist_get(in, k), bkg);
1251 
1252  /* Statistics on the background */
1253  if(bkg_stats != NULL)
1254  {
1256  (bkg_stats, bkg,
1257  1, 1, nx, ny,
1258  idet, k);
1259  }
1260  cpl_image_delete(bkg);
1261 
1262  /* Place the new image in a result buffer */
1263  cpl_imagelist_set(result_buffer, tmp_ima,
1264  cpl_imagelist_get_size(result_buffer));
1265 
1266  /* Empty the buffer as much as possible */
1267  next_not_to_be_used = k - halfw;
1268  while(next_not_to_be_used >= first_buffered)
1269  {
1270  cpl_imagelist_set(in, cpl_imagelist_unset(result_buffer, 0),
1271  first_buffered);
1272  first_buffered++;
1273  }
1274  }
1275  /* Empty the buffer finally */
1276  next_not_to_be_used = ni - 1;
1277  while(next_not_to_be_used >= first_buffered)
1278  {
1279  cpl_imagelist_set(in, cpl_imagelist_unset(result_buffer, 0),
1280  first_buffered);
1281  first_buffered++;
1282  }
1283  cpl_imagelist_delete(result_buffer);
1284  cpl_vector_delete(medians);
1285 
1286  /* Subtract median from each frame */
1287  for (i=0 ; i<ni ; i++) {
1288  cur_ima = cpl_imagelist_get(in, i);
1289  one_med = cpl_image_get_median(cur_ima) ;
1290  cpl_image_subtract_scalar(cur_ima, one_med) ;
1291  }
1292  return 0;
1293 }
1294 
1295 /*----------------------------------------------------------------------------*/
1304 /*----------------------------------------------------------------------------*/
1305 static cpl_image ** hawki_sci_jitter_saa(
1306  cpl_imagelist ** in,
1307  cpl_bivector * offsets,
1308  double * pos_x,
1309  double * pos_y)
1310 {
1311  cpl_bivector * offs_est;
1312  cpl_bivector * offs_used;
1313  cpl_bivector * objs ;
1314  cpl_image ** combined ;
1315  int nfiles, ngood, nima, nx, ny ;
1316  int i;
1317 
1318  /* Check entries */
1319  if (pos_x == NULL || pos_y == NULL) return NULL ;
1320  if (offsets == NULL) return NULL ;
1321 
1322  /* Get the number of images */
1323  nfiles = cpl_imagelist_get_size(*in) ;
1324  if (cpl_bivector_get_size(offsets) != nfiles) {
1325  cpl_msg_error(cpl_func, "Invalid input objects sizes") ;
1326  return NULL ;
1327  }
1328 
1329  /* Get the offsets estimation of each input file pair */
1330  cpl_msg_info(cpl_func, "Get the offsets estimation") ;
1331  offs_est = NULL ;
1332  if (hawki_sci_jitter_config.offsets &&
1333  hawki_sci_jitter_config.offsets[0] != (char)0) {
1334  /* A file has been provided on the command line */
1335  offs_est = cpl_bivector_read((char*)hawki_sci_jitter_config.offsets);
1336  if ((offs_est==NULL)||(cpl_bivector_get_size(offs_est)!=nfiles)) {
1337  cpl_msg_error(cpl_func, "Cannot get offsets from %s",
1338  hawki_sci_jitter_config.offsets) ;
1339  return NULL ;
1340  }
1341  } else {
1342  /* Use the offsets from the header */
1343  offs_est = cpl_bivector_duplicate(offsets) ;
1344  cpl_vector_multiply_scalar(cpl_bivector_get_x(offs_est), -1.0) ;
1345  cpl_vector_multiply_scalar(cpl_bivector_get_y(offs_est), -1.0) ;
1346  }
1347 
1348  /* Read the provided objects file if provided */
1349  objs = NULL ;
1350  if (hawki_sci_jitter_config.refine &&
1351  hawki_sci_jitter_config.objects &&
1352  hawki_sci_jitter_config.objects[0] != (char)0) {
1353  cpl_msg_info(cpl_func, "Get the user provided correlation objects") ;
1354  /* A file has been provided on the command line */
1355  objs = cpl_bivector_read((char*)hawki_sci_jitter_config.objects) ;
1356  if (objs==NULL) {
1357  cpl_msg_error(cpl_func, "Cannot get objects from %s",
1358  hawki_sci_jitter_config.objects) ;
1359  cpl_bivector_delete(offs_est) ;
1360  return NULL ;
1361  }
1362  }
1363 
1364  /* Get a correlation point from the difference of the first images */
1365  if (hawki_sci_jitter_config.refine && objs == NULL) {
1366  cpl_apertures * aperts;
1367  cpl_image * detect_image;
1368  cpl_vector * thresh_vect;
1369  double * objs_x ;
1370  double * objs_y ;
1371  cpl_msg_info(cpl_func, "Get a cross-correlation point") ;
1372  thresh_vect = cpl_vector_new(4) ;
1373  cpl_vector_set(thresh_vect, 0, 5.0) ;
1374  cpl_vector_set(thresh_vect, 1, 2.0) ;
1375  cpl_vector_set(thresh_vect, 2, 1.0) ;
1376  cpl_vector_set(thresh_vect, 3, 0.5) ;
1377  detect_image = cpl_imagelist_get(*in, 0);
1378  if ((aperts = cpl_apertures_extract_window(detect_image, thresh_vect,
1379  400, 400, 1600, 1600, NULL)) == NULL) {
1380  cpl_msg_error(cpl_func, "Cannot find any cross-correlation point") ;
1381  cpl_bivector_delete(offs_est) ;
1382  cpl_vector_delete(thresh_vect) ;
1383  return NULL ;
1384  }
1385  cpl_vector_delete(thresh_vect) ;
1386  cpl_apertures_sort_by_npix(aperts) ;
1387  objs = cpl_bivector_new(1) ;
1388  objs_x = cpl_bivector_get_x_data(objs) ;
1389  objs_y = cpl_bivector_get_y_data(objs) ;
1390  objs_x[0] = cpl_apertures_get_pos_x(aperts, 1) ;
1391  objs_y[0] = cpl_apertures_get_pos_y(aperts, 1) ;
1392  cpl_apertures_delete(aperts) ;
1393  if (objs == NULL) {
1394  cpl_msg_error(cpl_func, "Cannot find any cross-correlation point") ;
1395  cpl_bivector_delete(offs_est) ;
1396  return NULL ;
1397  }
1398  cpl_msg_info(cpl_func,
1399  "Correlation point: %g %g\n", objs_x[0], objs_y[0]);
1400  }
1401 
1402  /* Refine the offsets */
1403  if (hawki_sci_jitter_config.refine) {
1404  cpl_bivector * offs_refined;
1405  double * offs_refined_x;
1406  double * offs_refined_y;
1407  double * offs_est_x;
1408  double * offs_est_y;
1409  cpl_vector * correl ;
1410  double * correl_data ;
1411  cpl_msg_info(cpl_func, "Refine the offsets");
1412  cpl_msg_indent_more() ;
1413  nima = cpl_imagelist_get_size(*in) ;
1414  correl = cpl_vector_new(nima) ;
1415  if ((offs_refined = cpl_geom_img_offset_fine(*in, offs_est, objs,
1416  hawki_sci_jitter_config.sx,
1417  hawki_sci_jitter_config.sy,
1418  hawki_sci_jitter_config.mx,
1419  hawki_sci_jitter_config.my,
1420  correl)) == NULL) {
1421  cpl_msg_error(cpl_func, "Cannot refine the offsets");
1422  cpl_bivector_delete(offs_est) ;
1423  if (objs != NULL) cpl_bivector_delete(objs) ;
1424  cpl_vector_delete(correl) ;
1425  return NULL ;
1426  }
1427  if (objs != NULL) cpl_bivector_delete(objs) ;
1428 
1429  /* Display the results */
1430  offs_est_x = cpl_bivector_get_x_data(offs_est);
1431  offs_est_y = cpl_bivector_get_y_data(offs_est);
1432  offs_refined_x = cpl_bivector_get_x_data(offs_refined);
1433  offs_refined_y = cpl_bivector_get_y_data(offs_refined) ;
1434  correl_data = cpl_vector_get_data(correl) ;
1435  cpl_msg_info(cpl_func, "Refined offsets [correlation factor]") ;
1436  ngood = 0 ;
1437  for (i=0 ; i<nima ; i++) {
1438  cpl_msg_info(cpl_func, "#%02d: %8.2f %8.2f [%12.2f]",
1439  i+1, offs_refined_x[i], offs_refined_y[i], correl_data[i]);
1440  if (correl_data[i] > -0.5) ngood++ ;
1441  }
1442  if (ngood == 0) {
1443  cpl_msg_error(cpl_func, "No frame correctly correlated") ;
1444  cpl_bivector_delete(offs_est);
1445  cpl_bivector_delete(offs_refined);
1446  cpl_vector_delete(correl);
1447  return NULL ;
1448  }
1449  cpl_msg_indent_less();
1450 
1451  /* Replace bad correlated images with the nominal offsets */
1452  cpl_msg_info(cpl_func, "Using nominal offsets for badly "
1453  "correlated images (%d out of %d)", nima-ngood, nima);
1454  for (i=0 ; i<nima ; i++) {
1455  if (correl_data[i] < -0.5) {
1456  offs_refined_x[i] = offs_est_x[i];
1457  offs_refined_y[i] = offs_est_y[i];
1458  }
1459  }
1460  offs_used = cpl_bivector_duplicate(offs_refined);
1461  cpl_bivector_delete(offs_est);
1462  cpl_bivector_delete(offs_refined);
1463  cpl_vector_delete(correl);
1464  }
1465  else
1466  {
1467  offs_used = cpl_bivector_duplicate(offs_est);
1468  cpl_bivector_delete(offs_est);
1469  }
1470 
1471  /* Discard the pixels on the sides */
1472  if (hawki_sci_jitter_config.borders > 0) {
1473  cpl_imagelist * in_ext ;
1474  cpl_image * tmp1 ;
1475  cpl_image * tmp2 ;
1476  nx = cpl_image_get_size_x(cpl_imagelist_get(*in, 0)) ;
1477  ny = cpl_image_get_size_y(cpl_imagelist_get(*in, 0)) ;
1478  in_ext = cpl_imagelist_new() ;
1479  while(cpl_imagelist_get_size(*in) > 0)
1480  {
1481  tmp1 = cpl_imagelist_unset(*in, 0);
1482  tmp2 = cpl_image_extract(tmp1,
1483  hawki_sci_jitter_config.borders+1,
1484  hawki_sci_jitter_config.borders+1,
1485  nx-hawki_sci_jitter_config.borders,
1486  ny-hawki_sci_jitter_config.borders) ;
1487  cpl_image_delete(tmp1);
1488  cpl_imagelist_set(in_ext, tmp2, cpl_imagelist_get_size(in_ext)) ;
1489  }
1490  cpl_imagelist_delete(*in) ;
1491  *in = in_ext ;
1492  }
1493 
1494  /* Apply the shift & add */
1495  cpl_msg_info(cpl_func, "Recombine the images set") ;
1496  cpl_msg_indent_more() ;
1497  if ((combined=cpl_geom_img_offset_saa(*in, offs_used,
1498  CPL_KERNEL_DEFAULT,
1499  hawki_sci_jitter_config.rej_low,
1500  hawki_sci_jitter_config.rej_high,
1501  hawki_sci_jitter_config.comb_meth,
1502  pos_x, pos_y)) == NULL) {
1503  cpl_msg_error(cpl_func, "Cannot apply the shift and add") ;
1504  cpl_bivector_delete(offs_used) ;
1505  cpl_msg_indent_less() ;
1506  return NULL ;
1507  }
1508  cpl_msg_indent_less() ;
1509  *pos_x -= hawki_sci_jitter_config.borders ;
1510  *pos_y -= hawki_sci_jitter_config.borders ;
1511 
1512  /* Free and return */
1513  cpl_bivector_delete(offs_used) ;
1514  return combined ;
1515 }
1516 
1517 /*----------------------------------------------------------------------------*/
1524 /*----------------------------------------------------------------------------*/
1525 static int hawki_sci_jitter_qc
1526 (cpl_frameset * science_frames,
1527  cpl_image ** combined_images,
1528  cpl_table ** obj_charac)
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_bivector * iqe ;
1537  int nb_good ;
1538  cpl_vector * fwhms_good ;
1539  double * fwhms_good_data ;
1540  double f_min, f_max, fr, fx, fy ;
1541  int chip;
1542  int iobj;
1543  int j;
1544 
1545  /* Initialise */
1546  double seeing_min_arcsec = 0.1 ;
1547  double seeing_max_arcsec = 5.0 ;
1548  double seeing_fwhm_var = 0.2 ;
1549 
1550  /* Check entries */
1551  if (combined_images == NULL) return -1 ;
1552  if (obj_charac == NULL) return -1 ;
1553 
1554  /* Create the vector for the detection thresholds */
1555  thresh_vec = cpl_vector_new(11) ;
1556  cpl_vector_set(thresh_vec, 0, 100.0) ;
1557  cpl_vector_set(thresh_vec, 0, 90.0) ;
1558  cpl_vector_set(thresh_vec, 0, 80.0) ;
1559  cpl_vector_set(thresh_vec, 0, 70.0) ;
1560  cpl_vector_set(thresh_vec, 0, 60.0) ;
1561  cpl_vector_set(thresh_vec, 0, 50.0) ;
1562  cpl_vector_set(thresh_vec, 1, 40.0) ;
1563  cpl_vector_set(thresh_vec, 1, 30.0) ;
1564  cpl_vector_set(thresh_vec, 1, 20.0) ;
1565  cpl_vector_set(thresh_vec, 1, 10.0) ;
1566  cpl_vector_set(thresh_vec, 2, 5.0) ;
1567 
1568  /* Get the mean airmass */
1569  hawki_sci_jitter_output.mean_airmass =
1570  hawki_get_mean_airmass(science_frames);;
1571 
1572  /* Loop on the HAWK-I detectors */
1573  for (chip=0 ; chip<HAWKI_NB_DETECTORS ; chip++)
1574  {
1575  /* Check entries */
1576  if (combined_images[chip] == NULL) return -1 ;
1577  if (obj_charac[chip] == NULL) return -1 ;
1578 
1579  /* Detect apertures */
1580  if ((aperts = cpl_apertures_extract
1581  (combined_images[chip], thresh_vec, NULL)) == NULL) {
1582  cpl_msg_warning(cpl_func, "Cannot detect any aperture on chip %d",
1583  chip+1) ;
1584  continue;
1585  }
1586 
1587  /* Number of detected objects */
1588  nb_objs = cpl_apertures_get_size(aperts);
1589  cpl_msg_info(cpl_func, "%d objects detected on chip %d",nb_objs,chip+1);
1590  hawki_sci_jitter_output.nbobjs[chip] = nb_objs ;
1591  fwhms_x = cpl_malloc(nb_objs * sizeof(double)) ;
1592  fwhms_y = cpl_malloc(nb_objs * sizeof(double)) ;
1593 
1594  /* Initialize the output table */
1595  cpl_table_set_size(obj_charac[chip], nb_objs);
1596  cpl_table_new_column
1597  (obj_charac[chip], HAWKI_COL_OBJ_POSX, CPL_TYPE_DOUBLE);
1598  cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_POSX,"pix");
1599  cpl_table_new_column
1600  (obj_charac[chip], HAWKI_COL_OBJ_POSY, CPL_TYPE_DOUBLE);
1601  cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_POSY,"pix");
1602  cpl_table_new_column
1603  (obj_charac[chip], HAWKI_COL_OBJ_ANGLE, CPL_TYPE_DOUBLE);
1604  cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_ANGLE,"grad");
1605  cpl_table_new_column
1606  (obj_charac[chip], HAWKI_COL_OBJ_FWHM_MAJAX, CPL_TYPE_DOUBLE);
1607  cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_FWHM_MAJAX,"pix");
1608  cpl_table_new_column
1609  (obj_charac[chip], HAWKI_COL_OBJ_FWHM_MINAX, CPL_TYPE_DOUBLE);
1610  cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_FWHM_MINAX,"pix");
1611  cpl_table_new_column
1612  (obj_charac[chip], HAWKI_COL_OBJ_ELLIP, CPL_TYPE_DOUBLE);
1613  cpl_table_new_column
1614  (obj_charac[chip], HAWKI_COL_OBJ_FLUX, CPL_TYPE_DOUBLE);
1615  cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_FLUX,"ADU");
1616  for (iobj=0 ; iobj<nb_objs ; iobj++)
1617  {
1618  /* Fill with the already known information */
1619  cpl_table_set_double(obj_charac[chip], HAWKI_COL_OBJ_POSX, iobj,
1620  cpl_apertures_get_centroid_x(aperts, iobj+1));
1621  cpl_table_set_double(obj_charac[chip], HAWKI_COL_OBJ_POSY, iobj,
1622  cpl_apertures_get_centroid_y(aperts, iobj+1));
1623  cpl_table_set_double(obj_charac[chip], HAWKI_COL_OBJ_FLUX, iobj,
1624  cpl_apertures_get_flux(aperts, iobj+1)) ;
1625  /* Compute the FWHM informations */
1626  if ((iqe = cpl_image_iqe(combined_images[chip],
1627  (int)cpl_apertures_get_centroid_x(aperts, iobj+1) - 10,
1628  (int)cpl_apertures_get_centroid_y(aperts, iobj+1) - 10,
1629  (int)cpl_apertures_get_centroid_x(aperts, iobj+1) + 10,
1630  (int)cpl_apertures_get_centroid_y(aperts, iobj+1) + 10))==NULL)
1631  {
1632  cpl_error_reset() ;
1633  cpl_msg_debug(cpl_func, "Cannot get FWHM for obj at pos %g %g",
1634  cpl_apertures_get_centroid_x(aperts, iobj+1),
1635  cpl_apertures_get_centroid_y(aperts, iobj+1)) ;
1636  fwhms_x[iobj] = -1.0 ;
1637  fwhms_y[iobj] = -1.0 ;
1638  angle = 0.0 ;
1639  }
1640  else
1641  {
1642  fwhms_x[iobj] = cpl_vector_get(cpl_bivector_get_x(iqe), 2) ;
1643  fwhms_y[iobj] = cpl_vector_get(cpl_bivector_get_x(iqe), 3) ;
1644  angle = cpl_vector_get(cpl_bivector_get_x(iqe), 4) ;
1645  cpl_bivector_delete(iqe) ;
1646  cpl_msg_debug(cpl_func,
1647  "FWHM for obj at pos %g %g: %g x %g (%g)",
1648  cpl_apertures_get_centroid_x(aperts, iobj+1),
1649  cpl_apertures_get_centroid_y(aperts, iobj+1),
1650  fwhms_x[iobj], fwhms_y[iobj], angle) ;
1651  }
1652  cpl_table_set_double
1653  (obj_charac[chip], HAWKI_COL_OBJ_ANGLE, iobj, angle) ;
1654  cpl_table_set_double
1655  (obj_charac[chip], HAWKI_COL_OBJ_FWHM_MAJAX, iobj,
1656  fwhms_x[iobj]);
1657  cpl_table_set_double
1658  (obj_charac[chip], HAWKI_COL_OBJ_FWHM_MINAX, iobj,
1659  fwhms_y[iobj]);
1660  cpl_table_set_double
1661  (obj_charac[chip], HAWKI_COL_OBJ_ELLIP, iobj,
1662  1 - fwhms_y[iobj] / fwhms_x[iobj]);
1663  }
1664  cpl_apertures_delete(aperts) ;
1665 
1666  /* Get the number of good values */
1667  nb_good = 0 ;
1668  for (iobj=0 ; iobj<nb_objs ; iobj++)
1669  {
1670  if ((fwhms_x[iobj] > 0.0) && (fwhms_y[iobj] > 0.0)) nb_good++ ;
1671  }
1672  if (nb_good == 0)
1673  {
1674  cpl_msg_warning(cpl_func, "No objects to compute FWHM on chip %d",
1675  chip+1);
1676  cpl_free(fwhms_x) ;
1677  cpl_free(fwhms_y) ;
1678  continue;
1679  }
1680 
1681  /* Get the good values */
1682  fwhms_good = cpl_vector_new(nb_good) ;
1683  fwhms_good_data = cpl_vector_get_data(fwhms_good) ;
1684  j=0 ;
1685  for (iobj=0 ; iobj<nb_objs ; iobj++)
1686  {
1687  if ((fwhms_x[iobj] > 0.0) && (fwhms_y[iobj] > 0.0))
1688  {
1689  fwhms_good_data[j] = (fwhms_x[iobj]+fwhms_y[iobj])/2.0 ;
1690  j++ ;
1691  }
1692  }
1693 
1694  /* Compute the fwhm */
1695  if (nb_good < 3)
1696  {
1697  /* Too few values to compute the median */
1698  hawki_sci_jitter_output.fwhm_pix[chip] = fwhms_good_data[0] ;
1699  }
1700  else
1701  {
1702  /* Compute the median */
1703  hawki_sci_jitter_output.fwhm_pix[chip] =
1704  cpl_vector_get_median_const(fwhms_good) ;
1705  }
1706  hawki_sci_jitter_output.fwhm_arcsec[chip] =
1707  hawki_sci_jitter_output.fwhm_pix[chip] *
1708  hawki_sci_jitter_output.pixscale ;
1709 
1710  /* Compute the mode of the FWHMs */
1711  if (nb_good > 5)
1712  {
1713  hawki_sci_jitter_output.fwhm_mode[chip] =
1714  hawki_vector_get_mode(fwhms_good);
1715  hawki_sci_jitter_output.fwhm_mode[chip] *=
1716  hawki_sci_jitter_output.pixscale ;
1717  }
1718  cpl_vector_delete(fwhms_good) ;
1719 
1720  /* IQ is the median of the (fwhm_x+fwhm_y/2) of the good stars */
1721  /* Compute f_min and f_max */
1722  f_min = seeing_min_arcsec / hawki_sci_jitter_output.pixscale ;
1723  f_max = seeing_max_arcsec / hawki_sci_jitter_output.pixscale ;
1724 
1725  /* Get the number of good values */
1726  nb_good = 0 ;
1727  for (iobj=0 ; iobj<nb_objs ; iobj++)
1728  {
1729  fx = fwhms_x[iobj] ;
1730  fy = fwhms_y[iobj] ;
1731  fr = 2.0 * fabs(fx-fy) / (fx+fy) ;
1732  if ((fx > f_min) && (fx < f_max) && (fy > f_min) && (fy < f_max) &&
1733  (fr < seeing_fwhm_var)) nb_good++ ;
1734  }
1735  if (nb_good == 0)
1736  {
1737  cpl_msg_warning(cpl_func, "No objects to compute IQ on chip %d",
1738  chip+1);
1739  cpl_free(fwhms_x) ;
1740  cpl_free(fwhms_y) ;
1741  continue;
1742  }
1743 
1744  /* Get the good values */
1745  fwhms_good = cpl_vector_new(nb_good) ;
1746  fwhms_good_data = cpl_vector_get_data(fwhms_good) ;
1747  j=0 ;
1748  for (iobj=0 ; iobj<nb_objs ; iobj++)
1749  {
1750  fx = fwhms_x[iobj] ;
1751  fy = fwhms_y[iobj] ;
1752  fr = 2.0 * fabs(fx-fy) / (fx+fy) ;
1753  if ((fx > f_min) && (fx < f_max) && (fy > f_min) && (fy < f_max) &&
1754  (fr < seeing_fwhm_var))
1755  {
1756  fwhms_good_data[j] = (fx + fy)/2.0 ;
1757  j++ ;
1758  }
1759  }
1760  cpl_free(fwhms_x) ;
1761  cpl_free(fwhms_y) ;
1762 
1763  /* Compute the fwhm */
1764  if (nb_good < 3)
1765  {
1766  /* Too few values to compute the median */
1767  hawki_sci_jitter_output.iq[chip] = fwhms_good_data[0] ;
1768  }
1769  else
1770  {
1771  /* Compute the median */
1772  hawki_sci_jitter_output.iq[chip] =
1773  cpl_vector_get_median_const(fwhms_good) ;
1774  }
1775  cpl_vector_delete(fwhms_good) ;
1776  hawki_sci_jitter_output.iq[chip] *= hawki_sci_jitter_output.pixscale ;
1777  }
1778 
1779  /* Cleanup */
1780  cpl_vector_delete(thresh_vec) ;
1781 
1782  return 0;
1783 }
1784 
1785 /*----------------------------------------------------------------------------*/
1797 /*----------------------------------------------------------------------------*/
1798 static int hawki_sci_jitter_read_calib
1799 (const char * flat,
1800  const char * dark,
1801  const char * bpm,
1802  cpl_image ** flat_image,
1803  cpl_image ** dark_image,
1804  cpl_image ** bpm_image,
1805  int idet)
1806 {
1807  const char * reffile;
1808  int ext_nb;
1809 
1810  if(flat == NULL && dark == NULL && bpm == NULL)
1811  return 0;
1812  if(*flat_image != NULL || *dark_image != NULL || *bpm_image != NULL)
1813  return 0;
1814 
1815  /* Get the extension number for this detector */
1816  if(flat != NULL)
1817  reffile = flat;
1818  else if(dark != NULL)
1819  reffile = dark;
1820  else
1821  reffile = bpm;
1822 
1823  /* Guess which is the extension to read */
1824  if ((ext_nb = hawki_get_ext_from_detector(reffile, idet + 1)) == -1) {
1825  cpl_msg_error(cpl_func, "Cannot get the extension with detector %d",
1826  idet + 1);
1827  return -1;
1828  }
1829 
1830  /* Load the dark image */
1831  if(dark != NULL)
1832  *dark_image = cpl_image_load(dark, CPL_TYPE_FLOAT, 0, ext_nb);
1833  /* Load the flat image */
1834  if(flat != NULL)
1835  *flat_image = cpl_image_load(flat, CPL_TYPE_FLOAT, 0, ext_nb);
1836  /* Load the bpm image */
1837  if(bpm != NULL)
1838  *bpm_image = cpl_image_load(bpm, CPL_TYPE_FLOAT, 0, ext_nb);
1839 
1840  /* Multiply the dark image by the science exposure time */
1841  if(dark != NULL)
1842  cpl_image_multiply_scalar(*dark_image, hawki_sci_jitter_output.dit);
1843 
1844  /* Return */
1845  return 0;
1846 }
1847 
1848 /*----------------------------------------------------------------------------*/
1857 /*----------------------------------------------------------------------------*/
1858 static int hawki_sci_jitter_save
1859 (cpl_image ** combined,
1860  cpl_image * stitched,
1861  cpl_table ** obj_charac,
1862  cpl_table ** raw_jitter_stats,
1863  cpl_table ** bkg_stats,
1864  const cpl_table * raw_obj_tel_info,
1865  cpl_frameset * science_frames,
1866  cpl_frameset * calib_frames,
1867  cpl_parameterlist * parlist,
1868  cpl_frameset * set)
1869 {
1870  cpl_propertylist * plist ;
1871  double pscale, dit, bg_mean, bg_stdev, bg_instmag ;
1872  cpl_propertylist ** qclists ;
1873  const cpl_frame * ref_frame ;
1874  cpl_frameset * used_frames;
1875  cpl_propertylist * wcslist ;
1876  cpl_propertylist * telstats;
1877  cpl_propertylist * inputlist ;
1878  double crpix1, crpix2 ;
1879  int ext_nb ;
1880  const char * recipe_name = "hawki_sci_jitter" ;
1881  int i;
1882  int ext_chip_1;
1883  cpl_errorstate error_prevstate = cpl_errorstate_get();
1884 
1885  /* Initialise */
1886  pscale = hawki_sci_jitter_output.pixscale;
1887  dit = hawki_sci_jitter_output.dit;
1888 
1889  /* Get reference frame */
1890  ref_frame = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW);
1891 
1892  /* Get the used frames */
1893  used_frames = cpl_frameset_duplicate(science_frames);
1894  for(i = 0; i< cpl_frameset_get_size(calib_frames); ++i)
1895  cpl_frameset_insert(used_frames,
1896  cpl_frame_duplicate(cpl_frameset_get_frame(calib_frames, i)));
1897 
1898  /* Create the telescope data statistics */
1899  telstats = cpl_propertylist_new();
1900  hawki_compute_prop_tel_qc_stats(raw_obj_tel_info, telstats);
1901 
1902  /* Create the QC lists */
1903  qclists = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_propertylist*)) ;
1904  for (i=0 ; i<HAWKI_NB_DETECTORS ; i++) {
1905 
1906  /* Get the extension number */
1907  ext_nb=hawki_get_ext_from_detector(cpl_frame_get_filename(ref_frame), i+1);
1908 
1909  /* Handle WCS keys */
1910  wcslist = cpl_propertylist_load_regexp(
1911  cpl_frame_get_filename(ref_frame), ext_nb, HAWKI_HEADER_WCS, 0);
1912  qclists[i] = cpl_propertylist_new() ;
1913 
1914  /* Compute bg_instmag */
1915  bg_mean = cpl_table_get_column_mean(bkg_stats[i], HAWKI_COL_STAT_MEAN);
1916  if (cpl_table_get_nrow(bkg_stats[i]) < 2) bg_stdev = 0 ;
1917  else bg_stdev = cpl_table_get_column_stdev
1918  (bkg_stats[i], HAWKI_COL_STAT_MEAN);
1919  if(bg_mean >= 0)
1920  bg_instmag = -2.5 * log10(bg_mean/(pscale*pscale*dit));
1921  else
1922  bg_instmag = 0;
1923 
1924  /* Fill the QC */
1925  cpl_propertylist_append_double
1926  (qclists[i], "ESO QC BACKGD MEAN", bg_mean);
1927  cpl_propertylist_set_comment(qclists[i], "ESO QC BACKGD MEAN",
1928  "Mean of all the image mean backgrounds");
1929  cpl_propertylist_append_double
1930  (qclists[i], "ESO QC BACKGD STDEV", bg_stdev);
1931  cpl_propertylist_set_comment(qclists[i], "ESO QC BACKGD STDEV",
1932  "The standard deviation of all the image mean backgrounds");
1933  cpl_propertylist_append_double
1934  (qclists[i], "ESO QC BACKGD INSTMAG", bg_instmag) ;
1935  cpl_propertylist_set_comment(qclists[i], "ESO QC BACKGD INSTMAG",
1936  "Mean of all the image mean backgrounds in instrumental magnitudes");
1937  cpl_propertylist_append_int
1938  (qclists[i], "ESO QC NBOBJS", hawki_sci_jitter_output.nbobjs[i]);
1939  cpl_propertylist_set_comment(qclists[i], "ESO QC NBOBJS",
1940  "Number of detected objects in the combined image");
1941  cpl_propertylist_append_double
1942  (qclists[i], "ESO QC IQ", hawki_sci_jitter_output.iq[i]);
1943  cpl_propertylist_set_comment(qclists[i], "ESO QC IQ",
1944  "Estimated image quality [arcsec]");
1945  cpl_propertylist_append_double
1946  (qclists[i], "ESO QC IQ DIFF AMBI",
1947  hawki_sci_jitter_output.iq[i] - cpl_propertylist_get_double
1948  (telstats, "ESO QC TEL AMBI FWHM MEAN"));
1949  cpl_propertylist_set_comment(qclists[i], "ESO QC IQ DIFF AMBI",
1950  "Mean Observatory seeing measured by AS");
1951  cpl_propertylist_append_double
1952  (qclists[i], "ESO QC IQ DIFF TEL",
1953  hawki_sci_jitter_output.iq[i] - cpl_propertylist_get_double
1954  (telstats, "ESO QC TEL IA FWHM MEAN"));
1955  cpl_propertylist_set_comment(qclists[i], "ESO QC IQ DIFF TEL",
1956  "Mean Observatory seeing measured by AS corrected by airmass");
1957  cpl_propertylist_append_double
1958  (qclists[i], "ESO QC FWHM PIX",
1959  hawki_sci_jitter_output.fwhm_pix[i]);
1960  cpl_propertylist_set_comment(qclists[i], "ESO QC FWHM PIX",
1961  "The median FWHM in the image [pixels]");
1962  cpl_propertylist_append_double
1963  (qclists[i], "ESO QC FWHM ARCSEC",
1964  hawki_sci_jitter_output.fwhm_arcsec[i]);
1965  cpl_propertylist_set_comment(qclists[i], "ESO QC FWHM ARCSEC",
1966  "The median FWHM in the image [arcsec]");
1967  cpl_propertylist_append_double
1968  (qclists[i], "ESO QC FWHM MODE",
1969  hawki_sci_jitter_output.fwhm_mode[i]);
1970  cpl_propertylist_set_comment(qclists[i], "ESO QC FWHM MODE",
1971  "The mode FWHM in the image [pixels]");
1972  cpl_propertylist_append_double
1973  (qclists[i], "ESO QC COMBINED POSX",
1974  hawki_sci_jitter_output.combined_pos_x[i]);
1975  cpl_propertylist_set_comment(qclists[i], "ESO QC COMBINED POSX",
1976  "Position in X of the first image");
1977  cpl_propertylist_append_double
1978  (qclists[i], "ESO QC COMBINED POSY",
1979  hawki_sci_jitter_output.combined_pos_y[i]);
1980  cpl_propertylist_set_comment(qclists[i], "ESO QC COMBINED POSY",
1981  "Position in Y of the first image");
1982  cpl_propertylist_append_double
1983  (qclists[i], "ESO QC COMBINED CUMOFFSETX",
1984  hawki_sci_jitter_output.combined_cumoffset_x[i]);
1985  cpl_propertylist_append_double
1986  (qclists[i], "ESO QC COMBINED CUMOFFSETY",
1987  hawki_sci_jitter_output.combined_cumoffset_y[i]);
1988  cpl_propertylist_append_int
1989  (qclists[i], "ESO QC DATANCOM",hawki_sci_jitter_output.ncomb[i]);
1990  cpl_propertylist_set_comment(qclists[i], "ESO QC DATANCOM",
1991  "Number of files used for the reduction");
1992  cpl_propertylist_append_double
1993  (qclists[i], "ESO QC AIRMASS MEAN",
1994  hawki_sci_jitter_output.mean_airmass);
1995  cpl_propertylist_set_comment(qclists[i], "ESO QC AIRMASS MEAN",
1996  "Average airmass");
1997 
1998  /* Update WCS and write them */
1999  crpix1 = cpl_propertylist_get_double(wcslist, "CRPIX1");
2000  crpix1 += hawki_sci_jitter_output.combined_pos_x[i];
2001  cpl_propertylist_update_double(wcslist, "CRPIX1", crpix1) ;
2002  crpix2 = cpl_propertylist_get_double(wcslist, "CRPIX2");
2003  crpix2 += hawki_sci_jitter_output.combined_pos_y[i] ;
2004  cpl_propertylist_update_double(wcslist, "CRPIX2", crpix2) ;
2005  cpl_propertylist_copy_property_regexp
2006  (qclists[i], wcslist, HAWKI_HEADER_WCS, 0) ;
2007  cpl_propertylist_delete(wcslist);
2008 
2009  /* Propagate some keywords from input raw frame extensions */
2010  inputlist = cpl_propertylist_load_regexp(
2011  cpl_frame_get_filename(ref_frame), ext_nb,
2012  HAWKI_HEADER_EXT_FORWARD, 0) ;
2013  cpl_propertylist_append(qclists[i], inputlist);
2014  cpl_propertylist_delete(inputlist) ;
2015  }
2016 
2017  /* Statistics of the raw images in the QC */
2018  hawki_image_stats_stats(raw_jitter_stats, qclists);
2019 
2020  /* Statistics of the detected objects in the QC */
2021  hawki_obj_prop_stats(obj_charac, qclists);
2022 
2023  /* Write the combined image */
2024  hawki_images_save(set,
2025  parlist,
2026  used_frames,
2027  (const cpl_image **)combined,
2028  recipe_name,
2029  HAWKI_CALPRO_COMBINED,
2030  HAWKI_PROTYPE_COMBINED,
2031  NULL,
2032  (const cpl_propertylist**)qclists,
2033  "hawki_sci_jitter.fits");
2034 
2035  /* Erase the WCS */
2036  for (i=0 ; i<HAWKI_NB_DETECTORS ; i++) {
2037  cpl_propertylist_erase_regexp(qclists[i], HAWKI_HEADER_WCS, 0) ;
2038  }
2039 
2040  /* Create a propertylist for PRO.x */
2041  plist = cpl_propertylist_new();
2042  cpl_propertylist_append_string(plist, CPL_DFS_PRO_TYPE,
2043  HAWKI_PROTYPE_STITCHED) ;
2044  cpl_propertylist_append_string(plist, CPL_DFS_PRO_CATG,
2045  HAWKI_CALPRO_STITCHED) ;
2046  /* Handle WCS keys */
2047  ext_chip_1 = 1;
2048  wcslist = cpl_propertylist_load_regexp(
2049  cpl_frame_get_filename(ref_frame), ext_chip_1, HAWKI_HEADER_WCS, 0);
2050  /* Update WCS and write them */
2051  crpix1 = cpl_propertylist_get_double(wcslist, "CRPIX1");
2052  crpix1 += hawki_sci_jitter_output.combined_pos_x[0];
2053  cpl_propertylist_update_double(wcslist, "CRPIX1", crpix1) ;
2054  crpix2 = cpl_propertylist_get_double(wcslist, "CRPIX2");
2055  crpix2 += hawki_sci_jitter_output.combined_pos_y[0] ;
2056  cpl_propertylist_update_double(wcslist, "CRPIX2", crpix2) ;
2057  cpl_propertylist_append(plist, wcslist);
2058  cpl_propertylist_delete(wcslist) ;
2059  /* Write the stitched image */
2060  cpl_dfs_save_image(set,
2061  NULL,
2062  parlist,
2063  used_frames,
2064  NULL,
2065  stitched,
2066  CPL_BPP_IEEE_FLOAT,
2067  recipe_name,
2068  plist,
2069  NULL,
2070  PACKAGE "/" PACKAGE_VERSION,
2071  "hawki_sci_jitter_stitched.fits");
2072  cpl_propertylist_delete(plist);
2073 
2074  /* Write the FITS table with the objects statistics */
2075  if (obj_charac)
2076  {
2077  hawki_tables_save(set,
2078  parlist,
2079  used_frames,
2080  (const cpl_table **)obj_charac,
2081  recipe_name,
2082  HAWKI_CALPRO_OBJ_PARAM,
2083  HAWKI_PROTYPE_OBJ_PARAM,
2084  NULL,
2085  (const cpl_propertylist**)qclists,
2086  "hawki_sci_jitter_stars.fits");
2087  }
2088 
2089  /* Write the table with the background statistics */
2090  hawki_tables_save(set,
2091  parlist,
2092  used_frames,
2093  (const cpl_table **)bkg_stats,
2094  recipe_name,
2095  HAWKI_CALPRO_JITTER_BKG_STATS,
2096  HAWKI_PROTYPE_JITTER_BKG_STATS,
2097  NULL,
2098  (const cpl_propertylist **)qclists,
2099  "hawki_sci_jitter_bkg_stats.fits");
2100 
2101  /* Free and return */
2102  cpl_frameset_delete(used_frames);
2103  for (i=0 ; i<HAWKI_NB_DETECTORS ; i++) {
2104  cpl_propertylist_delete(qclists[i]) ;
2105  }
2106  cpl_propertylist_delete(telstats) ;
2107  cpl_free(qclists) ;
2108  if(!cpl_errorstate_is_equal(error_prevstate))
2109  {
2110  cpl_errorstate_set(CPL_ERROR_NONE);
2111  return -1;
2112  }
2113  return 0;
2114 }
2115 
2116 int hawki_sci_jitter_whole_image_algo
2117 (cpl_frameset * obj,
2118  cpl_table ** raw_jitter_stats,
2119  cpl_table * raw_obj_tel_info,
2120  cpl_parameterlist * parlist,
2121  cpl_frameset * recipe_set)
2122 {
2123  int nframes;
2124  int iframe;
2125 
2126 
2127  nframes = cpl_frameset_get_size(obj);
2128  for( iframe = 0 ; iframe < nframes ; ++iframe)
2129  {
2130  /* Local storage variables */
2131  cpl_frame * this_target_frame;
2132  cpl_propertylist * this_properties;
2133 
2134  /* Computing statistics for this frame */
2135  cpl_msg_info(cpl_func, "Getting statistics for image %d", iframe + 1);
2136  this_target_frame = cpl_frameset_get_frame(obj, iframe);
2138  (raw_jitter_stats, this_target_frame, iframe);
2139 
2140  /* Compute the telescope pcs statistics */
2141  this_properties = cpl_propertylist_load
2142  (cpl_frame_get_filename(this_target_frame), 0);
2143  if(this_properties == NULL)
2144  {
2145  cpl_msg_error(cpl_func,"Could not read the header of object frame");
2146  return -1;
2147  }
2148  if(hawki_extract_prop_tel_qc(this_properties, raw_obj_tel_info, iframe))
2149  {
2150  cpl_msg_warning(cpl_func,"Some telescope properties could not be "
2151  "read for image %d", iframe+1);
2152  cpl_errorstate_set(CPL_ERROR_NONE);
2153  }
2154  cpl_propertylist_delete(this_properties);
2155  }
2156 
2157  /* Saving the already computed products */
2158  cpl_msg_info(cpl_func, "Saving image statistics");
2159  if(hawki_sci_jitter_save_stats(raw_jitter_stats, raw_obj_tel_info,
2160  obj,
2161  parlist, recipe_set) != 0)
2162  cpl_msg_warning(cpl_func,"Some data could not be saved. "
2163  "Check permisions or disk space");
2164 
2165 
2166  /* Free and return */
2167  return 0;
2168 }
2169 
2170 int hawki_sci_jitter_save_stats
2171 (cpl_table ** raw_jitter_stats,
2172  cpl_table * raw_obj_tel_info,
2173  cpl_frameset * jitter_frames,
2174  cpl_parameterlist * parlist,
2175  cpl_frameset * recipe_set)
2176 {
2177  int idet;
2178  const cpl_frame * ref_frame;
2179  cpl_propertylist ** qcstats;
2180  cpl_propertylist * telstats;
2181  const char * recipe_name = "hawki_sci_jitter" ;
2182  cpl_errorstate error_prevstate = cpl_errorstate_get();
2183 
2184  /* Statistics of the raw images in the QC */
2185  qcstats = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_propertylist*));
2186  /* Create the QC lists */
2187  ref_frame = irplib_frameset_get_first_from_group
2188  (recipe_set, CPL_FRAME_GROUP_RAW);
2189  for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
2190  {
2191  int ext_nb;
2192  cpl_propertylist * reflist;
2193 
2194  qcstats[idet] = cpl_propertylist_new();
2195  /* Propagate some keywords from input raw frame extensions */
2196  ext_nb =
2197  hawki_get_ext_from_detector(cpl_frame_get_filename(ref_frame), idet+1);
2198  reflist = cpl_propertylist_load_regexp
2199  (cpl_frame_get_filename(ref_frame), ext_nb,
2200  HAWKI_HEADER_EXT_FORWARD, 0) ;
2201  cpl_propertylist_append(qcstats[idet], reflist);
2202  cpl_propertylist_delete(reflist);
2203  }
2204  hawki_image_stats_stats(raw_jitter_stats, qcstats);
2205  /* Write the table with the raw jitter objects statistics */
2206  hawki_tables_save(recipe_set,
2207  parlist,
2208  jitter_frames,
2209  (const cpl_table **)raw_jitter_stats,
2210  recipe_name,
2211  HAWKI_CALPRO_JITTER_STATS,
2212  HAWKI_PROTYPE_JITTER_STATS,
2213  NULL,
2214  (const cpl_propertylist**)qcstats,
2215  "hawki_sci_jitter_stats.fits");
2216  /* Free qcstats */
2217  for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
2218  cpl_propertylist_delete(qcstats[idet]);
2219 
2220  /* Write the FITS table with the raw telescope data */
2221  telstats = cpl_propertylist_new();
2222  cpl_propertylist_append_string(telstats, CPL_DFS_PRO_TYPE,
2223  HAWKI_PROTYPE_SCIENCE_PCS);
2224  cpl_propertylist_append_string(telstats, CPL_DFS_PRO_CATG,
2225  HAWKI_CALPRO_SCIENCE_PCS);
2226  hawki_compute_prop_tel_qc_stats(raw_obj_tel_info, telstats);
2227  if(cpl_dfs_save_table(recipe_set,
2228  NULL,
2229  parlist,
2230  jitter_frames,
2231  NULL,
2232  raw_obj_tel_info,
2233  NULL,
2234  recipe_name,
2235  telstats,
2236  NULL,
2237  PACKAGE "/" PACKAGE_VERSION,
2238  "hawki_sci_jitter_pcs.fits") != CPL_ERROR_NONE)
2239  cpl_msg_error(cpl_func,"Cannot save PCS table");
2240 
2241  /* Free and return */
2242  cpl_propertylist_delete(telstats);
2243  cpl_free(qcstats);
2244  if(!cpl_errorstate_is_equal(error_prevstate))
2245  {
2246  cpl_errorstate_set(CPL_ERROR_NONE);
2247  return -1;
2248  }
2249 
2250  return 0;
2251 }