HAWKI Pipeline Reference Manual 1.8.1

hawki_sci_jitter.c

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