HAWKI Pipeline Reference Manual 1.8.12
hawki_step_combine.c
00001 /* $Id: hawki_step_combine.c,v 1.26 2013/01/14 15:18:44 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/01/14 15:18:44 $
00024  * $Revision: 1.26 $
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 #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 
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_step_combine_create(cpl_plugin *) ;
00065 static int hawki_step_combine_exec(cpl_plugin *) ;
00066 static int hawki_step_combine_destroy(cpl_plugin *) ;
00067 static int hawki_step_combine(cpl_parameterlist *, cpl_frameset *) ;
00068 
00069 static int hawki_step_combine_retrieve_input_param
00070 (cpl_parameterlist  *  parlist);
00071 static cpl_image ** hawki_step_combine_apply_comb
00072 (cpl_frameset    * obj,
00073  cpl_frameset    * offsets,
00074  cpl_frameset    * bpm,
00075  cpl_frameset    * bkg_bpm_frames);
00076 static cpl_image **  hawki_step_combine_chip
00077 (cpl_imagelist   * in,
00078  cpl_bivector    * offsets,
00079  double          * pos_x,
00080  double          * pos_y);
00081 static int hawki_step_combine_interpolate_badpix
00082 (cpl_image           *  image);
00083 static int hawki_step_combine_save
00084 (cpl_image           ** combined,
00085  cpl_image           ** contrib_map,
00086  cpl_frameset        *  used_frames,
00087  cpl_parameterlist   *  parlist,
00088  cpl_frameset        *  recipe_frameset);
00089 
00090 /*-----------------------------------------------------------------------------
00091                             Static variables
00092  -----------------------------------------------------------------------------*/
00093 
00094 static struct 
00095 {
00096     /* Inputs */
00097     int                 offset_max ;
00098     int                 borders ;
00099     cpl_geom_combine    comb_meth ;
00100     int                 rej_low;
00101     int                 rej_high;
00102     cpl_kernel          resamp_kernel;
00103 } hawki_step_combine_config;
00104 
00105 static struct 
00106 {
00107     /* Outputs */
00108     double  mean_airmass;
00109     double  combined_pos_x[HAWKI_NB_DETECTORS];
00110     double  combined_pos_y[HAWKI_NB_DETECTORS];
00111     double  combined_cumoffset_x[HAWKI_NB_DETECTORS];
00112     double  combined_cumoffset_y[HAWKI_NB_DETECTORS];
00113 } hawki_step_combine_output;
00114 
00115 static char hawki_step_combine_description[] =
00116 "hawki_step_combine -- hawki combine jitter images.\n"
00117 "The files listed in the Set Of Frames (sof-file) must be tagged:\n"
00118 "science-file.fits "HAWKI_CALPRO_DIST_CORRECTED" or\n"
00119 "science-file.fits "HAWKI_CALPRO_BKG_SUBTRACTED" or\n"
00120 "bpm-file.fits "HAWKI_CALPRO_BPM" (optional) \n"
00121 "bkg_bpm-file.fits "HAWKI_CALPRO_BKGBPM" (optional) \n"
00122 "offsets-file.fits "HAWKI_CALPRO_OFFSETS" (optional) \n"
00123 "The recipe creates as an output:\n"
00124 "hawki_step_combine.fits ("HAWKI_CALPRO_COMBINED"): \n"
00125 "The recipe does the following steps:\n"
00126 "-Allocate an image with the proper combined size \n"
00127 "   (depends on parameters --comb_meth and --borders)\n"
00128 "-Retrieve the offsets either from the offsets-file.fits or from the header\n"
00129 "-For each combined pixel, the contribution of each individual frame \n"
00130 "   is added using a resampling kernel. If any of the pixels involved in\n"
00131 "   the resampling is a bad pixel (defined in bpm-file.fits), it is not\n"
00132 "   taken into account.\n"
00133 "   With the remaining pixels a minmax rejection is performed\n"
00134 "Return code:\n"
00135 "esorex exits with an error code of 0 if the recipe completes successfully\n"
00136 "or 1 otherwise";
00137 
00138 /*-----------------------------------------------------------------------------
00139                                 Functions code
00140  -----------------------------------------------------------------------------*/
00141 
00142 /*----------------------------------------------------------------------------*/
00150 /*----------------------------------------------------------------------------*/
00151 int cpl_plugin_get_info(cpl_pluginlist * list)
00152 {
00153     cpl_recipe  *   recipe = cpl_calloc(1, sizeof(*recipe)) ;
00154     cpl_plugin  *   plugin = &recipe->interface ;
00155 
00156     cpl_plugin_init(plugin,
00157                     CPL_PLUGIN_API,
00158                     HAWKI_BINARY_VERSION,
00159                     CPL_PLUGIN_TYPE_RECIPE,
00160                     "hawki_step_combine",
00161                     "Jitter image combination recipe",
00162                     hawki_step_combine_description,
00163                     "Cesar Enrique Garcia Dabo",
00164                     PACKAGE_BUGREPORT,  
00165                     hawki_get_license(),
00166                     hawki_step_combine_create,
00167                     hawki_step_combine_exec,
00168                     hawki_step_combine_destroy) ;
00169 
00170     cpl_pluginlist_append(list, plugin) ;
00171     
00172     return 0;
00173 }
00174 
00175 /*----------------------------------------------------------------------------*/
00184 /*----------------------------------------------------------------------------*/
00185 static int hawki_step_combine_create(cpl_plugin * plugin)
00186 {
00187     cpl_recipe      * recipe ;
00188     cpl_parameter   * p ;
00189 
00190     /* Get the recipe out of the plugin */
00191     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00192         recipe = (cpl_recipe *)plugin ;
00193     else return -1 ;
00194 
00195     /* Create the parameters list in the cpl_recipe object */
00196     recipe->parameters = cpl_parameterlist_new() ;
00197     if (recipe->parameters == NULL)
00198         return 1;
00199 
00200     /* Fill the parameters list */
00201     /* --offset_max */
00202     p = cpl_parameter_new_value("hawki.hawki_step_combine.offset_max",
00203                                 CPL_TYPE_INT,
00204                                 "Maximum offset allowed",
00205                                 "hawki.hawki_step_combine",
00206                                 1500) ;
00207     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "offset_max") ;
00208     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
00209     cpl_parameterlist_append(recipe->parameters, p) ;
00210 
00211     /* --comb_meth */
00212     p = cpl_parameter_new_value("hawki.hawki_step_combine.comb_meth",
00213                                 CPL_TYPE_STRING,
00214                                 "Final size of combination (union / inter / first)",
00215                                 "hawki.hawki_step_combine",
00216                                 "union") ;
00217     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "comb_meth") ;
00218     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
00219     cpl_parameterlist_append(recipe->parameters, p) ;
00220   
00221     /* --rej */
00222     p = cpl_parameter_new_value("hawki.hawki_step_combine.rej",
00223                                 CPL_TYPE_STRING,
00224                                 "Low and high number of rejected values",
00225                                 "hawki.hawki_step_combine",
00226                                 "1,1") ;
00227     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rej") ;
00228     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
00229     cpl_parameterlist_append(recipe->parameters, p) ;
00230 
00231     /* --borders */
00232     p = cpl_parameter_new_value("hawki.hawki_step_combine.borders",
00233                                 CPL_TYPE_INT,
00234                                 "Border pixels trimmed",
00235                                 "hawki.hawki_step_combine",
00236                                 4) ;
00237     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "borders") ;
00238     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
00239     cpl_parameterlist_append(recipe->parameters, p) ;
00240 
00241     /* --resamp_kernel */
00242     p = cpl_parameter_new_value("hawki.hawki_step_combine.resamp_kernel",
00243                                 CPL_TYPE_STRING,
00244                                 "Resampling kernel (default/tanh/sinc/sinc2/lanczos/hamming/hann)",
00245                                 "hawki.hawki_step_combine",
00246                                 "default") ;
00247     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "resamp_kernel") ;
00248     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
00249     cpl_parameterlist_append(recipe->parameters, p) ;
00250 
00251     /* Return */
00252     return 0;
00253 }
00254 
00255 /*----------------------------------------------------------------------------*/
00261 /*----------------------------------------------------------------------------*/
00262 static int hawki_step_combine_exec(cpl_plugin * plugin)
00263 {
00264     cpl_recipe  *   recipe ;
00265 
00266     /* Get the recipe out of the plugin */
00267     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00268         recipe = (cpl_recipe *)plugin ;
00269     else return -1 ;
00270 
00271     /* Issue a banner */
00272     hawki_print_banner();
00273 
00274     return hawki_step_combine(recipe->parameters, recipe->frames) ;
00275 }
00276 
00277 /*----------------------------------------------------------------------------*/
00283 /*----------------------------------------------------------------------------*/
00284 static int hawki_step_combine_destroy(cpl_plugin * plugin)
00285 {
00286     cpl_recipe  *   recipe ;
00287 
00288     /* Get the recipe out of the plugin */
00289     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00290         recipe = (cpl_recipe *)plugin ;
00291     else return -1 ;
00292 
00293     cpl_parameterlist_delete(recipe->parameters) ;
00294     return 0 ;
00295 }
00296 
00297 /*----------------------------------------------------------------------------*/
00304 /*----------------------------------------------------------------------------*/
00305 static int hawki_step_combine(
00306         cpl_parameterlist   *   parlist, 
00307         cpl_frameset        *   framelist)
00308 {
00309     cpl_frameset    *  objframes ;
00310     cpl_frameset    *  offsets;
00311     cpl_frameset    *  bpm;
00312     cpl_frameset    *  bpmbkg;
00313     cpl_frameset    *  used_frames;
00314     cpl_image       ** combined_contrib;
00315     cpl_image       ** combined;
00316     cpl_image       ** contrib_map;
00317     int                idet;
00318 
00319     /* Retrieve input parameters */
00320     if(hawki_step_combine_retrieve_input_param(parlist))
00321     {
00322         cpl_msg_error(__func__, "Wrong parameters");
00323         return -1;
00324     }
00325 
00326     /* Identify the RAW and CALIB frames in the input frameset */
00327     if (hawki_dfs_set_groups(framelist)) {
00328         cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
00329         return -1 ;
00330     }
00331 
00332     /* Retrieve raw frames */
00333     objframes = hawki_extract_frameset(framelist, HAWKI_CALPRO_DIST_CORRECTED);
00334     if (objframes == NULL) 
00335     {
00336         objframes = hawki_extract_frameset
00337             (framelist, HAWKI_CALPRO_BKG_SUBTRACTED);
00338         if (objframes == NULL) 
00339         {
00340             cpl_msg_error(__func__,"Cannot find objs frames in the input list (%s or %s)",
00341                     HAWKI_CALPRO_DIST_CORRECTED, HAWKI_CALPRO_BKG_SUBTRACTED);
00342             return -1 ;
00343         }
00344     }
00345     /* Check that pointing is the same for all the frames */
00346     if(!hawki_utils_check_equal_double_keys(objframes, &hawki_pfits_get_targ_alpha) ||
00347        !hawki_utils_check_equal_double_keys(objframes, &hawki_pfits_get_targ_delta))
00348     {
00349         cpl_msg_error(__func__, "Not all input science frames belong to the "
00350                 "same pointing/target. Check keywords TEL TARG ALPHA/DELTA");
00351         cpl_frameset_delete(objframes);
00352         return -1;        
00353     }
00354     used_frames = cpl_frameset_duplicate(objframes);
00355     
00356     /* Retrieve the refined offsets, if provided */
00357     offsets = hawki_extract_frameset(framelist, HAWKI_CALPRO_OFFSETS);
00358     if(offsets)
00359         cpl_frameset_insert(used_frames, cpl_frame_duplicate(
00360                 cpl_frameset_get_position(offsets, 0)));
00361     
00362     /* Retrieve the general bad pixel mask, if provided */
00363     bpm = hawki_extract_frameset(framelist, HAWKI_CALPRO_BPM);
00364     if(bpm)
00365         cpl_frameset_insert(used_frames, cpl_frame_duplicate(
00366                 cpl_frameset_get_position(bpm, 0)));
00367 
00368     /* Retrieve the background bad pixel masks, if provided */
00369     bpmbkg = hawki_extract_frameset(framelist, HAWKI_CALPRO_BKGBPM);
00370     if(bpmbkg)
00371     {
00372         int iframe;
00373         for(iframe=0; iframe < cpl_frameset_get_size(bpmbkg); iframe++)
00374             cpl_frameset_insert(used_frames, cpl_frame_duplicate(
00375                     cpl_frameset_get_frame(bpmbkg,iframe)));
00376         if(cpl_frameset_get_size(bpmbkg) != cpl_frameset_get_size(objframes))
00377         {
00378             cpl_msg_error(__func__,"Incompatible number of science and bad bkg"
00379                                    " images.");
00380             cpl_msg_error(__func__,"Supply as many bad bkg images as objects");
00381             cpl_frameset_delete(objframes);
00382             cpl_frameset_delete(used_frames);
00383             cpl_frameset_delete(offsets);
00384             cpl_frameset_delete(bpm);
00385             cpl_frameset_delete(bpmbkg);
00386             return -1;
00387         }
00388     }
00389     
00390     /* Apply the combination */
00391     cpl_msg_info(__func__, "Apply the data recombination");
00392     cpl_msg_indent_more() ;
00393     if ((combined_contrib = hawki_step_combine_apply_comb
00394              (objframes, offsets, bpm, bpmbkg)) == NULL)
00395     {
00396         cpl_msg_error(__func__, "Cannot combine the data");
00397         cpl_frameset_delete(objframes);
00398         cpl_frameset_delete(used_frames);
00399         if(offsets != NULL)
00400             cpl_frameset_delete(offsets);
00401         if(bpm != NULL)
00402             cpl_frameset_delete(bpm);
00403         cpl_msg_indent_less() ;
00404         return -1 ;
00405     }
00406     
00407     /* Get both the combination and the contribution map */
00408     combined   = combined_contrib;
00409     contrib_map = combined_contrib + HAWKI_NB_DETECTORS;
00410     cpl_msg_indent_less() ;
00411     cpl_frameset_delete(objframes);
00412     if(offsets != NULL)
00413         cpl_frameset_delete(offsets);
00414     if(bpm != NULL)
00415         cpl_frameset_delete(bpm);
00416     if(bpmbkg != NULL)
00417         cpl_frameset_delete(bpmbkg);
00418 
00419     /* Save the products */
00420     cpl_msg_info(__func__, "Save the products") ;
00421     cpl_msg_indent_more() ;
00422     if (hawki_step_combine_save(combined, contrib_map, 
00423                                 used_frames, parlist, framelist) != 0)
00424     {
00425         cpl_msg_warning(__func__, "Some error happened saving the data. "
00426                         "Check permisions or disk space") ;
00427         for(idet=0; idet< 2 * HAWKI_NB_DETECTORS; ++idet)
00428             cpl_image_delete(combined_contrib[idet]);
00429         cpl_frameset_delete(used_frames);
00430         cpl_free(combined_contrib);
00431         cpl_msg_indent_less() ;
00432         return -1 ;
00433     }
00434     cpl_msg_indent_less() ;
00435     
00436     /* Return */
00437     for(idet=0; idet< 2 * HAWKI_NB_DETECTORS; ++idet)
00438         cpl_image_delete(combined_contrib[idet]);
00439     cpl_free(combined_contrib);
00440     cpl_frameset_delete(used_frames);
00441 
00442     /* Return */
00443     if (cpl_error_get_code())
00444     {
00445         cpl_msg_error(__func__,
00446                       "HAWK-I pipeline could not recover from previous errors");
00447         return -1 ;
00448     }
00449     else return 0 ;
00450 }
00451 
00452 int hawki_step_combine_retrieve_input_param
00453 (cpl_parameterlist  *  parlist)
00454 {
00455     cpl_parameter   *   par ;
00456     const char      *   sval ;
00457     par = NULL ;
00458     par = cpl_parameterlist_find(parlist,
00459             "hawki.hawki_step_combine.offset_max");
00460     hawki_step_combine_config.offset_max = cpl_parameter_get_int(par);
00461     par = cpl_parameterlist_find(parlist,
00462             "hawki.hawki_step_combine.comb_meth");
00463     sval = cpl_parameter_get_string(par);
00464     if (!strcmp(sval, "union"))
00465         hawki_step_combine_config.comb_meth = CPL_GEOM_UNION;
00466     else if (!strcmp(sval, "inter"))
00467         hawki_step_combine_config.comb_meth = CPL_GEOM_INTERSECT;
00468     else if (!strcmp(sval, "first"))
00469         hawki_step_combine_config.comb_meth = CPL_GEOM_FIRST;
00470     else
00471     {
00472         cpl_msg_error(__func__, "Invalid combine method specified");
00473         return -1;
00474     }
00475     par = cpl_parameterlist_find(parlist,
00476             "hawki.hawki_step_combine.borders");
00477     hawki_step_combine_config.borders = cpl_parameter_get_int(par);
00478     if(hawki_step_combine_config.borders < 0 )
00479     {
00480         cpl_msg_error(__func__, "Borders cannot be less than zero");
00481         return -1;
00482     }
00483     par = cpl_parameterlist_find(parlist, 
00484             "hawki.hawki_step_combine.rej");
00485     sval = cpl_parameter_get_string(par);
00486     if (sscanf(sval, "%d,%d",
00487                &hawki_step_combine_config.rej_low,
00488                &hawki_step_combine_config.rej_high)!=2)
00489     {
00490         return -1;
00491     }
00492     par = cpl_parameterlist_find(parlist, 
00493             "hawki.hawki_step_combine.resamp_kernel");
00494     sval = cpl_parameter_get_string(par);
00495     if (!strcmp(sval, "tanh"))
00496         hawki_step_combine_config.resamp_kernel = CPL_KERNEL_TANH;
00497     else if (!strcmp(sval, "sinc"))
00498         hawki_step_combine_config.resamp_kernel = CPL_KERNEL_SINC;
00499     else if (!strcmp(sval, "sinc2"))
00500         hawki_step_combine_config.resamp_kernel = CPL_KERNEL_SINC2;
00501     else if (!strcmp(sval, "lanczos"))
00502         hawki_step_combine_config.resamp_kernel = CPL_KERNEL_LANCZOS;
00503     else if (!strcmp(sval, "hamming"))
00504         hawki_step_combine_config.resamp_kernel = CPL_KERNEL_HAMMING;
00505     else if (!strcmp(sval, "hann"))
00506         hawki_step_combine_config.resamp_kernel = CPL_KERNEL_HANN;
00507     else if (!strcmp(sval, "default"))
00508         hawki_step_combine_config.resamp_kernel = CPL_KERNEL_DEFAULT;
00509     else
00510     {
00511         cpl_msg_error(__func__, "Invalid resampling kernel specified");
00512         return -1;
00513     }
00514 
00515     return 0;
00516 }
00517 
00518 
00519 
00520 /*----------------------------------------------------------------------------*/
00526 /*----------------------------------------------------------------------------*/
00527 static cpl_image ** hawki_step_combine_apply_comb
00528 (cpl_frameset    * obj,
00529  cpl_frameset    * offsets_frames,
00530  cpl_frameset    * bpm_frame,
00531  cpl_frameset    * bkg_bpm_frames)
00532 {
00533     cpl_image           **  combined_contrib;
00534     cpl_bivector        **  offsets;
00535     cpl_mask             *  bpm_masks[HAWKI_NB_DETECTORS];
00536     int                     idet;
00537     int                     ioff;
00538 
00539     if(offsets_frames == NULL)
00540     {
00541         cpl_bivector        *   offsets_single_chip;
00542         if ((offsets_single_chip = hawki_get_header_tel_offsets(obj)) == NULL) 
00543         {
00544             cpl_msg_error(__func__, "Cannot load the header offsets");
00545             return NULL;
00546         }
00547         offsets = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_bivector *));
00548         for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
00549             offsets[idet] =  cpl_bivector_duplicate(offsets_single_chip);
00550         cpl_bivector_delete(offsets_single_chip);
00551     }
00552     else
00553     {
00554         offsets = hawki_load_refined_offsets
00555             (cpl_frameset_get_first(offsets_frames));
00556         if(offsets == NULL)
00557         {
00558             cpl_msg_error(__func__, "Cannot load the refined offsets");
00559             return NULL;
00560         }
00561     }
00562     /* Get the oposite offsets. This is to change from 
00563      * telescope convention to cpl convention 
00564      * WARNING: It may appear that the img_jitter function 
00565      * does not apply the multiplication by -1, but it really does it in 
00566      * hawki_img_jitter_saa instead of when it reads the offsets */
00567     for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
00568     {
00569         cpl_vector_multiply_scalar(cpl_bivector_get_x(offsets[idet]), -1.0);
00570         cpl_vector_multiply_scalar(cpl_bivector_get_y(offsets[idet]), -1.0);
00571     }
00572     
00573     /* Load the bpm */
00574     if(bpm_frame != NULL)
00575     {
00576         cpl_imagelist *  bpm_images = NULL;
00577         bpm_images = hawki_load_frame
00578             (cpl_frameset_get_first(bpm_frame), CPL_TYPE_INT);
00579         if(bpm_images == NULL)
00580         {
00581             cpl_msg_error(__func__, "Cannot load the bad pixel mask");
00582             return NULL;
00583         }
00584         for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
00585         {
00586             bpm_masks[idet] = cpl_mask_threshold_image_create
00587                 (cpl_imagelist_get(bpm_images, idet), 0.5, 1.5);
00588         }
00589         cpl_imagelist_delete(bpm_images);
00590     }
00591 
00592     /* Create output object */
00593     combined_contrib = cpl_malloc(2 * HAWKI_NB_DETECTORS * sizeof(cpl_image *));
00594  
00595     /* Loop on the detectors */
00596     for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
00597     {
00598         cpl_imagelist   * in ;
00599         cpl_imagelist   * bpm_bkg_im = NULL;
00600         cpl_image      ** comb_contrib_chip ;
00601         double          * offs_est_x ;
00602         double          * offs_est_y ;
00603         double            max_x, max_y ;
00604         double            off_0_x;
00605         double            off_0_y;
00606         int               jdet;
00607         int               iframe;
00608 
00609         cpl_msg_info(__func__, "Combine chip number %d", idet+1) ;
00610         cpl_msg_indent_more() ;
00611         
00612         /* Print the offsets */
00613         offs_est_x = cpl_bivector_get_x_data(offsets[idet]) ;
00614         offs_est_y = cpl_bivector_get_y_data(offsets[idet]) ;
00615         for (ioff=0 ; ioff<cpl_bivector_get_size(offsets[idet]) ; ioff++) {
00616             cpl_msg_info(__func__,"Telescope offsets (Frame %d): %g %g", ioff+1,
00617                     -offs_est_x[ioff], -offs_est_y[ioff]) ;
00618         }
00619 
00620         /* Subtract the first offset to all offsets */
00621         max_x = max_y = 0.0 ;
00622         off_0_x = offs_est_x[0];
00623         off_0_y = offs_est_y[0];
00624         for (ioff=1 ; ioff<cpl_bivector_get_size(offsets[idet]) ; ioff++) 
00625         {
00626             offs_est_x[ioff] -= offs_est_x[0] ;
00627             offs_est_y[ioff] -= offs_est_y[0] ;
00628             if (fabs(offs_est_x[ioff]) > max_x) max_x = fabs(offs_est_x[ioff]);
00629             if (fabs(offs_est_y[ioff]) > max_y) max_y = fabs(offs_est_y[ioff]);
00630         }
00631         offs_est_x[0] = offs_est_y[0] = 0.00 ;
00632 
00633         /* Check if the max offset is not too big */
00634         if (max_x > hawki_step_combine_config.offset_max || 
00635                 max_y > hawki_step_combine_config.offset_max) 
00636         {
00637             cpl_msg_error(__func__,"Sorry, no support for offsets larger than %d",
00638                           hawki_step_combine_config.offset_max);
00639             for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
00640             {
00641                 cpl_bivector_delete(offsets[idet]);
00642                 if(bpm_frame != NULL)
00643                     cpl_mask_delete(bpm_masks[idet]);
00644             }
00645             for(jdet = 0; jdet < idet; ++jdet)
00646             {
00647                 cpl_image_delete(combined_contrib[idet]);
00648                 cpl_image_delete(combined_contrib[idet+HAWKI_NB_DETECTORS]);
00649             }
00650             cpl_free(combined_contrib);
00651             return NULL ;
00652         }
00653 
00654         /* Load the input data */
00655         cpl_msg_info(__func__, "Load the input data") ;
00656         cpl_msg_indent_more();
00657         if ((in = hawki_load_detector(obj, idet+1, CPL_TYPE_FLOAT)) == NULL) {
00658             cpl_msg_error(__func__, "Cannot load chip %d",idet+1);
00659             //TODO: there is probably a memory leak here. It should be checked.
00660             for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
00661             {
00662                 cpl_bivector_delete(offsets[idet]);
00663                 if(bpm_frame != NULL)
00664                     cpl_mask_delete(bpm_masks[idet]);
00665             }
00666             for(jdet = 0; jdet < idet; ++jdet)
00667             {
00668                 cpl_image_delete(combined_contrib[idet]);
00669                 cpl_image_delete(combined_contrib[idet+HAWKI_NB_DETECTORS]);
00670             }
00671             cpl_free(combined_contrib);
00672             cpl_free(offsets);
00673             cpl_msg_indent_less() ;
00674             cpl_msg_indent_less() ;
00675             return NULL ;
00676         }
00677 
00678         /* Load the bad bkg images */
00679         if(bkg_bpm_frames != NULL)
00680         {
00681             cpl_msg_info(__func__, "Load the bad bkg images");
00682             cpl_msg_indent_more() ;
00683             if ((bpm_bkg_im = hawki_load_detector(bkg_bpm_frames, idet+1,
00684                               CPL_TYPE_FLOAT)) == NULL)
00685             {
00686                 cpl_msg_error(__func__, "Cannot load chip %d",idet+1);
00687                 for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
00688                 {
00689                     cpl_bivector_delete(offsets[idet]);
00690                     if(bpm_frame != NULL)
00691                         cpl_mask_delete(bpm_masks[idet]);
00692                 }
00693                 for(jdet = 0; jdet < idet; ++jdet)
00694                 {
00695                     cpl_image_delete(combined_contrib[idet]);
00696                     cpl_image_delete(combined_contrib[idet+HAWKI_NB_DETECTORS]);
00697                 }
00698                 cpl_free(combined_contrib);
00699                 cpl_imagelist_delete(in);
00700                 cpl_free(offsets);
00701                 cpl_msg_indent_less() ;
00702                 cpl_msg_indent_less() ;
00703                 return NULL ;
00704             }
00705             cpl_msg_indent_less() ;
00706         }
00707         cpl_msg_indent_less() ;
00708         
00709         /* Add the general bpm or background bpms in case they were specified */
00710         if(bpm_frame != NULL || bkg_bpm_frames != NULL)
00711         {
00712             for(iframe = 0 ; iframe <cpl_imagelist_get_size(in) ; ++iframe)
00713             {
00714                 cpl_mask  * final_mask;
00715                 cpl_image * target_image =  cpl_imagelist_get(in, iframe);
00716                 final_mask = cpl_mask_new(cpl_image_get_size_x(target_image),
00717                                           cpl_image_get_size_y(target_image));
00718                 //Add the common bpm
00719                 if(bpm_frame != NULL)
00720                     cpl_mask_or(final_mask, bpm_masks[idet]);
00721                 //Add the background mask if provided
00722                 if(bkg_bpm_frames != NULL)
00723                 {
00724                     cpl_mask * bpm_bkg_mask = 
00725                         cpl_mask_threshold_image_create
00726                           (cpl_imagelist_get(bpm_bkg_im, iframe), 0.5, FLT_MAX);
00727                     cpl_mask_or(final_mask, bpm_bkg_mask);
00728                     cpl_mask_delete(bpm_bkg_mask);
00729                 }
00730                 cpl_image_reject_from_mask(target_image, final_mask);
00731                 cpl_mask_delete(final_mask);
00732             }
00733         }
00734         
00735         if(bkg_bpm_frames != NULL)
00736             cpl_imagelist_delete(bpm_bkg_im);
00737 
00738         /* Apply the shift and add */
00739         cpl_msg_info(__func__, "Shift and add") ;
00740         cpl_msg_indent_more() ;
00741         comb_contrib_chip = hawki_step_combine_chip(in, offsets[idet], 
00742                 &(hawki_step_combine_output.combined_pos_x[idet]),
00743                 &(hawki_step_combine_output.combined_pos_y[idet])) ;
00744         if (comb_contrib_chip == NULL) 
00745         {
00746             cpl_msg_error(__func__, "Cannot apply the shift and add") ;
00747             cpl_imagelist_delete(in) ;
00748             for(jdet = 0; jdet < HAWKI_NB_DETECTORS; ++jdet)
00749                 cpl_bivector_delete(offsets[jdet]);
00750             {
00751                 cpl_image_delete(combined_contrib[idet]);
00752                 cpl_image_delete(combined_contrib[idet+HAWKI_NB_DETECTORS]);
00753             }
00754             cpl_free(combined_contrib);
00755             cpl_free(offsets);
00756             cpl_msg_indent_less() ;
00757             cpl_msg_indent_less() ;
00758             return NULL ;
00759         }
00760         
00761         /* The cumoffset have the opposite criteria as cpl */
00762         hawki_step_combine_output.combined_cumoffset_x[idet] = 
00763             hawki_step_combine_output.combined_pos_x[idet] - off_0_x;
00764         hawki_step_combine_output.combined_cumoffset_y[idet] = 
00765             hawki_step_combine_output.combined_pos_y[idet] - off_0_y;
00766         cpl_imagelist_delete(in) ;
00767         cpl_msg_indent_less() ;
00768 
00769         /* Interpolate bad pixels */
00770         hawki_step_combine_interpolate_badpix(comb_contrib_chip[0]);        
00771 
00772         /* Put the results in the image list */
00773         combined_contrib[idet] = comb_contrib_chip[0];
00774         combined_contrib[idet+HAWKI_NB_DETECTORS] = comb_contrib_chip[1];
00775         cpl_free(comb_contrib_chip);
00776         cpl_msg_indent_less() ;
00777     }
00778     
00779     /* Compute the mean airmass */
00780     hawki_step_combine_output.mean_airmass = hawki_get_mean_airmass(obj);
00781     
00782     for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
00783     {
00784         cpl_bivector_delete(offsets[idet]);
00785         if(bpm_frame != NULL)
00786             cpl_mask_delete(bpm_masks[idet]);
00787     }
00788     cpl_free(offsets);
00789     return combined_contrib;
00790 }
00791 
00792 /*----------------------------------------------------------------------------*/
00801 /*----------------------------------------------------------------------------*/
00802 static cpl_image ** hawki_step_combine_chip(
00803         cpl_imagelist   *  in,
00804         cpl_bivector    *  offsets,
00805         double          *  pos_x,
00806         double          *  pos_y)
00807 {
00808     cpl_image        **  combined_contrib;
00809     cpl_imagelist    *   in_ext ;
00810     cpl_image        *   tmp1 ;
00811     cpl_image        *   tmp2 ;
00812     int                  nfiles, nx, ny ;
00813     int                  i;
00814 
00815     /* Check entries */
00816     if (pos_x == NULL || pos_y == NULL) return NULL ;
00817     if (offsets == NULL) return NULL ;
00818 
00819     /* Get the number of images */
00820     nfiles = cpl_imagelist_get_size(in) ;
00821     if (cpl_bivector_get_size(offsets) != nfiles) {
00822         cpl_msg_error(__func__, "Number of refined offsets in table """
00823                       "is different than number of frames to combine"); 
00824         return NULL ;
00825     }
00826     
00827     /* Discard the pixels on the sides */
00828     if (hawki_step_combine_config.borders > 0) {
00829         nx = cpl_image_get_size_x(cpl_imagelist_get(in, 0)) ;
00830         ny = cpl_image_get_size_y(cpl_imagelist_get(in, 0)) ;
00831         in_ext = cpl_imagelist_new() ;
00832         for (i=0 ; i<cpl_imagelist_get_size(in) ; i++) {
00833             tmp1 = cpl_imagelist_get(in, i) ;
00834             tmp2 = cpl_image_extract(tmp1, 
00835                     hawki_step_combine_config.borders+1, 
00836                     hawki_step_combine_config.borders+1, 
00837                     nx-hawki_step_combine_config.borders, 
00838                     ny-hawki_step_combine_config.borders) ;
00839             cpl_imagelist_set(in_ext, tmp2, i) ;
00840         }
00841     }
00842     else
00843     {
00844         in_ext = cpl_imagelist_duplicate(in);
00845     }
00846 
00847     /* Apply the shift & add */
00848     cpl_msg_info(__func__, "Recombine the images set") ;
00849     cpl_msg_indent_more() ;
00850     if ((combined_contrib=cpl_geom_img_offset_saa(in_ext, offsets,
00851             hawki_step_combine_config.resamp_kernel, 
00852             hawki_step_combine_config.rej_low,
00853             hawki_step_combine_config.rej_high,
00854             hawki_step_combine_config.comb_meth,
00855             pos_x, pos_y)) == NULL) {
00856         cpl_msg_error(cpl_func, "Cannot apply the shift and add") ;
00857         cpl_msg_indent_less();
00858         return NULL;
00859     }
00860     cpl_msg_indent_less();
00861     *pos_x -= hawki_step_combine_config.borders;
00862     *pos_y -= hawki_step_combine_config.borders;
00863 
00864     /* Free and return */
00865     cpl_imagelist_delete(in_ext);
00866     return combined_contrib;
00867 }
00868 
00869 /*----------------------------------------------------------------------------*/
00875 /*----------------------------------------------------------------------------*/
00876 static int hawki_step_combine_interpolate_badpix
00877 (cpl_image           *  image)
00878 {
00879     int nbadpixels = cpl_image_count_rejected(image); 
00880     if(nbadpixels !=0)
00881         cpl_msg_info(__func__,"Number of pixels with no combined value available: %d ",
00882                      nbadpixels);
00883     if(cpl_image_count_rejected(image) > 0)
00884     {
00885         //I use this even if DFS08929 is still not solved
00886         cpl_detector_interpolate_rejected(image);
00887     }
00888     return 0;
00889 }
00890 
00891 /*----------------------------------------------------------------------------*/
00900 /*----------------------------------------------------------------------------*/
00901 static int hawki_step_combine_save
00902 (cpl_image           ** combined,
00903  cpl_image           ** contrib_map,
00904  cpl_frameset        *  used_frames,
00905  cpl_parameterlist   *  parlist,
00906  cpl_frameset        *  recipe_frameset)
00907 {
00908     cpl_propertylist    **  extproplists ;
00909     const cpl_frame     *   ref_frame ;
00910     cpl_propertylist    *   wcslist ;
00911     cpl_propertylist    *   inputlist ;
00912     double                  crpix1, crpix2 ;
00913     int                     ext_nb ;
00914     const char          *   recipe_name = "hawki_step_combine" ;
00915     int                     idet;
00916     cpl_errorstate          error_prevstate = cpl_errorstate_get();
00917 
00918     /* Get a reference frame for the WCS keys */
00919     ref_frame = irplib_frameset_get_first_from_group
00920         (recipe_frameset, CPL_FRAME_GROUP_RAW) ;
00921     
00922     if(ref_frame == NULL)
00923     {
00924         cpl_msg_error(__func__, "Cannot get a reference frame");
00925         return -1;
00926     }
00927 
00928     /* Create the QC lists */
00929     extproplists = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_propertylist*)) ;
00930     for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++) 
00931     {
00932 
00933         /* Initialize qclists */
00934         extproplists[idet] = cpl_propertylist_new() ;
00935 
00936         /* Get the extension number */
00937         ext_nb=hawki_get_ext_from_detector(cpl_frame_get_filename(ref_frame), idet+1);
00938 
00939         /* Handle WCS keys */
00940         wcslist = cpl_propertylist_load_regexp(
00941                 cpl_frame_get_filename(ref_frame), ext_nb, HAWKI_HEADER_WCS, 0);
00942 
00943         /* Update WCS and write them */
00944         crpix1 = cpl_propertylist_get_double(wcslist, "CRPIX1"); 
00945         crpix1 += hawki_step_combine_output.combined_pos_x[idet];
00946         cpl_propertylist_update_double(wcslist, "CRPIX1", crpix1) ;
00947         crpix2 = cpl_propertylist_get_double(wcslist, "CRPIX2"); 
00948         crpix2 += hawki_step_combine_output.combined_pos_y[idet] ;
00949         cpl_propertylist_update_double(wcslist, "CRPIX2", crpix2) ;
00950         cpl_propertylist_copy_property_regexp
00951             (extproplists[idet], wcslist, HAWKI_HEADER_WCS, 0);
00952         cpl_propertylist_delete(wcslist) ;
00953         
00954         /* Keywords for the relative position of the combined image */
00955         cpl_propertylist_append_double
00956             (extproplists[idet], "ESO QC COMBINED CUMOFFSETX",
00957              hawki_step_combine_output.combined_cumoffset_x[idet]);
00958         cpl_propertylist_append_double
00959             (extproplists[idet], "ESO QC COMBINED CUMOFFSETY",
00960              hawki_step_combine_output.combined_cumoffset_y[idet]);
00961         cpl_propertylist_append_double
00962             (extproplists[idet], "ESO QC COMBINED POSX",
00963              hawki_step_combine_output.combined_pos_x[idet]);
00964         cpl_propertylist_append_double
00965             (extproplists[idet], "ESO QC COMBINED POSY",
00966              hawki_step_combine_output.combined_pos_y[idet]);
00967         cpl_propertylist_append_double
00968             (extproplists[idet], "ESO QC AIRMASS MEAN",
00969              hawki_step_combine_output.mean_airmass);
00970 
00971         /* Propagate some keywords from input raw frame extensions */
00972         inputlist = cpl_propertylist_load_regexp(
00973                 cpl_frame_get_filename(ref_frame), ext_nb,
00974                 HAWKI_HEADER_EXT_FORWARD, 0) ;
00975         cpl_propertylist_append(extproplists[idet], inputlist);
00976         cpl_propertylist_delete(inputlist) ;
00977     }
00978 
00979     /* Write the combined image */
00980     if(hawki_images_save(recipe_frameset,
00981                          parlist,
00982                          used_frames,
00983                          (const cpl_image **)combined,
00984                          recipe_name,
00985                          HAWKI_CALPRO_COMBINED,
00986                          HAWKI_PROTYPE_COMBINED, 
00987                          NULL,
00988                          (const cpl_propertylist**)extproplists,
00989                          "hawki_step_combine.fits")  != 0)
00990     {
00991         for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++) {
00992             cpl_propertylist_delete(extproplists[idet]) ;
00993         }
00994         cpl_free(extproplists) ;
00995         return -1;
00996     }
00997 
00998     /* Write the contrib map */
00999     if(hawki_images_save(recipe_frameset,
01000                          parlist,
01001                          used_frames,
01002                          (const cpl_image **)contrib_map,
01003                          recipe_name,
01004                          HAWKI_CALPRO_COMB_CONTRIB_MAP,
01005                          HAWKI_PROTYPE_COMB_CONTRIB_MAP,
01006                          NULL,
01007                          (const cpl_propertylist**)extproplists,
01008                          "hawki_step_combine_contrib_map.fits")  != 0)
01009     {
01010         for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++) {
01011             cpl_propertylist_delete(extproplists[idet]);
01012         }
01013         cpl_free(extproplists) ;
01014         return -1;
01015     }
01016 
01017     /* Free and return */
01018     for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++) {
01019         cpl_propertylist_delete(extproplists[idet]) ;
01020     }
01021     cpl_free(extproplists) ;
01022 
01023     if(!cpl_errorstate_is_equal(error_prevstate))
01024     {
01025         cpl_errorstate_set(CPL_ERROR_NONE);
01026         return 1;
01027     }
01028 
01029     return  0;
01030 }
01031