HAWKI Pipeline Reference Manual 1.8.10
hawki_step_combine.c
00001 /* $Id: hawki_step_combine.c,v 1.25 2012/11/30 14:50:51 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: 2012/11/30 14:50:51 $
00024  * $Revision: 1.25 $
00025  * $Name: hawki-1_8_10 $
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     used_frames = cpl_frameset_duplicate(objframes);
00346     
00347     /* Retrieve the refined offsets, if provided */
00348     offsets = hawki_extract_frameset(framelist, HAWKI_CALPRO_OFFSETS);
00349     if(offsets)
00350         cpl_frameset_insert(used_frames, cpl_frame_duplicate(
00351                 cpl_frameset_get_first(offsets)));
00352     
00353     /* Retrieve the general bad pixel mask, if provided */
00354     bpm = hawki_extract_frameset(framelist, HAWKI_CALPRO_BPM);
00355     if(bpm)
00356         cpl_frameset_insert(used_frames, cpl_frame_duplicate(
00357                 cpl_frameset_get_first(bpm)));
00358 
00359     /* Retrieve the background bad pixel masks, if provided */
00360     bpmbkg = hawki_extract_frameset(framelist, HAWKI_CALPRO_BKGBPM);
00361     if(bpmbkg)
00362     {
00363         int iframe;
00364         for(iframe=0; iframe < cpl_frameset_get_size(bpmbkg); iframe++)
00365             cpl_frameset_insert(used_frames, cpl_frame_duplicate(
00366                     cpl_frameset_get_frame(bpmbkg,iframe)));
00367         if(cpl_frameset_get_size(bpmbkg) != cpl_frameset_get_size(objframes))
00368         {
00369             cpl_msg_error(__func__,"Incompatible number of science and bad bkg"
00370                                    " images.");
00371             cpl_msg_error(__func__,"Supply as many bad bkg images as objects");
00372             cpl_frameset_delete(objframes);
00373             cpl_frameset_delete(used_frames);
00374             cpl_frameset_delete(offsets);
00375             cpl_frameset_delete(bpm);
00376             cpl_frameset_delete(bpmbkg);
00377             return -1;
00378         }
00379     }
00380     
00381     /* Apply the combination */
00382     cpl_msg_info(__func__, "Apply the data recombination");
00383     cpl_msg_indent_more() ;
00384     if ((combined_contrib = hawki_step_combine_apply_comb
00385              (objframes, offsets, bpm, bpmbkg)) == NULL)
00386     {
00387         cpl_msg_error(__func__, "Cannot combine the data");
00388         cpl_frameset_delete(objframes);
00389         cpl_frameset_delete(used_frames);
00390         if(offsets != NULL)
00391             cpl_frameset_delete(offsets);
00392         if(bpm != NULL)
00393             cpl_frameset_delete(bpm);
00394         cpl_msg_indent_less() ;
00395         return -1 ;
00396     }
00397     
00398     /* Get both the combination and the contribution map */
00399     combined   = combined_contrib;
00400     contrib_map = combined_contrib + HAWKI_NB_DETECTORS;
00401     cpl_msg_indent_less() ;
00402     cpl_frameset_delete(objframes);
00403     if(offsets != NULL)
00404         cpl_frameset_delete(offsets);
00405     if(bpm != NULL)
00406         cpl_frameset_delete(bpm);
00407     if(bpmbkg != NULL)
00408         cpl_frameset_delete(bpmbkg);
00409 
00410     /* Save the products */
00411     cpl_msg_info(__func__, "Save the products") ;
00412     cpl_msg_indent_more() ;
00413     if (hawki_step_combine_save(combined, contrib_map, 
00414                                 used_frames, parlist, framelist) != 0)
00415     {
00416         cpl_msg_warning(__func__, "Some error happened saving the data. "
00417                         "Check permisions or disk space") ;
00418         for(idet=0; idet< 2 * HAWKI_NB_DETECTORS; ++idet)
00419             cpl_image_delete(combined_contrib[idet]);
00420         cpl_frameset_delete(used_frames);
00421         cpl_free(combined_contrib);
00422         cpl_msg_indent_less() ;
00423         return -1 ;
00424     }
00425     cpl_msg_indent_less() ;
00426     
00427     /* Return */
00428     for(idet=0; idet< 2 * HAWKI_NB_DETECTORS; ++idet)
00429         cpl_image_delete(combined_contrib[idet]);
00430     cpl_free(combined_contrib);
00431     cpl_frameset_delete(used_frames);
00432 
00433     /* Return */
00434     if (cpl_error_get_code())
00435     {
00436         cpl_msg_error(__func__,
00437                       "HAWK-I pipeline could not recover from previous errors");
00438         return -1 ;
00439     }
00440     else return 0 ;
00441 }
00442 
00443 int hawki_step_combine_retrieve_input_param
00444 (cpl_parameterlist  *  parlist)
00445 {
00446     cpl_parameter   *   par ;
00447     const char      *   sval ;
00448     par = NULL ;
00449     par = cpl_parameterlist_find(parlist,
00450             "hawki.hawki_step_combine.offset_max");
00451     hawki_step_combine_config.offset_max = cpl_parameter_get_int(par);
00452     par = cpl_parameterlist_find(parlist,
00453             "hawki.hawki_step_combine.comb_meth");
00454     sval = cpl_parameter_get_string(par);
00455     if (!strcmp(sval, "union"))
00456         hawki_step_combine_config.comb_meth = CPL_GEOM_UNION;
00457     else if (!strcmp(sval, "inter"))
00458         hawki_step_combine_config.comb_meth = CPL_GEOM_INTERSECT;
00459     else if (!strcmp(sval, "first"))
00460         hawki_step_combine_config.comb_meth = CPL_GEOM_FIRST;
00461     else
00462     {
00463         cpl_msg_error(__func__, "Invalid combine method specified");
00464         return -1;
00465     }
00466     par = cpl_parameterlist_find(parlist,
00467             "hawki.hawki_step_combine.borders");
00468     hawki_step_combine_config.borders = cpl_parameter_get_int(par);
00469     if(hawki_step_combine_config.borders < 0 )
00470     {
00471         cpl_msg_error(__func__, "Borders cannot be less than zero");
00472         return -1;
00473     }
00474     par = cpl_parameterlist_find(parlist, 
00475             "hawki.hawki_step_combine.rej");
00476     sval = cpl_parameter_get_string(par);
00477     if (sscanf(sval, "%d,%d",
00478                &hawki_step_combine_config.rej_low,
00479                &hawki_step_combine_config.rej_high)!=2)
00480     {
00481         return -1;
00482     }
00483     par = cpl_parameterlist_find(parlist, 
00484             "hawki.hawki_step_combine.resamp_kernel");
00485     sval = cpl_parameter_get_string(par);
00486     if (!strcmp(sval, "tanh"))
00487         hawki_step_combine_config.resamp_kernel = CPL_KERNEL_TANH;
00488     else if (!strcmp(sval, "sinc"))
00489         hawki_step_combine_config.resamp_kernel = CPL_KERNEL_SINC;
00490     else if (!strcmp(sval, "sinc2"))
00491         hawki_step_combine_config.resamp_kernel = CPL_KERNEL_SINC2;
00492     else if (!strcmp(sval, "lanczos"))
00493         hawki_step_combine_config.resamp_kernel = CPL_KERNEL_LANCZOS;
00494     else if (!strcmp(sval, "hamming"))
00495         hawki_step_combine_config.resamp_kernel = CPL_KERNEL_HAMMING;
00496     else if (!strcmp(sval, "hann"))
00497         hawki_step_combine_config.resamp_kernel = CPL_KERNEL_HANN;
00498     else if (!strcmp(sval, "default"))
00499         hawki_step_combine_config.resamp_kernel = CPL_KERNEL_DEFAULT;
00500     else
00501     {
00502         cpl_msg_error(__func__, "Invalid resampling kernel specified");
00503         return -1;
00504     }
00505 
00506     return 0;
00507 }
00508 
00509 
00510 
00511 /*----------------------------------------------------------------------------*/
00517 /*----------------------------------------------------------------------------*/
00518 static cpl_image ** hawki_step_combine_apply_comb
00519 (cpl_frameset    * obj,
00520  cpl_frameset    * offsets_frames,
00521  cpl_frameset    * bpm_frame,
00522  cpl_frameset    * bkg_bpm_frames)
00523 {
00524     cpl_image           **  combined_contrib;
00525     cpl_bivector        **  offsets;
00526     cpl_mask             *  bpm_masks[HAWKI_NB_DETECTORS];
00527     int                     idet;
00528     int                     ioff;
00529 
00530     if(offsets_frames == NULL)
00531     {
00532         cpl_bivector        *   offsets_single_chip;
00533         if ((offsets_single_chip = hawki_get_header_tel_offsets(obj)) == NULL) 
00534         {
00535             cpl_msg_error(__func__, "Cannot load the header offsets");
00536             return NULL;
00537         }
00538         offsets = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_bivector *));
00539         for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
00540             offsets[idet] =  cpl_bivector_duplicate(offsets_single_chip);
00541         cpl_bivector_delete(offsets_single_chip);
00542     }
00543     else
00544     {
00545         offsets = hawki_load_refined_offsets
00546             (cpl_frameset_get_first(offsets_frames));
00547         if(offsets == NULL)
00548         {
00549             cpl_msg_error(__func__, "Cannot load the refined offsets");
00550             return NULL;
00551         }
00552     }
00553     /* Get the oposite offsets. This is to change from 
00554      * telescope convention to cpl convention 
00555      * WARNING: It may appear that the img_jitter function 
00556      * does not apply the multiplication by -1, but it really does it in 
00557      * hawki_img_jitter_saa instead of when it reads the offsets */
00558     for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
00559     {
00560         cpl_vector_multiply_scalar(cpl_bivector_get_x(offsets[idet]), -1.0);
00561         cpl_vector_multiply_scalar(cpl_bivector_get_y(offsets[idet]), -1.0);
00562     }
00563     
00564     /* Load the bpm */
00565     if(bpm_frame != NULL)
00566     {
00567         cpl_imagelist *  bpm_images = NULL;
00568         bpm_images = hawki_load_frame
00569             (cpl_frameset_get_first(bpm_frame), CPL_TYPE_INT);
00570         if(bpm_images == NULL)
00571         {
00572             cpl_msg_error(__func__, "Cannot load the bad pixel mask");
00573             return NULL;
00574         }
00575         for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
00576         {
00577             bpm_masks[idet] = cpl_mask_threshold_image_create
00578                 (cpl_imagelist_get(bpm_images, idet), 0.5, 1.5);
00579         }
00580         cpl_imagelist_delete(bpm_images);
00581     }
00582 
00583     /* Create output object */
00584     combined_contrib = cpl_malloc(2 * HAWKI_NB_DETECTORS * sizeof(cpl_image *));
00585  
00586     /* Loop on the detectors */
00587     for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
00588     {
00589         cpl_imagelist   * in ;
00590         cpl_imagelist   * bpm_bkg_im = NULL;
00591         cpl_image      ** comb_contrib_chip ;
00592         double          * offs_est_x ;
00593         double          * offs_est_y ;
00594         double            max_x, max_y ;
00595         double            off_0_x;
00596         double            off_0_y;
00597         int               jdet;
00598         int               iframe;
00599 
00600         cpl_msg_info(__func__, "Combine chip number %d", idet+1) ;
00601         cpl_msg_indent_more() ;
00602         
00603         /* Print the offsets */
00604         offs_est_x = cpl_bivector_get_x_data(offsets[idet]) ;
00605         offs_est_y = cpl_bivector_get_y_data(offsets[idet]) ;
00606         for (ioff=0 ; ioff<cpl_bivector_get_size(offsets[idet]) ; ioff++) {
00607             cpl_msg_info(__func__,"Telescope offsets (Frame %d): %g %g", ioff+1,
00608                     -offs_est_x[ioff], -offs_est_y[ioff]) ;
00609         }
00610 
00611         /* Subtract the first offset to all offsets */
00612         max_x = max_y = 0.0 ;
00613         off_0_x = offs_est_x[0];
00614         off_0_y = offs_est_y[0];
00615         for (ioff=1 ; ioff<cpl_bivector_get_size(offsets[idet]) ; ioff++) 
00616         {
00617             offs_est_x[ioff] -= offs_est_x[0] ;
00618             offs_est_y[ioff] -= offs_est_y[0] ;
00619             if (fabs(offs_est_x[ioff]) > max_x) max_x = fabs(offs_est_x[ioff]);
00620             if (fabs(offs_est_y[ioff]) > max_y) max_y = fabs(offs_est_y[ioff]);
00621         }
00622         offs_est_x[0] = offs_est_y[0] = 0.00 ;
00623 
00624         /* Check if the max offset is not too big */
00625         if (max_x > hawki_step_combine_config.offset_max || 
00626                 max_y > hawki_step_combine_config.offset_max) 
00627         {
00628             cpl_msg_error(__func__,"Sorry, no support for offsets larger than %d",
00629                           hawki_step_combine_config.offset_max);
00630             for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
00631             {
00632                 cpl_bivector_delete(offsets[idet]);
00633                 if(bpm_frame != NULL)
00634                     cpl_mask_delete(bpm_masks[idet]);
00635             }
00636             for(jdet = 0; jdet < idet; ++jdet)
00637             {
00638                 cpl_image_delete(combined_contrib[idet]);
00639                 cpl_image_delete(combined_contrib[idet+HAWKI_NB_DETECTORS]);
00640             }
00641             cpl_free(combined_contrib);
00642             return NULL ;
00643         }
00644 
00645         /* Load the input data */
00646         cpl_msg_info(__func__, "Load the input data") ;
00647         cpl_msg_indent_more();
00648         if ((in = hawki_load_detector(obj, idet+1, CPL_TYPE_FLOAT)) == NULL) {
00649             cpl_msg_error(__func__, "Cannot load chip %d",idet+1);
00650             //TODO: there is probably a memory leak here. It should be checked.
00651             for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
00652             {
00653                 cpl_bivector_delete(offsets[idet]);
00654                 if(bpm_frame != NULL)
00655                     cpl_mask_delete(bpm_masks[idet]);
00656             }
00657             for(jdet = 0; jdet < idet; ++jdet)
00658             {
00659                 cpl_image_delete(combined_contrib[idet]);
00660                 cpl_image_delete(combined_contrib[idet+HAWKI_NB_DETECTORS]);
00661             }
00662             cpl_free(combined_contrib);
00663             cpl_free(offsets);
00664             cpl_msg_indent_less() ;
00665             cpl_msg_indent_less() ;
00666             return NULL ;
00667         }
00668 
00669         /* Load the bad bkg images */
00670         if(bkg_bpm_frames != NULL)
00671         {
00672             cpl_msg_info(__func__, "Load the bad bkg images");
00673             cpl_msg_indent_more() ;
00674             if ((bpm_bkg_im = hawki_load_detector(bkg_bpm_frames, idet+1,
00675                               CPL_TYPE_FLOAT)) == NULL)
00676             {
00677                 cpl_msg_error(__func__, "Cannot load chip %d",idet+1);
00678                 for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
00679                 {
00680                     cpl_bivector_delete(offsets[idet]);
00681                     if(bpm_frame != NULL)
00682                         cpl_mask_delete(bpm_masks[idet]);
00683                 }
00684                 for(jdet = 0; jdet < idet; ++jdet)
00685                 {
00686                     cpl_image_delete(combined_contrib[idet]);
00687                     cpl_image_delete(combined_contrib[idet+HAWKI_NB_DETECTORS]);
00688                 }
00689                 cpl_free(combined_contrib);
00690                 cpl_imagelist_delete(in);
00691                 cpl_free(offsets);
00692                 cpl_msg_indent_less() ;
00693                 cpl_msg_indent_less() ;
00694                 return NULL ;
00695             }
00696             cpl_msg_indent_less() ;
00697         }
00698         cpl_msg_indent_less() ;
00699         
00700         /* Add the general bpm or background bpms in case they were specified */
00701         if(bpm_frame != NULL || bkg_bpm_frames != NULL)
00702         {
00703             for(iframe = 0 ; iframe <cpl_imagelist_get_size(in) ; ++iframe)
00704             {
00705                 cpl_mask  * final_mask;
00706                 cpl_image * target_image =  cpl_imagelist_get(in, iframe);
00707                 final_mask = cpl_mask_new(cpl_image_get_size_x(target_image),
00708                                           cpl_image_get_size_y(target_image));
00709                 //Add the common bpm
00710                 if(bpm_frame != NULL)
00711                     cpl_mask_or(final_mask, bpm_masks[idet]);
00712                 //Add the background mask if provided
00713                 if(bkg_bpm_frames != NULL)
00714                 {
00715                     cpl_mask * bpm_bkg_mask = 
00716                         cpl_mask_threshold_image_create
00717                           (cpl_imagelist_get(bpm_bkg_im, iframe), 0.5, FLT_MAX);
00718                     cpl_mask_or(final_mask, bpm_bkg_mask);
00719                     cpl_mask_delete(bpm_bkg_mask);
00720                 }
00721                 cpl_image_reject_from_mask(target_image, final_mask);
00722                 cpl_mask_delete(final_mask);
00723             }
00724         }
00725         
00726         if(bkg_bpm_frames != NULL)
00727             cpl_imagelist_delete(bpm_bkg_im);
00728 
00729         /* Apply the shift and add */
00730         cpl_msg_info(__func__, "Shift and add") ;
00731         cpl_msg_indent_more() ;
00732         comb_contrib_chip = hawki_step_combine_chip(in, offsets[idet], 
00733                 &(hawki_step_combine_output.combined_pos_x[idet]),
00734                 &(hawki_step_combine_output.combined_pos_y[idet])) ;
00735         if (comb_contrib_chip == NULL) 
00736         {
00737             cpl_msg_error(__func__, "Cannot apply the shift and add") ;
00738             cpl_imagelist_delete(in) ;
00739             for(jdet = 0; jdet < HAWKI_NB_DETECTORS; ++jdet)
00740                 cpl_bivector_delete(offsets[jdet]);
00741             {
00742                 cpl_image_delete(combined_contrib[idet]);
00743                 cpl_image_delete(combined_contrib[idet+HAWKI_NB_DETECTORS]);
00744             }
00745             cpl_free(combined_contrib);
00746             cpl_free(offsets);
00747             cpl_msg_indent_less() ;
00748             cpl_msg_indent_less() ;
00749             return NULL ;
00750         }
00751         
00752         /* The cumoffset have the opposite criteria as cpl */
00753         hawki_step_combine_output.combined_cumoffset_x[idet] = 
00754             hawki_step_combine_output.combined_pos_x[idet] - off_0_x;
00755         hawki_step_combine_output.combined_cumoffset_y[idet] = 
00756             hawki_step_combine_output.combined_pos_y[idet] - off_0_y;
00757         cpl_imagelist_delete(in) ;
00758         cpl_msg_indent_less() ;
00759 
00760         /* Interpolate bad pixels */
00761         hawki_step_combine_interpolate_badpix(comb_contrib_chip[0]);        
00762 
00763         /* Put the results in the image list */
00764         combined_contrib[idet] = comb_contrib_chip[0];
00765         combined_contrib[idet+HAWKI_NB_DETECTORS] = comb_contrib_chip[1];
00766         cpl_free(comb_contrib_chip);
00767         cpl_msg_indent_less() ;
00768     }
00769     
00770     /* Compute the mean airmass */
00771     hawki_step_combine_output.mean_airmass = hawki_get_mean_airmass(obj);
00772     
00773     for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
00774     {
00775         cpl_bivector_delete(offsets[idet]);
00776         if(bpm_frame != NULL)
00777             cpl_mask_delete(bpm_masks[idet]);
00778     }
00779     cpl_free(offsets);
00780     return combined_contrib;
00781 }
00782 
00783 /*----------------------------------------------------------------------------*/
00792 /*----------------------------------------------------------------------------*/
00793 static cpl_image ** hawki_step_combine_chip(
00794         cpl_imagelist   *  in,
00795         cpl_bivector    *  offsets,
00796         double          *  pos_x,
00797         double          *  pos_y)
00798 {
00799     cpl_image        **  combined_contrib;
00800     cpl_imagelist    *   in_ext ;
00801     cpl_image        *   tmp1 ;
00802     cpl_image        *   tmp2 ;
00803     int                  nfiles, nx, ny ;
00804     int                  i;
00805 
00806     /* Check entries */
00807     if (pos_x == NULL || pos_y == NULL) return NULL ;
00808     if (offsets == NULL) return NULL ;
00809 
00810     /* Get the number of images */
00811     nfiles = cpl_imagelist_get_size(in) ;
00812     if (cpl_bivector_get_size(offsets) != nfiles) {
00813         cpl_msg_error(__func__, "Number of refined offsets in table """
00814                       "is different than number of frames to combine"); 
00815         return NULL ;
00816     }
00817     
00818     /* Discard the pixels on the sides */
00819     if (hawki_step_combine_config.borders > 0) {
00820         nx = cpl_image_get_size_x(cpl_imagelist_get(in, 0)) ;
00821         ny = cpl_image_get_size_y(cpl_imagelist_get(in, 0)) ;
00822         in_ext = cpl_imagelist_new() ;
00823         for (i=0 ; i<cpl_imagelist_get_size(in) ; i++) {
00824             tmp1 = cpl_imagelist_get(in, i) ;
00825             tmp2 = cpl_image_extract(tmp1, 
00826                     hawki_step_combine_config.borders+1, 
00827                     hawki_step_combine_config.borders+1, 
00828                     nx-hawki_step_combine_config.borders, 
00829                     ny-hawki_step_combine_config.borders) ;
00830             cpl_imagelist_set(in_ext, tmp2, i) ;
00831         }
00832     }
00833     else
00834     {
00835         in_ext = cpl_imagelist_duplicate(in);
00836     }
00837 
00838     /* Apply the shift & add */
00839     cpl_msg_info(__func__, "Recombine the images set") ;
00840     cpl_msg_indent_more() ;
00841     if ((combined_contrib=cpl_geom_img_offset_saa(in_ext, offsets,
00842             hawki_step_combine_config.resamp_kernel, 
00843             hawki_step_combine_config.rej_low,
00844             hawki_step_combine_config.rej_high,
00845             hawki_step_combine_config.comb_meth,
00846             pos_x, pos_y)) == NULL) {
00847         cpl_msg_error(cpl_func, "Cannot apply the shift and add") ;
00848         cpl_msg_indent_less();
00849         return NULL;
00850     }
00851     cpl_msg_indent_less();
00852     *pos_x -= hawki_step_combine_config.borders;
00853     *pos_y -= hawki_step_combine_config.borders;
00854 
00855     /* Free and return */
00856     cpl_imagelist_delete(in_ext);
00857     return combined_contrib;
00858 }
00859 
00860 /*----------------------------------------------------------------------------*/
00866 /*----------------------------------------------------------------------------*/
00867 static int hawki_step_combine_interpolate_badpix
00868 (cpl_image           *  image)
00869 {
00870     int nbadpixels = cpl_image_count_rejected(image); 
00871     if(nbadpixels !=0)
00872         cpl_msg_info(__func__,"Number of pixels with no combined value available: %d ",
00873                      nbadpixels);
00874     if(cpl_image_count_rejected(image) > 0)
00875     {
00876         //I use this even if DFS08929 is still not solved
00877         cpl_detector_interpolate_rejected(image);
00878     }
00879     return 0;
00880 }
00881 
00882 /*----------------------------------------------------------------------------*/
00891 /*----------------------------------------------------------------------------*/
00892 static int hawki_step_combine_save
00893 (cpl_image           ** combined,
00894  cpl_image           ** contrib_map,
00895  cpl_frameset        *  used_frames,
00896  cpl_parameterlist   *  parlist,
00897  cpl_frameset        *  recipe_frameset)
00898 {
00899     cpl_propertylist    **  extproplists ;
00900     const cpl_frame     *   ref_frame ;
00901     cpl_propertylist    *   wcslist ;
00902     cpl_propertylist    *   inputlist ;
00903     double                  crpix1, crpix2 ;
00904     int                     ext_nb ;
00905     const char          *   recipe_name = "hawki_step_combine" ;
00906     int                     idet;
00907     cpl_errorstate          error_prevstate = cpl_errorstate_get();
00908 
00909     /* Get a reference frame for the WCS keys */
00910     ref_frame = irplib_frameset_get_first_from_group
00911         (recipe_frameset, CPL_FRAME_GROUP_RAW) ;
00912     
00913     if(ref_frame == NULL)
00914     {
00915         cpl_msg_error(__func__, "Cannot get a reference frame");
00916         return -1;
00917     }
00918 
00919     /* Create the QC lists */
00920     extproplists = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_propertylist*)) ;
00921     for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++) 
00922     {
00923 
00924         /* Initialize qclists */
00925         extproplists[idet] = cpl_propertylist_new() ;
00926 
00927         /* Get the extension number */
00928         ext_nb=hawki_get_ext_from_detector(cpl_frame_get_filename(ref_frame), idet+1);
00929 
00930         /* Handle WCS keys */
00931         wcslist = cpl_propertylist_load_regexp(
00932                 cpl_frame_get_filename(ref_frame), ext_nb, HAWKI_HEADER_WCS, 0);
00933 
00934         /* Update WCS and write them */
00935         crpix1 = cpl_propertylist_get_double(wcslist, "CRPIX1"); 
00936         crpix1 += hawki_step_combine_output.combined_pos_x[idet];
00937         cpl_propertylist_update_double(wcslist, "CRPIX1", crpix1) ;
00938         crpix2 = cpl_propertylist_get_double(wcslist, "CRPIX2"); 
00939         crpix2 += hawki_step_combine_output.combined_pos_y[idet] ;
00940         cpl_propertylist_update_double(wcslist, "CRPIX2", crpix2) ;
00941         cpl_propertylist_copy_property_regexp
00942             (extproplists[idet], wcslist, HAWKI_HEADER_WCS, 0);
00943         cpl_propertylist_delete(wcslist) ;
00944         
00945         /* Keywords for the relative position of the combined image */
00946         cpl_propertylist_append_double
00947             (extproplists[idet], "ESO QC COMBINED CUMOFFSETX",
00948              hawki_step_combine_output.combined_cumoffset_x[idet]);
00949         cpl_propertylist_append_double
00950             (extproplists[idet], "ESO QC COMBINED CUMOFFSETY",
00951              hawki_step_combine_output.combined_cumoffset_y[idet]);
00952         cpl_propertylist_append_double
00953             (extproplists[idet], "ESO QC COMBINED POSX",
00954              hawki_step_combine_output.combined_pos_x[idet]);
00955         cpl_propertylist_append_double
00956             (extproplists[idet], "ESO QC COMBINED POSY",
00957              hawki_step_combine_output.combined_pos_y[idet]);
00958         cpl_propertylist_append_double
00959             (extproplists[idet], "ESO QC AIRMASS MEAN",
00960              hawki_step_combine_output.mean_airmass);
00961 
00962         /* Propagate some keywords from input raw frame extensions */
00963         inputlist = cpl_propertylist_load_regexp(
00964                 cpl_frame_get_filename(ref_frame), ext_nb,
00965                 HAWKI_HEADER_EXT_FORWARD, 0) ;
00966         cpl_propertylist_append(extproplists[idet], inputlist);
00967         cpl_propertylist_delete(inputlist) ;
00968     }
00969 
00970     /* Write the combined image */
00971     if(hawki_images_save(recipe_frameset,
00972                          parlist,
00973                          used_frames,
00974                          (const cpl_image **)combined,
00975                          recipe_name,
00976                          HAWKI_CALPRO_COMBINED,
00977                          HAWKI_PROTYPE_COMBINED, 
00978                          NULL,
00979                          (const cpl_propertylist**)extproplists,
00980                          "hawki_step_combine.fits")  != 0)
00981     {
00982         for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++) {
00983             cpl_propertylist_delete(extproplists[idet]) ;
00984         }
00985         cpl_free(extproplists) ;
00986         return -1;
00987     }
00988 
00989     /* Write the contrib map */
00990     if(hawki_images_save(recipe_frameset,
00991                          parlist,
00992                          used_frames,
00993                          (const cpl_image **)contrib_map,
00994                          recipe_name,
00995                          HAWKI_CALPRO_COMB_CONTRIB_MAP,
00996                          HAWKI_PROTYPE_COMB_CONTRIB_MAP,
00997                          NULL,
00998                          (const cpl_propertylist**)extproplists,
00999                          "hawki_step_combine_contrib_map.fits")  != 0)
01000     {
01001         for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++) {
01002             cpl_propertylist_delete(extproplists[idet]);
01003         }
01004         cpl_free(extproplists) ;
01005         return -1;
01006     }
01007 
01008     /* Free and return */
01009     for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++) {
01010         cpl_propertylist_delete(extproplists[idet]) ;
01011     }
01012     cpl_free(extproplists) ;
01013 
01014     if(!cpl_errorstate_is_equal(error_prevstate))
01015     {
01016         cpl_errorstate_set(CPL_ERROR_NONE);
01017         return 1;
01018     }
01019 
01020     return  0;
01021 }
01022