HAWKI Pipeline Reference Manual 1.8.6
hawki_sci_jitter.c
00001 /* $Id: hawki_sci_jitter.c,v 1.30 2011/12/22 15:27:06 cgarcia Exp $
00002  *
00003  * This file is part of the HAWKI Pipeline
00004  * Copyright (C) 2002,2003 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: cgarcia $
00023  * $Date: 2011/12/22 15:27:06 $
00024  * $Revision: 1.30 $
00025  * $Name: hawki-1_8_6 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*-----------------------------------------------------------------------------
00033                                 Includes
00034  -----------------------------------------------------------------------------*/
00035 
00036 #include <math.h>
00037 #include <cpl.h>
00038 #include <string.h>
00039 
00040 #include "irplib_utils.h"
00041 #include "irplib_calib.h"
00042 
00043 #include "hawki_utils.h"
00044 #include "hawki_calib.h"
00045 #include "hawki_load.h"
00046 #include "hawki_save.h"
00047 #include "hawki_pfits.h"
00048 #include "hawki_dfs.h"
00049 #include "hawki_saa.h"
00050 #include "hawki_bkg.h"
00051 #include "hawki_distortion.h"
00052 #include "hawki_properties_tel.h"
00053 #include "hawki_image_stats.h"
00054 #include "hawki_obj_det.h"
00055 
00056 /*-----------------------------------------------------------------------------
00057                                 Define
00058  -----------------------------------------------------------------------------*/
00059 
00060 #define NEGLIG_OFF_DIFF     0.1
00061 #define SQR(x) ((x)*(x))
00062 
00063 /*-----------------------------------------------------------------------------
00064                             Functions prototypes
00065  -----------------------------------------------------------------------------*/
00066 
00067 static int hawki_sci_jitter_create(cpl_plugin *) ;
00068 static int hawki_sci_jitter_exec(cpl_plugin *) ;
00069 static int hawki_sci_jitter_destroy(cpl_plugin *) ;
00070 static int hawki_sci_jitter(cpl_parameterlist *, cpl_frameset *) ;
00071 
00072 static int hawki_sci_jitter_retrieve_input_param
00073 (cpl_parameterlist  *  parlist);
00074 static cpl_image ** hawki_sci_jitter_reduce
00075 (cpl_frameset      *   jitters,
00076  cpl_frameset      *   sky,
00077  const char        *   flat,
00078  const char        *   dark,
00079  const char        *   bpm,
00080  cpl_table         **  bkg_stats);
00081 static int hawki_sci_jitter_sky
00082 (cpl_imagelist   *   jitters,
00083  cpl_imagelist   *   skys,
00084  cpl_table       **  bkg_stats,
00085  int                 idet);
00086 static int hawki_sci_jitter_sky_running
00087 (cpl_imagelist *  in,
00088  cpl_table     ** bkg_stats,
00089  int              idet); 
00090 static cpl_image ** hawki_sci_jitter_saa(cpl_imagelist **, cpl_bivector *, 
00091         double *, double *);
00092 static int hawki_sci_jitter_qc
00093 (cpl_frameset *   science_frames,
00094  cpl_image   **   combined, 
00095  cpl_table   **   obj_charac);
00096 static int hawki_sci_jitter_read_calib
00097 (const char *  flat,
00098  const char *  dark,
00099  const char *  bpm,
00100  cpl_image  ** flat_image,
00101  cpl_image  ** dark_image,
00102  cpl_image  ** bpm_image,
00103  int           idet);
00104 static int hawki_sci_jitter_save
00105 (cpl_image           **  combined,
00106  cpl_image           *   stitched,
00107  cpl_table           **  objs_charac,
00108  cpl_table           **  raw_jitter_stats,
00109  cpl_table           **  bkg_stats,
00110  const cpl_table     *   raw_obj_tel_info,
00111  cpl_frameset        *   science_frames,
00112  cpl_frameset        *   calib_frames,
00113  cpl_parameterlist   *   parlist,
00114  cpl_frameset        *   set);
00115 int hawki_sci_jitter_whole_image_algo
00116 (cpl_frameset       *  obj,
00117  cpl_table          ** raw_jitter_stats,
00118  cpl_table          *  raw_obj_tel_info,
00119  cpl_parameterlist  *  parlist,
00120  cpl_frameset       *  recipe_set);
00121 int hawki_sci_jitter_save_stats
00122 (cpl_table          ** raw_jitter_stats,
00123  cpl_table          *  raw_obj_tel_info,
00124  cpl_frameset       *  jitter_frames,
00125  cpl_parameterlist  *  parlist,
00126  cpl_frameset       *  recipe_set);
00127 
00128 /*-----------------------------------------------------------------------------
00129                             Static variables
00130  -----------------------------------------------------------------------------*/
00131 
00132 static struct 
00133 {
00134     /* Inputs */
00135     const char      *   offsets ;
00136     const char      *   objects ;
00137     int                 offset_max ;
00138     int                 sky_minnb ;
00139     int                 sky_halfw ;
00140     int                 sky_rejmin ;
00141     int                 sky_rejmax ;
00142     int                 refine ;
00143     int                 sx ;
00144     int                 sy ;
00145     int                 mx ;
00146     int                 my ;
00147     int                 borders ;
00148     cpl_geom_combine    comb_meth ;
00149     int                 rej_low ;
00150     int                 rej_high ;
00151     int                 max_njitter;
00152 } hawki_sci_jitter_config;
00153 
00154 static struct 
00155 {
00156     /* Outputs */
00157     double          pixscale;
00158     double          dit;
00159     double          mean_airmass;
00160     double          iq[HAWKI_NB_DETECTORS];
00161     int             nbobjs[HAWKI_NB_DETECTORS];
00162     double          fwhm_pix[HAWKI_NB_DETECTORS];
00163     double          fwhm_arcsec[HAWKI_NB_DETECTORS];
00164     double          fwhm_mode[HAWKI_NB_DETECTORS];
00165     double          combined_pos_x[HAWKI_NB_DETECTORS];
00166     double          combined_pos_y[HAWKI_NB_DETECTORS];
00167     double          combined_cumoffset_x[HAWKI_NB_DETECTORS];
00168     double          combined_cumoffset_y[HAWKI_NB_DETECTORS];
00169     int             ncomb[HAWKI_NB_DETECTORS];
00170 } hawki_sci_jitter_output;
00171 
00172 static char hawki_sci_jitter_description[] =
00173 "hawki_sci_jitter -- hawki imaging jitter recipe.\n\n"
00174 "The input of the recipe files listed in the Set Of Frames (sof-file)\n"
00175 "must be tagged as:\n"
00176 "raw-file.fits "HAWKI_IMG_JITTER_RAW" or\n"
00177 "raw-file.fits "HAWKI_IMG_JITTER_SKY_RAW" or\n"
00178 "flat-file.fits "HAWKI_CALPRO_FLAT" or\n"
00179 "dark-file.fits "HAWKI_CALPRO_DARK" \n"
00180 "bpm-file.fits "HAWKI_CALPRO_BPM"\n"
00181 "distortion_x-file.fits "HAWKI_CALPRO_DISTORTION_X"\n"
00182 "distortion_y-file.fits "HAWKI_CALPRO_DISTORTION_Y"\n\n"
00183 "The recipe creates as an output:\n"
00184 "hawki_sci_jitter.fits ("HAWKI_CALPRO_COMBINED")\n"
00185 "hawki_sci_jitter_stitched.fits ("HAWKI_CALPRO_STITCHED")\n"
00186 "hawki_sci_jitter_stars.fits ("HAWKI_CALPRO_OBJ_PARAM"): Detected objects properties\n"
00187 "hawki_sci_jitter_stats.fits ("HAWKI_CALPRO_JITTER_STATS"): Stats of the individual images\n"
00188 "hawki_sci_jitter_bkg_stats.fits ("HAWKI_CALPRO_JITTER_BKG_STATS"): Statistics on the bkg\n\n"
00189 "The recipe performs the following steps:\n"
00190 "1) Frame statistics\n"
00191 "2) Basic reduction (using "HAWKI_CALPRO_FLAT" and "HAWKI_CALPRO_BPM")\n"
00192 "3) Background computation (the algorithm depends on parameter --sky_par) \n"
00193 "4) Offset refinement (uses parameters --off, --refine and --xcorr)\n"
00194 "5) Stacking of jitter frames (uses --comb_meth, --rej,\n"
00195 "   --offset_max, --borders, --max_njitter)\n"
00196 "6) Stitching of the four detectors into one image\n"
00197 "7) Object detection in the stacked image\n\n"
00198 "Return code:\n"
00199 "esorex exits with an error code of 0 if the recipe completes successfully\n"
00200 "or 1 otherwise";
00201 
00202 /*-----------------------------------------------------------------------------
00203                                 Functions code
00204  -----------------------------------------------------------------------------*/
00205 
00206 /*----------------------------------------------------------------------------*/
00214 /*----------------------------------------------------------------------------*/
00215 int cpl_plugin_get_info(cpl_pluginlist * list)
00216 {
00217     cpl_recipe  *   recipe = cpl_calloc(1, sizeof(*recipe)) ;
00218     cpl_plugin  *   plugin = &recipe->interface ;
00219 
00220     cpl_plugin_init(plugin,
00221                     CPL_PLUGIN_API,
00222                     HAWKI_BINARY_VERSION,
00223                     CPL_PLUGIN_TYPE_RECIPE,
00224                     "hawki_sci_jitter",
00225                     "Jitter recipe",
00226                     hawki_sci_jitter_description,
00227                     "Cesar Enrique Garcia",
00228                     PACKAGE_BUGREPORT,
00229                     hawki_get_license(),
00230                     hawki_sci_jitter_create,
00231                     hawki_sci_jitter_exec,
00232                     hawki_sci_jitter_destroy) ;
00233 
00234     cpl_pluginlist_append(list, plugin) ;
00235     
00236     return 0;
00237 }
00238 
00239 /*----------------------------------------------------------------------------*/
00248 /*----------------------------------------------------------------------------*/
00249 static int hawki_sci_jitter_create(cpl_plugin * plugin)
00250 {
00251     cpl_recipe      * recipe ;
00252     cpl_parameter   * p ;
00253 
00254     /* Get the recipe out of the plugin */
00255     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00256         recipe = (cpl_recipe *)plugin ;
00257     else return -1 ;
00258 
00259     /* Create the parameters list in the cpl_recipe object */
00260     recipe->parameters = cpl_parameterlist_new() ;
00261     if (recipe->parameters == NULL)
00262         return 1;
00263 
00264     /* Fill the parameters list */
00265     /* --offsets */
00266     p = cpl_parameter_new_value("hawki.hawki_sci_jitter.offsets", 
00267             CPL_TYPE_STRING, "offsets file", "hawki.hawki_sci_jitter", NULL) ;
00268     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "offsets") ;
00269     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
00270     cpl_parameterlist_append(recipe->parameters, p) ;
00271 
00272     /* --objects */
00273     p = cpl_parameter_new_value("hawki.hawki_sci_jitter.objects", 
00274             CPL_TYPE_STRING, "objects file", "hawki.hawki_sci_jitter", NULL) ;
00275     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "objects") ;
00276     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
00277     cpl_parameterlist_append(recipe->parameters, p) ;
00278 
00279     /* --offset_max */
00280     p = cpl_parameter_new_value("hawki.hawki_sci_jitter.offset_max",
00281                                 CPL_TYPE_INT,
00282                                 "Maximum offset allowed",
00283                                 "hawki.hawki_sci_jitter",
00284                                 1500) ;
00285     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "offset_max") ;
00286     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
00287     cpl_parameterlist_append(recipe->parameters, p) ;
00288 
00289     /* --sky_par */
00290     p = cpl_parameter_new_value("hawki.hawki_sci_jitter.sky_par",
00291                                 CPL_TYPE_STRING,
00292                                 "Rejection parameters for sky filtering",
00293                                 "hawki.hawki_sci_jitter",
00294                                 "10,7,3,3") ;
00295     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sky_par") ;
00296     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
00297     cpl_parameterlist_append(recipe->parameters, p) ;
00298 
00299     /* --refine */
00300     p = cpl_parameter_new_value("hawki.hawki_sci_jitter.refine",
00301             CPL_TYPE_BOOL, "refine offsets", "hawki.hawki_sci_jitter",
00302             FALSE);
00303     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "refine") ;
00304     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
00305     cpl_parameterlist_append(recipe->parameters, p) ;
00306 
00307     /* --xcorr */
00308     p = cpl_parameter_new_value("hawki.hawki_sci_jitter.xcorr",
00309                                 CPL_TYPE_STRING,
00310                                 "Cross correlation search and measure sizes",
00311                                 "hawki.hawki_sci_jitter",
00312                                 "20,20,25,25") ;
00313     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "xcorr") ;
00314     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
00315     cpl_parameterlist_append(recipe->parameters, p) ;
00316 
00317     /* --comb_meth */
00318     p = cpl_parameter_new_value("hawki.hawki_sci_jitter.comb_meth", 
00319             CPL_TYPE_STRING, "union / inter / first", "hawki.hawki_sci_jitter",
00320             "union") ;
00321     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "comb_meth") ;
00322     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
00323     cpl_parameterlist_append(recipe->parameters, p) ;
00324   
00325     /* --rej */
00326     p = cpl_parameter_new_value("hawki.hawki_sci_jitter.rej",
00327                                 CPL_TYPE_STRING,
00328                                 "Low and high number of rejected values",
00329                                 "hawki.hawki_sci_jitter",
00330                                 "1,1") ;
00331     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rej") ;
00332     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
00333     cpl_parameterlist_append(recipe->parameters, p) ;
00334 
00335     /* --borders */
00336     p = cpl_parameter_new_value("hawki.hawki_sci_jitter.borders",
00337                                 CPL_TYPE_INT,
00338                                 "Borders rejected",
00339                                 "hawki.hawki_sci_jitter",
00340                                 4) ;
00341     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "borders") ;
00342     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
00343     cpl_parameterlist_append(recipe->parameters, p) ;
00344 
00345     /* --max_njitter */
00346     p = cpl_parameter_new_value("hawki.hawki_sci_jitter.max_njitter",
00347                                 CPL_TYPE_INT,
00348                                 "Maximum numbers of jitter frames to combine",
00349                                 "hawki.hawki_sci_jitter",
00350                                 -1);
00351     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "max_njitter");
00352     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00353     cpl_parameterlist_append(recipe->parameters, p);
00354 
00355     /* Return */
00356     return 0;
00357 }
00358 
00359 /*----------------------------------------------------------------------------*/
00365 /*----------------------------------------------------------------------------*/
00366 static int hawki_sci_jitter_exec(cpl_plugin * plugin)
00367 {
00368     cpl_recipe  *   recipe ;
00369 
00370     /* Get the recipe out of the plugin */
00371     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00372         recipe = (cpl_recipe *)plugin ;
00373     else return -1 ;
00374 
00375     /* Issue a banner */
00376     hawki_print_banner();
00377 
00378     return hawki_sci_jitter(recipe->parameters, recipe->frames) ;
00379 }
00380 
00381 /*----------------------------------------------------------------------------*/
00387 /*----------------------------------------------------------------------------*/
00388 static int hawki_sci_jitter_destroy(cpl_plugin * plugin)
00389 {
00390     cpl_recipe  *   recipe ;
00391 
00392     /* Get the recipe out of the plugin */
00393     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00394         recipe = (cpl_recipe *)plugin ;
00395     else return -1 ;
00396 
00397     cpl_parameterlist_delete(recipe->parameters) ;
00398     return 0 ;
00399 }
00400 
00401 /*----------------------------------------------------------------------------*/
00408 /*----------------------------------------------------------------------------*/
00409 static int hawki_sci_jitter(
00410         cpl_parameterlist   *   parlist, 
00411         cpl_frameset        *   framelist)
00412 {
00413     const char      *   flat;
00414     const char      *   dark;
00415     const char      *   bpm;
00416     const cpl_frame *   distx;
00417     const cpl_frame *   disty;
00418     cpl_frameset    *   jitterframes ;
00419     cpl_frameset    *   skyframes ;
00420     cpl_frameset    *   science_frames;
00421     cpl_frameset    *   calib_frames;
00422     cpl_image       **  combined ;
00423     cpl_table       **  obj_charac;
00424     cpl_table       **  raw_jitter_stats; 
00425     cpl_table       **  bkg_stats; 
00426     cpl_table       *   raw_obj_tel_info;
00427     cpl_image       *   stitched ;
00428     int                 i;
00429 
00430     /* Initialise */
00431     for (i=0 ; i<HAWKI_NB_DETECTORS ; i++) 
00432     {
00433         hawki_sci_jitter_output.iq[i] = -1.0 ;
00434         hawki_sci_jitter_output.nbobjs[i] = -1 ;
00435         hawki_sci_jitter_output.fwhm_pix[i] = -1.0 ;
00436         hawki_sci_jitter_output.fwhm_arcsec[i] = -1.0 ;
00437         hawki_sci_jitter_output.fwhm_mode[i] = -1.0 ;
00438         hawki_sci_jitter_output.combined_pos_x[i] = -1.0 ;
00439         hawki_sci_jitter_output.combined_pos_y[i] = -1.0 ;
00440         hawki_sci_jitter_output.combined_cumoffset_x[i] = -1.0 ;
00441         hawki_sci_jitter_output.combined_cumoffset_y[i] = -1.0 ;
00442     }
00443     hawki_sci_jitter_output.pixscale = -1.0 ;
00444     hawki_sci_jitter_output.dit = -1.0 ;
00445     hawki_sci_jitter_config.offsets = NULL ;
00446     hawki_sci_jitter_config.objects = NULL ;
00447     calib_frames = cpl_frameset_new();
00448 
00449     /* Retrieve input parameters */
00450     if(hawki_sci_jitter_retrieve_input_param(parlist))
00451     {
00452         cpl_msg_error(cpl_func, "Wrong parameters");
00453         cpl_frameset_delete(calib_frames);
00454         return -1;
00455     }
00456 
00457     /* Identify the RAW and CALIB frames in the input frameset */
00458     if (hawki_dfs_set_groups(framelist)) {
00459         cpl_msg_error(cpl_func, "Cannot identify RAW and CALIB frames") ;
00460         cpl_frameset_delete(calib_frames);
00461         return -1 ;
00462     }
00463 
00464     /* Retrieve calibration data */
00465     flat   = hawki_extract_first_filename(framelist, HAWKI_CALPRO_FLAT) ;
00466     dark   = hawki_extract_first_filename(framelist, HAWKI_CALPRO_DARK);
00467     bpm    = hawki_extract_first_filename(framelist, HAWKI_CALPRO_BPM) ;
00468     distx  = cpl_frameset_find_const(framelist, HAWKI_CALPRO_DISTORTION_X);
00469     disty  = cpl_frameset_find_const(framelist, HAWKI_CALPRO_DISTORTION_Y);
00470     if((distx == NULL && disty !=NULL) || (distx != NULL && disty ==NULL))
00471     {
00472         cpl_msg_error(cpl_func, "Both distortion in X (%s) and Y (%s) must be provided",
00473                       HAWKI_CALPRO_DISTORTION_X, HAWKI_CALPRO_DISTORTION_Y);
00474         cpl_frameset_delete(calib_frames);
00475         return -1 ;
00476     }
00477     if(flat)
00478         cpl_frameset_insert(calib_frames, cpl_frame_duplicate(
00479                 cpl_frameset_find_const(framelist, HAWKI_CALPRO_FLAT)));
00480     if(dark)
00481         cpl_frameset_insert(calib_frames, cpl_frame_duplicate(
00482                 cpl_frameset_find_const(framelist, HAWKI_CALPRO_DARK)));
00483     if(bpm)
00484         cpl_frameset_insert(calib_frames, cpl_frame_duplicate(
00485                 cpl_frameset_find_const(framelist, HAWKI_CALPRO_BPM)));
00486     if(distx)
00487     {
00488         cpl_frameset_insert(calib_frames, cpl_frame_duplicate(distx));
00489         cpl_frameset_insert(calib_frames, cpl_frame_duplicate(disty));
00490     }
00491         
00492 
00493     /* Retrieve raw frames */
00494     jitterframes = hawki_extract_frameset(framelist, HAWKI_IMG_JITTER_RAW) ;
00495     if (jitterframes == NULL) {
00496         cpl_msg_error(cpl_func, "Cannot find jitter frames in the input list (%s)",
00497                       HAWKI_IMG_JITTER_RAW);
00498         cpl_frameset_delete(calib_frames);
00499         return -1 ;
00500     }
00501     science_frames = cpl_frameset_duplicate(jitterframes);
00502     skyframes = hawki_extract_frameset(framelist, HAWKI_IMG_JITTER_SKY_RAW) ;
00503     if (skyframes != NULL) 
00504     {
00505         int isky;
00506         for(isky = 0; isky< cpl_frameset_get_size(skyframes); ++isky)
00507             cpl_frameset_insert(science_frames, 
00508                     cpl_frame_duplicate(cpl_frameset_get_frame(skyframes, isky)));
00509     }
00510     
00511     /* Create the statistics table */
00512     raw_jitter_stats = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_table *));
00513     for( i=0 ; i<HAWKI_NB_DETECTORS ; i++)
00514     {
00515         raw_jitter_stats[i] = cpl_table_new(cpl_frameset_get_size(jitterframes));
00516     }
00517     hawki_image_stats_initialize(raw_jitter_stats);
00518     bkg_stats = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_table *));
00519     for( i=0 ; i<HAWKI_NB_DETECTORS ; i++)
00520     {
00521         bkg_stats[i] = cpl_table_new(cpl_frameset_get_size(jitterframes));
00522     }
00523     hawki_image_stats_initialize(bkg_stats);
00524 
00525     /* Create the  telescope statistics parameters from the raw images */
00526     raw_obj_tel_info = cpl_table_new(cpl_frameset_get_size(jitterframes));
00527     /* Add the proper columns of the pcs table */
00528     if(hawki_prop_tel_initialize(raw_obj_tel_info))
00529     {
00530         cpl_msg_error(cpl_func,"Could not initialize the pcs table");
00531         cpl_frameset_delete(jitterframes) ;
00532         for( i=0 ; i<HAWKI_NB_DETECTORS ; i++)
00533         {
00534             cpl_table_delete(raw_jitter_stats[i]) ;
00535             cpl_table_delete(bkg_stats[i]) ;
00536         }
00537         cpl_free(raw_jitter_stats) ;
00538         cpl_free(bkg_stats) ;
00539         cpl_table_delete(raw_obj_tel_info);
00540         if (skyframes) cpl_frameset_delete(skyframes) ;
00541         cpl_frameset_delete(calib_frames);
00542         cpl_msg_indent_less() ;
00543         return -1;
00544     }
00545     
00546     /* Do the algorithms that need the whole image */
00547     hawki_sci_jitter_whole_image_algo(jitterframes,
00548                                       raw_jitter_stats,
00549                                       raw_obj_tel_info,
00550                                       parlist,
00551                                       framelist);
00552 
00553     /* Apply the reduction */
00554     /* Do the algorithms that can be applied to subsection of the images */
00555     cpl_msg_info(cpl_func, "Apply the data combination") ;
00556     cpl_msg_indent_more() ;
00557     if ((combined = hawki_sci_jitter_reduce(jitterframes, skyframes, flat, dark,
00558                     bpm, bkg_stats)) == NULL) 
00559     {
00560         cpl_msg_error(cpl_func, "Cannot recombine the data");
00561         cpl_frameset_delete(jitterframes);
00562         for( i=0 ; i<HAWKI_NB_DETECTORS ; i++)
00563         {
00564             cpl_table_delete(raw_jitter_stats[i]) ;
00565             cpl_table_delete(bkg_stats[i]) ;
00566         }
00567         cpl_free(raw_jitter_stats) ;
00568         cpl_free(bkg_stats) ;
00569         cpl_table_delete(raw_obj_tel_info);
00570         if (skyframes) cpl_frameset_delete(skyframes) ;
00571         cpl_frameset_delete(calib_frames);
00572         cpl_msg_indent_less() ;
00573         return -1 ;
00574     }
00575     cpl_msg_indent_less() ;
00576 
00577     /* Compute QC parameters from the combined image */
00578     cpl_msg_info(cpl_func, "Compute QC parameters from the combined images") ;
00579     cpl_msg_indent_more() ;
00580     obj_charac = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_table*)) ;
00581     for (i=0 ; i<HAWKI_NB_DETECTORS ; i++)
00582     {
00583         obj_charac[i] = cpl_table_new(0);
00584     }
00585     if ((hawki_sci_jitter_qc(jitterframes, combined, obj_charac)) != 0)
00586     {
00587         cpl_msg_warning(cpl_func, "Cannot compute all parameters") ;
00588     }
00589     cpl_msg_indent_less();
00590     cpl_frameset_delete(jitterframes);
00591     if (skyframes) cpl_frameset_delete(skyframes);
00592 
00593  
00594     /* Correct for the distortion */
00595     if (distx && disty)
00596     {
00597         cpl_msg_info(cpl_func, "Applying the distortion correction") ;
00598         cpl_msg_indent_more() ;
00599         if (hawki_distortion_correct_alldetectors(combined, distx, disty) == -1) 
00600         {
00601             cpl_msg_error(cpl_func, "Cannot correct the distortion") ;
00602             for (i=0 ; i<HAWKI_NB_DETECTORS ; i++)
00603                 cpl_image_delete(combined[i]) ;
00604             cpl_free(combined) ;
00605             if (obj_charac) {
00606                 for (i=0 ; i<HAWKI_NB_DETECTORS ; i++) 
00607                     cpl_table_delete(obj_charac[i]) ;
00608                 cpl_free(obj_charac);
00609             }
00610             cpl_table_delete(raw_obj_tel_info);
00611             for( i=0 ; i<HAWKI_NB_DETECTORS ; i++)
00612             {
00613                 cpl_table_delete(raw_jitter_stats[i]);
00614                 cpl_table_delete(bkg_stats[i]);
00615             }
00616             cpl_free(raw_jitter_stats);
00617             cpl_free(bkg_stats);
00618             cpl_frameset_delete(calib_frames);
00619             cpl_frameset_delete(science_frames);
00620             cpl_msg_indent_less() ;
00621             return -1;
00622         }
00623         cpl_msg_indent_less() ;
00624     }
00625 
00626     /* Compute the stitched image */
00627     cpl_msg_info(cpl_func, "Compute the stiched image") ;
00628     if ((stitched = hawki_images_stitch(combined, 
00629                     hawki_sci_jitter_output.combined_pos_x,
00630                     hawki_sci_jitter_output.combined_pos_y)) == NULL)
00631     {
00632         cpl_msg_error(cpl_func, "Cannot stitch the images") ;
00633         for (i=0 ; i<HAWKI_NB_DETECTORS ; i++)
00634             cpl_image_delete(combined[i]) ;
00635         cpl_free(combined) ;
00636         if (obj_charac) {
00637             for (i=0 ; i<HAWKI_NB_DETECTORS ; i++) 
00638                 cpl_table_delete(obj_charac[i]) ;
00639             cpl_free(obj_charac);
00640         }
00641         cpl_table_delete(raw_obj_tel_info);
00642         for( i=0 ; i<HAWKI_NB_DETECTORS ; i++)
00643         {
00644             cpl_table_delete(raw_jitter_stats[i]);
00645             cpl_table_delete(bkg_stats[i]);
00646         }
00647         cpl_free(raw_jitter_stats);
00648         cpl_free(bkg_stats);
00649         cpl_frameset_delete(calib_frames);
00650         cpl_frameset_delete(science_frames);
00651         return -1;
00652     }
00653 
00654     /* Save the products */
00655     cpl_msg_info(cpl_func, "Save the products") ;
00656     cpl_msg_indent_more() ;
00657     if (hawki_sci_jitter_save(combined, stitched, obj_charac,
00658                               raw_jitter_stats, bkg_stats, 
00659                               raw_obj_tel_info,
00660                               science_frames,
00661                               calib_frames,
00662                               parlist, framelist) == -1)
00663         cpl_msg_warning(cpl_func,"Some data could not be saved. "
00664                                  "Check permisions or disk space");
00665     
00666     /* Return */
00667     for (i=0 ; i<HAWKI_NB_DETECTORS ; i++)
00668         cpl_image_delete(combined[i]) ;
00669     cpl_free(combined) ;
00670     if (obj_charac) {
00671         for (i=0 ; i<HAWKI_NB_DETECTORS ; i++) 
00672             cpl_table_delete(obj_charac[i]) ;
00673         cpl_free(obj_charac);
00674     }
00675     if (stitched) cpl_image_delete(stitched) ;
00676     cpl_table_delete(raw_obj_tel_info);
00677     for( i=0 ; i<HAWKI_NB_DETECTORS ; i++)
00678     {
00679         cpl_table_delete(raw_jitter_stats[i]);
00680         cpl_table_delete(bkg_stats[i]);
00681     }
00682     cpl_free(raw_jitter_stats);
00683     cpl_free(bkg_stats);
00684     cpl_frameset_delete(calib_frames);
00685     cpl_frameset_delete(science_frames);
00686     cpl_msg_indent_less() ;
00687 
00688     /* Return */
00689     if (cpl_error_get_code())
00690     {
00691         cpl_msg_error(cpl_func,
00692                       "HAWK-I pipeline could not recover from previous errors");
00693         return -1 ;
00694     }
00695     else return 0 ;
00696 }
00697 
00698 int hawki_sci_jitter_retrieve_input_param
00699 (cpl_parameterlist  *  parlist)
00700 {
00701     cpl_parameter   *   par ;
00702     const char      *   sval ;
00703     par = NULL ;
00704     par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.offsets");
00705     hawki_sci_jitter_config.offsets = cpl_parameter_get_string(par);
00706     par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.objects");
00707     hawki_sci_jitter_config.objects = cpl_parameter_get_string(par);
00708     par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.offset_max");
00709     hawki_sci_jitter_config.offset_max = cpl_parameter_get_int(par);
00710     par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.sky_par");
00711     sval = cpl_parameter_get_string(par);
00712     if (sscanf(sval, "%d,%d,%d,%d",
00713                &hawki_sci_jitter_config.sky_minnb,
00714                &hawki_sci_jitter_config.sky_halfw,
00715                &hawki_sci_jitter_config.sky_rejmin,
00716                &hawki_sci_jitter_config.sky_rejmax)!=4)
00717     {
00718         return -1;
00719     }
00720     par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.xcorr");
00721     sval = cpl_parameter_get_string(par);
00722     if (sscanf(sval, "%d,%d,%d,%d",
00723                &hawki_sci_jitter_config.sx,
00724                &hawki_sci_jitter_config.sy,
00725                &hawki_sci_jitter_config.mx,
00726                &hawki_sci_jitter_config.my)!=4)
00727     {
00728         return -1;
00729     }
00730     par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.refine");
00731     hawki_sci_jitter_config.refine = cpl_parameter_get_bool(par);
00732     par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.comb_meth");
00733     sval = cpl_parameter_get_string(par);
00734     if (!strcmp(sval, "union"))
00735     hawki_sci_jitter_config.comb_meth = CPL_GEOM_UNION;
00736     else if (!strcmp(sval, "inter"))
00737     hawki_sci_jitter_config.comb_meth = CPL_GEOM_INTERSECT;
00738     else if (!strcmp(sval, "first"))
00739     hawki_sci_jitter_config.comb_meth = CPL_GEOM_FIRST;
00740     else
00741     {
00742         cpl_msg_error(cpl_func, "Invalid combine method specified");
00743         return -1;
00744     }
00745     par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.borders");
00746     hawki_sci_jitter_config.borders = cpl_parameter_get_int(par);
00747     par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.rej");
00748     sval = cpl_parameter_get_string(par);
00749     if (sscanf(sval, "%d,%d",
00750                &hawki_sci_jitter_config.rej_low,
00751                &hawki_sci_jitter_config.rej_high)!=2)
00752     {
00753         return -1;
00754     }
00755     par = cpl_parameterlist_find(parlist, "hawki.hawki_sci_jitter.max_njitter");
00756     hawki_sci_jitter_config.max_njitter = cpl_parameter_get_int(par);
00757     return 0;
00758 }
00759 
00760 
00761 
00762 /*----------------------------------------------------------------------------*/
00773 /*----------------------------------------------------------------------------*/
00774 static cpl_image ** hawki_sci_jitter_reduce
00775 (cpl_frameset      *   jitters,
00776  cpl_frameset      *   sky,
00777  const char        *   flat,
00778  const char        *   dark,
00779  const char        *   bpm,
00780  cpl_table         **  bkg_stats)
00781 {
00782     cpl_frame           *   frame ;
00783     cpl_propertylist    *   plist ;
00784     cpl_image           **  comb_chip ;
00785     cpl_image           **  combined ;
00786     cpl_bivector        *   offsets ;
00787     cpl_vector          *   offset_x_sort; 
00788     cpl_vector          *   offset_y_sort; 
00789     double              *   offs_est_x ;
00790     double              *   offs_est_y ;
00791     double                  off_0_x;
00792     double                  off_0_y;
00793     double                  max_x, max_y ;
00794     int                     idet;
00795     int                     ioff;
00796     
00797     /* Get the header infos */
00798     frame = cpl_frameset_get_frame(jitters, 0) ;
00799     plist=cpl_propertylist_load(cpl_frame_get_filename(frame), 0) ;
00800     hawki_sci_jitter_output.pixscale = hawki_pfits_get_pixscale(plist) ;
00801     hawki_sci_jitter_output.dit = hawki_pfits_get_dit(plist) ;
00802     cpl_propertylist_delete(plist) ;
00803     if (cpl_error_get_code()) {
00804         cpl_msg_error(cpl_func, "Missing keyword in FITS header") ;
00805         return NULL ;
00806     }
00807 
00808     /* Check that DIT/NDIT and NDSAMPLES are the same for all the frames */
00809     if(!hawki_utils_check_equal_double_keys(jitters, &hawki_pfits_get_dit) ||
00810        !hawki_utils_check_equal_int_keys(jitters, &hawki_pfits_get_ndit)||
00811        !hawki_utils_check_equal_int_keys(jitters, &hawki_pfits_get_ndsamples))
00812     {
00813         cpl_msg_error(__func__, "Not all input science have the same "
00814                 "DIT/NDIT/NDSAMPLES values");
00815         cpl_msg_indent_less() ;
00816         return NULL;        
00817     }
00818     
00819     /* Get the offsets */
00820     if ((offsets = hawki_get_header_tel_offsets(jitters)) == NULL) {
00821         cpl_msg_error(cpl_func, "Cannot load the offsets") ;
00822         return NULL ;
00823     }
00824     offs_est_x = cpl_bivector_get_x_data(offsets) ;
00825     offs_est_y = cpl_bivector_get_y_data(offsets) ;
00826 
00827     /* Print the header offsets */
00828     for (ioff=0 ; ioff<cpl_bivector_get_size(offsets) ; ioff++) {
00829         cpl_msg_info(cpl_func, "Telescope offsets (Frame %d): %g %g", ioff+1,
00830                 offs_est_x[ioff], offs_est_y[ioff]) ;
00831     }
00832 
00833     /* Subtract the first offset to all offsets */
00834     off_0_x = -offs_est_x[0]; // This is to get the cpl convention
00835     off_0_y = -offs_est_y[0];
00836     for (ioff=1 ; ioff<cpl_bivector_get_size(offsets) ; ioff++) 
00837     {
00838         offs_est_x[ioff] -= offs_est_x[0] ;
00839         offs_est_y[ioff] -= offs_est_y[0] ;
00840     }
00841     offs_est_x[0] = offs_est_y[0] = 0.00 ;
00842 
00843     /* Check if the max offset is not too big */
00844     /* The criteria is that for a given frame, the closest frame cannot be 
00845      * further than hawki_sci_jitter_config.offset_max (in both dimensions) */
00846     offset_x_sort = cpl_vector_duplicate(cpl_bivector_get_x(offsets));
00847     offset_y_sort = cpl_vector_duplicate(cpl_bivector_get_y(offsets));
00848     cpl_vector_sort(offset_x_sort, +1);
00849     cpl_vector_sort(offset_y_sort, +1);
00850     for (ioff=0 ; ioff<cpl_bivector_get_size(offsets) - 1 ; ioff++)
00851     {
00852         double diff_x, diff_y;
00853         diff_x = cpl_vector_get(offset_x_sort,ioff+1)-cpl_vector_get(offset_x_sort,ioff);
00854         cpl_vector_set(offset_x_sort, ioff, diff_x);
00855         diff_y = cpl_vector_get(offset_y_sort,ioff+1)-cpl_vector_get(offset_y_sort,ioff);
00856         cpl_vector_set(offset_y_sort, ioff, diff_y);
00857     }
00858     cpl_vector_set(offset_x_sort, cpl_bivector_get_size(offsets)-1, 0.);
00859     cpl_vector_set(offset_y_sort, cpl_bivector_get_size(offsets)-1, 0.);
00860     max_x = cpl_vector_get_max(offset_x_sort);
00861     max_y = cpl_vector_get_max(offset_y_sort);
00862     cpl_vector_delete(offset_x_sort);
00863     cpl_vector_delete(offset_y_sort);
00864     
00865     if (max_x > hawki_sci_jitter_config.offset_max || 
00866         max_y > hawki_sci_jitter_config.offset_max) 
00867     {
00868         cpl_msg_error(cpl_func, "Sorry, no support for frames further than %d from its closest neighbour",
00869                 hawki_sci_jitter_config.offset_max) ;
00870         cpl_bivector_delete(offsets);
00871         return NULL ;
00872     }
00873     
00874     /* Create output object */
00875     combined = cpl_malloc(HAWKI_NB_DETECTORS*sizeof(cpl_image*)) ;
00876   
00877     /* Loop on the detectors */
00878     for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
00879     {
00880         cpl_frameset  *  selected_jitter;
00881         cpl_bivector  *  selected_offsets;
00882         cpl_image     *  flat_ima = NULL;
00883         cpl_image     *  dark_ima = NULL;
00884         cpl_image     *  bpm_ima = NULL;
00885         cpl_imagelist *  in = NULL;
00886         cpl_imagelist *  in_sky = NULL;
00887         int              nrejected;
00888         
00889         cpl_msg_info(cpl_func, "Combine chip number %d", idet+1) ;
00890         cpl_msg_indent_more() ;
00891         
00892         /* Apply frame selection based on offset values */
00893         selected_jitter     = cpl_frameset_duplicate(jitters);
00894         selected_offsets = cpl_bivector_duplicate(offsets);
00895         if(hawki_sci_jitter_config.max_njitter != -1)
00896         {
00897             if(hawki_sci_jitter_config.max_njitter <
00898                     cpl_frameset_get_size(selected_jitter))
00899             {
00900                 while(cpl_frameset_get_size(selected_jitter) >
00901                       hawki_sci_jitter_config.max_njitter)
00902                 {
00903                     int irm = cpl_frameset_get_size(selected_jitter) - 1;
00904                     cpl_frameset_erase_frame
00905                         (selected_jitter,
00906                          cpl_frameset_get_frame(selected_jitter,irm));
00907                 }
00908                 cpl_vector_set_size(cpl_bivector_get_x(selected_offsets),
00909                                     hawki_sci_jitter_config.max_njitter);
00910                 cpl_vector_set_size(cpl_bivector_get_y(selected_offsets),
00911                                     hawki_sci_jitter_config.max_njitter);
00912             }
00913         }
00914         hawki_sci_jitter_output.ncomb[idet] = 
00915             cpl_frameset_get_size(selected_jitter);
00916         nrejected = cpl_frameset_get_size(selected_jitter) - 
00917             cpl_frameset_get_size(jitters);
00918         if(nrejected != 0)
00919             cpl_msg_info(cpl_func,"%d frames reject due to large offsets", 
00920                          nrejected); 
00921                 
00922         
00923         /* Load the input data */
00924         cpl_msg_info(cpl_func, "Load the input data") ;
00925         cpl_msg_indent_more() ;
00926         if ((in = hawki_load_detector(selected_jitter,
00927                                   idet+1, CPL_TYPE_FLOAT)) == NULL) {
00928             cpl_msg_error(cpl_func, "Cannot load chip %d", idet+1) ;
00929             cpl_free(combined) ;
00930             cpl_bivector_delete(offsets) ;
00931             cpl_msg_indent_less() ;
00932             cpl_msg_indent_less() ;
00933             return NULL ;
00934         }
00935         if (sky) {
00936             if ((in_sky = hawki_load_detector(sky, idet+1, CPL_TYPE_FLOAT)) == NULL) 
00937             {
00938                 cpl_msg_warning(cpl_func, "Cannot load sky for chip %d",idet+1);
00939             }
00940         } else in_sky = NULL ;
00941         cpl_msg_indent_less() ;
00942 
00943         /* Read the calibrations */
00944         cpl_msg_info(cpl_func, "Load the calibration data") ;
00945         if(hawki_sci_jitter_read_calib(flat, dark, bpm,
00946                                        &flat_ima, &dark_ima, &bpm_ima,
00947                                        idet) != 0)
00948         {
00949             cpl_msg_error(cpl_func, "Cannot read some of the calibrations");
00950             cpl_imagelist_delete(in);
00951             cpl_free(combined);
00952             if (in_sky) cpl_imagelist_delete(in_sky);
00953             cpl_bivector_delete(offsets);
00954             cpl_msg_indent_less();
00955             cpl_msg_indent_less();
00956             return NULL ;
00957         }
00958         
00959         /* Apply the calibrations */
00960         if (flat || dark || bpm ) 
00961         {
00962             cpl_msg_info(cpl_func, "Apply the calibrations") ;
00963             cpl_msg_indent_more() ;
00964             /* Basic calibration of the OBJECTS */
00965             if (hawki_flat_dark_bpm_detector_calib
00966                     (in, flat_ima, dark_ima, bpm_ima) == -1) 
00967             {
00968                 cpl_msg_error(cpl_func, "Cannot calibrate the objects") ;
00969                 cpl_imagelist_delete(in) ;
00970                 cpl_free(combined) ;
00971                 if (in_sky) cpl_imagelist_delete(in_sky) ;
00972                 cpl_bivector_delete(offsets) ;
00973                 cpl_image_delete(flat_ima);
00974                 cpl_image_delete(dark_ima);
00975                 cpl_image_delete(bpm_ima);
00976                 cpl_msg_indent_less() ;
00977                 cpl_msg_indent_less() ;
00978                 return NULL ;
00979             }
00980             /* Basic calibration of the SKY */
00981             if (in_sky) {
00982                 if (hawki_flat_dark_bpm_detector_calib
00983                         (in_sky, flat_ima, dark_ima, bpm_ima) == -1) 
00984                 {
00985                     cpl_msg_warning(cpl_func, "Cannot calibrate the sky") ;
00986                     cpl_imagelist_delete(in_sky) ;
00987                     in_sky = NULL ;
00988                 }
00989             }
00990             cpl_msg_indent_less() ;
00991         }
00992         cpl_image_delete(flat_ima);
00993         cpl_image_delete(dark_ima);
00994         cpl_image_delete(bpm_ima);
00995 
00996         /* Apply the sky correction */
00997         cpl_msg_info(cpl_func, "Sky estimation and correction") ;
00998         cpl_msg_indent_more() ;
00999         if (hawki_sci_jitter_sky(in, in_sky, bkg_stats, idet) == -1)
01000         {
01001             cpl_msg_error(cpl_func, "Cannot estimate the sky") ;
01002             cpl_imagelist_delete(in) ;
01003             if (in_sky) cpl_imagelist_delete(in_sky) ;
01004             cpl_free(combined) ;
01005             cpl_bivector_delete(offsets) ;
01006             cpl_msg_indent_less() ;
01007             cpl_msg_indent_less() ;
01008             return NULL ;
01009         }
01010         if (in_sky) cpl_imagelist_delete(in_sky) ;
01011         cpl_msg_indent_less() ;
01012     
01013         /* Apply the shift and add */
01014         cpl_msg_info(cpl_func, "Shift and stacking") ;
01015         cpl_msg_indent_more() ;
01016         comb_chip = hawki_sci_jitter_saa(&in, selected_offsets, 
01017                 &(hawki_sci_jitter_output.combined_pos_x[idet]),
01018                 &(hawki_sci_jitter_output.combined_pos_y[idet])) ;
01019         hawki_sci_jitter_output.combined_cumoffset_x[idet] = 
01020             hawki_sci_jitter_output.combined_pos_x[idet] - off_0_x;
01021         hawki_sci_jitter_output.combined_cumoffset_y[idet] = 
01022             hawki_sci_jitter_output.combined_pos_y[idet] - off_0_y;
01023         if (comb_chip == NULL) {
01024             cpl_msg_error(cpl_func, "Cannot apply the shift and add") ;
01025             cpl_imagelist_delete(in) ;
01026             cpl_free(combined) ;
01027             cpl_bivector_delete(offsets) ;
01028             cpl_msg_indent_less() ;
01029             cpl_msg_indent_less() ;
01030             return NULL ;
01031         }
01032         cpl_imagelist_delete(in) ;
01033         cpl_msg_indent_less() ;
01034 
01035         /* Put the results in the image list */
01036         combined[idet] = comb_chip[0] ;
01037         cpl_image_delete(comb_chip[1]) ;
01038         cpl_free(comb_chip) ;
01039         cpl_msg_indent_less() ;
01040         
01041         /* Free */
01042         cpl_frameset_delete(selected_jitter);
01043         cpl_bivector_delete(selected_offsets);
01044     }
01045     cpl_bivector_delete(offsets) ;
01046 
01047     return combined ;
01048 }
01049 
01050 /*----------------------------------------------------------------------------*/
01057 /*----------------------------------------------------------------------------*/
01058 static int hawki_sci_jitter_sky
01059 (cpl_imagelist   *   objs,
01060  cpl_imagelist   *   skys,
01061  cpl_table       **  bkg_stats,
01062  int                 idet)
01063 {
01064     cpl_image       *   sky ;
01065     int                 nframes;
01066     double              median ;
01067     cpl_image       *   cur_ima ;
01068     int                 i ;
01069 
01070     /* Initialise */
01071     nframes = cpl_imagelist_get_size(objs) ;
01072 
01073     /* Compute the sky frame */
01074     if (skys != NULL) {
01075        cpl_msg_info(cpl_func, "Median of sky images") ;
01076         /* Use sky images */
01077         if ((sky = cpl_imagelist_collapse_median_create(skys)) == NULL) {
01078             cpl_msg_error(cpl_func, "Cannot compute the median of sky images") ;
01079             return -1;
01080         }
01081         
01082         /* Statistics on the background */
01083         if(bkg_stats != NULL)
01084         {
01085             cpl_table_set_size(bkg_stats[idet], 1);
01086             hawki_image_stats_fill_from_image
01087                 (bkg_stats, sky,
01088                  1,
01089                  1,
01090                  cpl_image_get_size_x(sky),
01091                  cpl_image_get_size_y(sky),
01092                  idet, 0);
01093         }
01094         
01095         /* Correct the objects images  */
01096         if (cpl_imagelist_subtract_image(objs, sky) != CPL_ERROR_NONE) {
01097             cpl_msg_error(cpl_func, "Cannot corr. the obj images from the sky");
01098             cpl_image_delete(sky) ;
01099             return -1;
01100         }
01101         cpl_image_delete(sky) ;
01102         /* Normalise the object planes */
01103         for (i=0 ; i<nframes ; i++) {
01104             cur_ima = cpl_imagelist_get(objs, i) ;
01105             median = cpl_image_get_median(cur_ima) ;
01106             cpl_image_subtract_scalar(cur_ima, median) ;
01107         }
01108     } else if (hawki_sci_jitter_config.sky_minnb > nframes) {
01109         cpl_msg_info(cpl_func, "Median of object images") ;
01110          /* Use objs images */
01111         if ((sky = cpl_imagelist_collapse_median_create(objs)) == NULL) {
01112             cpl_msg_error(cpl_func, "Cannot compute the median of obj images") ;
01113             return -1;
01114         }
01115 
01116         /* Statistics on the background */
01117         if(bkg_stats != NULL)
01118         {
01119             cpl_table_set_size(bkg_stats[idet], 1);
01120             hawki_image_stats_fill_from_image
01121                 (bkg_stats, sky,
01122                  1,
01123                  1,
01124                  cpl_image_get_size_x(sky),
01125                  cpl_image_get_size_y(sky),
01126                  idet, 0);
01127         }
01128         
01129         /* Correct the objects images  */
01130         if (cpl_imagelist_subtract_image(objs, sky) != CPL_ERROR_NONE) {
01131             cpl_msg_error(cpl_func, "Cannot corr. the obj images from the sky");
01132             cpl_image_delete(sky) ;
01133             return -1;
01134         }
01135         /* Normalise the object planes */
01136         for (i=0 ; i<nframes ; i++) {
01137             cur_ima = cpl_imagelist_get(objs, i) ;
01138             median = cpl_image_get_median(cur_ima) ;
01139             cpl_image_subtract_scalar(cur_ima, median) ;
01140         }
01141         /* Delete sky image */
01142         cpl_image_delete(sky) ;
01143     } else {
01144         cpl_msg_info(cpl_func, "Computing running median on jitter images") ;
01145         /* Use objects images */
01146         if (hawki_sci_jitter_sky_running(objs, bkg_stats, idet) == -1)
01147         {
01148             cpl_msg_error(cpl_func, 
01149                     "Cannot apply the running median");
01150             return -1;
01151         }
01152     }
01153     return 0;
01154 }
01155 
01156 /*----------------------------------------------------------------------------*/
01175 /*----------------------------------------------------------------------------*/
01176 static int hawki_sci_jitter_sky_running
01177 (cpl_imagelist *  in,
01178  cpl_table     ** bkg_stats,
01179  int              idet) 
01180 {
01181     int                 rejmin, rejmax, halfw;
01182     cpl_imagelist   *   result_buffer;
01183     int                 ni, nx, ny;
01184     cpl_vector      *   medians;
01185     cpl_image       *   cur_ima;
01186     cpl_image       *   tmp_ima;
01187     double              one_med;
01188     int                 i, k;
01189     int                 first_buffered = 0;
01190     int                 next_not_to_be_used;
01191 
01192     /* Test entries */
01193     if (in==NULL) return -1;
01194 
01195     /* Initialise */
01196     rejmin = hawki_sci_jitter_config.sky_rejmin ;
01197     rejmax = hawki_sci_jitter_config.sky_rejmax ;
01198     halfw  = hawki_sci_jitter_config.sky_halfw ;
01199     ni = cpl_imagelist_get_size(in) ;
01200     cur_ima = cpl_imagelist_get(in, 0) ;
01201     nx = cpl_image_get_size_x(cur_ima) ;
01202     ny = cpl_image_get_size_y(cur_ima) ;
01203     
01204     /* Tests on validity of rejection parameters */
01205     if (((rejmin+rejmax)>=halfw) || (halfw<1) || (rejmin<0) || (rejmax<0)) {
01206         cpl_msg_error(cpl_func, "cannot run filter with rej parms %d (%d-%d)",
01207                 halfw, rejmin, rejmax);
01208         return -1;
01209     }   
01210     /* Pre-compute median value in each plane */
01211     medians = cpl_vector_new(ni) ;
01212     for (i=0 ; i<ni ; i++) {
01213         cur_ima = cpl_imagelist_get(in, i) ;
01214         cpl_vector_set(medians, i, cpl_image_get_median(cur_ima)) ;
01215     }
01216     /* Allocate output cube */
01217     result_buffer = cpl_imagelist_new() ;
01218 
01219     /* Allocate output bg stats */
01220     cpl_table_set_size(bkg_stats[idet], ni);
01221     
01222     /* Main loop over input planes */
01223     for (k=0 ; k<ni ; k++)
01224     {
01225         cpl_image * bkg;
01226 
01227         /* Create the background image, to later compute stats */
01228         bkg = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01229 
01230         hawki_bkg_from_running_mean_detector
01231             (in, medians, k, halfw, rejmin, rejmax, bkg);
01232 
01233         /* Subtract the background from the current image */
01234         tmp_ima = cpl_image_subtract_create(cpl_imagelist_get(in, k), bkg);
01235         
01236         /* Statistics on the background */
01237         if(bkg_stats != NULL)
01238         {
01239             hawki_image_stats_fill_from_image
01240                 (bkg_stats, bkg,
01241                  1, 1, nx, ny,
01242                  idet, k);
01243         }
01244         cpl_image_delete(bkg);
01245        
01246         /* Place the new image in a result buffer */
01247         cpl_imagelist_set(result_buffer, tmp_ima,
01248                           cpl_imagelist_get_size(result_buffer));
01249         
01250         /* Empty the buffer as much as possible */
01251         next_not_to_be_used = k - halfw;
01252         while(next_not_to_be_used >= first_buffered)
01253         {
01254             cpl_imagelist_set(in, cpl_imagelist_unset(result_buffer, 0),
01255                               first_buffered);
01256             first_buffered++;
01257         }
01258     }
01259     /* Empty the buffer finally */
01260     next_not_to_be_used = ni - 1;
01261     while(next_not_to_be_used >= first_buffered)
01262     {
01263         cpl_imagelist_set(in, cpl_imagelist_unset(result_buffer, 0),
01264                           first_buffered);
01265         first_buffered++;
01266     }
01267     cpl_imagelist_delete(result_buffer);
01268     cpl_vector_delete(medians);
01269 
01270     /* Subtract median from each frame */
01271     for (i=0 ; i<ni ; i++) {
01272         cur_ima = cpl_imagelist_get(in, i);
01273         one_med = cpl_image_get_median(cur_ima) ;
01274         cpl_image_subtract_scalar(cur_ima, one_med) ;
01275     }
01276     return 0;
01277 }
01278 
01279 /*----------------------------------------------------------------------------*/
01288 /*----------------------------------------------------------------------------*/
01289 static cpl_image ** hawki_sci_jitter_saa(
01290         cpl_imagelist   **  in,
01291         cpl_bivector    *   offsets,
01292         double          *   pos_x,
01293         double          *   pos_y)
01294 {
01295     cpl_bivector        *   offs_est;
01296     cpl_bivector        *   offs_used;
01297     cpl_bivector        *   objs ;
01298     cpl_image           **  combined ;
01299     int                     nfiles, ngood, nima, nx, ny ;
01300     int                     i;
01301 
01302     /* Check entries */
01303     if (pos_x == NULL || pos_y == NULL) return NULL ;
01304     if (offsets == NULL) return NULL ;
01305 
01306     /* Get the number of images */
01307     nfiles = cpl_imagelist_get_size(*in) ;
01308     if (cpl_bivector_get_size(offsets) != nfiles) {
01309         cpl_msg_error(cpl_func, "Invalid input objects sizes") ; 
01310         return NULL ;
01311     }
01312     
01313     /* Get the offsets estimation of each input file pair */
01314     cpl_msg_info(cpl_func, "Get the offsets estimation") ;
01315     offs_est = NULL ;
01316     if (hawki_sci_jitter_config.offsets &&
01317             hawki_sci_jitter_config.offsets[0] != (char)0) {
01318         /* A file has been provided on the command line */
01319         offs_est = cpl_bivector_read((char*)hawki_sci_jitter_config.offsets);
01320         if ((offs_est==NULL)||(cpl_bivector_get_size(offs_est)!=nfiles)) {
01321             cpl_msg_error(cpl_func, "Cannot get offsets from %s", 
01322                     hawki_sci_jitter_config.offsets) ;
01323             return NULL ;
01324         }
01325     } else {
01326         /* Use the offsets from the header */
01327         offs_est = cpl_bivector_duplicate(offsets) ;
01328         cpl_vector_multiply_scalar(cpl_bivector_get_x(offs_est), -1.0) ;
01329         cpl_vector_multiply_scalar(cpl_bivector_get_y(offs_est), -1.0) ;
01330     }
01331 
01332     /* Read the provided objects file if provided */
01333     objs = NULL ;
01334     if (hawki_sci_jitter_config.refine &&
01335             hawki_sci_jitter_config.objects &&
01336             hawki_sci_jitter_config.objects[0] != (char)0) {
01337         cpl_msg_info(cpl_func, "Get the user provided correlation objects") ;
01338         /* A file has been provided on the command line */
01339         objs = cpl_bivector_read((char*)hawki_sci_jitter_config.objects) ;
01340         if (objs==NULL) {
01341             cpl_msg_error(cpl_func, "Cannot get objects from %s",
01342                     hawki_sci_jitter_config.objects) ;
01343             cpl_bivector_delete(offs_est) ;
01344             return NULL ;
01345         }
01346     }
01347 
01348     /* Get a correlation point from the difference of the first images */
01349     if (hawki_sci_jitter_config.refine && objs == NULL) {
01350         cpl_apertures  *   aperts;
01351         cpl_image      *   detect_image;
01352         cpl_vector     *   thresh_vect;
01353         double         *   objs_x ;
01354         double         *   objs_y ;
01355         cpl_msg_info(cpl_func, "Get a cross-correlation point") ;
01356         thresh_vect = cpl_vector_new(4) ;
01357         cpl_vector_set(thresh_vect, 0, 5.0) ;
01358         cpl_vector_set(thresh_vect, 1, 2.0) ;
01359         cpl_vector_set(thresh_vect, 2, 1.0) ;
01360         cpl_vector_set(thresh_vect, 3, 0.5) ;
01361         detect_image  = cpl_imagelist_get(*in, 0);
01362         if ((aperts = cpl_apertures_extract_window(detect_image, thresh_vect, 
01363                         400, 400, 1600, 1600, NULL)) == NULL) {
01364             cpl_msg_error(cpl_func, "Cannot find any cross-correlation point") ;
01365             cpl_bivector_delete(offs_est) ;
01366             cpl_vector_delete(thresh_vect) ;
01367             return NULL ;
01368         }
01369         cpl_vector_delete(thresh_vect) ;
01370         cpl_apertures_sort_by_npix(aperts) ;
01371         objs = cpl_bivector_new(1) ;
01372         objs_x = cpl_bivector_get_x_data(objs) ;
01373         objs_y = cpl_bivector_get_y_data(objs) ;
01374         objs_x[0] = cpl_apertures_get_pos_x(aperts, 1) ;
01375         objs_y[0] = cpl_apertures_get_pos_y(aperts, 1) ;
01376         cpl_apertures_delete(aperts) ;
01377         if (objs == NULL) {
01378             cpl_msg_error(cpl_func, "Cannot find any cross-correlation point") ;
01379             cpl_bivector_delete(offs_est) ;
01380             return NULL ;
01381         }
01382         cpl_msg_info(cpl_func, 
01383                 "Correlation point: %g %g\n", objs_x[0], objs_y[0]);
01384     }
01385 
01386     /* Refine the offsets */
01387     if (hawki_sci_jitter_config.refine) {
01388         cpl_bivector *   offs_refined;
01389         double       *   offs_refined_x;
01390         double       *   offs_refined_y;
01391         double       *   offs_est_x;
01392         double       *   offs_est_y;
01393         cpl_vector   *   correl ;
01394         double       *   correl_data ;
01395         cpl_msg_info(cpl_func, "Refine the offsets");
01396         cpl_msg_indent_more() ;
01397         nima = cpl_imagelist_get_size(*in) ;
01398         correl = cpl_vector_new(nima) ;
01399         if ((offs_refined = cpl_geom_img_offset_fine(*in, offs_est, objs,
01400                         hawki_sci_jitter_config.sx, 
01401                         hawki_sci_jitter_config.sy,
01402                         hawki_sci_jitter_config.mx, 
01403                         hawki_sci_jitter_config.my,
01404                         correl)) == NULL) {
01405             cpl_msg_error(cpl_func, "Cannot refine the offsets");
01406             cpl_bivector_delete(offs_est) ;
01407             if (objs != NULL) cpl_bivector_delete(objs) ;
01408             cpl_vector_delete(correl) ;
01409             return NULL ;
01410         }
01411         if (objs != NULL) cpl_bivector_delete(objs) ;
01412 
01413         /* Display the results */
01414         offs_est_x = cpl_bivector_get_x_data(offs_est);
01415         offs_est_y = cpl_bivector_get_y_data(offs_est);
01416         offs_refined_x = cpl_bivector_get_x_data(offs_refined);
01417         offs_refined_y = cpl_bivector_get_y_data(offs_refined) ;
01418         correl_data = cpl_vector_get_data(correl) ;
01419         cpl_msg_info(cpl_func, "Refined offsets [correlation factor]") ;
01420         ngood = 0 ;
01421         for (i=0 ; i<nima ; i++) {
01422             cpl_msg_info(cpl_func, "#%02d: %8.2f %8.2f [%12.2f]",
01423                     i+1, offs_refined_x[i], offs_refined_y[i], correl_data[i]);
01424             if (correl_data[i] > -0.5) ngood++ ;
01425         }
01426         if (ngood == 0) {
01427             cpl_msg_error(cpl_func, "No frame correctly correlated") ;
01428             cpl_bivector_delete(offs_est);
01429             cpl_bivector_delete(offs_refined);
01430             cpl_vector_delete(correl);
01431             return NULL ;
01432         }
01433         cpl_msg_indent_less();
01434 
01435         /* Replace bad correlated images with the nominal offsets */
01436         cpl_msg_info(cpl_func, "Using nominal offsets for badly "
01437                      "correlated images (%d out of %d)", nima-ngood, nima);
01438         for (i=0 ; i<nima ; i++) {
01439             if (correl_data[i] < -0.5) {
01440                 offs_refined_x[i] = offs_est_x[i];
01441                 offs_refined_y[i] = offs_est_y[i];
01442             }
01443         }
01444         offs_used = cpl_bivector_duplicate(offs_refined);
01445         cpl_bivector_delete(offs_est);
01446         cpl_bivector_delete(offs_refined);
01447         cpl_vector_delete(correl);
01448     }
01449     else
01450     {
01451         offs_used = cpl_bivector_duplicate(offs_est);
01452         cpl_bivector_delete(offs_est);
01453     }
01454 
01455     /* Discard the pixels on the sides */
01456     if (hawki_sci_jitter_config.borders > 0) {
01457         cpl_imagelist  *   in_ext ;
01458         cpl_image      *   tmp1 ;
01459         cpl_image      *   tmp2 ;
01460         nx = cpl_image_get_size_x(cpl_imagelist_get(*in, 0)) ;
01461         ny = cpl_image_get_size_y(cpl_imagelist_get(*in, 0)) ;
01462         in_ext = cpl_imagelist_new() ;
01463         while(cpl_imagelist_get_size(*in) > 0)
01464         {
01465             tmp1 = cpl_imagelist_unset(*in, 0);
01466             tmp2 = cpl_image_extract(tmp1, 
01467                     hawki_sci_jitter_config.borders+1, 
01468                     hawki_sci_jitter_config.borders+1, 
01469                     nx-hawki_sci_jitter_config.borders, 
01470                     ny-hawki_sci_jitter_config.borders) ;
01471             cpl_image_delete(tmp1);
01472             cpl_imagelist_set(in_ext, tmp2, cpl_imagelist_get_size(in_ext)) ;
01473         }
01474         cpl_imagelist_delete(*in) ;
01475         *in = in_ext ;
01476     }
01477 
01478     /* Apply the shift & add */
01479     cpl_msg_info(cpl_func, "Recombine the images set") ;
01480     cpl_msg_indent_more() ;
01481     if ((combined=cpl_geom_img_offset_saa(*in, offs_used,
01482                     CPL_KERNEL_DEFAULT, 
01483                     hawki_sci_jitter_config.rej_low,
01484                     hawki_sci_jitter_config.rej_high,
01485                     hawki_sci_jitter_config.comb_meth,
01486                     pos_x, pos_y)) == NULL) {
01487         cpl_msg_error(cpl_func, "Cannot apply the shift and add") ;
01488         cpl_bivector_delete(offs_used) ;
01489         cpl_msg_indent_less() ;
01490         return NULL ;
01491     }
01492     cpl_msg_indent_less() ;
01493     *pos_x -= hawki_sci_jitter_config.borders ;
01494     *pos_y -= hawki_sci_jitter_config.borders ;
01495 
01496     /* Free and return */
01497     cpl_bivector_delete(offs_used) ;
01498     return combined ;
01499 }
01500 
01501 /*----------------------------------------------------------------------------*/
01508 /*----------------------------------------------------------------------------*/
01509 static int hawki_sci_jitter_qc
01510 (cpl_frameset *   science_frames,
01511  cpl_image   **   combined_images, 
01512  cpl_table   **   obj_charac)
01513 {
01514     cpl_vector      *   thresh_vec ;
01515     cpl_apertures   *   aperts ;
01516     int                 nb_objs ;
01517     double              angle ;
01518     double          *   fwhms_x ;
01519     double          *   fwhms_y ;
01520     cpl_bivector    *   iqe ;
01521     int                 nb_good ;
01522     cpl_vector      *   fwhms_good ;
01523     double          *   fwhms_good_data ;
01524     double              f_min, f_max, fr, fx, fy ;
01525     int                 chip;
01526     int                 iobj;
01527     int                 j;
01528     
01529     /* Initialise */
01530     double              seeing_min_arcsec = 0.1 ;
01531     double              seeing_max_arcsec = 5.0 ;
01532     double              seeing_fwhm_var   = 0.2 ;
01533 
01534     /* Check entries */
01535     if (combined_images  == NULL) return -1 ;
01536     if (obj_charac       == NULL) return -1 ;
01537 
01538     /* Create the vector for the detection thresholds */
01539     thresh_vec = cpl_vector_new(11) ;
01540     cpl_vector_set(thresh_vec, 0, 100.0) ;
01541     cpl_vector_set(thresh_vec, 0, 90.0) ;
01542     cpl_vector_set(thresh_vec, 0, 80.0) ;
01543     cpl_vector_set(thresh_vec, 0, 70.0) ;
01544     cpl_vector_set(thresh_vec, 0, 60.0) ;
01545     cpl_vector_set(thresh_vec, 0, 50.0) ;
01546     cpl_vector_set(thresh_vec, 1, 40.0) ;
01547     cpl_vector_set(thresh_vec, 1, 30.0) ;
01548     cpl_vector_set(thresh_vec, 1, 20.0) ;
01549     cpl_vector_set(thresh_vec, 1, 10.0) ;
01550     cpl_vector_set(thresh_vec, 2, 5.0) ;
01551 
01552     /* Get the mean airmass */
01553     hawki_sci_jitter_output.mean_airmass = 
01554         hawki_get_mean_airmass(science_frames);;
01555     
01556     /* Loop on the HAWK-I detectors */
01557     for (chip=0 ; chip<HAWKI_NB_DETECTORS ; chip++) 
01558     {
01559         /* Check entries */
01560         if (combined_images[chip]  == NULL) return -1 ;
01561         if (obj_charac[chip] == NULL) return -1 ;
01562     
01563         /* Detect apertures */
01564         if ((aperts = cpl_apertures_extract
01565                 (combined_images[chip], thresh_vec, NULL)) == NULL) {
01566             cpl_msg_warning(cpl_func, "Cannot detect any aperture on chip %d",
01567                             chip+1) ;
01568             continue;
01569         }
01570 
01571         /* Number of detected objects */
01572         nb_objs = cpl_apertures_get_size(aperts);
01573         cpl_msg_info(cpl_func, "%d objects detected on chip %d",nb_objs,chip+1);
01574         hawki_sci_jitter_output.nbobjs[chip] = nb_objs ;
01575         fwhms_x = cpl_malloc(nb_objs * sizeof(double)) ;
01576         fwhms_y = cpl_malloc(nb_objs * sizeof(double)) ;
01577         
01578         /* Initialize the output table */
01579         cpl_table_set_size(obj_charac[chip], nb_objs);
01580         cpl_table_new_column
01581             (obj_charac[chip], HAWKI_COL_OBJ_POSX, CPL_TYPE_DOUBLE);
01582         cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_POSX,"pix");
01583         cpl_table_new_column
01584             (obj_charac[chip], HAWKI_COL_OBJ_POSY, CPL_TYPE_DOUBLE);
01585         cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_POSY,"pix");
01586         cpl_table_new_column
01587             (obj_charac[chip], HAWKI_COL_OBJ_ANGLE, CPL_TYPE_DOUBLE);
01588         cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_ANGLE,"grad");
01589         cpl_table_new_column
01590             (obj_charac[chip], HAWKI_COL_OBJ_FWHM_MAJAX, CPL_TYPE_DOUBLE);
01591         cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_FWHM_MAJAX,"pix");
01592         cpl_table_new_column
01593             (obj_charac[chip], HAWKI_COL_OBJ_FWHM_MINAX, CPL_TYPE_DOUBLE);
01594         cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_FWHM_MINAX,"pix");
01595         cpl_table_new_column
01596             (obj_charac[chip], HAWKI_COL_OBJ_ELLIP, CPL_TYPE_DOUBLE);
01597         cpl_table_new_column
01598             (obj_charac[chip], HAWKI_COL_OBJ_FLUX, CPL_TYPE_DOUBLE);
01599         cpl_table_set_column_unit(obj_charac[chip],HAWKI_COL_OBJ_FLUX,"ADU");
01600         for (iobj=0 ; iobj<nb_objs ; iobj++) 
01601         {
01602             /* Fill with the already known information */
01603             cpl_table_set_double(obj_charac[chip], HAWKI_COL_OBJ_POSX, iobj, 
01604                                  cpl_apertures_get_centroid_x(aperts, iobj+1));
01605             cpl_table_set_double(obj_charac[chip], HAWKI_COL_OBJ_POSY, iobj, 
01606                                  cpl_apertures_get_centroid_y(aperts, iobj+1));
01607             cpl_table_set_double(obj_charac[chip], HAWKI_COL_OBJ_FLUX, iobj, 
01608                                  cpl_apertures_get_flux(aperts, iobj+1)) ;
01609             /* Compute the FWHM informations */
01610             if ((iqe = cpl_image_iqe(combined_images[chip], 
01611                 (int)cpl_apertures_get_centroid_x(aperts, iobj+1) - 10,
01612                 (int)cpl_apertures_get_centroid_y(aperts, iobj+1) - 10,
01613                 (int)cpl_apertures_get_centroid_x(aperts, iobj+1) + 10,
01614                 (int)cpl_apertures_get_centroid_y(aperts, iobj+1) + 10))==NULL)
01615             {
01616                 cpl_error_reset() ;
01617                 cpl_msg_debug(cpl_func, "Cannot get FWHM for obj at pos %g %g",
01618                               cpl_apertures_get_centroid_x(aperts, iobj+1),
01619                               cpl_apertures_get_centroid_y(aperts, iobj+1)) ;
01620                 fwhms_x[iobj] = -1.0 ;
01621                 fwhms_y[iobj] = -1.0 ;
01622                 angle = 0.0 ;
01623             }
01624             else 
01625             {
01626                 fwhms_x[iobj] = cpl_vector_get(cpl_bivector_get_x(iqe), 2) ;
01627                 fwhms_y[iobj] = cpl_vector_get(cpl_bivector_get_x(iqe), 3) ;
01628                 angle = cpl_vector_get(cpl_bivector_get_x(iqe), 4) ;
01629                 cpl_bivector_delete(iqe) ;
01630                 cpl_msg_debug(cpl_func,
01631                               "FWHM for obj at pos %g %g: %g x %g (%g)",
01632                               cpl_apertures_get_centroid_x(aperts, iobj+1),
01633                               cpl_apertures_get_centroid_y(aperts, iobj+1),
01634                               fwhms_x[iobj], fwhms_y[iobj], angle) ;
01635             }
01636             cpl_table_set_double
01637                 (obj_charac[chip], HAWKI_COL_OBJ_ANGLE, iobj, angle) ;
01638             cpl_table_set_double
01639                 (obj_charac[chip], HAWKI_COL_OBJ_FWHM_MAJAX, iobj,
01640                  fwhms_x[iobj]);
01641             cpl_table_set_double
01642                 (obj_charac[chip], HAWKI_COL_OBJ_FWHM_MINAX, iobj,
01643                  fwhms_y[iobj]);
01644             cpl_table_set_double
01645                 (obj_charac[chip], HAWKI_COL_OBJ_ELLIP, iobj,
01646                  1 - fwhms_y[iobj] / fwhms_x[iobj]);
01647         }
01648         cpl_apertures_delete(aperts) ;
01649 
01650         /* Get the number of good values */
01651         nb_good = 0 ;
01652         for (iobj=0 ; iobj<nb_objs ; iobj++) 
01653         {
01654             if ((fwhms_x[iobj] > 0.0) && (fwhms_y[iobj] > 0.0)) nb_good++ ;
01655         }
01656         if (nb_good == 0)
01657         {
01658             cpl_msg_warning(cpl_func, "No objects to compute FWHM on chip %d",
01659                             chip+1);
01660             cpl_free(fwhms_x) ;
01661             cpl_free(fwhms_y) ;
01662             continue;
01663         }
01664     
01665         /* Get the good values */
01666         fwhms_good = cpl_vector_new(nb_good) ;
01667         fwhms_good_data = cpl_vector_get_data(fwhms_good) ;
01668         j=0 ;
01669         for (iobj=0 ; iobj<nb_objs ; iobj++) 
01670         {
01671             if ((fwhms_x[iobj] > 0.0) && (fwhms_y[iobj] > 0.0)) 
01672             {
01673                 fwhms_good_data[j] = (fwhms_x[iobj]+fwhms_y[iobj])/2.0 ;
01674                 j++ ;
01675             }
01676         }
01677    
01678         /* Compute the fwhm */
01679         if (nb_good < 3) 
01680         {
01681             /* Too few values to compute the median */
01682             hawki_sci_jitter_output.fwhm_pix[chip] = fwhms_good_data[0] ;
01683         } 
01684         else 
01685         {
01686             /* Compute the median */
01687             hawki_sci_jitter_output.fwhm_pix[chip] =
01688                 cpl_vector_get_median_const(fwhms_good) ;
01689         }
01690         hawki_sci_jitter_output.fwhm_arcsec[chip] = 
01691             hawki_sci_jitter_output.fwhm_pix[chip] *
01692             hawki_sci_jitter_output.pixscale ;
01693 
01694         /* Compute the mode of the FWHMs */
01695         if (nb_good > 5) 
01696         {
01697             hawki_sci_jitter_output.fwhm_mode[chip] =
01698                 hawki_vector_get_mode(fwhms_good);
01699             hawki_sci_jitter_output.fwhm_mode[chip] *= 
01700                 hawki_sci_jitter_output.pixscale ;
01701         }
01702         cpl_vector_delete(fwhms_good) ;
01703     
01704         /* IQ is the median of the (fwhm_x+fwhm_y/2) of the good stars */
01705         /* Compute f_min and f_max */
01706         f_min = seeing_min_arcsec / hawki_sci_jitter_output.pixscale ;
01707         f_max = seeing_max_arcsec / hawki_sci_jitter_output.pixscale ;
01708 
01709         /* Get the number of good values */
01710         nb_good = 0 ;
01711         for (iobj=0 ; iobj<nb_objs ; iobj++) 
01712         {
01713             fx = fwhms_x[iobj] ;
01714             fy = fwhms_y[iobj] ;
01715             fr = 2.0 * fabs(fx-fy) / (fx+fy) ;
01716             if ((fx > f_min) && (fx < f_max) && (fy > f_min) && (fy < f_max) &&
01717                     (fr < seeing_fwhm_var)) nb_good++ ;
01718         }
01719         if (nb_good == 0) 
01720         {
01721             cpl_msg_warning(cpl_func, "No objects to compute IQ on chip %d",
01722                             chip+1);
01723             cpl_free(fwhms_x) ;
01724             cpl_free(fwhms_y) ;
01725             continue;
01726         }
01727 
01728         /* Get the good values */
01729         fwhms_good = cpl_vector_new(nb_good) ;
01730         fwhms_good_data = cpl_vector_get_data(fwhms_good) ;
01731         j=0 ;
01732         for (iobj=0 ; iobj<nb_objs ; iobj++) 
01733         {
01734             fx = fwhms_x[iobj] ;
01735             fy = fwhms_y[iobj] ;
01736             fr = 2.0 * fabs(fx-fy) / (fx+fy) ;
01737             if ((fx > f_min) && (fx < f_max) && (fy > f_min) && (fy < f_max) &&
01738                     (fr < seeing_fwhm_var)) 
01739             {
01740                 fwhms_good_data[j] = (fx + fy)/2.0 ;
01741                 j++ ;
01742             }
01743         }
01744         cpl_free(fwhms_x) ;
01745         cpl_free(fwhms_y) ;
01746     
01747         /* Compute the fwhm */
01748         if (nb_good < 3) 
01749         {
01750             /* Too few values to compute the median */
01751             hawki_sci_jitter_output.iq[chip] = fwhms_good_data[0] ;
01752         }
01753         else 
01754         {
01755             /* Compute the median */
01756             hawki_sci_jitter_output.iq[chip] = 
01757                 cpl_vector_get_median_const(fwhms_good) ;
01758         }
01759         cpl_vector_delete(fwhms_good) ;
01760         hawki_sci_jitter_output.iq[chip] *= hawki_sci_jitter_output.pixscale ;
01761     }
01762     
01763     /* Cleanup */
01764     cpl_vector_delete(thresh_vec) ;
01765     
01766     return 0;
01767 }
01768 
01769 /*----------------------------------------------------------------------------*/
01781 /*----------------------------------------------------------------------------*/
01782 static int hawki_sci_jitter_read_calib
01783 (const char *  flat,
01784  const char *  dark,
01785  const char *  bpm,
01786  cpl_image  ** flat_image,
01787  cpl_image  ** dark_image,
01788  cpl_image  ** bpm_image,
01789  int           idet)
01790 {
01791     const char * reffile;
01792     int          ext_nb;
01793     
01794     if(flat == NULL && dark == NULL && bpm == NULL)
01795         return 0;
01796     if(*flat_image != NULL || *dark_image != NULL || *bpm_image != NULL)
01797         return 0;
01798     
01799     /* Get the extension number for this detector */
01800     if(flat != NULL)
01801         reffile = flat;
01802     else if(dark != NULL)
01803         reffile = dark;
01804     else
01805         reffile = bpm;
01806 
01807     /* Guess which is the extension to read */
01808     if ((ext_nb = hawki_get_ext_from_detector(reffile, idet + 1)) == -1) {
01809         cpl_msg_error(cpl_func, "Cannot get the extension with detector %d",
01810                       idet + 1);
01811         return -1;
01812     }
01813 
01814     /* Load the dark image */
01815     if(dark != NULL)
01816         *dark_image = cpl_image_load(dark, CPL_TYPE_FLOAT, 0, ext_nb);
01817     /* Load the flat image */
01818     if(flat != NULL)
01819         *flat_image = cpl_image_load(flat, CPL_TYPE_FLOAT, 0, ext_nb);
01820     /* Load the bpm image */
01821     if(bpm != NULL)
01822         *bpm_image = cpl_image_load(bpm, CPL_TYPE_FLOAT, 0, ext_nb);
01823     
01824     /* Multiply the dark image by the science exposure time */
01825     if(dark != NULL)
01826         cpl_image_multiply_scalar(*dark_image, hawki_sci_jitter_output.dit);
01827 
01828     /* Return */
01829     return 0;
01830 }
01831 
01832 /*----------------------------------------------------------------------------*/
01841 /*----------------------------------------------------------------------------*/
01842 static int hawki_sci_jitter_save
01843 (cpl_image           **  combined,
01844  cpl_image           *   stitched,
01845  cpl_table           **  obj_charac,
01846  cpl_table           **  raw_jitter_stats,
01847  cpl_table           **  bkg_stats,
01848  const cpl_table     *   raw_obj_tel_info,
01849  cpl_frameset        *   science_frames,
01850  cpl_frameset        *   calib_frames,
01851  cpl_parameterlist   *   parlist,
01852  cpl_frameset        *   set)
01853 {
01854     cpl_propertylist    *   plist ;
01855     double                  pscale, dit, bg_mean, bg_stdev, bg_instmag ;
01856     cpl_propertylist    **  qclists ;
01857     const cpl_frame     *   ref_frame ;
01858     cpl_frameset        *   used_frames;
01859     cpl_propertylist    *   wcslist ;
01860     cpl_propertylist    *   telstats;
01861     cpl_propertylist    *   inputlist ;
01862     double                  crpix1, crpix2 ;
01863     int                     ext_nb ;
01864     const char          *   recipe_name = "hawki_sci_jitter" ;
01865     int                     i;
01866     int                     ext_chip_1;
01867     cpl_errorstate          error_prevstate = cpl_errorstate_get();
01868 
01869     /* Initialise */
01870     pscale = hawki_sci_jitter_output.pixscale;
01871     dit = hawki_sci_jitter_output.dit;
01872 
01873     /* Get reference frame */
01874     ref_frame = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW);
01875 
01876     /* Get the used frames */ 
01877     used_frames = cpl_frameset_duplicate(science_frames);
01878     for(i = 0; i< cpl_frameset_get_size(calib_frames); ++i)
01879         cpl_frameset_insert(used_frames, 
01880                 cpl_frame_duplicate(cpl_frameset_get_frame(calib_frames, i)));
01881 
01882     /* Create the telescope data statistics */
01883     telstats = cpl_propertylist_new();
01884     hawki_compute_prop_tel_qc_stats(raw_obj_tel_info, telstats);
01885 
01886     /* Create the QC lists */
01887     qclists = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_propertylist*)) ;
01888     for (i=0 ; i<HAWKI_NB_DETECTORS ; i++) {
01889 
01890         /* Get the extension number */
01891         ext_nb=hawki_get_ext_from_detector(cpl_frame_get_filename(ref_frame), i+1);
01892 
01893         /* Handle WCS keys */
01894         wcslist = cpl_propertylist_load_regexp(
01895                 cpl_frame_get_filename(ref_frame), ext_nb, HAWKI_HEADER_WCS, 0);
01896         qclists[i] = cpl_propertylist_new() ;
01897 
01898         /* Compute bg_instmag */
01899         bg_mean = cpl_table_get_column_mean(bkg_stats[i], HAWKI_COL_STAT_MEAN);
01900         if (cpl_table_get_nrow(bkg_stats[i]) < 2) bg_stdev = 0 ;
01901         else bg_stdev = cpl_table_get_column_stdev
01902             (bkg_stats[i], HAWKI_COL_STAT_MEAN);
01903         if(bg_mean >= 0)
01904             bg_instmag = -2.5 * log10(bg_mean/(pscale*pscale*dit));
01905         else
01906             bg_instmag = 0;
01907 
01908         /* Fill the QC */
01909         cpl_propertylist_append_double
01910             (qclists[i], "ESO QC BACKGD MEAN", bg_mean) ;
01911         cpl_propertylist_append_double
01912             (qclists[i], "ESO QC BACKGD STDEV", bg_stdev);
01913         cpl_propertylist_append_double
01914             (qclists[i], "ESO QC BACKGD INSTMAG", bg_instmag) ;
01915         cpl_propertylist_append_int
01916             (qclists[i], "ESO QC NBOBJS", hawki_sci_jitter_output.nbobjs[i]);
01917         cpl_propertylist_append_double
01918             (qclists[i], "ESO QC IQ", hawki_sci_jitter_output.iq[i]);
01919         cpl_propertylist_append_double
01920             (qclists[i], "ESO QC IQ DIFF AMBI",
01921              hawki_sci_jitter_output.iq[i] - cpl_propertylist_get_double
01922                  (telstats, "ESO QC TEL AMBI FWHM MEAN"));
01923         cpl_propertylist_append_double
01924             (qclists[i], "ESO QC IQ DIFF TEL",
01925              hawki_sci_jitter_output.iq[i] - cpl_propertylist_get_double
01926                  (telstats, "ESO QC TEL IA FWHM MEAN"));
01927         cpl_propertylist_append_double
01928             (qclists[i], "ESO QC FWHM PIX",
01929              hawki_sci_jitter_output.fwhm_pix[i]);
01930         cpl_propertylist_append_double
01931             (qclists[i], "ESO QC FWHM ARCSEC",
01932              hawki_sci_jitter_output.fwhm_arcsec[i]);
01933         cpl_propertylist_append_double
01934             (qclists[i], "ESO QC FWHM MODE",
01935              hawki_sci_jitter_output.fwhm_mode[i]);
01936         cpl_propertylist_append_double
01937             (qclists[i], "ESO QC COMBINED POSX",
01938              hawki_sci_jitter_output.combined_pos_x[i]);
01939         cpl_propertylist_append_double
01940             (qclists[i], "ESO QC COMBINED POSY",
01941              hawki_sci_jitter_output.combined_pos_y[i]);
01942         cpl_propertylist_append_double
01943             (qclists[i], "ESO QC COMBINED CUMOFFSETX",
01944              hawki_sci_jitter_output.combined_cumoffset_x[i]);
01945         cpl_propertylist_append_double
01946             (qclists[i], "ESO QC COMBINED CUMOFFSETY",
01947              hawki_sci_jitter_output.combined_cumoffset_y[i]);
01948         cpl_propertylist_append_int
01949             (qclists[i], "ESO QC DATANCOM",hawki_sci_jitter_output.ncomb[i]);
01950         cpl_propertylist_append_double
01951             (qclists[i], "ESO QC AIRMASS MEAN",
01952              hawki_sci_jitter_output.mean_airmass);
01953 
01954         /* Update WCS and write them */
01955         crpix1 = cpl_propertylist_get_double(wcslist, "CRPIX1"); 
01956         crpix1 += hawki_sci_jitter_output.combined_pos_x[i];
01957         cpl_propertylist_update_double(wcslist, "CRPIX1", crpix1) ;
01958         crpix2 = cpl_propertylist_get_double(wcslist, "CRPIX2"); 
01959         crpix2 += hawki_sci_jitter_output.combined_pos_y[i] ;
01960         cpl_propertylist_update_double(wcslist, "CRPIX2", crpix2) ;
01961         cpl_propertylist_copy_property_regexp
01962             (qclists[i], wcslist, HAWKI_HEADER_WCS, 0) ;
01963         cpl_propertylist_delete(wcslist);
01964 
01965         /* Propagate some keywords from input raw frame extensions */
01966         inputlist = cpl_propertylist_load_regexp(
01967                 cpl_frame_get_filename(ref_frame), ext_nb,
01968                 HAWKI_HEADER_EXT_FORWARD, 0) ;
01969         cpl_propertylist_append(qclists[i], inputlist);
01970         cpl_propertylist_delete(inputlist) ;
01971     }
01972     
01973     /* Statistics of the raw images in the QC */
01974     hawki_image_stats_stats(raw_jitter_stats, qclists);
01975     
01976     /* Statistics of the detected objects in the QC */
01977     hawki_obj_prop_stats(obj_charac, qclists);
01978 
01979     /* Write the combined image */
01980     hawki_images_save(set,
01981                       parlist,
01982                       used_frames,
01983                       (const cpl_image **)combined,
01984                       recipe_name,
01985                       HAWKI_CALPRO_COMBINED,
01986                       HAWKI_PROTYPE_COMBINED, 
01987                       NULL,
01988                       (const cpl_propertylist**)qclists,
01989                       "hawki_sci_jitter.fits");
01990 
01991     /* Erase the WCS */
01992     for (i=0 ; i<HAWKI_NB_DETECTORS ; i++) {
01993         cpl_propertylist_erase_regexp(qclists[i], HAWKI_HEADER_WCS, 0) ;
01994     }
01995 
01996     /* Create a propertylist for PRO.x */
01997     plist = cpl_propertylist_new();
01998     cpl_propertylist_append_string(plist, CPL_DFS_PRO_TYPE,
01999                                    HAWKI_PROTYPE_STITCHED) ;
02000     cpl_propertylist_append_string(plist, CPL_DFS_PRO_CATG,
02001                                    HAWKI_CALPRO_STITCHED) ;
02002     /* Handle WCS keys */
02003     ext_chip_1 = 1;
02004     wcslist = cpl_propertylist_load_regexp(
02005             cpl_frame_get_filename(ref_frame), ext_chip_1, HAWKI_HEADER_WCS, 0);
02006     /* Update WCS and write them */
02007     crpix1 = cpl_propertylist_get_double(wcslist, "CRPIX1"); 
02008     crpix1 += hawki_sci_jitter_output.combined_pos_x[0];
02009     cpl_propertylist_update_double(wcslist, "CRPIX1", crpix1) ;
02010     crpix2 = cpl_propertylist_get_double(wcslist, "CRPIX2"); 
02011     crpix2 += hawki_sci_jitter_output.combined_pos_y[0] ;
02012     cpl_propertylist_update_double(wcslist, "CRPIX2", crpix2) ;
02013     cpl_propertylist_append(plist, wcslist);
02014     cpl_propertylist_delete(wcslist) ;
02015     /* Write the stitched image */
02016     cpl_dfs_save_image(set,
02017                        NULL,
02018                        parlist,
02019                        used_frames,
02020                        NULL,
02021                        stitched,
02022                        CPL_BPP_IEEE_FLOAT,
02023                        recipe_name,
02024                        plist,
02025                        NULL,
02026                        PACKAGE "/" PACKAGE_VERSION,
02027                        "hawki_sci_jitter_stitched.fits");
02028     cpl_propertylist_delete(plist);
02029 
02030     /* Write the FITS table with the objects statistics */
02031     if (obj_charac) 
02032     {
02033         hawki_tables_save(set,
02034                           parlist,
02035                           used_frames,
02036                           (const cpl_table **)obj_charac,
02037                           recipe_name,
02038                           HAWKI_CALPRO_OBJ_PARAM,
02039                           HAWKI_PROTYPE_OBJ_PARAM,
02040                           NULL,
02041                           (const cpl_propertylist**)qclists,
02042                           "hawki_sci_jitter_stars.fits");
02043     }
02044 
02045     /* Write the table with the background statistics */
02046     hawki_tables_save(set,
02047                       parlist,
02048                       used_frames,   
02049                       (const cpl_table **)bkg_stats,
02050                       recipe_name,
02051                       HAWKI_CALPRO_JITTER_BKG_STATS,
02052                       HAWKI_PROTYPE_JITTER_BKG_STATS,
02053                       NULL,
02054                       (const cpl_propertylist **)qclists,
02055                       "hawki_sci_jitter_bkg_stats.fits");
02056 
02057     /* Free and return */
02058     cpl_frameset_delete(used_frames);
02059     for (i=0 ; i<HAWKI_NB_DETECTORS ; i++) {
02060         cpl_propertylist_delete(qclists[i]) ;
02061     }
02062     cpl_propertylist_delete(telstats) ;
02063     cpl_free(qclists) ;
02064     if(!cpl_errorstate_is_equal(error_prevstate))
02065     {
02066         cpl_errorstate_set(CPL_ERROR_NONE);
02067         return -1;
02068     }
02069     return  0;
02070 }
02071 
02072 int hawki_sci_jitter_whole_image_algo
02073 (cpl_frameset       *  obj,
02074  cpl_table          ** raw_jitter_stats,
02075  cpl_table          *  raw_obj_tel_info,
02076  cpl_parameterlist  *  parlist,
02077  cpl_frameset       *  recipe_set)
02078 {
02079     int                 nframes;
02080     int                 iframe;
02081 
02082     
02083     nframes = cpl_frameset_get_size(obj);
02084     for( iframe = 0 ; iframe < nframes ; ++iframe)
02085     {
02086         /* Local storage variables */
02087         cpl_frame        * this_target_frame;
02088         cpl_propertylist * this_properties;
02089 
02090         /* Computing statistics for this frame */
02091         cpl_msg_info(cpl_func, "Getting statistics for image %d", iframe + 1);
02092         this_target_frame = cpl_frameset_get_frame(obj, iframe);
02093         hawki_image_stats_fill_from_frame
02094             (raw_jitter_stats, this_target_frame, iframe);
02095 
02096         /* Compute the telescope pcs statistics */
02097         this_properties = cpl_propertylist_load
02098             (cpl_frame_get_filename(this_target_frame), 0);
02099         if(this_properties == NULL)
02100         {
02101             cpl_msg_error(cpl_func,"Could not read the header of object frame");
02102             return  -1;
02103         }
02104         if(hawki_extract_prop_tel_qc(this_properties, raw_obj_tel_info, iframe))
02105         {
02106             cpl_msg_warning(cpl_func,"Some telescope properties could not be "
02107                             "read for image %d", iframe+1);
02108             cpl_errorstate_set(CPL_ERROR_NONE);
02109         }
02110         cpl_propertylist_delete(this_properties);
02111     }
02112 
02113     /* Saving the already computed products */
02114     cpl_msg_info(cpl_func, "Saving image statistics");
02115     if(hawki_sci_jitter_save_stats(raw_jitter_stats, raw_obj_tel_info, 
02116                                    obj,
02117                                    parlist, recipe_set) != 0)
02118         cpl_msg_warning(cpl_func,"Some data could not be saved. "
02119                         "Check permisions or disk space");
02120         
02121     
02122     /* Free and return */
02123     return 0;
02124 }
02125 
02126 int hawki_sci_jitter_save_stats
02127 (cpl_table          ** raw_jitter_stats,
02128  cpl_table          *  raw_obj_tel_info,
02129  cpl_frameset       *  jitter_frames,
02130  cpl_parameterlist  *  parlist,
02131  cpl_frameset       *  recipe_set)
02132 {
02133     int                 idet;
02134     const cpl_frame  *  ref_frame;
02135     cpl_propertylist ** qcstats;
02136     cpl_propertylist *  telstats;
02137     const char       *  recipe_name = "hawki_sci_jitter" ;
02138     cpl_errorstate      error_prevstate = cpl_errorstate_get();
02139     
02140     /* Statistics of the raw images in the QC */
02141     qcstats = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_propertylist*));
02142     /* Create the QC lists */
02143     ref_frame = irplib_frameset_get_first_from_group
02144         (recipe_set, CPL_FRAME_GROUP_RAW);
02145     for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
02146     {
02147         int                ext_nb;
02148         cpl_propertylist * reflist;
02149         
02150         qcstats[idet] = cpl_propertylist_new();
02151         /* Propagate some keywords from input raw frame extensions */
02152         ext_nb = 
02153             hawki_get_ext_from_detector(cpl_frame_get_filename(ref_frame), idet+1);
02154         reflist = cpl_propertylist_load_regexp
02155             (cpl_frame_get_filename(ref_frame), ext_nb,
02156              HAWKI_HEADER_EXT_FORWARD, 0) ;
02157         cpl_propertylist_append(qcstats[idet], reflist);
02158         cpl_propertylist_delete(reflist);
02159     }
02160     hawki_image_stats_stats(raw_jitter_stats, qcstats);
02161     /* Write the table with the raw jitter objects statistics */
02162     hawki_tables_save(recipe_set,
02163                       parlist,
02164                       jitter_frames,
02165                       (const cpl_table **)raw_jitter_stats,
02166                       recipe_name,
02167                       HAWKI_CALPRO_JITTER_STATS,
02168                       HAWKI_PROTYPE_JITTER_STATS,
02169                       NULL,
02170                       (const cpl_propertylist**)qcstats,
02171                       "hawki_sci_jitter_stats.fits");
02172     /* Free qcstats */
02173     for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
02174         cpl_propertylist_delete(qcstats[idet]);
02175     
02176     /* Write the FITS table with the raw telescope data */
02177     telstats = cpl_propertylist_new();
02178     cpl_propertylist_append_string(telstats, CPL_DFS_PRO_TYPE,
02179                                    HAWKI_PROTYPE_SCIENCE_PCS);
02180     cpl_propertylist_append_string(telstats, CPL_DFS_PRO_CATG,
02181                                    HAWKI_CALPRO_SCIENCE_PCS);
02182     hawki_compute_prop_tel_qc_stats(raw_obj_tel_info, telstats);
02183     if(cpl_dfs_save_table(recipe_set,
02184                           NULL,
02185                           parlist,
02186                           jitter_frames,
02187                           NULL,
02188                           raw_obj_tel_info,
02189                           NULL,
02190                           recipe_name,
02191                           telstats,
02192                           NULL,
02193                           PACKAGE "/" PACKAGE_VERSION,
02194                           "hawki_sci_jitter_pcs.fits") != CPL_ERROR_NONE)
02195         cpl_msg_error(cpl_func,"Cannot save PCS table");
02196     
02197     /* Free and return */
02198     cpl_propertylist_delete(telstats);
02199     cpl_free(qcstats);
02200     if(!cpl_errorstate_is_equal(error_prevstate))
02201     {
02202         cpl_errorstate_set(CPL_ERROR_NONE);
02203         return -1;
02204     }
02205         
02206     return 0;
02207 }