isaac_img_jitter.c

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

Generated on Wed Mar 9 15:43:10 2011 for ISAAC Pipeline Reference Manual by  doxygen 1.5.8