irplib_detmon_lg.c

00001 /* $Id: irplib_detmon_lg.c,v 1.108 2009/03/06 10:29:43 amodigli 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: amodigli $
00023  * $Date: 2009/03/06 10:29:43 $
00024  * $Revision: 1.108 $
00025  * $Name: visir-3_2_2 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*---------------------------------------------------------------------------
00033                                   Includes
00034  ---------------------------------------------------------------------------*/
00035 
00036 #ifdef HAVE_SFFTW
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     double                     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_lin_table_fill_row(cpl_table *, double,
00161                  cpl_imagelist *,
00162                  const cpl_imagelist *,
00163                  const cpl_imagelist *,
00164                  int, int, int, int,
00165                  const int,
00166                                  const int,
00167                  unsigned);
00168 
00169 static cpl_error_code
00170 irplib_detmon_gain_table_fill_row(cpl_table *, double,
00171                   cpl_imagelist *,
00172                   cpl_imagelist *,
00173                   const cpl_imagelist *,
00174                   const cpl_imagelist *,
00175                                   double, int,
00176                                   int, int, int, int,
00177                   int, int, const int, unsigned);
00178 
00179 static                  cpl_error_code
00180 irplib_detmon_lg_save(const cpl_parameterlist *,
00181                       cpl_frameset *,
00182                       const char *,
00183                       const char *,
00184                       const char *,
00185               const cpl_propertylist  *,
00186               const cpl_propertylist  *,
00187               const cpl_propertylist  *,
00188               const cpl_propertylist  *,
00189               const cpl_propertylist  *,
00190               const cpl_propertylist  *,
00191                       const char *,
00192                       cpl_imagelist *,
00193                       cpl_table *,
00194                       cpl_table *,
00195                       cpl_image *,
00196                       cpl_imagelist *,
00197                       cpl_imagelist *,
00198                       cpl_propertylist *,
00199                       const int, const int, const cpl_frameset *,
00200                       int);
00201 
00202 static cpl_error_code
00203 irplib_detmon_lg_qc_ptc(const cpl_table  *,
00204             cpl_propertylist *, unsigned);
00205 
00206 static cpl_error_code
00207 irplib_detmon_lg_qc_med(const cpl_table  *,
00208             cpl_propertylist *);
00209 
00210 static cpl_error_code
00211 irplib_detmon_pair_extract(const cpl_frameset *,
00212                            int *, int,
00213                            int ,
00214                            int *,
00215                            int,
00216                            cpl_frameset **);
00217 
00218 static cpl_error_code
00219 irplib_detmon_single_extract(const cpl_frameset *,
00220                  int *, int,
00221                  int ,
00222                  int *,
00223                  int,
00224                  cpl_frameset **);
00225 
00226 
00227 static double
00228 irplib_pfits_get_dit(const cpl_propertylist *);
00229 
00230 static double
00231 irplib_pfits_get_dit_opt(const cpl_propertylist *);
00232 
00233 
00234 static cpl_image       *irplib_detmon_bpixs(const cpl_imagelist *, cpl_boolean, const double, int *);
00235 
00236 static double
00237 irplib_detmon_autocorr_factor(const cpl_image *,
00238                               cpl_image **, int, int);
00239 
00240 /*
00241 #ifdef HAVE_SFFTW
00242 static cpl_image       *irplib_detmon_image_autocorrelate_fftw(const cpl_image
00243                                                                *, const int,
00244                                                                const int);
00245 #endif
00246 */
00247 
00248 
00249 
00250 static                  cpl_error_code
00251 irplib_detmon_opt_contamination(const cpl_imagelist *,
00252                 const cpl_imagelist *, 
00253                 unsigned mode, cpl_propertylist *);
00254 
00255 #if 0
00256 irplib_detmon_opt_lampcr(cpl_frameset *, int);
00257 #endif
00258 
00259 int
00260 irplib_detmon_lg_dfs_set_groups(cpl_frameset *, const char *, const char *);
00261 
00262 static cpl_error_code
00263 irplib_detmon_lg_reduce_all(const cpl_table *,
00264                 cpl_propertylist *,
00265                 cpl_imagelist **,
00266                 cpl_image **,
00267                             const cpl_imagelist *, 
00268                 const cpl_table *, int, cpl_boolean);
00269 
00270 static cpl_error_code          
00271 irplib_detmon_lg_check_defaults(const cpl_image *);
00272 
00273 static cpl_error_code          
00274 irplib_detmon_lg_rescale(cpl_imagelist *);
00275 
00276 static cpl_error_code
00277 irplib_detmon_lg_reduce_init(cpl_table *,
00278                              cpl_table *,
00279                              cpl_imagelist **,
00280                              const cpl_boolean);
00281 
00282 
00283 
00284 static cpl_error_code          
00285 irplib_detmon_add_adl_column(cpl_table *, cpl_boolean);
00286 
00287 static cpl_error_code
00288 irplib_detmon_lg_lamp_stab(const cpl_frameset *,
00289                const cpl_frameset *,
00290                            cpl_boolean, int);
00291 
00292 
00293 static cpl_error_code
00294 irplib_detmon_lg_reduce_dit(const cpl_frameset *,
00295                 int                *,
00296                 const int                 ,
00297                             int *,
00298                 int                 ,
00299                 const cpl_frameset *,
00300                 int                *,
00301                 cpl_table          *,
00302                 cpl_table          *,
00303                 cpl_imagelist      *,
00304                 cpl_propertylist   *,
00305                 cpl_boolean         ,
00306                 cpl_imagelist      *,
00307                 cpl_imagelist      *,
00308                             cpl_imagelist      *,
00309                 int (*)(const cpl_frameset *,
00310                     cpl_type,
00311                     cpl_imagelist *), int);
00312 
00313 static cpl_error_code
00314 irplib_detmon_lg_core(cpl_frameset *,
00315               cpl_frameset *,
00316               int *,
00317               int *,
00318               int ,
00319               int ,
00320                       int ,
00321               const char              *,
00322               const char              *,
00323               const char              *,
00324               const cpl_propertylist  *,
00325               const cpl_propertylist  *,
00326               const cpl_propertylist  *,
00327               const cpl_propertylist  *,
00328               const cpl_propertylist  *,
00329               const cpl_propertylist  *,
00330               const char              *,
00331               int                    (*) (const cpl_frameset *,
00332                                 cpl_type,
00333                                 cpl_imagelist *),
00334               int, cpl_boolean,
00335                       cpl_frameset *,  const cpl_parameterlist *, cpl_frameset *);
00336 
00337 static cpl_error_code
00338 irplib_detmon_lg_lineff(double *, cpl_propertylist *, int, int);
00339 
00340 
00341 static int
00342 irplib_detmon_lg_compare_pairs(const cpl_frame *,
00343                    const cpl_frame *);
00344 
00345 static cpl_error_code
00346 irplib_detmon_gain_table_create(cpl_table *,
00347                                 const cpl_boolean);
00348 
00349 
00350 static cpl_error_code
00351 irplib_detmon_lin_table_create(cpl_table *,
00352                                const cpl_boolean);
00353 
00354 static cpl_vector *
00355 irplib_detmon_lg_find_dits(const cpl_vector *,
00356                            double            );
00357 
00358 /*--------------------------------------------------------------------------*/
00359 
00360 /*
00361  * @brief  Reduce linearity and gain in the IR domain
00362  * @param  parlist              List of required parameters
00363  * @param  frameset             Input frameset
00364  * @param  tag_on               Tag to identify the ON frames
00365  * @param  tag_off              Tag to identify the OFF frames
00366  * @param  recipe_name          Name of the recipe calling this function
00367  * @param  pipeline_name        Name of the pipeline calling this function
00368  * @param  procatg_lintbl       PRO.CATG keyword for the Linearity Table
00369  * @param  procatg_gaintbl      PRO.CATG keyword for the Gain Table
00370  * @param  procatg_coeffscube     PRO.CATG keyword for the
00371  *                              Linearity Coefficients' Images
00372  * @param  procatg_bpm          PRO.CATG required for the Bad Pixel Map
00373  * @param  procatg_corr     PRO.CATG required for the Autocorrelation Images
00374  *                              (Intermediate product - only created if required)
00375  * @param  procatg_diff         PRO.CATG required for the Difference Images
00376  *                              (Intermediate Product - only created if required)
00377  * @param  package              PACKAGE (incl. VERSION) required
00378  *                              for the DFS keywords
00379  * @param  compare              Compare function used to classified frameset into
00380  *                              different settings, if any.
00381  * @param  load_fset            Loading function for preprocessing of input
00382                                 frames with special data format (needed for
00383                                 AMBER and MIDI processing)
00384 
00385  * @param  opt_nir              Boolean parameter to activate/deactivate
00386  *                              OPT-only / IR-only parts of the recipe
00387  * @return 0 on success, -1 on fail.
00388  * @note: The parlist contains the following parameters:
00389  *
00390  * @par1  kappa                 Kappa value used for the kappa-sigma clipping
00391  *                              rejection of bad pixels when computing sigma for
00392  *                              gain calculation
00393  * @par2  niter                 Number of iterations for the kappa-sigma clipping
00394  * @par3  threshold_min         Minimum threshold of the k-sigma (Not applied)
00395  * @par4  threshold_max         Maximum threshold of the k-sigma (Not applied)
00396  * @par5  llx                   Region of Interest (Default to the whole area)
00397  * @par6  lly                   Region of Interest (Default to the whole area)
00398  * @par7  urx                   Region of Interest (Default to the whole area)
00399  * @par8  ury                   Region of Interest (Default to the whole area)
00400  * @par9  ref_level             Reference Level (Not applied)
00401  * @par10 threshold             Threshold (Not applied)
00402  * @par11 intermediate          Boolean to activate the production of
00403  *                              Intermediate Products
00404  * @par12 autocorr              Boolean to activate autocorr method
00405  * @par13 collapse              Boolean to activate collapse of OFF frames
00406  * @par14 rescale               Boolean to activate pair rescaling
00407  * @par15 m                     X-Shift of the autocorrelation
00408  * @par16 n                     Y-Shift of the autocorrelation
00409  * @par17 llx1                  Region of Interest 1 (Only OPT)
00410  * @par18 lly1                  Region of Interest 1 (Only OPT)
00411  * @par19 urx1                  Region of Interest 1 (Only OPT)
00412  * @par20 ury1                  Region of Interest 1 (Only OPT)
00413  * @par21 llx2                  Region of Interest 2 (Only OPT)
00414  * @par22 lly2                  Region of Interest 2 (Only OPT)
00415  * @par23 urx2                  Region of Interest 2 (Only OPT)
00416  * @par24 ury2                  Region of Interest 2 (Only OPT)
00417  * @par25 llx3                  Region of Interest 3 (Only OPT)
00418  * @par26 lly3                  Region of Interest 3 (Only OPT)
00419  * @par27 urx3                  Region of Interest 3 (Only OPT)
00420  * @par28 ury3                  Region of Interest 3 (Only OPT)
00421  * @par29 llx4                  Region of Interest 4 (Only OPT)
00422  * @par30 lly4                  Region of Interest 4 (Only OPT)
00423  * @par31 urx4                  Region of Interest 4 (Only OPT)
00424  * @par32 ury4                  Region of Interest 4 (Only OPT)
00425  * @par33 llx5                  Region of Interest 5 (Only OPT)
00426  * @par34 lly5                  Region of Interest 5 (Only OPT)
00427  * @par35 urx5                  Region of Interest 5 (Only OPT)
00428  * @par36 ury5                  Region of Interest 5 (Only OPT)
00429  * @par37 exts                  Integer to select extension 
00430  */
00431 
00432 /*--------------------------------------------------------------------------*/
00433 
00434 cpl_error_code
00435 irplib_detmon_lg(cpl_frameset            * frameset,
00436                  const cpl_parameterlist * parlist,
00437                  const char              * tag_on,
00438                  const char              * tag_off,
00439                  const char              * recipe_name,
00440                  const char              * pipeline_name,
00441                  const char              * pafregexp,
00442                  const cpl_propertylist  * pro_lintbl,
00443                  const cpl_propertylist  * pro_gaintbl,
00444                  const cpl_propertylist  * pro_coeffscube,
00445                  const cpl_propertylist  * pro_bpm,
00446                  const cpl_propertylist  * pro_corr,
00447                  const cpl_propertylist  * pro_diff,
00448                  const char              * package,
00449                  int                    (* compare) (const cpl_frame *,
00450                              const cpl_frame *),
00451          int                    (* load_fset) (const cpl_frameset *,
00452                                cpl_type,
00453                                                cpl_imagelist *),
00454                  const cpl_boolean         opt_nir)
00455 {
00456     int              nsets;
00457     int            * selection = NULL;
00458     int              i;
00459     cpl_frame      * first     = NULL;
00460     cpl_image      * reference = NULL;
00461     cpl_frameset   * set       = NULL;
00462 
00463     /*
00464      * Variables used only inside the for() statement.
00465      * However, there are declared here to ease
00466      * memory management in error case.
00467      */
00468     int              * selection_on    = NULL;
00469     int              * selection_off   = NULL;
00470     cpl_frameset     * cur_fset        = NULL;
00471     cpl_frameset     * cur_fset_on     = NULL;        
00472     cpl_frameset     * cur_fset_off    = NULL;
00473 
00474     /* Test entries */
00475     cpl_ensure_code(frameset           != NULL, CPL_ERROR_NULL_INPUT);
00476     cpl_ensure_code(parlist            != NULL, CPL_ERROR_NULL_INPUT);
00477     cpl_ensure_code(tag_on             != NULL, CPL_ERROR_NULL_INPUT);
00478     cpl_ensure_code(tag_off            != NULL, CPL_ERROR_NULL_INPUT);
00479     cpl_ensure_code(recipe_name        != NULL, CPL_ERROR_NULL_INPUT);
00480     cpl_ensure_code(pipeline_name      != NULL, CPL_ERROR_NULL_INPUT);
00481     cpl_ensure_code(pro_lintbl         != NULL, CPL_ERROR_NULL_INPUT);
00482     cpl_ensure_code(pro_gaintbl        != NULL, CPL_ERROR_NULL_INPUT);
00483     cpl_ensure_code(pro_coeffscube     != NULL, CPL_ERROR_NULL_INPUT);
00484     cpl_ensure_code(pro_bpm            != NULL, CPL_ERROR_NULL_INPUT);
00485     cpl_ensure_code(pro_corr           != NULL, CPL_ERROR_NULL_INPUT);
00486     cpl_ensure_code(pro_diff           != NULL, CPL_ERROR_NULL_INPUT);
00487     cpl_ensure_code(package            != NULL, CPL_ERROR_NULL_INPUT);
00488 
00489     skip_if (irplib_detmon_lg_dfs_set_groups(frameset, tag_on, tag_off));
00490 
00491     /*
00492      * First check of input consistency in NIR case:
00493      * There must be a pair ON and a pair OFF for each DIT.
00494      */
00495  
00496     skip_if (irplib_detmon_lg_retrieve_parlist(pipeline_name, recipe_name,
00497                            parlist, opt_nir));
00498 
00499     /*
00500      * Retrieve first image to check some parameters' values and
00501      * set default values which refer to the image.
00502      */
00503 
00504     first = cpl_frameset_get_first(frameset);
00505     irplib_ensure (first != NULL, CPL_ERROR_ILLEGAL_INPUT, "Empty data set!");
00506 
00507     if (detmon_lg_config.exts < 0) {
00508         reference = cpl_image_load(cpl_frame_get_filename(first),
00509                                    CPL_TYPE_FLOAT, 0, 1);
00510     } else {
00511     if (load_fset != NULL) {
00512         cpl_frameset * new = cpl_frameset_new();
00513         cpl_imagelist * p = cpl_imagelist_new();
00514         cpl_frameset_insert(new, cpl_frame_duplicate(first));
00515         (*load_fset)(new, CPL_TYPE_FLOAT, p);
00516         reference = cpl_image_duplicate(cpl_imagelist_get(p, 0));
00517         cpl_imagelist_delete(p);
00518         cpl_frameset_delete(new);
00519     } else {
00520            cpl_msg_info(cpl_func,"name=%s",cpl_frame_get_filename(first));
00521         reference = cpl_image_load(cpl_frame_get_filename(first),
00522                        CPL_TYPE_FLOAT, 0, detmon_lg_config.exts);
00523     }
00524     }
00525     skip_if (reference == NULL);
00526 
00527     skip_if (irplib_detmon_lg_check_defaults(reference));
00528 
00529     /* Labelise all input frames */
00530     set = cpl_frameset_duplicate(frameset);
00531     /*
00532      * After each setting iteration, frameset will be modified (product
00533      * frames will have been added), so it is better to duplicate it, keep
00534      * it in its original state for the labelise-extract scheme.
00535      */
00536     if (compare == NULL) {
00537         nsets = 1;
00538     } else {
00539         cpl_msg_info(cpl_func, "Identifying different settings");
00540         selection = cpl_frameset_labelise(set, compare, &nsets);
00541         skip_if (selection == NULL);
00542     }
00543 
00544     /* Get the nb of extensions */
00545     detmon_lg_config.nb_extensions = 1;
00546     if (detmon_lg_config.exts < 0) {
00547     detmon_lg_config.nb_extensions = cpl_frame_get_nextensions(first);
00548     }
00549 
00550     /* Extract settings and reduce each of them */
00551     for(i = 0; i < nsets; i++) {
00552     int  j;
00553     int nexts = detmon_lg_config.nb_extensions;
00554 
00555     int  nsets_on  = 0;
00556     int  nsets_off = 0;
00557 
00558     /* Reduce data set nb i */
00559     cpl_msg_info(cpl_func, "Reduce data set nb %d out of %d",
00560              i + 1, nsets);
00561 
00562     cur_fset = nsets == 1 ?
00563         cpl_frameset_duplicate(set) : 
00564         cpl_frameset_extract(set, selection, i);   
00565     skip_if(cur_fset == NULL);
00566 
00567     /* Split input frameset into 2 sub-framesets for ON and OFF frames */
00568     cur_fset_on  = cpl_frameset_new();
00569     cur_fset_off = cpl_frameset_new();
00570     cpl_msg_info(cpl_func, "Splitting into ON and OFF sub-framesets");
00571     skip_if (irplib_detmon_lg_split_onoff(cur_fset,
00572                           cur_fset_on, cur_fset_off,
00573                           tag_on, tag_off /*, opt_nir*/));
00574 
00575     /* Labelise each sub-frameset according to DIT values */
00576     selection_on = cpl_frameset_labelise(cur_fset_on,
00577                          irplib_detmon_lg_compare_pairs,
00578                          &nsets_on);
00579     skip_if (selection_on == NULL);
00580 
00581     if (!detmon_lg_config.collapse) {
00582         selection_off = cpl_frameset_labelise(cur_fset_off,
00583                           irplib_detmon_lg_compare_pairs,
00584                           &nsets_off);
00585         skip_if (selection_off == NULL);
00586     }
00587 
00588     /* Test if they have equal nb of labels */
00589     if (!detmon_lg_config.collapse) {
00590         skip_if(nsets_on != nsets_off);
00591     }
00592 
00593     if(nsets_on <= detmon_lg_config.order) {
00594         cpl_msg_error(cpl_func, "Not enough frames for the polynomial"
00595               " fitting. nsets <= order.");
00596         skip_if(1);
00597     }
00598 
00599     if(detmon_lg_config.exts >= 0) {
00600         /*
00601          * In the optical domain, the first 2 frames
00602          * are used apart from the pairs.
00603          */
00604 
00605 #if 0
00606         if (detmon_lg_config.lamp_ok) {
00607         skip_if(irplib_detmon_opt_lampcr(cur_fset, 0));
00608         }
00609 #endif
00610         skip_if(irplib_detmon_lg_core(cur_fset_on, cur_fset_off, selection_on,
00611                       selection_off, nsets_on, detmon_lg_config.exts, i, recipe_name, pipeline_name, pafregexp, pro_lintbl, pro_gaintbl, pro_coeffscube, pro_bpm, pro_corr, pro_diff, package, load_fset, nsets, opt_nir, frameset, parlist, cur_fset));
00612     } else {
00613         for(j = 1; j <= nexts; j++) {
00614         /*
00615          * In the optical domain, the first 2 frames
00616          * are used apart from the pairs.
00617          */
00618 
00619 #if 0
00620         if (detmon_lg_config.lamp_ok) {
00621             skip_if(irplib_detmon_opt_lampcr(cur_fset, j));
00622         }
00623 #endif
00624 
00625         skip_if(irplib_detmon_lg_core(cur_fset_on, cur_fset_off, selection_on,
00626                           selection_off, nsets_on, j, i,  recipe_name, pipeline_name,pafregexp,  pro_lintbl, pro_gaintbl, pro_coeffscube, pro_bpm, pro_corr, pro_diff, package, load_fset, nsets, opt_nir, frameset, parlist, cur_fset));
00627         }
00628     }
00629 
00630     /* Free for each setting */
00631     cpl_free(selection_on);
00632     cpl_free(selection_off);
00633 
00634     cpl_frameset_delete(cur_fset);
00635     cpl_frameset_delete(cur_fset_on);
00636     cpl_frameset_delete(cur_fset_off);
00637 
00638     selection_on  = NULL;
00639     selection_off = NULL;
00640     cur_fset      = NULL;
00641     cur_fset_on   = NULL;
00642     cur_fset_off  = NULL;
00643     }
00644 
00645     end_skip;
00646 
00647     cpl_free(selection_on);
00648     cpl_free(selection_off);
00649 
00650     cpl_frameset_delete(cur_fset);
00651     cpl_frameset_delete(cur_fset_on);
00652     cpl_frameset_delete(cur_fset_off);
00653 
00654     cpl_frameset_delete(set);
00655     cpl_free(selection);
00656     cpl_image_delete(reference);
00657 
00658     return cpl_error_get_code();
00659 }
00660 
00661 /*---------------------------------------------------------------------------*/
00694 /*---------------------------------------------------------------------------*/
00695 
00696 static cpl_error_code
00697 irplib_detmon_lg_core(cpl_frameset * cur_fset_on,
00698               cpl_frameset * cur_fset_off,
00699               int * selection_on,
00700               int * selection_off,
00701               int nsets_on,
00702               int whichext,
00703                       int whichset,
00704               const char              * recipe_name,
00705               const char              * pipeline_name,
00706               const char              * pafregexp,
00707               const cpl_propertylist  * pro_lintbl,
00708               const cpl_propertylist  * pro_gaintbl,
00709               const cpl_propertylist  * pro_coeffscube,
00710               const cpl_propertylist  * pro_bpm,
00711               const cpl_propertylist  * pro_corr,
00712               const cpl_propertylist  * pro_diff,
00713               const char              * package,
00714               int                    (* load_fset) (const cpl_frameset *,
00715                                 cpl_type,
00716                                 cpl_imagelist *),
00717               int nsets, cpl_boolean opt_nir,
00718                       cpl_frameset * frameset, const cpl_parameterlist * parlist,
00719                       cpl_frameset * cur_fset)
00720 {
00721     cpl_table        * gain_table      = cpl_table_new(cpl_frameset_get_size(cur_fset_on)/2);
00722     cpl_table        * linear_table    = cpl_table_new(cpl_frameset_get_size(cur_fset_on)/2);
00723     cpl_imagelist    * coeffs          = NULL;
00724     cpl_image        * bpm             = NULL;
00725     cpl_imagelist    * autocorr_images = NULL;
00726     cpl_imagelist    * diff_flats      = NULL;
00727     cpl_propertylist * qclist          = NULL;
00728 
00729     /* Reduce extension nb i */
00730     cpl_msg_info(cpl_func, "Reduce extension nb %d ",
00731          whichext);
00732 
00733     /* FIXME: All other memory objects in use should be 
00734        initialised here (except coeffs which can not be) */
00735     if (detmon_lg_config.intermediate) {
00736     autocorr_images = cpl_imagelist_new();
00737     diff_flats      = cpl_imagelist_new();
00738     }
00739     qclist = cpl_propertylist_new();
00740 
00741     /* Reduction done here */
00742     cpl_msg_info(cpl_func, "Starting data reduction");
00743     skip_if(irplib_detmon_lg_reduce(cur_fset_on, cur_fset_off,
00744                     selection_on, selection_off,
00745                     nsets_on, &coeffs, gain_table,
00746                     linear_table, &bpm, autocorr_images,
00747                     diff_flats, qclist, load_fset,
00748                     opt_nir, whichext));
00749 
00750     /* Save the products for each setting */
00751     cpl_msg_info(cpl_func, "Saving the products");
00752     if(nsets == 1) {
00753     skip_if(irplib_detmon_lg_save(parlist, frameset, recipe_name,
00754                       pipeline_name, pafregexp,
00755                       pro_lintbl, pro_gaintbl,
00756                       pro_coeffscube, pro_bpm,
00757                       pro_corr, pro_diff, package,
00758                       coeffs, gain_table, linear_table,
00759                       bpm, autocorr_images, diff_flats,
00760                       qclist, 0, 0, cur_fset, whichext));
00761     } else {
00762     skip_if(irplib_detmon_lg_save(parlist, frameset, recipe_name,
00763                       pipeline_name, pafregexp,
00764                       pro_lintbl, pro_gaintbl,
00765                       pro_coeffscube, pro_bpm,
00766                       pro_corr, pro_diff, package,
00767                       coeffs, gain_table, linear_table,
00768                       bpm, autocorr_images, diff_flats,
00769                       qclist, 1, whichset+ 1, cur_fset, whichext));
00770     }
00771 
00772     end_skip;
00773 
00774     /* Free for each extension */
00775     cpl_table_delete(gain_table);
00776     cpl_table_delete(linear_table);
00777     cpl_imagelist_delete(coeffs);
00778     cpl_propertylist_delete(qclist);
00779     cpl_image_delete(bpm);
00780     cpl_imagelist_delete(autocorr_images);
00781     cpl_imagelist_delete(diff_flats);
00782 
00783     return cpl_error_get_code();
00784 }
00785 /*--------------------------------------------------------------------------*/
00786 
00787 /*
00788  * @brief  Correlate two images with a given range of shifts
00789  * @param  image1       Input image
00790  * @param  image2       Input image
00791  * @param  m            Shift to apply on the x-axis
00792  * @param  n            Shift to apply on the y-axis
00793  * @return              An image of size 2m+1 by 2n+1. Each pixel value
00794  *                      corresponds to the correlation of shift the position
00795  *                      of the pixel. Pixel in the centre (m+1, n+1),
00796  *                      corresponds to shift (0,0). Pixels to the left and
00797  *                      down correspond to negative shifts.
00798  *
00799  * @note                At this moment, this function only accepts images to
00800  *                      have both the same size.
00801  */
00802 
00803 /*--------------------------------------------------------------------------*/
00804 #ifdef HAVE_SFFTW
00805 
00806 cpl_image              *
00807 irplib_detmon_image_correlate(const cpl_image * image1,
00808                               const cpl_image * image2,
00809                               const int m, const int n)
00810 {
00811     cpl_image              *image1_padded;
00812     cpl_image              *image2_padded;
00813     float                  *data1;
00814     float                  *data2;
00815     int                     nx, ny;
00816     int                     nx2, ny2;
00817     int                     i;
00818 
00819     fftwnd_plan              p1;
00820     fftw_complex          *in1;
00821     fftw_complex          *ri1;
00822 
00823     fftwnd_plan              p2;
00824     fftw_complex          *in2;
00825     fftw_complex          *ri2;
00826 
00827     fftwnd_plan              p_inv;
00828     fftw_complex          *in_inv;
00829     fftw_complex          *ri_inv;
00830 
00831     fftw_complex          *corr;
00832     float                  *corr_r;
00833 
00834     cpl_image              *corr_image;
00835     cpl_image              *corr_image_window;
00836     cpl_image              *reorganised;
00837     cpl_image              *image;
00838 
00839     /* Test the entries */
00840     cpl_ensure(image1 != NULL, CPL_ERROR_NULL_INPUT, NULL);
00841     cpl_ensure(image2 != NULL, CPL_ERROR_NULL_INPUT, NULL);
00842 
00843     cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
00844     cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
00845 
00846     nx = cpl_image_get_size_x(image1);
00847     ny = cpl_image_get_size_y(image1);
00848 
00849     nx2 = cpl_image_get_size_x(image2);
00850     ny2 = cpl_image_get_size_y(image2);
00851 
00852     /* At this moment, the images must be of the same size */
00853     cpl_ensure(nx == nx2 && ny == ny2, CPL_ERROR_ILLEGAL_INPUT, NULL);
00854 
00855     /* Pad the images with zeroes to avoid periodical effects of DFT */
00856     image1_padded = cpl_image_new(nx + 2 * m, ny + 2 * n, CPL_TYPE_FLOAT);
00857     cpl_image_copy(image1_padded, image1, m + 1, n + 1);
00858 
00859     image2_padded = cpl_image_new(nx + 2 * m, ny + 2 * n, CPL_TYPE_FLOAT);
00860     cpl_image_copy(image2_padded, image2, m + 1, n + 1);
00861 
00862     /* Get pointers to the pixel data */
00863     data1 = cpl_image_get_data_float(image1_padded);
00864     data2 = cpl_image_get_data_float(image2_padded);
00865 
00866     /*New dimensions of the padded images */
00867     nx = nx + 2 * m;
00868     ny = ny + 2 * n;
00869 
00870     /* Establish the input/output data arrays and the FFT plan */
00871     in1 = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * nx * ny);
00872     ri1 = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * nx * ny);
00873     p1 = fftw2d_create_plan_specific(ny, nx, FFTW_FORWARD, FFTW_ESTIMATE,
00874                      in1, 1, ri1, 1);
00875 
00876     /* Pack the CPL image data into the FFTW input array */
00877     for(i = 0; i < nx * ny; i++) {
00878         *((float complex *)in1 + i) = (*(data1 + i) + 0.0 * I);
00879     }
00880 
00881     /* Actually perform the FFT */
00882     fftwnd_one(p1, in1, ri1);
00883 
00884     /* Cleanup resources */
00885     fftwnd_destroy_plan(p1);
00886     cpl_image_delete(image1_padded);
00887 
00888     /* Establish the input/output data arrays and the FFT plan */
00889     in2 = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * nx * ny);
00890     ri2 = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * nx * ny);
00891 
00892     p2 = fftw2d_create_plan_specific(ny, nx, FFTW_FORWARD, FFTW_ESTIMATE,
00893                       in2, 1, ri2, 1);
00894 
00895 
00896     /* Pack the CPL image data into the FFTW input array */
00897     for(i = 0; i < nx * ny; i++) {
00898         *((float complex *)in2 + i) = (*(data2 + i) + 0.0 * I);
00899     }
00900 
00901     /* Actually perform the FFT */
00902     fftwnd_one(p2, in2, ri2);
00903 
00904     /* Cleanup resources */
00905     fftwnd_destroy_plan(p2);
00906     cpl_image_delete(image2_padded);
00907 
00908     /* Establish the input/output data arrays and the FFT plan */
00909     in_inv = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * nx * ny);
00910     ri_inv = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * nx * ny);
00911     p_inv = fftw2d_create_plan_specific(ny, nx, FFTW_FORWARD, FFTW_ESTIMATE,
00912                     in_inv, 1, ri_inv, 1);
00913 
00914     /* Correlation in the Fourier domain: G*[n]·H[n] */
00915     for(i = 0; i < nx * ny; i++) {
00916         *((float complex *)in_inv + i) = conjf(*((float complex *)ri1 + i)) *
00917         (*((float complex *)ri2+i));
00918     }
00919 
00920     /* Cleanup resources */
00921     fftw_free(in1);
00922     fftw_free(ri1);
00923 
00924     fftw_free(in2);
00925     fftw_free(ri2);
00926 
00927     /* Actually perform the FFT */
00928     fftwnd_one(p_inv, in_inv, ri_inv);
00929 
00930     /* Cleanup FFTW resources */
00931     fftwnd_destroy_plan(p_inv);
00932 
00933     /* Get the module of the inversed signal */
00934     corr = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * nx * ny);
00935     corr_r = (float *) cpl_malloc(sizeof(float) * nx * ny);
00936 
00937     for(i = 0; i < nx * ny; i++) {
00938         *((float complex *)corr + i) = conjf(*((float complex *)ri_inv + i));
00939         *((float complex *)corr + i) *= *((float complex *)ri_inv + i);
00940         *(corr_r + i) = crealf(*((float complex *)corr + i));
00941     }
00942     fftw_free(in_inv);
00943     fftw_free(ri_inv);
00944 
00945     /* Wrap the data onto an image */
00946     corr_image = cpl_image_wrap_float(nx, ny, corr_r);
00947 
00948     /* Cleanup resources */
00949     fftw_free(corr);
00950 
00951     /* Reorganise the pixels to the output */
00952     reorganised = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00953 
00954     image = cpl_image_extract(corr_image, nx / 2 + 1, 1, nx, ny);
00955     cpl_image_copy(reorganised, image, 1, 1);
00956     cpl_image_delete(image);
00957 
00958     image = cpl_image_extract(corr_image, 1, 1, nx / 2, ny);
00959     cpl_image_copy(reorganised, image, nx / 2 + 1, 1);
00960     cpl_image_delete(image);
00961 
00962     cpl_image_unwrap(corr_image);
00963     cpl_free(corr_r);
00964 
00965     corr_image = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00966 
00967     image = cpl_image_extract(reorganised, 1, ny / 2 + 1, nx, ny);
00968     cpl_image_copy(corr_image, image, 1, 1);
00969     cpl_image_delete(image);
00970 
00971     image = cpl_image_extract(reorganised, 1, 1, nx, ny / 2);
00972     cpl_image_copy(corr_image, image, 1, ny / 2 + 1);
00973     cpl_image_delete(image);
00974 
00975     /* Extract a window with the desired shifts */
00976     corr_image_window = cpl_image_extract(corr_image,
00977                                           nx / 2 + 1 - m,
00978                                           ny / 2 + 1 - n,
00979                                           nx / 2 + 1 + m, ny / 2 + 1 + n);
00980 
00981     /* Free and return */
00982     cpl_image_delete(reorganised);
00983     cpl_image_delete(corr_image);
00984 
00985     if(cpl_image_divide_scalar(corr_image_window,
00986                                cpl_image_get_max(corr_image_window))) {
00987         cpl_image_delete(corr_image_window);
00988         return NULL;
00989     }
00990 
00991     return corr_image_window;
00992 }
00993 
00994 /*
00995 static cpl_image       *
00996 irplib_detmon_image_autocorrelate_fftw(const cpl_image * image,
00997                                        const int m, const int n)
00998 {
00999     cpl_image              *input;
01000     cpl_image              *image_padded;
01001 
01002     int                     nx, ny;
01003     int                     i;
01004 
01005     fftwf_plan              p1;
01006     fftwf_complex          *fourier;
01007     fftwf_plan              p_inv;
01008 
01009     cpl_image              *corr_image;
01010     cpl_image              *corr_image_window;
01011     cpl_image              *reorganised;
01012     cpl_image              *image1;
01013     int                     npix;
01014     size_t                  bigsize;
01015     float                  *in;
01016 
01017 
01018     cpl_ensure(image != NULL, CPL_ERROR_NULL_INPUT, NULL);
01019 
01020     cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
01021     cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
01022 
01023     nx = cpl_image_get_size_x(image);
01024     ny = cpl_image_get_size_y(image);
01025 
01026     npix = (nx + 2 * m) * (ny + 2 * n);
01027 
01028 
01029     bigsize = 2 * (npix / 2 + 1);
01030 
01031 
01032     in = (float *) fftw_malloc(sizeof(float) * bigsize);
01033 
01034 
01035     input = cpl_image_cast(image, CPL_TYPE_FLOAT);
01036 
01037     image_padded = cpl_image_wrap_float(nx, ny, in);
01038     cpl_image_copy(image_padded, input, m + 1, n + 1);
01039     cpl_image_delete(input);
01040 
01041 
01042     nx = nx + 2 * m;
01043     ny = ny + 2 * n;
01044 
01045 
01046     fourier = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * nx * ny);
01047     p1 = fftwf_plan_dft_r2c_2d(ny, nx, in, fourier, FFTW_FORWARD);
01048 
01049 
01050     fftwf_execute(p1);
01051 
01052 
01053     fftwf_destroy_plan(p1);
01054     cpl_image_unwrap(image_padded);
01055 
01056 
01057     p_inv = fftwf_plan_dft_c2r_2d(ny, nx, fourier, in, FFTW_BACKWARD);
01058 
01059 
01060     for(i = 0; i < nx * ny; i++) {
01061         fourier[i] = conj(fourier[i]) * fourier[i];
01062     }
01063 
01064 
01065     fftwf_execute(p_inv);
01066 
01067 
01068     fftwf_destroy_plan(p_inv);
01069 
01070     fftwf_free(fourier);
01071 
01072 
01073     corr_image = cpl_image_wrap_float(nx, ny, in);
01074 
01075 
01076     reorganised = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01077 
01078     image1 = cpl_image_extract(corr_image, nx / 2 + 1, 1, nx, ny);
01079     cpl_image_copy(reorganised, image1, 1, 1);
01080     cpl_image_delete(image1);
01081 
01082     image1 = cpl_image_extract(corr_image, 1, 1, nx / 2, ny);
01083     cpl_image_copy(reorganised, image1, nx / 2 + 1, 1);
01084     cpl_image_delete(image1);
01085 
01086     cpl_image_unwrap(corr_image);
01087     fftwf_free(in);
01088 
01089     corr_image = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01090     image1 = cpl_image_extract(reorganised, 1, ny / 2 + 1, nx, ny);
01091     cpl_image_copy(corr_image, image1, 1, 1);
01092     cpl_image_delete(image1);
01093 
01094     image1 = cpl_image_extract(reorganised, 1, 1, nx, ny / 2);
01095     cpl_image_copy(corr_image, image1, 1, ny / 2 + 1);
01096     cpl_image_delete(image1);
01097 
01098 
01099     corr_image_window = cpl_image_extract(corr_image,
01100                                           nx / 2 + 1 - m,
01101                                           ny / 2 + 1 - n,
01102                                           nx / 2 + 1 + m, ny / 2 + 1 + n);
01103 
01104 
01105     cpl_image_delete(reorganised);
01106     cpl_image_delete(corr_image);
01107 
01108     if(cpl_image_divide_scalar(corr_image_window,
01109                                cpl_image_get_max(corr_image_window))) {
01110         cpl_image_delete(corr_image_window);
01111         return NULL;
01112     }
01113 
01114     return corr_image_window;
01115 }
01116 */
01117 
01118 #endif
01119 
01120 /*--------------------------------------------------------------------------*/
01121 
01122 /*
01123  * @brief  Autocorrelate an image with a given range of shifts, using
01124  *         cpl_image_fft()
01125  * @param  input2       Input image
01126  * @param  m            Shift to apply on the x-axis
01127  * @param  n            Shift to apply on the y-axis
01128  * @return              An image of size 2m+1 by 2n+1. Each pixel value
01129  *                      corresponds to the correlation of shift the position
01130  *                      of the pixel. Pixel in the centre (m+1, n+1),
01131  *                      corresponds to shift (0,0). Pixels to the left and
01132  *                      down correspond to negative shifts.
01133  */
01134 
01135 /*--------------------------------------------------------------------------*/
01136 
01137 cpl_image              *
01138 irplib_detmon_autocorrelate(const cpl_image * input2, const int m,
01139                             const int n)
01140 {
01141     cpl_image              *im_re = NULL;
01142     cpl_image              *im_im = NULL;
01143     int                     nx, ny;
01144     cpl_image              *ifft_re = NULL;
01145     cpl_image              *ifft_im = NULL;
01146     cpl_image              *autocorr = NULL;
01147     cpl_image              *autocorr_norm_double = NULL;
01148     cpl_image              *autocorr_norm = NULL;
01149     cpl_image              *reorganised = NULL;
01150     cpl_image              *image = NULL;
01151     int                     p;
01152     cpl_error_code          error;
01153     cpl_image              *input;
01154 
01155     cpl_ensure(input2 != NULL, CPL_ERROR_NULL_INPUT, NULL);
01156 
01157     cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
01158     cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
01159 
01160     nx = cpl_image_get_size_x(input2) + 2 * m;
01161     ny = cpl_image_get_size_y(input2) + 2 * n;
01162 
01163     p = 128;
01164     while(nx > p || ny > p) {
01165         p *= 2;
01166     }
01167 
01168     input = cpl_image_cast(input2, CPL_TYPE_DOUBLE);
01169 
01170     im_re = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01171     error = cpl_image_copy(im_re, input, 1, 1);
01172     cpl_ensure(!error, error, NULL);
01173 
01174     im_im = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01175 
01176     error = cpl_image_fft(im_re, im_im, CPL_FFT_DEFAULT);
01177     cpl_ensure(!error, error, NULL);
01178 
01179     ifft_re = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01180     error = cpl_image_power(im_re, 2);
01181     cpl_ensure(!error, error, NULL);
01182 
01183     error = cpl_image_add(ifft_re, im_re);
01184     cpl_ensure(!error, error, NULL);
01185 
01186     cpl_image_delete(im_re);
01187 
01188     error = cpl_image_power(im_im, 2);
01189     cpl_ensure(!error, error, NULL);
01190 
01191     error = cpl_image_add(ifft_re, im_im);
01192     cpl_ensure(!error, error, NULL);
01193 
01194     cpl_image_delete(im_im);
01195 
01196     ifft_im = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01197 
01198     error = cpl_image_fft(ifft_re, ifft_im, CPL_FFT_INVERSE);
01199     cpl_ensure(!error, error, NULL);
01200 
01201     autocorr = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01202 
01203     error = cpl_image_power(ifft_re, 2);
01204     cpl_ensure(!error, error, NULL);
01205 
01206     error = cpl_image_add(autocorr, ifft_re);
01207     cpl_ensure(!error, error, NULL);
01208 
01209     cpl_image_delete(ifft_re);
01210 
01211     error = cpl_image_power(ifft_im, 2);
01212     cpl_ensure(!error, error, NULL);
01213 
01214     error = cpl_image_add(autocorr, ifft_im);
01215     cpl_ensure(!error, error, NULL);
01216 
01217     cpl_image_delete(ifft_im);
01218 
01219     /* Reorganise the pixels to the output */
01220     reorganised = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01221 
01222     image = cpl_image_extract(autocorr, p / 2 + 1, 1, p, p);
01223     cpl_image_copy(reorganised, image, 1, 1);
01224     cpl_image_delete(image);
01225 
01226     image = cpl_image_extract(autocorr, 1, 1, p / 2, p);
01227     cpl_image_copy(reorganised, image, p / 2 + 1, 1);
01228     cpl_image_delete(image);
01229 
01230     cpl_image_delete(autocorr);
01231 
01232     autocorr = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01233 
01234     image = cpl_image_extract(reorganised, 1, p / 2 + 1, p, p);
01235     cpl_image_copy(autocorr, image, 1, 1);
01236     cpl_image_delete(image);
01237 
01238     image = cpl_image_extract(reorganised, 1, 1, p, p / 2);
01239     cpl_image_copy(autocorr, image, 1, p / 2 + 1);
01240     cpl_image_delete(image);
01241 
01242     cpl_image_delete(reorganised);
01243 
01244     autocorr_norm_double =
01245         cpl_image_extract(autocorr, p / 2 + 1 - m, p / 2 + 1 - n,
01246                           p / 2 + 1 + m, p / 2 + 1 + n);
01247 
01248     cpl_image_delete(autocorr);
01249 
01250     if(cpl_image_divide_scalar(autocorr_norm_double,
01251                                cpl_image_get_max(autocorr_norm_double))) {
01252         cpl_image_delete(autocorr_norm_double);
01253         cpl_ensure(0, cpl_error_get_code(), NULL);
01254     }
01255 
01256 
01257     autocorr_norm = cpl_image_cast(autocorr_norm_double, CPL_TYPE_FLOAT);
01258     cpl_image_delete(autocorr_norm_double);
01259 
01260     cpl_image_delete(input);
01261 
01262     return autocorr_norm;
01263 }
01264 
01265 /*---------------------------------------------------------------------------*/
01276 /*---------------------------------------------------------------------------*/
01277 cpl_error_code
01278 irplib_detmon_lg_fill_parlist_nir_default(cpl_parameterlist * parlist,
01279                                   const char *recipe_name,
01280                                   const char *pipeline_name)
01281 {
01282     const cpl_error_code error = 
01283     irplib_detmon_lg_fill_parlist(parlist, recipe_name, pipeline_name,
01284                   "PTC", /* --method */
01285                   3,   /* --order         */
01286                               3.,        /* --kappa         */
01287                               5,       /* --niter         */
01288                               -1,       /* --llx           */
01289                               -1,       /* --lly           */
01290                               -1,       /* --urx           */
01291                               -1,       /* --ury           */
01292                               10000,    /* --ref_level     */
01293                               "CPL_FALSE",      /* --intermediate  */
01294                               "CPL_FALSE",      /* --autocorr      */
01295                               "CPL_FALSE",      /* --collapse      */
01296                               "CPL_TRUE",       /* --rescale       */
01297                       "CPL_TRUE",/* --pix2pix */
01298                       "CPL_FALSE", /* --bpmbin */
01299                               -1,       /* --filter        */
01300                               26,       /* --m             */
01301                               26,       /* --n             */
01302                       1e-3, /* --tolerance */
01303                       recipe_name, /* --pafname */
01304                               -1,       /* --llx1          */
01305                               -1,       /* --lly1          */
01306                               -1,       /* --urx1          */
01307                               -1,       /* --ury1          */
01308                               -1,       /* --llx2          */
01309                               -1,       /* --lly2          */
01310                               -1,       /* --urx2          */
01311                               -1,       /* --ury2          */
01312                               -1,       /* --llx3          */
01313                               -1,       /* --lly3          */
01314                               -1,       /* --urx3          */
01315                               -1,       /* --ury3          */
01316                               -1,       /* --llx4          */
01317                               -1,       /* --lly4          */
01318                               -1,       /* --urx4          */
01319                               -1,       /* --ury4          */
01320                               -1,       /* --llx5          */
01321                               -1,       /* --lly5          */
01322                               -1,       /* --urx5          */
01323                               -1,       /* --ury5          */
01324                       0,      /* --exts */
01325                           NIR);       /* This is to specify OPT params */
01326 
01327 
01328     cpl_ensure_code(!error, error);
01329 
01330     return cpl_error_get_code();
01331 }
01332 
01333 /*---------------------------------------------------------------------------*/
01344 /*---------------------------------------------------------------------------*/
01345 cpl_error_code
01346 irplib_detmon_lg_fill_parlist_opt_default(cpl_parameterlist * parlist,
01347                                   const char *recipe_name,
01348                                   const char *pipeline_name)
01349 {
01350     const cpl_error_code error = 
01351     irplib_detmon_lg_fill_parlist(parlist, recipe_name, pipeline_name,
01352                   "PTC", /* --method */
01353                   3,   /* --order         */
01354                               3.,        /* --kappa         */
01355                               5,       /* --niter         */
01356                               -1,       /* --llx           */
01357                               -1,       /* --lly           */
01358                               -1,       /* --urx           */
01359                               -1,       /* --ury           */
01360                               10000,    /* --ref_level     */
01361                               "CPL_FALSE",      /* --intermediate  */
01362                               "CPL_FALSE",      /* --autocorr      */
01363                               "CPL_TRUE",      /* --collapse      */
01364                               "CPL_TRUE",       /* --rescale       */
01365                       "CPL_FALSE", /* --pix2pix */
01366                       "CPL_FALSE", /* --bpmbin */
01367                               -1,       /* --filter        */
01368                               26,       /* --m             */
01369                               26,       /* --n             */
01370                       1e-3, /* --tolerance */
01371                       recipe_name, /* --pafname */
01372                               -1,       /* --llx1          */
01373                               -1,       /* --lly1          */
01374                               -1,       /* --urx1          */
01375                               -1,       /* --ury1          */
01376                               -1,       /* --llx2          */
01377                               -1,       /* --lly2          */
01378                               -1,       /* --urx2          */
01379                               -1,       /* --ury2          */
01380                               -1,       /* --llx3          */
01381                               -1,       /* --lly3          */
01382                               -1,       /* --urx3          */
01383                               -1,       /* --ury3          */
01384                               -1,       /* --llx4          */
01385                               -1,       /* --lly4          */
01386                               -1,       /* --urx4          */
01387                               -1,       /* --ury4          */
01388                               -1,       /* --llx5          */
01389                               -1,       /* --lly5          */
01390                               -1,       /* --urx5          */
01391                               -1,       /* --ury5          */
01392                       0,      /* --exts */
01393                           OPT);       /* This is to specify OPT params */
01394 
01395     cpl_ensure_code(!error, error);
01396 
01397     return cpl_error_get_code();
01398 }
01399 
01400 /*---------------------------------------------------------------------------*/
01454 /*---------------------------------------------------------------------------*/
01455 cpl_error_code
01456 irplib_detmon_lg_fill_parlist(cpl_parameterlist * parlist,
01457                           const char *recipe_name, const char *pipeline_name,
01458               const char *method,
01459                           int order,
01460                           double kappa,
01461                           int niter,
01462                           int llx,
01463                           int lly,
01464                           int urx,
01465                           int ury,
01466                           int ref_level,
01467                           const char *intermediate,
01468                           const char *autocorr,
01469                           const char *collapse,
01470                           const char *rescale,
01471                   const char *pix2pix,
01472                   const char *bpmbin,
01473                           int filter,
01474                           int m,
01475                           int n,
01476                   double tolerance,
01477                   const char * pafname,
01478                           int llx1,
01479                           int lly1,
01480                           int urx1,
01481                           int ury1,
01482                           int llx2,
01483                           int lly2,
01484                           int urx2,
01485                           int ury2,
01486                           int llx3,
01487                           int lly3,
01488                           int urx3,
01489                           int ury3,
01490                           int llx4,
01491                           int lly4,
01492                           int urx4,
01493                           int ury4,
01494                   int llx5, int lly5, int urx5, int ury5, int exts,
01495                           cpl_boolean opt_nir)
01496 {
01497     const cpl_error_code error =
01498     irplib_detmon_fill_parlist(parlist, recipe_name, pipeline_name, 21,
01499                    "method",
01500                    "Method to be used when computing GAIN. Methods appliable: <PTC | MED>. By default PTC method will be applied.",
01501                                    "CPL_TYPE_STRING", method,
01502 
01503                                "order",
01504                                "Polynomial order for the fit (Linearity)",
01505                                "CPL_TYPE_INT", order,
01506                                "kappa",
01507                                "Kappa value for the kappa-sigma clipping (Gain)",
01508                                "CPL_TYPE_DOUBLE", kappa,
01509                                "niter",
01510                                "Number of iterations to compute rms (Gain)",
01511                                "CPL_TYPE_INT", niter,
01512                                "llx",
01513                                "x coordinate of the lower-left "
01514                                "point of the region of interest. If not modified, default value will be 1.",
01515                                "CPL_TYPE_INT", llx,
01516                                "lly",
01517                                "y coordinate of the lower-left "
01518                                "point of the region of interest. If not modified, default value will be 1.",
01519                                "CPL_TYPE_INT", lly,
01520                                "urx",
01521                                "x coordinate of the upper-right "
01522                                "point of the region of interest. If not modified, default value will be X dimension of the input image.",
01523                                "CPL_TYPE_INT", urx,
01524                                "ury",
01525                                "y coordinate of the upper-right "
01526                                "point of the region of interest. If not modified, default value will be Y dimension of the input image.",
01527                                "CPL_TYPE_INT", ury,
01528                                "ref_level",
01529                                "User reference level",
01530                                "CPL_TYPE_INT", ref_level,
01531                                "intermediate",
01532                                "De-/Activate intermediate products",
01533                                "CPL_TYPE_BOOL", intermediate,
01534                                "autocorr",
01535                                "De-/Activate the autocorr option",
01536                                "CPL_TYPE_BOOL", autocorr,
01537                                "collapse",
01538                                "De-/Activate the collapse option",
01539                                "CPL_TYPE_BOOL", collapse,
01540                                "rescale",
01541                                "De-/Activate the image rescale option",
01542                                "CPL_TYPE_BOOL", rescale,
01543                    "pix2pix",
01544                                "De-/Activate the computation with pixel to pixel accuracy",
01545                                "CPL_TYPE_BOOL", pix2pix,
01546                    "bpmbin",
01547                                "De-/Activate the binary bpm option",
01548                                "CPL_TYPE_BOOL", bpmbin,
01549                                "m",
01550                                "Maximum x-shift for the autocorr",
01551                                "CPL_TYPE_INT", m,
01552                                "filter",
01553                                "Upper limit of Median flux to be filtered",
01554                                "CPL_TYPE_INT", filter,
01555                                "n",
01556                                "Maximum y-shift for the autocorr",
01557                    "CPL_TYPE_INT", n,
01558                                "tolerance",
01559                                "Tolerance for pair discrimination",
01560                    "CPL_TYPE_DOUBLE", tolerance,
01561                                "pafname",
01562                                "Specific name for PAF file",
01563                    "CPL_TYPE_STRING", pafname,
01564 
01565                                "exts",
01566                                "Activate the multi-exts option",
01567                                "CPL_TYPE_INT", exts);
01568 
01569     /* OPT specific parameters */
01570     if(opt_nir == FALSE) {
01571     const cpl_error_code erroropt = 
01572         irplib_detmon_fill_parlist(parlist, recipe_name, pipeline_name, 20,
01573                                "llx1",
01574                                "x coord of the lower-left point of the first "
01575                                "field used for contamination measurement. If not modified, default value will be 1.",
01576                                "CPL_TYPE_INT", llx1,
01577                                "lly1",
01578                                "y coord of the lower-left point of the first "
01579                                "field used for contamination measurement. If not modified, default value will be 1.",
01580                                "CPL_TYPE_INT", lly1,
01581                                "urx1",
01582                                "x coord of the upper-right point of the first "
01583                                "field used for contamination measurement. If not modified, default value will be X dimension of the input image.",
01584                                "CPL_TYPE_INT", urx1,
01585                                "ury1",
01586                                "y coord of the upper-right point of the first "
01587                                "field used for contamination measurement. If not modified, default value will be Y dimension of the input image.",
01588                                "CPL_TYPE_INT", ury1,
01589                                "llx2",
01590                                "x coord of the lower-left point of the second "
01591                                "field used for contamination measurement. If not modified, default value will be 1.",
01592                                "CPL_TYPE_INT", llx2,
01593                                "lly2",
01594                                "y coord of the lower-left point of the second "
01595                                "field used for contamination measurement. If not modified, default value will be 1.",
01596                                "CPL_TYPE_INT", lly2,
01597                                "urx2",
01598                                "x coord of the upper-right point of the second "
01599                                "field used for contamination measurement. If not modified, default value will be half of the X dimension of the input image.",
01600                                "CPL_TYPE_INT", urx2,
01601                                "ury2",
01602                                "y coord of the upper-right point of the second "
01603                                "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
01604                                "CPL_TYPE_INT", ury2,
01605                                "llx3",
01606                                "x coord of the lower-left point of the third "
01607                                "field used for contamination measurement. If not modified, default value will be 1.",
01608                                "CPL_TYPE_INT", llx3,
01609                                "lly3",
01610                                "y coord of the lower-left point of the third "
01611                                "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
01612                                "CPL_TYPE_INT", lly3,
01613                                "urx3",
01614                                "x coord of the upper-right point of the third "
01615                                "field used for contamination measurement. If not modified, default value will be half of X dimension of the image.",
01616                                "CPL_TYPE_INT", urx3,
01617                                "ury3",
01618                                "y coord of the upper-right point of the third "
01619                                "field used for contamination measurement. If not modified, default value will be Y dimension of the image.",
01620                                "CPL_TYPE_INT", ury3,
01621                                "llx4",
01622                                "x coord of the lower-left point of the fourth "
01623                                "field used for contamination measurement. If not modified, default value will be half of X dimension of the image.",
01624                                "CPL_TYPE_INT", llx4,
01625                                "lly4",
01626                                "y coord of the lower-left point of the fourth "
01627                                "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
01628                                "CPL_TYPE_INT", lly4,
01629                                "urx4",
01630                                "x coord of the upper-right point of the fourth "
01631                                "field used for contamination measurement. If not modified, default value will be X dimension of the image.",
01632                                "CPL_TYPE_INT", urx4,
01633                                "ury4",
01634                                "y coord of the upper-right point of the fourth "
01635                                "field used for contamination measurement. If not modified, default value will be Y dimension of the input image.",
01636                                "CPL_TYPE_INT", ury4,
01637                                "llx5",
01638                                "x coord of the lower-left point of the fifth "
01639                                "field used for contamination measurement. If not modified, default value will be half of the X dimension of the input image.",
01640                                "CPL_TYPE_INT", llx5,
01641                                "lly5",
01642                                "y coord of the lower-left point of the fifth "
01643                                "field used for contamination measurement. If not modified, default value will be 1.",
01644                                "CPL_TYPE_INT", lly5,
01645                                "urx5",
01646                                "x coord of the upper-right point of the fifth "
01647                                "field used for contamination measurement. If not modified, default value will be X dimension of the image.",
01648                                "CPL_TYPE_INT", urx5,
01649                                "ury5",
01650                                "y coord of the upper-right point of the fifth "
01651                                "field used for contamination measurement. If not modified, default value will be half of Y dimension of the input image.",
01652                    "CPL_TYPE_INT", ury5);
01653     cpl_ensure_code(!erroropt, erroropt);
01654     }
01655 
01656     cpl_ensure_code(!error, error);
01657 
01658     return cpl_error_get_code();
01659 }
01660 
01661 /*---------------------------------------------------------------------------*/
01670 /*---------------------------------------------------------------------------*/
01671 static cpl_error_code
01672 irplib_detmon_lg_retrieve_parlist(const char              * pipeline_name,
01673                   const char              * recipe_name,
01674                   const cpl_parameterlist * parlist,
01675                   cpl_boolean               opt_nir)
01676 {
01677 
01678     char                   * par_name;
01679     cpl_parameter          * par;
01680 
01681     /* --method */
01682     par_name = cpl_sprintf("%s.%s.method", pipeline_name, recipe_name);
01683     assert(par_name != NULL);
01684     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01685     detmon_lg_config.method = cpl_parameter_get_string(par);
01686     cpl_free(par_name);
01687 
01688     /* --order */
01689     detmon_lg_config.order =
01690         irplib_detmon_retrieve_par_int("order", pipeline_name, recipe_name,
01691                                    parlist);
01692 
01693     /* --kappa */
01694     detmon_lg_config.kappa =
01695         irplib_detmon_retrieve_par_double("kappa", pipeline_name, recipe_name,
01696                                    parlist);
01697 
01698     /* --niter */
01699     detmon_lg_config.niter =
01700         irplib_detmon_retrieve_par_int("niter", pipeline_name, recipe_name,
01701                                    parlist);
01702 
01703     /* --llx */
01704     detmon_lg_config.llx =
01705         irplib_detmon_retrieve_par_int("llx", pipeline_name, recipe_name,
01706                                    parlist);
01707 
01708     /* --lly */
01709     detmon_lg_config.lly =
01710         irplib_detmon_retrieve_par_int("lly", pipeline_name, recipe_name,
01711                                    parlist);
01712 
01713     /* --urx */
01714     detmon_lg_config.urx =
01715         irplib_detmon_retrieve_par_int("urx", pipeline_name, recipe_name,
01716                                    parlist);
01717 
01718     /* --ury */
01719     detmon_lg_config.ury =
01720         irplib_detmon_retrieve_par_int("ury", pipeline_name, recipe_name,
01721                                    parlist);
01722 
01723     /* --ref_level */
01724     detmon_lg_config.ref_level =
01725         irplib_detmon_retrieve_par_int("ref_level", pipeline_name, recipe_name,
01726                                    parlist);
01727 
01728     /* --intermediate */
01729     par_name =
01730         cpl_sprintf("%s.%s.intermediate", pipeline_name, recipe_name);
01731     assert(par_name != NULL);
01732     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01733     detmon_lg_config.intermediate = cpl_parameter_get_bool(par);
01734     cpl_free(par_name);
01735  
01736     /* --autocorr */
01737     par_name = cpl_sprintf("%s.%s.autocorr", pipeline_name, recipe_name);
01738     assert(par_name != NULL);
01739     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01740     detmon_lg_config.autocorr = cpl_parameter_get_bool(par);
01741     cpl_free(par_name);
01742 
01743     /* --collapse */
01744     par_name = cpl_sprintf("%s.%s.collapse", pipeline_name, recipe_name);
01745     assert(par_name != NULL);
01746     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01747     detmon_lg_config.collapse = cpl_parameter_get_bool(par);
01748     cpl_free(par_name);
01749 
01750     /* --rescale */
01751     par_name = cpl_sprintf("%s.%s.rescale", pipeline_name, recipe_name);
01752     assert(par_name != NULL);
01753     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01754     detmon_lg_config.rescale = cpl_parameter_get_bool(par);
01755     cpl_free(par_name);
01756 
01757     /* --pix2pix */
01758     par_name = cpl_sprintf("%s.%s.pix2pix", pipeline_name, recipe_name);
01759     assert(par_name != NULL);
01760     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01761     detmon_lg_config.pix2pix = cpl_parameter_get_bool(par);
01762     cpl_free(par_name);
01763 
01764     /* --bpmbin */
01765     par_name = cpl_sprintf("%s.%s.bpmbin", pipeline_name, recipe_name);
01766     assert(par_name != NULL);
01767     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01768     detmon_lg_config.bpmbin = cpl_parameter_get_bool(par);
01769     cpl_free(par_name);
01770 
01771     /* --filter */
01772     detmon_lg_config.filter =
01773         irplib_detmon_retrieve_par_int("filter", pipeline_name,
01774                                    recipe_name, parlist);
01775 
01776     /* --m */
01777     detmon_lg_config.m =
01778         irplib_detmon_retrieve_par_int("m", pipeline_name, recipe_name, parlist);
01779 
01780     /* --n */
01781     detmon_lg_config.n =
01782         irplib_detmon_retrieve_par_int("n", pipeline_name, recipe_name, parlist);
01783 
01784     /* --tolerance */
01785     par_name = cpl_sprintf("%s.%s.tolerance", pipeline_name, recipe_name);
01786     assert(par_name != NULL);
01787     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01788     detmon_lg_config.tolerance = cpl_parameter_get_double(par);
01789     cpl_free(par_name);
01790 
01791     /* --pafname */
01792     par_name = cpl_sprintf("%s.%s.pafname", pipeline_name, recipe_name);
01793     assert(par_name != NULL);
01794     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01795     detmon_lg_config.pafname = cpl_parameter_get_string(par);
01796     cpl_free(par_name);
01797 
01798     if(opt_nir == OPT) {
01799     /* --llx1 */
01800     detmon_lg_config.llx1 =
01801         irplib_detmon_retrieve_par_int("llx1", pipeline_name, recipe_name,
01802                        parlist);
01803 
01804     /* --lly1 */
01805     detmon_lg_config.lly1 =
01806         irplib_detmon_retrieve_par_int("lly1", pipeline_name, recipe_name,
01807                        parlist);
01808 
01809     /* --urx1 */
01810     detmon_lg_config.urx1 =
01811         irplib_detmon_retrieve_par_int("urx1", pipeline_name, recipe_name,
01812                        parlist);
01813 
01814     /* --ury1 */
01815     detmon_lg_config.ury1 =
01816         irplib_detmon_retrieve_par_int("ury1", pipeline_name, recipe_name,
01817                        parlist);
01818 
01819     /* --llx2 */
01820     detmon_lg_config.llx2 =
01821         irplib_detmon_retrieve_par_int("llx2", pipeline_name, recipe_name,
01822                        parlist);
01823 
01824     /* --lly2 */
01825     detmon_lg_config.lly2 =
01826         irplib_detmon_retrieve_par_int("lly2", pipeline_name, recipe_name,
01827                        parlist);
01828 
01829     /* --urx2 */
01830     detmon_lg_config.urx2 =
01831         irplib_detmon_retrieve_par_int("urx2", pipeline_name, recipe_name,
01832                        parlist);
01833 
01834     /* --ury2 */
01835     detmon_lg_config.ury2 =
01836         irplib_detmon_retrieve_par_int("ury2", pipeline_name, recipe_name,
01837                        parlist);
01838 
01839     /* --llx3 */
01840     detmon_lg_config.llx3 =
01841         irplib_detmon_retrieve_par_int("llx3", pipeline_name, recipe_name,
01842                        parlist);
01843 
01844     /* --lly3 */
01845     detmon_lg_config.lly3 =
01846         irplib_detmon_retrieve_par_int("lly3", pipeline_name, recipe_name,
01847                        parlist);
01848 
01849     /* --urx3 */
01850     detmon_lg_config.urx3 =
01851         irplib_detmon_retrieve_par_int("urx3", pipeline_name, recipe_name,
01852                        parlist);
01853 
01854     /* --ury3 */
01855     detmon_lg_config.ury3 =
01856         irplib_detmon_retrieve_par_int("ury3", pipeline_name, recipe_name,
01857                        parlist);
01858 
01859     /* --llx4 */
01860     detmon_lg_config.llx4 =
01861         irplib_detmon_retrieve_par_int("llx4", pipeline_name, recipe_name,
01862                        parlist);
01863 
01864     /* --lly4 */
01865     detmon_lg_config.lly4 =
01866         irplib_detmon_retrieve_par_int("lly4", pipeline_name, recipe_name,
01867                        parlist);
01868 
01869     /* --urx4 */
01870     detmon_lg_config.urx4 =
01871         irplib_detmon_retrieve_par_int("urx4", pipeline_name, recipe_name,
01872                        parlist);
01873 
01874     /* --ury4 */
01875     detmon_lg_config.ury4 =
01876         irplib_detmon_retrieve_par_int("ury4", pipeline_name, recipe_name,
01877                        parlist);
01878 
01879     /* --llx5 */
01880     detmon_lg_config.llx5 =
01881         irplib_detmon_retrieve_par_int("llx5", pipeline_name, recipe_name,
01882                        parlist);
01883 
01884     /* --lly5 */
01885     detmon_lg_config.lly5 =
01886         irplib_detmon_retrieve_par_int("lly5", pipeline_name, recipe_name,
01887                        parlist);
01888 
01889     /* --urx5 */
01890     detmon_lg_config.urx5 =
01891         irplib_detmon_retrieve_par_int("urx5", pipeline_name, recipe_name,
01892                        parlist);
01893 
01894     /* --ury5 */
01895     detmon_lg_config.ury5 =
01896         irplib_detmon_retrieve_par_int("ury5", pipeline_name, recipe_name,
01897                        parlist);
01898     }
01899 
01900     /* --exts */
01901     detmon_lg_config.exts =
01902         irplib_detmon_retrieve_par_int("exts", pipeline_name, recipe_name,
01903                                    parlist);
01904 
01905     if(cpl_error_get_code()) {
01906         cpl_msg_error(cpl_func, "Failed to retrieve the input parameters");
01907         cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
01908     }
01909 
01910 
01911     return cpl_error_get_code();
01912 }
01913 
01914 /*---------------------------------------------------------------------------*/
01920 /*---------------------------------------------------------------------------*/
01921 static cpl_error_code
01922 irplib_detmon_lg_check_defaults(const cpl_image * reference)
01923 {
01924     const int               nx = cpl_image_get_size_x(reference);
01925     const int               ny = cpl_image_get_size_y(reference);
01926 
01927     if(detmon_lg_config.llx == -1)
01928         detmon_lg_config.llx = 1;
01929     if(detmon_lg_config.lly == -1)
01930         detmon_lg_config.lly = 1;
01931     if(detmon_lg_config.urx == -1)
01932         detmon_lg_config.urx = nx;
01933     if(detmon_lg_config.ury == -1)
01934         detmon_lg_config.ury = ny;
01935 
01936     if(detmon_lg_config.llx1 == -1)
01937         detmon_lg_config.llx1 = 1;
01938     if(detmon_lg_config.lly1 == -1)
01939         detmon_lg_config.lly1 = 1;
01940     if(detmon_lg_config.urx1 == -1)
01941         detmon_lg_config.urx1 = nx;
01942     if(detmon_lg_config.ury1 == -1)
01943         detmon_lg_config.ury1 = ny;
01944 
01945     if(detmon_lg_config.llx2 == -1)
01946         detmon_lg_config.llx2 = 1;
01947     if(detmon_lg_config.lly2 == -1)
01948         detmon_lg_config.lly2 = 1;
01949     if(detmon_lg_config.urx2 == -1)
01950         detmon_lg_config.urx2 = nx / 2;
01951     if(detmon_lg_config.ury2 == -1)
01952         detmon_lg_config.ury2 = ny / 2;
01953 
01954     if(detmon_lg_config.llx3 == -1)
01955         detmon_lg_config.llx3 = 1;
01956     if(detmon_lg_config.lly3 == -1)
01957         detmon_lg_config.lly3 = ny / 2;
01958     if(detmon_lg_config.urx3 == -1)
01959         detmon_lg_config.urx3 = nx / 2;
01960     if(detmon_lg_config.ury3 == -1)
01961         detmon_lg_config.ury3 = ny;
01962 
01963     if(detmon_lg_config.llx4 == -1)
01964         detmon_lg_config.llx4 = nx / 2;
01965     if(detmon_lg_config.lly4 == -1)
01966         detmon_lg_config.lly4 = ny / 2;
01967     if(detmon_lg_config.urx4 == -1)
01968         detmon_lg_config.urx4 = nx;
01969     if(detmon_lg_config.ury4 == -1)
01970         detmon_lg_config.ury4 = ny;
01971 
01972     if(detmon_lg_config.llx5 == -1)
01973         detmon_lg_config.llx5 = nx / 2;
01974     if(detmon_lg_config.lly5 == -1)
01975         detmon_lg_config.lly5 = 1;
01976     if(detmon_lg_config.urx5 == -1)
01977         detmon_lg_config.urx5 = nx;
01978     if(detmon_lg_config.ury5 == -1)
01979         detmon_lg_config.ury5 = ny / 2;
01980 
01981     if(detmon_lg_config.intermediate == TRUE) {
01982         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.");
01983         detmon_lg_config.autocorr = TRUE;
01984     }
01985 
01986 #ifndef HAVE_SFFTW
01987     if(detmon_lg_config.autocorr == TRUE)
01988         cpl_msg_warning(cpl_func,
01989                         "You don't have FFTW installed in your system."
01990                         " Please note that use of --autocorr option without it "
01991                         "will result in an execution time close to 10 minutes.");
01992 
01993 #endif
01994 
01995     detmon_lg_config.lamp_stability = 0.0;
01996 
01997     detmon_lg_config.lamp_ok = FALSE;
01998 
01999     detmon_lg_config.cr = 0.0;
02000 
02001     return cpl_error_get_code();
02002 }
02003 
02004 /*---------------------------------------------------------------------------*/
02015 /*---------------------------------------------------------------------------*/
02016 static cpl_error_code
02017 irplib_detmon_lg_split_onoff(const cpl_frameset * cur_fset,
02018                              cpl_frameset * cur_fset_on,
02019                              cpl_frameset * cur_fset_off,
02020                              const char *tag_on,
02021                              const char *tag_off)
02022 {
02023     int                     nframes;
02024     int                     i;
02025 
02026     const cpl_frame * first;
02027     const cpl_frame * second;
02028 
02029     const char * first_tag;
02030     const char * second_tag;
02031 
02032     cpl_frame * cur_frame_dup = NULL;
02033 
02034     skip_if((first   = cpl_frameset_get_first_const(cur_fset)) == NULL);
02035     skip_if((second  = cpl_frameset_get_next_const (cur_fset)) == NULL);
02036 
02037     skip_if((first_tag  = cpl_frame_get_tag(first))  == NULL);
02038     skip_if((second_tag = cpl_frame_get_tag(second)) == NULL);
02039 
02040 #if 0
02041     if (opt_nir == OPT &&
02042     ((!strcmp(first_tag, tag_on ) && !strcmp(second_tag, tag_off)) ||
02043      (!strcmp(first_tag, tag_off) && !strcmp(second_tag, tag_on )))) {
02044     detmon_lg_config.lamp_ok = TRUE;
02045     }
02046 #endif
02047 
02048     nframes = cpl_frameset_get_size(cur_fset);
02049     for(i = detmon_lg_config.lamp_ok ? 2 : 0; i < nframes; i++) {
02050         const cpl_frame * cur_frame =
02051         cpl_frameset_get_frame_const(cur_fset, i);
02052     char            * tag;
02053 
02054         /* Duplication is required for insertion to a different frameset */
02055         cur_frame_dup = cpl_frame_duplicate(cur_frame);
02056         tag = (char *) cpl_frame_get_tag(cur_frame_dup);
02057 
02058         /* Insertion in the corresponding sub-frameset */
02059         if(!strcmp(tag, tag_on)) {
02060             skip_if(cpl_frameset_insert(cur_fset_on, cur_frame_dup));
02061         } else if(!strcmp(tag, tag_off)) {
02062             skip_if(cpl_frameset_insert(cur_fset_off, cur_frame_dup));
02063         } else {
02064             cpl_frame_delete(cur_frame_dup);
02065         cur_frame_dup = NULL;
02066         }
02067     }
02068     cur_frame_dup = NULL;
02069 
02070     end_skip;
02071 
02072     cpl_frame_delete(cur_frame_dup);
02073 
02074     return cpl_error_get_code();
02075 }
02076 
02077 /*--------------------------------------------------------------------------*/
02101 /*--------------------------------------------------------------------------*/
02102 
02103 static cpl_error_code
02104 irplib_detmon_lg_reduce(const cpl_frameset * set_on,
02105                         const cpl_frameset * set_off,
02106                         int *selection_on,
02107                         int *selection_off,
02108                         int nsets_extracted,
02109                         cpl_imagelist ** coeffs_ptr,
02110                         cpl_table * gain_table,
02111                         cpl_table * linear_table,
02112                         cpl_image ** bpm_ptr,
02113                         cpl_imagelist * autocorr_images,
02114                         cpl_imagelist * diff_flats,
02115                         cpl_propertylist * qclist,
02116          int                    (* load_fset) (const cpl_frameset *,
02117                                cpl_type,
02118                                                cpl_imagelist *),
02119             const cpl_boolean opt_nir,
02120                         int whichext)
02121 {
02122     int                     i;
02123     cpl_imagelist         * linearity_inputs = NULL;
02124     cpl_imagelist         * opt_offs = NULL;
02125     int                     nsets;
02126     cpl_propertylist      * reflist = NULL;
02127     int dit_nskip=0;
02128     /* Test entries */
02129     cpl_ensure(set_on != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
02130     cpl_ensure(set_off != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
02131 
02132     nsets = cpl_frameset_get_size(set_on) / 2;
02133 
02134     if(detmon_lg_config.collapse) {
02135         /*
02136          * When the 'collapse' option is used, there are no OFF pairs. We
02137          * construct a pair with the 2 first raw OFF frames, which will be
02138          * passed for each DIT value, to maintain the same API in the function
02139          * irplib_detmon_gain_table_fill_row().
02140          */
02141         const cpl_frame        *first = cpl_frameset_get_first_const(set_off);
02142         cpl_frame              *dup_first = cpl_frame_duplicate(first);
02143 
02144         const cpl_frame        *second = cpl_frameset_get_next_const(set_off);
02145         cpl_frame              *dup_second = cpl_frame_duplicate(second);
02146 
02147         cpl_frameset           *raw_offs = cpl_frameset_new();
02148 
02149         cpl_frameset_insert(raw_offs, dup_first);
02150         cpl_frameset_insert(raw_offs, dup_second);
02151 
02152     opt_offs = cpl_imagelist_load_frameset(raw_offs, CPL_TYPE_FLOAT,
02153                            0, whichext);
02154 
02155         cpl_frameset_delete(raw_offs);
02156 
02157     }
02158 
02159     skip_if(irplib_detmon_lg_reduce_init(gain_table,
02160                      linear_table,
02161                      &linearity_inputs,
02162                                  opt_nir));
02163 
02164     if (!strcmp(detmon_lg_config.method, "PTC")) 
02165     cpl_msg_warning(cpl_func, "PTC method incompatible with lamp stability computation");
02166     else if(!detmon_lg_config.collapse)
02167     skip_if(irplib_detmon_lg_lamp_stab(set_on, set_off,
02168                        opt_nir, whichext));
02169 
02170     /* Unselect all rows, to select only invalid ones */
02171     skip_if(cpl_table_unselect_all(linear_table));
02172     skip_if(cpl_table_unselect_all(gain_table));
02173 
02174     /* Loop on every DIT value */
02175  
02176     for(i = 0; i < nsets /*_extracted*/; i++) {
02177        skip_if(irplib_detmon_lg_reduce_dit(set_on, selection_on, i,&dit_nskip,
02178                         nsets_extracted, set_off,
02179                         selection_off, linear_table,
02180                         gain_table, linearity_inputs,
02181                         qclist, opt_nir,
02182                         autocorr_images, diff_flats,
02183                         opt_offs, load_fset, whichext));
02184     }
02185 
02186     skip_if(irplib_detmon_add_adl_column(linear_table, opt_nir));
02187 
02188     /*
02189      * Removal of rows corresponding to frames above --filter threshold.
02190      * See calls to cpl_table_select_row() in irplib_detmon_lg_reduce_dit().
02191      */
02192     skip_if(cpl_table_erase_selected(gain_table));
02193     skip_if(cpl_table_erase_selected(linear_table));
02194 
02195     reflist = cpl_propertylist_new();
02196     skip_if(cpl_propertylist_append_bool(reflist, "ADU", FALSE));
02197     skip_if(cpl_table_sort(gain_table, reflist));
02198 
02199 
02200     /*
02201      * --Final reduction--
02202      * The following call to irplib_detmon_lg_reduce_all() makes the
02203      * computations which are over all posible DIT values.
02204      */
02205     skip_if(irplib_detmon_lg_reduce_all(linear_table,
02206                     qclist, coeffs_ptr, bpm_ptr,
02207                     linearity_inputs,
02208                     gain_table, whichext, opt_nir));
02209 
02210     end_skip;
02211 
02212     cpl_imagelist_delete(linearity_inputs);
02213     cpl_imagelist_delete(opt_offs);
02214     cpl_propertylist_delete(reflist);
02215 
02216     return cpl_error_get_code();
02217 }
02218 
02219 /*--------------------------------------------------------------------------*/
02227 /*--------------------------------------------------------------------------*/
02228 static cpl_error_code
02229 irplib_detmon_lg_lamp_stab(const cpl_frameset * lamps,
02230                const cpl_frameset * darks,
02231                            cpl_boolean          opt_nir,
02232                            int                  whichext)
02233 {
02234     /*
02235      * NOTE:
02236      * Most of this code is copied (and modified) from
02237      * isaac_img_detlin_load(), in isaac_img_detlin.c v.1.25
02238      */
02239 
02240     int                     nb_lamps;
02241     cpl_vector          *   selection = NULL;
02242     cpl_propertylist    *   plist;
02243     double                  dit_lamp, dit_dark;
02244     int                     dit_stab;
02245     cpl_imagelist       *   lamps_data = NULL;
02246     cpl_imagelist       *   darks_data = NULL;
02247     double              *   stab_levels = NULL;
02248     int                     i, j;
02249     double              *   ditvals = NULL;
02250     int                     last_stab = 0; /* Avoid false uninit warning */
02251 
02252     /* Check that there are as many lamp as darks */
02253     cpl_ensure_code((nb_lamps = cpl_frameset_get_size(lamps)) >= 3,
02254             CPL_ERROR_ILLEGAL_INPUT);
02255     cpl_ensure_code(cpl_frameset_get_size(darks) == nb_lamps,
02256                 CPL_ERROR_ILLEGAL_INPUT);
02257 
02258     /* Check out that they have consistent integration times */
02259     cpl_msg_info(__func__, "Checking DIT consistency");
02260     selection = cpl_vector_new(nb_lamps);
02261     ditvals = cpl_malloc(nb_lamps * sizeof(double));
02262     dit_stab = 0;
02263     for (i = 0; i < nb_lamps; i++) {
02264     const cpl_frame           * c_lamp;
02265     const cpl_frame           * c_dark;
02266         /* Check if ok */
02267         skip_if (cpl_error_get_code());
02268 
02269         /* DIT from LAMP */
02270         c_lamp = cpl_frameset_get_frame_const(lamps, i);
02271         plist = cpl_propertylist_load(cpl_frame_get_filename(c_lamp), 0);
02272     if(opt_nir)
02273         dit_lamp = (double)irplib_pfits_get_dit(plist);
02274     else
02275         dit_lamp = (double)irplib_pfits_get_dit_opt(plist);
02276         cpl_propertylist_delete(plist);
02277         skip_if (cpl_error_get_code());
02278 
02279         /* DIT from DARK */
02280         c_dark = cpl_frameset_get_frame_const(darks, i);
02281         plist  = cpl_propertylist_load(cpl_frame_get_filename(c_dark), 0);
02282     if(opt_nir)
02283         dit_dark = (double)irplib_pfits_get_dit(plist);
02284     else
02285         dit_dark = (double)irplib_pfits_get_dit_opt(plist);
02286         cpl_propertylist_delete(plist);
02287         skip_if (cpl_error_get_code());
02288 
02289         /* Check consistency */
02290         if (fabs(dit_dark-dit_lamp) > 1e-3) {
02291             cpl_msg_error(__func__, "DIT not consistent between LAMP and DARK");
02292         /* FIXME: Should an error code be set here? */
02293         skip_if(1);
02294         }
02295         ditvals[i] = dit_lamp;
02296         /* Set selection */
02297         if (i==0) {
02298             cpl_vector_set(selection, i, -1.0);
02299             dit_stab ++;
02300         last_stab = 0;
02301         } else {
02302         /*
02303          * The second condition is to make sure that frames taken into
02304          * account for lamp stability are not consecutive.
02305          */
02306             if (fabs(dit_lamp - ditvals[0]) < 1e-5 && i - last_stab > 3) {
02307                 cpl_vector_set(selection, i, -1.0);
02308                 dit_stab ++;
02309         last_stab = i;
02310             } else {
02311                 cpl_vector_set(selection, i, 1.0);
02312             }
02313         }
02314     }
02315 
02316     /* Check if there are enough DITs for stability check */
02317     if (dit_stab < 2) {
02318         cpl_msg_info(__func__, "Not enough frames for stability check");
02319     } else {
02320 
02321     /* Load the data and compute lamp-dark */
02322     cpl_msg_info(__func__, "Compute the differences lamp - dark");
02323     lamps_data = cpl_imagelist_load_frameset(lamps, CPL_TYPE_FLOAT, 1,
02324                          whichext);
02325     darks_data = cpl_imagelist_load_frameset(darks, CPL_TYPE_FLOAT, 1,
02326                          whichext);
02327     skip_if(cpl_imagelist_subtract(lamps_data,darks_data));
02328     
02329     /* Check the lamp stability */
02330     cpl_msg_info(__func__, "Check the lamp stability");
02331     stab_levels = cpl_malloc(dit_stab * sizeof(double));
02332     j = 0;
02333     for (i=0; i<nb_lamps; i++) {
02334         if (cpl_vector_get(selection, i) < 0) {
02335         stab_levels[j] = 
02336             cpl_image_get_mean(cpl_imagelist_get(lamps_data, i));
02337         j++;
02338         }
02339     }
02340 
02341     /* Compute the lamp stability */
02342     for (i=1; i<dit_stab; i++) {
02343         if ((fabs(stab_levels[i]-stab_levels[0]) / stab_levels[0]) >
02344                 detmon_lg_config.lamp_stability) 
02345         detmon_lg_config.lamp_stability = 
02346             fabs(stab_levels[i]-stab_levels[0]) / stab_levels[0];
02347     }
02348 
02349     
02350     /* Check the lamp stability */
02351     if (detmon_lg_config.lamp_stability > 0.01) {
02352             cpl_msg_warning(__func__, 
02353                 "level difference too high - proceed anyway");
02354     }
02355     }
02356     end_skip;
02357 
02358     cpl_free(ditvals);
02359     cpl_vector_delete(selection);
02360     cpl_imagelist_delete(lamps_data);
02361     cpl_imagelist_delete(darks_data);
02362     cpl_free(stab_levels);
02363 
02364     return cpl_error_get_code();
02365 }
02366 
02367 /*--------------------------------------------------------------------------*/
02395 /*--------------------------------------------------------------------------*/
02396 static cpl_error_code
02397 irplib_detmon_lg_reduce_dit(const cpl_frameset * set_on,
02398                 int * selection_on,
02399                 const int dit_nb,
02400                             int * dit_nskip,
02401                 int nsets_extracted,
02402                 const cpl_frameset * set_off,
02403                 int * selection_off,
02404                 cpl_table * linear_table,
02405                 cpl_table * gain_table,
02406                 cpl_imagelist * linearity_inputs,
02407                 cpl_propertylist * qclist,
02408                 cpl_boolean opt_nir,
02409                 cpl_imagelist * autocorr_images,
02410                 cpl_imagelist * diff_flats,
02411                             cpl_imagelist * opt_offs,
02412                 int                    (* load_fset) (const cpl_frameset *,
02413                                cpl_type,
02414                                   cpl_imagelist *),
02415                             int whichext)
02416 {
02417     cpl_frameset          * pair_on = NULL;
02418     cpl_frameset          * pair_off = NULL;
02419     cpl_imagelist         * ons = NULL;
02420     cpl_imagelist         * offs = NULL;
02421     int                     with_equal_dit = 0;
02422     cpl_boolean             follow = CPL_TRUE;
02423     cpl_imagelist *         masterl = NULL;
02424     unsigned mode = detmon_lg_config.autocorr ? IRPLIB_GAIN_WITH_AUTOCORR : 0;
02425     double c_dit;
02426     const char * filename;
02427     cpl_propertylist * plist = NULL;
02428     
02429     mode = detmon_lg_config.collapse ?
02430     mode | IRPLIB_GAIN_COLLAPSE    | IRPLIB_LIN_COLLAPSE:
02431     mode | IRPLIB_GAIN_NO_COLLAPSE | IRPLIB_LIN_NO_COLLAPSE;
02432     mode = detmon_lg_config.pix2pix  ? 
02433     mode | IRPLIB_LIN_PIX2PIX : mode;
02434     mode = opt_nir  ?
02435     mode | IRPLIB_GAIN_NIR | IRPLIB_LIN_NIR :
02436     mode | IRPLIB_GAIN_OPT | IRPLIB_LIN_OPT ;
02437 
02438 
02439     /* ON pair extraction */
02440     skip_if(irplib_detmon_pair_extract(set_on, selection_on, dit_nb, nsets_extracted, &with_equal_dit, 1, &pair_on));
02441 
02442  
02443     /* Load the ON images */
02444     if (load_fset != NULL) {
02445     ons = cpl_imagelist_new();
02446     (*load_fset)(pair_on, CPL_TYPE_FLOAT, ons);
02447     } else {
02448     ons = cpl_imagelist_load_frameset(pair_on, CPL_TYPE_FLOAT, 1,whichext);
02449     }
02450     skip_if(ons == NULL);
02451 
02452     if(detmon_lg_config.filter > 0) {
02453     double med1 =
02454         cpl_image_get_median_window(cpl_imagelist_get(ons, 0),
02455                     detmon_lg_config.llx,
02456                     detmon_lg_config.lly,
02457                     detmon_lg_config.urx,
02458                     detmon_lg_config.ury);
02459     double med2 = 
02460         cpl_image_get_median_window(cpl_imagelist_get(ons, 1),
02461                     detmon_lg_config.llx,
02462                     detmon_lg_config.lly,
02463                     detmon_lg_config.urx,
02464                     detmon_lg_config.ury);
02465     if ( med1 > (double)detmon_lg_config.filter ||
02466          med2 > (double)detmon_lg_config.filter) {
02467         follow = CPL_FALSE;
02468         cpl_table_select_row(gain_table,   dit_nb);
02469         cpl_table_select_row(linear_table, dit_nb);
02470             (*dit_nskip)++;
02471         cpl_msg_warning(cpl_func, "Frames of EXPTIME nb %d "
02472                 "will not be taken into account for computation "
02473                 "as they are above --filter threshold", dit_nb);
02474     }
02475     }
02476 
02477     if (follow || detmon_lg_config.filter < 0) {
02478 
02479     /*
02480      * If the --collapse option is not activated by the user, the OFF 
02481      * sub-frameset is also supposed to be organized into pairs and,
02482      * therefore, processed as the ON sub-frameset.
02483      */
02484     if(!detmon_lg_config.collapse) {
02485 
02486         if (!strcmp(detmon_lg_config.method, "MED") || 
02487         cpl_frameset_get_size(set_on) == cpl_frameset_get_size(set_off))
02488 
02489         skip_if(irplib_detmon_pair_extract(set_off, selection_off,
02490                            dit_nb, nsets_extracted,
02491                            &with_equal_dit, 0,
02492                            &pair_off));
02493         else 
02494         skip_if(irplib_detmon_single_extract(set_off, selection_off,
02495                              dit_nb, nsets_extracted,
02496                              &with_equal_dit, 0,
02497                              &pair_off));
02498            
02499 
02500         /* Load the OFF images */
02501         if (load_fset != NULL) {
02502         offs = cpl_imagelist_new();
02503         (*load_fset)(pair_off, CPL_TYPE_FLOAT, offs);
02504         } else {
02505         offs = cpl_imagelist_load_frameset(pair_off, CPL_TYPE_FLOAT,
02506                                            1, whichext);
02507         }
02508         skip_if(offs == NULL);
02509         skip_if(cpl_error_get_code());
02510     } else {
02511         /*
02512          * The master bias is required only for 
02513          * linearity computation in the OPT domain
02514          */
02515         cpl_image * collapse;
02516         masterl = cpl_imagelist_load_frameset(set_off, CPL_TYPE_FLOAT,
02517                                           1, whichext);
02518         skip_if(masterl == NULL);
02519         skip_if(cpl_error_get_code());
02520 
02521         collapse = cpl_imagelist_collapse_create(masterl);
02522         skip_if(collapse == NULL);
02523         skip_if(cpl_imagelist_set(masterl, collapse, 0));
02524 
02525         /* Any extra error checking needed here? */
02526         offs = (cpl_imagelist *)masterl;
02527     }
02528 
02529     /* Rescaling */
02530     if(detmon_lg_config.rescale) {
02531         skip_if(irplib_detmon_lg_rescale(ons));
02532         if (!detmon_lg_config.collapse &&
02533         !strcmp(detmon_lg_config.method, "MED"))
02534         skip_if(irplib_detmon_lg_rescale(offs));
02535     }
02536         
02537     /* DIT or EXPTIME value extraction */
02538 
02539     filename = 
02540         cpl_frame_get_filename(cpl_frameset_get_first_const(pair_on));
02541     skip_if ((plist = cpl_propertylist_load(filename, 0)) == NULL);
02542 
02543     if(opt_nir == NIR) {
02544         c_dit = irplib_pfits_get_dit(plist);
02545     } else {
02546         c_dit = irplib_pfits_get_exptime(plist);
02547     }
02548 
02549     /* Linearity reduction */
02550  
02551     skip_if(irplib_detmon_lin_table_fill_row(linear_table, c_dit,
02552                          linearity_inputs, ons, offs,
02553                          detmon_lg_config.llx,
02554                          detmon_lg_config.lly,
02555                          detmon_lg_config.urx,
02556                          detmon_lg_config.ury,
02557                          dit_nb, *dit_nskip, mode));
02558 
02559     if(opt_nir == OPT && dit_nb == nsets_extracted / 2) {
02560         irplib_detmon_opt_contamination(ons, offs, mode, qclist);
02561     }
02562 
02563     /*
02564      * --GAIN part for each DIT value--
02565      * The following call to irplib_detmon_gain_table_fill_row() fills
02566      * in the row nb i
02567      * of the GAIN table (output) and of the FIT table (by-product to be
02568      * used later for the polynomial computation of the GAIN)
02569      */
02570     if(detmon_lg_config.collapse) {
02571         offs = (cpl_imagelist *) opt_offs;
02572     }
02573 
02574     cpl_msg_info(cpl_func, "Computing GAIN for EXPTIME value nb %d",
02575              dit_nb + 1);
02576 
02577     /* In case PTC is applied, this is allowed */
02578     if(cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE && dit_nb == 0) {
02579         cpl_table_erase_column(gain_table, "MEAN_OFF1");
02580         cpl_table_erase_column(gain_table, "MEAN_OFF2");
02581         cpl_table_erase_column(gain_table, "SIG_OFF_DIF");
02582         cpl_table_erase_column(gain_table, "GAIN");
02583         cpl_table_erase_column(gain_table, "GAIN_CORR");
02584         cpl_table_new_column(gain_table, "MEAN_OFF", CPL_TYPE_DOUBLE);
02585     }
02586 
02587     skip_if(irplib_detmon_gain_table_fill_row(gain_table, c_dit,
02588                           autocorr_images,
02589                           diff_flats, ons, offs,
02590                                                   detmon_lg_config.kappa,
02591                                                   detmon_lg_config.niter,
02592                                                   detmon_lg_config.llx,
02593                                                   detmon_lg_config.lly,
02594                                                   detmon_lg_config.urx,
02595                                                   detmon_lg_config.ury,
02596                           detmon_lg_config.m,
02597                                                   detmon_lg_config.n,
02598                                                   dit_nb, mode));
02599     }
02600 
02601     end_skip;
02602 
02603     cpl_frameset_delete(pair_on);
02604     cpl_imagelist_delete(ons);
02605 
02606     if(!detmon_lg_config.collapse ) {
02607     cpl_imagelist_delete(offs);
02608     }
02609 
02610     if(!detmon_lg_config.collapse) {
02611     cpl_frameset_delete(pair_off);
02612     }
02613 
02614     if(detmon_lg_config.collapse) {
02615     cpl_imagelist_delete(masterl);
02616     }
02617 
02618     cpl_propertylist_delete(plist);
02619 
02620     return cpl_error_get_code();
02621 }
02622 
02623 /*---------------------------------------------------------------------------*/
02629 /*---------------------------------------------------------------------------*/
02630 static cpl_error_code
02631 irplib_detmon_add_adl_column(cpl_table * table,
02632                              cpl_boolean opt_nir)
02633 {
02634     cpl_error_code          error;
02635     double                  mean_med_dit;
02636     double                 *dits;
02637 
02638     cpl_ensure_code(table != NULL, CPL_ERROR_NULL_INPUT);
02639 
02640     mean_med_dit = cpl_table_get_column_mean(table, "MED_DIT");
02641     if (opt_nir == OPT) 
02642     dits = cpl_table_get_data_double(table, "EXPTIME");
02643     else
02644     dits = cpl_table_get_data_double(table, "DIT");
02645 
02646     error = cpl_table_copy_data_double(table, "ADL", dits);
02647     cpl_ensure_code(!error, error);
02648     error = cpl_table_multiply_scalar(table, "ADL", mean_med_dit);
02649     cpl_ensure_code(!error, error);
02650 
02651     return cpl_error_get_code();
02652 }
02653 
02654 /*---------------------------------------------------------------------------*/
02662 /*---------------------------------------------------------------------------*/
02663 static cpl_error_code
02664 irplib_detmon_lg_reduce_init(cpl_table * gain_table,
02665                              cpl_table * linear_table,
02666                              cpl_imagelist ** linearity_inputs,
02667                              const cpl_boolean opt_nir)
02668 {
02669     skip_if(irplib_detmon_gain_table_create(gain_table, opt_nir));
02670     skip_if(irplib_detmon_lin_table_create(linear_table, opt_nir));
02671 
02672     if(detmon_lg_config.pix2pix) {
02673     *linearity_inputs = cpl_imagelist_new();
02674     skip_if(*linearity_inputs == NULL);
02675     }
02676 
02677     end_skip;
02678 
02679     return cpl_error_get_code();
02680 }
02681 
02682 /*--------------------------------------------------------------------------*/
02688 /*--------------------------------------------------------------------------*/
02689 static double
02690 irplib_pfits_get_dit(const cpl_propertylist * plist)
02691 {
02692     double                  dit;
02693 
02694     dit = cpl_propertylist_get_double(plist, "ESO DET DIT");
02695 
02696     if(cpl_error_get_code() != CPL_ERROR_NONE) {
02697         cpl_msg_error(cpl_func, cpl_error_get_where());
02698     } 
02699     return dit;
02700 }
02701 
02702 /*--------------------------------------------------------------------------*/
02708 /*--------------------------------------------------------------------------*/
02709 static double
02710 irplib_pfits_get_dit_opt(const cpl_propertylist * plist)
02711 {
02712     double                  dit;
02713 
02714     dit = cpl_propertylist_get_double(plist, "ESO DET WIN1 UIT1");
02715 
02716     if(cpl_error_get_code() != CPL_ERROR_NONE) {
02717         cpl_msg_error(cpl_func, cpl_error_get_where());
02718     } 
02719     return dit;
02720 }
02721 
02722 /*---------------------------------------------------------------------------*/
02754 /*---------------------------------------------------------------------------*/
02755 static cpl_error_code
02756 irplib_detmon_gain_table_fill_row(cpl_table * gain_table, double c_dit,
02757                   cpl_imagelist * autocorr_images,
02758                   cpl_imagelist * diff_flats,
02759                   const cpl_imagelist * ons,
02760                                   const cpl_imagelist * offs,
02761                                   double kappa, int nclip,
02762                                   int llx, int lly, int urx, int ury,
02763                                   int m, int n,
02764                   const int pos, unsigned mode)
02765 {
02766     const cpl_image        *image;
02767     double                  std = 0;
02768     cpl_image              *on_dif = NULL;
02769     cpl_image              *off_dif = NULL;
02770     double                  avg_on1, avg_on2;
02771     double                  avg_off1, avg_off2;
02772     double                  avg_on_dif, sig_on_dif;
02773     double                  avg_off_dif, sig_off_dif;
02774     double                  double_adu, autocorr, gain, gain_corr;
02775     double                  sigma, sigma_corr;
02776 
02777     if (mode & IRPLIB_GAIN_NIR) {
02778     cpl_table_set(gain_table, "DIT", pos, c_dit);
02779     } else if (mode & IRPLIB_GAIN_OPT) {
02780     cpl_table_set(gain_table, "EXPTIME", pos, c_dit);
02781     } else {
02782     cpl_msg_error(cpl_func, "Mandatory mode (OPT or NIR) not provided");
02783     skip_if(1);
02784     }
02785 
02786     skip_if((image = cpl_imagelist_get_const(ons, 0)) == NULL);
02787     skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
02788                                          nclip, 1e-5, &avg_on1, &std));
02789     skip_if(cpl_table_set_double(gain_table, "MEAN_ON1", pos, avg_on1));
02790 
02791     skip_if((image = cpl_imagelist_get_const(ons, 1)) == NULL);
02792     skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
02793                      nclip, 1e-5, &avg_on2, &std));
02794     skip_if(cpl_table_set_double(gain_table, "MEAN_ON2", pos, avg_on2));
02795 
02796     on_dif =
02797     cpl_image_subtract_create(cpl_imagelist_get_const(ons, 0),
02798                   cpl_imagelist_get_const(ons, 1));
02799     skip_if(on_dif == NULL);
02800 
02801     skip_if(irplib_ksigma_clip(on_dif, llx, lly, urx, ury, kappa,
02802                      nclip, 1e-5,
02803                                          &avg_on_dif, &sig_on_dif));
02804     skip_if(cpl_table_set_double(gain_table, "SIG_ON_DIF", pos, sig_on_dif));
02805 
02806 
02807 
02808     if(mode & IRPLIB_GAIN_WITH_AUTOCORR) {
02809       if (diff_flats) {
02810     cpl_image * diff = cpl_image_duplicate(on_dif);
02811         skip_if(cpl_imagelist_set(diff_flats, diff, pos));
02812       }
02813       if (autocorr_images) {
02814         cpl_image * corr;
02815         autocorr = irplib_detmon_autocorr_factor(on_dif, &corr, m, n);
02816         skip_if(cpl_imagelist_set(autocorr_images, corr, pos));
02817       } else {
02818         autocorr = irplib_detmon_autocorr_factor(on_dif, NULL, m, n);
02819       }
02820     } else {
02821         autocorr = 1.0;
02822     }
02823 
02824     if (cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE) {
02825 
02826         skip_if(irplib_ksigma_clip(cpl_imagelist_get_const(offs, 0),
02827                    llx, lly, urx, ury, kappa, nclip,
02828                    1e-5, &avg_off1, &std));
02829         skip_if(cpl_table_set_double(gain_table, "MEAN_OFF", pos, avg_off1));
02830 
02831     } else if (mode & IRPLIB_GAIN_NO_COLLAPSE || 
02832          ( pos == 0 && mode & IRPLIB_GAIN_COLLAPSE )) {
02833         skip_if(irplib_ksigma_clip(cpl_imagelist_get_const(offs, 0),
02834                                              llx, lly, urx, ury, kappa, nclip,
02835                                              1e-5, &avg_off1, &std));
02836         skip_if(cpl_table_set_double(gain_table, "MEAN_OFF1", pos, avg_off1));
02837         skip_if(irplib_ksigma_clip(cpl_imagelist_get_const(offs, 1),
02838                                              llx, lly, urx, ury, kappa, nclip,
02839                          1e-5, &avg_off2, &std));
02840         skip_if(cpl_table_set_double(gain_table, "MEAN_OFF2", pos, avg_off2));
02841         off_dif =
02842             cpl_image_subtract_create(cpl_imagelist_get_const(offs, 0),
02843                                       cpl_imagelist_get_const(offs, 1));
02844     skip_if(off_dif == NULL);
02845         skip_if(irplib_ksigma_clip(off_dif, llx, lly, urx, ury,
02846                                              kappa, nclip, 1e-5,
02847                          &avg_off_dif, &sig_off_dif));
02848         skip_if(cpl_table_set_double(gain_table, "SIG_OFF_DIF",
02849                      pos, sig_off_dif));
02850     } else if (pos > 0 && mode & IRPLIB_GAIN_COLLAPSE){
02851         int status;
02852         avg_off1 = cpl_table_get_double(gain_table, "MEAN_OFF1", 0, &status);
02853         skip_if(cpl_table_set_double(gain_table, "MEAN_OFF1", pos, avg_off1));
02854     avg_off2 = cpl_table_get_double(gain_table, "MEAN_OFF2", 0, &status);
02855         skip_if(cpl_table_set_double(gain_table, "MEAN_OFF2", pos, avg_off2));
02856     sig_off_dif = cpl_table_get_double(gain_table, "SIG_OFF_DIF",
02857                                            0, &status);
02858         skip_if(cpl_table_set_double(gain_table, "SIG_OFF_DIF",
02859                                      pos, sig_off_dif));
02860     }
02861 
02862     if (cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE)
02863     double_adu = (avg_on1 + avg_on2) - 2 * avg_off1;
02864     else {
02865     double_adu = (avg_on1 + avg_on2) - (avg_off1 + avg_off2);
02866 
02867     sigma = (sig_on_dif * sig_on_dif) - (sig_off_dif * sig_off_dif);
02868 
02869     sigma_corr = autocorr * sigma;
02870 
02871     gain = double_adu / sigma;
02872     
02873     gain_corr = double_adu / sigma_corr;
02874 
02875     skip_if(cpl_table_set_double(gain_table, "GAIN", pos, gain));
02876     skip_if(cpl_table_set_double(gain_table, "GAIN_CORR", pos, gain_corr));
02877     }
02878 
02879     skip_if(cpl_table_set_double(gain_table, "AUTOCORR", pos, autocorr));
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, "Y_FIT_CORR",
02886                  pos, sig_on_dif * sig_on_dif));
02887     skip_if(cpl_table_set_double(gain_table, "X_FIT", pos, double_adu));
02888     skip_if(cpl_table_set_double(gain_table, "X_FIT_CORR",
02889                  pos, double_adu / autocorr));
02890 
02891     end_skip;
02892     
02893     cpl_image_delete(on_dif);
02894     cpl_image_delete(off_dif);
02895 
02896     return cpl_error_get_code();
02897 }
02898 
02899 /*--------------------------------------------------------------------------*/
02906 /*--------------------------------------------------------------------------*/
02907 
02908 static cpl_image       *
02909 irplib_detmon_bpixs(const cpl_imagelist * coeffs, 
02910                     cpl_boolean bpmbin, 
02911                     const double kappa, 
02912                     int *nbpixs)
02913 {
02914     int                     size;
02915     int                     i;
02916     const cpl_image        *first= cpl_imagelist_get_const(coeffs, 0);
02917     cpl_stats              *stats;
02918     double                  cur_mean;
02919     double                  cur_stdev;
02920     double                  lo_cut;
02921     double                  hi_cut;
02922     cpl_mask               *cur_mask;
02923     cpl_mask               *mask = cpl_mask_new(cpl_image_get_size_x(first),
02924                                             cpl_image_get_size_y(first));
02925     cpl_image              *cur_image = NULL;
02926     cpl_image              *bpm = NULL; /* Avoid false uninit warning */
02927     double                  p;
02928 
02929     size = cpl_imagelist_get_size(coeffs);
02930 
02931     if(!bpmbin) {
02932     bpm = cpl_image_new(cpl_image_get_size_x(first),
02933                 cpl_image_get_size_y(first),
02934                 CPL_TYPE_INT);
02935     }
02936 
02937 
02938     for(i = 0; i < size; i++) {
02939         const cpl_image * cur_coeff = cpl_imagelist_get_const(coeffs, i);
02940 
02941         stats = cpl_stats_new_from_image(cur_coeff,
02942                                          CPL_STATS_MEAN | CPL_STATS_STDEV);
02943         cur_mean = cpl_stats_get_mean(stats);
02944         cur_stdev = cpl_stats_get_stdev(stats);
02945 
02946         lo_cut = cur_mean - kappa * cur_stdev;
02947         hi_cut = cur_mean + kappa * cur_stdev;
02948 
02949         cur_mask = cpl_mask_threshold_image_create(cur_coeff, lo_cut, hi_cut);
02950         cpl_mask_not(cur_mask);
02951 
02952     if(!bpmbin) {
02953         cur_image = cpl_image_new_from_mask(cur_mask);
02954         p = pow(2, i);
02955         cpl_image_power(cur_image, p);
02956         cpl_image_add(bpm, cur_image);
02957         cpl_image_delete(cur_image);
02958     }
02959 
02960     cpl_mask_or(mask, cur_mask);
02961 
02962         cpl_mask_delete(cur_mask);
02963         cpl_stats_delete(stats);
02964     }
02965 
02966     if(bpmbin) {
02967     bpm = cpl_image_new_from_mask(mask);
02968     }
02969 
02970     *nbpixs += cpl_mask_count(mask);
02971 
02972     cpl_mask_delete(mask);
02973 
02974     return bpm;
02975 }
02976 
02977 /*---------------------------------------------------------------------------*/
02989 /*---------------------------------------------------------------------------*/
02990 
02991 static double
02992 irplib_detmon_autocorr_factor(const cpl_image * image, 
02993                               cpl_image ** autocorr_image, int m, int n)
02994 {
02995     cpl_image * mycorr_image;
02996     double      autocorr;
02997 
02998 #ifdef HAVE_SFFTW
02999     mycorr_image = irplib_detmon_image_correlate(image, image, m, n);
03000 #else
03001     mycorr_image = irplib_detmon_autocorrelate(image, m, n);
03002 #endif
03003     if(mycorr_image == NULL) {
03004         return -1;
03005     }
03006 
03007     cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), -1);
03008 
03009     autocorr = cpl_image_get_flux(mycorr_image);
03010 
03011     if (autocorr_image) *autocorr_image = mycorr_image;
03012     else cpl_image_delete(mycorr_image);
03013 
03014     return autocorr;
03015 }
03016 
03017 /*---------------------------------------------------------------------------*/
03048 /*---------------------------------------------------------------------------*/
03049 static cpl_error_code
03050 irplib_detmon_lg_save(const cpl_parameterlist * parlist,
03051                       cpl_frameset * frameset,
03052                       const char *recipe_name,
03053                       const char *pipeline_name,
03054                       const char *pafregexp,
03055               const cpl_propertylist  * pro_lintbl,
03056               const cpl_propertylist  * pro_gaintbl,
03057               const cpl_propertylist  * pro_coeffscube,
03058               const cpl_propertylist  * pro_bpm,
03059               const cpl_propertylist  * pro_corr,
03060               const cpl_propertylist  * pro_diff,
03061                       const char *package,
03062                       cpl_imagelist * coeffs,
03063                       cpl_table * gain_table,
03064                       cpl_table * linear_table,
03065                       cpl_image * bpms,
03066                       cpl_imagelist * autocorr_images,
03067                       cpl_imagelist * diff_flats,
03068                       cpl_propertylist * qclist,
03069                       const int flag_sets,
03070                       const int which_set,
03071                       const cpl_frameset * usedframes,
03072                       int whichext)
03073 {
03074 
03075     cpl_frame              *ref_frame;
03076     cpl_propertylist       *plist = NULL;
03077     cpl_propertylist       *mainplist = NULL;
03078     char                   *name_o = NULL; /* Avoid (false) uninit warning */
03079     int                     nb_images;
03080     int                     i;
03081     cpl_error_code          error;
03082     cpl_propertylist *      xplist = NULL;
03083     cpl_propertylist *      paflist = NULL;
03084 
03085     cpl_propertylist  * mypro_lintbl     =
03086     cpl_propertylist_duplicate(pro_lintbl);
03087     cpl_propertylist  * mypro_gaintbl    =
03088     cpl_propertylist_duplicate(pro_gaintbl);
03089     cpl_propertylist  * mypro_coeffscube =
03090     cpl_propertylist_duplicate(pro_coeffscube);
03091     cpl_propertylist  * mypro_bpm        =
03092     cpl_propertylist_duplicate(pro_bpm);
03093     cpl_propertylist  * mypro_corr       =
03094     cpl_propertylist_duplicate(pro_corr);
03095     cpl_propertylist  * mypro_diff       =
03096     cpl_propertylist_duplicate(pro_diff);
03097 
03098     /* Extract extension headers if multi-extension */
03099     if (detmon_lg_config.exts < 0) {
03100         const char * filename =
03101             cpl_frame_get_filename(cpl_frameset_get_first(frameset));
03102 
03103 
03104             xplist = cpl_propertylist_load_regexp(filename, whichext,
03105                                                      "ESO DET|EXTNAME", 0);
03106 
03107             /* Workaround for DFS05341 before CPL 4.2 */
03108             cpl_propertylist_erase_regexp(xplist, "DET CHIP LIVE", 0) ;
03109             /* End of Workaround */
03110 
03111             skip_if(cpl_propertylist_append(xplist, qclist));
03112     }
03113 
03114     /* This is only used later for PAF and temporarily for COEFFS_CUBE
03115        (see if defined)*/
03116     /* Get FITS header from reference file */
03117     ref_frame = cpl_frameset_get_first(frameset);
03118 
03119     skip_if((mainplist =
03120     cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
03121                   0)) == NULL);
03122 
03123     /*******************************/
03124     /*  Write the LINEARITY TABLE  */
03125     /*******************************/
03126 
03127     /* Set the file name for the table */
03128     if(!flag_sets) {
03129         name_o = cpl_sprintf("%s_linearity_table.fits", recipe_name);
03130         assert(name_o != NULL);
03131     } else {
03132         name_o =
03133             cpl_sprintf("%s_linearity_table_set%02d.fits", recipe_name,
03134                            which_set);
03135         assert(name_o != NULL);
03136     }
03137 
03138     if (detmon_lg_config.exts >= 0) {
03139         /* Save the table */
03140 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 8, 0)
03141     cpl_propertylist_append(mypro_lintbl, qclist);
03142 
03143         skip_if(cpl_dfs_save_table(frameset, NULL,parlist, usedframes, NULL,linear_table,
03144                    NULL, recipe_name,
03145                    mypro_lintbl, NULL, package, name_o));
03146 #else
03147     const char * procatg_lintbl = 
03148         cpl_propertylist_get_string(mypro_lintbl, CPL_DFS_PRO_CATG);
03149 
03150     cpl_propertylist_append(mypro_lintbl, qclist);
03151 
03152         skip_if(cpl_dfs_save_table(frameset, parlist, usedframes, linear_table,
03153                    NULL, recipe_name, procatg_lintbl,
03154                    mypro_lintbl, NULL, package, name_o));
03155 #endif
03156     } else {
03157     if(whichext == 1) {
03158         /* Save the 1. extension table */
03159 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 8, 0)
03160         skip_if(cpl_dfs_save_table(frameset,NULL, parlist, usedframes, NULL, linear_table,
03161                        xplist, recipe_name, mypro_lintbl,
03162                   NULL, package, name_o));
03163 #else
03164         const char * procatg_lintbl = 
03165         cpl_propertylist_get_string(mypro_lintbl, CPL_DFS_PRO_CATG);
03166 
03167         skip_if(cpl_dfs_save_table(frameset, parlist, usedframes, linear_table,
03168                        xplist, recipe_name, procatg_lintbl, mypro_lintbl,
03169                   NULL, package, name_o));
03170 #endif
03171 
03172     } else {
03173             skip_if(cpl_table_save(linear_table, NULL, xplist, name_o,
03174                                CPL_IO_EXTEND));
03175     }
03176     }
03177 
03178     /* Free */
03179     cpl_free(name_o);
03180     name_o = NULL;
03181 
03182     /**************************/
03183     /*  Write the GAIN TABLE  */
03184     /**************************/
03185 
03186     /* Set the file name for the table */
03187     if(!flag_sets) {
03188         name_o = cpl_sprintf("%s_gain_table.fits", recipe_name);
03189         assert(name_o != NULL);
03190     } else {
03191         name_o =
03192             cpl_sprintf("%s_gain_table_set%02d.fits", recipe_name,
03193                            which_set);
03194         assert(name_o != NULL);
03195     }
03196 
03197     if (detmon_lg_config.exts >= 0) {
03198         /* Save the table */
03199 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 8, 0)
03200     cpl_propertylist_append(mypro_gaintbl, qclist);
03201 
03202         skip_if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL,gain_table,
03203                               NULL, recipe_name, mypro_gaintbl,
03204                               NULL, package, name_o));
03205 #else
03206     const char * procatg_gaintbl = 
03207         cpl_propertylist_get_string(mypro_gaintbl, CPL_DFS_PRO_CATG);
03208 
03209     cpl_propertylist_append(mypro_gaintbl, qclist);
03210 
03211         skip_if(cpl_dfs_save_table(frameset, parlist, usedframes, gain_table,
03212                               NULL, recipe_name, procatg_gaintbl, mypro_gaintbl,
03213                               NULL, package, name_o));
03214 #endif
03215     } else {
03216     if(whichext == 1) {
03217 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 8, 0)
03218         /* Save the 1. extension table */
03219         skip_if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL, gain_table,
03220                   xplist, recipe_name, mypro_gaintbl,
03221                   NULL, package, name_o));
03222 #else
03223         const char * procatg_gaintbl = 
03224         cpl_propertylist_get_string(mypro_gaintbl, CPL_DFS_PRO_CATG);
03225 
03226         skip_if(cpl_dfs_save_table(frameset, parlist, usedframes, gain_table,
03227                   xplist, recipe_name, procatg_gaintbl, mypro_gaintbl,
03228                   NULL, package, name_o));
03229 #endif
03230     } else {
03231             skip_if(cpl_table_save(gain_table, NULL, xplist, name_o,
03232                                CPL_IO_EXTEND));
03233         }
03234     }
03235 
03236     /* Free */
03237     cpl_free(name_o);
03238     name_o = NULL;
03239 
03240     if(detmon_lg_config.pix2pix) {
03241 
03242     /***************************/
03243     /*  Write the COEFFS FITS  */
03244     /***************************/
03245 
03246     /* Set the file name for the data cube */
03247     if(!flag_sets) {
03248         name_o =
03249         cpl_sprintf("%s_coeffs_cube.fits", recipe_name);
03250         assert(name_o != NULL);
03251     } else {
03252         name_o =
03253         cpl_sprintf("%s_coeffs_cube_set%02d.fits",
03254                 recipe_name, which_set);
03255         assert(name_o != NULL);
03256     }
03257 
03258     /* Save the imagelist */
03259     if(detmon_lg_config.exts >= 0) {
03260 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 8, 0)
03261         cpl_propertylist_append(mypro_coeffscube, qclist);
03262 
03263         skip_if(cpl_dfs_save_imagelist
03264            (frameset, NULL, parlist, usedframes, NULL,coeffs, CPL_BPP_IEEE_FLOAT,
03265         recipe_name, mypro_coeffscube, NULL, package,
03266         name_o));
03267 #else
03268         const char * procatg_coeffscube = 
03269         cpl_propertylist_get_string(mypro_coeffscube, CPL_DFS_PRO_CATG);
03270         cpl_propertylist_append(mypro_coeffscube, qclist);
03271 
03272         skip_if(cpl_dfs_save_imagelist
03273            (frameset, parlist, usedframes, coeffs, CPL_BPP_IEEE_FLOAT,
03274         recipe_name, procatg_coeffscube, mypro_coeffscube, NULL, package,
03275         name_o));
03276 #endif
03277     } else {
03278         if(whichext == 1) {
03279 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 8, 0)
03280         skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
03281                                            NULL, NULL,
03282                       CPL_BPP_IEEE_FLOAT, recipe_name,
03283                       mypro_coeffscube, NULL,
03284                       package, name_o));
03285 #else
03286         const char * procatg_coeffscube = 
03287             cpl_propertylist_get_string(mypro_coeffscube, CPL_DFS_PRO_CATG);
03288 
03289         skip_if(cpl_dfs_save_image(frameset, parlist, usedframes, NULL,
03290                       CPL_BPP_IEEE_FLOAT, recipe_name,
03291                       procatg_coeffscube, mypro_coeffscube, NULL,
03292                       package, name_o));
03293 #endif
03294         skip_if(cpl_imagelist_save(coeffs,
03295                    name_o, CPL_BPP_IEEE_FLOAT, xplist,
03296                    CPL_IO_EXTEND));
03297         } else {
03298         skip_if(cpl_imagelist_save(coeffs,
03299                    name_o, CPL_BPP_IEEE_FLOAT, xplist,
03300                    CPL_IO_EXTEND));
03301         }
03302     }
03303     cpl_free(name_o);
03304         name_o = NULL;
03305 
03306         /*******************************/
03307         /*  Write the BAD PIXEL MAP    */
03308         /*******************************/
03309 
03310         /* Set the file name for the bpm */
03311         if(!flag_sets) {
03312             name_o = cpl_sprintf("%s_bpm.fits", recipe_name);
03313             assert(name_o != NULL);
03314         } else {
03315             name_o =
03316                 cpl_sprintf("%s_bpm_set%02d.fits", recipe_name, which_set);
03317             assert(name_o != NULL);
03318         }
03319 
03320         /* Save the image */
03321         if(detmon_lg_config.exts >= 0) {
03322 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 8, 0)
03323         cpl_propertylist_append(mypro_bpm, qclist);
03324 
03325             skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL, bpms,
03326                                   CPL_BPP_IEEE_FLOAT, recipe_name,
03327                                   mypro_bpm, NULL, package,
03328                                   name_o));
03329 #else
03330         const char * procatg_bpm = 
03331         cpl_propertylist_get_string(mypro_bpm, CPL_DFS_PRO_CATG);
03332 
03333         cpl_propertylist_append(mypro_bpm, qclist);
03334 
03335             skip_if(cpl_dfs_save_image(frameset, parlist, usedframes, bpms,
03336                                   CPL_BPP_IEEE_FLOAT, recipe_name,
03337                                   procatg_bpm, mypro_bpm, NULL, package,
03338                                   name_o));
03339 #endif
03340         } else {
03341         if (whichext == 1) {
03342 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 8, 0)
03343         skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,NULL,  NULL,
03344                       CPL_BPP_IEEE_FLOAT, recipe_name,
03345                       mypro_bpm, NULL, package,
03346                       name_o));
03347 #else
03348         const char * procatg_bpm = 
03349             cpl_propertylist_get_string(mypro_bpm, CPL_DFS_PRO_CATG);
03350 
03351         skip_if(cpl_dfs_save_image(frameset, parlist, usedframes, NULL,
03352                       CPL_BPP_IEEE_FLOAT, recipe_name,
03353                       procatg_bpm, mypro_bpm, NULL, package,
03354                       name_o));
03355 #endif
03356                 skip_if(cpl_image_save(bpms, name_o, CPL_BPP_IEEE_FLOAT,
03357                                    xplist, CPL_IO_EXTEND));
03358         } else {
03359                 skip_if(cpl_image_save(bpms, name_o, CPL_BPP_IEEE_FLOAT,
03360                                    xplist, CPL_IO_EXTEND));
03361             }
03362         }
03363         /* Free */
03364         cpl_free(name_o);
03365         name_o = NULL;
03366 
03367     } /* End of if(pix2pix) */
03368 
03369     if(detmon_lg_config.intermediate) {
03370         /******************************/
03371         /*  Write the AUTOCORRS FITS  */
03372         /******************************/
03373 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE < CPL_VERSION(4, 8, 0)
03374     const char * procatg_corr = 
03375         cpl_propertylist_get_string(mypro_corr, CPL_DFS_PRO_CATG);
03376 
03377     const char * procatg_diff = 
03378         cpl_propertylist_get_string(mypro_diff, CPL_DFS_PRO_CATG);
03379 #endif
03380 
03381         int                     j;
03382 
03383         nb_images = cpl_imagelist_get_size(autocorr_images);
03384         cpl_ensure_code(nb_images > 0, CPL_ERROR_DATA_NOT_FOUND);
03385 
03386     if(detmon_lg_config.exts >= 0)
03387         cpl_propertylist_append(mypro_corr, qclist);
03388 
03389         for(i = 0; i < nb_images; i++) {
03390             /* Set the file name for each image */
03391             if(!flag_sets) {
03392                 name_o =
03393                     cpl_sprintf("%s_autocorr_%d.fits", recipe_name, i);
03394                 assert(name_o != NULL);
03395             } else {
03396                 name_o =
03397                     cpl_sprintf("%s_autocorr_%d_set%02d.fits",
03398                                    recipe_name, i, which_set);
03399                 assert(name_o != NULL);
03400             }
03401 
03402 
03403             /* Save the image */
03404             if(detmon_lg_config.exts >= 0) {
03405 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 8, 0)
03406                 skip_if(cpl_dfs_save_image
03407                    (frameset, NULL, parlist, usedframes, NULL,
03408                     cpl_imagelist_get(autocorr_images, i), CPL_BPP_IEEE_FLOAT,
03409                     recipe_name, mypro_corr, NULL, package,
03410                     name_o));
03411 #else
03412                 skip_if(cpl_dfs_save_image
03413                    (frameset, parlist, usedframes,
03414                     cpl_imagelist_get(autocorr_images, i), CPL_BPP_IEEE_FLOAT,
03415                     recipe_name, procatg_corr, mypro_corr, NULL, package,
03416                     name_o));
03417 #endif
03418             } else {
03419         if(whichext == 1) {
03420 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 8, 0)
03421             skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL,NULL,
03422                       CPL_BPP_IEEE_FLOAT, recipe_name,
03423                       mypro_corr, NULL,
03424                       package, name_o));
03425 #else
03426             skip_if(cpl_dfs_save_image(frameset, parlist, usedframes, NULL,
03427                       CPL_BPP_IEEE_FLOAT, recipe_name,
03428                       procatg_corr, mypro_corr, NULL,
03429                       package, name_o));
03430 #endif
03431                     skip_if(cpl_image_save(cpl_imagelist_get(autocorr_images, i),
03432                                        name_o, CPL_BPP_IEEE_FLOAT, xplist,
03433                                        CPL_IO_EXTEND));
03434         } else {
03435                     skip_if(cpl_image_save(cpl_imagelist_get(autocorr_images, i),
03436                                        name_o, CPL_BPP_IEEE_FLOAT, xplist,
03437                                        CPL_IO_EXTEND));
03438                 }
03439             }
03440             cpl_free(name_o);
03441             name_o = NULL;
03442         }
03443 
03444         /***************************/
03445         /*   Write the DIFFS FITS  */
03446         /***************************/
03447 
03448     if(detmon_lg_config.exts >= 0)
03449         cpl_propertylist_append(mypro_diff, qclist);
03450 
03451         for(i = 0; i < nb_images; i++) {
03452             /* Set the file name for each image */
03453             if(!flag_sets) {
03454                 name_o =
03455                     cpl_sprintf("%s_diff_flat_%d.fits", recipe_name, i);
03456                 assert(name_o != NULL);
03457             } else {
03458                 name_o =
03459                     cpl_sprintf("%s_diff_flat_%d_set%02d.fits",
03460                                    recipe_name, i, which_set);
03461                 assert(name_o != NULL);
03462             }
03463 
03464 
03465             /* Save the image */
03466             if(detmon_lg_config.exts >= 0) {
03467 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 8, 0)
03468                 skip_if(cpl_dfs_save_image
03469                    (frameset, NULL, parlist, usedframes, NULL, 
03470                     cpl_imagelist_get(diff_flats, i), CPL_BPP_IEEE_FLOAT,
03471                     recipe_name, mypro_diff, NULL, package,
03472                     name_o));
03473 #else
03474                 skip_if(cpl_dfs_save_image
03475                    (frameset, parlist, usedframes,
03476                     cpl_imagelist_get(diff_flats, i), CPL_BPP_IEEE_FLOAT,
03477                     recipe_name, procatg_diff, mypro_diff, NULL, package,
03478                     name_o));
03479 #endif
03480             } else {
03481 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 8, 0)
03482                 skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL, NULL,
03483                                       CPL_BPP_IEEE_FLOAT, recipe_name,
03484                                       mypro_diff, NULL,
03485                                       package, name_o));
03486 #else
03487                 skip_if(cpl_dfs_save_image(frameset, parlist, usedframes, NULL,
03488                                       CPL_BPP_IEEE_FLOAT, recipe_name,
03489                                       procatg_diff, mypro_diff, NULL,
03490                                       package, name_o));
03491 #endif
03492                 for(j = 0; j < detmon_lg_config.nb_extensions; j++) {
03493                     skip_if(cpl_image_save(cpl_imagelist_get(diff_flats, i),
03494                                        name_o, CPL_BPP_IEEE_FLOAT, xplist,
03495                                        CPL_IO_EXTEND));
03496                 }
03497             }
03498             cpl_free(name_o);
03499             name_o = NULL;
03500         }
03501 
03502     } /* End of if(intermediate) */
03503 
03504     /*******************************/
03505     /*  Write the PAF file(s)      */
03506     /*******************************/
03507 
03508     paflist = cpl_propertylist_new();
03509 
03510 
03511     /* Set the file name for the PAF */
03512     if(detmon_lg_config.exts >= 0) {
03513     skip_if((plist =
03514         cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
03515                   detmon_lg_config.exts)) == NULL);
03516 
03517     if(!flag_sets) {
03518         name_o = cpl_sprintf("%s.paf", detmon_lg_config.pafname);
03519         assert(name_o != NULL);
03520     } else {
03521         name_o = cpl_sprintf("%s_set%02d.paf",
03522                  detmon_lg_config.pafname, which_set);
03523         assert(name_o != NULL);
03524     }
03525     } else {
03526     skip_if((plist =
03527         cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
03528                   whichext)) == NULL);
03529 
03530 
03531     if(!flag_sets) {
03532         name_o = cpl_sprintf("%s_ext%02d.paf", 
03533                  detmon_lg_config.pafname, whichext);
03534         assert(name_o != NULL);
03535     } else {
03536         name_o = cpl_sprintf("%s_set%02d_ext%02d.paf", 
03537                  detmon_lg_config.pafname,
03538                  which_set, whichext);
03539         assert(name_o != NULL);
03540     }
03541     }
03542 
03543     /* Get the keywords for the paf file */
03544     skip_if(cpl_propertylist_copy_property_regexp(paflist, plist,
03545                       pafregexp, 0));
03546     skip_if(cpl_propertylist_copy_property_regexp(paflist, mainplist,
03547                       pafregexp, 0));
03548 
03549     if(detmon_lg_config.exts >= 0)
03550     skip_if(error = cpl_propertylist_append(paflist, qclist));
03551     else
03552     skip_if(error = cpl_propertylist_append(paflist, xplist));
03553 
03554     /* Save the PAF */
03555     skip_if(cpl_dfs_save_paf(pipeline_name, recipe_name, paflist, name_o));
03556 
03557     end_skip;
03558 
03559     cpl_propertylist_delete(xplist);
03560     cpl_propertylist_delete(paflist);
03561     cpl_propertylist_delete(plist);
03562     cpl_free(name_o);
03563     cpl_propertylist_delete(mainplist);
03564 
03565     cpl_propertylist_delete(mypro_lintbl);
03566     cpl_propertylist_delete(mypro_gaintbl);
03567     cpl_propertylist_delete(mypro_coeffscube);
03568     cpl_propertylist_delete(mypro_bpm);
03569     cpl_propertylist_delete(mypro_corr);
03570     cpl_propertylist_delete(mypro_diff);
03571 
03572     return cpl_error_get_code();
03573 }
03574 
03575 
03576 /*---------------------------------------------------------------------------*/
03584 /*---------------------------------------------------------------------------*/
03585 static cpl_error_code
03586 irplib_detmon_opt_contamination(const cpl_imagelist * ons,
03587                 const cpl_imagelist * offs,
03588                 unsigned mode,
03589                                 cpl_propertylist * qclist)
03590 {
03591 
03592     double                  median[5] = {0, 0, 0, 0, 0};
03593 
03594     cpl_image * dif1=NULL;
03595     cpl_image * dif2=NULL;
03596     cpl_image * dif_avg=NULL;
03597     const char* kname=NULL;
03598     int offsize = cpl_imagelist_get_size(offs);
03599 
03600     /* Algorithm defined: substract ON - OFF and average 2 differences */
03601     dif1 = cpl_image_subtract_create(cpl_imagelist_get_const(ons, 0),
03602                                      cpl_imagelist_get_const(offs, 0));
03603 
03604     if (offsize == 1 || mode & IRPLIB_LIN_COLLAPSE)
03605         dif2 = cpl_image_subtract_create(cpl_imagelist_get_const(ons, 1),
03606                                          cpl_imagelist_get_const(offs, 0));
03607     else if (mode & IRPLIB_LIN_NO_COLLAPSE)
03608         dif2 = cpl_image_subtract_create(cpl_imagelist_get_const(ons, 1),
03609                                          cpl_imagelist_get_const(offs, 1));
03610 
03611     dif_avg = cpl_image_average_create(dif1, dif2);
03612 
03613     cpl_image_abs(dif_avg);
03614 
03615     median[0] = cpl_image_get_median_window(dif_avg,
03616                         detmon_lg_config.llx1,
03617                         detmon_lg_config.lly1,
03618                         detmon_lg_config.urx1,
03619                         detmon_lg_config.ury1);
03620 
03621     skip_if(0);
03622     kname = cpl_sprintf("%s%d", DETMON_QC_CONTAM,1);
03623     skip_if(cpl_propertylist_append_double(qclist,kname,median[0]));
03624     skip_if(cpl_propertylist_set_comment(qclist,kname,DETMON_QC_CONTAM_C));
03625 
03626     median[1] = cpl_image_get_median_window(dif_avg,
03627                         detmon_lg_config.llx2,
03628                         detmon_lg_config.lly2,
03629                         detmon_lg_config.urx2,
03630                         detmon_lg_config.ury2);
03631 
03632     skip_if(0);
03633     kname = cpl_sprintf("%s%d", DETMON_QC_CONTAM,2);
03634     skip_if(cpl_propertylist_append_double(qclist,kname,median[1]));
03635     skip_if(cpl_propertylist_set_comment(qclist,kname,DETMON_QC_CONTAM_C));
03636 
03637     median[2] = cpl_image_get_median_window(dif_avg,
03638                         detmon_lg_config.llx3,
03639                         detmon_lg_config.lly3,
03640                         detmon_lg_config.urx3,
03641                         detmon_lg_config.ury3);
03642     skip_if(0);
03643 
03644     kname = cpl_sprintf("%s%d", DETMON_QC_CONTAM,3);
03645     skip_if(cpl_propertylist_append_double(qclist,kname,median[2]));
03646     skip_if(cpl_propertylist_set_comment(qclist,kname,DETMON_QC_CONTAM_C));
03647 
03648 
03649     median[3] = cpl_image_get_median_window(dif_avg,
03650                         detmon_lg_config.llx4,
03651                         detmon_lg_config.lly4,
03652                         detmon_lg_config.urx4,
03653                         detmon_lg_config.ury4);
03654     skip_if(0);
03655 
03656     kname = cpl_sprintf("%s%d", DETMON_QC_CONTAM,4);
03657     skip_if(cpl_propertylist_append_double(qclist,kname,median[3]));
03658     skip_if(cpl_propertylist_set_comment(qclist,kname,DETMON_QC_CONTAM_C));
03659 
03660     median[4] = cpl_image_get_median_window(dif_avg,
03661                         detmon_lg_config.llx5,
03662                         detmon_lg_config.lly5,
03663                         detmon_lg_config.urx5,
03664                         detmon_lg_config.ury5);
03665     skip_if(0);
03666 
03667     kname = cpl_sprintf("%s%d", DETMON_QC_CONTAM,5);
03668     skip_if(cpl_propertylist_append_double(qclist,kname,median[4]));
03669     skip_if(cpl_propertylist_set_comment(qclist,kname,DETMON_QC_CONTAM_C));
03670 
03671     end_skip;
03672 
03673     cpl_image_delete(dif1);
03674     cpl_image_delete(dif2);
03675     cpl_image_delete(dif_avg);
03676 
03677     return cpl_error_get_code();
03678 }
03679 
03680 /*---------------------------------------------------------------------------*/
03687 /*---------------------------------------------------------------------------*/
03688 /*
03689 static cpl_error_code
03690 irplib_detmon_opt_lampcr(cpl_frameset * cur_fset, int ext)
03691 {
03692     cpl_image        * on        = NULL;
03693     cpl_image        * off       = NULL; 
03694     cpl_frame        * first_off = NULL;
03695     cpl_frame        * first_on  = NULL;
03696     cpl_propertylist * plist     = NULL;
03697     double             dit;
03698 
03699     cpl_ensure_code(cur_fset != NULL, CPL_ERROR_NULL_INPUT);
03700 
03701     skip_if((first_off = cpl_frameset_get_first(cur_fset)) == NULL);
03702     skip_if((first_on  = cpl_frameset_get_next (cur_fset)) == NULL);
03703 
03704     on = cpl_image_load(cpl_frame_get_filename(first_on),
03705                         CPL_TYPE_FLOAT, 0, ext);
03706     off = cpl_image_load(cpl_frame_get_filename(first_off),
03707                          CPL_TYPE_FLOAT, 0, ext);
03708     skip_if(cpl_image_subtract(on, off));
03709 
03710     plist = cpl_propertylist_load(cpl_frame_get_filename(first_on), 0);
03711     skip_if(plist == NULL);
03712     
03713     dit = irplib_pfits_get_dit_opt(plist);
03714 
03715     detmon_lg_config.cr = cpl_image_get_mean(on) / dit;
03716 
03717     end_skip;
03718 
03719     cpl_image_delete(on);
03720     cpl_image_delete(off);
03721     cpl_propertylist_delete(plist);
03722 
03723     return cpl_error_get_code();
03724 }
03725 */
03726 /*---------------------------------------------------------------------------*/
03734 /*---------------------------------------------------------------------------*/
03735 int
03736 irplib_detmon_lg_dfs_set_groups(cpl_frameset * set,
03737                                 const char *tag_on, const char *tag_off)
03738 {
03739     cpl_frame              *cur_frame;
03740     const char             *tag;
03741     int                     nframes;
03742     int                     i;
03743 
03744     /* Check entries */
03745     if(set == NULL)
03746         return -1;
03747 
03748     /* Initialize */
03749     nframes = cpl_frameset_get_size(set);
03750 
03751     /* Loop on frames */
03752     for(i = 0; i < nframes; i++) {
03753         cur_frame = cpl_frameset_get_frame(set, i);
03754         tag = cpl_frame_get_tag(cur_frame);
03755 
03756         /* RAW frames */
03757         if(!strcmp(tag, tag_on) || !strcmp(tag, tag_off))
03758             cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW);
03759         /* CALIB frames */
03760 
03761 /*        else if (!strcmp(tag, IIINSTRUMENT_CALIB_FLAT))
03762             cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB);
03763 */
03764     }
03765     return 0;
03766 }
03767 
03768 /*---------------------------------------------------------------------------*/
03782 /*---------------------------------------------------------------------------*/
03783 static cpl_error_code
03784 irplib_detmon_lg_reduce_all(const cpl_table * linear_table,
03785                             cpl_propertylist * qclist,
03786                             cpl_imagelist ** coeffs_ptr,
03787                             cpl_image ** bpms_ptr,
03788                             const cpl_imagelist * linearity_inputs,
03789                             const cpl_table * gain_table,
03790                 int which_ext, cpl_boolean opt_nir)
03791 {
03792 
03793     int                     nbpixs = 0;
03794     const int               nsets = cpl_table_get_nrow(linear_table);
03795     int                     i;
03796     double autocorr;
03797     cpl_polynomial         *poly_linfit = NULL;
03798     cpl_image              *fiterror = NULL;
03799     char * name_o1 = NULL;
03800     char * name_o2 = NULL;
03801     double * pcoeffs = cpl_malloc(sizeof(double)*(detmon_lg_config.order + 1));
03802     unsigned mode = detmon_lg_config.autocorr ? IRPLIB_GAIN_WITH_AUTOCORR : 0;
03803     double min_val=0;
03804     double max_val=0;
03805     cpl_vector *x =NULL;
03806     const cpl_vector *y =NULL;
03807 
03808 
03809     const cpl_image * first = NULL;
03810     int sizex = 0;
03811     int sizey = 0;
03812 
03813     double vsize = 0;
03814 
03815 
03816     /* FIXME: This should go before the x and y vectors.
03817        Checking for all the inputs */
03818     cpl_ensure_code(qclist != NULL, CPL_ERROR_NULL_INPUT);
03819 
03820     skip_if(cpl_propertylist_append_string(qclist, DETMON_QC_METHOD,
03821                        detmon_lg_config.method));
03822     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_METHOD,
03823                      DETMON_QC_METHOD_C));
03824 
03825     if (!strcmp(detmon_lg_config.method, "PTC")) {
03826     /* Computation of GAIN via polynomial fit */
03827     if (detmon_lg_config.exts >= 0) { 
03828         cpl_msg_info(cpl_func,
03829              "Polynomial fitting for the GAIN (constant term method)");
03830     } else {
03831         cpl_msg_info(cpl_func,
03832              "Polynomial fitting for the GAIN (constant term method)"
03833              " for extension nb %d", which_ext);
03834     }
03835     skip_if(irplib_detmon_lg_qc_ptc(gain_table, qclist, mode));
03836     } else {
03837     skip_if(irplib_detmon_lg_qc_med(gain_table, qclist));
03838     }
03839 
03840     /*^FIXME: This shouldn't be written when no applied */
03841     /* Lamp flux */
03842     if(detmon_lg_config.lamp_ok) {
03843     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LAMP_FLUX,
03844                            detmon_lg_config.cr));
03845     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LAMP_FLUX,
03846                          DETMON_QC_LAMP_FLUX_C));
03847     }
03848 
03849     /*^FIXME: This shouldn't be written when no applied */
03850     if(detmon_lg_config.autocorr == TRUE) {
03851     autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
03852     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_AUTOCORR,
03853                            autocorr));
03854     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_AUTOCORR,
03855                          DETMON_QC_AUTOCORR_C));
03856     }
03857     if (detmon_lg_config.exts >= 0) { 
03858         cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix");
03859     } else {
03860         cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix"
03861                                " for extension nb %d", which_ext);
03862     }
03863 
03864     if(!detmon_lg_config.pix2pix) {
03865     double mse = 0;
03866         /* Computation of LINEARITY via polynomial fit */
03867     y = cpl_vector_wrap(nsets,
03868                 (double *)cpl_table_get_data_double_const(linear_table,
03869                                   "MED"));
03870 
03871     if (opt_nir == NIR) 
03872         x = cpl_vector_wrap(nsets,
03873                 (double *)cpl_table_get_data_double_const(linear_table,
03874                                   "DIT"));
03875     else
03876         x = cpl_vector_wrap(nsets,
03877                 (double *)cpl_table_get_data_double_const(linear_table,
03878                                   "EXPTIME"));
03879 
03880 
03881         if(x == NULL || y == NULL) {
03882         cpl_vector_unwrap((cpl_vector *)x);
03883         cpl_vector_unwrap((cpl_vector *)y);
03884         /*
03885          * As x and y are const vectors, if they would be defined at the
03886          * beginning of the function (required for skip_if - end_skip
03887          * scheme), they couldn't be initialised to NULL (required too).
03888          * Therefore, they are considered apart from the scheme.
03889          */
03890         skip_if(1);
03891     }
03892 
03893         cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
03894         poly_linfit = cpl_polynomial_fit_1d_create(x, y,
03895                            detmon_lg_config.order,
03896                            &mse);
03897 
03898     if(detmon_lg_config.order == cpl_vector_get_size(x) - 1) {
03899         cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
03900         mse = 0;
03901     }
03902 
03903     if(poly_linfit == NULL) {
03904         cpl_vector_unwrap((cpl_vector *)x);
03905         cpl_vector_unwrap((cpl_vector *)y);
03906         /* See comment in previous error checking if() statement */
03907         skip_if(1);
03908     }
03909 
03910     
03911         min_val=cpl_vector_get_min(y);
03912         max_val=cpl_vector_get_max(y);
03913 
03914     cpl_vector_unwrap((cpl_vector *)x);
03915     cpl_vector_unwrap((cpl_vector *)y);
03916 
03917         for(i = 0; i <= detmon_lg_config.order; i++) {
03918             const double            coeff =
03919                 cpl_polynomial_get_coeff(poly_linfit, &i);
03920             char                   *name_o =
03921                 cpl_sprintf("ESO QC LIN COEF%d", i);
03922             assert(name_o != NULL);
03923             skip_if(cpl_propertylist_append_double(qclist, name_o, coeff));
03924             skip_if(cpl_propertylist_set_comment(qclist,name_o,
03925                          DETMON_QC_LIN_COEF_C));
03926 
03927             cpl_free(name_o);
03928         pcoeffs[i] = coeff;
03929         }
03930     skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT, mse));
03931         skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
03932                          DETMON_QC_ERRFIT_MSE_C));
03933 
03934 
03935     } else {
03936 
03937 
03938     y = cpl_vector_wrap(nsets,
03939                 (double *)cpl_table_get_data_double_const(linear_table,
03940                                   "MED"));
03941 
03942       if (opt_nir == NIR) {
03943          x=
03944         cpl_vector_wrap(nsets,
03945                 (double *)cpl_table_get_data_double_const(linear_table,
03946                                   "DIT"));
03947 
03948       } else {
03949 
03950     x =
03951         cpl_vector_wrap(nsets,
03952                 (double *)cpl_table_get_data_double_const(linear_table,
03953                                   "EXPTIME"));
03954 
03955       }
03956 
03957 
03958     first = cpl_imagelist_get_const(linearity_inputs, 0);
03959     sizex = cpl_image_get_size_x(first);
03960     sizey = cpl_image_get_size_y(first);
03961 
03962     vsize = cpl_vector_get_size(x);
03963 
03964     fiterror = cpl_image_new(sizex, sizey, CPL_TYPE_FLOAT);
03965 
03966     *coeffs_ptr =
03967         cpl_fit_imagelist_polynomial(x, linearity_inputs, 0,
03968                      detmon_lg_config.order, FALSE,
03969                      CPL_TYPE_FLOAT, fiterror);
03970 
03971         min_val=cpl_vector_get_min(y);
03972         max_val=cpl_vector_get_max(y);
03973 
03974 
03975     cpl_vector_unwrap((cpl_vector*)x);
03976     cpl_vector_unwrap((cpl_vector*)y);
03977     irplib_ensure(*coeffs_ptr != NULL, CPL_ERROR_UNSPECIFIED, 
03978               "Failed polynomial fit");
03979 
03980         for(i = 0; i <= detmon_lg_config.order; i++) {
03981             cpl_image              *image = cpl_imagelist_get(*coeffs_ptr, i);
03982         const double coeff = cpl_image_get_median(image);
03983         pcoeffs[i] = coeff;
03984             name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
03985             name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
03986             assert(name_o1 != NULL);
03987             assert(name_o2 != NULL);
03988             skip_if(cpl_propertylist_append_double(qclist, name_o1, coeff));
03989             skip_if(cpl_propertylist_set_comment(qclist,name_o1,
03990                          DETMON_QC_LIN_COEF_C));
03991             cpl_free(name_o1);
03992         name_o1= NULL;
03993             skip_if(cpl_propertylist_append_double(qclist, name_o2,
03994                        cpl_image_get_stdev(image)));
03995             skip_if(cpl_propertylist_set_comment(qclist,name_o2,
03996                          DETMON_QC_LIN_COEF_ERR_C));
03997             cpl_free(name_o2);
03998         name_o2= NULL;
03999         }
04000 
04001     if(detmon_lg_config.order == vsize - 1) {
04002         cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
04003         skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
04004                            0.0));
04005             skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
04006                          DETMON_QC_ERRFIT_C));
04007 
04008 
04009 
04010     } else {
04011         skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
04012                            cpl_image_get_median(fiterror)));
04013             skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
04014                          DETMON_QC_ERRFIT_C));
04015 
04016     }
04017     }
04018 
04019 
04020     skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_COUNTS_MIN,
04021                                            min_val));
04022 
04023     skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_COUNTS_MIN,
04024                                          DETMON_QC_COUNTS_MIN_C));
04025 
04026     skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_COUNTS_MAX,
04027                                            max_val));
04028 
04029     skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_COUNTS_MAX,
04030                                          DETMON_QC_COUNTS_MAX_C));
04031 
04032     skip_if(irplib_detmon_lg_lineff(pcoeffs,qclist,detmon_lg_config.ref_level,
04033                                     detmon_lg_config.order));
04034 
04035     /* Detection of bad pixels */
04036     if (detmon_lg_config.exts >= 0) { 
04037         cpl_msg_info(cpl_func, "Bad pixel detection");
04038     } else {
04039         cpl_msg_info(cpl_func, "Bad pixel detection"
04040              " for extension nb %d", which_ext);
04041     }
04042 
04043     if(detmon_lg_config.pix2pix) {
04044        *bpms_ptr = irplib_detmon_bpixs(*coeffs_ptr, detmon_lg_config.bpmbin, 
04045                                        detmon_lg_config.kappa, &nbpixs);
04046     skip_if(*bpms_ptr == NULL);
04047     }
04048 
04049     skip_if(cpl_propertylist_append_int(qclist, DETMON_QC_NUM_BPM, nbpixs));
04050     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_NUM_BPM,
04051                                          DETMON_QC_NUM_BPM_C));
04052 
04053     if(detmon_lg_config.lamp_stability != 0.0) {
04054     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LAMP_STAB,
04055                            detmon_lg_config.lamp_stability));
04056     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LAMP_STAB,
04057                          DETMON_QC_LAMP_STAB_C));
04058     }
04059     end_skip;
04060 
04061     cpl_free(pcoeffs);
04062     cpl_free(name_o1);
04063     cpl_free(name_o2);
04064     cpl_image_delete(fiterror);
04065     cpl_polynomial_delete(poly_linfit);
04066 
04067     return cpl_error_get_code();
04068 }
04069 
04070 /*---------------------------------------------------------------------------*/
04078 /*---------------------------------------------------------------------------*/
04079 static cpl_error_code
04080 irplib_detmon_lg_lineff(double * pcoeffs,
04081                         cpl_propertylist * qclist,
04082                         int ref_level, 
04083                         int order)
04084 {
04085     double           lineff = 0;
04086     double           root = 0;
04087     cpl_polynomial * poly = cpl_polynomial_new(1);
04088     int i;
04089 
04090     double residual, slope;
04091 
04092     /*
04093      * Construction of the polynomial F_m(F_r) from F_m(t),
04094      * using F_r = a_1 * t.
04095      */
04096     pcoeffs[0] -= ref_level;
04097 
04098     for (i = 2; i <= order; i++) {
04099     int j;
04100     for(j = 0; j < i; j++) {
04101         pcoeffs[i] /= pcoeffs[1];
04102     }
04103     }
04104 
04105     pcoeffs[1] = 1;
04106 
04107     for (i = 0; i <= order; i++) {
04108     skip_if(cpl_polynomial_set_coeff(poly, &i, pcoeffs[i]));
04109     }
04110 
04111     /*
04112      * Verification of validity of first guess (0).
04113      * The root to be found will be in the same interval of monotony
04114      * of the first guess; therefore, slope must be greater than 0.
04115      * Slope > 0 and poly(root) = 0 force also residual to be negative.
04116      */
04117     residual = cpl_polynomial_eval_1d(poly, 0.0, &slope);
04118 
04119     if (slope <= 0.0 && residual >= 0.0) {
04120     cpl_msg_warning(cpl_func, "Reference level (--ref_level) outside"
04121             " linearity range of the detector. Cannot compute"
04122             " linearity efficiency (QC.LINEFF).");
04123     lineff = -1;
04124     } else {
04125     skip_if(cpl_polynomial_solve_1d(poly, 0.0, &root, 1));
04126 
04127     lineff = (root - ref_level) / ref_level;
04128     }
04129 
04130     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LIN_EFF,
04131                        lineff));
04132     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LIN_EFF,
04133                      DETMON_QC_LIN_EFF_C));
04134 
04135     end_skip;
04136 
04137     cpl_polynomial_delete(poly);
04138 
04139     return cpl_error_get_code();
04140 }
04141 
04142 /*---------------------------------------------------------------------------*/
04149 /*---------------------------------------------------------------------------*/
04150 static cpl_error_code
04151 irplib_detmon_lg_qc_ptc(const cpl_table  * gain_table,
04152             cpl_propertylist * qclist, unsigned mode)
04153 {
04154     double                  mse = 0;
04155     cpl_polynomial         *poly_fit = NULL;
04156     cpl_polynomial         *poly_fit2 = NULL;
04157     int i;
04158     const int               nsets = cpl_table_get_nrow(gain_table);
04159 
04160     /* The following 2 vectors are declared 'const' as they shouldn't be 
04161        modified. However, the data to be wrapped are casted as 'non-const'
04162        to avoid warning in cpl_vector_wrap, where API is 'non-const' */
04163 
04164     const cpl_vector             *x;
04165     const cpl_vector             *y;
04166 
04167     cpl_errorstate                prestate;
04168     double coef = 0;
04169 
04170     cpl_ensure_code(gain_table != NULL, CPL_ERROR_NULL_INPUT);
04171     cpl_ensure_code(qclist     != NULL, CPL_ERROR_NULL_INPUT);
04172 
04173     x = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT"));
04174     
04175     y = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
04176 
04177     skip_if(x == NULL || y == NULL);
04178 
04179     poly_fit = cpl_polynomial_fit_1d_create(x, y, 1, &mse);
04180     skip_if(poly_fit == NULL);
04181 
04182     /* Write the QC params corresponding to the fitting of the GAIN */
04183     i = 1;
04184     prestate = cpl_errorstate_get();
04185     coef = cpl_polynomial_get_coeff(poly_fit, &i);
04186     skip_if (!cpl_errorstate_is_equal(prestate) || coef == 0);
04187 
04188     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD, coef));
04189     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
04190                      DETMON_QC_CONAD_C));
04191 
04192     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,
04193                        1 / coef));
04194     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
04195                      DETMON_QC_GAIN_C));
04196 
04197     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE, mse));
04198     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
04199                      DETMON_QC_GAIN_MSE_C));
04200     i = 0;
04201     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_RON,
04202                        cpl_polynomial_get_coeff(poly_fit, &i)));
04203     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_RON,
04204                      DETMON_QC_RON_C));
04205     
04206     if(mode & IRPLIB_GAIN_WITH_AUTOCORR){
04207     const cpl_vector             *x2 =
04208         cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT_CORR"));
04209     const cpl_vector             *y2 =
04210         cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
04211 
04212     if(x2 == NULL || y2 == NULL) {
04213         cpl_vector_unwrap((cpl_vector *)x2);
04214         cpl_vector_unwrap((cpl_vector *)y2);
04215         /*
04216          * As x and y are const vectors, if they would be defined at the
04217          * beginning of the function (required for skip_if - end_skip
04218          * scheme), they couldn't be initialised to NULL (required too).
04219          * Therefore, they are considered apart from the scheme.
04220          */
04221         skip_if(1);
04222     }
04223 
04224     /* Revise mse, maybe used afterwards */
04225     poly_fit2 = cpl_polynomial_fit_1d_create(x2, y2, 1, &mse);
04226     if(poly_fit2 == NULL) {
04227         cpl_vector_unwrap((cpl_vector *)x2);
04228         cpl_vector_unwrap((cpl_vector *)y2);
04229         /* See comment in previous error checking if() statement */
04230         skip_if(1);
04231     }
04232 
04233     cpl_vector_unwrap((cpl_vector *)x2);
04234     cpl_vector_unwrap((cpl_vector *)y2);
04235 
04236     /* Write the QC params corresponding to the fitting of the GAIN */
04237     i = 1;
04238     prestate = cpl_errorstate_get();
04239     coef = cpl_polynomial_get_coeff(poly_fit2, &i);
04240     skip_if (!cpl_errorstate_is_equal(prestate) || coef == 0);
04241 
04242     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
04243                            1 / coef));
04244     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
04245                          DETMON_QC_GAIN_CORR_C));
04246     }
04247 
04248     end_skip;
04249 
04250     /* Cast back to 'non-const' to avoid warning. See comment above */
04251     cpl_vector_unwrap((cpl_vector *)x);
04252     cpl_vector_unwrap((cpl_vector *)y);
04253     cpl_polynomial_delete(poly_fit);
04254     cpl_polynomial_delete(poly_fit2);
04255 
04256     return cpl_error_get_code();
04257 }
04258 
04259 /*---------------------------------------------------------------------------*/
04268 /*---------------------------------------------------------------------------*/
04269 static cpl_error_code
04270 irplib_detmon_lg_qc_med(const cpl_table * gain_table,
04271                 cpl_propertylist * qclist)
04272 {
04273 
04274    double gain=0;
04275    gain=cpl_table_get_column_median(gain_table, "GAIN");
04276 
04277    skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,gain));
04278 
04279    skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
04280                                         DETMON_QC_GAIN_C));
04281 
04282    skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE,
04283                                           cpl_table_get_column_stdev
04284                                           (gain_table, "GAIN")));
04285    skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
04286                                         DETMON_QC_GAIN_MSE_C));
04287 
04288    skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD,1./gain));
04289    skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
04290                                         DETMON_QC_CONAD_C));
04291 
04292 
04293    gain=cpl_table_get_column_median(gain_table, "GAIN_CORR");
04294 
04295    skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
04296                                           gain));
04297    skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
04298                                         DETMON_QC_GAIN_CORR_C));
04299 
04300 
04301    skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD_CORR,1./gain));
04302    skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD_CORR,
04303                                         DETMON_QC_CONAD_CORR_C));
04304 
04305 
04306     end_skip;
04307 
04308     return cpl_error_get_code();
04309 }
04310 
04311 
04312 /*---------------------------------------------------------------------------*/
04321 /*---------------------------------------------------------------------------*/
04322 static cpl_error_code
04323 irplib_detmon_lg_rescale(cpl_imagelist * to_rescale)
04324 {
04325     double                  med1 =
04326         cpl_image_get_median(cpl_imagelist_get(to_rescale, 0));
04327     double                  med2 =
04328         cpl_image_get_median(cpl_imagelist_get(to_rescale, 1));
04329 
04330     skip_if(0);
04331 
04332     if(fabs(med1 / med2 - 1) > 0.001) {
04333         if(med1 > med2)
04334             skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 0),
04335                                             med1 / med2));
04336         else
04337             skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 1),
04338                                             med2 / med1));
04339     }
04340     
04341     end_skip;
04342 
04343     return cpl_error_get_code();
04344 }
04345 
04346 /*---------------------------------------------------------------------------*/
04364 /*---------------------------------------------------------------------------*/
04365 static cpl_error_code
04366 irplib_detmon_pair_extract(const cpl_frameset * set,
04367                            int * selection, int selected,
04368                            int nsets_extracted,
04369                            int * with_equal_dit,
04370                            int onoff,
04371                            cpl_frameset ** pair)
04372 {
04373     int new_with_equal_dit = 0;
04374 
04375     cpl_ensure_code(set             != NULL, CPL_ERROR_NULL_INPUT);
04376     cpl_ensure_code(selection       != NULL, CPL_ERROR_NULL_INPUT);
04377     cpl_ensure_code(with_equal_dit  != NULL, CPL_ERROR_NULL_INPUT);
04378     cpl_ensure_code(pair            != NULL, CPL_ERROR_NULL_INPUT);
04379 
04380     *pair = cpl_frameset_extract(set, selection, selected);
04381     cpl_ensure_code(*pair != NULL, cpl_error_get_code());
04382 
04383     /* FIXME: Error checkin to be done here */
04384 
04385     /* It must be even (a single pair or multiple pairs of same DIT) */
04386     skip_if(cpl_frameset_get_size(*pair) % 2 != 0);
04387 
04388     /* See how many pairs with same DIT */
04389     if(cpl_frameset_get_size(*pair) != 2) {
04390         new_with_equal_dit = cpl_frameset_get_size(*pair) / 2;
04391         if(onoff == 1) {
04392             *with_equal_dit = new_with_equal_dit;
04393         } else {
04394             skip_if (*with_equal_dit    != 0 &&
04395              new_with_equal_dit != *with_equal_dit);
04396         }
04397     }
04398 
04399     /* If more than a pair, update selection array */
04400     if (new_with_equal_dit != 0) {
04401         int                     found = 0;
04402         int j;
04403         for(j = 0; j < cpl_frameset_get_size(set); j++) {
04404 
04405             if(selection[j] == selected) {
04406                 found++;
04407 
04408                 if((found - 1) / 2 != 0) {
04409                     selection[j] =
04410                         nsets_extracted + (found - 1) / 2 - 1;
04411                 }
04412             }
04413         }
04414         cpl_frameset_delete(*pair);
04415         *pair = cpl_frameset_extract(set, selection, selected);
04416         /* FIXME: Error checking missing here */
04417     }
04418 
04419     end_skip;
04420 
04421     return cpl_error_get_code();
04422 }
04423 /*---------------------------------------------------------------------------*/
04441 /*---------------------------------------------------------------------------*/
04442 static cpl_error_code
04443 irplib_detmon_single_extract(const cpl_frameset * set,
04444                  int * selection, int selected,
04445                  int nsets_extracted,
04446                  int * with_equal_dit,
04447                  int onoff,
04448                  cpl_frameset ** single)
04449 {
04450     int new_with_equal_dit = 0;
04451 
04452     cpl_ensure_code(set             != NULL, CPL_ERROR_NULL_INPUT);
04453     cpl_ensure_code(selection       != NULL, CPL_ERROR_NULL_INPUT);
04454     cpl_ensure_code(with_equal_dit  != NULL, CPL_ERROR_NULL_INPUT);
04455     cpl_ensure_code(single          != NULL, CPL_ERROR_NULL_INPUT);
04456 
04457     *single = cpl_frameset_extract(set, selection, selected);
04458     cpl_ensure_code(*single != NULL, cpl_error_get_code());
04459 
04460     /* FIXME: Error checkin to be done here */
04461 
04462     /* See how many singles with same DIT */
04463     if(cpl_frameset_get_size(*single) != 1) {
04464         new_with_equal_dit = cpl_frameset_get_size(*single);
04465         if(onoff == 1) {
04466             *with_equal_dit = new_with_equal_dit;
04467         } else {
04468             skip_if (*with_equal_dit    != 0 &&
04469              new_with_equal_dit != *with_equal_dit);
04470         }
04471     }
04472 
04473     /* If more than a single, update selection array */
04474     if (new_with_equal_dit != 0) {
04475         int                     found = 0;
04476         int j;
04477         for(j = 0; j < cpl_frameset_get_size(set); j++) {
04478 
04479             if(selection[j] == selected) {
04480                 found++;
04481 
04482                 if(found > 1) {
04483                     selection[j] =
04484                         nsets_extracted + (found - 2);
04485                 }
04486             }
04487         }
04488         cpl_frameset_delete(*single);
04489         *single = cpl_frameset_extract(set, selection, selected);
04490         /* FIXME: Error checking missing here */
04491     }
04492 
04493     end_skip;
04494 
04495     return cpl_error_get_code();
04496 }
04497 /*--------------------------------------------------------------------------*/
04498 
04499 /*
04500  * @brief    Comparison function to identify different settings
04501  * @param    frame1  First frame 
04502  * @param    frame2  Second frame 
04503  * @return   0 if different, 1 if equal, -1 in error case
04504  */
04505 
04506 /*--------------------------------------------------------------------------*/
04507 
04508 static int
04509 irplib_detmon_lg_compare_pairs(const cpl_frame * frame1,
04510                    const cpl_frame * frame2)
04511 {
04512     int                     comparison;
04513     cpl_propertylist       *plist1;
04514     cpl_propertylist       *plist2;
04515     double                  dval1, dval2;
04516 
04517     /* Test entries */
04518     if(frame1 == NULL || frame2 == NULL)
04519         return -1;
04520 
04521     /* Get property lists */
04522     if((plist1 = cpl_propertylist_load(cpl_frame_get_filename(frame1),
04523                                        0)) == NULL) {
04524         cpl_msg_error(cpl_func, "getting header from reference frame");
04525         return -1;
04526     }
04527     if((plist2 = cpl_propertylist_load(cpl_frame_get_filename(frame2),
04528                                        0)) == NULL) {
04529         cpl_msg_error(cpl_func, "getting header from reference frame");
04530         cpl_propertylist_delete(plist1);
04531         return -1;
04532     }
04533 
04534     /* Test status */
04535     if(cpl_error_get_code()) {
04536         cpl_propertylist_delete(plist1);
04537         cpl_propertylist_delete(plist2);
04538         return -1;
04539     }
04540 
04541     /* Compare exposure time */
04542     comparison = 1;
04543     dval1 = irplib_pfits_get_exptime(plist1);
04544     dval2 = irplib_pfits_get_exptime(plist2);
04545     if(cpl_error_get_code()) {
04546         cpl_msg_error(cpl_func, "cannot get exposure time");
04547         cpl_propertylist_delete(plist1);
04548         cpl_propertylist_delete(plist2);
04549         return -1;
04550     }
04551     if(fabs(dval1 - dval2) > detmon_lg_config.tolerance)
04552         comparison = 0;
04553 
04554     /* Free and return */
04555     cpl_propertylist_delete(plist1);
04556     cpl_propertylist_delete(plist2);
04557     return comparison;
04558 }
04559 
04560 /*---------------------------------------------------------------------------*/
04649 /*---------------------------------------------------------------------------*/
04650 
04651 cpl_table *
04652 irplib_detmon_gain(const cpl_imagelist  * imlist_on,
04653            const cpl_imagelist  * imlist_off,
04654            const cpl_vector     * exptimes,
04655            double                 tolerance,
04656            int                    llx,
04657            int                    lly,
04658            int                    urx,
04659            int                    ury,
04660                    double                 kappa,
04661                    int                    nclip,
04662                    int                    xshift,
04663                    int                    yshift,
04664            cpl_propertylist     * qclist,
04665            unsigned               mode,
04666            cpl_imagelist       ** diff_imlist,
04667            cpl_imagelist       ** autocorr_imlist)
04668 {
04669     cpl_table     * gain_table   = NULL;
04670     cpl_imagelist * difflist     = NULL;
04671     cpl_imagelist * autocorrlist = NULL;
04672     cpl_imagelist * c_onlist     = NULL;
04673     cpl_imagelist * c_offlist    = NULL;
04674     cpl_vector    * diffdits     = NULL;
04675     int             ndiffdits, ndits;
04676     int             i, j;
04677     cpl_boolean     opt_nir      = mode & IRPLIB_GAIN_OPT ? OPT : NIR;
04678 
04679     cpl_ensure(imlist_on  != NULL, CPL_ERROR_NULL_INPUT, NULL);
04680     cpl_ensure(imlist_off != NULL, CPL_ERROR_NULL_INPUT, NULL);
04681     cpl_ensure(exptimes   != NULL, CPL_ERROR_NULL_INPUT, NULL);
04682     cpl_ensure(qclist     != NULL, CPL_ERROR_NULL_INPUT, NULL);
04683 
04684     /* Create table with columns */
04685     gain_table = cpl_table_new(cpl_vector_get_size(exptimes) / 2);
04686     skip_if(irplib_detmon_gain_table_create(gain_table, opt_nir));
04687 
04688     /* Search for different EXPTIME values */
04689     diffdits  = irplib_detmon_lg_find_dits(exptimes, tolerance);
04690     ndiffdits = cpl_vector_get_size(diffdits);
04691 
04692     ndits     = cpl_vector_get_size(exptimes);
04693 
04694     /* AUTOCORR processing requires both. They will become outputs later. */
04695     if (mode & IRPLIB_GAIN_WITH_AUTOCORR && (diff_imlist || autocorr_imlist)) {
04696     difflist     = cpl_imagelist_new();
04697     autocorrlist = cpl_imagelist_new();
04698     }
04699 
04700     if (mode & IRPLIB_GAIN_COLLAPSE) {
04701         if (mode & IRPLIB_GAIN_WITH_RESCALE) {
04702         c_offlist = cpl_imagelist_duplicate(imlist_off);
04703         skip_if(irplib_detmon_lg_rescale(c_offlist));
04704         } else {
04705             c_offlist = (cpl_imagelist *) imlist_off;
04706         }
04707     }
04708 
04709     /* Loop over the different DITs found in EXPTIMEs */
04710     for (i = 0; i < ndiffdits; i++) {
04711         int c_nons;
04712         int c_noffs = 0; /* False (uninit) warning */
04713 
04714     double c_dit = cpl_vector_get(diffdits, i);
04715 
04716     c_onlist  = cpl_imagelist_new();
04717     c_nons = 0;
04718 
04719     if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
04720         c_offlist = cpl_imagelist_new();
04721         c_noffs = 0;
04722     }
04723 
04724     /* Extraction of images of EXPTIME i */
04725     for(j = 0; j < ndits; j++) {
04726         if (fabs(c_dit - cpl_vector_get(exptimes, j)) <= tolerance) {
04727                 /*
04728                  * First we get the corresponding image from the ON imlist. 
04729                  * The option IRPLIB_GAIN_WITH_RESCALE requires to modify
04730                  * the input pixel buffer; therefore we must duplicate it.
04731                  * On the other hand, if this option is not required, there
04732                  * is no need for that duplication. We must only care that
04733                  * c_onlist must not be deleted but only unset.
04734                  */
04735                 cpl_image * im_on;
04736                 if (mode & IRPLIB_GAIN_WITH_RESCALE) {
04737                     const cpl_image * im =
04738                         cpl_imagelist_get_const(imlist_on, j);
04739                     im_on = cpl_image_duplicate(im);
04740                 } else {
04741                     im_on = (cpl_image *)cpl_imagelist_get_const(imlist_on, j);
04742                 }
04743                 skip_if(cpl_imagelist_set(c_onlist, im_on, c_nons));
04744                 c_nons++;
04745 
04746                 /*
04747                  * Same explanation as above but for OFF imlist.
04748                  * Only necessary when IRPLIB_GAIN_NO_COLLAPSE required.
04749                  */
04750         if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
04751                     cpl_image * im_off;
04752                     if (mode & IRPLIB_GAIN_WITH_RESCALE) {
04753                         const cpl_image * im = 
04754                           cpl_imagelist_get_const(imlist_off, j);
04755                         im_off = cpl_image_duplicate(im);
04756                     } else {
04757                         im_off = 
04758                           (cpl_image *) cpl_imagelist_get_const(imlist_off, j);
04759                     }
04760             skip_if(cpl_imagelist_set(c_offlist, im_off, c_noffs));
04761             c_noffs++;
04762         }
04763         }
04764     }
04765 
04766     /* If NO_COLLAPSE, must be the same number of images! */
04767     if (mode & IRPLIB_GAIN_NO_COLLAPSE)
04768         skip_if (c_nons != c_noffs);
04769 
04770     /* There must be pairs! */
04771     skip_if (c_nons == 0 || c_nons % 2 != 0);
04772 
04773     /* Rescaling */
04774     if(mode & IRPLIB_GAIN_WITH_RESCALE) {
04775         skip_if(irplib_detmon_lg_rescale(c_onlist));
04776         if (mode & IRPLIB_GAIN_NO_COLLAPSE)
04777         skip_if(irplib_detmon_lg_rescale(c_offlist));
04778     }
04779         
04780     /* The following loop is necessary for the case of multiple pairs
04781        of same EXPTIME values */
04782     while(c_nons > 0) {
04783         skip_if(irplib_detmon_gain_table_fill_row(gain_table, c_dit,
04784                               autocorrlist,
04785                               difflist, c_onlist,
04786                               c_offlist, kappa, nclip,
04787                                                       llx, lly, urx, ury,
04788                                                       xshift, yshift, i, 
04789 mode));
04790             if (mode & IRPLIB_GAIN_WITH_RESCALE) {
04791                 cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
04792                 cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
04793                 if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
04794                   cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
04795                   cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
04796                 }
04797             } else {
04798             cpl_imagelist_unset(c_onlist, 0);
04799                 skip_if(0);
04800                 cpl_imagelist_unset(c_onlist, 0);
04801                 skip_if(0);
04802                 if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
04803                   cpl_imagelist_unset(c_offlist, 0);
04804                   skip_if(0);
04805                   cpl_imagelist_unset(c_offlist, 0);
04806                   skip_if(0);
04807                 }
04808             }
04809             skip_if(0);
04810         c_nons -= 2;
04811     }
04812 
04813     cpl_imagelist_delete(c_onlist);
04814     if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
04815           cpl_imagelist_delete(c_offlist);
04816     }
04817     }
04818 
04819     /* Computation of GAIN via polynomial fit */
04820     if (mode & IRPLIB_GAIN_PTC) {
04821       skip_if(irplib_detmon_lg_qc_ptc(gain_table, qclist, mode));
04822     } else {
04823     skip_if(irplib_detmon_lg_qc_med(gain_table, qclist));
04824     }
04825 
04826     if(mode & IRPLIB_GAIN_WITH_AUTOCORR) {
04827         double autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
04828     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_AUTOCORR,
04829                            autocorr));
04830     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_AUTOCORR,
04831                          DETMON_QC_AUTOCORR_C));
04832     }
04833 
04834     if (diff_imlist != NULL) *diff_imlist = difflist;
04835     if (autocorr_imlist != NULL) *autocorr_imlist = autocorrlist;
04836 
04837     end_skip;
04838 
04839     cpl_vector_delete(diffdits);
04840 
04841     return gain_table;
04842 }
04843 
04844 static cpl_error_code
04845 irplib_detmon_gain_table_create(cpl_table * gain_table,
04846                                 const cpl_boolean opt_nir)
04847 {
04848     if (opt_nir == NIR) {
04849     skip_if(cpl_table_new_column(gain_table, "DIT",     CPL_TYPE_DOUBLE));
04850     } else { /* OPT */
04851     skip_if(cpl_table_new_column(gain_table, "EXPTIME", CPL_TYPE_DOUBLE));
04852     }
04853     skip_if(cpl_table_new_column(gain_table, "MEAN_ON1",    CPL_TYPE_DOUBLE));
04854     skip_if(cpl_table_new_column(gain_table, "MEAN_ON2",    CPL_TYPE_DOUBLE));
04855     skip_if(cpl_table_new_column(gain_table, "MEAN_OFF1",   CPL_TYPE_DOUBLE));
04856     skip_if(cpl_table_new_column(gain_table, "MEAN_OFF2",   CPL_TYPE_DOUBLE));
04857     skip_if(cpl_table_new_column(gain_table, "SIG_ON_DIF",  CPL_TYPE_DOUBLE));
04858     skip_if(cpl_table_new_column(gain_table, "SIG_OFF_DIF", CPL_TYPE_DOUBLE));
04859     skip_if(cpl_table_new_column(gain_table, "GAIN",        CPL_TYPE_DOUBLE));
04860     skip_if(cpl_table_new_column(gain_table, "AUTOCORR",    CPL_TYPE_DOUBLE));
04861     skip_if(cpl_table_new_column(gain_table, "GAIN_CORR",   CPL_TYPE_DOUBLE));
04862     skip_if(cpl_table_new_column(gain_table, "ADU",         CPL_TYPE_DOUBLE));
04863     skip_if(cpl_table_new_column(gain_table, "X_FIT",       CPL_TYPE_DOUBLE));
04864     skip_if(cpl_table_new_column(gain_table, "X_FIT_CORR",  CPL_TYPE_DOUBLE));
04865     skip_if(cpl_table_new_column(gain_table, "Y_FIT",       CPL_TYPE_DOUBLE));
04866     skip_if(cpl_table_new_column(gain_table, "Y_FIT_CORR",  CPL_TYPE_DOUBLE));
04867 
04868     end_skip;
04869 
04870     return cpl_error_get_code();
04871 }
04872 
04873 static cpl_error_code
04874 irplib_detmon_lin_table_create(cpl_table * lin_table,
04875                                const cpl_boolean opt_nir)
04876 {
04877     if (opt_nir == NIR) {
04878     skip_if(cpl_table_new_column(lin_table, "DIT",     CPL_TYPE_DOUBLE));
04879     } else { /* OPT */
04880     skip_if(cpl_table_new_column(lin_table, "EXPTIME", CPL_TYPE_DOUBLE));
04881     }
04882     skip_if(cpl_table_new_column(lin_table, "MED",      CPL_TYPE_DOUBLE));
04883     skip_if(cpl_table_new_column(lin_table, "MEAN",     CPL_TYPE_DOUBLE));
04884     skip_if(cpl_table_new_column(lin_table, "MED_DIT",  CPL_TYPE_DOUBLE));
04885     skip_if(cpl_table_new_column(lin_table, "MEAN_DIT", CPL_TYPE_DOUBLE));
04886     skip_if(cpl_table_new_column(lin_table, "ADL",      CPL_TYPE_DOUBLE));
04887 
04888     end_skip;
04889 
04890     return cpl_error_get_code();
04891 }
04892 
04893 static cpl_vector *
04894 irplib_detmon_lg_find_dits(const cpl_vector * exptimes,
04895                            double             tolerance)
04896 {
04897     cpl_vector * dits  = cpl_vector_new(cpl_vector_get_size(exptimes) / 2);
04898     int          ndits = 0;
04899 
04900     int          i, j;
04901 
04902     /* First different EXPTIME */
04903     cpl_vector_set(dits, 0, cpl_vector_get(exptimes, 0));
04904     ndits = 1;
04905 
04906     /* Search for all different EXPTIMEs */
04907     for(i = 1; i < cpl_vector_get_size(exptimes); i++) {
04908       int ndiffs = 0;
04909     for (j = 0; j < ndits; j++) {
04910         if (fabs(cpl_vector_get(exptimes, i) -
04911              cpl_vector_get(dits,     j)) > tolerance)
04912               ndiffs++;
04913     }
04914         if(ndiffs == ndits) {
04915           cpl_vector_set(dits, ndits, cpl_vector_get(exptimes, i));
04916           ndits++;
04917         }
04918     }
04919 
04920     cpl_vector_set_size(dits, ndits);
04921 
04922     return dits;
04923 }
04924 
04925 
04926 /*---------------------------------------------------------------------------*/
05007 /*---------------------------------------------------------------------------*/
05008 
05009 cpl_table *
05010 irplib_detmon_lin(const cpl_imagelist  * imlist_on,
05011           const cpl_imagelist  * imlist_off,
05012           const cpl_vector     * exptimes,
05013           double                 tolerance,
05014           int                    llx,
05015           int                    lly,
05016           int                    urx,
05017           int                    ury,
05018           int                    order,
05019                   int                    ref_level,
05020                   double kappa,
05021                   cpl_boolean bpmbin,
05022           cpl_propertylist     * qclist,
05023           unsigned               mode,
05024           cpl_imagelist       ** coeffs_cube,
05025           cpl_image           ** bpm)
05026 {
05027     cpl_table     * lin_table    = NULL;
05028     cpl_imagelist * c_onlist     = NULL;
05029     cpl_imagelist * c_offlist    = NULL;
05030     cpl_vector    * diffdits     = NULL;
05031     cpl_imagelist * lin_inputs   = NULL;
05032     cpl_polynomial * poly_linfit = NULL;
05033     cpl_image     * fiterror     = NULL;
05034     cpl_vector    * vcoeffs      = NULL;
05035     double        * pcoeffs      = NULL;
05036     int             ndiffdits, ndits;
05037     int             i, j;
05038     cpl_boolean     opt_nir      = mode & IRPLIB_LIN_OPT ? OPT : NIR;
05039     const cpl_vector *x = NULL;
05040     const cpl_vector *y = NULL;
05041 
05042     const cpl_image * first = NULL;
05043     int sizex = 0;
05044     int sizey = 0;
05045 
05046     double vsize = 0;
05047 
05048 
05049     cpl_ensure(imlist_on  != NULL, CPL_ERROR_NULL_INPUT, NULL);
05050     cpl_ensure(imlist_off != NULL, CPL_ERROR_NULL_INPUT, NULL);
05051     cpl_ensure(exptimes   != NULL, CPL_ERROR_NULL_INPUT, NULL);
05052     cpl_ensure(qclist     != NULL, CPL_ERROR_NULL_INPUT, NULL);
05053     cpl_ensure(order      >  0   , CPL_ERROR_ILLEGAL_INPUT, NULL);
05054     
05055     vcoeffs      = cpl_vector_new(order + 1);
05056     pcoeffs      = cpl_vector_get_data(vcoeffs);
05057 
05058     /* This mode requires optional outputs */
05059     if (mode & IRPLIB_LIN_PIX2PIX) {
05060     lin_inputs = cpl_imagelist_new();
05061     cpl_ensure(coeffs_cube != NULL, CPL_ERROR_NULL_INPUT, NULL);
05062     cpl_ensure(bpm         != NULL, CPL_ERROR_NULL_INPUT, NULL);
05063     }
05064 
05065     /* Create table with columns */
05066     lin_table = cpl_table_new(cpl_vector_get_size(exptimes) / 2);
05067     skip_if(irplib_detmon_lin_table_create(lin_table, opt_nir));
05068 
05069     /* Search for different EXPTIME values */
05070     /* Search for different EXPTIME values */
05071     diffdits  = irplib_detmon_lg_find_dits(exptimes, tolerance);
05072     ndiffdits = cpl_vector_get_size(diffdits);
05073 
05074     ndits     = cpl_vector_get_size(exptimes);
05075 
05076 
05077 
05078 
05079 
05080 
05081 /* TO BE IMPLEMENTED SIMILARLY TO UPPER LEVEL FUNCTION (search for nskip)
05082    if(filter > 0) {
05083     double med1 =
05084         cpl_image_get_median_window(cpl_imagelist_get(imlist_on, 0),
05085                     llx,lly,urx,ury);
05086     double med2 = 
05087            cpl_image_get_median_window(cpl_imagelist_get(imlist_on, 1),
05088                     llx,lly,urx,ury);
05089     if ( med1 > (double)filter ||
05090          med2 > (double)filter) {
05091         follow = CPL_FALSE;
05092         cpl_table_select_row(lin_table, dit_nb);
05093             dit_nskip++;
05094         cpl_msg_warning(cpl_func, "Frames of EXPTIME nb %d "
05095                 "will not be taken into account for computation "
05096                 "as they are above --filter threshold", dit_nb);
05097     }
05098     }
05099 */
05100 
05101 
05102 
05103 
05104     if (mode & IRPLIB_LIN_COLLAPSE) {
05105     /*
05106      * The master bias is required only for 
05107      * linearity computation in the OPT domain
05108      */
05109     cpl_image * collapse = cpl_imagelist_collapse_create(imlist_off);
05110     skip_if(collapse == NULL);
05111 
05112     c_offlist = cpl_imagelist_new();
05113     skip_if(cpl_imagelist_set(c_offlist, collapse, 0));
05114     }
05115 
05116     /* Loop over the different DITs found in EXPTIMEs */
05117     for (i = 0; i < ndiffdits; i++) {
05118         int c_nons;
05119         int c_noffs = 0; /* False (uninit) warning */
05120 
05121     double c_dit = cpl_vector_get(diffdits, i);
05122 
05123     c_onlist  = cpl_imagelist_new();
05124     c_nons = 0;
05125 
05126     if (mode & IRPLIB_LIN_NO_COLLAPSE) {
05127         c_offlist = cpl_imagelist_new();
05128         c_noffs = 0;
05129     }
05130 
05131     for(j = 0; j < ndits; j++) {
05132         if (fabs(c_dit - cpl_vector_get(exptimes, j)) <= tolerance) {
05133                 /*
05134                  * First we get the corresponding image from the ON imlist. 
05135                  * The option IRPLIB_GAIN_WITH_RESCALE requires to modify
05136                  * the input pixel buffer; therefore we must duplicate it.
05137                  * On the other hand, if this option is not required, there
05138                  * is no need for that duplication. We must only care that
05139                  * c_onlist must not be deleted but only unset.
05140                  */
05141                 cpl_image * im_on;
05142                 if (mode & IRPLIB_LIN_WITH_RESCALE) {
05143                     const cpl_image * im =
05144                         cpl_imagelist_get_const(imlist_on, j);
05145                     im_on = cpl_image_duplicate(im);
05146                 } else {
05147                     im_on = (cpl_image *)cpl_imagelist_get_const(imlist_on, j);
05148                 }
05149                 skip_if(cpl_imagelist_set(c_onlist, im_on, c_nons));
05150                 c_nons++;
05151 
05152                 /*
05153                  * Same explanation as above but for OFF imlist.
05154                  * Only necessary when IRPLIB_GAIN_NO_COLLAPSE required.
05155                  */
05156         if (mode & IRPLIB_LIN_NO_COLLAPSE) {
05157                     cpl_image * im_off;
05158                     if (mode & IRPLIB_LIN_WITH_RESCALE) {
05159                         const cpl_image * im = 
05160                           cpl_imagelist_get_const(imlist_off, j);
05161                         im_off = cpl_image_duplicate(im);
05162                     } else {
05163                         im_off = 
05164                           (cpl_image *) cpl_imagelist_get_const(imlist_off, j);
05165                     }
05166             skip_if(cpl_imagelist_set(c_offlist, im_off, c_noffs));
05167             c_noffs++;
05168         }
05169         }
05170     }
05171 
05172     /* If NO_COLLAPSE, must be the same number of images! */
05173     if (mode & IRPLIB_LIN_NO_COLLAPSE)
05174         skip_if (c_nons != c_noffs);
05175 
05176     /* There must be pairs! */
05177     skip_if (c_nons == 0 || c_nons % 2 != 0);
05178 
05179     /* Rescaling */
05180     if(mode & IRPLIB_LIN_WITH_RESCALE) {
05181         skip_if(irplib_detmon_lg_rescale(c_onlist));
05182         if (mode & IRPLIB_LIN_NO_COLLAPSE)
05183         skip_if(irplib_detmon_lg_rescale(c_offlist));
05184     }
05185         
05186     /* The following loop is necessary for the case of multiple pairs
05187        of same EXPTIME values */
05188     while(c_nons > 0) {
05189 
05190         skip_if(irplib_detmon_lin_table_fill_row(lin_table, c_dit,
05191                              lin_inputs,
05192                              c_onlist, c_offlist,
05193                              llx, lly, urx, ury,
05194                              i, 0, mode));
05195 
05196             if (mode & IRPLIB_LIN_WITH_RESCALE) {
05197                 cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
05198                 cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
05199                 if (mode & IRPLIB_LIN_NO_COLLAPSE) {
05200                   cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
05201                   cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
05202                 }
05203             } else {
05204             cpl_imagelist_unset(c_onlist, 0);
05205                 skip_if(0);
05206                 cpl_imagelist_unset(c_onlist, 0);
05207                 skip_if(0);
05208                 if (mode & IRPLIB_LIN_NO_COLLAPSE) {
05209                   cpl_imagelist_unset(c_offlist, 0);
05210                   skip_if(0);
05211                   cpl_imagelist_unset(c_offlist, 0);
05212                   skip_if(0);
05213                 }
05214             }
05215             skip_if(0);
05216         c_nons -= 2;
05217     }
05218 
05219     cpl_imagelist_delete(c_onlist);
05220     if (mode & IRPLIB_LIN_NO_COLLAPSE) {
05221           cpl_imagelist_delete(c_offlist);
05222     }
05223     }
05224 
05225     skip_if(irplib_detmon_add_adl_column(lin_table, opt_nir));
05226 
05227     if(!(mode & IRPLIB_LIN_PIX2PIX)) {
05228     double mse = 0;
05229         /* Computation of LINEARITY via polynomial fit */
05230     y = cpl_vector_wrap(cpl_table_get_nrow(lin_table),
05231                 (double *)cpl_table_get_data_double_const(lin_table,
05232                                   "MED"));
05233         if (opt_nir == NIR) {
05234            x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
05235                              (double *)cpl_table_get_data_double_const(lin_table,                                                                                                 "DIT"));
05236         } else {
05237            x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
05238                              (double *)cpl_table_get_data_double_const(lin_table,                                                                                                 "EXPTIME"));
05239         }
05240         if(x == NULL || y == NULL) {
05241         cpl_vector_unwrap((cpl_vector *)x);
05242         cpl_vector_unwrap((cpl_vector *)y);
05243         /*
05244          * As x and y are const vectors, if they would be defined at the
05245          * beginning of the function (required for skip_if - end_skip
05246          * scheme), they couldn't be initialised to NULL (required too).
05247          * Therefore, they are considered apart from the scheme.
05248          */
05249         skip_if(1);
05250     }
05251 
05252         cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
05253         poly_linfit = cpl_polynomial_fit_1d_create(x, y, order, &mse);
05254 
05255     if(order == cpl_vector_get_size(x) - 1) {
05256         cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
05257         mse = 0;
05258     }
05259 
05260     if(poly_linfit == NULL) {
05261         cpl_vector_unwrap((cpl_vector *)x);
05262         cpl_vector_unwrap((cpl_vector *)y);
05263         /* See comment in previous error checking if() statement */
05264         skip_if(1);
05265     }
05266 
05267     cpl_vector_unwrap((cpl_vector *)x);
05268     cpl_vector_unwrap((cpl_vector *)y);
05269 
05270         for(i = 0; i <= order; i++) {
05271             const double            coeff =
05272                 cpl_polynomial_get_coeff(poly_linfit, &i);
05273             char                   *name_o =
05274                 cpl_sprintf("ESO QC LIN COEF%d", i);
05275             assert(name_o != NULL);
05276             skip_if(cpl_propertylist_append_double(qclist, name_o, coeff));
05277             skip_if(cpl_propertylist_set_comment(qclist,name_o,
05278                          DETMON_QC_LIN_COEF_C));
05279             cpl_free(name_o);
05280         pcoeffs[i] = coeff;
05281         }
05282     skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT, mse));
05283             skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
05284                          DETMON_QC_ERRFIT_MSE_C));
05285 
05286 
05287     } else {
05288        if (opt_nir == NIR) {
05289           x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
05290                 (double *)cpl_table_get_data_double_const(lin_table,
05291                                                                       "DIT"));
05292        } else {
05293           x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
05294                 (double *)cpl_table_get_data_double_const(lin_table,
05295                                                                       "EXPTIME"));
05296        }
05297 
05298 
05299        first = cpl_imagelist_get_const(lin_inputs, 0);
05300        sizex = cpl_image_get_size_x(first);
05301        sizey = cpl_image_get_size_y(first);
05302 
05303        vsize = cpl_vector_get_size(x);
05304 
05305     fiterror = cpl_image_new(sizex, sizey, CPL_TYPE_FLOAT);
05306 
05307         *coeffs_cube =
05308             cpl_fit_imagelist_polynomial(x, lin_inputs, 0,
05309                                          order, FALSE, CPL_TYPE_FLOAT,
05310                      fiterror);
05311 
05312     cpl_vector_unwrap((cpl_vector*)x);
05313     irplib_ensure(*coeffs_cube != NULL, CPL_ERROR_UNSPECIFIED, 
05314               "Failed polynomial fit");
05315     
05316         for(i = 0; i <= order; i++) {
05317             cpl_image              *image = cpl_imagelist_get(*coeffs_cube, i);
05318         const double coeff = cpl_image_get_median(image);
05319             char * name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
05320             char * name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
05321         pcoeffs[i] = coeff;
05322             assert(name_o1 != NULL);
05323             assert(name_o2 != NULL);
05324             skip_if(cpl_propertylist_append_double(qclist, name_o1, coeff));
05325             skip_if(cpl_propertylist_set_comment(qclist,name_o1,
05326                          DETMON_QC_LIN_COEF_C));
05327             cpl_free(name_o1);
05328         name_o1= NULL;
05329             skip_if(cpl_propertylist_append_double(qclist, name_o2,
05330                        cpl_image_get_stdev(image)));
05331             skip_if(cpl_propertylist_set_comment(qclist,name_o2,
05332                          DETMON_QC_LIN_COEF_ERR_C));
05333             cpl_free(name_o2);
05334         name_o2= NULL;
05335         }
05336 
05337     if(order == vsize - 1) {
05338         cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
05339         skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
05340                            0.0));
05341             skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
05342                          DETMON_QC_ERRFIT_C));
05343 
05344 
05345     } else {
05346         skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
05347                            cpl_image_get_median(fiterror)));
05348             skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
05349                          DETMON_QC_ERRFIT_C));
05350 
05351     }
05352     }
05353 
05354     skip_if(irplib_detmon_lg_lineff(pcoeffs, qclist, ref_level, order));
05355 
05356     if(mode & IRPLIB_LIN_PIX2PIX) {
05357     int nbpixs;
05358         *bpm = irplib_detmon_bpixs(*coeffs_cube, bpmbin, kappa, &nbpixs);
05359     skip_if(*bpm == NULL);
05360     skip_if(cpl_propertylist_append_int(qclist, DETMON_QC_NUM_BPM,
05361                         nbpixs));
05362     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_NUM_BPM,
05363                          DETMON_QC_NUM_BPM_C));
05364     }
05365 
05366     end_skip;
05367 
05368     cpl_vector_delete(diffdits);
05369     cpl_polynomial_delete(poly_linfit);
05370     cpl_imagelist_delete(lin_inputs);
05371     cpl_vector_delete(vcoeffs);
05372     cpl_image_delete(fiterror);
05373 
05374     return lin_table;
05375 
05376 }
05377 
05378 /*--------------------------------------------------------------------------*/
05402 /*--------------------------------------------------------------------------*/
05403 static cpl_error_code
05404 irplib_detmon_lin_table_fill_row(cpl_table * lin_table, double c_dit,
05405                  cpl_imagelist * linearity_inputs,
05406                  const cpl_imagelist * ons,
05407                  const cpl_imagelist * offs,
05408                  int llx,
05409                  int lly,
05410                  int urx,
05411                  int ury,
05412                  const int pos,
05413                                  const int nskip,
05414                  unsigned mode)
05415 {
05416     cpl_image              * dif1=NULL;
05417     cpl_image              * dif2=NULL;
05418     cpl_image              * dif_avg=NULL;
05419 
05420     double                   med_dit=0;
05421     double                   mean_dit=0;
05422     cpl_error_code           error;
05423     cpl_image * extracted=NULL;
05424     int offsize=0;
05425 
05426     cpl_ensure_code(lin_table != NULL, CPL_ERROR_NULL_INPUT);
05427     cpl_ensure_code(ons != NULL, CPL_ERROR_NULL_INPUT);
05428     cpl_ensure_code(offs != NULL, CPL_ERROR_NULL_INPUT);
05429 
05430     if (mode & IRPLIB_LIN_PIX2PIX) {
05431        cpl_msg_debug(cpl_func,"checking linearity inputs");
05432     cpl_ensure_code(linearity_inputs != NULL, CPL_ERROR_NULL_INPUT);
05433     }
05434 
05435 
05436     if (mode & IRPLIB_LIN_NIR) {
05437     cpl_table_set(lin_table, "DIT", pos, c_dit);
05438     } else if (mode & IRPLIB_LIN_OPT) { /*OPT */
05439         cpl_table_set(lin_table, "EXPTIME", pos, c_dit);
05440     } else {
05441     cpl_msg_error(cpl_func, "Mandatory mode not given");
05442     }
05443 
05444 
05445     offsize = cpl_imagelist_get_size(offs);
05446 
05447     /* Algorithm defined: substract ON - OFF and average 2 differences */
05448     dif1 = cpl_image_subtract_create(cpl_imagelist_get_const(ons, 0),
05449                                      cpl_imagelist_get_const(offs, 0));
05450 
05451     if (mode & IRPLIB_LIN_NO_COLLAPSE && offsize > 1)
05452         dif2 = cpl_image_subtract_create(cpl_imagelist_get_const(ons, 1),
05453                                          cpl_imagelist_get_const(offs, 1));
05454     else 
05455         dif2 = cpl_image_subtract_create(cpl_imagelist_get_const(ons, 1),
05456                                          cpl_imagelist_get_const(offs, 0)); 
05457 
05458     dif_avg = cpl_image_average_create(dif1, dif2);
05459 
05460     cpl_image_abs(dif_avg);
05461     extracted = cpl_image_extract(dif_avg, llx, lly, urx, ury);
05462 
05463     cpl_ensure_code(extracted != NULL, cpl_error_get_code());
05464 
05465     cpl_table_set(lin_table, "MED", pos, cpl_image_get_median(extracted));
05466     cpl_table_set(lin_table, "MEAN", pos, cpl_image_get_mean(extracted));
05467     med_dit = cpl_image_get_median(extracted) / c_dit;
05468     mean_dit = cpl_image_get_mean(extracted)  / c_dit;
05469 
05470     cpl_table_set(lin_table, "MED_DIT", pos, med_dit);
05471     cpl_table_set(lin_table, "MEAN_DIT", pos, mean_dit);
05472 
05473     cpl_image_delete(dif1);
05474     cpl_image_delete(dif2);
05475 
05476     /* Insert to the imagelist used to fit the polynomial */
05477     if(mode & IRPLIB_LIN_PIX2PIX) {
05478         error = cpl_imagelist_set(linearity_inputs, extracted, pos-nskip);
05479         cpl_ensure_code(!error, error);
05480     } else {
05481         cpl_image_delete(extracted);
05482     }
05483 
05484 
05485     cpl_image_delete(dif_avg);
05486 
05487     return cpl_error_get_code();
05488 }

Generated on Fri Jul 3 11:15:22 2009 for VISIR Pipeline Reference Manual by  doxygen 1.5.8