isaac_img_jitter.c

00001 /* $Id: isaac_img_jitter.c,v 1.74 2012/01/12 12:00:42 llundin Exp $
00002  *
00003  * This file is part of the ISAAC 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: llundin $
00023  * $Date: 2012/01/12 12:00:42 $
00024  * $Revision: 1.74 $
00025  * $Name: isaac-6_1_0 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*-----------------------------------------------------------------------------
00033                                 Includes
00034  -----------------------------------------------------------------------------*/
00035 
00036 #include <string.h>
00037 #include <math.h>
00038 #include <cpl.h>
00039 
00040 #include "irplib_plugin.h"
00041 #include "irplib_utils.h"
00042 #include "irplib_calib.h"
00043 
00044 #include "isaac_utils.h"
00045 #include "isaac_pfits.h"
00046 #include "isaac_dfs.h"
00047 
00048 /*-----------------------------------------------------------------------------
00049                                 Define
00050  -----------------------------------------------------------------------------*/
00051 
00052 #define RECIPE_STRING "isaac_img_jitter"
00053 
00054 #ifndef NEGLIG_OFF_DIFF
00055 #define NEGLIG_OFF_DIFF     0.1
00056 #endif
00057 
00058 #define SQR(x) ((x)*(x))
00059 
00060 #ifdef ISAAC_IMG_ERR_ESTIMATE
00061 #ifndef ISAAC_IMG_GAIN
00062 /* FIXME: Empirically determined. Use header info (arm dependent) */
00063 #define ISAAC_IMG_GAIN 4.5
00064 #endif
00065 
00066 #ifndef ISAAC_IMG_SATURATION_LEVEL
00067 /* FIXME: Empirically determined */
00068 #define ISAAC_IMG_SATURATION_LEVEL 40000.0
00069 #endif
00070 #endif
00071 
00072 
00073 /*-----------------------------------------------------------------------------
00074                             Private Function prototypes
00075  -----------------------------------------------------------------------------*/
00076 
00077 static cpl_image ** isaac_img_jitter_reduce(cpl_frameset *,
00078                                             const cpl_parameterlist *,
00079                                             const cpl_frameset *,
00080                                             const cpl_frameset *, 
00081                                             const char *, const char *,
00082                                             const char *, cpl_vector **);
00083 static cpl_imagelist ** isaac_img_jitter_load(const cpl_frameset *,
00084                                               const cpl_frameset *);
00085 static cpl_vector * isaac_img_jitter_sky(cpl_imagelist **, cpl_imagelist *);
00086 static cpl_vector * isaac_img_jitter_sky_running(cpl_imagelist **); 
00087 static cpl_image ** isaac_img_jitter_saa_nochop(cpl_imagelist *,
00088                                                 const cpl_frameset *);
00089 static cpl_image ** isaac_img_jitter_saa_chop(cpl_imagelist *,
00090                                               const cpl_frameset *);
00091 static int isaac_img_jitter_chopping_classif(cpl_bivector *, int **, int **);
00092 static cpl_error_code isaac_img_jitter_sub_row_median(cpl_image *);
00093 static cpl_table * isaac_img_jitter_qc(cpl_image *);
00094 static double isaac_img_jitter_get_mode(cpl_vector *);
00095 static cpl_error_code isaac_img_jitter_save(cpl_frameset *, const cpl_image *,
00096                                             const cpl_image *,
00097                                             const cpl_table *,
00098                                             const cpl_vector *, 
00099                                             const cpl_parameterlist *);
00100 
00101 cpl_recipe_define(isaac_img_jitter, ISAAC_BINARY_VERSION,
00102                   "Lars Lundin", PACKAGE_BUGREPORT, "2008", 
00103                   "ISAAC imaging jitter recipe",
00104                   RECIPE_STRING " -- ISAAC imaging jitter recipe.\n"
00105                   "The files listed in the Set Of Frames (sof-file) " 
00106                   "must be tagged:\n"
00107                   "raw-file.fits "  ISAAC_IMG_JITTER_OBJ_RAW  " or\n"
00108                   "raw-file.fits "  ISAAC_IMG_JITTER_SKY_RAW  " or\n"
00109                   "raw-file.fits "  ISAAC_IMG_JITTER_CHOP_RAW " or\n"
00110                   "flat-file.fits " ISAAC_CALIB_FLAT          " or\n"
00111                   "bpm-file.fits "  ISAAC_CALIB_BPM           " or\n"
00112                   "dark-file.fits " ISAAC_CALIB_DARK          "\n");
00113 
00114 /*-----------------------------------------------------------------------------
00115                             Static variables
00116  -----------------------------------------------------------------------------*/
00117 
00118 static struct {
00119     /* Inputs */
00120     const char      *   offsets;
00121     const char      *   objects;
00122     int                 oddeven;
00123     int                 sky_minnb;
00124     int                 sky_halfw;
00125     int                 sky_rejmin;
00126     int                 sky_rejmax;
00127     int                 sx;
00128     int                 sy;
00129     int                 mx;
00130     int                 my;
00131     cpl_geom_combine    comb_meth;
00132     int                 saa_refine;
00133     int                 rej_low;
00134     int                 rej_high;
00135     int                 row_med;
00136     int                 chopping;
00137     /* Outputs */
00138     double          pixscale;
00139     double          dit;
00140     int             nb_obj_frames;
00141     int             nb_sky_frames;
00142     int             nb_rej_frames;
00143     double          iq;
00144     int             nbobjs;
00145     double          fwhm_pix;
00146     double          fwhm_arcsec;
00147     double          fwhm_mode;
00148     double          angle_med;
00149     double          ellip_med;
00150 } isaac_img_jitter_config;
00151 
00152 /*-----------------------------------------------------------------------------
00153                                 Functions code
00154  -----------------------------------------------------------------------------*/
00155 
00156 /*----------------------------------------------------------------------------*/
00164 /*----------------------------------------------------------------------------*/
00165 static
00166 cpl_error_code isaac_img_jitter_fill_parameterlist(cpl_parameterlist * self)
00167 {
00168     const char * context = PACKAGE "." RECIPE_STRING;
00169     cpl_error_code err;
00170 
00171     cpl_ensure_code(self, CPL_ERROR_NULL_INPUT);
00172 
00173     /* Fill the parameters list */
00174 
00175     /* --off */
00176     err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
00177                                           "offsets", NULL, "off", context,
00178                        "An optional ASCII specification of the offsets "
00179                        "in case those in FITS-headers are missing or wrong. "
00180                        "The file must consist of one line per object FITS-"
00181                        "file and each line must consist of two "
00182                        "numbers which represent the shift in pixels of that "
00183                        "image relative to the first image. The first line "
00184                        "should thus comprise two zeros. Correct FITS-header "
00185                        "offsets mean that the i'th X offset can be gotten "
00186                        "from Xoffset_0 - Xoffset_i, where Xoffset_i is the "
00187                        "value of ESO SEQ CUMOFFSETX and likewise for Y.");
00188     cpl_ensure_code(!err, err);
00189 
00190     /* --objs */
00191     err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
00192                                           "objects", NULL, "objs", context,
00193                                           "objects file");
00194     cpl_ensure_code(!err, err);
00195 
00196     /* --oddeven */
00197     err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING, "oddeven",
00198                                         CPL_FALSE, NULL, context, "Flag to "
00199                                         "correct the oddeven column effect");
00200     cpl_ensure_code(!err, err);
00201 
00202     /* --sky_par */
00203     err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
00204                                           "sky_par", "10,7,3,3", NULL, context,
00205                                           "Rejection parameters for sky "
00206                                           "filtering");
00207     cpl_ensure_code(!err, err);
00208 
00209     /* --xcorr */
00210     err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING, "xcorr",
00211                                           "40,40,65,65", NULL, context, "Cross "
00212                                           "correlation search and measure "
00213                                           "sizes");
00214     cpl_ensure_code(!err, err);
00215 
00216     /* --comb_meth */
00217     err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
00218                                           "comb_meth", "union", NULL, context,
00219                                           "union / inter / first");
00220     cpl_ensure_code(!err, err);
00221  
00222     /* --saa_refine */
00223     err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
00224                                         "saa_refine", CPL_TRUE, NULL, context,
00225                                         "Flag to refine the offsets");
00226     cpl_ensure_code(!err, err);
00227 
00228     /* --rej */
00229     err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING, "rej",
00230                                           "2,2", NULL, context, "Low and high "
00231                                           "number of rejected values");
00232     cpl_ensure_code(!err, err);
00233 
00234     /* --row_med */
00235     err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
00236                                         "row_med", CPL_TRUE, NULL, context,
00237                                         "Flag to subtract the median of each "
00238                                         "row");
00239     cpl_ensure_code(!err, err);
00240 
00241     return CPL_ERROR_NONE;
00242 }
00243 
00244 
00245 
00246 /*----------------------------------------------------------------------------*/
00254 /*----------------------------------------------------------------------------*/
00255 static int isaac_img_jitter(cpl_frameset            * framelist,
00256                             const cpl_parameterlist * parlist)
00257 {
00258     const char   * sval;
00259     const char   * badpix;
00260     const char   * flat;
00261     const char   * dark;
00262     cpl_frameset * objframes = NULL;
00263     cpl_frameset * skyframes = NULL;
00264     cpl_image   ** combined = NULL;
00265     cpl_table    * objs_stats = NULL;
00266     cpl_vector   * sky_bg = NULL;
00267 
00268     bug_if(0);
00269 
00270     /* Initialise */
00271     isaac_img_jitter_config.pixscale = -1.0;
00272     isaac_img_jitter_config.dit = -1.0;
00273     isaac_img_jitter_config.iq = -1.0;
00274     isaac_img_jitter_config.nbobjs = -1;
00275     isaac_img_jitter_config.fwhm_pix = -1.0;
00276     isaac_img_jitter_config.fwhm_arcsec = -1.0;
00277     isaac_img_jitter_config.fwhm_mode = -1.0;
00278     isaac_img_jitter_config.offsets = NULL;
00279     isaac_img_jitter_config.objects = NULL;
00280     isaac_img_jitter_config.nb_obj_frames = 0;
00281     isaac_img_jitter_config.nb_rej_frames = 0;
00282     isaac_img_jitter_config.nb_sky_frames = 0;
00283 
00284     /* Retrieve input parameters */
00285     /* Offsets */
00286     isaac_img_jitter_config.offsets
00287         = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
00288                                        "offsets");
00289 
00290     /* Objects */
00291     isaac_img_jitter_config.objects
00292         = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
00293                                        "objects");
00294 
00295     /* Oddeven */
00296     isaac_img_jitter_config.oddeven
00297         = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
00298                                        "oddeven");
00299 
00300     /* Rejection parameters for sky filtering */
00301     sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
00302                                        "sky_par");
00303 
00304     bug_if(sval == NULL);
00305 
00306     skip_if (sscanf(sval, "%d,%d,%d,%d",
00307                     &isaac_img_jitter_config.sky_minnb,
00308                     &isaac_img_jitter_config.sky_halfw,
00309                     &isaac_img_jitter_config.sky_rejmin,
00310                     &isaac_img_jitter_config.sky_rejmax) != 4);
00311 
00312     /* Cross correlation windows parameters */
00313     sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
00314                                        "xcorr");
00315     bug_if(sval == NULL);
00316 
00317     skip_if (sscanf(sval, "%d,%d,%d,%d",
00318                     &isaac_img_jitter_config.sx,
00319                     &isaac_img_jitter_config.sy,
00320                     &isaac_img_jitter_config.mx,
00321                     &isaac_img_jitter_config.my) != 4);
00322 
00323     /* --comb_meth */
00324     sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
00325                                        "comb_meth");
00326     bug_if(sval == NULL);
00327     if (!strcmp(sval, "union")) 
00328         isaac_img_jitter_config.comb_meth = CPL_GEOM_UNION;
00329     else if (!strcmp(sval, "inter"))
00330         isaac_img_jitter_config.comb_meth = CPL_GEOM_INTERSECT;
00331     else if (!strcmp(sval, "first"))
00332         isaac_img_jitter_config.comb_meth = CPL_GEOM_FIRST;
00333     else {
00334         cpl_msg_error(cpl_func, "Invalid combine method specified");
00335         skip_if(1);
00336     }
00337     
00338     /* Refine of offsets */
00339     isaac_img_jitter_config.saa_refine
00340         = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
00341                                         "saa_refine");
00342 
00343      /* Number of rejected values in stacking */
00344     sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
00345                                        "rej");
00346     bug_if(sval == NULL);
00347     skip_if (sscanf(sval, "%d,%d",
00348                     &isaac_img_jitter_config.rej_low,
00349                     &isaac_img_jitter_config.rej_high) != 2);
00350 
00351     /* Row median */
00352     isaac_img_jitter_config.row_med
00353         = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
00354                                         "row_med");
00355 
00356     /* Identify the RAW and CALIB frames in the input frameset */
00357     skip_if (isaac_dfs_set_groups(framelist));
00358 
00359     /* Retrieve calibration data */
00360     flat   = isaac_extract_filename(framelist, ISAAC_CALIB_FLAT);
00361     dark   = isaac_extract_filename(framelist, ISAAC_CALIB_DARK);
00362     badpix = isaac_extract_filename(framelist, ISAAC_CALIB_BPM);
00363     
00364     /* Retrieve raw frames */
00365     if ((objframes = isaac_extract_frameset(framelist,
00366                     ISAAC_IMG_JITTER_OBJ_RAW)) != NULL) {
00367         isaac_img_jitter_config.chopping = 0;
00368     } else if ((objframes = isaac_extract_frameset(framelist,
00369                     ISAAC_IMG_JITTER_CHOP_RAW)) != NULL) {
00370         isaac_img_jitter_config.chopping = 1;
00371     } else {
00372         cpl_msg_error(cpl_func, "Cannot find objs frames in the input list");
00373         skip_if(1);
00374     }
00375     skyframes = isaac_extract_frameset(framelist, ISAAC_IMG_JITTER_SKY_RAW);
00376     
00377     /* Apply the reduction */
00378     cpl_msg_info(cpl_func, "Apply the data recombination");
00379     cpl_msg_indent_more();
00380     if ((combined = isaac_img_jitter_reduce(framelist, parlist, objframes,
00381                                             skyframes, flat,
00382                                             dark, badpix, &sky_bg)) == NULL) {
00383         cpl_msg_error(cpl_func, "Cannot recombine the data");
00384         cpl_msg_indent_less();
00385         skip_if(1);
00386     }
00387     cpl_msg_indent_less();
00388    
00389     /* Compute QC parameters from the combined image */
00390     cpl_msg_info(cpl_func, "Compute QC parameters from the combined image");
00391     cpl_msg_indent_more();
00392     if ((objs_stats = isaac_img_jitter_qc(combined[0])) == NULL) {
00393         cpl_msg_warning(cpl_func, "Cannot compute all parameters");
00394     }
00395     cpl_msg_indent_less();
00396     
00397     /* Save the products */
00398     cpl_msg_info(cpl_func, "Save the products");
00399     skip_if (isaac_img_jitter_save(framelist, combined[0], combined[1],
00400                                    objs_stats, sky_bg, parlist));
00401     
00402     end_skip;
00403 
00404     cpl_frameset_delete(objframes);
00405     cpl_frameset_delete(skyframes);
00406     if (combined != NULL) {
00407         cpl_image_delete(combined[0]);
00408         cpl_image_delete(combined[1]);
00409         cpl_free(combined);
00410     }
00411     cpl_table_delete(objs_stats);
00412     cpl_vector_delete(sky_bg);
00413 
00414     return cpl_error_get_code();
00415 }
00416 
00417 /*----------------------------------------------------------------------------*/
00428 /*----------------------------------------------------------------------------*/
00429 static
00430 cpl_image ** isaac_img_jitter_reduce(cpl_frameset            * frameset,
00431                                      const cpl_parameterlist * parlist,
00432                                      const cpl_frameset    *   obj,
00433                                      const cpl_frameset    *   sky,
00434                                      const char      *   flat,
00435                                      const char      *   dark,
00436                                      const char      *   bpm,
00437                                      cpl_vector      **  skybg)
00438 {
00439 #ifdef ISAAC_IMG_ERR_ESTIMATE
00440     cpl_propertylist * qclist;
00441     cpl_imagelist    * err;
00442 #endif
00443     cpl_imagelist   **  in;
00444     cpl_image       **  combined;
00445     cpl_imagelist   *   corrected;
00446     cpl_image       *   cur_im;
00447     int                 i;
00448 
00449     cpl_ensure(frameset != NULL, CPL_ERROR_NULL_INPUT, NULL);
00450     cpl_ensure(parlist  != NULL, CPL_ERROR_NULL_INPUT, NULL);
00451 
00452     /* Initialise */
00453     *skybg = NULL;
00454     combined = NULL;
00455     
00456     /* Load the input data */
00457     cpl_msg_info(cpl_func, "Load the input data");
00458     cpl_msg_indent_more();
00459     if ((in = isaac_img_jitter_load(obj, sky)) == NULL) {
00460         cpl_msg_error(cpl_func, "Cannot load input data");
00461         cpl_msg_indent_less();
00462         return NULL;
00463     }
00464     cpl_msg_indent_less();
00465 
00466     /* Apply the odd-even correction */
00467     if (isaac_img_jitter_config.oddeven) {
00468         cpl_msg_info(cpl_func, "Apply the odd-even effect correction");
00469         cpl_msg_indent_more();
00470         corrected = cpl_imagelist_new();
00471         for (i=0; i<cpl_imagelist_get_size(in[0]); i++) {
00472             cpl_msg_info(cpl_func, "Correct object frame nb %d", i+1);
00473             if ((cur_im = isaac_oddeven_correct(
00474                             cpl_imagelist_get(in[0], i))) == NULL) {
00475                 cpl_msg_warning(cpl_func,"Problem in odd-even corr. %d",i+1);
00476                 cpl_imagelist_delete(corrected);
00477                 corrected = NULL;
00478                 break;
00479             } 
00480             cpl_imagelist_set(corrected, cur_im, i);
00481         }
00482         /* Odd/even correction successfull */
00483         if (corrected != NULL) {
00484             cpl_imagelist_delete(in[0]);
00485             in[0] = corrected;
00486         }
00487         cpl_msg_indent_less();
00488     }
00489 
00490 #ifdef ISAAC_IMG_ERR_ESTIMATE
00491     /*----------------------------------------------------------------------------*/
00492     /* Save the imagelist before applying the correction */
00493 
00494     err = cpl_imagelist_duplicate(in[0]);
00495 
00496     /* Dark correction */
00497     if (dark != NULL) {
00498         cpl_image * dark_image;
00499 
00500         cpl_msg_info(cpl_func, "Error propagation: Subtract the dark to the images");
00501         /* Load the dark image */
00502         if ((dark_image = cpl_image_load(dark, CPL_TYPE_FLOAT, 0, 0)) == NULL) {
00503             cpl_msg_error(cpl_func, "Cannot load the dark %s", dark);
00504             return NULL;
00505         }
00506         /* Apply the dark correction to the images */
00507         if (cpl_imagelist_subtract_image(err, dark_image)!=CPL_ERROR_NONE) {
00508             cpl_msg_error(cpl_func, "Cannot apply the dark to the images");
00509             cpl_image_delete(dark_image);
00510             return NULL;
00511         }
00512         cpl_image_delete(dark_image);
00513     }
00514 
00515 
00516     /* Apply the bad pixel mask requested */
00517     if (bpm != NULL) {
00518         cpl_image * bpm_im;
00519         cpl_msg_info(cpl_func, "Error propagation: Correct the bad pixels in the images");
00520         /* Load the bad pixels image */
00521         if ((bpm_im = cpl_image_load(bpm, CPL_TYPE_INT, 0, 0)) == NULL) {
00522             cpl_msg_error(cpl_func, "Cannot load the bad pixel map %s", bpm);
00523             return NULL;
00524         }
00525         /* Convert the map from integer to double and invert */
00526 
00527         cpl_image_cast(bpm_im, CPL_TYPE_DOUBLE);
00528         cpl_image_threshold(bpm_im, 0.4, 0.6, 1, 0);
00529 
00530         cpl_imagelist_multiply_image(err, bpm_im);
00531 
00532         /*        cpl_image_save(bpm_im,"test.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_CREATE);*/
00533         cpl_image_delete(bpm_im);
00534     }
00535 
00536     cpl_imagelist_threshold(err, 1, ISAAC_IMG_SATURATION_LEVEL,
00537                             FLT_MAX, FLT_MAX);
00538     cpl_imagelist_divide_scalar(err, ISAAC_IMG_GAIN);
00539     cpl_imagelist_power(err, 0.5);
00540 
00541     /* Flat-field correction */
00542     if (flat != NULL) {
00543         cpl_image * flat_image;
00544         cpl_msg_info(cpl_func, "Error propagation: Divide the images by the flatfield");
00545         /* Load the flat image */
00546         if ((flat_image = cpl_image_load(flat, CPL_TYPE_FLOAT, 0, 0)) == NULL) {
00547             cpl_msg_error(cpl_func, "Cannot load the flat field %s", flat);
00548             return NULL;
00549         }
00550         /* Apply the flatfield correction to the images */
00551         if (cpl_imagelist_divide_image(err, flat_image)!=CPL_ERROR_NONE) {
00552             cpl_msg_error(cpl_func, "Cannot apply the flatfield to the images");
00553             cpl_image_delete(flat_image);
00554             return NULL;
00555         }
00556         cpl_image_delete(flat_image);
00557     }
00558     cpl_imagelist_threshold(err, 1, ISAAC_IMG_SATURATION_LEVEL,
00559                             FLT_MAX, FLT_MAX);
00560 
00561     /*----------------------------------------------------------------------------*/
00562 #endif
00563 
00564     /* Apply the calibrations */
00565     if (flat || dark || bpm) {
00566         cpl_msg_info(cpl_func, "Apply the calibrations");
00567         cpl_msg_indent_more();
00568         if (irplib_flat_dark_bpm_calib(in[0], flat, dark, bpm) == -1) {
00569             /* Calibrate the objects */
00570             cpl_msg_error(cpl_func, "Cannot calibrate the objects");
00571             cpl_imagelist_delete(in[0]);
00572             if (in[1]) cpl_imagelist_delete(in[1]);
00573             cpl_free(in);
00574             cpl_msg_indent_less();
00575             return NULL;
00576         }
00577         if (in[1]) {
00578             if (irplib_flat_dark_bpm_calib(in[1], flat, dark, bpm) == -1) {
00579                 /* Calibrate the sky */
00580                 cpl_msg_error(cpl_func, "Cannot calibrate the sky");
00581                 cpl_imagelist_delete(in[0]);
00582                 if (in[1]) cpl_imagelist_delete(in[1]);
00583                 cpl_free(in);
00584                 cpl_msg_indent_less();
00585                 return NULL;
00586             }
00587         }
00588         cpl_msg_indent_less();
00589     }
00590 
00591 
00592 #ifdef ISAAC_IMG_ERR_ESTIMATE
00593     /* Save the imagelist as intermediate product */
00594 
00595     qclist = cpl_propertylist_new();
00596 
00597     cpl_propertylist_update_string(qclist, CPL_DFS_PRO_CATG, "ISAAC_IMAGELIST");
00598     if(cpl_dfs_save_imagelist(frameset,
00599                               NULL,
00600                               parlist,
00601                               frameset,
00602                               NULL,
00603                               in[0],
00604                               CPL_BPP_IEEE_FLOAT,
00605                               RECIPE_STRING,
00606                               qclist,
00607                               NULL,
00608                               PACKAGE "/" PACKAGE_VERSION,
00609                               "isaac_img_imagelist.fits")) {
00610         /* Propagate the error */
00611         (void)cpl_error_set_where(cpl_func);
00612     }
00613 
00614     cpl_propertylist_update_string(qclist, CPL_DFS_PRO_CATG, "ISAAC_IMAGELISTERR");
00615     if(cpl_dfs_save_imagelist(frameset,
00616                               NULL,
00617                               parlist,
00618                               frameset,
00619                               NULL,
00620                               err,
00621                               CPL_BPP_IEEE_FLOAT,
00622                               RECIPE_STRING,
00623                               qclist,
00624                               NULL,
00625                               PACKAGE "/" PACKAGE_VERSION,
00626                               "isaac_img_imagelist_error.fits")) {
00627         /* Propagate the error */
00628         (void)cpl_error_set_where(cpl_func);
00629     }
00630 
00631     cpl_propertylist_delete(qclist);
00632     cpl_imagelist_delete(err);
00633 #endif
00634 
00635     /* Apply the sky correction only in jitter mode */
00636     if (isaac_img_jitter_config.chopping == 0) {
00637         cpl_msg_info(cpl_func, "Sky estimation and correction");
00638         cpl_msg_indent_more();
00639         if ((*skybg = isaac_img_jitter_sky(&(in[0]), in[1])) == NULL) {
00640             cpl_msg_error(cpl_func, "Cannot estimate the sky");
00641             cpl_imagelist_delete(in[0]);
00642             if (in[1]) cpl_imagelist_delete(in[1]);
00643             cpl_free(in);
00644             cpl_msg_indent_less();
00645             return NULL;
00646         }
00647         cpl_msg_indent_less();
00648     }
00649     isaac_img_jitter_config.nb_obj_frames = cpl_imagelist_get_size(in[0]);
00650     if (in[1] != NULL) 
00651         isaac_img_jitter_config.nb_sky_frames = cpl_imagelist_get_size(in[1]);
00652     if (in[1]) cpl_imagelist_delete(in[1]);
00653     in[1] = NULL;
00654     
00655     /* Apply the shift and add */
00656     cpl_msg_info(cpl_func, "Shift and add");
00657     cpl_msg_indent_more();
00658     if (isaac_img_jitter_config.chopping == 0) {
00659         combined = isaac_img_jitter_saa_nochop(in[0], obj);
00660     } else if (isaac_img_jitter_config.chopping == 1) {
00661         combined = isaac_img_jitter_saa_chop(in[0], obj);
00662     }
00663     if (combined == NULL) {
00664         cpl_msg_error(cpl_func, "Cannot apply the shift and add");
00665         cpl_imagelist_delete(in[0]);
00666         cpl_free(in);
00667         if (*skybg != NULL) cpl_vector_delete(*skybg);
00668         *skybg = NULL;
00669         cpl_msg_indent_less();
00670         return NULL;
00671     }
00672     cpl_imagelist_delete(in[0]);
00673     cpl_free(in);  
00674     cpl_msg_indent_less();
00675      
00676     /* Post processing on the combined image */
00677     if (isaac_img_jitter_config.row_med) {
00678         cpl_msg_info(cpl_func, "Subtract the median from each row");
00679         skip_if(isaac_img_jitter_sub_row_median(combined[0]));
00680     }
00681 
00682     end_skip;
00683 
00684     return combined;
00685 }
00686 
00687 /*----------------------------------------------------------------------------*/
00694 /*----------------------------------------------------------------------------*/
00695 static cpl_imagelist ** isaac_img_jitter_load(
00696         const cpl_frameset    *   obj,
00697         const cpl_frameset    *   sky)
00698 {
00699     cpl_imagelist       **  isets;
00700     cpl_imagelist       *   chop_b;
00701     const cpl_frame     *   frame;
00702     cpl_propertylist    *   plist;
00703     const char          *   sval;
00704     
00705     /* Test entries */
00706     if (obj == NULL) return NULL;
00707 
00708     /* Check if ok */
00709     cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), NULL);
00710    
00711     /* Get the frame type pixscale and DIT value */
00712     frame = cpl_frameset_get_frame_const(obj, 0);
00713     cpl_ensure(frame != NULL, cpl_error_get_code(), NULL);
00714 
00715     plist=cpl_propertylist_load(cpl_frame_get_filename(frame), 0);
00716     cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), NULL);
00717 
00718     isaac_img_jitter_config.pixscale = isaac_pfits_get_pixscale(plist);
00719     isaac_img_jitter_config.dit = isaac_pfits_get_dit(plist);
00720     sval = isaac_pfits_get_frame_type(plist);
00721     if (sval == NULL) {
00722         cpl_msg_error(cpl_func, "Could not get frame type for jitter");
00723         cpl_propertylist_delete(plist);
00724         return NULL;
00725     } else if ((isaac_img_jitter_config.chopping==0) && strcmp(sval, "INT")) {
00726         cpl_msg_error(cpl_func, "Wrong type for jitter: %s - Should be INT", 
00727                 sval);
00728         cpl_propertylist_delete(plist);
00729         return NULL;
00730     } else if ((isaac_img_jitter_config.chopping==1) && strcmp(sval, "CUBE1")) {
00731         cpl_msg_error(cpl_func, "Wrong type for chopping: %s - Should be CUBE1",
00732                 sval);
00733         cpl_propertylist_delete(plist);
00734         return NULL;
00735     }
00736     cpl_propertylist_delete(plist);
00737     if (cpl_error_get_code()) {
00738         cpl_msg_error(cpl_func, "Missing keyword in FITS header");
00739         return NULL;
00740     }
00741 
00742     /* Allocate the image sets */
00743     isets = cpl_malloc(2 * sizeof(cpl_imagelist *));
00744     
00745     /* Check if chop or nochop */
00746     if (isaac_img_jitter_config.chopping == 0) {
00747         isets[0] = cpl_imagelist_load_frameset(obj, CPL_TYPE_FLOAT, 1, 0);
00748         if (sky != NULL) 
00749             isets[1] = cpl_imagelist_load_frameset(sky, CPL_TYPE_FLOAT, 1, 0);
00750         else isets[1] = NULL;
00751     } else if (isaac_img_jitter_config.chopping == 1) {
00752         isets[1] = NULL;
00753         isets[0] = cpl_imagelist_load_frameset(obj, CPL_TYPE_FLOAT, 1, 0);
00754         chop_b = cpl_imagelist_load_frameset(obj, CPL_TYPE_FLOAT, 2, 0);
00755         cpl_imagelist_subtract(isets[0], chop_b);
00756         cpl_imagelist_delete(chop_b);
00757     } 
00758     
00759     /* Check if at least the objects are there */
00760     if (isets[0] == NULL) {
00761         cpl_msg_error(cpl_func, "The objects frames could not be loaded");
00762         if (isets[1] != NULL) cpl_imagelist_delete(isets[1]);
00763         cpl_free(isets);
00764         return NULL;
00765     }
00766     /* Return */
00767     return isets;
00768 }
00769 
00770 /*----------------------------------------------------------------------------*/
00777 /*----------------------------------------------------------------------------*/
00778 static cpl_vector * isaac_img_jitter_sky(
00779         cpl_imagelist   **  objs,
00780         cpl_imagelist   *   skys)
00781 {
00782     cpl_image       *   sky;
00783     cpl_vector      *   bg;
00784     int                 sky_method;
00785     int                 nframes, nskys;
00786     double              median;
00787     cpl_image       *   cur_ima;
00788     int                 i;
00789 
00790     /* Initialise */
00791     bg = NULL;
00792     nframes = cpl_imagelist_get_size(*objs);
00793 
00794     /* Decide the sky method */
00795     if (isaac_img_jitter_config.sky_minnb > nframes) sky_method = 1;
00796     else sky_method = 2;
00797 
00798     /* Compute the sky frame */
00799     if (skys != NULL) {
00800         cpl_msg_info(cpl_func, "Median of sky images");
00801         /* Get the median of the sky images */
00802         nskys = cpl_imagelist_get_size(skys);
00803         bg = cpl_vector_new(nskys);
00804         for (i=0; i<nskys; i++) {
00805             median = cpl_image_get_median(cpl_imagelist_get(skys, i));
00806             cpl_vector_set(bg, i, median);
00807         }
00808         /* Use sky images */
00809         if ((sky = cpl_imagelist_collapse_median_create(skys)) == NULL) {
00810             cpl_msg_error(cpl_func, "Cannot compute the median of sky images");
00811             cpl_vector_delete(bg);
00812             return NULL;
00813         }
00814         /* Correct the objects images  */
00815         if (cpl_imagelist_subtract_image(*objs, sky) != CPL_ERROR_NONE) {
00816             cpl_msg_error(cpl_func, "Cannot corr. the obj images from the sky");
00817             cpl_image_delete(sky);
00818             cpl_vector_delete(bg);
00819             return NULL;
00820         }
00821         cpl_image_delete(sky);
00822         /* Normalise the object planes */
00823         for (i=0; i<nframes; i++) {
00824             cur_ima = cpl_imagelist_get(*objs, i);
00825             median = cpl_image_get_median(cur_ima);
00826             cpl_image_subtract_scalar(cur_ima, median);
00827         }
00828     } else if (sky_method == 1) {
00829         cpl_msg_info(cpl_func, "Median of object images");
00830          /* Use objs images */
00831         if ((sky = cpl_imagelist_collapse_median_create(*objs)) == NULL) {
00832             cpl_msg_error(cpl_func, "Cannot compute the median of obj images");
00833             return NULL;
00834         }
00835         /* Correct the objects images  */
00836         if (cpl_imagelist_subtract_image(*objs, sky) != CPL_ERROR_NONE) {
00837             cpl_msg_error(cpl_func, "Cannot corr. the obj images from the sky");
00838             cpl_image_delete(sky);
00839             return NULL;
00840         }
00841         /* Create a 1 value vector */
00842         bg = cpl_vector_new(1);
00843         cpl_vector_set(bg, 0, cpl_image_get_median(sky));
00844         cpl_image_delete(sky);
00845         /* Normalise the object planes */
00846         for (i=0; i<nframes; i++) {
00847             cur_ima = cpl_imagelist_get(*objs, i);
00848             median = cpl_image_get_median(cur_ima);
00849             cpl_image_subtract_scalar(cur_ima, median);
00850         }
00851     } else if (sky_method == 2) {
00852         cpl_msg_info(cpl_func, "Running filter on object images");
00853         /* Use objects images */
00854         if ((bg = isaac_img_jitter_sky_running(objs)) == NULL) {
00855             cpl_msg_error(cpl_func, 
00856                     "Cannot apply the running filter for the sky");
00857             return NULL;
00858         }
00859     }
00860     /* Free and return */
00861     return bg;
00862 }
00863 
00864 /*----------------------------------------------------------------------------*/
00883 /*----------------------------------------------------------------------------*/
00884 static cpl_vector * isaac_img_jitter_sky_running(cpl_imagelist ** in) 
00885 {
00886     int                 rejmin, rejmax, halfw;
00887     cpl_imagelist   *   filtres;
00888     int                 ni, nx, ny, pos;
00889     cpl_vector      *   medians;
00890     cpl_image       *   cur_ima;
00891     float           *   pcur_ima;
00892     cpl_image       *   tmp_ima;
00893     float           *   ptmp_ima;
00894     cpl_vector      *   localwin;
00895     int                 fr_p, to_p, n_curp;
00896     cpl_vector      *   bg;
00897     double              bg_val, out;
00898     float               one_med;
00899     int                 i, j, k;
00900 
00901     /* Test entries */
00902     if (in==NULL || *in == NULL) return NULL;
00903 
00904     /* Initialise */
00905     rejmin = isaac_img_jitter_config.sky_rejmin;
00906     rejmax = isaac_img_jitter_config.sky_rejmax;
00907     halfw  = isaac_img_jitter_config.sky_halfw;
00908     ni = cpl_imagelist_get_size(*in);
00909     cur_ima = cpl_imagelist_get(*in, 0);
00910     nx = cpl_image_get_size_x(cur_ima);
00911     ny = cpl_image_get_size_y(cur_ima);
00912     
00913     /* Tests on validity of rejection parameters */
00914     if (((rejmin+rejmax)>=halfw) || (halfw<1) || (rejmin<0) || (rejmax<0)) {
00915         cpl_msg_error(cpl_func, "cannot run filter with rej parms %d (%d-%d)",
00916                 halfw, rejmin, rejmax);
00917         return NULL;
00918     }   
00919     /* Pre-compute median value in each plane */
00920     medians = cpl_vector_new(ni);
00921     for (i=0; i<ni; i++) {
00922         cur_ima = cpl_imagelist_get(*in, i);
00923         cpl_vector_set(medians, i, cpl_image_get_median(cur_ima));
00924     }
00925     /* Allocate output cube */
00926     filtres = cpl_imagelist_new();
00927 
00928     /* Allocate output bg */
00929     bg = cpl_vector_new(ni);
00930     
00931     /* Main loop over input planes */
00932     for (k=0; k<ni; k++) {
00933         /* Allocate output plane */
00934         tmp_ima = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00935         ptmp_ima = cpl_image_get_data_float(tmp_ima);
00936         /* Compute border indices */
00937         fr_p = k - halfw;
00938         to_p = k + halfw;
00939         if (fr_p<0) fr_p=0;
00940         if (to_p>(ni-1)) to_p=ni-1;
00941 
00942         /* Number of valid planes to consider after edge effects */
00943         n_curp = to_p - fr_p;
00944 
00945         /* Allocate local window */
00946         localwin = cpl_vector_new(n_curp);
00947         
00948         bg_val = 0.0;
00949         /* Loop over all pixels */
00950         for (pos=0; pos<nx*ny; pos++) {
00951             /* Fill up local window */
00952             j=0;
00953             for (i=fr_p; i<=to_p; i++) {
00954                 if (i!=k) {
00955                     cur_ima = cpl_imagelist_get(*in, i);
00956                     pcur_ima = cpl_image_get_data_float(cur_ima);
00957                     cpl_vector_set(localwin, j,
00958                             (double)pcur_ima[pos]-cpl_vector_get(medians, i));
00959                     j++;
00960                 }
00961             }
00962             /* Sort window */
00963             cpl_vector_sort(localwin, 1);
00964             /* Reject min and max, accumulate other pixels */
00965             out = 0.0;
00966             for (i=rejmin; i<(n_curp-rejmax); i++) {
00967                 out += cpl_vector_get(localwin, i);
00968             }
00969             /* Take the mean */
00970             out /= (double)(n_curp - rejmin - rejmax);
00971             /* Assign value */
00972             cur_ima = cpl_imagelist_get(*in, k);
00973             pcur_ima = cpl_image_get_data_float(cur_ima);
00974             ptmp_ima[pos] = pcur_ima[pos] - 
00975                 (float)(out + cpl_vector_get(medians, k));
00976 
00977             bg_val += (out+cpl_vector_get(medians, k));
00978         }
00979         cpl_vector_delete(localwin);
00980         cpl_vector_set(bg, k, bg_val/(nx*ny));
00981         cpl_imagelist_set(filtres, tmp_ima, k);
00982     }
00983     cpl_imagelist_delete(*in);
00984     cpl_vector_delete(medians);
00985 
00986     /* Subtract median from each frame */
00987     for (i=0; i<ni; i++) {
00988         cur_ima = cpl_imagelist_get(filtres, i);
00989         one_med = cpl_image_get_median(cur_ima);
00990         cpl_image_subtract_scalar(cur_ima, one_med);
00991     }
00992     *in = filtres;
00993     return bg;
00994 }
00995 
00996 /*----------------------------------------------------------------------------*/
01003 /*----------------------------------------------------------------------------*/
01004 static cpl_image ** isaac_img_jitter_saa_nochop(
01005         cpl_imagelist   *   in,
01006         const cpl_frameset    *   objframes)
01007 {
01008     const cpl_frame     *   frame;
01009     cpl_propertylist    *   plist;
01010     cpl_bivector        *   offsets_est;
01011     double              *   offsets_est_x;
01012     double              *   offsets_est_y;
01013     cpl_bivector        *   objs;
01014     double              *   objs_x;
01015     double              *   objs_y;
01016     cpl_apertures       *   aperts;
01017     cpl_image           **  combined;
01018     cpl_vector          *   thresh_vect;
01019     cpl_image           *   diff;
01020     int                     nfiles;
01021     int                     nima;
01022     int                     refine = 
01023     isaac_img_jitter_config.saa_refine ? 1 : 0;
01024     int                     i;
01025 
01026     /* Get the number of images */
01027     nfiles = cpl_imagelist_get_size(in);
01028     if (cpl_frameset_get_size(objframes) != nfiles) {
01029         cpl_msg_error(cpl_func, "Invalid input objects sizes"); 
01030         return NULL;
01031     }
01032     
01033     /* Get the offsets estimation of each input file pair */
01034     cpl_msg_info(cpl_func, "Get the offsets estimation");
01035     offsets_est = NULL;
01036     if (isaac_img_jitter_config.offsets &&
01037             isaac_img_jitter_config.offsets[0] != (char)0) {
01038         /* A file has been provided on the command line */
01039         offsets_est = cpl_bivector_read(isaac_img_jitter_config.offsets);
01040         if ((offsets_est==NULL)||(cpl_bivector_get_size(offsets_est)!=nfiles)) {
01041             cpl_msg_error(cpl_func, "Cannot get offsets from %s", 
01042                     isaac_img_jitter_config.offsets);
01043             return NULL;
01044         }
01045     } else {
01046         /* Get the offsets from the header */
01047         offsets_est = cpl_bivector_new(nfiles);
01048         offsets_est_x = cpl_bivector_get_x_data(offsets_est);
01049         offsets_est_y = cpl_bivector_get_y_data(offsets_est);
01050         for (i=0; i<nfiles; i++) {
01051             if (cpl_error_get_code()) {
01052                 cpl_bivector_delete(offsets_est);
01053                 offsets_est = NULL;
01054                 break;
01055             }
01056             /* X and Y offsets */
01057             frame = cpl_frameset_get_frame_const(objframes, i);
01058             plist=cpl_propertylist_load(cpl_frame_get_filename(frame),0);
01059             offsets_est_x[i] = -1.0 * isaac_pfits_get_cumoffsetx(plist);
01060             offsets_est_y[i] = -1.0 * isaac_pfits_get_cumoffsety(plist);
01061             cpl_propertylist_delete(plist);
01062             if (cpl_error_get_code()) {
01063                 cpl_msg_warning(cpl_func, "Cannot get offsets from header");
01064                 cpl_bivector_delete(offsets_est);
01065                 offsets_est = NULL;
01066                 break;
01067             }
01068             if (i > 0) {
01069                 /* Subtract the first offset from all offsets */
01070                 offsets_est_x[i] -= offsets_est_x[0];
01071                 offsets_est_y[i] -= offsets_est_y[0];
01072             }
01073         }
01074         if (i == nfiles) {
01075             offsets_est_x[0] = offsets_est_y[0] = 0.0;
01076         }
01077     }
01078 
01079     /* Read the provided objects file if provided */
01080     objs = NULL;
01081     if (isaac_img_jitter_config.objects &&
01082             isaac_img_jitter_config.objects[0] != (char)0) {
01083         cpl_msg_info(cpl_func, "Get the user provided correlation objects");
01084         /* A file has been provided on the command line */
01085         objs = cpl_bivector_read(isaac_img_jitter_config.objects);
01086         if (objs==NULL) {
01087             cpl_msg_error(cpl_func, "Cannot get objects from %s",
01088                     isaac_img_jitter_config.objects);
01089             if (offsets_est) cpl_bivector_delete(offsets_est);
01090             return NULL;
01091         }
01092     }
01093 
01094     /* Get a correlation point from the difference of the first images */
01095     if (objs == NULL) {
01096         cpl_msg_info(cpl_func, "Get a cross-correlation point");
01097         thresh_vect = cpl_vector_new(4);
01098         cpl_vector_set(thresh_vect, 0, 5.0);
01099         cpl_vector_set(thresh_vect, 1, 2.0);
01100         cpl_vector_set(thresh_vect, 2, 1.0);
01101         cpl_vector_set(thresh_vect, 3, 0.5);
01102         diff = cpl_image_subtract_create(cpl_imagelist_get(in, 0),
01103                 cpl_imagelist_get(in, 1));
01104         if ((aperts = cpl_apertures_extract_window(diff, thresh_vect, 
01105                         200, 200, 800, 800, NULL)) == NULL) {
01106             cpl_msg_error(cpl_func, "Cannot find any cross-correlation point");
01107             if (offsets_est) cpl_bivector_delete(offsets_est);
01108             cpl_vector_delete(thresh_vect);
01109             cpl_image_delete(diff);
01110             return NULL;
01111         }
01112         cpl_image_delete(diff);
01113         cpl_vector_delete(thresh_vect);
01114         cpl_apertures_sort_by_npix(aperts);
01115         objs = cpl_bivector_new(1);
01116         objs_x = cpl_bivector_get_x_data(objs);
01117         objs_y = cpl_bivector_get_y_data(objs);
01118         objs_x[0] = cpl_apertures_get_max_x(aperts, 1);
01119         objs_y[0] = cpl_apertures_get_max_y(aperts, 1);
01120         cpl_apertures_delete(aperts);
01121         if (objs == NULL) {
01122             cpl_msg_error(cpl_func, "Cannot find any cross-correlation point");
01123             if (offsets_est) cpl_bivector_delete(offsets_est);
01124             return NULL;
01125         }
01126         cpl_msg_info(cpl_func, 
01127                 "Correlation point: %g %g\n", objs_x[0], objs_y[0]);
01128     }
01129     
01130     /* Recombine the images */
01131     cpl_msg_info(cpl_func, "Recombine the images set");
01132     cpl_msg_indent_more();
01133     if ((combined = cpl_geom_img_offset_combine(in, offsets_est, refine, objs,
01134                     NULL, NULL,
01135                     isaac_img_jitter_config.sx, 
01136                     isaac_img_jitter_config.sy,
01137                     isaac_img_jitter_config.mx, 
01138                     isaac_img_jitter_config.my,
01139                     isaac_img_jitter_config.rej_low,
01140                     isaac_img_jitter_config.rej_high,
01141                     isaac_img_jitter_config.comb_meth)) == NULL) {
01142         cpl_msg_error(cpl_func, "Cannot recombine the images");
01143         if (offsets_est) cpl_bivector_delete(offsets_est);
01144         cpl_bivector_delete(objs);
01145         cpl_msg_indent_less();
01146         return NULL;
01147     }
01148     /* Update QC params */
01149     i = (int)(cpl_image_get_max(combined[1]));
01150     nima = cpl_imagelist_get_size(in);
01151     if ((nima > 3) && (nima>2*
01152             (isaac_img_jitter_config.rej_low+isaac_img_jitter_config.rej_high)))
01153         i += isaac_img_jitter_config.rej_low+isaac_img_jitter_config.rej_high;
01154     isaac_img_jitter_config.nb_rej_frames = 
01155         isaac_img_jitter_config.nb_obj_frames - i;
01156     isaac_img_jitter_config.nb_obj_frames = i;
01157     cpl_msg_indent_less();
01158 
01159     /* Free and return */
01160     if (offsets_est) cpl_bivector_delete(offsets_est);
01161     cpl_bivector_delete(objs);
01162     return combined;
01163 }
01164 
01165 
01166 /*----------------------------------------------------------------------------*/
01173 /*----------------------------------------------------------------------------*/
01174 static cpl_image ** isaac_img_jitter_saa_chop(
01175         cpl_imagelist   *   in,
01176         const cpl_frameset    *   objframes)
01177 {
01178     const cpl_frame     *   frame;
01179     cpl_propertylist    *   plist;
01180     cpl_bivector        *   offsets_est;
01181     cpl_bivector        *   offsets_est_nod;
01182     double              *   offsets_est_x;
01183     double              *   offsets_est_y;
01184     double              *   offsets_est_nod_x;
01185     double              *   offsets_est_nod_y;
01186     cpl_bivector        *   objs;
01187     cpl_image           **  combined;
01188     cpl_vector          *   thresh_vect;
01189     int                     nfiles, nb_chop;
01190     int                 *   chop_a;
01191     int                 *   chop_b;
01192     cpl_imagelist       *   nodded;
01193     cpl_image           *   tmp_ima;
01194     int                     refine = 
01195     isaac_img_jitter_config.saa_refine ? 1 : 0;
01196     int                     i;
01197 
01198     /* Get the number of images */
01199     nfiles = cpl_imagelist_get_size(in);
01200     if (cpl_frameset_get_size(objframes) != nfiles) {
01201         cpl_msg_error(cpl_func, "Invalid input objects sizes"); 
01202         return NULL;
01203     }
01204    
01205     /* Get the offsets estimation of each input file pair */
01206     cpl_msg_info(cpl_func, "Get the offsets estimation");
01207     offsets_est = NULL;
01208     if (isaac_img_jitter_config.offsets &&
01209             isaac_img_jitter_config.offsets[0] != (char)0) {
01210         /* A file has been provided on the command line */
01211         offsets_est = cpl_bivector_read(isaac_img_jitter_config.offsets);
01212         if ((offsets_est==NULL) || 
01213                 (cpl_bivector_get_size(offsets_est) != nfiles)) {
01214             cpl_msg_error(cpl_func, "Cannot get offsets from %s", 
01215                     isaac_img_jitter_config.offsets);
01216             return NULL;
01217         }
01218         offsets_est_x = cpl_bivector_get_x_data(offsets_est);
01219         offsets_est_y = cpl_bivector_get_y_data(offsets_est);
01220     } else {
01221         /* Get the offsets from the header */
01222         offsets_est = cpl_bivector_new(nfiles);
01223         offsets_est_x = cpl_bivector_get_x_data(offsets_est);
01224         offsets_est_y = cpl_bivector_get_y_data(offsets_est);
01225         for (i=0; i<nfiles; i++) {
01226             if (cpl_error_get_code()) {
01227                 cpl_bivector_delete(offsets_est);
01228                 return NULL;
01229             }
01230             /* X and Y offsets */
01231             frame = cpl_frameset_get_frame_const(objframes, i);
01232             plist=cpl_propertylist_load(cpl_frame_get_filename(frame),0);
01233             offsets_est_x[i] = -1.0 * isaac_pfits_get_cumoffsetx(plist);
01234             offsets_est_y[i] = -1.0 * isaac_pfits_get_cumoffsety(plist);
01235             cpl_propertylist_delete(plist);
01236             if (cpl_error_get_code()) {
01237                 cpl_msg_warning(cpl_func, "Cannot get offsets from header");
01238                 cpl_bivector_delete(offsets_est);
01239                 return NULL;
01240             }
01241         }
01242         /* Subtract the first offset to all offsets */
01243         for (i=1; i<nfiles; i++) {
01244             offsets_est_x[i] -= offsets_est_x[0];
01245             offsets_est_y[i] -= offsets_est_y[0];
01246         }
01247         offsets_est_x[0] = offsets_est_y[0] = 0.00;
01248     }
01249 
01250     /* Classify the A and B nodding positions using the offsets */
01251     if ((nb_chop=isaac_img_jitter_chopping_classif(offsets_est, 
01252                     &chop_a, &chop_b)) == -1) {
01253         cpl_msg_error(cpl_func, "cannot classify chopped frames");
01254         cpl_bivector_delete(offsets_est);
01255         return NULL;
01256     }
01257     
01258     /* Create the nodded frames chop_a-chop_b */
01259     nodded = cpl_imagelist_new();
01260     for (i=0; i<nb_chop; i++) {
01261         tmp_ima = cpl_image_subtract_create(
01262                 cpl_imagelist_get(in, chop_a[i]),
01263                 cpl_imagelist_get(in, chop_b[i]));
01264         cpl_imagelist_set(nodded, tmp_ima, i);
01265     }
01266 
01267     /* Update the offsets estimations between the nodded frames */
01268     offsets_est_nod = cpl_bivector_new(nb_chop);
01269     offsets_est_nod_x = cpl_bivector_get_x_data(offsets_est_nod);
01270     offsets_est_nod_y = cpl_bivector_get_y_data(offsets_est_nod);
01271     for (i=0; i<nb_chop; i++) {
01272         offsets_est_nod_x[i] = offsets_est_x[chop_a[i]];
01273         offsets_est_nod_y[i] = offsets_est_y[chop_a[i]];
01274     }
01275     cpl_bivector_delete(offsets_est);
01276     cpl_free(chop_a);
01277     cpl_free(chop_b);
01278 
01279     /* Read the provided objects file if provided */
01280     objs = NULL;
01281     if (isaac_img_jitter_config.objects &&
01282             isaac_img_jitter_config.objects[0] != (char)0) {
01283         cpl_msg_info(cpl_func, "Get the user provided correlation objects");
01284         /* A file has been provided on the command line */
01285         objs = cpl_bivector_read(isaac_img_jitter_config.objects);
01286         if (objs==NULL) {
01287             cpl_msg_error(cpl_func, "Cannot get objects from %s",
01288                     isaac_img_jitter_config.objects);
01289             cpl_bivector_delete(offsets_est_nod);
01290             cpl_imagelist_delete(nodded);
01291             return NULL;
01292         }
01293     }
01294 
01295     /* Create the vector for the detection thresholds */
01296     thresh_vect = cpl_vector_new(4);
01297     cpl_vector_set(thresh_vect, 0, 5.0);
01298     cpl_vector_set(thresh_vect, 1, 2.0);
01299     cpl_vector_set(thresh_vect, 2, 1.0);
01300     cpl_vector_set(thresh_vect, 3, 0.5);
01301     
01302     /* Recombine the images */
01303     cpl_msg_info(cpl_func, "Recombine the images set");
01304     cpl_msg_indent_more();
01305     if ((combined = cpl_geom_img_offset_combine(nodded, offsets_est_nod,
01306             refine, objs, thresh_vect, NULL,
01307                     isaac_img_jitter_config.sx, 
01308                     isaac_img_jitter_config.sy,
01309                     isaac_img_jitter_config.mx, 
01310                     isaac_img_jitter_config.my,
01311                     isaac_img_jitter_config.rej_low,
01312                     isaac_img_jitter_config.rej_high,
01313                     isaac_img_jitter_config.comb_meth)) == NULL) {
01314         cpl_msg_error(cpl_func, "Cannot recombine the images");
01315         cpl_bivector_delete(offsets_est_nod);
01316         cpl_imagelist_delete(nodded);
01317         if (objs) cpl_bivector_delete(objs);
01318         cpl_vector_delete(thresh_vect);
01319         cpl_msg_indent_less();
01320         return NULL;
01321     }
01322     /* Update QC params */
01323     i = (int)(cpl_image_get_max(combined[1]));
01324     isaac_img_jitter_config.nb_rej_frames = 
01325         isaac_img_jitter_config.nb_obj_frames - i;
01326     isaac_img_jitter_config.nb_obj_frames = i;
01327     cpl_msg_indent_less();
01328 
01329     /* Free and return */
01330     cpl_vector_delete(thresh_vect);
01331     cpl_bivector_delete(offsets_est_nod);
01332     cpl_imagelist_delete(nodded);
01333     if (objs) cpl_bivector_delete(objs);
01334     return combined;
01335 }
01336 
01337 /*----------------------------------------------------------------------------*/
01345 /*----------------------------------------------------------------------------*/
01346 static int isaac_img_jitter_chopping_classif(
01347         cpl_bivector    *   offsets,
01348         int             **  chop_a,
01349         int             **  chop_b)
01350 {
01351     int             nb_obj;
01352     double      *   offsets_x;
01353     double      *   offsets_y;
01354     double          throw_x,
01355                     throw_y;
01356     double      *   dist;
01357     int         *   dcount;
01358     int             max_count;
01359     int             i_max, j_max;
01360     int             classified;
01361     int             i, j, k, l;
01362 
01363     /* Test entries */
01364     if (offsets==NULL || chop_a==NULL || chop_b==NULL) return -1;
01365 
01366     /* Initialise */
01367     *chop_a = *chop_b = NULL;
01368     
01369     /* Find number of type_obj frames */
01370     nb_obj = cpl_bivector_get_size(offsets);
01371     offsets_x = cpl_bivector_get_x_data(offsets);
01372     offsets_y = cpl_bivector_get_y_data(offsets);
01373 
01374     /* If no object frame, exit */
01375     if (nb_obj == 0) return -1;
01376 
01377     /* Odd number of frames ? */
01378     if (nb_obj%2) {
01379         cpl_msg_error(cpl_func, "odd number of frames in input [%d]", nb_obj);
01380         return -1;
01381     }
01382 
01383     /* Find all distances between offsets and count them */
01384     dist   = cpl_calloc(nb_obj*nb_obj, sizeof(double));
01385     dcount = cpl_calloc(nb_obj*nb_obj, sizeof(int));
01386     for (i=0; i<nb_obj; i++) {
01387          for (j=0; j<nb_obj; j++) {
01388              dist[i+j*nb_obj] = sqrt(SQR(offsets_x[i] - offsets_x[j]) +
01389                      SQR(offsets_y[i] - offsets_y[j]));
01390          }
01391     }
01392 
01393     for (i=0; i<nb_obj*nb_obj; i++) {
01394         for (j=0; j<nb_obj*nb_obj; j++)
01395             if (fabs(dist[i]-dist[j]) <= NEGLIG_OFF_DIFF) dcount[i] ++;
01396     }
01397 
01398     /* Find Chop offsets as the nonzero distance with maximal occurrence */
01399     max_count = 0;
01400     i_max     = 0;
01401     j_max     = 0;
01402     for (i=0; i<nb_obj; i++){
01403         for (j=0; j<nb_obj; j++) {
01404             if ((dcount[i+j*nb_obj]>max_count)&&(dist[i+j*nb_obj]>0.5)){
01405                 max_count = dcount[i+j*nb_obj];
01406                 i_max = i;
01407                 j_max = j;
01408             }
01409         }
01410     }
01411 
01412     /* Compute the throw */
01413     throw_x = offsets_x[j_max] - offsets_x[i_max];
01414     throw_y = offsets_y[j_max] - offsets_y[i_max];
01415 
01416     cpl_msg_info(cpl_func, "Typical (%d) non-zero throw is (%g, %g) from %d "
01417                  "(%g, %g) to %d (%g, %g)", max_count, throw_x, throw_y,
01418                  i_max, offsets_x[i_max], offsets_y[i_max],
01419                  j_max, offsets_x[j_max], offsets_y[j_max]);
01420 
01421     /* Free */
01422     cpl_free(dist);
01423     cpl_free(dcount);
01424 
01425     /* Test the throw */
01426     if ((throw_x == 0) && (throw_y == 0)) {
01427         cpl_msg_error(cpl_func, "Throw is equal to 0 - cannot classify");
01428         return -1;
01429     }
01430 
01431     /* Allocate maximal possible nb of chop frames (worst case: abab)*/
01432     *chop_a = cpl_calloc(nb_obj/2, sizeof(int));
01433     *chop_b = cpl_calloc(nb_obj/2, sizeof(int));
01434 
01435     k = l = 0;
01436     for (i=0; i<nb_obj-1; i++) {
01437         /* Consider the successive pairs of frames */
01438         /* AB ?  */
01439         if ((fabs(offsets_x[i]-offsets_x[i+1]+throw_x) < NEGLIG_OFF_DIFF) &&
01440             (fabs(offsets_y[i]-offsets_y[i+1]+throw_y) < NEGLIG_OFF_DIFF)) {
01441             (*chop_a)[k++] = i;
01442             (*chop_b)[l++] = i+1;
01443         /* BA ? */
01444         } else if ((fabs(offsets_x[i]-offsets_x[i+1]-throw_x) < 
01445                     NEGLIG_OFF_DIFF) &&
01446                 (fabs(offsets_y[i]-offsets_y[i+1]-throw_y) < 
01447                  NEGLIG_OFF_DIFF)) {
01448             (*chop_b)[l++] = i;
01449             (*chop_a)[k++] = i+1;
01450         /* AA or BB ? -> do nothing */
01451         }
01452     }
01453 
01454     cpl_msg_info(cpl_func, "Found %d A- and %d B-frames (out of %d)", k, l,
01455                  nb_obj);
01456 
01457     /* Classify the frames not seen until here as rejected */
01458     for (i=0; i<nb_obj; i++) {
01459         classified = 0;
01460         /* For each frame, check if it has been classified */
01461         for (j=0; j < nb_obj/2; j++) {
01462             if ((*chop_a)[j] == i || (*chop_b)[j] == i) classified = 1;
01463         }
01464         if (classified == 0) {
01465             cpl_msg_error(cpl_func, "Frame %d cannot be classified", i+1);
01466             cpl_free(*chop_a);
01467             cpl_free(*chop_b);
01468             *chop_a = *chop_b = NULL;
01469             return -1;
01470         }
01471     }
01472 
01473     /* There should be as much chop a as chop b frames */
01474     if (k != l) {
01475         cpl_free(*chop_a);
01476         cpl_free(*chop_b);
01477         *chop_a = *chop_b = NULL;
01478         return -1;
01479     }
01480     return k;
01481 }
01482 
01483 /*----------------------------------------------------------------------------*/
01490 /*----------------------------------------------------------------------------*/
01491 static cpl_error_code isaac_img_jitter_sub_row_median(cpl_image * self)
01492 {
01493     const int nx    = cpl_image_get_size_x(self);
01494     const int ny    = cpl_image_get_size_y(self);
01495     float *   pself = cpl_image_get_data_float(self);
01496     int       i, j;
01497 
01498     bug_if(self == NULL);
01499     bug_if(cpl_image_get_type(self) != CPL_TYPE_FLOAT);
01500 
01501  
01502     for (j = 0; j < ny; j++, pself += nx) {
01503         cpl_errorstate prestate = cpl_errorstate_get();
01504         const double median = cpl_image_get_median_window(self, 1, j+1, nx, j+1);
01505 
01506         if (cpl_errorstate_is_equal(prestate)) {
01507             for (i = 0; i < nx; i++) {
01508                 pself[i] -= (float)median;
01509             }
01510         } else {
01511             cpl_msg_warning(cpl_func, "Could not subtract median from %d "
01512                             "pixel(s) in row %d/%d (%d bad pixel(s))", nx, 1+j,
01513                             ny, (int)cpl_image_count_rejected(self));
01514             cpl_errorstate_set(prestate);
01515         }
01516     }
01517 
01518     end_skip;
01519 
01520     return cpl_error_get_code();
01521 }
01522 
01523 /*----------------------------------------------------------------------------*/
01529 /*----------------------------------------------------------------------------*/
01530 static cpl_table * isaac_img_jitter_qc(cpl_image * combined)
01531 {
01532     cpl_vector      *   thresh_vec;
01533     cpl_apertures   *   aperts;
01534     int                 nb_objs;
01535     double              angle;
01536     double          *   fwhms_x;
01537     double          *   fwhms_y;
01538     cpl_table       *   out_tab;
01539     cpl_bivector    *   iqe;
01540     int                 nb_good;
01541     cpl_vector      *   fwhms_good;
01542     double          *   fwhms_good_data;
01543     double              f_min, f_max, fr, fx, fy;
01544     int                 i, j;
01545     
01546     /* Initialise */
01547     double              seeing_min_arcsec = 0.1;
01548     double              seeing_max_arcsec = 5.0;
01549     double              seeing_fwhm_var   = 0.2;
01550 
01551     /* Check entries */
01552     if (combined == NULL) return NULL;
01553     
01554     /* Create the vector for the detection thresholds */
01555     thresh_vec = cpl_vector_new(4);
01556     cpl_vector_set(thresh_vec, 0, 5.0);
01557     cpl_vector_set(thresh_vec, 1, 2.0);
01558     cpl_vector_set(thresh_vec, 2, 1.0);
01559     cpl_vector_set(thresh_vec, 3, 0.5);
01560 
01561     /* Detect apertures */
01562     if ((aperts = cpl_apertures_extract(combined, thresh_vec, NULL)) == NULL) {
01563         cpl_msg_error(cpl_func, "Cannot detect any aperture");
01564         cpl_vector_delete(thresh_vec);
01565         return NULL;
01566     }
01567     cpl_vector_delete(thresh_vec);
01568 
01569     /* Number of detected objects */
01570     nb_objs = cpl_apertures_get_size(aperts);
01571     isaac_img_jitter_config.nbobjs = nb_objs;
01572     fwhms_x = cpl_malloc(nb_objs * sizeof(double));
01573     fwhms_y = cpl_malloc(nb_objs * sizeof(double));
01574 
01575     /* Create the output table */
01576     out_tab = cpl_table_new(nb_objs);
01577     cpl_table_new_column(out_tab, "POS_X", CPL_TYPE_DOUBLE);
01578     cpl_table_new_column(out_tab, "POS_Y", CPL_TYPE_DOUBLE);
01579     cpl_table_new_column(out_tab, "ANGLE", CPL_TYPE_DOUBLE);
01580     cpl_table_new_column(out_tab, "FWHM_X", CPL_TYPE_DOUBLE);
01581     cpl_table_new_column(out_tab, "FWHM_Y", CPL_TYPE_DOUBLE);
01582     cpl_table_new_column(out_tab, "ELLIP", CPL_TYPE_DOUBLE);
01583     cpl_table_new_column(out_tab, "FLUX", CPL_TYPE_DOUBLE);
01584     for (i=0; i<nb_objs; i++) {
01585         /* Fill with the already known information */
01586         cpl_table_set_double(out_tab, "POS_X", i, 
01587                 cpl_apertures_get_centroid_x(aperts, i+1));
01588         cpl_table_set_double(out_tab, "POS_Y", i, 
01589                 cpl_apertures_get_centroid_y(aperts, i+1));
01590         cpl_table_set_double(out_tab, "FLUX", i, 
01591                 cpl_apertures_get_flux(aperts, i+1));
01592         /* Compute the FWHM informations */
01593         if ((iqe = cpl_image_iqe(combined, 
01594                 (int)cpl_apertures_get_centroid_x(aperts, i+1) - 10,
01595                 (int)cpl_apertures_get_centroid_y(aperts, i+1) - 10,
01596                 (int)cpl_apertures_get_centroid_x(aperts, i+1) + 10,
01597                 (int)cpl_apertures_get_centroid_y(aperts, i+1) + 10))==NULL){
01598             cpl_error_reset();
01599             cpl_msg_warning(cpl_func, "Cannot get FWHM for obj at pos %g %g",
01600                     cpl_apertures_get_centroid_x(aperts, i+1),
01601                     cpl_apertures_get_centroid_y(aperts, i+1));
01602             fwhms_x[i] = -1.0;
01603             fwhms_y[i] = -1.0;
01604             angle = 0.0;
01605         } else {
01606             fwhms_x[i] = cpl_vector_get(cpl_bivector_get_x(iqe), 2);
01607             fwhms_y[i] = cpl_vector_get(cpl_bivector_get_x(iqe), 3);
01608             angle = cpl_vector_get(cpl_bivector_get_x(iqe), 4);
01609             cpl_bivector_delete(iqe);
01610         }
01611         cpl_table_set_double(out_tab, "ANGLE",  i, angle);
01612         cpl_table_set_double(out_tab, "FWHM_X", i, fwhms_x[i]);
01613         cpl_table_set_double(out_tab, "FWHM_Y", i, fwhms_y[i]);
01614     if (fwhms_x[i] == 0.0) {
01615         cpl_msg_warning(cpl_func, "Infinite ELLIP for obj at pos %g %g",
01616                     cpl_apertures_get_centroid_x(aperts, i+1),
01617                     cpl_apertures_get_centroid_y(aperts, i+1));
01618         cpl_table_set_double(out_tab, "ELLIP",  i, DBL_MAX);
01619     } else {
01620         cpl_table_set_double(out_tab, "ELLIP",  i,
01621                  fwhms_y[i] / fwhms_x[i]);
01622     }
01623     }
01624     cpl_apertures_delete(aperts);
01625 
01626     /* Get the number of good values */
01627     nb_good = 0;
01628     for (i=0; i<nb_objs; i++) {
01629         if ((fwhms_x[i] > 0.0) && (fwhms_y[i] > 0.0)) nb_good++;
01630     }
01631     if (nb_good == 0) {
01632         cpl_table_delete(out_tab);
01633         cpl_free(fwhms_x);
01634         cpl_free(fwhms_y);
01635         return NULL;
01636     }
01637     
01638     /* Get the good values */
01639     fwhms_good = cpl_vector_new(nb_good);
01640     fwhms_good_data = cpl_vector_get_data(fwhms_good);
01641     j=0;
01642     for (i=0; i<nb_objs; i++) {
01643         if ((fwhms_x[i] > 0.0) && (fwhms_y[i] > 0.0)) {
01644             fwhms_good_data[j] = (fwhms_x[i]+fwhms_y[i])/2.0;
01645             j++;
01646         }
01647     }
01648    
01649     /* Compute the fwhm */
01650     if (nb_good < 3) {
01651         /* Too few values to compute the median */
01652         isaac_img_jitter_config.fwhm_pix = fwhms_good_data[0];
01653     } else {
01654         /* Compute the median */
01655         isaac_img_jitter_config.fwhm_pix = cpl_vector_get_median_const(fwhms_good);
01656     }
01657     isaac_img_jitter_config.fwhm_arcsec = 
01658         isaac_img_jitter_config.fwhm_pix * isaac_img_jitter_config.pixscale;
01659 
01660     /* Compute the mode of the FWHMs */
01661     if (nb_good > 5) {
01662         isaac_img_jitter_config.fwhm_mode=isaac_img_jitter_get_mode(fwhms_good);
01663         isaac_img_jitter_config.fwhm_mode *= isaac_img_jitter_config.pixscale;
01664     }
01665     cpl_vector_delete(fwhms_good);
01666     
01667     /* IQ is the median of the (fwhm_x+fwhm_y/2) of the good stars */
01668     /* Compute f_min and f_max */
01669     f_min = seeing_min_arcsec / isaac_img_jitter_config.pixscale;
01670     f_max = seeing_max_arcsec / isaac_img_jitter_config.pixscale;
01671 
01672     /* Get the number of good values */
01673     nb_good = 0;
01674     for (i=0; i<nb_objs; i++) {
01675         fx = fwhms_x[i];
01676         fy = fwhms_y[i];
01677         fr = 2.0 * fabs(fx-fy) / (fx+fy);
01678         if ((fx > f_min) && (fx < f_max) && (fy > f_min) && (fy < f_max) &&
01679             (fr < seeing_fwhm_var)) nb_good++;
01680     }
01681     if (nb_good == 0) {
01682         cpl_table_delete(out_tab);
01683         cpl_free(fwhms_x);
01684         cpl_free(fwhms_y);
01685         return NULL;
01686     }
01687 
01688     /* Get the good values */
01689     fwhms_good = cpl_vector_new(nb_good);
01690     fwhms_good_data = cpl_vector_get_data(fwhms_good);
01691     j=0;
01692     for (i=0; i<nb_objs; i++) {
01693         fx = fwhms_x[i];
01694         fy = fwhms_y[i];
01695         fr = 2.0 * fabs(fx-fy) / (fx+fy);
01696         if ((fx > f_min) && (fx < f_max) && (fy > f_min) && (fy < f_max) &&
01697             (fr < seeing_fwhm_var)) {
01698             fwhms_good_data[j] = (fx + fy)/2.0;
01699             j++;
01700         }
01701     }
01702     cpl_free(fwhms_x);
01703     cpl_free(fwhms_y);
01704     
01705     /* Compute the fwhm */
01706     if (nb_good < 3) {
01707         /* Too few values to compute the median */
01708         isaac_img_jitter_config.iq = fwhms_good_data[0];
01709     } else {
01710         /* Compute the median */
01711         isaac_img_jitter_config.iq = cpl_vector_get_median_const(fwhms_good);
01712     }
01713     cpl_vector_delete(fwhms_good);
01714     isaac_img_jitter_config.iq *= isaac_img_jitter_config.pixscale;
01715 
01716     isaac_img_jitter_config.angle_med = cpl_table_get_column_median(out_tab,
01717                                     "ANGLE");
01718     isaac_img_jitter_config.ellip_med = cpl_table_get_column_median(out_tab,
01719                                     "ELLIP");
01720     return out_tab;
01721 }
01722         
01723 /*----------------------------------------------------------------------------*/
01729 /*----------------------------------------------------------------------------*/
01730 static double isaac_img_jitter_get_mode(cpl_vector * vec)
01731 {
01732     int                 nb;
01733     int                 nbins;
01734     double              min, max;
01735     double              bin_size;
01736     cpl_bivector    *   hist;
01737     cpl_vector      *   hist_x;
01738     cpl_vector      *   hist_y;
01739     double              cur_val;
01740     int                 cur_bin;
01741     double              max_val;
01742     int                 max_bin;
01743     double              mode;
01744     int                 i;
01745 
01746     /* Test entries  */
01747     if (vec == NULL) return -1.0;
01748     
01749     /* Initialise */
01750     nb = cpl_vector_get_size(vec);
01751 
01752     /* Create the histogram */
01753     nbins = 10;
01754     min = cpl_vector_get_min(vec);
01755     max = cpl_vector_get_max(vec);
01756     bin_size = (max-min)/nbins;
01757     hist = cpl_bivector_new(nbins);
01758     hist_x = cpl_bivector_get_x(hist);
01759     hist_y = cpl_bivector_get_y(hist);
01760     cpl_vector_fill(hist_x, 0.0);
01761     cpl_vector_fill(hist_y, 0.0);
01762     for (i=0; i<nbins; i++) {
01763         cpl_vector_set(hist_x, i, min + i * bin_size);
01764     }
01765     for (i=0; i<nb; i++) {
01766         cur_val = cpl_vector_get(vec, i);
01767         cur_bin = (int)((cur_val - min) / bin_size);
01768         if (cur_bin >= nbins) cur_bin -= 1.0;
01769         cur_val = cpl_vector_get(hist_y, cur_bin);
01770         cur_val += 1.0;
01771         cpl_vector_set(hist_y, cur_bin, cur_val);
01772     }
01773     
01774     /* Get the mode of the histogram */
01775     max_val = cpl_vector_get(hist_y, 0);
01776     max_bin = 0;
01777     for (i=0; i<nbins; i++) {
01778         cur_val = cpl_vector_get(hist_y, i);
01779         if (cur_val > max_val) {
01780             max_val = cur_val;
01781             max_bin = i;
01782         }
01783     }
01784     mode = cpl_vector_get(hist_x, max_bin);
01785     cpl_bivector_delete(hist);
01786     return mode;
01787 }
01788         
01789 /*----------------------------------------------------------------------------*/
01801 /*----------------------------------------------------------------------------*/
01802 static
01803 cpl_error_code isaac_img_jitter_save(cpl_frameset            * set,
01804                                      const cpl_image         * combined,
01805                                      const cpl_image         * contrib,
01806                                      const cpl_table         * objs_stats,
01807                                      const cpl_vector        * sky_bg,
01808                                      const cpl_parameterlist * parlist)
01809 {
01810     const cpl_frame  * ref_frame
01811         = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW);
01812     const char       * filename = cpl_frame_get_filename(ref_frame);
01813     const int          sz_skybg = sky_bg ? cpl_vector_get_size(sky_bg) : 0;
01814     cpl_propertylist * plist = NULL;
01815     cpl_propertylist * qclist = cpl_propertylist_new();
01816     const char       * wcs_reg = "(CRVAL|CRPIX|CTYPE)[0-9]+|(CD)[0-9]+_[0-9]+";
01817     cpl_table        * sky_bg_tab = NULL;
01818     int                i;
01819 
01820     bug_if(0);
01821     bug_if(combined   == NULL);
01822     bug_if(contrib    == NULL);
01823     bug_if(parlist    == NULL);
01824 
01825     /* Get the QC params in qclist */
01826     if (isaac_img_jitter_config.chopping == 0) {
01827         const char * key = "ESO QC BACKGD INSTMAG";
01828         const double pscale   = isaac_img_jitter_config.pixscale;
01829         const double dit      = isaac_img_jitter_config.dit;
01830         const double bg_mean  = cpl_vector_get_mean(sky_bg);
01831         const double bg_stdev = sz_skybg < 2 ? 0.0
01832             : cpl_vector_get_stdev(sky_bg);
01833 
01834 
01835         bug_if(cpl_propertylist_append_double(qclist, "ESO QC BACKGD MEAN",
01836                                               bg_mean));
01837         bug_if(cpl_propertylist_append_double(qclist, "ESO QC BACKGD STDEV",
01838                                               bg_stdev));
01839 
01840         if (pscale * dit != 0.0 && bg_mean / (pscale * pscale * dit) > 0.0) {
01841             const double bg_instmag = -2.5 * log10(bg_mean/(pscale*pscale*dit));
01842 
01843             bug_if(cpl_propertylist_append_double(qclist, key, bg_instmag));
01844         } else {
01845             cpl_msg_warning(cpl_func, "Could not compute %s: dit=%g, pscale=%g, "
01846                             "bg_mean=%g", key, dit, pscale, bg_mean);
01847         }
01848     }
01849 
01850     cpl_propertylist_append_int(qclist, "ESO QC NBOBJS",
01851                                 isaac_img_jitter_config.nbobjs);
01852     cpl_propertylist_append_double(qclist, "ESO QC IQ",
01853                                    isaac_img_jitter_config.iq);
01854     cpl_propertylist_append_double(qclist, "ESO QC FWHM PIX",
01855                                    isaac_img_jitter_config.fwhm_pix);
01856     cpl_propertylist_append_double(qclist, "ESO QC FWHM ARCSEC",
01857                                    isaac_img_jitter_config.fwhm_arcsec);
01858     cpl_propertylist_append_double(qclist, "ESO QC FWHM MODE",
01859                                    isaac_img_jitter_config.fwhm_mode);
01860     cpl_propertylist_append_int(qclist, "ESO QC NB_OBJ_F",
01861                                 isaac_img_jitter_config.nb_obj_frames);
01862     cpl_propertylist_append_int(qclist, "ESO QC NB_SKY_F",
01863                                 isaac_img_jitter_config.nb_sky_frames);
01864     cpl_propertylist_append_int(qclist, "ESO QC NB_REJ_F",
01865                                 isaac_img_jitter_config.nb_rej_frames);
01866     cpl_propertylist_append_double(qclist, "ESO QC ANGLE MED",
01867                                    isaac_img_jitter_config.angle_med);
01868     cpl_propertylist_append_double(qclist, "ESO QC ELLIP MED",
01869                                    isaac_img_jitter_config.ellip_med);
01870     bug_if(0);
01871 
01872     /* Get FITS header from reference file */
01873     plist = cpl_propertylist_load(filename, 0);
01874     skip_if(plist == NULL);
01875 
01876     /* Load the WCS keys */
01877     bug_if(cpl_propertylist_copy_property_regexp(qclist, plist, wcs_reg, 0));
01878 
01879     /* Get the keywords for the paf file */
01880     (void)cpl_propertylist_erase_regexp(plist,
01881                                         "^(ARCFILE|MJD-OBS|INSTRUME"
01882                                         "|ESO TPL ID|ESO TPL NEXP"
01883                                         "|ESO DPR CATG"
01884                                         "|ESO DPR TECH|ESO DPR TYPE"
01885                                         "|DATE-OBS|ESO OBS ID"
01886                                         "|ESO INS PIXSCALE)$", 1);
01887 
01888     /* Write the image */
01889     skip_if(irplib_dfs_save_image(set, parlist, set, combined,
01890                                   CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
01891                                   ISAAC_IMG_JITTER_COMB, qclist, NULL,
01892                                   PACKAGE "/" PACKAGE_VERSION,
01893                                   RECIPE_STRING  CPL_DFS_FITS));
01894     (void)cpl_propertylist_erase_regexp(qclist, wcs_reg, 0);
01895 
01896     /* Append the contribution map */
01897     skip_if (cpl_image_save(contrib, RECIPE_STRING CPL_DFS_FITS,
01898                             CPL_BPP_16_UNSIGNED, NULL, CPL_IO_EXTEND));
01899 
01900     if (sky_bg != NULL) {
01901         /* Write the FITS background table */
01902 
01903         /* First create the table from the vector */
01904         sky_bg_tab = cpl_table_new(sz_skybg);
01905 
01906         cpl_table_new_column(sky_bg_tab, "SKY_BG", CPL_TYPE_DOUBLE);
01907 
01908         for (i = 0; i < sz_skybg; i++) {
01909             cpl_table_set_double(sky_bg_tab, "SKY_BG", i, 
01910                                  cpl_vector_get(sky_bg, i));
01911         } 
01912 
01913         skip_if(irplib_dfs_save_table(set, parlist, set, sky_bg_tab, NULL,
01914                                       RECIPE_STRING, ISAAC_IMG_JITTER_BG,
01915                                       qclist, NULL, PACKAGE "/" PACKAGE_VERSION,
01916                                       RECIPE_STRING "_bg" CPL_DFS_FITS));
01917         cpl_table_delete(sky_bg_tab);
01918         sky_bg_tab = NULL;
01919     }
01920 
01921     /* Write the FITS table */
01922     if (objs_stats) {
01923         skip_if(irplib_dfs_save_table(set, parlist, set, objs_stats, NULL,
01924                                       RECIPE_STRING, ISAAC_IMG_JITTER_STARS,
01925                                       qclist, NULL, PACKAGE "/" PACKAGE_VERSION,
01926                                       RECIPE_STRING "_stars" CPL_DFS_FITS));
01927     }
01928 
01929     bug_if(cpl_propertylist_append(plist, qclist));
01930     cpl_propertylist_empty(qclist);
01931 
01932     /* PRO.CATG */
01933     cpl_propertylist_update_string(plist, CPL_DFS_PRO_CATG,
01934                                    ISAAC_IMG_JITTER_COMB);
01935 
01936     /* Save the PAF file */
01937     skip_if (cpl_dfs_save_paf("ISAAC", RECIPE_STRING, plist,
01938                              RECIPE_STRING CPL_DFS_PAF));
01939 
01940     end_skip;
01941 
01942     cpl_propertylist_delete(plist);
01943     cpl_propertylist_delete(qclist);
01944     cpl_table_delete(sky_bg_tab);
01945 
01946     return cpl_error_get_code();
01947 }

Generated on Mon Feb 6 14:44:02 2012 for ISAAC Pipeline Reference Manual by  doxygen 1.5.8