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