irplib_detmon_lg.c

00001 /* $Id: irplib_detmon_lg.c,v 1.59 2008/04/02 15:16:43 lbilbao Exp $
00002  *
00003  * This file is part of the irplib package
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., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
00019  */
00020 
00021 /*
00022  * $Author: lbilbao $
00023  * $Date: 2008/04/02 15:16:43 $
00024  * $Revision: 1.59 $
00025  * $Name: uves-3_9_0 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*---------------------------------------------------------------------------
00033                                   Includes
00034  ---------------------------------------------------------------------------*/
00035 
00036 #ifdef HAVE_FFTW
00037 #include <complex.h>
00038 
00039 #include <sfftw.h>
00040 
00041 #endif
00042 
00043 
00044 
00045 #include <math.h>
00046 #include <string.h>
00047 #include <assert.h>
00048 
00049 #include <cpl.h>
00050 
00051 #include "irplib_detmon.h"
00052 #include "irplib_detmon_lg.h"
00053 
00054 #include "irplib_utils.h"
00055 
00056 
00057 
00058 /*--------------------------------------------------------------------------*/
00059 
00060 /*
00061  * @defgroup irplib_detmon        Detector monitoring functions
00062  */
00063 
00064 /*--------------------------------------------------------------------------*/
00065 
00066 /*---------------------------------------------------------------------------
00067                                   Defines
00068  ---------------------------------------------------------------------------*/
00069 static struct
00070 {
00071     const char            * method;
00072     /* Inputs */
00073     int                     order;
00074     int                     kappa;
00075     int                     niter;
00076     int                     threshold_min;
00077     int                     threshold_max;
00078     int                     llx;
00079     int                     lly;
00080     int                     urx;
00081     int                     ury;
00082     int                     ref_level;
00083     int                     threshold;
00084     int                     m;
00085     int                     n;
00086     int                     llx1;
00087     int                     lly1;
00088     int                     urx1;
00089     int                     ury1;
00090     int                     llx2;
00091     int                     lly2;
00092     int                     urx2;
00093     int                     ury2;
00094     int                     llx3;
00095     int                     lly3;
00096     int                     urx3;
00097     int                     ury3;
00098     int                     llx4;
00099     int                     lly4;
00100     int                     urx4;
00101     int                     ury4;
00102     int                     llx5;
00103     int                     lly5;
00104     int                     urx5;
00105     int                     ury5;
00106     cpl_boolean             autocorr;
00107     cpl_boolean             intermediate;
00108     cpl_boolean             collapse;
00109     cpl_boolean             rescale;
00110     cpl_boolean             pix2pix;
00111     cpl_boolean             bpmbin;
00112     int                     filter;
00113     double                  tolerance;
00114     const char            * pafname;
00115     /* Outputs */
00116     double                  cr;
00117     int                     exts;
00118     int                     nb_extensions;
00119     double                  lamp_stability;
00120     cpl_boolean             lamp_ok;
00121 } detmon_lg_config;
00122 
00123 /*---------------------------------------------------------------------------
00124                                   Private function prototypes
00125  ---------------------------------------------------------------------------*/
00126 /*  Functions for the Linearity/Gain recipe, irplib_detmon_lg() */
00127 
00128 /*  Parameters */
00129 static cpl_error_code
00130 irplib_detmon_lg_retrieve_parlist(const char *,
00131                   const char *, const cpl_parameterlist *,
00132                                   cpl_boolean);
00133 
00134 
00135 static cpl_error_code
00136 irplib_detmon_lg_split_onoff(const cpl_frameset *,
00137                              cpl_frameset *,
00138                              cpl_frameset *,
00139                              const char *, const char * /*, cpl_boolean*/);
00140 
00141 static cpl_error_code
00142 irplib_detmon_lg_reduce(const cpl_frameset *,
00143                         const cpl_frameset *,
00144                         int *,
00145                         int *,
00146                         int,
00147                         cpl_imagelist **,
00148                         cpl_table *,
00149                         cpl_table *,
00150                         cpl_image **,
00151                         cpl_imagelist *,
00152                         cpl_imagelist *,
00153                         cpl_propertylist *,
00154          int                    (* load_fset) (const cpl_frameset *,
00155                                cpl_type,
00156                                                cpl_imagelist *),
00157                         const cpl_boolean, int);
00158 
00159 static cpl_error_code
00160 irplib_detmon_linearity(const cpl_frameset *,
00161                         cpl_table *,
00162                         cpl_table *,
00163                         cpl_imagelist *,
00164                         cpl_imagelist *,
00165                         cpl_imagelist *,
00166                         const int,
00167                         const int, cpl_propertylist *,
00168             const cpl_boolean);
00169 
00170 static cpl_error_code
00171 irplib_detmon_gain_table_fill_row(cpl_table *,
00172                   cpl_imagelist *,
00173                   cpl_imagelist *,
00174                   const cpl_imagelist *,
00175                   const cpl_imagelist *,
00176                                   double, int,
00177                                   int, int, int, int,
00178                   int, int, const int, unsigned);
00179 
00180 static                  cpl_error_code
00181 irplib_detmon_lg_save(const cpl_parameterlist *,
00182                       cpl_frameset *,
00183                       const char *,
00184                       const char *,
00185                       const char *,
00186                       const char *,
00187                       const char *,
00188                       const char *,
00189                       const char *,
00190                       const char *,
00191                       const char *,
00192                       const char *,
00193                       cpl_imagelist *,
00194                       cpl_table *,
00195                       cpl_table *,
00196                       cpl_image *,
00197                       cpl_imagelist *,
00198                       cpl_imagelist *,
00199                       cpl_propertylist *,
00200                       const int, const int, const cpl_frameset *,
00201                       int);
00202 
00203 static cpl_error_code
00204 irplib_detmon_lg_qc_ptc(const cpl_table  *,
00205             cpl_propertylist *, unsigned);
00206 
00207 static cpl_error_code
00208 irplib_detmon_lg_qc_med(const cpl_table  *,
00209             cpl_propertylist *);
00210 
00211 static cpl_error_code
00212 irplib_detmon_pair_extract(const cpl_frameset *,
00213                            int *, int,
00214                            int ,
00215                            int *,
00216                            int,
00217                            cpl_frameset **);
00218 
00219 
00220 
00221 static double
00222 irplib_pfits_get_dit(const cpl_propertylist *);
00223 
00224 static double
00225 irplib_pfits_get_dit_opt(const cpl_propertylist *);
00226 
00227 
00228 static cpl_image       *irplib_detmon_bpixs(const cpl_imagelist *, int *);
00229 
00230 static double
00231 irplib_detmon_autocorr_factor(const cpl_image *,
00232                               cpl_image **, int, int);
00233 
00234 /*
00235 #ifdef HAVE_FFTW
00236 static cpl_image       *irplib_detmon_image_autocorrelate_fftw(const cpl_image
00237                                                                *, const int,
00238                                                                const int);
00239 #endif
00240 */
00241 
00242 
00243 
00244 static                  cpl_error_code
00245 irplib_detmon_opt_contamination(const cpl_image *, cpl_propertylist *);
00246 
00247 //Deactivated until supported
00248 //static cpl_error_code              
00249 //irplib_detmon_opt_lampcr(cpl_frameset *, int);
00250 
00251 int
00252 irplib_detmon_lg_dfs_set_groups(cpl_frameset *, const char *, const char *);
00253 
00254 static cpl_error_code
00255 irplib_detmon_lg_reduce_all(const cpl_table *,
00256                 cpl_propertylist *,
00257                 cpl_imagelist **,
00258                 cpl_image **,
00259                             const cpl_imagelist *, 
00260                 const cpl_table *, int);
00261 
00262 static cpl_error_code          
00263 irplib_detmon_lg_check_defaults(const cpl_image *);
00264 
00265 static cpl_error_code          
00266 irplib_detmon_lg_rescale(cpl_imagelist *);
00267 
00268 static cpl_error_code
00269 irplib_detmon_lg_reduce_init(cpl_table *,
00270                              cpl_table *,
00271                              cpl_imagelist **);
00272 
00273 
00274 
00275 static cpl_error_code          
00276 irplib_detmon_add_adl_column(cpl_table *);
00277 
00278 static cpl_error_code
00279 irplib_detmon_lg_lamp_stab(const cpl_frameset *,
00280                const cpl_frameset *,
00281                            cpl_boolean);
00282 
00283 
00284 static cpl_error_code
00285 irplib_detmon_lg_reduce_dit(const cpl_frameset *,
00286                 int                *,
00287                 int                 ,
00288                 int                 ,
00289                 const cpl_frameset *,
00290                 int                *,
00291                 cpl_table          *,
00292                 cpl_table          *,
00293                 cpl_imagelist      *,
00294                 cpl_propertylist   *,
00295                 cpl_boolean         ,
00296                 cpl_imagelist      *,
00297                 cpl_imagelist      *,
00298                             cpl_imagelist      *,
00299                 int (*)(const cpl_frameset *,
00300                     cpl_type,
00301                     cpl_imagelist *), int);
00302 
00303 static cpl_error_code
00304 irplib_detmon_lg_core(cpl_frameset *,
00305               cpl_frameset *,
00306               int *,
00307               int *,
00308               int ,
00309               int ,
00310                       int ,
00311               const char              *,
00312               const char              *,
00313               const char              *,
00314               const char              *,
00315               const char              *,
00316               const char              *,
00317               const char              *,
00318               const char              *,
00319               const char              *,
00320               const char              *,
00321               int                    (*) (const cpl_frameset *,
00322                                 cpl_type,
00323                                 cpl_imagelist *),
00324               int, cpl_boolean,
00325                       cpl_frameset *,  const cpl_parameterlist *, cpl_frameset *);
00326 
00327 static cpl_error_code
00328 irplib_detmon_lg_lineff(double *, cpl_propertylist *);
00329 
00330 
00331 static int
00332 irplib_detmon_lg_compare_pairs(const cpl_frame *,
00333                    const cpl_frame *);
00334 
00335 static cpl_error_code
00336 irplib_detmon_gain_table_create(cpl_table *);
00337 
00338 static cpl_vector *
00339 irplib_detmon_lg_find_dits(const cpl_vector * exptimes);
00340 
00341 /*--------------------------------------------------------------------------*/
00342 
00343 /*
00344  * @brief  Reduce linearity and gain in the IR domain
00345  * @param  parlist              List of required parameters
00346  * @param  frameset             Input frameset
00347  * @param  tag_on               Tag to identify the ON frames
00348  * @param  tag_off              Tag to identify the OFF frames
00349  * @param  recipe_name          Name of the recipe calling this function
00350  * @param  pipeline_name        Name of the pipeline calling this function
00351  * @param  procatg_lintbl       PRO.CATG keyword for the Linearity Table
00352  * @param  procatg_gaintbl      PRO.CATG keyword for the Gain Table
00353  * @param  procatg_coeffscube     PRO.CATG keyword for the
00354  *                              Linearity Coefficients' Images
00355  * @param  procatg_bpm          PRO.CATG required for the Bad Pixel Map
00356  * @param  procatg_corr     PRO.CATG required for the Autocorrelation Images
00357  *                              (Intermediate product - only created if required)
00358  * @param  procatg_diff         PRO.CATG required for the Difference Images
00359  *                              (Intermediate Product - only created if required)
00360  * @param  package              PACKAGE (incl. VERSION) required
00361  *                              for the DFS keywords
00362  * @param  compare              Compare function used to classified frameset into
00363  *                              different settings, if any.
00364  * @param  load_fset            Loading function for preprocessing of input
00365                                 frames with special data format (needed for
00366                                 AMBER and MIDI processing)
00367 
00368  * @param  opt_nir              Boolean parameter to activate/deactivate
00369  *                              OPT-only / IR-only parts of the recipe
00370  * @return 0 on success, -1 on fail.
00371  * @note: The parlist contains the following parameters:
00372  *
00373  * @par1  kappa                 Kappa value used for the kappa-sigma clipping
00374  *                              rejection of bad pixels when computing sigma for
00375  *                              gain calculation
00376  * @par2  niter                 Number of iterations for the kappa-sigma clipping
00377  * @par3  threshold_min         Minimum threshold of the k-sigma (Not applied)
00378  * @par4  threshold_max         Maximum threshold of the k-sigma (Not applied)
00379  * @par5  llx                   Region of Interest (Default to the whole area)
00380  * @par6  lly                   Region of Interest (Default to the whole area)
00381  * @par7  urx                   Region of Interest (Default to the whole area)
00382  * @par8  ury                   Region of Interest (Default to the whole area)
00383  * @par9  ref_level             Reference Level (Not applied)
00384  * @par10 threshold             Threshold (Not applied)
00385  * @par11 intermediate          Boolean to activate the production of
00386  *                              Intermediate Products
00387  * @par12 autocorr              Boolean to activate autocorr method
00388  * @par13 collapse              Boolean to activate collapse of OFF frames
00389  * @par14 rescale               Boolean to activate pair rescaling
00390  * @par15 m                     X-Shift of the autocorrelation
00391  * @par16 n                     Y-Shift of the autocorrelation
00392  * @par17 llx1                  Region of Interest 1 (Only OPT)
00393  * @par18 lly1                  Region of Interest 1 (Only OPT)
00394  * @par19 urx1                  Region of Interest 1 (Only OPT)
00395  * @par20 ury1                  Region of Interest 1 (Only OPT)
00396  * @par21 llx2                  Region of Interest 2 (Only OPT)
00397  * @par22 lly2                  Region of Interest 2 (Only OPT)
00398  * @par23 urx2                  Region of Interest 2 (Only OPT)
00399  * @par24 ury2                  Region of Interest 2 (Only OPT)
00400  * @par25 llx3                  Region of Interest 3 (Only OPT)
00401  * @par26 lly3                  Region of Interest 3 (Only OPT)
00402  * @par27 urx3                  Region of Interest 3 (Only OPT)
00403  * @par28 ury3                  Region of Interest 3 (Only OPT)
00404  * @par29 llx4                  Region of Interest 4 (Only OPT)
00405  * @par30 lly4                  Region of Interest 4 (Only OPT)
00406  * @par31 urx4                  Region of Interest 4 (Only OPT)
00407  * @par32 ury4                  Region of Interest 4 (Only OPT)
00408  * @par33 llx5                  Region of Interest 5 (Only OPT)
00409  * @par34 lly5                  Region of Interest 5 (Only OPT)
00410  * @par35 urx5                  Region of Interest 5 (Only OPT)
00411  * @par36 ury5                  Region of Interest 5 (Only OPT)
00412  * @par37 exts                  Integer to select extension 
00413  */
00414 
00415 /*--------------------------------------------------------------------------*/
00416 
00417 cpl_error_code
00418 irplib_detmon_lg(cpl_frameset            * frameset,
00419                  const cpl_parameterlist * parlist,
00420                  const char              * tag_on,
00421                  const char              * tag_off,
00422                  const char              * recipe_name,
00423                  const char              * pipeline_name,
00424                  const char              * pafregexp,
00425                  const char              * procatg_lintbl,
00426                  const char              * procatg_gaintbl,
00427                  const char              * procatg_coeffscube,
00428                  const char              * procatg_bpm,
00429                  const char              * procatg_corr,
00430                  const char              * procatg_diff,
00431                  const char              * package,
00432                  int                    (* compare) (const cpl_frame *,
00433                              const cpl_frame *),
00434          int                    (* load_fset) (const cpl_frameset *,
00435                                cpl_type,
00436                                                cpl_imagelist *),
00437                  const cpl_boolean         opt_nir)
00438 {
00439     int              nsets;
00440     int            * selection = NULL;
00441     int              i;
00442     cpl_frame      * first     = NULL;
00443     cpl_image      * reference = NULL;
00444     cpl_frameset   * set       = NULL;
00445 
00446     /*
00447      * Variables used only inside the for() statement.
00448      * However, there are declared here to ease
00449      * memory management in error case.
00450      */
00451     int              * selection_on    = NULL;
00452     int              * selection_off   = NULL;
00453     cpl_frameset     * cur_fset        = NULL;
00454     cpl_frameset     * cur_fset_on     = NULL;        
00455     cpl_frameset     * cur_fset_off    = NULL;
00456 
00457     /* Test entries */
00458     cpl_ensure_code(frameset           != NULL, CPL_ERROR_NULL_INPUT);
00459     cpl_ensure_code(parlist            != NULL, CPL_ERROR_NULL_INPUT);
00460     cpl_ensure_code(tag_on             != NULL, CPL_ERROR_NULL_INPUT);
00461     cpl_ensure_code(tag_off            != NULL, CPL_ERROR_NULL_INPUT);
00462     cpl_ensure_code(recipe_name        != NULL, CPL_ERROR_NULL_INPUT);
00463     cpl_ensure_code(pipeline_name      != NULL, CPL_ERROR_NULL_INPUT);
00464     cpl_ensure_code(procatg_lintbl     != NULL, CPL_ERROR_NULL_INPUT);
00465     cpl_ensure_code(procatg_gaintbl    != NULL, CPL_ERROR_NULL_INPUT);
00466     cpl_ensure_code(procatg_coeffscube != NULL, CPL_ERROR_NULL_INPUT);
00467     cpl_ensure_code(procatg_bpm        != NULL, CPL_ERROR_NULL_INPUT);
00468     cpl_ensure_code(procatg_corr       != NULL, CPL_ERROR_NULL_INPUT);
00469     cpl_ensure_code(procatg_diff       != NULL, CPL_ERROR_NULL_INPUT);
00470     cpl_ensure_code(package            != NULL, CPL_ERROR_NULL_INPUT);
00471 
00472     skip_if (irplib_detmon_lg_dfs_set_groups(frameset, tag_on, tag_off));
00473 
00474     /*
00475      * First check of input consistency in NIR case:
00476      * There must be a pair ON and a pair OFF for each DIT.
00477      */
00478     irplib_ensure(!(opt_nir == NIR && 
00479                     cpl_frameset_get_size(frameset) % 4 != 0),
00480           CPL_ERROR_ILLEGAL_INPUT,
00481                   "For NIR data an even number of ON frames "
00482                   "and an even number of off frames is required");
00483 
00484  
00485     skip_if (irplib_detmon_lg_retrieve_parlist(pipeline_name, recipe_name,
00486                            parlist, opt_nir));
00487 
00488     /*
00489      * Retrieve first image to check some parameters' values and
00490      * set default values which refer to the image.
00491      */
00492 
00493     first = cpl_frameset_get_first(frameset);
00494     irplib_ensure (first != NULL, CPL_ERROR_ILLEGAL_INPUT, "Empty data set!");
00495 
00496     if (detmon_lg_config.exts < 0) {
00497         reference = cpl_image_load(cpl_frame_get_filename(first),
00498                                    CPL_TYPE_FLOAT, 0, 1);
00499     } else {
00500     if (load_fset != NULL) {
00501         cpl_frameset * new = cpl_frameset_new();
00502         cpl_imagelist * p = cpl_imagelist_new();
00503         cpl_frameset_insert(new, cpl_frame_duplicate(first));
00504         (*load_fset)(new, CPL_TYPE_FLOAT, p);
00505         reference = cpl_image_duplicate(cpl_imagelist_get(p, 0));
00506         cpl_imagelist_delete(p);
00507         cpl_frameset_delete(new);
00508     } else {
00509            cpl_msg_info(cpl_func,"name=%s",cpl_frame_get_filename(first));
00510         reference = cpl_image_load(cpl_frame_get_filename(first),
00511                        CPL_TYPE_FLOAT, 0, detmon_lg_config.exts);
00512     }
00513     }
00514     skip_if (reference == NULL);
00515 
00516     skip_if (irplib_detmon_lg_check_defaults(reference));
00517 
00518     /* Labelise all input frames */
00519     set = cpl_frameset_duplicate(frameset);
00520     /*
00521      * After each setting iteration, frameset will be modified (product
00522      * frames will have been added), so it is better to duplicate it, keep
00523      * it in its original state for the labelise-extract scheme.
00524      */
00525     if (compare == NULL) {
00526         nsets = 1;
00527     } else {
00528         cpl_msg_info(cpl_func, "Identifying different settings");
00529         selection = cpl_frameset_labelise(set, compare, &nsets);
00530         skip_if (selection == NULL);
00531     }
00532 
00533     /* Get the nb of extensions */
00534     detmon_lg_config.nb_extensions = 1;
00535     if (detmon_lg_config.exts < 0) {
00536     detmon_lg_config.nb_extensions = cpl_frame_get_nextensions(first);
00537     }
00538 
00539     /* Extract settings and reduce each of them */
00540     for(i = 0; i < nsets; i++) {
00541     int  j;
00542     int nexts = detmon_lg_config.nb_extensions;
00543 
00544     int  nsets_on  = 0;
00545     int  nsets_off = 0;
00546 
00547     /* Reduce data set nb i */
00548     cpl_msg_info(cpl_func, "Reduce data set nb %d out of %d",
00549              i + 1, nsets);
00550 
00551     cur_fset = nsets == 1 ?
00552         cpl_frameset_duplicate(set) : 
00553         cpl_frameset_extract(set, selection, i);   
00554     skip_if(cur_fset == NULL);
00555 
00556     /* Split input frameset into 2 sub-framesets for ON and OFF frames */
00557     cur_fset_on  = cpl_frameset_new();
00558     cur_fset_off = cpl_frameset_new();
00559     cpl_msg_info(cpl_func, "Splitting into ON and OFF sub-framesets");
00560     skip_if (irplib_detmon_lg_split_onoff(cur_fset,
00561                           cur_fset_on, cur_fset_off,
00562                           tag_on, tag_off /*, opt_nir*/));
00563 
00564     /* Labelise each sub-frameset according to DIT values */
00565     selection_on = cpl_frameset_labelise(cur_fset_on,
00566                          irplib_detmon_lg_compare_pairs,
00567                          &nsets_on);
00568     skip_if (selection_on == NULL);
00569 
00570     if (!detmon_lg_config.collapse) {
00571         selection_off = cpl_frameset_labelise(cur_fset_off,
00572                           irplib_detmon_lg_compare_pairs,
00573                           &nsets_off);
00574         skip_if (selection_off == NULL);
00575     }
00576 
00577     /* Test if they have equal nb of labels */
00578     if (!detmon_lg_config.collapse) {
00579         skip_if(nsets_on != nsets_off);
00580     }
00581 
00582     if(nsets_on <= detmon_lg_config.order) {
00583         cpl_msg_error(cpl_func, "Not enough frames for the polynomial"
00584               " fitting. nsets <= order.");
00585         skip_if(1);
00586     }
00587 
00588     if(detmon_lg_config.exts >= 0) {
00589         /*
00590          * In the optical domain, the first 2 frames
00591          * are used apart from the pairs.
00592          */
00593 // Count rate computation inactive until supported
00594 //      if (detmon_lg_config.lamp_ok) {
00595 //      skip_if(irplib_detmon_opt_lampcr(cur_fset, 0));
00596 //      }
00597         skip_if(irplib_detmon_lg_core(cur_fset_on, cur_fset_off, selection_on,
00598                       selection_off, nsets_on, detmon_lg_config.exts, i, recipe_name, pipeline_name, pafregexp, procatg_lintbl, procatg_gaintbl, procatg_coeffscube, procatg_bpm, procatg_corr, procatg_diff, package, load_fset, nsets, opt_nir, frameset, parlist, cur_fset));
00599     } else {
00600         for(j = 1; j <= nexts; j++) {
00601         /*
00602          * In the optical domain, the first 2 frames
00603          * are used apart from the pairs.
00604          */
00605 // Count rate computation inactive until supported
00606 //      if (detmon_lg_config.lamp_ok) {
00607 //          skip_if(irplib_detmon_opt_lampcr(cur_fset, j));
00608 //      }
00609 
00610 
00611         skip_if(irplib_detmon_lg_core(cur_fset_on, cur_fset_off, selection_on,
00612                           selection_off, nsets_on, j, i,  recipe_name, pipeline_name,pafregexp,  procatg_lintbl, procatg_gaintbl, procatg_coeffscube, procatg_bpm, procatg_corr, procatg_diff, package, load_fset, nsets, opt_nir, frameset, parlist, cur_fset));
00613         }
00614     }
00615 
00616     /* Free for each setting */
00617     cpl_free(selection_on);
00618     cpl_free(selection_off);
00619 
00620     cpl_frameset_delete(cur_fset);
00621     cpl_frameset_delete(cur_fset_on);
00622     cpl_frameset_delete(cur_fset_off);
00623 
00624     selection_on  = NULL;
00625     selection_off = NULL;
00626     cur_fset      = NULL;
00627     cur_fset_on   = NULL;
00628     cur_fset_off  = NULL;
00629     }
00630 
00631     end_skip;
00632 
00633     cpl_free(selection_on);
00634     cpl_free(selection_off);
00635 
00636     cpl_frameset_delete(cur_fset);
00637     cpl_frameset_delete(cur_fset_on);
00638     cpl_frameset_delete(cur_fset_off);
00639 
00640     cpl_frameset_delete(set);
00641     cpl_free(selection);
00642     cpl_image_delete(reference);
00643 
00644     return cpl_error_get_code();
00645 }
00646 
00647 /*---------------------------------------------------------------------------*/
00680 /*---------------------------------------------------------------------------*/
00681 
00682 static cpl_error_code
00683 irplib_detmon_lg_core(cpl_frameset * cur_fset_on,
00684               cpl_frameset * cur_fset_off,
00685               int * selection_on,
00686               int * selection_off,
00687               int nsets_on,
00688               int whichext,
00689                       int whichset,
00690               const char              * recipe_name,
00691               const char              * pipeline_name,
00692               const char              * pafregexp,
00693               const char              * procatg_lintbl,
00694               const char              * procatg_gaintbl,
00695               const char              * procatg_coeffscube,
00696               const char              * procatg_bpm,
00697               const char              * procatg_diff,
00698               const char              * procatg_corr,
00699               const char              * package,
00700               int                    (* load_fset) (const cpl_frameset *,
00701                                 cpl_type,
00702                                 cpl_imagelist *),
00703               int nsets, cpl_boolean opt_nir,
00704                       cpl_frameset * frameset, const cpl_parameterlist * parlist,
00705                       cpl_frameset * cur_fset)
00706 {
00707     cpl_table        * gain_table      = cpl_table_new(cpl_frameset_get_size(cur_fset_on)/2);
00708     cpl_table        * linear_table    = cpl_table_new(cpl_frameset_get_size(cur_fset_on)/2);
00709     cpl_imagelist    * coeffs          = NULL;
00710     cpl_image        * bpm             = NULL;
00711     cpl_imagelist    * autocorr_images = NULL;
00712     cpl_imagelist    * diff_flats      = NULL;
00713     cpl_propertylist * qclist          = NULL;
00714 
00715     /* Reduce extension nb i */
00716     cpl_msg_info(cpl_func, "Reduce extension nb %d ",
00717          whichext);
00718 
00719     /* FIXME: All other memory objects in use should be 
00720        initialised here (except coeffs which can not be) */
00721     if (detmon_lg_config.intermediate) {
00722     autocorr_images = cpl_imagelist_new();
00723     diff_flats      = cpl_imagelist_new();
00724     }
00725     qclist = cpl_propertylist_new();
00726 
00727     /* Reduction done here */
00728     cpl_msg_info(cpl_func, "Starting data reduction");
00729     skip_if(irplib_detmon_lg_reduce(cur_fset_on, cur_fset_off,
00730                     selection_on, selection_off,
00731                     nsets_on, &coeffs, gain_table,
00732                     linear_table, &bpm, autocorr_images,
00733                     diff_flats, qclist, load_fset,
00734                     opt_nir, whichext));
00735 
00736     /* Save the products for each setting */
00737     cpl_msg_info(cpl_func, "Saving the products");
00738     if(nsets == 1) {
00739     skip_if(irplib_detmon_lg_save(parlist, frameset, recipe_name,
00740                       pipeline_name, pafregexp,
00741                       procatg_lintbl, procatg_gaintbl,
00742                       procatg_coeffscube, procatg_bpm,
00743                       procatg_corr, procatg_diff, package,
00744                       coeffs, gain_table, linear_table,
00745                       bpm, autocorr_images, diff_flats,
00746                       qclist, 0, 0, cur_fset, whichext));
00747     } else {
00748     skip_if(irplib_detmon_lg_save(parlist, frameset, recipe_name,
00749                       pipeline_name, pafregexp,
00750                       procatg_lintbl, procatg_gaintbl,
00751                       procatg_coeffscube, procatg_bpm,
00752                       procatg_corr, procatg_diff, package,
00753                       coeffs, gain_table, linear_table,
00754                       bpm, autocorr_images, diff_flats,
00755                       qclist, 1, whichset+ 1, cur_fset, whichext));
00756     }
00757 
00758     end_skip;
00759 
00760     /* Free for each extension */
00761     cpl_table_delete(gain_table);
00762     cpl_table_delete(linear_table);
00763     cpl_imagelist_delete(coeffs);
00764     cpl_propertylist_delete(qclist);
00765     cpl_image_delete(bpm);
00766     cpl_imagelist_delete(autocorr_images);
00767     cpl_imagelist_delete(diff_flats);
00768 
00769     return cpl_error_get_code();
00770 }
00771 /*--------------------------------------------------------------------------*/
00772 
00773 /*
00774  * @brief  Correlate two images with a given range of shifts
00775  * @param  image1       Input image
00776  * @param  image2       Input image
00777  * @param  m            Shift to apply on the x-axis
00778  * @param  n            Shift to apply on the y-axis
00779  * @return              An image of size 2m+1 by 2n+1. Each pixel value
00780  *                      corresponds to the correlation of shift the position
00781  *                      of the pixel. Pixel in the centre (m+1, n+1),
00782  *                      corresponds to shift (0,0). Pixels to the left and
00783  *                      down correspond to negative shifts.
00784  *
00785  * @note                At this moment, this function only accepts images to
00786  *                      have both the same size.
00787  */
00788 
00789 /*--------------------------------------------------------------------------*/
00790 #ifdef HAVE_FFTW
00791 
00792 cpl_image              *
00793 irplib_detmon_image_correlate(const cpl_image * image1,
00794                               const cpl_image * image2,
00795                               const int m, const int n)
00796 {
00797     cpl_image              *image1_padded;
00798     cpl_image              *image2_padded;
00799     float                  *data1;
00800     float                  *data2;
00801     int                     nx, ny;
00802     int                     nx2, ny2;
00803     int                     i;
00804 
00805     fftwnd_plan              p1;
00806     fftw_complex          *in1;
00807     fftw_complex          *ri1;
00808 
00809     fftwnd_plan              p2;
00810     fftw_complex          *in2;
00811     fftw_complex          *ri2;
00812 
00813     fftwnd_plan              p_inv;
00814     fftw_complex          *in_inv;
00815     fftw_complex          *ri_inv;
00816 
00817     fftw_complex          *corr;
00818     float                  *corr_r;
00819 
00820     cpl_image              *corr_image;
00821     cpl_image              *corr_image_window;
00822     cpl_image              *reorganised;
00823     cpl_image              *image;
00824 
00825 //    fftwf_init_threads();
00826 //    fftwf_plan_with_nthreads(2);
00827 
00828     /* Test the entries */
00829     cpl_ensure(image1 != NULL, CPL_ERROR_NULL_INPUT, NULL);
00830     cpl_ensure(image2 != NULL, CPL_ERROR_NULL_INPUT, NULL);
00831 
00832     cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
00833     cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
00834 
00835     nx = cpl_image_get_size_x(image1);
00836     ny = cpl_image_get_size_y(image1);
00837 
00838     nx2 = cpl_image_get_size_x(image2);
00839     ny2 = cpl_image_get_size_y(image2);
00840 
00841     /* At this moment, the images must be of the same size */
00842     cpl_ensure(nx == nx2 && ny == ny2, CPL_ERROR_ILLEGAL_INPUT, NULL);
00843 
00844     /* Pad the images with zeroes to avoid periodical effects of DFT */
00845     image1_padded = cpl_image_new(nx + 2 * m, ny + 2 * n, CPL_TYPE_FLOAT);
00846     cpl_image_copy(image1_padded, image1, m + 1, n + 1);
00847 
00848     image2_padded = cpl_image_new(nx + 2 * m, ny + 2 * n, CPL_TYPE_FLOAT);
00849     cpl_image_copy(image2_padded, image2, m + 1, n + 1);
00850 
00851     /* Get pointers to the pixel data */
00852     data1 = cpl_image_get_data_float(image1_padded);
00853     data2 = cpl_image_get_data_float(image2_padded);
00854 
00855     /*New dimensions of the padded images */
00856     nx = nx + 2 * m;
00857     ny = ny + 2 * n;
00858 
00859     /* Establish the input/output data arrays and the FFT plan */
00860     in1 = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * nx * ny);
00861     ri1 = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * nx * ny);
00862 //    p1 = fftw_plan_dft_2d(ny, nx, in1, ri1, FFTW_FORWARD, FFTW_ESTIMATE);
00863     p1 = fftw2d_create_plan_specific(ny, nx, FFTW_FORWARD, FFTW_ESTIMATE,
00864                      in1, 1, ri1, 1);
00865 
00866     /* Pack the CPL image data into the FFTW input array */
00867     for(i = 0; i < nx * ny; i++) {
00868         *((float complex *)in1 + i) = (*(data1 + i) + 0.0 * I);
00869     }
00870 
00871     /* Actually perform the FFT */
00872     fftwnd_one(p1, in1, ri1);
00873 
00874     /* Cleanup resources */
00875     fftwnd_destroy_plan(p1);
00876     cpl_image_delete(image1_padded);
00877 
00878     /* Establish the input/output data arrays and the FFT plan */
00879     in2 = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * nx * ny);
00880     ri2 = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * nx * ny);
00881 
00882 //    p2 = fftwf_plan_dft_2d(ny, nx, in2, ri2, FFTW_FORWARD, FFTW_ESTIMATE)
00883 ;    p2 = fftw2d_create_plan_specific(ny, nx, FFTW_FORWARD, FFTW_ESTIMATE,
00884                       in2, 1, ri2, 1);
00885 
00886 
00887     /* Pack the CPL image data into the FFTW input array */
00888     for(i = 0; i < nx * ny; i++) {
00889         *((float complex *)in2 + i) = (*(data2 + i) + 0.0 * I);
00890     }
00891 
00892     /* Actually perform the FFT */
00893     fftwnd_one(p2, in2, ri2);
00894 
00895     /* Cleanup resources */
00896     fftwnd_destroy_plan(p2);
00897     cpl_image_delete(image2_padded);
00898 
00899     /* Establish the input/output data arrays and the FFT plan */
00900     in_inv = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * nx * ny);
00901     ri_inv = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * nx * ny);
00902 //    p_inv = fftwf_plan_dft_2d(ny, nx, in_inv, ri_inv,
00903     //                            FFTW_BACKWARD, FFTW_ESTIMATE);
00904     p_inv = fftw2d_create_plan_specific(ny, nx, FFTW_FORWARD, FFTW_ESTIMATE,
00905                     in_inv, 1, ri_inv, 1);
00906 
00907     /* Correlation in the Fourier domain: G*[n]·H[n] */
00908     for(i = 0; i < nx * ny; i++) {
00909         *((float complex *)in_inv + i) = conjf(*((float complex *)ri1 + i)) *
00910         (*((float complex *)ri2+i));
00911     }
00912 
00913     /* Cleanup resources */
00914     fftw_free(in1);
00915     fftw_free(ri1);
00916 
00917     fftw_free(in2);
00918     fftw_free(ri2);
00919 
00920     /* Actually perform the FFT */
00921     fftwnd_one(p_inv, in_inv, ri_inv);
00922 
00923     /* Cleanup FFTW resources */
00924     fftwnd_destroy_plan(p_inv);
00925 
00926     /* Get the module of the inversed signal */
00927     corr = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * nx * ny);
00928     corr_r = (float *) cpl_malloc(sizeof(float) * nx * ny);
00929 
00930     for(i = 0; i < nx * ny; i++) {
00931         *((float complex *)corr + i) = conjf(*((float complex *)ri_inv + i));
00932         *((float complex *)corr + i) *= *((float complex *)ri_inv + i);
00933         *(corr_r + i) = crealf(*((float complex *)corr + i));
00934     }
00935     fftw_free(in_inv);
00936     fftw_free(ri_inv);
00937 
00938     /* Wrap the data onto an image */
00939     corr_image = cpl_image_wrap_float(nx, ny, corr_r);
00940 
00941     /* Cleanup resources */
00942     fftw_free(corr);
00943 
00944 //    fftwf_cleanup_threads();
00945 
00946     /* Reorganise the pixels to the output */
00947     reorganised = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00948 
00949     image = cpl_image_extract(corr_image, nx / 2 + 1, 1, nx, ny);
00950     cpl_image_copy(reorganised, image, 1, 1);
00951     cpl_image_delete(image);
00952 
00953     image = cpl_image_extract(corr_image, 1, 1, nx / 2, ny);
00954     cpl_image_copy(reorganised, image, nx / 2 + 1, 1);
00955     cpl_image_delete(image);
00956 
00957     cpl_image_unwrap(corr_image);
00958     cpl_free(corr_r);
00959 
00960     corr_image = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00961 
00962     image = cpl_image_extract(reorganised, 1, ny / 2 + 1, nx, ny);
00963     cpl_image_copy(corr_image, image, 1, 1);
00964     cpl_image_delete(image);
00965 
00966     image = cpl_image_extract(reorganised, 1, 1, nx, ny / 2);
00967     cpl_image_copy(corr_image, image, 1, ny / 2 + 1);
00968     cpl_image_delete(image);
00969 
00970     /* Extract a window with the desired shifts */
00971     corr_image_window = cpl_image_extract(corr_image,
00972                                           nx / 2 + 1 - m,
00973                                           ny / 2 + 1 - n,
00974                                           nx / 2 + 1 + m, ny / 2 + 1 + n);
00975 
00976     /* Free and return */
00977     cpl_image_delete(reorganised);
00978     cpl_image_delete(corr_image);
00979 
00980     if(cpl_image_divide_scalar(corr_image_window,
00981                                cpl_image_get_max(corr_image_window))) {
00982         cpl_image_delete(corr_image_window);
00983         return NULL;
00984     }
00985 
00986     return corr_image_window;
00987 }
00988 
00989 /*
00990 static cpl_image       *
00991 irplib_detmon_image_autocorrelate_fftw(const cpl_image * image,
00992                                        const int m, const int n)
00993 {
00994     cpl_image              *input;
00995     cpl_image              *image_padded;
00996 
00997     int                     nx, ny;
00998     int                     i;
00999 
01000     fftwf_plan              p1;
01001     fftwf_complex          *fourier;
01002     fftwf_plan              p_inv;
01003 
01004     cpl_image              *corr_image;
01005     cpl_image              *corr_image_window;
01006     cpl_image              *reorganised;
01007     cpl_image              *image1;
01008     int                     npix;
01009     size_t                  bigsize;
01010     float                  *in;
01011 
01012 
01013     cpl_ensure(image != NULL, CPL_ERROR_NULL_INPUT, NULL);
01014 
01015     cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
01016     cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
01017 
01018     nx = cpl_image_get_size_x(image);
01019     ny = cpl_image_get_size_y(image);
01020 
01021     npix = (nx + 2 * m) * (ny + 2 * n);
01022 
01023 
01024     bigsize = 2 * (npix / 2 + 1);
01025 
01026 
01027     in = (float *) fftw_malloc(sizeof(float) * bigsize);
01028 
01029 
01030     input = cpl_image_cast(image, CPL_TYPE_FLOAT);
01031 
01032     image_padded = cpl_image_wrap_float(nx, ny, in);
01033     cpl_image_copy(image_padded, input, m + 1, n + 1);
01034     cpl_image_delete(input);
01035 
01036 
01037     nx = nx + 2 * m;
01038     ny = ny + 2 * n;
01039 
01040 
01041     fourier = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * nx * ny);
01042     p1 = fftwf_plan_dft_r2c_2d(ny, nx, in, fourier, FFTW_FORWARD);
01043 
01044 
01045     fftwf_execute(p1);
01046 
01047 
01048     fftwf_destroy_plan(p1);
01049     cpl_image_unwrap(image_padded);
01050 
01051 
01052     p_inv = fftwf_plan_dft_c2r_2d(ny, nx, fourier, in, FFTW_BACKWARD);
01053 
01054 
01055     for(i = 0; i < nx * ny; i++) {
01056         fourier[i] = conj(fourier[i]) * fourier[i];
01057     }
01058 
01059 
01060     fftwf_execute(p_inv);
01061 
01062 
01063     fftwf_destroy_plan(p_inv);
01064 
01065     fftwf_free(fourier);
01066 
01067 
01068     corr_image = cpl_image_wrap_float(nx, ny, in);
01069 
01070 
01071     reorganised = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01072 
01073     image1 = cpl_image_extract(corr_image, nx / 2 + 1, 1, nx, ny);
01074     cpl_image_copy(reorganised, image1, 1, 1);
01075     cpl_image_delete(image1);
01076 
01077     image1 = cpl_image_extract(corr_image, 1, 1, nx / 2, ny);
01078     cpl_image_copy(reorganised, image1, nx / 2 + 1, 1);
01079     cpl_image_delete(image1);
01080 
01081     cpl_image_unwrap(corr_image);
01082     fftwf_free(in);
01083 
01084     corr_image = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01085     image1 = cpl_image_extract(reorganised, 1, ny / 2 + 1, nx, ny);
01086     cpl_image_copy(corr_image, image1, 1, 1);
01087     cpl_image_delete(image1);
01088 
01089     image1 = cpl_image_extract(reorganised, 1, 1, nx, ny / 2);
01090     cpl_image_copy(corr_image, image1, 1, ny / 2 + 1);
01091     cpl_image_delete(image1);
01092 
01093 
01094     corr_image_window = cpl_image_extract(corr_image,
01095                                           nx / 2 + 1 - m,
01096                                           ny / 2 + 1 - n,
01097                                           nx / 2 + 1 + m, ny / 2 + 1 + n);
01098 
01099 
01100     cpl_image_delete(reorganised);
01101     cpl_image_delete(corr_image);
01102 
01103     if(cpl_image_divide_scalar(corr_image_window,
01104                                cpl_image_get_max(corr_image_window))) {
01105         cpl_image_delete(corr_image_window);
01106         return NULL;
01107     }
01108 
01109     return corr_image_window;
01110 }
01111 */
01112 
01113 #endif
01114 
01115 /*--------------------------------------------------------------------------*/
01116 
01117 /*
01118  * @brief  Autocorrelate an image with a given range of shifts, using
01119  *         cpl_image_fft()
01120  * @param  input2       Input image
01121  * @param  m            Shift to apply on the x-axis
01122  * @param  n            Shift to apply on the y-axis
01123  * @return              An image of size 2m+1 by 2n+1. Each pixel value
01124  *                      corresponds to the correlation of shift the position
01125  *                      of the pixel. Pixel in the centre (m+1, n+1),
01126  *                      corresponds to shift (0,0). Pixels to the left and
01127  *                      down correspond to negative shifts.
01128  */
01129 
01130 /*--------------------------------------------------------------------------*/
01131 
01132 cpl_image              *
01133 irplib_detmon_autocorrelate(const cpl_image * input2, const int m,
01134                             const int n)
01135 {
01136     cpl_image              *im_re = NULL;
01137     cpl_image              *im_im = NULL;
01138     int                     nx, ny;
01139     cpl_image              *ifft_re = NULL;
01140     cpl_image              *ifft_im = NULL;
01141     cpl_image              *autocorr = NULL;
01142     cpl_image              *autocorr_norm_double = NULL;
01143     cpl_image              *autocorr_norm = NULL;
01144 
01145 //    double                  max;
01146     cpl_image              *reorganised = NULL;
01147     cpl_image              *image = NULL;
01148     int                     p;
01149     cpl_error_code          error;
01150     cpl_image              *input;
01151 
01152     cpl_ensure(input2 != NULL, CPL_ERROR_NULL_INPUT, NULL);
01153 
01154     cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
01155     cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
01156 
01157     nx = cpl_image_get_size_x(input2) + 2 * m;
01158     ny = cpl_image_get_size_y(input2) + 2 * n;
01159 
01160     p = 128;
01161     while(nx > p || ny > p) {
01162         p *= 2;
01163     }
01164 
01165     input = cpl_image_cast(input2, CPL_TYPE_DOUBLE);
01166 
01167     im_re = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01168     error = cpl_image_copy(im_re, input, 1, 1);
01169     cpl_ensure(!error, error, NULL);
01170 
01171     im_im = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01172 
01173     error = cpl_image_fft(im_re, im_im, CPL_FFT_DEFAULT);
01174     cpl_ensure(!error, error, NULL);
01175 
01176     ifft_re = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01177     //ifft_im = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
01178 
01179     error = cpl_image_power(im_re, 2);
01180     cpl_ensure(!error, error, NULL);
01181 
01182     error = cpl_image_add(ifft_re, im_re);
01183     cpl_ensure(!error, error, NULL);
01184 
01185     cpl_image_delete(im_re);
01186 
01187     error = cpl_image_power(im_im, 2);
01188     cpl_ensure(!error, error, NULL);
01189 
01190     error = cpl_image_add(ifft_re, im_im);
01191     cpl_ensure(!error, error, NULL);
01192 
01193     cpl_image_delete(im_im);
01194 
01195     ifft_im = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01196 
01197     error = cpl_image_fft(ifft_re, ifft_im, CPL_FFT_INVERSE);
01198     cpl_ensure(!error, error, NULL);
01199 
01200     autocorr = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01201 
01202     error = cpl_image_power(ifft_re, 2);
01203     cpl_ensure(!error, error, NULL);
01204 
01205     error = cpl_image_add(autocorr, ifft_re);
01206     cpl_ensure(!error, error, NULL);
01207 
01208     cpl_image_delete(ifft_re);
01209 
01210     error = cpl_image_power(ifft_im, 2);
01211     cpl_ensure(!error, error, NULL);
01212 
01213     error = cpl_image_add(autocorr, ifft_im);
01214     cpl_ensure(!error, error, NULL);
01215 
01216     cpl_image_delete(ifft_im);
01217 
01218 //    max = cpl_image_get_max(autocorr);
01219 
01220     //   cpl_image_divide_scalar(autocorr, max);
01221 
01222     /* Reorganise the pixels to the output */
01223     reorganised = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01224 
01225     image = cpl_image_extract(autocorr, p / 2 + 1, 1, p, p);
01226     cpl_image_copy(reorganised, image, 1, 1);
01227     cpl_image_delete(image);
01228 
01229     image = cpl_image_extract(autocorr, 1, 1, p / 2, p);
01230     cpl_image_copy(reorganised, image, p / 2 + 1, 1);
01231     cpl_image_delete(image);
01232 
01233     cpl_image_delete(autocorr);
01234 
01235     autocorr = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01236 
01237     image = cpl_image_extract(reorganised, 1, p / 2 + 1, p, p);
01238     cpl_image_copy(autocorr, image, 1, 1);
01239     cpl_image_delete(image);
01240 
01241     image = cpl_image_extract(reorganised, 1, 1, p, p / 2);
01242     cpl_image_copy(autocorr, image, 1, p / 2 + 1);
01243     cpl_image_delete(image);
01244 
01245     cpl_image_delete(reorganised);
01246 
01247     autocorr_norm_double =
01248         cpl_image_extract(autocorr, p / 2 + 1 - m, p / 2 + 1 - n,
01249                           p / 2 + 1 + m, p / 2 + 1 + n);
01250 
01251     cpl_image_delete(autocorr);
01252 
01253     if(cpl_image_divide_scalar(autocorr_norm_double,
01254                                cpl_image_get_max(autocorr_norm_double))) {
01255         cpl_image_delete(autocorr_norm_double);
01256         cpl_ensure(0, cpl_error_get_code(), NULL);
01257     }
01258 
01259 
01260     autocorr_norm = cpl_image_cast(autocorr_norm_double, CPL_TYPE_FLOAT);
01261     cpl_image_delete(autocorr_norm_double);
01262 
01263     cpl_image_delete(input);
01264 
01265     return autocorr_norm;
01266 }
01267 
01268 /*---------------------------------------------------------------------------*/
01279 /*---------------------------------------------------------------------------*/
01280 cpl_error_code
01281 irplib_detmon_lg_fill_parlist_nir_default(cpl_parameterlist * parlist,
01282                                   const char *recipe_name,
01283                                   const char *pipeline_name)
01284 {
01285     const cpl_error_code error = 
01286     irplib_detmon_lg_fill_parlist(parlist, recipe_name, pipeline_name,
01287                   "PTC", /* --method */
01288                   3,   /* --order         */
01289                               3,        /* --kappa         */
01290                               25,       /* --niter         */
01291                               -1,       /* --llx           */
01292                               -1,       /* --lly           */
01293                               -1,       /* --urx           */
01294                               -1,       /* --ury           */
01295                               10000,    /* --ref_level     */
01296                               "CPL_FALSE",      /* --intermediate  */
01297                               "CPL_FALSE",      /* --autocorr      */
01298                               "CPL_FALSE",      /* --collapse      */
01299                               "CPL_TRUE",       /* --rescale       */
01300                       "CPL_TRUE",/* --pix2pix */
01301                       "CPL_FALSE", /* --bpmbin */
01302                               -1,       /* --filter        */
01303                               26,       /* --m             */
01304                               26,       /* --n             */
01305                       1e-3, /* --tolerance */
01306                       recipe_name, /* --pafname */
01307                               -1,       /* --llx1          */
01308                               -1,       /* --lly1          */
01309                               -1,       /* --urx1          */
01310                               -1,       /* --ury1          */
01311                               -1,       /* --llx2          */
01312                               -1,       /* --lly2          */
01313                               -1,       /* --urx2          */
01314                               -1,       /* --ury2          */
01315                               -1,       /* --llx3          */
01316                               -1,       /* --lly3          */
01317                               -1,       /* --urx3          */
01318                               -1,       /* --ury3          */
01319                               -1,       /* --llx4          */
01320                               -1,       /* --lly4          */
01321                               -1,       /* --urx4          */
01322                               -1,       /* --ury4          */
01323                               -1,       /* --llx5          */
01324                               -1,       /* --lly5          */
01325                               -1,       /* --urx5          */
01326                               -1,       /* --ury5          */
01327                       0,      /* --exts */
01328                           NIR);       /* This is to specify OPT params */
01329 
01330 
01331     cpl_ensure_code(!error, error);
01332 
01333     return cpl_error_get_code();
01334 }
01335 
01336 /*---------------------------------------------------------------------------*/
01347 /*---------------------------------------------------------------------------*/
01348 cpl_error_code
01349 irplib_detmon_lg_fill_parlist_opt_default(cpl_parameterlist * parlist,
01350                                   const char *recipe_name,
01351                                   const char *pipeline_name)
01352 {
01353     const cpl_error_code error = 
01354     irplib_detmon_lg_fill_parlist(parlist, recipe_name, pipeline_name,
01355                   "PTC", /* --method */
01356                   3,   /* --order         */
01357                               3,        /* --kappa         */
01358                               25,       /* --niter         */
01359                               -1,       /* --llx           */
01360                               -1,       /* --lly           */
01361                               -1,       /* --urx           */
01362                               -1,       /* --ury           */
01363                               10000,    /* --ref_level     */
01364                               "CPL_FALSE",      /* --intermediate  */
01365                               "CPL_FALSE",      /* --autocorr      */
01366                               "CPL_TRUE",      /* --collapse      */
01367                               "CPL_TRUE",       /* --rescale       */
01368                       "CPL_FALSE", /* --pix2pix */
01369                       "CPL_FALSE", /* --bpmbin */
01370                               -1,       /* --filter        */
01371                               26,       /* --m             */
01372                               26,       /* --n             */
01373                       1e-3, /* --tolerance */
01374                       recipe_name, /* --pafname */
01375                               -1,       /* --llx1          */
01376                               -1,       /* --lly1          */
01377                               -1,       /* --urx1          */
01378                               -1,       /* --ury1          */
01379                               -1,       /* --llx2          */
01380                               -1,       /* --lly2          */
01381                               -1,       /* --urx2          */
01382                               -1,       /* --ury2          */
01383                               -1,       /* --llx3          */
01384                               -1,       /* --lly3          */
01385                               -1,       /* --urx3          */
01386                               -1,       /* --ury3          */
01387                               -1,       /* --llx4          */
01388                               -1,       /* --lly4          */
01389                               -1,       /* --urx4          */
01390                               -1,       /* --ury4          */
01391                               -1,       /* --llx5          */
01392                               -1,       /* --lly5          */
01393                               -1,       /* --urx5          */
01394                               -1,       /* --ury5          */
01395                       0,      /* --exts */
01396                           OPT);       /* This is to specify OPT params */
01397 
01398     cpl_ensure_code(!error, error);
01399 
01400     return cpl_error_get_code();
01401 }
01402 
01403 /*---------------------------------------------------------------------------*/
01457 /*---------------------------------------------------------------------------*/
01458 cpl_error_code
01459 irplib_detmon_lg_fill_parlist(cpl_parameterlist * parlist,
01460                           const char *recipe_name, const char *pipeline_name,
01461               const char *method,
01462                           int order,
01463                           int kappa,
01464                           int niter,
01465                           int llx,
01466                           int lly,
01467                           int urx,
01468                           int ury,
01469                           int ref_level,
01470                           const char *intermediate,
01471                           const char *autocorr,
01472                           const char *collapse,
01473                           const char *rescale,
01474                   const char *pix2pix,
01475                   const char *bpmbin,
01476                           int filter,
01477                           int m,
01478                           int n,
01479                   double tolerance,
01480                   const char * pafname,
01481                           int llx1,
01482                           int lly1,
01483                           int urx1,
01484                           int ury1,
01485                           int llx2,
01486                           int lly2,
01487                           int urx2,
01488                           int ury2,
01489                           int llx3,
01490                           int lly3,
01491                           int urx3,
01492                           int ury3,
01493                           int llx4,
01494                           int lly4,
01495                           int urx4,
01496                           int ury4,
01497                   int llx5, int lly5, int urx5, int ury5, int exts,
01498                           cpl_boolean opt_nir)
01499 {
01500     const cpl_error_code error =
01501     irplib_detmon_fill_parlist(parlist, recipe_name, pipeline_name, 21,
01502                    "method",
01503                    "Method to be used when computing GAIN. Methods appliable: <PTC | MED>. By default PTC method will be applied.",
01504                                    "CPL_TYPE_STRING", method,
01505 
01506                                "order",
01507                                "Polynomial order for the fit (Linearity)",
01508                                "CPL_TYPE_INT", order,
01509                                "kappa",
01510                                "Kappa value for the kappa-sigma clipping (Gain)",
01511                                "CPL_TYPE_INT", kappa,
01512                                "niter",
01513                                "Number of iterations to compute rms (Gain)",
01514                                "CPL_TYPE_INT", niter,
01515                                "llx",
01516                                "x coordinate of the lower-left "
01517                                "point of the region of interest. If not modified, default value will be 1.",
01518                                "CPL_TYPE_INT", llx,
01519                                "lly",
01520                                "y coordinate of the lower-left "
01521                                "point of the region of interest. If not modified, default value will be 1.",
01522                                "CPL_TYPE_INT", lly,
01523                                "urx",
01524                                "x coordinate of the upper-right "
01525                                "point of the region of interest. If not modified, default value will be X dimension of the input image.",
01526                                "CPL_TYPE_INT", urx,
01527                                "ury",
01528                                "y coordinate of the upper-right "
01529                                "point of the region of interest. If not modified, default value will be Y dimension of the input image.",
01530                                "CPL_TYPE_INT", ury,
01531                                "ref_level",
01532                                "User reference level",
01533                                "CPL_TYPE_INT", ref_level,
01534                                "intermediate",
01535                                "De-/Activate intermediate products",
01536                                "CPL_TYPE_BOOL", intermediate,
01537                                "autocorr",
01538                                "De-/Activate the autocorr option",
01539                                "CPL_TYPE_BOOL", autocorr,
01540                                "collapse",
01541                                "De-/Activate the collapse option",
01542                                "CPL_TYPE_BOOL", collapse,
01543                                "rescale",
01544                                "De-/Activate the collapse option",
01545                                "CPL_TYPE_BOOL", rescale,
01546                    "pix2pix",
01547                                "De-/Activate the pix2pix option",
01548                                "CPL_TYPE_BOOL", pix2pix,
01549                    "bpmbin",
01550                                "De-/Activate the binary bpm option",
01551                                "CPL_TYPE_BOOL", bpmbin,
01552                                "m",
01553                                "Maximum x-shift for the autocorr",
01554                                "CPL_TYPE_INT", m,
01555                                "filter",
01556                                "Upper limit of Median flux to be filtered",
01557                                "CPL_TYPE_INT", filter,
01558                                "n",
01559                                "Maximum y-shift for the autocorr",
01560                    "CPL_TYPE_INT", n,
01561                                "tolerance",
01562                                "Tolerance for pair discrimination",
01563                    "CPL_TYPE_DOUBLE", tolerance,
01564                                "pafname",
01565                                "Specific name for PAF file",
01566                    "CPL_TYPE_STRING", pafname,
01567 
01568                                "exts",
01569                                "Activate the multi-exts option",
01570                                "CPL_TYPE_INT", exts);
01571 
01572     /* OPT specific parameters */
01573     if(opt_nir == FALSE) {
01574     const cpl_error_code erroropt = 
01575         irplib_detmon_fill_parlist(parlist, recipe_name, pipeline_name, 20,
01576                                "llx1",
01577                                "x coord of the lower-left point of the first "
01578                                "field used for contamination measurement. If not modified, default value will be 1.",
01579                                "CPL_TYPE_INT", llx1,
01580                                "lly1",
01581                                "y coord of the lower-left point of the first "
01582                                "field used for contamination measurement. If not modified, default value will be 1.",
01583                                "CPL_TYPE_INT", lly1,
01584                                "urx1",
01585                                "x coord of the upper-right point of the first "
01586                                "field used for contamination measurement. If not modified, default value will be X dimension of the input image.",
01587                                "CPL_TYPE_INT", urx1,
01588                                "ury1",
01589                                "y coord of the upper-right point of the first "
01590                                "field used for contamination measurement. If not modified, default value will be Y dimension of the input image.",
01591                                "CPL_TYPE_INT", ury1,
01592                                "llx2",
01593                                "x coord of the lower-left point of the second "
01594                                "field used for contamination measurement. If not modified, default value will be 1.",
01595                                "CPL_TYPE_INT", llx2,
01596                                "lly2",
01597                                "y coord of the lower-left point of the second "
01598                                "field used for contamination measurement. If not modified, default value will be 1.",
01599                                "CPL_TYPE_INT", lly2,
01600                                "urx2",
01601                                "x coord of the upper-right point of the second "
01602                                "field used for contamination measurement. If not modified, default value will be half of the X dimension of the input image.",
01603                                "CPL_TYPE_INT", urx2,
01604                                "ury2",
01605                                "y coord of the upper-right point of the second "
01606                                "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
01607                                "CPL_TYPE_INT", ury2,
01608                                "llx3",
01609                                "x coord of the lower-left point of the third "
01610                                "field used for contamination measurement. If not modified, default value will be 1.",
01611                                "CPL_TYPE_INT", llx3,
01612                                "lly3",
01613                                "y coord of the lower-left point of the third "
01614                                "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
01615                                "CPL_TYPE_INT", lly3,
01616                                "urx3",
01617                                "x coord of the upper-right point of the third "
01618                                "field used for contamination measurement. If not modified, default value will be half of X dimension of the image.",
01619                                "CPL_TYPE_INT", urx3,
01620                                "ury3",
01621                                "y coord of the upper-right point of the third "
01622                                "field used for contamination measurement. If not modified, default value will be Y dimension of the image.",
01623                                "CPL_TYPE_INT", ury3,
01624                                "llx4",
01625                                "x coord of the lower-left point of the fourth "
01626                                "field used for contamination measurement. If not modified, default value will be half of X dimension of the image.",
01627                                "CPL_TYPE_INT", llx4,
01628                                "lly4",
01629                                "y coord of the lower-left point of the fourth "
01630                                "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
01631                                "CPL_TYPE_INT", lly4,
01632                                "urx4",
01633                                "x coord of the upper-right point of the fourth "
01634                                "field used for contamination measurement. If not modified, default value will be X dimension of the image.",
01635                                "CPL_TYPE_INT", urx4,
01636                                "ury4",
01637                                "y coord of the upper-right point of the fourth "
01638                                "field used for contamination measurement. If not modified, default value will be Y dimension of the input image.",
01639                                "CPL_TYPE_INT", ury4,
01640                                "llx5",
01641                                "x coord of the lower-left point of the fifth "
01642                                "field used for contamination measurement. If not modified, default value will be half of the X dimension of the input image.",
01643                                "CPL_TYPE_INT", llx5,
01644                                "lly5",
01645                                "y coord of the lower-left point of the fifth "
01646                                "field used for contamination measurement. If not modified, default value will be 1.",
01647                                "CPL_TYPE_INT", lly5,
01648                                "urx5",
01649                                "x coord of the upper-right point of the fifth "
01650                                "field used for contamination measurement. If not modified, default value will be X dimension of the image.",
01651                                "CPL_TYPE_INT", urx5,
01652                                "ury5",
01653                                "y coord of the upper-right point of the fifth "
01654                                "field used for contamination measurement. If not modified, default value will be half of Y dimension of the input image.",
01655                    "CPL_TYPE_INT", ury5);
01656     cpl_ensure_code(!erroropt, erroropt);
01657     }
01658 
01659     cpl_ensure_code(!error, error);
01660 
01661     return cpl_error_get_code();
01662 }
01663 
01664 /*---------------------------------------------------------------------------*/
01673 /*---------------------------------------------------------------------------*/
01674 static cpl_error_code
01675 irplib_detmon_lg_retrieve_parlist(const char              * pipeline_name,
01676                   const char              * recipe_name,
01677                   const cpl_parameterlist * parlist,
01678                   cpl_boolean               opt_nir)
01679 {
01680 
01681     char                   * par_name;
01682     cpl_parameter          * par;
01683 
01684     /* --method */
01685     par_name = cpl_sprintf("%s.%s.method", pipeline_name, recipe_name);
01686     assert(par_name != NULL);
01687     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01688     detmon_lg_config.method = cpl_parameter_get_string(par);
01689     cpl_free(par_name);
01690 
01691     /* --order */
01692     detmon_lg_config.order =
01693         irplib_detmon_retrieve_par("order", pipeline_name, recipe_name,
01694                                    parlist);
01695 
01696     /* --kappa */
01697     detmon_lg_config.kappa =
01698         irplib_detmon_retrieve_par("kappa", pipeline_name, recipe_name,
01699                                    parlist);
01700 
01701     /* --niter */
01702     detmon_lg_config.niter =
01703         irplib_detmon_retrieve_par("niter", pipeline_name, recipe_name,
01704                                    parlist);
01705 
01706     /* --llx */
01707     detmon_lg_config.llx =
01708         irplib_detmon_retrieve_par("llx", pipeline_name, recipe_name,
01709                                    parlist);
01710 
01711     /* --lly */
01712     detmon_lg_config.lly =
01713         irplib_detmon_retrieve_par("lly", pipeline_name, recipe_name,
01714                                    parlist);
01715 
01716     /* --urx */
01717     detmon_lg_config.urx =
01718         irplib_detmon_retrieve_par("urx", pipeline_name, recipe_name,
01719                                    parlist);
01720 
01721     /* --ury */
01722     detmon_lg_config.ury =
01723         irplib_detmon_retrieve_par("ury", pipeline_name, recipe_name,
01724                                    parlist);
01725 
01726     /* --ref_level */
01727     detmon_lg_config.ref_level =
01728         irplib_detmon_retrieve_par("ref_level", pipeline_name, recipe_name,
01729                                    parlist);
01730 
01731     /* --intermediate */
01732     par_name =
01733         cpl_sprintf("%s.%s.intermediate", pipeline_name, recipe_name);
01734     assert(par_name != NULL);
01735     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01736     detmon_lg_config.intermediate = cpl_parameter_get_bool(par);
01737     cpl_free(par_name);
01738  
01739     /* --autocorr */
01740     par_name = cpl_sprintf("%s.%s.autocorr", pipeline_name, recipe_name);
01741     assert(par_name != NULL);
01742     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01743     detmon_lg_config.autocorr = cpl_parameter_get_bool(par);
01744     cpl_free(par_name);
01745 
01746     /* --collapse */
01747     par_name = cpl_sprintf("%s.%s.collapse", pipeline_name, recipe_name);
01748     assert(par_name != NULL);
01749     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01750     detmon_lg_config.collapse = cpl_parameter_get_bool(par);
01751     cpl_free(par_name);
01752 
01753     /* --rescale */
01754     par_name = cpl_sprintf("%s.%s.rescale", pipeline_name, recipe_name);
01755     assert(par_name != NULL);
01756     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01757     detmon_lg_config.rescale = cpl_parameter_get_bool(par);
01758     cpl_free(par_name);
01759 
01760     /* --pix2pix */
01761     par_name = cpl_sprintf("%s.%s.pix2pix", pipeline_name, recipe_name);
01762     assert(par_name != NULL);
01763     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01764     detmon_lg_config.pix2pix = cpl_parameter_get_bool(par);
01765     cpl_free(par_name);
01766 
01767     /* --bpmbin */
01768     par_name = cpl_sprintf("%s.%s.bpmbin", pipeline_name, recipe_name);
01769     assert(par_name != NULL);
01770     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01771     detmon_lg_config.bpmbin = cpl_parameter_get_bool(par);
01772     cpl_free(par_name);
01773 
01774     /* --filter */
01775     detmon_lg_config.filter =
01776         irplib_detmon_retrieve_par("filter", pipeline_name,
01777                                    recipe_name, parlist);
01778 
01779     /* --m */
01780     detmon_lg_config.m =
01781         irplib_detmon_retrieve_par("m", pipeline_name, recipe_name, parlist);
01782 
01783     /* --n */
01784     detmon_lg_config.n =
01785         irplib_detmon_retrieve_par("n", pipeline_name, recipe_name, parlist);
01786 
01787     /* --tolerance */
01788     par_name = cpl_sprintf("%s.%s.tolerance", pipeline_name, recipe_name);
01789     assert(par_name != NULL);
01790     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01791     detmon_lg_config.tolerance = cpl_parameter_get_double(par);
01792     cpl_free(par_name);
01793 
01794     /* --pafname */
01795     par_name = cpl_sprintf("%s.%s.pafname", pipeline_name, recipe_name);
01796     assert(par_name != NULL);
01797     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01798     detmon_lg_config.pafname = cpl_parameter_get_string(par);
01799     cpl_free(par_name);
01800 
01801     if(opt_nir == OPT) {
01802     /* --llx1 */
01803     detmon_lg_config.llx1 =
01804         irplib_detmon_retrieve_par("llx1", pipeline_name, recipe_name,
01805                        parlist);
01806 
01807     /* --lly1 */
01808     detmon_lg_config.lly1 =
01809         irplib_detmon_retrieve_par("lly1", pipeline_name, recipe_name,
01810                        parlist);
01811 
01812     /* --urx1 */
01813     detmon_lg_config.urx1 =
01814         irplib_detmon_retrieve_par("urx1", pipeline_name, recipe_name,
01815                        parlist);
01816 
01817     /* --ury1 */
01818     detmon_lg_config.ury1 =
01819         irplib_detmon_retrieve_par("ury1", pipeline_name, recipe_name,
01820                        parlist);
01821 
01822     /* --llx2 */
01823     detmon_lg_config.llx2 =
01824         irplib_detmon_retrieve_par("llx2", pipeline_name, recipe_name,
01825                        parlist);
01826 
01827     /* --lly2 */
01828     detmon_lg_config.lly2 =
01829         irplib_detmon_retrieve_par("lly2", pipeline_name, recipe_name,
01830                        parlist);
01831 
01832     /* --urx2 */
01833     detmon_lg_config.urx2 =
01834         irplib_detmon_retrieve_par("urx2", pipeline_name, recipe_name,
01835                        parlist);
01836 
01837     /* --ury2 */
01838     detmon_lg_config.ury2 =
01839         irplib_detmon_retrieve_par("ury2", pipeline_name, recipe_name,
01840                        parlist);
01841 
01842     /* --llx3 */
01843     detmon_lg_config.llx3 =
01844         irplib_detmon_retrieve_par("llx3", pipeline_name, recipe_name,
01845                        parlist);
01846 
01847     /* --lly3 */
01848     detmon_lg_config.lly3 =
01849         irplib_detmon_retrieve_par("lly3", pipeline_name, recipe_name,
01850                        parlist);
01851 
01852     /* --urx3 */
01853     detmon_lg_config.urx3 =
01854         irplib_detmon_retrieve_par("urx3", pipeline_name, recipe_name,
01855                        parlist);
01856 
01857     /* --ury3 */
01858     detmon_lg_config.ury3 =
01859         irplib_detmon_retrieve_par("ury3", pipeline_name, recipe_name,
01860                        parlist);
01861 
01862     /* --llx4 */
01863     detmon_lg_config.llx4 =
01864         irplib_detmon_retrieve_par("llx4", pipeline_name, recipe_name,
01865                        parlist);
01866 
01867     /* --lly4 */
01868     detmon_lg_config.lly4 =
01869         irplib_detmon_retrieve_par("lly4", pipeline_name, recipe_name,
01870                        parlist);
01871 
01872     /* --urx4 */
01873     detmon_lg_config.urx4 =
01874         irplib_detmon_retrieve_par("urx4", pipeline_name, recipe_name,
01875                        parlist);
01876 
01877     /* --ury4 */
01878     detmon_lg_config.ury4 =
01879         irplib_detmon_retrieve_par("ury4", pipeline_name, recipe_name,
01880                        parlist);
01881 
01882     /* --llx5 */
01883     detmon_lg_config.llx5 =
01884         irplib_detmon_retrieve_par("llx5", pipeline_name, recipe_name,
01885                        parlist);
01886 
01887     /* --lly5 */
01888     detmon_lg_config.lly5 =
01889         irplib_detmon_retrieve_par("lly5", pipeline_name, recipe_name,
01890                        parlist);
01891 
01892     /* --urx5 */
01893     detmon_lg_config.urx5 =
01894         irplib_detmon_retrieve_par("urx5", pipeline_name, recipe_name,
01895                        parlist);
01896 
01897     /* --ury5 */
01898     detmon_lg_config.ury5 =
01899         irplib_detmon_retrieve_par("ury5", pipeline_name, recipe_name,
01900                        parlist);
01901     }
01902 
01903     /* --exts */
01904     detmon_lg_config.exts =
01905         irplib_detmon_retrieve_par("exts", pipeline_name, recipe_name,
01906                                    parlist);
01907 
01908     if(cpl_error_get_code()) {
01909         cpl_msg_error(cpl_func, "Failed to retrieve the input parameters");
01910         cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
01911     }
01912 
01913 
01914     return cpl_error_get_code();
01915 }
01916 
01917 /*---------------------------------------------------------------------------*/
01923 /*---------------------------------------------------------------------------*/
01924 static cpl_error_code
01925 irplib_detmon_lg_check_defaults(const cpl_image * reference)
01926 {
01927     const int               nx = cpl_image_get_size_x(reference);
01928     const int               ny = cpl_image_get_size_y(reference);
01929 
01930     if(detmon_lg_config.llx == -1)
01931         detmon_lg_config.llx = 1;
01932     if(detmon_lg_config.lly == -1)
01933         detmon_lg_config.lly = 1;
01934     if(detmon_lg_config.urx == -1)
01935         detmon_lg_config.urx = nx;
01936     if(detmon_lg_config.ury == -1)
01937         detmon_lg_config.ury = ny;
01938 
01939     if(detmon_lg_config.llx1 == -1)
01940         detmon_lg_config.llx1 = 1;
01941     if(detmon_lg_config.lly1 == -1)
01942         detmon_lg_config.lly1 = 1;
01943     if(detmon_lg_config.urx1 == -1)
01944         detmon_lg_config.urx1 = nx;
01945     if(detmon_lg_config.ury1 == -1)
01946         detmon_lg_config.ury1 = ny;
01947 
01948     if(detmon_lg_config.llx2 == -1)
01949         detmon_lg_config.llx2 = 1;
01950     if(detmon_lg_config.lly2 == -1)
01951         detmon_lg_config.lly2 = 1;
01952     if(detmon_lg_config.urx2 == -1)
01953         detmon_lg_config.urx2 = nx / 2;
01954     if(detmon_lg_config.ury2 == -1)
01955         detmon_lg_config.ury2 = ny / 2;
01956 
01957     if(detmon_lg_config.llx3 == -1)
01958         detmon_lg_config.llx3 = 1;
01959     if(detmon_lg_config.lly3 == -1)
01960         detmon_lg_config.lly3 = ny / 2;
01961     if(detmon_lg_config.urx3 == -1)
01962         detmon_lg_config.urx3 = nx / 2;
01963     if(detmon_lg_config.ury3 == -1)
01964         detmon_lg_config.ury3 = ny;
01965 
01966     if(detmon_lg_config.llx4 == -1)
01967         detmon_lg_config.llx4 = nx / 2;
01968     if(detmon_lg_config.lly4 == -1)
01969         detmon_lg_config.lly4 = ny / 2;
01970     if(detmon_lg_config.urx4 == -1)
01971         detmon_lg_config.urx4 = nx;
01972     if(detmon_lg_config.ury4 == -1)
01973         detmon_lg_config.ury4 = ny;
01974 
01975     if(detmon_lg_config.llx5 == -1)
01976         detmon_lg_config.llx5 = nx / 2;
01977     if(detmon_lg_config.lly5 == -1)
01978         detmon_lg_config.lly5 = 1;
01979     if(detmon_lg_config.urx5 == -1)
01980         detmon_lg_config.urx5 = nx;
01981     if(detmon_lg_config.ury5 == -1)
01982         detmon_lg_config.ury5 = ny / 2;
01983 
01984     if(detmon_lg_config.intermediate == TRUE) {
01985         cpl_msg_warning(cpl_func, "PLEASE NOTE: The --intermediate option saves the difference and correlation images produced during autocorrelation computation. Therefore, --autocorr option has been automatically activated. If you didn't want to run this, please abort and rerun.");
01986         detmon_lg_config.autocorr = TRUE;
01987     }
01988 
01989 #ifndef HAVE_FFTW
01990     if(detmon_lg_config.autocorr == TRUE)
01991         cpl_msg_warning(cpl_func,
01992                         "You don't have FFTW installed in your system."
01993                         " Please note that use of --autocorr option without it "
01994                         "will result in an execution time close to 10 minutes.");
01995 
01996 #endif
01997 
01998     detmon_lg_config.lamp_stability = 0.0;
01999 
02000     detmon_lg_config.lamp_ok = FALSE;
02001 
02002     detmon_lg_config.cr = 0.0;
02003 
02004     return cpl_error_get_code();
02005 }
02006 
02007 /*---------------------------------------------------------------------------*/
02018 /*---------------------------------------------------------------------------*/
02019 static cpl_error_code
02020 irplib_detmon_lg_split_onoff(const cpl_frameset * cur_fset,
02021                              cpl_frameset * cur_fset_on,
02022                              cpl_frameset * cur_fset_off,
02023                              const char *tag_on,
02024                              const char *tag_off)//,
02025                              //cpl_boolean opt_nir)
02026 {
02027     int                     nframes;
02028     int                     i;
02029 
02030     const cpl_frame * first;
02031     const cpl_frame * second;
02032 
02033     const char * first_tag;
02034     const char * second_tag;
02035 
02036     cpl_frame * cur_frame_dup = NULL;
02037 
02038     skip_if((first   = cpl_frameset_get_first_const(cur_fset)) == NULL);
02039     skip_if((second  = cpl_frameset_get_next_const (cur_fset)) == NULL);
02040 
02041     skip_if((first_tag  = cpl_frame_get_tag(first))  == NULL);
02042     skip_if((second_tag = cpl_frame_get_tag(second)) == NULL);
02043 
02044 // Count rate computation inactive until supported
02045 //    if (opt_nir == OPT &&
02046 //  ((!strcmp(first_tag, tag_on ) && !strcmp(second_tag, tag_off)) ||
02047 //   (!strcmp(first_tag, tag_off) && !strcmp(second_tag, tag_on )))) {
02048 //  detmon_lg_config.lamp_ok = TRUE;
02049 //    }
02050 
02051     nframes = cpl_frameset_get_size(cur_fset);
02052     for(i = detmon_lg_config.lamp_ok ? 2 : 0; i < nframes; i++) {
02053         const cpl_frame * cur_frame =
02054         cpl_frameset_get_frame_const(cur_fset, i);
02055     char            * tag;
02056 
02057         /* Duplication is required for insertion to a different frameset */
02058         cur_frame_dup = cpl_frame_duplicate(cur_frame);
02059         tag = (char *) cpl_frame_get_tag(cur_frame_dup);
02060 
02061         /* Insertion in the corresponding sub-frameset */
02062         if(!strcmp(tag, tag_on)) {
02063             skip_if(cpl_frameset_insert(cur_fset_on, cur_frame_dup));
02064         } else if(!strcmp(tag, tag_off)) {
02065             skip_if(cpl_frameset_insert(cur_fset_off, cur_frame_dup));
02066         } else {
02067             cpl_frame_delete(cur_frame_dup);
02068         cur_frame_dup = NULL;
02069         }
02070     }
02071     cur_frame_dup = NULL;
02072 
02073     end_skip;
02074 
02075     cpl_frame_delete(cur_frame_dup);
02076 
02077     return cpl_error_get_code();
02078 }
02079 
02080 /*--------------------------------------------------------------------------*/
02104 /*--------------------------------------------------------------------------*/
02105 
02106 static cpl_error_code
02107 irplib_detmon_lg_reduce(const cpl_frameset * set_on,
02108                         const cpl_frameset * set_off,
02109                         int *selection_on,
02110                         int *selection_off,
02111                         int nsets_extracted,
02112                         cpl_imagelist ** coeffs_ptr,
02113                         cpl_table * gain_table,
02114                         cpl_table * linear_table,
02115                         cpl_image ** bpm_ptr,
02116                         cpl_imagelist * autocorr_images,
02117                         cpl_imagelist * diff_flats,
02118                         cpl_propertylist * qclist,
02119          int                    (* load_fset) (const cpl_frameset *,
02120                                cpl_type,
02121                                                cpl_imagelist *),
02122             const cpl_boolean opt_nir,
02123                         int whichext)
02124 {
02125     int                     i;
02126     cpl_imagelist         * linearity_inputs = NULL;
02127     cpl_imagelist         * opt_offs = NULL;
02128     int                     nsets;
02129     cpl_propertylist      * reflist = NULL;
02130 
02131     /* Test entries */
02132     cpl_ensure(set_on != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
02133     cpl_ensure(set_off != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
02134 
02135     nsets = cpl_frameset_get_size(set_on) / 2;
02136 
02137     if(detmon_lg_config.collapse) {
02138         /*
02139          * When the 'collapse' option is used, there are no OFF pairs. We
02140          * construct a pair with the 2 first raw OFF frames, which will be
02141          * passed for each DIT value, to maintain the same API in the function
02142          * irplib_detmon_gain_table_fill_row().
02143          */
02144         const cpl_frame        *first = cpl_frameset_get_first_const(set_off);
02145         cpl_frame              *dup_first = cpl_frame_duplicate(first);
02146 
02147         const cpl_frame        *second = cpl_frameset_get_next_const(set_off);
02148         cpl_frame              *dup_second = cpl_frame_duplicate(second);
02149 
02150         cpl_frameset           *raw_offs = cpl_frameset_new();
02151 
02152         cpl_frameset_insert(raw_offs, dup_first);
02153         cpl_frameset_insert(raw_offs, dup_second);
02154 
02155     opt_offs = cpl_imagelist_load_frameset(raw_offs, CPL_TYPE_FLOAT,
02156                            0, whichext);
02157 
02158         cpl_frameset_delete(raw_offs);
02159 
02160     }
02161 
02162     skip_if(irplib_detmon_lg_reduce_init(gain_table,
02163                      linear_table,
02164                      &linearity_inputs));
02165 
02166     if(!detmon_lg_config.collapse)
02167     skip_if(irplib_detmon_lg_lamp_stab(set_on, set_off, opt_nir));
02168 
02169     /* Unselect all rows, to select only invalid ones */
02170     skip_if(cpl_table_unselect_all(linear_table));
02171     skip_if(cpl_table_unselect_all(gain_table));
02172 
02173     /* Loop on every DIT value */
02174     for(i = 0; i < nsets /*_extracted*/; i++) {
02175     skip_if(irplib_detmon_lg_reduce_dit(set_on, selection_on, i,
02176                         nsets_extracted, set_off,
02177                         selection_off, linear_table,
02178                         gain_table, linearity_inputs,
02179                         qclist, opt_nir,
02180                         autocorr_images, diff_flats,
02181                         opt_offs, load_fset, whichext));
02182     }
02183 
02184     skip_if(irplib_detmon_add_adl_column(linear_table));
02185 
02186     /*
02187      * Removal of rows corresponding to frames above --filter threshold.
02188      * See calls to cpl_table_select_row() in irplib_detmon_lg_reduce_dit().
02189      */
02190     skip_if(cpl_table_erase_selected(gain_table));
02191     skip_if(cpl_table_erase_selected(linear_table));
02192 
02193     reflist = cpl_propertylist_new();
02194     skip_if(cpl_propertylist_append_bool(reflist, "ADU", FALSE));
02195     skip_if(cpl_table_sort(gain_table, reflist));
02196 
02197 
02198     /*
02199      * --Final reduction--
02200      * The following call to irplib_detmon_lg_reduce_all() makes the
02201      * computations which are over all posible DIT values.
02202      */
02203     skip_if(irplib_detmon_lg_reduce_all(linear_table,
02204                     qclist, coeffs_ptr, bpm_ptr,
02205                     linearity_inputs,
02206                     gain_table, i+1));
02207 
02208     end_skip;
02209 
02210     cpl_imagelist_delete(linearity_inputs);
02211     cpl_imagelist_delete(opt_offs);
02212     cpl_propertylist_delete(reflist);
02213 
02214     return cpl_error_get_code();
02215 }
02216 
02217 /*--------------------------------------------------------------------------*/
02225 /*--------------------------------------------------------------------------*/
02226 static cpl_error_code
02227 irplib_detmon_lg_lamp_stab(const cpl_frameset * lamps,
02228                const cpl_frameset * darks,
02229                            cpl_boolean          opt_nir)
02230 {
02231     /*
02232      * NOTE:
02233      * Most of this code is copied (and modified) from
02234      * isaac_img_detlin_load(), in isaac_img_detlin.c v.1.25
02235      */
02236 
02237     int                     nb_lamps;
02238     cpl_vector          *   selection = NULL;
02239     cpl_propertylist    *   plist;
02240     double                  dit_lamp, dit_dark;
02241     int                     dit_stab;
02242     cpl_imagelist       *   lamps_data = NULL;
02243     cpl_imagelist       *   darks_data = NULL;
02244     double              *   stab_levels = NULL;
02245     int                     i, j;
02246     double              *   ditvals = NULL;
02247     int                     last_stab = 0; /* Avoid false uninit warning */
02248 
02249     /* Check that there are as many lamp as darks */
02250     cpl_ensure_code((nb_lamps = cpl_frameset_get_size(lamps)) >= 3,
02251             CPL_ERROR_ILLEGAL_INPUT);
02252     cpl_ensure_code(cpl_frameset_get_size(darks) == nb_lamps,
02253                 CPL_ERROR_ILLEGAL_INPUT);
02254 
02255     /* Check out that they have consistent integration times */
02256     cpl_msg_info(__func__, "Checking DIT consistency");
02257     selection = cpl_vector_new(nb_lamps);
02258     ditvals = cpl_malloc(nb_lamps * sizeof(double));
02259     dit_stab = 0;
02260     for (i = 0; i < nb_lamps; i++) {
02261     const cpl_frame           * c_lamp;
02262     const cpl_frame           * c_dark;
02263         /* Check if ok */
02264         skip_if (cpl_error_get_code());
02265 
02266         /* DIT from LAMP */
02267         c_lamp = cpl_frameset_get_frame_const(lamps, i);
02268         plist = cpl_propertylist_load(cpl_frame_get_filename(c_lamp), 0);
02269     if(opt_nir)
02270         dit_lamp = (double)irplib_pfits_get_dit(plist);
02271     else
02272         dit_lamp = (double)irplib_pfits_get_dit_opt(plist);
02273         cpl_propertylist_delete(plist);
02274         skip_if (cpl_error_get_code());
02275 
02276         /* DIT from DARK */
02277         c_dark = cpl_frameset_get_frame_const(darks, i);
02278         plist  = cpl_propertylist_load(cpl_frame_get_filename(c_dark), 0);
02279     if(opt_nir)
02280         dit_dark = (double)irplib_pfits_get_dit(plist);
02281     else
02282         dit_dark = (double)irplib_pfits_get_dit_opt(plist);
02283         cpl_propertylist_delete(plist);
02284         skip_if (cpl_error_get_code());
02285 
02286         /* Check consistency */
02287         if (fabs(dit_dark-dit_lamp) > 1e-3) {
02288             cpl_msg_error(__func__, "DIT not consistent between LAMP and DARK");
02289         /* FIXME: Should an error code be set here? */
02290         skip_if(1);
02291         }
02292         ditvals[i] = dit_lamp;
02293         /* Set selection */
02294         if (i==0) {
02295             cpl_vector_set(selection, i, -1.0);
02296             dit_stab ++;
02297         last_stab = 0;
02298         } else {
02299         /*
02300          * The second condition is to make sure that frames taken into
02301          * account for lamp stability are not consecutive.
02302          */
02303             if (fabs(dit_lamp - ditvals[0]) < 1e-5 && i - last_stab > 3) {
02304                 cpl_vector_set(selection, i, -1.0);
02305                 dit_stab ++;
02306         last_stab = i;
02307             } else {
02308                 cpl_vector_set(selection, i, 1.0);
02309             }
02310         }
02311     }
02312 
02313     /* Check if there are enough DITs for stability check */
02314     if (dit_stab < 2) {
02315         cpl_msg_info(__func__, "Not enough frames for stability check");
02316     } else {
02317 
02318     /* Load the data and compute lamp-dark */
02319     cpl_msg_info(__func__, "Compute the differences lamp - dark");
02320     lamps_data = cpl_imagelist_load_frameset(lamps, CPL_TYPE_FLOAT, 1, 0);
02321     darks_data = cpl_imagelist_load_frameset(darks, CPL_TYPE_FLOAT, 1, 0);
02322     skip_if(cpl_imagelist_subtract(lamps_data,darks_data));
02323     
02324     /* Check the lamp stability */
02325     cpl_msg_info(__func__, "Check the lamp stability");
02326     stab_levels = cpl_malloc(dit_stab * sizeof(double));
02327     j = 0;
02328     for (i=0; i<nb_lamps; i++) {
02329         if (cpl_vector_get(selection, i) < 0) {
02330         stab_levels[j] = 
02331             cpl_image_get_mean(cpl_imagelist_get(lamps_data, i));
02332         j++;
02333         }
02334     }
02335 
02336     /* Compute the lamp stability */
02337     for (i=1; i<dit_stab; i++) {
02338         if ((fabs(stab_levels[i]-stab_levels[0]) / stab_levels[0]) >
02339                 detmon_lg_config.lamp_stability) 
02340         detmon_lg_config.lamp_stability = 
02341             fabs(stab_levels[i]-stab_levels[0]) / stab_levels[0];
02342     }
02343 
02344     
02345     /* Check the lamp stability */
02346     if (detmon_lg_config.lamp_stability > 0.01) {
02347             cpl_msg_warning(__func__, 
02348                 "level difference too high - proceed anyway");
02349     }
02350     }
02351     end_skip;
02352 
02353     cpl_free(ditvals);
02354     cpl_vector_delete(selection);
02355     cpl_imagelist_delete(lamps_data);
02356     cpl_imagelist_delete(darks_data);
02357     cpl_free(stab_levels);
02358 
02359     return cpl_error_get_code();
02360 }
02361 
02362 /*--------------------------------------------------------------------------*/
02390 /*--------------------------------------------------------------------------*/
02391 static cpl_error_code
02392 irplib_detmon_lg_reduce_dit(const cpl_frameset * set_on,
02393                 int * selection_on,
02394                 int dit_nb,
02395                 int nsets_extracted,
02396                 const cpl_frameset * set_off,
02397                 int * selection_off,
02398                 cpl_table * linear_table,
02399                 cpl_table * gain_table,
02400                 cpl_imagelist * linearity_inputs,
02401                 cpl_propertylist * qclist,
02402                 cpl_boolean opt_nir,
02403                 cpl_imagelist * autocorr_images,
02404                 cpl_imagelist * diff_flats,
02405                             cpl_imagelist * opt_offs,
02406                 int                    (* load_fset) (const cpl_frameset *,
02407                                cpl_type,
02408                                   cpl_imagelist *),
02409                             int whichext)
02410 {
02411     cpl_frameset          * pair_on = NULL;
02412     cpl_frameset          * pair_off = NULL;
02413     cpl_imagelist         * ons = NULL;
02414     cpl_imagelist         * offs = NULL;
02415     int                     with_equal_dit = 0;
02416     cpl_boolean             follow = CPL_TRUE;
02417     cpl_imagelist *         masterl = NULL;
02418     unsigned mode = detmon_lg_config.autocorr ? IRPLIB_GAIN_WITH_AUTOCORR : 0;
02419 
02420     mode = detmon_lg_config.collapse ? mode & IRPLIB_GAIN_COLLAPSE : mode;
02421 
02422     /* ON pair extraction */
02423     skip_if(irplib_detmon_pair_extract(set_on, selection_on, dit_nb, nsets_extracted, &with_equal_dit, 1, &pair_on));
02424 
02425     /* Load the ON images */
02426     if (load_fset != NULL) {
02427     ons = cpl_imagelist_new();
02428     (*load_fset)(pair_on, CPL_TYPE_FLOAT, ons);
02429     } else {
02430     ons = cpl_imagelist_load_frameset(pair_on, CPL_TYPE_FLOAT, 1,whichext);
02431     }
02432     skip_if(ons == NULL);
02433     
02434     if(detmon_lg_config.filter > 0) {
02435     double med1 =
02436         cpl_image_get_median_window(cpl_imagelist_get(ons, 0),
02437                     detmon_lg_config.llx,
02438                     detmon_lg_config.lly,
02439                     detmon_lg_config.urx,
02440                     detmon_lg_config.ury);
02441     double med2 = 
02442         cpl_image_get_median_window(cpl_imagelist_get(ons, 1),
02443                     detmon_lg_config.llx,
02444                     detmon_lg_config.lly,
02445                     detmon_lg_config.urx,
02446                     detmon_lg_config.ury);
02447     if ( med1 > (double)detmon_lg_config.filter ||
02448          med2 > (double)detmon_lg_config.filter) {
02449         follow = CPL_FALSE;
02450         cpl_table_select_row(gain_table,   dit_nb);
02451         cpl_table_select_row(linear_table, dit_nb);
02452         cpl_msg_warning(cpl_func, "Frames of EXPTIME nb %d "
02453                 "will not be taken into account for computation "
02454                 "as they are above --filter threshold", dit_nb);
02455     }
02456     }
02457 
02458     if (follow || detmon_lg_config.filter < 0) {
02459     /*
02460      * If the --collapse option is not activated by the user, the OFF 
02461      * sub-frameset is also supposed to be organized into pairs and,
02462      * therefore, processed as the ON sub-frameset.
02463      */
02464     if(!detmon_lg_config.collapse) {
02465         skip_if(irplib_detmon_pair_extract(set_off, selection_off, dit_nb, nsets_extracted, &with_equal_dit, 0, &pair_off));
02466 
02467         /* Load the OFF images */
02468         if (load_fset != NULL) {
02469         offs = cpl_imagelist_new();
02470         (*load_fset)(pair_off, CPL_TYPE_FLOAT, offs);
02471         } else {
02472         offs = cpl_imagelist_load_frameset(pair_off, CPL_TYPE_FLOAT,
02473                                            1, whichext);
02474         }
02475         skip_if(offs == NULL);
02476         skip_if(cpl_error_get_code());
02477     } else {
02478         /*
02479          * The master bias is required only for 
02480          * linearity computation in the OPT domain
02481          */
02482         cpl_image * collapse;
02483         masterl = cpl_imagelist_load_frameset(set_off, CPL_TYPE_FLOAT,
02484                                           1, whichext);
02485         skip_if(masterl == NULL);
02486         skip_if(cpl_error_get_code());
02487 
02488         collapse = cpl_imagelist_collapse_create(masterl);
02489         skip_if(collapse == NULL);
02490         skip_if(cpl_imagelist_set(masterl, collapse, 0));
02491 
02492         /* Any extra error checking needed here? */
02493         offs = (cpl_imagelist *)masterl;
02494     }
02495 
02496     /* Rescaling */
02497     if(detmon_lg_config.rescale) {
02498         skip_if(irplib_detmon_lg_rescale(ons));
02499         skip_if(irplib_detmon_lg_rescale(offs));
02500     }
02501         
02502     /* Linearity reduction */
02503     skip_if(irplib_detmon_linearity(pair_on, linear_table,
02504                     gain_table,
02505                     linearity_inputs,
02506                     ons, offs, dit_nb,
02507                     nsets_extracted, qclist, opt_nir));
02508 
02509     /*
02510      * --GAIN part for each DIT value--
02511      * The following call to irplib_detmon_gain_table_fill_row() fills
02512      * in the row nb i
02513      * of the GAIN table (output) and of the FIT table (by-product to be
02514      * used later for the polynomial computation of the GAIN)
02515      */
02516     if(detmon_lg_config.collapse) {
02517         offs = (cpl_imagelist *) opt_offs;
02518     }
02519 
02520     cpl_msg_info(cpl_func, "Computing GAIN for EXPTIME value nb %d",
02521              dit_nb + 1);
02522 
02523     skip_if(irplib_detmon_gain_table_fill_row(gain_table, autocorr_images,
02524                           diff_flats, ons, offs,
02525                                                   (double)detmon_lg_config.kappa,
02526                                                   detmon_lg_config.niter,
02527                                                   detmon_lg_config.llx,
02528                                                   detmon_lg_config.lly,
02529                                                   detmon_lg_config.urx,
02530                                                   detmon_lg_config.ury,
02531                           detmon_lg_config.m,
02532                                                   detmon_lg_config.n,
02533                                                   dit_nb, mode));
02534     }
02535 
02536     end_skip;
02537 
02538     cpl_frameset_delete(pair_on);
02539     cpl_imagelist_delete(ons);
02540 
02541     if(!detmon_lg_config.collapse ) {
02542     cpl_imagelist_delete(offs);
02543     }
02544 
02545     if(!detmon_lg_config.collapse) {
02546     cpl_frameset_delete(pair_off);
02547     }
02548 
02549     if(detmon_lg_config.collapse) {
02550     cpl_imagelist_delete(masterl);
02551     }
02552 
02553 
02554     return cpl_error_get_code();
02555 }
02556 
02557 /*---------------------------------------------------------------------------*/
02563 /*---------------------------------------------------------------------------*/
02564 static cpl_error_code
02565 irplib_detmon_add_adl_column(cpl_table * table)
02566 {
02567     cpl_error_code          error;
02568     double                  mean_med_dit;
02569     double                 *dits;
02570 
02571     cpl_ensure_code(table != NULL, CPL_ERROR_NULL_INPUT);
02572 
02573     mean_med_dit = cpl_table_get_column_mean(table, "MED_DIT");
02574     dits = cpl_table_get_data_double(table, "DIT");
02575 
02576     error = cpl_table_copy_data_double(table, "ADL", dits);
02577     cpl_ensure_code(!error, error);
02578     error = cpl_table_multiply_scalar(table, "ADL", mean_med_dit);
02579     cpl_ensure_code(!error, error);
02580 
02581     return cpl_error_get_code();
02582 }
02583 
02584 /*---------------------------------------------------------------------------*/
02592 /*---------------------------------------------------------------------------*/
02593 static cpl_error_code
02594 irplib_detmon_lg_reduce_init(cpl_table * gain_table,
02595                              cpl_table * linear_table,
02596                              cpl_imagelist ** linearity_inputs)
02597 {
02598     skip_if(irplib_detmon_gain_table_create(gain_table));
02599 
02600     skip_if(cpl_table_new_column(linear_table, "DIT", CPL_TYPE_DOUBLE));
02601     skip_if(cpl_table_new_column(linear_table, "EXPTIME", CPL_TYPE_DOUBLE));
02602     skip_if(cpl_table_new_column(linear_table, "MED", CPL_TYPE_DOUBLE));
02603     skip_if(cpl_table_new_column(linear_table, "MEAN", CPL_TYPE_DOUBLE));
02604     skip_if(cpl_table_new_column(linear_table, "MED_DIT", CPL_TYPE_DOUBLE));
02605     skip_if(cpl_table_new_column(linear_table, "MEAN_DIT",
02606                  CPL_TYPE_DOUBLE));
02607     skip_if(cpl_table_new_column(linear_table, "ADL", CPL_TYPE_DOUBLE));
02608 
02609     if(detmon_lg_config.pix2pix) {
02610     *linearity_inputs = cpl_imagelist_new();
02611     skip_if(*linearity_inputs == NULL);
02612     }
02613 
02614     end_skip;
02615 
02616     return cpl_error_get_code();
02617 }
02618 
02619 /*--------------------------------------------------------------------------*/
02625 /*--------------------------------------------------------------------------*/
02626 static double
02627 irplib_pfits_get_dit(const cpl_propertylist * plist)
02628 {
02629     double                  dit;
02630 
02631     dit = cpl_propertylist_get_double(plist, "ESO DET DIT");
02632 
02633     if(cpl_error_get_code() != CPL_ERROR_NONE) {
02634         cpl_msg_error(cpl_func, cpl_error_get_where());
02635     } 
02636     return dit;
02637 }
02638 
02639 /*--------------------------------------------------------------------------*/
02645 /*--------------------------------------------------------------------------*/
02646 static double
02647 irplib_pfits_get_dit_opt(const cpl_propertylist * plist)
02648 {
02649     double                  dit;
02650 
02651     dit = cpl_propertylist_get_double(plist, "ESO DET WIN1 UIT1");
02652 
02653     if(cpl_error_get_code() != CPL_ERROR_NONE) {
02654         cpl_msg_error(cpl_func, cpl_error_get_where());
02655     } 
02656     return dit;
02657 }
02658 
02659 /*--------------------------------------------------------------------------*/
02675 /*--------------------------------------------------------------------------*/
02676 
02677 static cpl_error_code
02678 irplib_detmon_linearity(const cpl_frameset * pair,
02679                         cpl_table * linear_table,
02680                         cpl_table * gain_table,
02681                         cpl_imagelist * linearity_inputs,
02682                         cpl_imagelist * ons,
02683                         cpl_imagelist * offs,
02684                         const int pos,
02685                         const int nsets,
02686                         cpl_propertylist * qclist,
02687             const cpl_boolean opt_nir)
02688 {
02689     const char             *filename;
02690     cpl_propertylist       *plist;
02691     cpl_image              *dif1;
02692     cpl_image              *dif2;
02693     cpl_image              *dif_avg;
02694     double                  med_dit;
02695     double                  mean_dit;
02696     double                  exptime, dit;
02697     cpl_error_code          error;
02698 
02699     cpl_ensure_code(ons != NULL, CPL_ERROR_NULL_INPUT);
02700     cpl_ensure_code(offs != NULL, CPL_ERROR_NULL_INPUT);
02701     /* DIT needed for linearity */
02702     filename = cpl_frame_get_filename(cpl_frameset_get_first_const(pair));
02703     if((plist = cpl_propertylist_load(filename, 0)) == NULL) {
02704         cpl_msg_error(cpl_func, "getting header from reference frame");
02705         cpl_ensure_code(0, cpl_error_get_code());
02706     }
02707 
02708     if(opt_nir) {
02709     dit = irplib_pfits_get_dit(plist);
02710     } else {
02711     dit = irplib_pfits_get_dit_opt(plist);
02712     }
02713     /*FIXME: These 2 calls shouldn't be the same... */
02714     exptime = irplib_pfits_get_exptime(plist);
02715 
02716     cpl_table_set(linear_table, "DIT", pos, dit);
02717     cpl_table_set(gain_table, "DIT", pos, dit);
02718 
02719     cpl_table_set(linear_table, "EXPTIME", pos, exptime);
02720     cpl_table_set(gain_table, "EXPTIME", pos, exptime);
02721 
02722     /* Algorithm defined: substract ON - OFF and average 2 differences */
02723     dif1 = cpl_image_subtract_create(cpl_imagelist_get_const(ons, 0),
02724                                      cpl_imagelist_get_const(offs, 0));
02725     if(!detmon_lg_config.collapse)
02726         dif2 = cpl_image_subtract_create(cpl_imagelist_get_const(ons, 1),
02727                                          cpl_imagelist_get_const(offs, 1));
02728     else
02729         dif2 = cpl_image_subtract_create(cpl_imagelist_get_const(ons, 1),
02730                                          cpl_imagelist_get_const(offs, 0));
02731 
02732     dif_avg = cpl_image_average_create(dif1, dif2);
02733 
02734     cpl_image_abs(dif_avg);
02735 
02736     cpl_ensure_code(dif_avg != NULL, cpl_error_get_code());
02737 
02738     if(opt_nir == OPT && pos == nsets / 2) {
02739         irplib_detmon_opt_contamination(dif_avg, qclist);
02740     }
02741 
02742     cpl_table_set(linear_table, "MED", pos, cpl_image_get_median(dif_avg));
02743     cpl_table_set(linear_table, "MEAN", pos, cpl_image_get_mean(dif_avg));
02744     med_dit = cpl_image_get_median(dif_avg) / dit;
02745     mean_dit = cpl_image_get_mean(dif_avg) / dit;
02746 
02747     cpl_table_set(linear_table, "MED_DIT", pos, med_dit);
02748     cpl_table_set(linear_table, "MEAN_DIT", pos, mean_dit);
02749 
02750     cpl_image_delete(dif1);
02751     cpl_image_delete(dif2);
02752     cpl_propertylist_delete(plist);
02753 
02754     /* Insert to the imagelist used to fit the polynomial */
02755     if(detmon_lg_config.pix2pix) {
02756         error = cpl_imagelist_set(linearity_inputs, dif_avg, pos);
02757         cpl_ensure_code(!error, error);
02758     } else {
02759         cpl_image_delete(dif_avg);
02760     }
02761 
02762     return cpl_error_get_code();
02763 }
02764 
02765 /*---------------------------------------------------------------------------*/
02776 /*---------------------------------------------------------------------------*/
02777 static cpl_error_code
02778 irplib_detmon_gain_table_fill_row(cpl_table * gain_table,
02779                   cpl_imagelist * autocorr_images,
02780                   cpl_imagelist * diff_flats,
02781                   const cpl_imagelist * ons,
02782                                   const cpl_imagelist * offs,
02783                                   double kappa, int nclip,
02784                                   int llx, int lly, int urx, int ury,
02785                                   int m, int n,
02786                   const int pos, unsigned mode)
02787 {
02788     const cpl_image        *image;
02789     double                  std = 0;
02790     cpl_image              *on_dif = NULL;
02791     cpl_image              *off_dif = NULL;
02792     double                  avg_on1, avg_on2;
02793     double                  avg_off1, avg_off2;
02794     double                  avg_on_dif, sig_on_dif;
02795     double                  avg_off_dif, sig_off_dif;
02796     double                  double_adu, autocorr, gain, gain_corr;
02797     double                  sigma, sigma_corr;
02798 
02799     skip_if((image = cpl_imagelist_get_const(ons, 0)) == NULL);
02800     skip_if(irplib_get_clean_mean_window(image, llx, lly, urx, ury, kappa,
02801                                          nclip, 1e-5, &avg_on1, &std));
02802     skip_if(cpl_table_set_double(gain_table, "MEAN_ON1", pos, avg_on1));
02803 
02804     skip_if((image = cpl_imagelist_get_const(ons, 1)) == NULL);
02805     skip_if(irplib_get_clean_mean_window(image, llx, lly, urx, ury, kappa,
02806                      nclip, 1e-5, &avg_on2, &std));
02807     skip_if(cpl_table_set_double(gain_table, "MEAN_ON2", pos, avg_on2));
02808 
02809     on_dif =
02810     cpl_image_subtract_create(cpl_imagelist_get_const(ons, 0),
02811                   cpl_imagelist_get_const(ons, 1));
02812     skip_if(on_dif == NULL);
02813 
02814     skip_if(irplib_get_clean_mean_window(on_dif, llx, lly, urx, ury, kappa,
02815                      nclip, 1e-5,
02816                                          &avg_on_dif, &sig_on_dif));
02817     skip_if(cpl_table_set_double(gain_table, "SIG_ON_DIF", pos, sig_on_dif));
02818 
02819 
02820 
02821     if(mode & IRPLIB_GAIN_WITH_AUTOCORR) {
02822       if (diff_flats) {
02823     cpl_image * diff = cpl_image_duplicate(on_dif);
02824         skip_if(cpl_imagelist_set(diff_flats, diff, pos));
02825       }
02826       if (autocorr_images) {
02827         cpl_image * corr;
02828         autocorr = irplib_detmon_autocorr_factor(on_dif, &corr, m, n);
02829         skip_if(cpl_imagelist_set(autocorr_images, corr, pos));
02830       } else {
02831         autocorr = irplib_detmon_autocorr_factor(on_dif, NULL, m, n);
02832       }
02833     } else {
02834         autocorr = 1.0;
02835     }
02836 
02837     if (mode & IRPLIB_GAIN_NO_COLLAPSE || pos == 0) {
02838         skip_if(irplib_get_clean_mean_window(cpl_imagelist_get_const(offs, 0),
02839                                              llx, lly, urx, ury, kappa, nclip,
02840                                              1e-5, &avg_off1, &std));
02841         skip_if(cpl_table_set_double(gain_table, "MEAN_OFF1", pos, avg_off1));
02842         skip_if(irplib_get_clean_mean_window(cpl_imagelist_get_const(offs, 1),
02843                                              llx, lly, urx, ury, kappa, nclip,
02844                          1e-5, &avg_off2, &std));
02845         skip_if(cpl_table_set_double(gain_table, "MEAN_OFF2", pos, avg_off2));
02846         off_dif =
02847             cpl_image_subtract_create(cpl_imagelist_get_const(offs, 0),
02848                                       cpl_imagelist_get_const(offs, 1));
02849     skip_if(off_dif == NULL);
02850         skip_if(irplib_get_clean_mean_window(off_dif, llx, lly, urx, ury,
02851                                              kappa, nclip, 1e-5,
02852                          &avg_off_dif, &sig_off_dif));
02853         skip_if(cpl_table_set_double(gain_table, "SIG_OFF_DIF",
02854                      pos, sig_off_dif));
02855     } else {
02856         int status;
02857         avg_off1 = cpl_table_get_double(gain_table, "MEAN_OFF1", 0, &status);
02858         skip_if(cpl_table_set_double(gain_table, "MEAN_OFF1", pos, avg_off1));
02859     avg_off2 = cpl_table_get_double(gain_table, "MEAN_OFF2", 0, &status);
02860         skip_if(cpl_table_set_double(gain_table, "MEAN_OFF2", pos, avg_off2));
02861     sig_off_dif = cpl_table_get_double(gain_table, "SIG_OFF_DIF",
02862                                            0, &status);
02863         skip_if(cpl_table_set_double(gain_table, "SIG_OFF_DIF",
02864                                      pos, sig_off_dif));
02865     }
02866 
02867     double_adu = (avg_on1 + avg_on2) - (avg_off1 + avg_off2);
02868 
02869     sigma = (sig_on_dif * sig_on_dif) - (sig_off_dif * sig_off_dif);
02870 
02871     sigma_corr = autocorr * sigma;
02872 
02873     gain = double_adu / sigma;
02874 
02875     gain_corr = double_adu / sigma_corr;
02876 
02877     skip_if(cpl_table_set_double(gain_table, "GAIN", pos, gain));
02878     skip_if(cpl_table_set_double(gain_table, "AUTOCORR", pos, autocorr));
02879     skip_if(cpl_table_set_double(gain_table, "GAIN_CORR", pos, gain_corr));
02880     skip_if(cpl_table_set_double(gain_table, "ADU", pos, double_adu / 2));
02881 
02882     /* FIXME: Remove the following 3 columns after testing period */
02883     skip_if(cpl_table_set_double(gain_table, "Y_FIT",
02884                  pos, sig_on_dif * sig_on_dif));
02885     skip_if(cpl_table_set_double(gain_table, "X_FIT", pos, double_adu));
02886     skip_if(cpl_table_set_double(gain_table, "X_FIT_CORR",
02887                  pos, double_adu / autocorr));
02888 
02889     end_skip;
02890     
02891     cpl_image_delete(on_dif);
02892     cpl_image_delete(off_dif);
02893 
02894     return cpl_error_get_code();
02895 }
02896 
02897 /*--------------------------------------------------------------------------*/
02904 /*--------------------------------------------------------------------------*/
02905 
02906 static cpl_image       *
02907 irplib_detmon_bpixs(const cpl_imagelist * coeffs, int *nbpixs)
02908 {
02909     int                     size;
02910     int                     i;
02911     const cpl_image        *first= cpl_imagelist_get_const(coeffs, 0);
02912     cpl_stats              *stats;
02913     double                  cur_mean;
02914     double                  cur_stdev;
02915     double                  lo_cut;
02916     double                  hi_cut;
02917     cpl_mask               *cur_mask;
02918     cpl_mask               *mask = cpl_mask_new(cpl_image_get_size_x(first),
02919                                             cpl_image_get_size_y(first));
02920     cpl_image              *cur_image = NULL;
02921     cpl_image              *bpm = NULL; /* Avoid false uninit warning */
02922     double                  p;
02923 
02924     size = cpl_imagelist_get_size(coeffs);
02925 
02926     if(!detmon_lg_config.bpmbin) {
02927     bpm = cpl_image_new(cpl_image_get_size_x(first),
02928                 cpl_image_get_size_y(first),
02929                 CPL_TYPE_INT);
02930     }
02931 
02932 
02933     for(i = 0; i < size; i++) {
02934         const cpl_image * cur_coeff = cpl_imagelist_get_const(coeffs, i);
02935 
02936         stats = cpl_stats_new_from_image(cur_coeff,
02937                                          CPL_STATS_MEAN | CPL_STATS_STDEV);
02938         cur_mean = cpl_stats_get_mean(stats);
02939         cur_stdev = cpl_stats_get_stdev(stats);
02940 
02941         lo_cut = cur_mean - detmon_lg_config.kappa * cur_stdev;
02942         hi_cut = cur_mean + detmon_lg_config.kappa * cur_stdev;
02943 
02944         cur_mask = cpl_mask_threshold_image_create(cur_coeff, lo_cut, hi_cut);
02945         cpl_mask_not(cur_mask);
02946 
02947     if(!detmon_lg_config.bpmbin) {
02948         cur_image = cpl_image_new_from_mask(cur_mask);
02949         p = pow(2, i);
02950         cpl_image_power(cur_image, p);
02951         cpl_image_add(bpm, cur_image);
02952         cpl_image_delete(cur_image);
02953     }
02954 
02955     cpl_mask_or(mask, cur_mask);
02956 
02957         cpl_mask_delete(cur_mask);
02958         cpl_stats_delete(stats);
02959     }
02960 
02961     if(detmon_lg_config.bpmbin) {
02962     bpm = cpl_image_new_from_mask(mask);
02963     }
02964 
02965     *nbpixs += cpl_mask_count(mask);
02966 
02967     cpl_mask_delete(mask);
02968 
02969     return bpm;
02970 }
02971 
02972 /*---------------------------------------------------------------------------*/
02984 /*---------------------------------------------------------------------------*/
02985 
02986 static double
02987 irplib_detmon_autocorr_factor(const cpl_image * image, 
02988                               cpl_image ** autocorr_image, int m, int n)
02989 {
02990     cpl_image * mycorr_image;
02991     double      autocorr;
02992 
02993 #ifdef HAVE_FFTW
02994 //  autocorr_image = irplib_detmon_image_autocorrelate_fftw(image,
02995 //                       detmon_lg_config.m, detmon_lg_config.m);
02996     mycorr_image = irplib_detmon_image_correlate(image, image, m, n);
02997 #else
02998     mycorr_image = irplib_detmon_autocorrelate(image, m, n);
02999 #endif
03000     if(mycorr_image == NULL) {
03001         return -1;
03002     }
03003 
03004     cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), -1);
03005 
03006 //    cpl_image_subtract_scalar(autocorr_image,
03007 //                cpl_image_get_median(autocorr_image));
03008     autocorr = cpl_image_get_flux(mycorr_image);
03009 
03010     if (autocorr_image) *autocorr_image = mycorr_image;
03011     else cpl_image_delete(mycorr_image);
03012 
03013     return autocorr;
03014 }
03015 
03016 /*---------------------------------------------------------------------------*/
03047 /*---------------------------------------------------------------------------*/
03048 static cpl_error_code
03049 irplib_detmon_lg_save(const cpl_parameterlist * parlist,
03050                       cpl_frameset * frameset,
03051                       const char *recipe_name,
03052                       const char *pipeline_name,
03053                       const char *pafregexp,
03054                       const char *procatg_lintbl,
03055                       const char *procatg_gaintbl,
03056                       const char *procatg_coeffscube,
03057                       const char *procatg_bpm,
03058                       const char *procatg_corr,
03059                       const char *procatg_diff,
03060                       const char *package,
03061                       cpl_imagelist * coeffs,
03062                       cpl_table * gain_table,
03063                       cpl_table * linear_table,
03064                       cpl_image * bpms,
03065                       cpl_imagelist * autocorr_images,
03066                       cpl_imagelist * diff_flats,
03067                       cpl_propertylist * qclist,
03068                       const int flag_sets,
03069                       const int which_set,
03070                       const cpl_frameset * usedframes,
03071                       int whichext)
03072 {
03073 
03074     cpl_frame              *ref_frame;
03075     cpl_propertylist       *plist = NULL;
03076     cpl_propertylist       *mainplist = NULL;
03077     char                   *name_o = NULL; /* Avoid (false) uninit warning */
03078     int                     nb_images;
03079     int                     i;
03080     cpl_error_code          error;
03081     cpl_propertylist *      xplist = NULL;
03082     cpl_propertylist *      paflist = NULL;
03083 
03084     /* Extract extension headers if multi-extension */
03085     if (detmon_lg_config.exts < 0) {
03086         const char * filename =
03087             cpl_frame_get_filename(cpl_frameset_get_first(frameset));
03088 
03089 
03090             xplist = cpl_propertylist_load_regexp(filename, whichext,
03091                                                      "ESO DET", 0);
03092             skip_if(cpl_propertylist_append(xplist, qclist));
03093     }
03094 
03095     /* This is only used later for PAF and temporarily for COEFFS_CUBE
03096        (see if defined)*/
03097     /* Get FITS header from reference file */
03098     ref_frame = cpl_frameset_get_first(frameset);
03099 
03100     skip_if((mainplist =
03101     cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
03102                   0)) == NULL);
03103 
03104     /*******************************/
03105     /*  Write the LINEARITY TABLE  */
03106     /*******************************/
03107 
03108     /* Set the file name for the table */
03109     if(!flag_sets) {
03110         name_o = cpl_sprintf("%s_linearity_table.fits", recipe_name);
03111         assert(name_o != NULL);
03112     } else {
03113         name_o =
03114             cpl_sprintf("%s_linearity_table_set%02d.fits", recipe_name,
03115                            which_set);
03116         assert(name_o != NULL);
03117     }
03118 
03119     if (detmon_lg_config.exts >= 0) {
03120         /* Save the table */
03121         skip_if(cpl_dfs_save_table(frameset, parlist, usedframes, linear_table,
03122                               NULL, recipe_name, procatg_lintbl, qclist, NULL,
03123                               package, name_o));
03124     } else {
03125     if(whichext == 1) {
03126         /* Save the 1. extension table */
03127         skip_if(cpl_dfs_save_table(frameset, parlist, usedframes, linear_table,
03128                   xplist, recipe_name, procatg_lintbl, NULL,
03129                   NULL, package, name_o));
03130     } else {
03131             skip_if(cpl_table_save(linear_table, NULL, xplist, name_o,
03132                                CPL_IO_EXTEND));
03133     }
03134     }
03135 
03136     /* Free */
03137     cpl_free(name_o);
03138     name_o = NULL;
03139 
03140     /**************************/
03141     /*  Write the GAIN TABLE  */
03142     /**************************/
03143 
03144     /* Set the file name for the table */
03145     if(!flag_sets) {
03146         name_o = cpl_sprintf("%s_gain_table.fits", recipe_name);
03147         assert(name_o != NULL);
03148     } else {
03149         name_o =
03150             cpl_sprintf("%s_gain_table_set%02d.fits", recipe_name,
03151                            which_set);
03152         assert(name_o != NULL);
03153     }
03154 
03155     if (detmon_lg_config.exts >= 0) {
03156         /* Save the table */
03157         skip_if(cpl_dfs_save_table(frameset, parlist, usedframes, gain_table,
03158                               NULL, recipe_name, procatg_gaintbl, qclist,
03159                               NULL, package, name_o));
03160     } else {
03161     if(whichext == 1) {
03162         /* Save the 1. extension table */
03163         skip_if(cpl_dfs_save_table(frameset, parlist, usedframes, gain_table,
03164                   xplist, recipe_name, procatg_gaintbl, NULL,
03165                   NULL, package, name_o));
03166     } else {
03167             skip_if(cpl_table_save(gain_table, NULL, xplist, name_o,
03168                                CPL_IO_EXTEND));
03169         }
03170     }
03171 
03172     /* Free */
03173     cpl_free(name_o);
03174     name_o = NULL;
03175 
03176     if(detmon_lg_config.pix2pix) {
03177 
03178     /***************************/
03179     /*  Write the COEFFS FITS  */
03180     /***************************/
03181 
03182     /* Set the file name for the data cube */
03183     if(!flag_sets) {
03184         name_o =
03185         cpl_sprintf("%s_coeffs_cube.fits", recipe_name);
03186         assert(name_o != NULL);
03187     } else {
03188         name_o =
03189         cpl_sprintf("%s_coeffs_cube_set%02d.fits",
03190                 recipe_name, which_set);
03191         assert(name_o != NULL);
03192     }
03193 
03194     /* Save the imagelist */
03195     if(detmon_lg_config.exts >= 0) {
03196 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 1, 0)
03197         skip_if(cpl_dfs_save_imagelist
03198            (frameset, parlist, usedframes, coeffs, CPL_BPP_IEEE_FLOAT,
03199         recipe_name, procatg_coeffscube, qclist, NULL, package,
03200         name_o));
03201 #else
03202         cpl_propertylist * hlist = cpl_propertylist_new();
03203         cpl_frame * product_frame = NULL;
03204 
03205         product_frame = cpl_frame_new();
03206         cpl_frame_set_filename(product_frame, name_o);
03207         cpl_frame_set_tag(product_frame, procatg_coeffscube);
03208         cpl_frame_set_type(product_frame, CPL_FRAME_TYPE_IMAGE);
03209         cpl_frame_set_group(product_frame, CPL_FRAME_GROUP_PRODUCT);
03210         cpl_frame_set_level(product_frame, CPL_FRAME_LEVEL_FINAL);
03211 
03212         if(cpl_dfs_setup_product_header(hlist,product_frame,frameset,
03213                         parlist,recipe_name,
03214                         package, "PRO-1.15") !=
03215            CPL_ERROR_NONE) {
03216         cpl_msg_error(cpl_func,
03217                   "Problem in the product DFS-compliance");
03218             cpl_propertylist_delete(hlist);
03219                 cpl_frame_delete(product_frame);
03220                 return cpl_error_get_code();
03221         }
03222 
03223         error = cpl_propertylist_append(hlist, mainplist);
03224         cpl_ensure_code(!error, error);
03225 
03226         cpl_msg_info(cpl_func, "Writing DATA CUBE");
03227         error = cpl_imagelist_save(coeffs, name_o, CPL_BPP_IEEE_FLOAT,
03228                        hlist, CPL_IO_DEFAULT);
03229         cpl_ensure_code(!error, error);
03230         cpl_propertylist_delete(hlist);
03231         cpl_frameset_insert(frameset, product_frame);
03232 #endif
03233     } else {
03234         if(whichext == 1) {
03235         skip_if(cpl_dfs_save_image(frameset, parlist, usedframes, NULL,
03236                       CPL_BPP_IEEE_FLOAT, recipe_name,
03237                       procatg_coeffscube, NULL, NULL,
03238                       package, name_o));
03239         skip_if(cpl_imagelist_save(coeffs,
03240                    name_o, CPL_BPP_IEEE_FLOAT, xplist,
03241                    CPL_IO_EXTEND));
03242         } else {
03243         skip_if(cpl_imagelist_save(coeffs,
03244                    name_o, CPL_BPP_IEEE_FLOAT, xplist,
03245                    CPL_IO_EXTEND));
03246         }
03247     }
03248     cpl_free(name_o);
03249         name_o = NULL;
03250 
03251         /*******************************/
03252         /*  Write the BAD PIXEL MAP    */
03253         /*******************************/
03254 
03255         /* Set the file name for the bpm */
03256         if(!flag_sets) {
03257             name_o = cpl_sprintf("%s_bpm.fits", recipe_name);
03258             assert(name_o != NULL);
03259         } else {
03260             name_o =
03261                 cpl_sprintf("%s_bpm_set%02d.fits", recipe_name, which_set);
03262             assert(name_o != NULL);
03263         }
03264 
03265         /* Save the image */
03266         if(detmon_lg_config.exts >= 0) {
03267             skip_if(cpl_dfs_save_image(frameset, parlist, usedframes, bpms,
03268                                   CPL_BPP_IEEE_FLOAT, recipe_name,
03269                                   procatg_bpm, qclist, NULL, package,
03270                                   name_o));
03271         } else {
03272         if (whichext == 1) {
03273         skip_if(cpl_dfs_save_image(frameset, parlist, usedframes, NULL,
03274                       CPL_BPP_IEEE_FLOAT, recipe_name,
03275                       procatg_bpm, NULL, NULL, package,
03276                       name_o));
03277                 skip_if(cpl_image_save(bpms, name_o, CPL_BPP_IEEE_FLOAT,
03278                                    xplist, CPL_IO_EXTEND));
03279         } else {
03280                 skip_if(cpl_image_save(bpms, name_o, CPL_BPP_IEEE_FLOAT,
03281                                    xplist, CPL_IO_EXTEND));
03282             }
03283         }
03284         /* Free */
03285         cpl_free(name_o);
03286         name_o = NULL;
03287 
03288     } /* End of if(pix2pix) */
03289 
03290     if(detmon_lg_config.intermediate) {
03291         /******************************/
03292         /*  Write the AUTOCORRS FITS  */
03293         /******************************/
03294         int                     j;
03295 
03296         nb_images = cpl_imagelist_get_size(autocorr_images);
03297         cpl_ensure_code(nb_images > 0, CPL_ERROR_DATA_NOT_FOUND);
03298 
03299 
03300         for(i = 0; i < nb_images; i++) {
03301             /* Set the file name for each image */
03302             if(!flag_sets) {
03303                 name_o =
03304                     cpl_sprintf("%s_autocorr_%d.fits", recipe_name, i);
03305                 assert(name_o != NULL);
03306             } else {
03307                 name_o =
03308                     cpl_sprintf("%s_autocorr_%d_set%02d.fits",
03309                                    recipe_name, i, which_set);
03310                 assert(name_o != NULL);
03311             }
03312 
03313 
03314             /* Save the image */
03315             if(detmon_lg_config.exts >= 0) {
03316                 skip_if(cpl_dfs_save_image
03317                    (frameset, parlist, usedframes,
03318                     cpl_imagelist_get(autocorr_images, i), CPL_BPP_IEEE_FLOAT,
03319                     recipe_name, procatg_corr, qclist, NULL, package,
03320                     name_o));
03321             } else {
03322         if(whichext == 1) {
03323             skip_if(cpl_dfs_save_image(frameset, parlist, usedframes, NULL,
03324                       CPL_BPP_IEEE_FLOAT, recipe_name,
03325                       procatg_corr, NULL, NULL,
03326                       package, name_o));
03327                     skip_if(cpl_image_save(cpl_imagelist_get(autocorr_images, i),
03328                                        name_o, CPL_BPP_IEEE_FLOAT, xplist,
03329                                        CPL_IO_EXTEND));
03330         } else {
03331                     skip_if(cpl_image_save(cpl_imagelist_get(autocorr_images, i),
03332                                        name_o, CPL_BPP_IEEE_FLOAT, xplist,
03333                                        CPL_IO_EXTEND));
03334                 }
03335             }
03336             cpl_free(name_o);
03337             name_o = NULL;
03338         }
03339 
03340         /***************************/
03341         /*   Write the DIFFS FITS  */
03342         /***************************/
03343 
03344         for(i = 0; i < nb_images; i++) {
03345             /* Set the file name for each image */
03346             if(!flag_sets) {
03347                 name_o =
03348                     cpl_sprintf("%s_diff_flat_%d.fits", recipe_name, i);
03349                 assert(name_o != NULL);
03350             } else {
03351                 name_o =
03352                     cpl_sprintf("%s_diff_flat_%d_set%02d.fits",
03353                                    recipe_name, i, which_set);
03354                 assert(name_o != NULL);
03355             }
03356 
03357 
03358             /* Save the image */
03359             if(detmon_lg_config.exts >= 0) {
03360                 skip_if(cpl_dfs_save_image
03361                    (frameset, parlist, usedframes,
03362                     cpl_imagelist_get(diff_flats, i), CPL_BPP_IEEE_FLOAT,
03363                     recipe_name, procatg_diff, qclist, NULL, package,
03364                     name_o));
03365             } else {
03366                 skip_if(cpl_dfs_save_image(frameset, parlist, usedframes, NULL,
03367                                       CPL_BPP_IEEE_FLOAT, recipe_name,
03368                                       procatg_diff, NULL, NULL,
03369                                       package, name_o));
03370 
03371                 for(j = 0; j < detmon_lg_config.nb_extensions; j++) {
03372                     skip_if(cpl_image_save(cpl_imagelist_get(diff_flats, i),
03373                                        name_o, CPL_BPP_IEEE_FLOAT, xplist,
03374                                        CPL_IO_EXTEND));
03375                 }
03376             }
03377             cpl_free(name_o);
03378             name_o = NULL;
03379         }
03380 
03381     } /* End of if(intermediate) */
03382 
03383     /*******************************/
03384     /*  Write the PAF file(s)      */
03385     /*******************************/
03386 
03387     paflist = cpl_propertylist_new();
03388 
03389 
03390     /* Set the file name for the PAF */
03391     if(detmon_lg_config.exts >= 0) {
03392     skip_if((plist =
03393         cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
03394                   detmon_lg_config.exts)) == NULL);
03395 
03396     if(!flag_sets) {
03397         name_o = cpl_sprintf("%s.paf", detmon_lg_config.pafname);
03398         assert(name_o != NULL);
03399     } else {
03400         name_o = cpl_sprintf("%s_set%02d.paf",
03401                  detmon_lg_config.pafname, which_set);
03402         assert(name_o != NULL);
03403     }
03404     } else {
03405     skip_if((plist =
03406         cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
03407                   whichext)) == NULL);
03408 
03409 
03410     if(!flag_sets) {
03411         name_o = cpl_sprintf("%s_ext%02d.paf", 
03412                  detmon_lg_config.pafname, whichext);
03413         assert(name_o != NULL);
03414     } else {
03415         name_o = cpl_sprintf("%s_set%02d_ext%02d.paf", 
03416                  detmon_lg_config.pafname,
03417                  which_set, whichext);
03418         assert(name_o != NULL);
03419     }
03420     }
03421 
03422     /* Get the keywords for the paf file */
03423     skip_if(cpl_propertylist_copy_property_regexp(paflist, plist,
03424                       pafregexp, 0));
03425     skip_if(cpl_propertylist_copy_property_regexp(paflist, mainplist,
03426                       pafregexp, 0));
03427 
03428     skip_if(error = cpl_propertylist_append(paflist, qclist));
03429 
03430     /* Save the PAF */
03431     skip_if(cpl_dfs_save_paf(pipeline_name, recipe_name, paflist, name_o));
03432 
03433     end_skip;
03434 
03435     cpl_propertylist_delete(xplist);
03436     cpl_propertylist_delete(paflist);
03437     cpl_propertylist_delete(plist);
03438     cpl_free(name_o);
03439     cpl_propertylist_delete(mainplist);
03440 
03441     return cpl_error_get_code();
03442 }
03443 
03444 /*---------------------------------------------------------------------------*/
03451 /*---------------------------------------------------------------------------*/
03452 static cpl_error_code
03453 irplib_detmon_opt_contamination(const cpl_image * reduced,
03454                                 cpl_propertylist * qclist)
03455 {
03456     cpl_error_code error;
03457     double                  median[5] = {0, 0, 0, 0, 0};
03458 
03459     median[0] = cpl_image_get_median_window(reduced,
03460                                         detmon_lg_config.llx1,
03461                                         detmon_lg_config.lly1,
03462                                         detmon_lg_config.urx1,
03463                                         detmon_lg_config.ury1);
03464     cpl_ensure_code(!cpl_error_get_code(), cpl_error_get_code());
03465     error = cpl_propertylist_append_double(qclist, "ESO QC CONTAM1",
03466                                            median[0]);
03467     cpl_ensure_code(!error, error);
03468 
03469     median[1] = cpl_image_get_median_window(reduced,
03470                                         detmon_lg_config.llx2,
03471                                         detmon_lg_config.lly2,
03472                                         detmon_lg_config.urx2,
03473                                         detmon_lg_config.ury2);
03474     cpl_ensure_code(!cpl_error_get_code(), cpl_error_get_code());
03475     error = cpl_propertylist_append_double(qclist, "ESO QC CONTAM2",
03476                                            median[1]);
03477     cpl_ensure_code(!error, error);
03478 
03479     median[2] = cpl_image_get_median_window(reduced,
03480                                         detmon_lg_config.llx3,
03481                                         detmon_lg_config.lly3,
03482                                         detmon_lg_config.urx3,
03483                                         detmon_lg_config.ury3);
03484     cpl_ensure_code(!cpl_error_get_code(), cpl_error_get_code());
03485     error = cpl_propertylist_append_double(qclist, "ESO QC CONTAM3",
03486                                            median[2]);
03487     cpl_ensure_code(!error, error);
03488 
03489     median[3] = cpl_image_get_median_window(reduced,
03490                                         detmon_lg_config.llx4,
03491                                         detmon_lg_config.lly4,
03492                                         detmon_lg_config.urx4,
03493                                         detmon_lg_config.ury4);
03494     cpl_ensure_code(!cpl_error_get_code(), cpl_error_get_code());
03495     error = cpl_propertylist_append_double(qclist, "ESO QC CONTAM4",
03496                                            median[3]);
03497     cpl_ensure_code(!error, error);
03498 
03499     median[4] = cpl_image_get_median_window(reduced,
03500                                         detmon_lg_config.llx5,
03501                                         detmon_lg_config.lly5,
03502                                         detmon_lg_config.urx5,
03503                                         detmon_lg_config.ury5);
03504     cpl_ensure_code(!cpl_error_get_code(), cpl_error_get_code());
03505     error = cpl_propertylist_append_double(qclist, "ESO QC CONTAM5",
03506                                            median[4]);
03507     cpl_ensure_code(!error, error);
03508 
03509     return cpl_error_get_code();
03510 }
03511 
03512 /*---------------------------------------------------------------------------*/
03519 /*---------------------------------------------------------------------------*/
03520 /*
03521 static cpl_error_code
03522 irplib_detmon_opt_lampcr(cpl_frameset * cur_fset, int ext)
03523 {
03524     cpl_image        * on        = NULL;
03525     cpl_image        * off       = NULL; 
03526     cpl_frame        * first_off = NULL;
03527     cpl_frame        * first_on  = NULL;
03528     cpl_propertylist * plist     = NULL;
03529     double             dit;
03530 
03531     cpl_ensure_code(cur_fset != NULL, CPL_ERROR_NULL_INPUT);
03532 
03533     skip_if((first_off = cpl_frameset_get_first(cur_fset)) == NULL);
03534     skip_if((first_on  = cpl_frameset_get_next (cur_fset)) == NULL);
03535 
03536     on = cpl_image_load(cpl_frame_get_filename(first_on),
03537                         CPL_TYPE_FLOAT, 0, ext);
03538     off = cpl_image_load(cpl_frame_get_filename(first_off),
03539                          CPL_TYPE_FLOAT, 0, ext);
03540     skip_if(cpl_image_subtract(on, off));
03541 
03542     plist = cpl_propertylist_load(cpl_frame_get_filename(first_on), 0);
03543     skip_if(plist == NULL);
03544     
03545     dit = irplib_pfits_get_dit_opt(plist);
03546 
03547     detmon_lg_config.cr = cpl_image_get_mean(on) / dit;
03548 
03549     end_skip;
03550 
03551     cpl_image_delete(on);
03552     cpl_image_delete(off);
03553     cpl_propertylist_delete(plist);
03554 
03555     return cpl_error_get_code();
03556 }
03557 */
03558 /*---------------------------------------------------------------------------*/
03566 /*---------------------------------------------------------------------------*/
03567 int
03568 irplib_detmon_lg_dfs_set_groups(cpl_frameset * set,
03569                                 const char *tag_on, const char *tag_off)
03570 {
03571     cpl_frame              *cur_frame;
03572     const char             *tag;
03573     int                     nframes;
03574     int                     i;
03575 
03576     /* Check entries */
03577     if(set == NULL)
03578         return -1;
03579 
03580     /* Initialize */
03581     nframes = cpl_frameset_get_size(set);
03582 
03583     /* Loop on frames */
03584     for(i = 0; i < nframes; i++) {
03585         cur_frame = cpl_frameset_get_frame(set, i);
03586         tag = cpl_frame_get_tag(cur_frame);
03587 
03588         /* RAW frames */
03589         if(!strcmp(tag, tag_on) || !strcmp(tag, tag_off))
03590             cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW);
03591         /* CALIB frames */
03592 
03593 /*        else if (!strcmp(tag, IIINSTRUMENT_CALIB_FLAT))
03594             cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB);
03595 */
03596     }
03597     return 0;
03598 }
03599 
03600 /*---------------------------------------------------------------------------*/
03612 /*---------------------------------------------------------------------------*/
03613 static cpl_error_code
03614 irplib_detmon_lg_reduce_all(const cpl_table * linear_table,
03615                             cpl_propertylist * qclist,
03616                             cpl_imagelist ** coeffs_ptr,
03617                             cpl_image ** bpms_ptr,
03618                             const cpl_imagelist * linearity_inputs,
03619                             const cpl_table * gain_table,
03620                 int which_ext)
03621 {
03622 
03623     int                     nbpixs = 0;
03624     const int               nsets = cpl_table_get_nrow(linear_table);
03625     int                     i;
03626     double autocorr;
03627     cpl_polynomial         *poly_linfit = NULL;
03628     cpl_image              *fiterror = NULL;
03629     char * name_o1 = NULL;
03630     char * name_o2 = NULL;
03631     double * pcoeffs = cpl_malloc(sizeof(double)*(detmon_lg_config.order + 1));
03632     unsigned mode = detmon_lg_config.autocorr ? IRPLIB_GAIN_WITH_AUTOCORR : 0;
03633 
03634     /* FIXME: This should go before the x and y vectors.
03635        Checking for all the inputs */
03636     cpl_ensure_code(qclist != NULL, CPL_ERROR_NULL_INPUT);
03637 
03638     skip_if(cpl_propertylist_append_string(qclist, DETMON_QC_METHOD,
03639                        detmon_lg_config.method));
03640     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_METHOD,
03641                      DETMON_QC_METHOD_C));
03642 
03643     if (!strcmp(detmon_lg_config.method, "PTC")) {
03644     /* Computation of GAIN via polynomial fit */
03645     if (detmon_lg_config.exts >= 0) { 
03646         cpl_msg_info(cpl_func,
03647              "Polynomial fitting for the GAIN (constant term method)");
03648     } else {
03649         cpl_msg_info(cpl_func,
03650              "Polynomial fitting for the GAIN (constant term method)"
03651              " for extension nb %d", which_ext);
03652     }
03653     skip_if(irplib_detmon_lg_qc_ptc(gain_table, qclist, mode));
03654     } else {
03655     skip_if(irplib_detmon_lg_qc_med(gain_table, qclist));
03656     }
03657 
03658     /*^FIXME: This shouldn't be written when no applied */
03659     /* Lamp flux */
03660     if(detmon_lg_config.lamp_ok) {
03661     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LAMP_FLUX,
03662                            detmon_lg_config.cr));
03663     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LAMP_FLUX,
03664                          DETMON_QC_LAMP_FLUX_C));
03665     }
03666 
03667     /*^FIXME: This shouldn't be written when no applied */
03668     if(detmon_lg_config.autocorr == TRUE) {
03669     autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
03670     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_AUTOCORR,
03671                            autocorr));
03672     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_AUTOCORR,
03673                          DETMON_QC_AUTOCORR_C));
03674     }
03675     if (detmon_lg_config.exts >= 0) { 
03676         cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix");
03677     } else {
03678         cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix"
03679                                " for extension nb %d", which_ext);
03680     }
03681 
03682     if(!detmon_lg_config.pix2pix) {
03683     double mse = 0;
03684         /* Computation of LINEARITY via polynomial fit */
03685     const cpl_vector *y =
03686         cpl_vector_wrap(nsets,
03687                 (double *)cpl_table_get_data_double_const(linear_table,
03688                                   "MED"));
03689     const cpl_vector *x =
03690         cpl_vector_wrap(nsets,
03691                 (double *)cpl_table_get_data_double_const(linear_table,
03692                                   "DIT"));
03693 
03694         if(x == NULL || y == NULL) {
03695         cpl_vector_unwrap((cpl_vector *)x);
03696         cpl_vector_unwrap((cpl_vector *)y);
03697         /*
03698          * As x and y are const vectors, if they would be defined at the
03699          * beginning of the function (required for skip_if - end_skip
03700          * scheme), they couldn't be initialised to NULL (required too).
03701          * Therefore, they are considered apart from the scheme.
03702          */
03703         skip_if(1);
03704     }
03705 
03706         cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
03707         poly_linfit = cpl_polynomial_fit_1d_create(x, y,
03708                            detmon_lg_config.order,
03709                            &mse);
03710 
03711     if(detmon_lg_config.order == cpl_vector_get_size(x) - 1) {
03712         cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
03713         mse = 0;
03714     }
03715 
03716     if(poly_linfit == NULL) {
03717         cpl_vector_unwrap((cpl_vector *)x);
03718         cpl_vector_unwrap((cpl_vector *)y);
03719         /* See comment in previous error checking if() statement */
03720         skip_if(1);
03721     }
03722 
03723     cpl_vector_unwrap((cpl_vector *)x);
03724     cpl_vector_unwrap((cpl_vector *)y);
03725 
03726         for(i = 0; i <= detmon_lg_config.order; i++) {
03727             const double            coeff =
03728                 cpl_polynomial_get_coeff(poly_linfit, &i);
03729             char                   *name_o =
03730                 cpl_sprintf("ESO QC LIN COEF%d", i);
03731             assert(name_o != NULL);
03732             skip_if(cpl_propertylist_append_double(qclist, name_o, coeff));
03733             cpl_free(name_o);
03734         pcoeffs[i] = coeff;
03735         }
03736     skip_if(cpl_propertylist_append_double(qclist, "ESO QC ERRFIT", mse));
03737     } else {
03738     const cpl_vector *x =
03739         cpl_vector_wrap(nsets,
03740                 (double *)cpl_table_get_data_double_const(linear_table,
03741                                   "DIT"));
03742 
03743     const cpl_image * first = cpl_imagelist_get_const(linearity_inputs, 0);
03744     int sizex = cpl_image_get_size_x(first);
03745     int sizey = cpl_image_get_size_y(first);
03746 
03747     double vsize = cpl_vector_get_size(x);
03748 
03749     fiterror = cpl_image_new(sizex, sizey, CPL_TYPE_FLOAT);
03750 
03751         *coeffs_ptr =
03752             cpl_fit_imagelist_polynomial(x, linearity_inputs, 0,
03753                                          detmon_lg_config.order, FALSE,
03754                                          CPL_TYPE_FLOAT, fiterror);
03755 
03756     cpl_vector_unwrap((cpl_vector*)x);
03757     irplib_ensure(*coeffs_ptr != NULL, CPL_ERROR_UNSPECIFIED, 
03758               "Failed polynomial fit");
03759     
03760         for(i = 0; i <= detmon_lg_config.order; i++) {
03761             cpl_image              *image = cpl_imagelist_get(*coeffs_ptr, i);
03762         const double coeff = cpl_image_get_median(image);
03763         pcoeffs[i] = coeff;
03764             name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
03765             name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
03766             assert(name_o1 != NULL);
03767             assert(name_o2 != NULL);
03768             skip_if(cpl_propertylist_append_double(qclist, name_o1, coeff));
03769             cpl_free(name_o1);
03770         name_o1= NULL;
03771             skip_if(cpl_propertylist_append_double(qclist, name_o2,
03772                        cpl_image_get_stdev(image)));
03773             cpl_free(name_o2);
03774         name_o2= NULL;
03775         }
03776 
03777     if(detmon_lg_config.order == vsize - 1) {
03778         cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
03779         skip_if(cpl_propertylist_append_double(qclist, "ESO QC ERRFIT",
03780                            0.0));
03781 
03782     } else {
03783         skip_if(cpl_propertylist_append_double(qclist, "ESO QC ERRFIT",
03784                            cpl_image_get_median(fiterror)));
03785     }
03786     }
03787 
03788     skip_if(irplib_detmon_lg_lineff(pcoeffs, qclist));
03789 
03790     /* Detection of bad pixels */
03791     if (detmon_lg_config.exts >= 0) { 
03792         cpl_msg_info(cpl_func, "Bad pixel detection");
03793     } else {
03794         cpl_msg_info(cpl_func, "Bad pixel detection"
03795              " for extension nb %d", which_ext);
03796     }
03797 
03798     if(detmon_lg_config.pix2pix) {
03799         *bpms_ptr = irplib_detmon_bpixs(*coeffs_ptr, &nbpixs);
03800     skip_if(*bpms_ptr == NULL);
03801     }
03802 
03803     skip_if(cpl_propertylist_append_int(qclist, DETMON_QC_NUM_BPM, nbpixs));
03804     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_NUM_BPM,
03805                                          DETMON_QC_NUM_BPM_C));
03806 
03807     if(detmon_lg_config.lamp_stability != 0.0) {
03808     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LAMP_STAB,
03809                            detmon_lg_config.lamp_stability));
03810     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LAMP_STAB,
03811                          DETMON_QC_LAMP_STAB_C));
03812     }
03813     end_skip;
03814 
03815     cpl_free(pcoeffs);
03816     cpl_free(name_o1);
03817     cpl_free(name_o2);
03818     cpl_image_delete(fiterror);
03819     cpl_polynomial_delete(poly_linfit);
03820 
03821     return cpl_error_get_code();
03822 }
03823 
03824 /*---------------------------------------------------------------------------*/
03831 /*---------------------------------------------------------------------------*/
03832 static cpl_error_code
03833 irplib_detmon_lg_lineff(double * pcoeffs,
03834                         cpl_propertylist * qclist)
03835 {
03836     double           lineff = 0;
03837     double           root = 0;
03838     cpl_polynomial * poly = cpl_polynomial_new(1);
03839     int i;
03840 
03841     double residual, slope;
03842 
03843     /*
03844      * Construction of the polynomial F_m(F_r) from F_m(t),
03845      * using F_r = a_1 * t.
03846      */
03847     pcoeffs[0] -= detmon_lg_config.ref_level;
03848 
03849     for (i = 2; i <= detmon_lg_config.order; i++) {
03850     int j;
03851     for(j = 0; j < i; j++) {
03852         pcoeffs[i] /= pcoeffs[1];
03853     }
03854     }
03855 
03856     pcoeffs[1] = 1;
03857 
03858     for (i = 0; i <= detmon_lg_config.order; i++) {
03859     skip_if(cpl_polynomial_set_coeff(poly, &i, pcoeffs[i]));
03860     }
03861 
03862     /*
03863      * Verification of validity of first guess (0).
03864      * The root to be found will be in the same interval of monotony
03865      * of the first guess; therefore, slope must be greater than 0.
03866      * Slope > 0 and poly(root) = 0 force also residual to be negative.
03867      */
03868     residual = cpl_polynomial_eval_1d(poly, 0.0, &slope);
03869 
03870     skip_if(slope    <= 0.0);
03871     skip_if(residual >= 0.0);
03872 
03873     skip_if(cpl_polynomial_solve_1d(poly, 0.0, &root, 1));
03874 
03875     lineff = (root - detmon_lg_config.ref_level) /
03876          detmon_lg_config.ref_level;
03877 
03878     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LIN_EFF,
03879                        lineff));
03880     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LIN_EFF,
03881                      DETMON_QC_LIN_EFF_C));
03882 
03883     end_skip;
03884 
03885     cpl_polynomial_delete(poly);
03886 
03887     return cpl_error_get_code();
03888 }
03889 
03890 /*---------------------------------------------------------------------------*/
03897 /*---------------------------------------------------------------------------*/
03898 static cpl_error_code
03899 irplib_detmon_lg_qc_ptc(const cpl_table  * gain_table,
03900             cpl_propertylist * qclist, unsigned mode)
03901 {
03902     double                  mse = 0;
03903     cpl_polynomial         *poly_fit = NULL;
03904     cpl_polynomial         *poly_fit2 = NULL;
03905     int i;
03906     const int               nsets = cpl_table_get_nrow(gain_table);
03907 
03908     /* The following 2 vectors are declared 'const' as they shouldn't be 
03909        modified. However, the data to be wrapped are casted as 'non-const'
03910        to avoid warning in cpl_vector_wrap, where API is 'non-const' */
03911 
03912     const cpl_vector             *x;
03913     const cpl_vector             *y;
03914 
03915     cpl_errorstate                prestate;
03916     double coef = 0;
03917 
03918     cpl_ensure_code(gain_table != NULL, CPL_ERROR_NULL_INPUT);
03919     cpl_ensure_code(qclist     != NULL, CPL_ERROR_NULL_INPUT);
03920 
03921     x = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT"));
03922     
03923     y = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
03924 
03925     skip_if(x == NULL || y == NULL);
03926 
03927     poly_fit = cpl_polynomial_fit_1d_create(x, y, 1, &mse);
03928     skip_if(poly_fit == NULL);
03929 
03930     /* Write the QC params corresponding to the fitting of the GAIN */
03931     i = 1;
03932     prestate = cpl_errorstate_get();
03933     coef = cpl_polynomial_get_coeff(poly_fit, &i);
03934     skip_if (!cpl_errorstate_is_equal(prestate) || coef == 0);
03935 
03936     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD, coef));
03937     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
03938                      DETMON_QC_CONAD_C));
03939 
03940     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,
03941                        1 / coef));
03942     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
03943                      DETMON_QC_GAIN_C));
03944 
03945     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE, mse));
03946     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
03947                      DETMON_QC_GAIN_MSE_C));
03948     i = 0;
03949     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_RON,
03950                        cpl_polynomial_get_coeff(poly_fit, &i)));
03951     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_RON,
03952                      DETMON_QC_RON_C));
03953     
03954     if(mode & IRPLIB_GAIN_WITH_AUTOCORR){
03955     const cpl_vector             *x2 =
03956         cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT_CORR"));
03957     const cpl_vector             *y2 =
03958         cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
03959 
03960     if(x2 == NULL || y2 == NULL) {
03961         cpl_vector_unwrap((cpl_vector *)x2);
03962         cpl_vector_unwrap((cpl_vector *)y2);
03963         /*
03964          * As x and y are const vectors, if they would be defined at the
03965          * beginning of the function (required for skip_if - end_skip
03966          * scheme), they couldn't be initialised to NULL (required too).
03967          * Therefore, they are considered apart from the scheme.
03968          */
03969         skip_if(1);
03970     }
03971 
03972     /* Revise mse, maybe used afterwards */
03973     poly_fit2 = cpl_polynomial_fit_1d_create(x2, y2, 1, &mse);
03974     if(poly_fit2 == NULL) {
03975         cpl_vector_unwrap((cpl_vector *)x2);
03976         cpl_vector_unwrap((cpl_vector *)y2);
03977         /* See comment in previous error checking if() statement */
03978         skip_if(1);
03979     }
03980 
03981     cpl_vector_unwrap((cpl_vector *)x2);
03982     cpl_vector_unwrap((cpl_vector *)y2);
03983 
03984     /* Write the QC params corresponding to the fitting of the GAIN */
03985     i = 1;
03986     prestate = cpl_errorstate_get();
03987     coef = cpl_polynomial_get_coeff(poly_fit2, &i);
03988     skip_if (!cpl_errorstate_is_equal(prestate) || coef == 0);
03989 
03990     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
03991                            1 / coef));
03992     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
03993                          DETMON_QC_GAIN_CORR_C));
03994     }
03995 
03996     end_skip;
03997 
03998     /* Cast back to 'non-const' to avoid warning. See comment above */
03999     cpl_vector_unwrap((cpl_vector *)x);
04000     cpl_vector_unwrap((cpl_vector *)y);
04001     cpl_polynomial_delete(poly_fit);
04002     cpl_polynomial_delete(poly_fit2);
04003 
04004     return cpl_error_get_code();
04005 }
04006 
04007 /*---------------------------------------------------------------------------*/
04014 /*---------------------------------------------------------------------------*/
04015 static cpl_error_code
04016 irplib_detmon_lg_qc_med(const cpl_table * gain_table,
04017                 cpl_propertylist * qclist)
04018 {
04019     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,
04020                        cpl_table_get_column_median
04021                        (gain_table, "GAIN")));
04022     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
04023                      DETMON_QC_GAIN_C));
04024 
04025     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE,
04026                        cpl_table_get_column_stdev
04027                        (gain_table, "GAIN")));
04028     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
04029                      DETMON_QC_GAIN_MSE_C));
04030 
04031     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
04032                        cpl_table_get_column_median
04033                        (gain_table, "GAIN_CORR")));
04034     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
04035                      DETMON_QC_GAIN_CORR_C));
04036     end_skip;
04037 
04038     return cpl_error_get_code();
04039 }
04040 
04041 
04042 /*---------------------------------------------------------------------------*/
04051 /*---------------------------------------------------------------------------*/
04052 static cpl_error_code
04053 irplib_detmon_lg_rescale(cpl_imagelist * to_rescale)
04054 {
04055     double                  med1 =
04056         cpl_image_get_median(cpl_imagelist_get(to_rescale, 0));
04057     double                  med2 =
04058         cpl_image_get_median(cpl_imagelist_get(to_rescale, 1));
04059 
04060     skip_if(0);
04061 
04062     if(fabs(med1 / med2 - 1) > 0.001) {
04063         if(med1 > med2)
04064             skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 0),
04065                                             med1 / med2));
04066         else
04067             skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 1),
04068                                             med2 / med1));
04069     }
04070     
04071     end_skip;
04072 
04073     return cpl_error_get_code();
04074 }
04075 
04076 /*---------------------------------------------------------------------------*/
04094 /*---------------------------------------------------------------------------*/
04095 static cpl_error_code
04096 irplib_detmon_pair_extract(const cpl_frameset * set,
04097                            int * selection, int selected,
04098                            int nsets_extracted,
04099                            int * with_equal_dit,
04100                            int onoff,
04101                            cpl_frameset ** pair)
04102 {
04103     int new_with_equal_dit = 0;
04104 
04105     cpl_ensure_code(set             != NULL, CPL_ERROR_NULL_INPUT);
04106     cpl_ensure_code(selection       != NULL, CPL_ERROR_NULL_INPUT);
04107     cpl_ensure_code(with_equal_dit  != NULL, CPL_ERROR_NULL_INPUT);
04108     cpl_ensure_code(pair            != NULL, CPL_ERROR_NULL_INPUT);
04109 
04110     *pair = cpl_frameset_extract(set, selection, selected);
04111     cpl_ensure_code(*pair != NULL, cpl_error_get_code());
04112 
04113     /* FIXME: Error checkin to be done here */
04114 
04115     /* It must be even (a single pair or multiple pairs of same DIT) */
04116     skip_if(cpl_frameset_get_size(*pair) % 2 != 0);
04117 
04118     /* See how many pairs with same DIT */
04119     if(cpl_frameset_get_size(*pair) != 2) {
04120         new_with_equal_dit = cpl_frameset_get_size(*pair) / 2;
04121         if(onoff == 1) {
04122             *with_equal_dit = new_with_equal_dit;
04123         } else {
04124             skip_if (*with_equal_dit    != 0 &&
04125              new_with_equal_dit != *with_equal_dit);
04126         }
04127     }
04128 
04129     /* If more than a pair, update selection array */
04130     if (new_with_equal_dit != 0) {
04131         int                     found = 0;
04132         int j;
04133         for(j = 0; j < cpl_frameset_get_size(set); j++) {
04134 
04135             if(selection[j] == selected) {
04136                 found++;
04137 
04138                 if((found - 1) / 2 != 0) {
04139                     selection[j] =
04140                         nsets_extracted + (found - 1) / 2 - 1;
04141                 }
04142             }
04143         }
04144         cpl_frameset_delete(*pair);
04145         *pair = cpl_frameset_extract(set, selection, selected);
04146         /* FIXME: Error checking missing here */
04147     }
04148 
04149     end_skip;
04150 
04151     return cpl_error_get_code();
04152 }
04153 
04154 /*--------------------------------------------------------------------------*/
04155 
04156 /*
04157  * @brief    Comparison function to identify different settings
04158  * @param    frame1  First frame 
04159  * @param    frame2  Second frame 
04160  * @return   0 if different, 1 if equal, -1 in error case
04161  */
04162 
04163 /*--------------------------------------------------------------------------*/
04164 
04165 static int
04166 irplib_detmon_lg_compare_pairs(const cpl_frame * frame1,
04167                    const cpl_frame * frame2)
04168 {
04169     int                     comparison;
04170     cpl_propertylist       *plist1;
04171     cpl_propertylist       *plist2;
04172     double                  dval1, dval2;
04173 
04174     /* Test entries */
04175     if(frame1 == NULL || frame2 == NULL)
04176         return -1;
04177 
04178     /* Get property lists */
04179     if((plist1 = cpl_propertylist_load(cpl_frame_get_filename(frame1),
04180                                        0)) == NULL) {
04181         cpl_msg_error(cpl_func, "getting header from reference frame");
04182         return -1;
04183     }
04184     if((plist2 = cpl_propertylist_load(cpl_frame_get_filename(frame2),
04185                                        0)) == NULL) {
04186         cpl_msg_error(cpl_func, "getting header from reference frame");
04187         cpl_propertylist_delete(plist1);
04188         return -1;
04189     }
04190 
04191     /* Test status */
04192     if(cpl_error_get_code()) {
04193         cpl_propertylist_delete(plist1);
04194         cpl_propertylist_delete(plist2);
04195         return -1;
04196     }
04197 
04198     /* Compare exposure time */
04199     comparison = 1;
04200     dval1 = irplib_pfits_get_exptime(plist1);
04201     dval2 = irplib_pfits_get_exptime(plist2);
04202     if(cpl_error_get_code()) {
04203         cpl_msg_error(cpl_func, "cannot get exposure time");
04204         cpl_propertylist_delete(plist1);
04205         cpl_propertylist_delete(plist2);
04206         return -1;
04207     }
04208     if(fabs(dval1 - dval2) > detmon_lg_config.tolerance)
04209         comparison = 0;
04210 
04211     /* Free and return */
04212     cpl_propertylist_delete(plist1);
04213     cpl_propertylist_delete(plist2);
04214     return comparison;
04215 }
04216 
04217 /*---------------------------------------------------------------------------*/
04261 /*---------------------------------------------------------------------------*/
04262 
04263 cpl_table *
04264 irplib_detmon_gain(const cpl_imagelist  * imlist_on,
04265            const cpl_imagelist  * imlist_off,
04266            const cpl_vector     * exptimes,
04267            int                    llx,
04268            int                    lly,
04269            int                    urx,
04270            int                    ury,
04271                    double                 kappa,
04272                    int                    nclip,
04273                    int                    m,
04274                    int                    n,
04275            cpl_propertylist     * qclist,
04276            unsigned               mode,
04277            cpl_imagelist       ** diff_imlist,
04278            cpl_imagelist       ** autocorr_imlist)
04279 {
04280     cpl_table     * gain_table   = NULL;
04281     cpl_imagelist * difflist     = NULL;
04282     cpl_imagelist * autocorrlist = NULL;
04283     cpl_imagelist * c_onlist     = NULL;
04284     cpl_imagelist * c_offlist    = NULL;
04285     cpl_vector    * dits         = NULL;
04286     int             ndits;
04287     int             i, j;
04288 
04289     cpl_ensure(imlist_on  != NULL, CPL_ERROR_NULL_INPUT, NULL);
04290     cpl_ensure(imlist_off != NULL, CPL_ERROR_NULL_INPUT, NULL);
04291     cpl_ensure(exptimes   != NULL, CPL_ERROR_NULL_INPUT, NULL);
04292     cpl_ensure(qclist     != NULL, CPL_ERROR_NULL_INPUT, NULL);
04293 
04294     /* Create table with columns */
04295     gain_table = cpl_table_new(cpl_vector_get_size(exptimes) / 2);
04296     skip_if(irplib_detmon_gain_table_create(gain_table));
04297 
04298     /* Search for different EXPTIME values */
04299     dits  = irplib_detmon_lg_find_dits(exptimes);
04300     ndits = cpl_vector_get_size(dits);
04301 
04302     /* AUTOCORR processing requires both. They will become outputs later. */
04303     if (mode & IRPLIB_GAIN_WITH_AUTOCORR && (diff_imlist || autocorr_imlist)) {
04304     difflist     = cpl_imagelist_new();
04305     autocorrlist = cpl_imagelist_new();
04306     }
04307 
04308     if (mode & IRPLIB_GAIN_COLLAPSE) {
04309         if (mode & IRPLIB_GAIN_WITH_RESCALE) {
04310         c_offlist = cpl_imagelist_duplicate(imlist_off);
04311         skip_if(irplib_detmon_lg_rescale(c_offlist));
04312         } else {
04313             c_offlist = (cpl_imagelist *) imlist_off;
04314         }
04315     }
04316 
04317     for (i = 0; i < ndits; i++) {
04318         int c_nons;
04319         int c_noffs = 0; /* False (uninit) warning */
04320 
04321     c_onlist  = cpl_imagelist_new();
04322     c_nons = 0;
04323 
04324     if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
04325         c_offlist = cpl_imagelist_new();
04326         c_noffs = 0;
04327     }
04328 
04329     for(j = 0; j < cpl_vector_get_size(exptimes); j++) {
04330         if (cpl_vector_get(dits, i) == cpl_vector_get(exptimes, j)) {
04331                 /*
04332                  * First we get the corresponding image from the ON imlist. 
04333                  * The option IRPLIB_GAIN_WITH_RESCALE requires to modify
04334                  * the input pixel buffer; therefore we must duplicate it.
04335                  * On the other hand, if this option is not required, there
04336                  * is no need for that duplication. We must only care that
04337                  * c_onlist must not be deleted but only unset.
04338                  */
04339                 cpl_image * im_on;
04340                 if (mode & IRPLIB_GAIN_WITH_RESCALE) {
04341                     const cpl_image * im =
04342                         cpl_imagelist_get_const(imlist_on, j);
04343                     im_on = cpl_image_duplicate(im);
04344                 } else {
04345                     im_on = (cpl_image *)cpl_imagelist_get_const(imlist_on, j);
04346                 }
04347                 skip_if(cpl_imagelist_set(c_onlist, im_on, c_nons));
04348                 c_nons++;
04349 
04350                 /*
04351                  * Same explanation as above but for OFF imlist.
04352                  * Only necessary when IRPLIB_GAIN_NO_COLLAPSE required.
04353                  */
04354         if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
04355                     cpl_image * im_off;
04356                     if (mode & IRPLIB_GAIN_WITH_RESCALE) {
04357                         const cpl_image * im = 
04358                           cpl_imagelist_get_const(imlist_off, j);
04359                         im_off = cpl_image_duplicate(im);
04360                     } else {
04361                         im_off = 
04362                           (cpl_image *) cpl_imagelist_get_const(imlist_off, j);
04363                     }
04364             skip_if(cpl_imagelist_set(c_offlist, im_off, c_noffs));
04365             c_noffs++;
04366         }
04367         }
04368     }
04369 
04370     /* If NO_COLLAPSE, must be the same number of images! */
04371     if (mode & IRPLIB_GAIN_NO_COLLAPSE)
04372         skip_if (c_nons != c_noffs);
04373 
04374     /* There must be pairs! */
04375     skip_if (c_nons == 0 || c_nons % 2 != 0);
04376 
04377     /* Rescaling */
04378     if(mode & IRPLIB_GAIN_WITH_RESCALE) {
04379         skip_if(irplib_detmon_lg_rescale(c_onlist));
04380         if (mode & IRPLIB_GAIN_NO_COLLAPSE)
04381         skip_if(irplib_detmon_lg_rescale(c_offlist));
04382     }
04383         
04384     /* The following loop is necessary for the case of multiple pairs
04385        of same EXPTIME values */
04386     while(c_nons > 0) {
04387         skip_if(irplib_detmon_gain_table_fill_row(gain_table, autocorrlist,
04388                               difflist, c_onlist,
04389                               c_offlist, kappa, nclip,
04390                                                       llx, lly, urx, ury,
04391                                                       m, n, i, mode));
04392             if (mode & IRPLIB_GAIN_WITH_RESCALE) {
04393                 cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
04394                 cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
04395                 if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
04396                   cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
04397                   cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
04398                 }
04399             } else {
04400             cpl_imagelist_unset(c_onlist, 0);
04401                 skip_if(0);
04402                 cpl_imagelist_unset(c_onlist, 0);
04403                 skip_if(0);
04404                 if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
04405                   cpl_imagelist_unset(c_offlist, 0);
04406                   skip_if(0);
04407                   cpl_imagelist_unset(c_offlist, 0);
04408                   skip_if(0);
04409                 }
04410             }
04411             skip_if(0);
04412         c_nons -= 2;
04413     }
04414 
04415     cpl_imagelist_delete(c_onlist);
04416     if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
04417           cpl_imagelist_delete(c_offlist);
04418     }
04419     }
04420 
04421     /* Computation of GAIN via polynomial fit */
04422     if (mode & IRPLIB_GAIN_PTC) {
04423       skip_if(irplib_detmon_lg_qc_ptc(gain_table, qclist, mode));
04424     } else {
04425     skip_if(irplib_detmon_lg_qc_med(gain_table, qclist));
04426     }
04427 
04428     if(mode & IRPLIB_GAIN_WITH_AUTOCORR) {
04429         double autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
04430     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_AUTOCORR,
04431                            autocorr));
04432     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_AUTOCORR,
04433                          DETMON_QC_AUTOCORR_C));
04434     }
04435 
04436     if (diff_imlist != NULL) *diff_imlist = difflist;
04437     if (autocorr_imlist != NULL) *autocorr_imlist = autocorrlist;
04438 
04439     end_skip;
04440 
04441     cpl_vector_delete(dits);
04442 
04443     return gain_table;
04444 }
04445 
04446 static cpl_error_code
04447 irplib_detmon_gain_table_create(cpl_table * gain_table)
04448 {
04449     skip_if(cpl_table_new_column(gain_table, "DIT",         CPL_TYPE_DOUBLE));
04450     skip_if(cpl_table_new_column(gain_table, "EXPTIME",     CPL_TYPE_DOUBLE));
04451     skip_if(cpl_table_new_column(gain_table, "MEAN_ON1",    CPL_TYPE_DOUBLE));
04452     skip_if(cpl_table_new_column(gain_table, "MEAN_ON2",    CPL_TYPE_DOUBLE));
04453     skip_if(cpl_table_new_column(gain_table, "MEAN_OFF1",   CPL_TYPE_DOUBLE));
04454     skip_if(cpl_table_new_column(gain_table, "MEAN_OFF2",   CPL_TYPE_DOUBLE));
04455     skip_if(cpl_table_new_column(gain_table, "SIG_ON_DIF",  CPL_TYPE_DOUBLE));
04456     skip_if(cpl_table_new_column(gain_table, "SIG_OFF_DIF", CPL_TYPE_DOUBLE));
04457     skip_if(cpl_table_new_column(gain_table, "GAIN",        CPL_TYPE_DOUBLE));
04458     skip_if(cpl_table_new_column(gain_table, "AUTOCORR",    CPL_TYPE_DOUBLE));
04459     skip_if(cpl_table_new_column(gain_table, "GAIN_CORR",   CPL_TYPE_DOUBLE));
04460     skip_if(cpl_table_new_column(gain_table, "ADU",         CPL_TYPE_DOUBLE));
04461     skip_if(cpl_table_new_column(gain_table, "X_FIT",       CPL_TYPE_DOUBLE));
04462     skip_if(cpl_table_new_column(gain_table, "X_FIT_CORR",  CPL_TYPE_DOUBLE));
04463     skip_if(cpl_table_new_column(gain_table, "Y_FIT",       CPL_TYPE_DOUBLE));
04464 
04465     end_skip;
04466 
04467     return cpl_error_get_code();
04468 }
04469 
04470 static cpl_vector *
04471 irplib_detmon_lg_find_dits(const cpl_vector * exptimes)
04472 {
04473     cpl_vector * dits  = cpl_vector_new(cpl_vector_get_size(exptimes) / 2);
04474     int          ndits = 0;
04475 
04476     int          i, j;
04477 
04478     /* First different EXPTIME */
04479     cpl_vector_set(dits, 0, cpl_vector_get(exptimes, 0));
04480     ndits = 1;
04481 
04482     /* Search for all different EXPTIMEs */
04483     for(i = 1; i < cpl_vector_get_size(exptimes); i++) {
04484       int ndiffs = 0;
04485     for (j = 0; j < ndits; j++) {
04486         if (cpl_vector_get(exptimes, i) != cpl_vector_get(dits, j))
04487               ndiffs++;
04488     }
04489         if(ndiffs == ndits) {
04490           cpl_vector_set(dits, ndits, cpl_vector_get(exptimes, i));
04491           ndits++;
04492         }
04493     }
04494 
04495     cpl_vector_set_size(dits, ndits);
04496 
04497     return dits;
04498 }

Generated on Fri Apr 18 14:11:41 2008 for UVES Pipeline Reference Manual by  doxygen 1.5.1