HAWKI Pipeline Reference Manual 1.8.12
hawki_cal_distortion.c
00001 /* $Id: hawki_cal_distortion.c,v 1.17 2013/02/01 17:18:05 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: 2013/02/01 17:18:05 $
00024  * $Revision: 1.17 $
00025  * $Name: hawki-1_8_12 $
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 
00042 #include "hawki_alloc.h"
00043 #include "hawki_utils.h"
00044 #include "hawki_calib.h"
00045 #include "hawki_distortion.h"
00046 #include "hawki_load.h"
00047 #include "hawki_save.h"
00048 #include "hawki_pfits.h"
00049 #include "hawki_dfs.h"
00050 #include "irplib_cat.h"
00051 #include "irplib_stdstar.h"
00052 #include "irplib_match_cats.h"
00053 #include "hawki_match_cats.h"
00054 
00055 /*-----------------------------------------------------------------------------
00056                             Functions prototypes
00057  -----------------------------------------------------------------------------*/
00058 
00059 #ifdef __cplusplus
00060 extern "C"
00061 #endif
00062 int cpl_plugin_get_info(cpl_pluginlist * list);
00063 
00064 static int hawki_cal_distortion_create(cpl_plugin *) ;
00065 static int hawki_cal_distortion_exec(cpl_plugin *) ;
00066 static int hawki_cal_distortion_destroy(cpl_plugin *) ;
00067 static int hawki_cal_distortion(cpl_parameterlist   *   parlist,
00068                                    cpl_frameset        *   frameset);
00069 
00070 
00071 static int  hawki_cal_distortion_get_apertures_from_raw_distor
00072 (cpl_frameset      *  raw_target,
00073  const cpl_frame   *  flat,
00074  const cpl_frame   *  dark,
00075  const cpl_frame   *  bpm,
00076  cpl_image         ** master_sky,
00077  double               sigma_det,
00078  cpl_apertures     *** apertures);
00079 
00080 static int hawki_cal_distortion_load_master_calib
00081 (const cpl_frame   *  flat,
00082  const cpl_frame   *  dark,
00083  const cpl_frame   *  bpm,
00084  cpl_imagelist     ** flat_images,
00085  cpl_imagelist     ** dark_images,
00086  cpl_imagelist     ** bpm_images);
00087 
00088 static cpl_image **  hawki_cal_distortion_get_master_sky
00089 (cpl_frameset      *  raw_target,
00090  const cpl_frame   *  flat,
00091  const cpl_frame   *  dark,
00092  const cpl_frame   *  bpm);
00093 
00094 static int hawki_cal_distortion_subtract_sky
00095 (cpl_imagelist * distor_corrected,
00096  cpl_image     * master_sky);
00097 
00098 static hawki_distortion  ** hawki_cal_distortion_compute_dist_solution
00099 (cpl_apertures    *** apertures,
00100  int                  nframes,
00101  cpl_bivector     *   offsets,
00102  int                  grid_points,
00103  int              *   nmatched_pairs,
00104  double           *   rms,
00105  hawki_distortion **  distortion_guess);
00106 
00107 static cpl_apertures * hawki_cal_distortion_get_image_apertures
00108 (cpl_image * image,
00109  double sigma_det);
00110 
00111 static int hawki_cal_distortion_fill_obj_pos
00112 (cpl_table     * objects_positions,
00113  cpl_apertures * apertures);
00114 
00115 static int hawki_cal_distortion_add_offset_to_positions
00116 (cpl_table     ** objects_positions,
00117  cpl_bivector   * offsets);
00118 
00119 static int hawki_cal_distortion_fit_first_order_solution
00120 (hawki_distortion * distortion,
00121  cpl_polynomial   * fit2d_x,
00122  cpl_polynomial   * fit2d_y);
00123 
00124 static cpl_propertylist ** hawki_cal_distortion_qc
00125 (hawki_distortion ** distortion,
00126  int              *  nmatched_pairs,
00127  double           *  rms);
00128 
00129 static int hawki_cal_distortion_save
00130 (hawki_distortion       **  distortion,
00131  cpl_parameterlist       *  parlist,
00132  cpl_propertylist       **  qclists,
00133  cpl_frameset            *  recipe_set);
00134 
00135 static int hawki_cal_distortion_retrieve_input_param
00136 (cpl_parameterlist  *  parlist);
00137 
00138 
00139 /*-----------------------------------------------------------------------------
00140                             Static variables
00141  -----------------------------------------------------------------------------*/
00142 
00143 static struct 
00144 {
00145     /* Inputs */
00146     double sigma_det;
00147     int    grid_points;
00148     int    borders;
00149     int    subtract_linear;
00150 } hawki_cal_distortion_config;
00151 
00152 static char hawki_cal_distortion_description[] = 
00153 "hawki_cal_distortion -- HAWK-I distortion and astrometry autocalibration.\n\n"
00154 "The input files must be tagged:\n"
00155 "distortion_field.fits "HAWKI_CAL_DISTOR_RAW"\n"
00156 "sky_distortion.fits "HAWKI_CAL_DISTOR_SKY_RAW"\n"
00157 "flat-file.fits "HAWKI_CALPRO_FLAT" (optional)\n"
00158 "dark-file.fits "HAWKI_CALPRO_DARK" (optional)\n"
00159 "bpm-file.fits "HAWKI_CALPRO_BPM" (optional)\n\n"
00160 "The recipe creates as an output:\n"
00161 "hawki_cal_distortion_distx.fits ("HAWKI_CALPRO_DISTORTION_X") \n"
00162 "hawki_cal_distortion_disty.fits ("HAWKI_CALPRO_DISTORTION_Y") \n\n"
00163 "The recipe performs the following steps:\n"
00164 "-Basic calibration of astrometry fields\n"
00165 "-Autocalibration of distortion, using method in A&A 454,1029 (2006)\n\n"
00166 "Return code:\n"
00167 "esorex exits with an error code of 0 if the recipe completes successfully\n"
00168 "or 1 otherwise";
00169 
00170 /*-----------------------------------------------------------------------------
00171                                 Functions code
00172  -----------------------------------------------------------------------------*/
00173 
00174 /*----------------------------------------------------------------------------*/
00182 /*----------------------------------------------------------------------------*/
00183 int cpl_plugin_get_info(cpl_pluginlist * list)
00184 {
00185     cpl_recipe *   recipe = cpl_calloc(1, sizeof(*recipe)) ;
00186     cpl_plugin *   plugin = &recipe->interface ;
00187 
00188     cpl_plugin_init(plugin,
00189                     CPL_PLUGIN_API,
00190                     HAWKI_BINARY_VERSION,
00191                     CPL_PLUGIN_TYPE_RECIPE,
00192                     "hawki_cal_distortion",
00193                     "Distortion autocalibration",
00194                     hawki_cal_distortion_description,
00195                     "Cesar Enrique Garcia Dabo",
00196                     PACKAGE_BUGREPORT,
00197                     hawki_get_license(),
00198                     hawki_cal_distortion_create,
00199                     hawki_cal_distortion_exec,
00200                     hawki_cal_distortion_destroy);
00201 
00202     cpl_pluginlist_append(list, plugin) ;
00203     
00204     return 0;
00205 }
00206 
00207 /*----------------------------------------------------------------------------*/
00216 /*----------------------------------------------------------------------------*/
00217 static int hawki_cal_distortion_create(cpl_plugin * plugin)
00218 {
00219     cpl_recipe *   recipe ;
00220     cpl_parameter   * p ;
00221 
00222     /* Get the recipe out of the plugin */
00223     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00224         recipe = (cpl_recipe *)plugin ;
00225     else return -1 ;
00226 
00227     /* Create the parameters list in the cpl_recipe object */
00228     recipe->parameters = cpl_parameterlist_new() ;
00229     if (recipe->parameters == NULL)
00230         return 1;
00231 
00232     /* Fill the parameters list */
00233     /* --sigma_det */
00234     p = cpl_parameter_new_value("hawki.hawki_cal_distortion.sigma_det", 
00235                                 CPL_TYPE_DOUBLE, "detection level",
00236                                 "hawki.hawki_cal_distortion", 6.) ;
00237     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sigma_det") ;
00238     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
00239     cpl_parameterlist_append(recipe->parameters, p) ;
00240 
00241     /* --grid_points */
00242     p = cpl_parameter_new_value("hawki.hawki_cal_distortion.grid_points", 
00243                                 CPL_TYPE_INT,
00244                                 "number of points in distortion grid",
00245                                 "hawki.hawki_cal_distortion", 9) ;
00246     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "grid_points") ;
00247     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
00248     cpl_parameterlist_append(recipe->parameters, p) ;
00249 
00250     /* --borders */
00251     p = cpl_parameter_new_value("hawki.hawki_cal_distortion.borders", 
00252                                 CPL_TYPE_INT,
00253                                 "number of pixels to trim at the borders",
00254                                 "hawki.hawki_cal_distortion", 6) ;
00255     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "borders") ;
00256     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
00257     cpl_parameterlist_append(recipe->parameters, p) ;
00258 
00259     /* --subtract_linear */
00260     p = cpl_parameter_new_value("hawki.hawki_cal_distortion.subtract_linear", 
00261                                 CPL_TYPE_BOOL,
00262                                 "Subtract a linear term to the solution",
00263                                 "hawki.hawki_cal_distortion", TRUE) ;
00264     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "subtract_linear") ;
00265     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
00266     cpl_parameterlist_append(recipe->parameters, p) ;
00267 
00268     /* Return */
00269     return 0;
00270 }
00271 
00272 /*----------------------------------------------------------------------------*/
00278 /*----------------------------------------------------------------------------*/
00279 static int hawki_cal_distortion_exec(cpl_plugin * plugin)
00280 {
00281     cpl_recipe  *   recipe ;
00282 
00283     /* Get the recipe out of the plugin */
00284     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00285         recipe = (cpl_recipe *)plugin ;
00286     else return -1 ;
00287 
00288     /* Issue a banner */
00289     hawki_print_banner();
00290 
00291     return hawki_cal_distortion(recipe->parameters, recipe->frames) ;
00292 }
00293 
00294 /*----------------------------------------------------------------------------*/
00300 /*----------------------------------------------------------------------------*/
00301 static int hawki_cal_distortion_destroy(cpl_plugin * plugin)
00302 {
00303     cpl_recipe  *   recipe ;
00304 
00305     /* Get the recipe out of the plugin */
00306     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00307         recipe = (cpl_recipe *)plugin ;
00308     else return -1 ;
00309 
00310     cpl_parameterlist_delete(recipe->parameters) ;
00311     return 0 ;
00312 }
00313 
00314 /*----------------------------------------------------------------------------*/
00320 /*----------------------------------------------------------------------------*/
00321 static int hawki_cal_distortion(cpl_parameterlist *   parlist,
00322                                 cpl_frameset *        frameset)
00323 {
00324     const cpl_frame  *  flat = NULL;
00325     const cpl_frame  *  dark = NULL;
00326     const cpl_frame  *  bpm = NULL;
00327     cpl_frameset     *  distorframes = NULL;
00328     cpl_frameset     *  skyframes = NULL;
00329     const cpl_frame  *  distorxguess = NULL;
00330     const cpl_frame  *  distoryguess = NULL;
00331     hawki_distortion ** distortionguess = NULL;
00332     hawki_distortion ** distortion = NULL;
00333     cpl_propertylist ** qclists = NULL;
00334     cpl_image        ** master_sky = NULL;
00335     cpl_bivector     *  nominal_offsets = NULL;
00336     cpl_apertures    ** apertures[HAWKI_NB_DETECTORS];
00337     int                 nmatched_pairs[HAWKI_NB_DETECTORS];
00338     double              rms[HAWKI_NB_DETECTORS];
00339     int                 idet;
00340     int                 ioff;
00341     int                 iframe;
00342     int                 nframes;
00343 
00344 
00345     /* Retrieve input parameters */
00346     if(hawki_cal_distortion_retrieve_input_param(parlist))
00347     {
00348         cpl_msg_error(__func__, "Wrong parameters");
00349         return -1;
00350     }
00351 
00352     /* Identify the RAW and CALIB frames in the input frameset */
00353     if (hawki_dfs_set_groups(frameset)) {
00354         cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
00355         return -1 ;
00356     }
00357 
00358     /* Retrieve calibration data */
00359     cpl_msg_info(__func__, "Identifying calibration data");
00360     flat   = cpl_frameset_find_const(frameset, HAWKI_CALPRO_FLAT);
00361     dark   = cpl_frameset_find_const(frameset, HAWKI_CALPRO_DARK);
00362     bpm    = cpl_frameset_find_const(frameset, HAWKI_CALPRO_BPM);
00363 
00364     /* Retrieve raw frames */
00365     cpl_msg_info(__func__, "Identifying distortion and sky data");
00366     distorframes = hawki_extract_frameset(frameset, HAWKI_CAL_DISTOR_RAW) ;
00367     if (distorframes == NULL)
00368     {
00369         cpl_msg_error(__func__, "Distortion images have to be provided (%s)",
00370                       HAWKI_CAL_DISTOR_RAW);
00371         return -1 ;
00372     }
00373     /* Retrieve sky frames */
00374     skyframes = hawki_extract_frameset(frameset, HAWKI_CAL_DISTOR_SKY_RAW) ;
00375     if (skyframes == NULL)
00376     {
00377         cpl_msg_error(__func__, "Sky images have to be provided (%s)",
00378                       HAWKI_CAL_DISTOR_SKY_RAW);
00379         cpl_frameset_delete(distorframes);
00380         return -1 ;
00381     }
00382     /* Retrieve the distortion first guess (if provided) */
00383     distorxguess = cpl_frameset_find_const(frameset, HAWKI_CALPRO_DISTORTION_X);
00384     distoryguess = cpl_frameset_find_const(frameset, HAWKI_CALPRO_DISTORTION_Y);
00385     if(distorxguess != NULL && distoryguess != NULL)
00386     {
00387         //distortionguess = hawki_distortion_load(distorxtguess)
00388     }
00389     
00390     /* Get the master sky frame */
00391     cpl_msg_info(__func__, "Computing the master sky image");
00392     master_sky = hawki_cal_distortion_get_master_sky(skyframes, flat, dark, bpm);
00393     if(master_sky == NULL)
00394     {
00395         cpl_msg_error(__func__, "Cannot get master sky image") ;
00396         cpl_frameset_delete(distorframes);
00397         cpl_frameset_delete(skyframes);
00398         return -1;        
00399     }
00400     
00401     /* Aperture detection, basic reduction and sky subtraction of distortion images */
00402     cpl_msg_info(__func__, "Getting objects from distortion images");
00403     if(hawki_cal_distortion_get_apertures_from_raw_distor
00404        (distorframes, flat, dark, bpm, master_sky,
00405         hawki_cal_distortion_config.sigma_det, apertures) == -1)
00406     {
00407         cpl_msg_error(__func__, 
00408                 "Cannot get objects from distortion images");
00409         for(idet = 0; idet < HAWKI_NB_DETECTORS ; ++idet)
00410             cpl_image_delete(master_sky[idet]);
00411         cpl_free(master_sky);
00412         cpl_frameset_delete(distorframes);
00413         cpl_frameset_delete(skyframes);
00414         return -1 ;        
00415     }
00416     for(idet = 0; idet < HAWKI_NB_DETECTORS ; ++idet)
00417         cpl_image_delete(master_sky[idet]);
00418     cpl_free(master_sky);
00419 
00420     /* Get the nominal offsets from the header */
00421     cpl_msg_info(__func__,"Getting the nominal offsets");
00422     nominal_offsets = hawki_get_header_tel_offsets(distorframes); 
00423     if (nominal_offsets  == NULL) 
00424     {
00425         cpl_msg_error(__func__, "Cannot load the header offsets") ;
00426         cpl_frameset_delete(distorframes);
00427         cpl_frameset_delete(skyframes);
00428         return -1;
00429     }
00430     
00431     /* Get the oposite offsets. This is to change from 
00432      * telescope convention to cpl convention */
00433     cpl_vector_multiply_scalar(cpl_bivector_get_x(nominal_offsets), -1.0);
00434     cpl_vector_multiply_scalar(cpl_bivector_get_y(nominal_offsets), -1.0);
00435     
00436     /* Print the header offsets */
00437     cpl_msg_indent_more();
00438     for (ioff=0 ; ioff<cpl_bivector_get_size(nominal_offsets) ; ioff++) 
00439     {
00440         cpl_msg_info(__func__, "Telescope offsets (Frame %d): %g %g", ioff+1,
00441                 cpl_bivector_get_x_data(nominal_offsets)[ioff],
00442                 cpl_bivector_get_y_data(nominal_offsets)[ioff]);
00443     }
00444     cpl_msg_indent_less();
00445 
00446     /* Get the distortion solution, the real stuff */
00447     cpl_msg_info(__func__, "Computing the distortion");
00448     nframes = cpl_frameset_get_size(distorframes);
00449     distortion = hawki_cal_distortion_compute_dist_solution
00450         (apertures, nframes, nominal_offsets,
00451          hawki_cal_distortion_config.grid_points,
00452          nmatched_pairs, rms,
00453          distortionguess);
00454     cpl_bivector_delete(nominal_offsets);
00455     if(distortion  == NULL)
00456     {
00457         cpl_frameset_delete(distorframes);
00458         cpl_frameset_delete(skyframes);
00459         return -1;        
00460     }
00461     
00462     /* Get some QC */
00463     qclists =  hawki_cal_distortion_qc(distortion, nmatched_pairs, rms);
00464     
00465     /* Save the products */
00466     cpl_msg_info(__func__,"Saving products");
00467     if(hawki_cal_distortion_save(distortion,
00468                                  parlist, qclists, frameset) == -1)
00469     {
00470         cpl_msg_error(__func__,"Could not save products");
00471         for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++) 
00472             cpl_propertylist_delete(qclists[idet]);
00473         cpl_free(qclists);
00474         for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
00475             hawki_distortion_delete(distortion[idet]);
00476         cpl_free(distortion);
00477         cpl_frameset_delete(distorframes);
00478         cpl_frameset_delete(skyframes);
00479         return -1;
00480     }
00481     
00482     /* Free and return */
00483     for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
00484         cpl_propertylist_delete(qclists[idet]);
00485     cpl_free(qclists);
00486     for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
00487         hawki_distortion_delete(distortion[idet]);
00488     cpl_free(distortion);
00489     for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
00490     {
00491         for(iframe = 0 ; iframe < nframes; iframe++)
00492             cpl_apertures_delete(apertures[idet][iframe]);
00493         cpl_free(apertures[idet]);
00494     }
00495     cpl_frameset_delete(distorframes);
00496     cpl_frameset_delete(skyframes);
00497 
00498 
00499     /* Return */
00500     if (cpl_error_get_code())
00501     {
00502         cpl_msg_error(__func__,
00503                       "HAWK-I pipeline could not recover from previous errors");
00504         return -1 ;
00505     }
00506     else return 0 ;
00507 }
00508 
00509 /*----------------------------------------------------------------------------*/
00520 /*----------------------------------------------------------------------------*/
00521 static int hawki_cal_distortion_load_master_calib
00522 (const cpl_frame   *  flat,
00523  const cpl_frame   *  dark,
00524  const cpl_frame   *  bpm,
00525  cpl_imagelist     ** flat_images,
00526  cpl_imagelist     ** dark_images,
00527  cpl_imagelist     ** bpm_images)
00528 {
00529     cpl_errorstate          error_prevstate = cpl_errorstate_get();
00530     
00531     /* Initializing the pointers */
00532     *flat_images = NULL;
00533     *dark_images = NULL;
00534     *bpm_images  = NULL;
00535     
00536     /* Loading the calibration files */
00537     cpl_msg_info(__func__, "Loading the calibration data") ;
00538     if(flat != NULL)
00539     {
00540         *flat_images = hawki_load_frame(flat, CPL_TYPE_FLOAT);
00541         if(*flat_images == NULL)
00542         {
00543             cpl_msg_error(__func__, "Error reading flat") ;
00544             return -1;
00545         }
00546     }
00547     if(dark != NULL)
00548     {
00549         *dark_images = hawki_load_frame(dark, CPL_TYPE_FLOAT);
00550         if(*dark_images == NULL)
00551         {
00552             cpl_msg_error(__func__, "Error reading dark") ;
00553             cpl_imagelist_delete(*flat_images);
00554             return -1;
00555         }
00556     }
00557     if(bpm != NULL)
00558     {
00559         *bpm_images = hawki_load_frame(bpm, CPL_TYPE_INT);
00560         if(*bpm_images == NULL)
00561         {
00562             cpl_msg_error(__func__, "Error reading bpm") ;
00563             cpl_imagelist_delete(*flat_images);
00564             cpl_imagelist_delete(*dark_images);
00565             return -1;
00566         }
00567     }
00568     
00569     if(!cpl_errorstate_is_equal(error_prevstate ))
00570     {
00571         cpl_msg_error(__func__, "A problem happened loading calibration");
00572         cpl_imagelist_delete(*flat_images);
00573         cpl_imagelist_delete(*dark_images);
00574         cpl_imagelist_delete(*bpm_images);
00575         return -1;
00576     }
00577     return 0;
00578 }
00579 
00580 /*----------------------------------------------------------------------------*/
00590 /*----------------------------------------------------------------------------*/
00591 static int hawki_cal_distortion_get_apertures_from_raw_distor
00592 (cpl_frameset      *   raw_distor,
00593  const cpl_frame   *   flat,
00594  const cpl_frame   *   dark,
00595  const cpl_frame   *   bpm,
00596  cpl_image         **  master_sky,
00597  double                sigma_det,
00598  cpl_apertures     *** apertures)
00599 {
00600     cpl_imagelist    *  flat_images;
00601     cpl_imagelist    *  dark_images;
00602     cpl_imagelist    *  bpm_images;
00603     cpl_propertylist *  plist;
00604     
00605     double              science_dit;
00606     int                 iframe;
00607     int                 nframes;
00608     int                 idet;
00609 
00610     cpl_errorstate          error_prevstate = cpl_errorstate_get();
00611     
00612     /* Indentation */
00613     cpl_msg_indent_more();
00614     
00615     /* Loading calibrations */
00616     hawki_cal_distortion_load_master_calib
00617         (flat, dark, bpm, &flat_images, &dark_images, &bpm_images);
00618     
00619     /* Multiply the dark image by the science exposure time */
00620     if(dark != NULL)
00621     {
00622         if ((plist=cpl_propertylist_load
00623                 (cpl_frame_get_filename
00624                  (cpl_frameset_get_first_const(raw_distor)), 0)) == NULL) 
00625         {
00626             cpl_msg_error(__func__, "Cannot get header from frame");
00627             cpl_imagelist_delete(flat_images);
00628             cpl_imagelist_delete(dark_images);
00629             return -1;
00630         }
00631         science_dit = hawki_pfits_get_dit(plist);
00632         cpl_imagelist_multiply_scalar(dark_images, science_dit);
00633         cpl_propertylist_delete(plist);
00634     }
00635 
00636     /* Loop on detectors */
00637     nframes = cpl_frameset_get_size(raw_distor);
00638     for(idet = 0; idet < HAWKI_NB_DETECTORS ; ++idet)
00639     {
00640         cpl_imagelist * distor_serie;
00641         cpl_imagelist * distor_serie_trimmed;
00642         cpl_image     * flat_det = NULL;
00643         cpl_image     * dark_det = NULL;
00644         cpl_image     * bpm_det  = NULL;
00645         
00646         cpl_msg_info(__func__, "Working on detector %d", idet + 1);
00647         cpl_msg_indent_more();
00648 
00649         /* Loading the distortion images for one detector */
00650         cpl_msg_info(__func__, "Loading distortion images");
00651         distor_serie = hawki_load_detector(raw_distor, idet + 1, CPL_TYPE_FLOAT);
00652         if(distor_serie== NULL)
00653         {
00654             cpl_msg_error(__func__, "Error reading distortion images");
00655             return -1;
00656         } 
00657 
00658         /* Getting the calibs */
00659         if(flat_images != NULL)
00660             flat_det = cpl_imagelist_get(flat_images, idet);
00661         if(dark_images != NULL)
00662             dark_det = cpl_imagelist_get(dark_images, idet);
00663         if(bpm_images != NULL)
00664             bpm_det = cpl_imagelist_get(bpm_images, idet);
00665         
00666         if(!cpl_errorstate_is_equal(error_prevstate ))
00667             cpl_msg_warning(cpl_func,"PPPPPP5");
00668         
00669         /* Applying the calibrations */
00670         cpl_msg_info(__func__, "Applying basic calibration") ;
00671         cpl_msg_indent_more();
00672         if (hawki_flat_dark_bpm_detector_calib
00673                 (distor_serie, flat_det, dark_det, bpm_det) == -1)
00674         {
00675             cpl_msg_error(__func__, "Cannot calibrate frame") ;
00676             cpl_imagelist_delete(flat_images);
00677             cpl_imagelist_delete(dark_images);
00678             cpl_imagelist_delete(bpm_images);
00679             cpl_imagelist_delete(distor_serie);
00680             cpl_msg_indent_less() ;
00681             return -1;
00682         }
00683         cpl_msg_indent_less();
00684         
00685         /* Discard the pixels on the sides */
00686         if (hawki_cal_distortion_config.borders > 0) 
00687         {
00688           distor_serie_trimmed = hawki_trim_detector_calib(distor_serie,
00689                                  hawki_cal_distortion_config.borders);
00690           cpl_imagelist_delete(distor_serie);
00691         }
00692         else
00693           distor_serie_trimmed = distor_serie;
00694 
00695         /* Subtract sky */
00696         cpl_msg_info(__func__, "Subtracting master sky") ;
00697         if(hawki_cal_distortion_subtract_sky(distor_serie_trimmed, master_sky[idet]) == -1)
00698         {
00699             cpl_msg_error(__func__, "Cannot subtract the sky") ;
00700             cpl_imagelist_delete(flat_images);
00701             cpl_imagelist_delete(dark_images);
00702             cpl_imagelist_delete(bpm_images);
00703             cpl_imagelist_delete(distor_serie_trimmed);
00704             return -1;        
00705         }
00706 
00707         /* Creating apertures */
00708         apertures[idet] = cpl_malloc(sizeof(*(apertures[idet])) * nframes);
00709         for(iframe = 0 ; iframe < nframes; iframe++)
00710         {
00711             cpl_image * this_image = cpl_imagelist_get(distor_serie_trimmed, iframe);
00712             cpl_msg_info(__func__,"Working with distortion image %d", iframe+1);
00713             cpl_msg_indent_more();
00714             apertures[idet][iframe] = 
00715                     hawki_cal_distortion_get_image_apertures(this_image, sigma_det);
00716             cpl_msg_indent_less();
00717         }
00718         
00719         /* Delete the list of images */
00720         cpl_imagelist_delete(distor_serie_trimmed);
00721         cpl_msg_indent_less();
00722     }
00723     cpl_imagelist_delete(flat_images);
00724     cpl_imagelist_delete(dark_images);
00725     cpl_imagelist_delete(bpm_images);
00726     
00727     
00728     if(!cpl_errorstate_is_equal(error_prevstate ))
00729     {
00730         cpl_msg_error(__func__, "A problem happened detecting objects");
00731         return -1 ;
00732     }
00733     return 0;
00734 }
00735 
00736 static cpl_image **  hawki_cal_distortion_get_master_sky
00737 (cpl_frameset      *  raw_sky_frames,
00738  const cpl_frame   *  flat,
00739  const cpl_frame   *  dark,
00740  const cpl_frame   *  bpm)
00741 {
00742     cpl_propertylist *  plist;
00743     double              science_dit;
00744     int                 idet;
00745     int                 jdet;
00746     cpl_imagelist    *  flat_images;
00747     cpl_imagelist    *  dark_images;
00748     cpl_imagelist    *  bpm_images;
00749     cpl_image        ** bkg_images = NULL;
00750 
00751     cpl_errorstate          error_prevstate = cpl_errorstate_get();
00752 
00753     /* Indentation */
00754     cpl_msg_indent_more();
00755     
00756     /* Reading calibrations */
00757     hawki_cal_distortion_load_master_calib
00758         (flat, dark, bpm, &flat_images, &dark_images, &bpm_images);
00759     
00760     /* Multiply the dark image by the science exposure time */
00761     if(dark != NULL)
00762     {
00763         if ((plist=cpl_propertylist_load
00764                 (cpl_frame_get_filename
00765                  (cpl_frameset_get_first_const(raw_sky_frames)), 0)) == NULL) 
00766         {
00767             cpl_msg_error(__func__, "Cannot get header from frame");
00768             cpl_imagelist_delete(flat_images);
00769             cpl_imagelist_delete(dark_images);
00770             cpl_imagelist_delete(bpm_images);
00771             return NULL;
00772         }
00773         science_dit = hawki_pfits_get_dit(plist);
00774         cpl_imagelist_multiply_scalar(dark_images, science_dit);
00775         cpl_propertylist_delete(plist);
00776     }
00777 
00778     /* Compute the sky median */
00779     bkg_images = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(*bkg_images));
00780     for(idet = 0; idet < HAWKI_NB_DETECTORS ; ++idet)
00781     {
00782         cpl_imagelist * sky_serie;
00783         cpl_imagelist * sky_serie_trimmed;
00784         cpl_image     * flat_det = NULL;
00785         cpl_image     * dark_det = NULL;
00786         cpl_image     * bpm_det  = NULL;
00787         
00788         /* Loading the sky images for one detector */
00789         sky_serie = hawki_load_detector(raw_sky_frames, idet + 1, CPL_TYPE_FLOAT);
00790         if(sky_serie== NULL)
00791         {
00792             cpl_msg_error(__func__, "Error reading object image") ;
00793             return NULL;
00794         }
00795 
00796         /* Getting the calibs */
00797         if(flat_images != NULL)
00798             flat_det = cpl_imagelist_get(flat_images, idet);
00799         if(dark_images != NULL)
00800             dark_det = cpl_imagelist_get(dark_images, idet);
00801         if(bpm_images != NULL)
00802             bpm_det = cpl_imagelist_get(bpm_images, idet);
00803         
00804         /* Applying the calibrations */
00805         cpl_msg_info(__func__, "Working on detector %d", idet + 1);
00806         cpl_msg_indent_more();
00807         if (hawki_flat_dark_bpm_detector_calib
00808                 (sky_serie, flat_det, dark_det, bpm_det) == -1)
00809         {
00810             cpl_msg_error(__func__, "Cannot calibrate frame") ;
00811             cpl_imagelist_delete(flat_images);
00812             cpl_imagelist_delete(dark_images);
00813             cpl_imagelist_delete(bpm_images);
00814             cpl_imagelist_delete(sky_serie);
00815             for(jdet = 0; jdet < idet; ++jdet)
00816                 cpl_image_delete(bkg_images[jdet]);
00817             cpl_free(bkg_images);
00818             cpl_msg_indent_less() ;
00819             return NULL;
00820         }
00821         
00822         /* Discard the pixels on the sides */
00823         if (hawki_cal_distortion_config.borders > 0) 
00824         {
00825           sky_serie_trimmed = hawki_trim_detector_calib(sky_serie,
00826                           hawki_cal_distortion_config.borders);
00827           cpl_imagelist_delete(sky_serie);
00828         }
00829         else
00830           sky_serie_trimmed = sky_serie;
00831 
00832         /* Averaging */
00833         if ((bkg_images[idet] =
00834                 cpl_imagelist_collapse_median_create(sky_serie_trimmed))  == NULL) 
00835         {
00836             cpl_msg_error(__func__, "Cannot compute the median of obj images");
00837             cpl_imagelist_delete(flat_images);
00838             cpl_imagelist_delete(dark_images);
00839             cpl_imagelist_delete(bpm_images);
00840             cpl_imagelist_delete(sky_serie_trimmed);
00841             for(jdet = 0; jdet < idet; ++jdet)
00842                 cpl_image_delete(bkg_images[jdet]);
00843             cpl_free(bkg_images);
00844             cpl_msg_indent_less();
00845             return NULL;
00846         }
00847         cpl_imagelist_delete(sky_serie_trimmed);
00848         cpl_msg_indent_less();
00849     }
00850     
00851     /* Subtract the median of the frame */
00852     for(idet = 0; idet < HAWKI_NB_DETECTORS ; ++idet)
00853         cpl_image_subtract_scalar(bkg_images[idet],
00854                                   cpl_image_get_median(bkg_images[idet]));
00855     
00856     /* Cleaning up */
00857     cpl_msg_indent_less();
00858     cpl_imagelist_delete(flat_images);
00859     cpl_imagelist_delete(dark_images);
00860     cpl_imagelist_delete(bpm_images);
00861 
00862     if(!cpl_errorstate_is_equal(error_prevstate ))
00863     {
00864         cpl_msg_error(__func__, "A problem happened with basic calibration");
00865         for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
00866             cpl_image_delete(bkg_images[idet]);
00867         cpl_free(bkg_images);
00868         return NULL ;
00869     }
00870    return bkg_images;
00871 }
00872 
00873 static int hawki_cal_distortion_subtract_sky
00874 (cpl_imagelist * distor_corrected,
00875  cpl_image     * master_sky)
00876 {
00877     cpl_errorstate          error_prevstate = cpl_errorstate_get();
00878 
00879     /* Subtract the background to each object frame */
00880     int idist, ndistor;
00881     ndistor = cpl_imagelist_get_size(distor_corrected);
00882     for(idist = 0; idist < ndistor; ++idist)
00883     {
00884         cpl_image * target_image =
00885             cpl_imagelist_get(distor_corrected, idist);
00886         /* First subtract the median of the image */
00887         cpl_image_subtract_scalar
00888             (target_image, cpl_image_get_median(target_image));
00889 
00890         if (cpl_image_subtract
00891                 (target_image, master_sky)!=CPL_ERROR_NONE) 
00892         {
00893             cpl_msg_error(cpl_func,"Cannot apply the bkg to the images");
00894             return -1 ;
00895         }
00896     }
00897     
00898     /* Free and return */
00899     if(!cpl_errorstate_is_equal(error_prevstate ))
00900     {
00901         cpl_msg_error(__func__, "A problem happened with sky subtraction");
00902         return -1;
00903     }
00904    return 0;
00905 }
00906 
00907 
00908 /*----------------------------------------------------------------------------*/
00918 /*----------------------------------------------------------------------------*/
00919 static hawki_distortion  ** hawki_cal_distortion_compute_dist_solution
00920 (cpl_apertures    *** apertures,
00921  int                  nframes,
00922  cpl_bivector     *   offsets,   
00923  int                  grid_points,
00924  int              *   nmatched_pairs,
00925  double           *   rms,
00926  hawki_distortion **  distortion_guess)
00927 {
00928     int                 idet;
00929     hawki_distortion ** distortion = NULL;
00930 
00931     cpl_errorstate          error_prevstate = cpl_errorstate_get();
00932 
00933     /* Allocate the distortion */
00934     distortion = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(*distortion));
00935     
00936     /* Loop on the detectors */
00937     cpl_msg_indent_more();
00938     for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
00939     {
00940         cpl_table       ** obj_pos;
00941         cpl_table       ** obj_pos_offset;
00942         int                iframe;
00943         cpl_table        * matches;
00944         hawki_distortion * dist_guess;
00945         cpl_polynomial   * fit2d_x = NULL;
00946         cpl_polynomial   * fit2d_y = NULL;
00947 
00948         
00949         cpl_msg_info(__func__, "Working on detector %d", idet+1);
00950         cpl_msg_indent_more();
00951 
00952         /* Initialize the objects positions */
00953         obj_pos = 
00954             cpl_malloc(sizeof(*obj_pos) * nframes);
00955         obj_pos_offset = 
00956             cpl_malloc(sizeof(*obj_pos_offset) * nframes);
00957         for(iframe = 0; iframe < nframes; ++iframe)
00958         {
00959             obj_pos[iframe] = cpl_table_new(0);
00960             cpl_table_new_column
00961                 (obj_pos[iframe], HAWKI_COL_OBJ_POSX, CPL_TYPE_DOUBLE);
00962             cpl_table_new_column
00963                 (obj_pos[iframe], HAWKI_COL_OBJ_POSY, CPL_TYPE_DOUBLE);
00964         }
00965         
00966         /* Loop on images to fill object_positions */
00967         for(iframe = 0 ; iframe < nframes ; ++iframe)
00968         {
00969             cpl_apertures   * this_apertures;
00970 
00971             /* Create the detected apertures list */
00972             this_apertures = apertures[idet][iframe];
00973             
00974             /* Fill the objects position table */
00975             hawki_cal_distortion_fill_obj_pos(obj_pos[iframe],
00976                                               this_apertures);
00977             obj_pos_offset[iframe] = cpl_table_duplicate(obj_pos[iframe]);
00978         }
00979         
00980         /* Get the objects positions with offsets */
00981         hawki_cal_distortion_add_offset_to_positions
00982             (obj_pos_offset, offsets);
00983         
00984         /* Get the all the matching pairs */
00985         cpl_msg_info(__func__, "Matching all catalogs (may take a while)");
00986         matches =  irplib_match_cat_pairs(obj_pos_offset, nframes, 
00987                                           hawki_match_condition_5_pix);
00988         for(iframe = 0; iframe < nframes; ++iframe)
00989             cpl_table_delete(obj_pos_offset[iframe]);
00990         cpl_free(obj_pos_offset);
00991         if(matches == NULL)
00992         {
00993             cpl_msg_error(__func__, "Cannot match objects ");
00994             for(iframe = 0; iframe < nframes; ++iframe)
00995                 cpl_table_delete(obj_pos[iframe]);
00996             cpl_free(obj_pos);
00997             return NULL;
00998         }
00999         cpl_msg_info(__func__,"Number of matching pairs %"CPL_SIZE_FORMAT,
01000                      cpl_table_get_nrow(matches));
01001         nmatched_pairs[idet] = cpl_table_get_nrow(matches);
01002 
01003         /* Compute the distortion */
01004         cpl_msg_info(__func__, "Computing distortion with the matched objects");
01005         cpl_msg_info(__func__, "  (This step will take a long time to run)");
01006         if(distortion_guess != NULL)
01007             dist_guess = distortion_guess[idet];
01008         else
01009             dist_guess = NULL;
01010         distortion[idet] = hawki_distortion_compute_solution
01011              ((const cpl_table **)obj_pos, offsets, matches,
01012               nframes, HAWKI_DET_NPIX_X , HAWKI_DET_NPIX_Y, grid_points,
01013               dist_guess, rms + idet);
01014         if(distortion[idet] == NULL)
01015         {
01016             int jdet;
01017             cpl_msg_error(__func__,"Could not get the distortion");
01018             for(iframe = 0; iframe < nframes; ++iframe)
01019                 cpl_table_delete(obj_pos[iframe]);
01020             cpl_free(obj_pos);
01021             for(jdet = 0; jdet < idet; ++jdet)
01022                 hawki_distortion_delete(distortion[idet]);
01023             cpl_table_delete(matches);
01024             return NULL;
01025         }
01026 
01027         /* Removing the first order polinomial to the distortion */
01028         if(hawki_cal_distortion_config.subtract_linear)
01029         {
01030             cpl_msg_info(__func__,"Subtracting first order polynomial");
01031             fit2d_x = cpl_polynomial_new(2);
01032             fit2d_y = cpl_polynomial_new(2);
01033             hawki_cal_distortion_fit_first_order_solution
01034                 (distortion[idet], fit2d_x, fit2d_y);
01035         }
01036         
01037         /* Free */
01038         for(iframe = 0; iframe < nframes; ++iframe)
01039             cpl_table_delete(obj_pos[iframe]);
01040         cpl_free(obj_pos);
01041         if(hawki_cal_distortion_config.subtract_linear)
01042         {
01043             cpl_polynomial_delete(fit2d_x);
01044             cpl_polynomial_delete(fit2d_y);
01045         }
01046         cpl_table_delete(matches);
01047         cpl_msg_indent_less();
01048     }
01049 
01050     if(!cpl_errorstate_is_equal(error_prevstate ))
01051     {
01052         cpl_msg_error(__func__, "A problem happened computing the distortion");
01053         for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
01054             hawki_distortion_delete(distortion[idet]);
01055         return NULL ;
01056     }
01057     /* Free and return */
01058     return distortion;
01059 }
01060 
01061 static cpl_apertures * hawki_cal_distortion_get_image_apertures
01062 (cpl_image * image,
01063  double sigma_det)
01064 {
01065     cpl_apertures   * apertures = NULL;
01066     cpl_mask        * kernel = NULL;
01067     cpl_mask        * object_mask = NULL;
01068     cpl_image       * labels = NULL;
01069     cpl_size          nobj;
01070     double            median;
01071     double            med_dist;
01072     double            threshold;
01073     
01074     /* Get the threshold */
01075     median = cpl_image_get_median_dev(image, &med_dist);
01076     threshold = median + sigma_det * med_dist;
01077     cpl_msg_info(__func__,"Detection threshold: %f", threshold);
01078 
01079     /* Create the mask */
01080     object_mask = cpl_mask_threshold_image_create
01081             (image, threshold, DBL_MAX);
01082     if (object_mask == NULL)
01083         return NULL;
01084 
01085     /* Apply morphological opening to remove single pixel detections */
01086     kernel = cpl_mask_new(3,3);
01087     cpl_mask_not(kernel);
01088 
01089     if (cpl_mask_filter(object_mask, object_mask, kernel, 
01090             CPL_FILTER_OPENING, CPL_BORDER_ZERO) != CPL_ERROR_NONE) {
01091         cpl_mask_delete(object_mask) ;
01092         cpl_mask_delete(kernel) ;
01093         return NULL;
01094     }
01095     cpl_mask_delete(kernel);
01096 
01097     /* Labelise the different detected apertures */
01098     labels = cpl_image_labelise_mask_create(object_mask, &nobj);
01099     if (labels == NULL)
01100     {
01101         cpl_mask_delete(object_mask);
01102         return NULL;
01103     }
01104     cpl_mask_delete(object_mask);
01105     cpl_msg_info(__func__, "Number of objects detected: %"CPL_SIZE_FORMAT,
01106                  nobj);
01107 
01108     /* Create the detected apertures list */
01109     apertures = cpl_apertures_new_from_image(image, labels);
01110     if (apertures == NULL)
01111     {
01112         cpl_image_delete(labels);
01113         return NULL;
01114     }
01115     cpl_image_delete(labels);
01116     return apertures;
01117 }
01118 
01119 static int hawki_cal_distortion_fill_obj_pos
01120 (cpl_table     * objects_positions,
01121  cpl_apertures * apertures)
01122 {
01123     cpl_size nobjs;
01124     cpl_size iobj;
01125     double border_off = 0;
01126 
01127     /* Take into account that the images have been trimmed */
01128     if(hawki_cal_distortion_config.borders > 0)
01129         border_off = hawki_cal_distortion_config.borders;
01130     
01131     nobjs = cpl_apertures_get_size(apertures); 
01132     cpl_table_set_size(objects_positions, nobjs);
01133     
01134     for (iobj=0 ; iobj<nobjs ; iobj++)
01135     {
01136         /* Fill with the already known information */
01137         cpl_table_set_double(objects_positions, HAWKI_COL_OBJ_POSX, iobj, 
01138                              cpl_apertures_get_centroid_x(apertures,
01139                                                           iobj+1) + border_off);
01140         cpl_table_set_double(objects_positions, HAWKI_COL_OBJ_POSY, iobj, 
01141                              cpl_apertures_get_centroid_y(apertures,
01142                                                           iobj+1) + border_off);
01143     }
01144     
01145     return 0;
01146 }
01147 
01148 static int hawki_cal_distortion_add_offset_to_positions
01149 (cpl_table     ** objects_positions,
01150  cpl_bivector   * offsets)
01151 {
01152     int nframes;
01153     int iframe;
01154     cpl_size nobjs;
01155     cpl_size iobj;
01156     
01157     nframes = cpl_bivector_get_size(offsets); 
01158 
01159     for(iframe = 0 ; iframe < nframes ; ++iframe)
01160     {
01161         double offset_x;
01162         double offset_y;
01163         int    null;
01164         offset_x = cpl_bivector_get_x_data(offsets)[iframe];
01165         offset_y = cpl_bivector_get_y_data(offsets)[iframe];
01166         nobjs = cpl_table_get_nrow(objects_positions[iframe]);
01167         for (iobj=0 ; iobj<nobjs ; iobj++)
01168         {
01169             cpl_table_set_double(objects_positions[iframe], 
01170                      HAWKI_COL_OBJ_POSX, iobj, 
01171                      cpl_table_get_double(objects_positions[iframe], 
01172                              HAWKI_COL_OBJ_POSX, iobj, &null) + offset_x);
01173             cpl_table_set_double(objects_positions[iframe], 
01174                      HAWKI_COL_OBJ_POSY, iobj, 
01175                      cpl_table_get_double(objects_positions[iframe], 
01176                              HAWKI_COL_OBJ_POSY, iobj, &null) + offset_y);
01177         }
01178     }
01179           
01180     return 0;
01181 }
01182 
01183 static int hawki_cal_distortion_fit_first_order_solution
01184 (hawki_distortion * distortion,
01185  cpl_polynomial   * fit2d_x,
01186  cpl_polynomial   * fit2d_y)
01187 {
01188     cpl_matrix      * pixel_pos;
01189     cpl_vector      * dist_x_val;
01190     cpl_vector      * dist_y_val;
01191     int               nx;
01192     int               ny;
01193     int               i;
01194     int               j;
01195     int               null;
01196     const cpl_size    mindeg2d[] = {0, 0};
01197     const cpl_size    maxdeg2d[] = {1, 1};
01198     cpl_errorstate    error_prevstate = cpl_errorstate_get();
01199     cpl_vector      * pix;
01200     cpl_image       * dist_x_plane;
01201     cpl_image       * dist_y_plane;
01202     double            dist_x_mean;
01203     double            dist_y_mean;
01204    
01205     /* Fill the bivector with pixel positions in X,Y */
01206     nx = hawki_distortion_get_size_x(distortion);
01207     ny = hawki_distortion_get_size_y(distortion);
01208     pixel_pos = cpl_matrix_new(2, nx * ny);
01209     dist_x_val = cpl_vector_new(nx*ny);
01210     dist_y_val = cpl_vector_new(nx*ny);
01211     for(i = 0; i < nx; ++i)
01212         for(j = 0; j < ny; ++j)
01213         {
01214             cpl_matrix_set(pixel_pos, 0, i + nx * j, (double)i);
01215             cpl_matrix_set(pixel_pos, 1, i + nx * j, (double)j);
01216             cpl_vector_set(dist_x_val, i + nx * j,
01217                            cpl_image_get(distortion->dist_x, i+1, j+1, &null));
01218             cpl_vector_set(dist_y_val, i + nx * j,
01219                            cpl_image_get(distortion->dist_y, i+1, j+1, &null));
01220         }
01221 
01222     /* Fit the polynomial */
01223     cpl_polynomial_fit(fit2d_x, pixel_pos, NULL, dist_x_val, 
01224                        NULL, CPL_FALSE, mindeg2d, maxdeg2d);
01225     cpl_polynomial_fit(fit2d_y, pixel_pos, NULL, dist_y_val,
01226                        NULL, CPL_FALSE, mindeg2d, maxdeg2d);
01227     /* Removing the constant term */
01228     cpl_polynomial_set_coeff(fit2d_x, mindeg2d, 0.);
01229     cpl_polynomial_set_coeff(fit2d_y, mindeg2d, 0.);
01230     
01231     /* Subtract the linear term */
01232     pix = cpl_vector_new(2);
01233     dist_x_plane = cpl_image_new(nx,ny,cpl_image_get_type(distortion->dist_x));
01234     dist_y_plane = cpl_image_new(nx,ny,cpl_image_get_type(distortion->dist_y));
01235     for(i = 0; i < nx; ++i)
01236         for(j = 0; j < ny; ++j)
01237         {
01238             double fit_value_x;
01239             double fit_value_y;
01240             cpl_vector_set(pix, 0, (double)i);
01241             cpl_vector_set(pix, 1, (double)j);
01242             fit_value_x = cpl_polynomial_eval(fit2d_x, pix);
01243             fit_value_y = cpl_polynomial_eval(fit2d_y, pix);
01244             cpl_image_set(dist_x_plane, i+1, j+1, fit_value_x);
01245             cpl_image_set(dist_y_plane, i+1, j+1, fit_value_y);
01246         }
01247     cpl_image_subtract(distortion->dist_x, dist_x_plane);
01248     cpl_image_subtract(distortion->dist_y, dist_y_plane);
01249     
01250     /* Subtract the mean distortion, again */
01251     dist_x_mean = cpl_image_get_mean(distortion->dist_x);
01252     dist_y_mean = cpl_image_get_mean(distortion->dist_y);
01253     cpl_msg_warning(__func__,"Subtracting mean distortion in X %f",dist_x_mean);
01254     cpl_msg_warning(__func__,"Subtracting mean distortion in Y %f",dist_y_mean);
01255     cpl_image_subtract_scalar(distortion->dist_x, dist_x_mean);
01256     cpl_image_subtract_scalar(distortion->dist_y, dist_y_mean);
01257 
01258     /* Free and return */
01259     cpl_matrix_delete(pixel_pos);
01260     cpl_vector_delete(dist_x_val);
01261     cpl_vector_delete(dist_y_val);
01262     cpl_vector_delete(pix);
01263     cpl_image_delete(dist_x_plane);
01264     cpl_image_delete(dist_y_plane);
01265     
01266     if(!cpl_errorstate_is_equal(error_prevstate ))
01267     {
01268         cpl_msg_error(__func__, "A problem happened computing the linear term");
01269         cpl_msg_error(__func__,"Error %s",cpl_error_get_message());
01270         //cpl_msg_error(__func__,"Where  %s",cpl_error_get_where());
01271         return -1;
01272     }
01273     return 0;
01274 }
01275 
01276 /*----------------------------------------------------------------------------*/
01281 /*----------------------------------------------------------------------------*/
01282 static cpl_propertylist ** hawki_cal_distortion_qc
01283 (hawki_distortion ** distortion,
01284  int              *  nmatched_pairs,
01285  double           *  rms)
01286 {
01287     int idet;
01288     cpl_propertylist ** qclists;
01289     
01290     /* Allocate the qclists */
01291     qclists = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_propertylist*)) ;
01292     
01293     /* Loop on the detectors to get the mean zpoint */
01294     for(idet = 0 ; idet < HAWKI_NB_DETECTORS ; ++idet)
01295     {
01296         /* Allocate this qclist */
01297         qclists[idet] = cpl_propertylist_new() ;
01298         
01299         cpl_propertylist_append_double
01300             (qclists[idet], "ESO QC DIST NMATCHED", nmatched_pairs[idet]);
01301 
01302         cpl_propertylist_append_double
01303             (qclists[idet], "ESO QC DIST TOTAL RMS", rms[idet]);
01304 
01305         /* Getting the jacobian of the distortion map */
01306         /* The jacobian has to be definitive positive in all the detector to 
01307          * be have a biyective function invertible anywhere:
01308          * http://en.wikipedia.org/wiki/Jacobian_matrix_and_determinant#Jacobian_determinant
01309          * http://en.wikipedia.org/wiki/Inverse_function#Inverses_and_derivatives
01310          * This should be a QC check.
01311          */ 
01312 
01313         
01314         //cpl_propertylist_append_double
01315         //(qclists[idet], "ESO QC DIST JACOBIAN_1_1", jacobian[1][1]);
01316     }
01317     
01318     return qclists;
01319 }
01320 
01321 /*----------------------------------------------------------------------------*/
01331 /*----------------------------------------------------------------------------*/
01332 static int hawki_cal_distortion_save
01333 (hawki_distortion       **  distortion,
01334  cpl_parameterlist       *  parlist,
01335  cpl_propertylist       **  qclists,
01336  cpl_frameset            *  recipe_set)
01337 {
01338     const char   * recipe_name = "hawki_cal_distortion";
01339 
01340     /* Write the distortion in both axes */
01341     hawki_distortion_save(recipe_set,
01342                           parlist,
01343                           recipe_set,
01344                           (const hawki_distortion **) distortion,
01345                           recipe_name,
01346                           NULL,
01347                           (const cpl_propertylist **)qclists,
01348                           "hawki_cal_distortion_x.fits",
01349                           "hawki_cal_distortion_y.fits");
01350 
01351     /* Free and return */
01352     return  0;
01353 }
01354 
01355 static int hawki_cal_distortion_retrieve_input_param
01356 (cpl_parameterlist  *  parlist)
01357 {
01358     cpl_parameter   *   par ;
01359 
01360     par = NULL ;
01361     par = cpl_parameterlist_find
01362         (parlist, "hawki.hawki_cal_distortion.sigma_det");
01363     hawki_cal_distortion_config.sigma_det = cpl_parameter_get_double(par);
01364     par = cpl_parameterlist_find
01365         (parlist, "hawki.hawki_cal_distortion.grid_points");
01366     hawki_cal_distortion_config.grid_points = cpl_parameter_get_int(par);
01367     par = cpl_parameterlist_find
01368         (parlist, "hawki.hawki_cal_distortion.borders");
01369     hawki_cal_distortion_config.borders = cpl_parameter_get_int(par);
01370     par = cpl_parameterlist_find
01371         (parlist, "hawki.hawki_cal_distortion.subtract_linear");
01372     hawki_cal_distortion_config.subtract_linear = cpl_parameter_get_bool(par);
01373 
01374 
01375     return 0;
01376 }