GIRAFFE Pipeline Reference Manual

irplib_detmon_lg.c

00001 /* $Id: irplib_detmon_lg.c,v 1.3 2009/02/24 13:26:47 rpalsa 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: rpalsa $
00023  * $Date: 2009/02/24 13:26:47 $
00024  * $Revision: 1.3 $
00025  * $Name: giraffe-2_8_1 $
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     /* FIXME: This should go before the x and y vectors.
03810        Checking for all the inputs */
03811     cpl_ensure_code(qclist != NULL, CPL_ERROR_NULL_INPUT);
03812 
03813     skip_if(cpl_propertylist_append_string(qclist, DETMON_QC_METHOD,
03814                        detmon_lg_config.method));
03815     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_METHOD,
03816                      DETMON_QC_METHOD_C));
03817 
03818     if (!strcmp(detmon_lg_config.method, "PTC")) {
03819     /* Computation of GAIN via polynomial fit */
03820     if (detmon_lg_config.exts >= 0) { 
03821         cpl_msg_info(cpl_func,
03822              "Polynomial fitting for the GAIN (constant term method)");
03823     } else {
03824         cpl_msg_info(cpl_func,
03825              "Polynomial fitting for the GAIN (constant term method)"
03826              " for extension nb %d", which_ext);
03827     }
03828     skip_if(irplib_detmon_lg_qc_ptc(gain_table, qclist, mode));
03829     } else {
03830     skip_if(irplib_detmon_lg_qc_med(gain_table, qclist));
03831     }
03832 
03833     /*^FIXME: This shouldn't be written when no applied */
03834     /* Lamp flux */
03835     if(detmon_lg_config.lamp_ok) {
03836     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LAMP_FLUX,
03837                            detmon_lg_config.cr));
03838     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LAMP_FLUX,
03839                          DETMON_QC_LAMP_FLUX_C));
03840     }
03841 
03842     /*^FIXME: This shouldn't be written when no applied */
03843     if(detmon_lg_config.autocorr == TRUE) {
03844     autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
03845     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_AUTOCORR,
03846                            autocorr));
03847     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_AUTOCORR,
03848                          DETMON_QC_AUTOCORR_C));
03849     }
03850     if (detmon_lg_config.exts >= 0) { 
03851         cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix");
03852     } else {
03853         cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix"
03854                                " for extension nb %d", which_ext);
03855     }
03856 
03857     if(!detmon_lg_config.pix2pix) {
03858     double mse = 0;
03859         /* Computation of LINEARITY via polynomial fit */
03860     y = cpl_vector_wrap(nsets,
03861                 (double *)cpl_table_get_data_double_const(linear_table,
03862                                   "MED"));
03863 
03864     if (opt_nir == NIR) 
03865         x = cpl_vector_wrap(nsets,
03866                 (double *)cpl_table_get_data_double_const(linear_table,
03867                                   "DIT"));
03868     else
03869         x = cpl_vector_wrap(nsets,
03870                 (double *)cpl_table_get_data_double_const(linear_table,
03871                                   "EXPTIME"));
03872 
03873 
03874         if(x == NULL || y == NULL) {
03875         cpl_vector_unwrap((cpl_vector *)x);
03876         cpl_vector_unwrap((cpl_vector *)y);
03877         /*
03878          * As x and y are const vectors, if they would be defined at the
03879          * beginning of the function (required for skip_if - end_skip
03880          * scheme), they couldn't be initialised to NULL (required too).
03881          * Therefore, they are considered apart from the scheme.
03882          */
03883         skip_if(1);
03884     }
03885 
03886         cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
03887         poly_linfit = cpl_polynomial_fit_1d_create(x, y,
03888                            detmon_lg_config.order,
03889                            &mse);
03890 
03891     if(detmon_lg_config.order == cpl_vector_get_size(x) - 1) {
03892         cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
03893         mse = 0;
03894     }
03895 
03896     if(poly_linfit == NULL) {
03897         cpl_vector_unwrap((cpl_vector *)x);
03898         cpl_vector_unwrap((cpl_vector *)y);
03899         /* See comment in previous error checking if() statement */
03900         skip_if(1);
03901     }
03902 
03903     
03904         min_val=cpl_vector_get_min(y);
03905         max_val=cpl_vector_get_max(y);
03906 
03907     cpl_vector_unwrap((cpl_vector *)x);
03908     cpl_vector_unwrap((cpl_vector *)y);
03909 
03910         for(i = 0; i <= detmon_lg_config.order; i++) {
03911             const double            coeff =
03912                 cpl_polynomial_get_coeff(poly_linfit, &i);
03913             char                   *name_o =
03914                 cpl_sprintf("ESO QC LIN COEF%d", i);
03915             assert(name_o != NULL);
03916             skip_if(cpl_propertylist_append_double(qclist, name_o, coeff));
03917             skip_if(cpl_propertylist_set_comment(qclist,name_o,
03918                          DETMON_QC_LIN_COEF_C));
03919 
03920             cpl_free(name_o);
03921         pcoeffs[i] = coeff;
03922         }
03923     skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT, mse));
03924         skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
03925                          DETMON_QC_ERRFIT_MSE_C));
03926 
03927 
03928     } else {
03929 
03930 
03931     y = cpl_vector_wrap(nsets,
03932                 (double *)cpl_table_get_data_double_const(linear_table,
03933                                   "MED"));
03934 
03935       if (opt_nir == NIR) {
03936          x=
03937         cpl_vector_wrap(nsets,
03938                 (double *)cpl_table_get_data_double_const(linear_table,
03939                                   "DIT"));
03940 
03941       } else {
03942 
03943     x =
03944         cpl_vector_wrap(nsets,
03945                 (double *)cpl_table_get_data_double_const(linear_table,
03946                                   "EXPTIME"));
03947 
03948       }
03949 
03950 
03951     const cpl_image * first = cpl_imagelist_get_const(linearity_inputs, 0);
03952     int sizex = cpl_image_get_size_x(first);
03953     int sizey = cpl_image_get_size_y(first);
03954 
03955     double vsize = cpl_vector_get_size(x);
03956 
03957     fiterror = cpl_image_new(sizex, sizey, CPL_TYPE_FLOAT);
03958 
03959     *coeffs_ptr =
03960         cpl_fit_imagelist_polynomial(x, linearity_inputs, 0,
03961                      detmon_lg_config.order, FALSE,
03962                      CPL_TYPE_FLOAT, fiterror);
03963 
03964         min_val=cpl_vector_get_min(y);
03965         max_val=cpl_vector_get_max(y);
03966 
03967 
03968     cpl_vector_unwrap((cpl_vector*)x);
03969     cpl_vector_unwrap((cpl_vector*)y);
03970     irplib_ensure(*coeffs_ptr != NULL, CPL_ERROR_UNSPECIFIED, 
03971               "Failed polynomial fit");
03972 
03973         for(i = 0; i <= detmon_lg_config.order; i++) {
03974             cpl_image              *image = cpl_imagelist_get(*coeffs_ptr, i);
03975         const double coeff = cpl_image_get_median(image);
03976         pcoeffs[i] = coeff;
03977             name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
03978             name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
03979             assert(name_o1 != NULL);
03980             assert(name_o2 != NULL);
03981             skip_if(cpl_propertylist_append_double(qclist, name_o1, coeff));
03982             skip_if(cpl_propertylist_set_comment(qclist,name_o1,
03983                          DETMON_QC_LIN_COEF_C));
03984             cpl_free(name_o1);
03985         name_o1= NULL;
03986             skip_if(cpl_propertylist_append_double(qclist, name_o2,
03987                        cpl_image_get_stdev(image)));
03988             skip_if(cpl_propertylist_set_comment(qclist,name_o2,
03989                          DETMON_QC_LIN_COEF_ERR_C));
03990             cpl_free(name_o2);
03991         name_o2= NULL;
03992         }
03993 
03994     if(detmon_lg_config.order == vsize - 1) {
03995         cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
03996         skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
03997                            0.0));
03998             skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
03999                          DETMON_QC_ERRFIT_C));
04000 
04001 
04002 
04003     } else {
04004         skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
04005                            cpl_image_get_median(fiterror)));
04006             skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
04007                          DETMON_QC_ERRFIT_C));
04008 
04009     }
04010     }
04011 
04012 
04013     skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_COUNTS_MIN,
04014                                            min_val));
04015 
04016     skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_COUNTS_MIN,
04017                                          DETMON_QC_COUNTS_MIN_C));
04018 
04019     skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_COUNTS_MAX,
04020                                            max_val));
04021 
04022     skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_COUNTS_MAX,
04023                                          DETMON_QC_COUNTS_MAX_C));
04024 
04025     skip_if(irplib_detmon_lg_lineff(pcoeffs,qclist,detmon_lg_config.ref_level,
04026                                     detmon_lg_config.order));
04027 
04028     /* Detection of bad pixels */
04029     if (detmon_lg_config.exts >= 0) { 
04030         cpl_msg_info(cpl_func, "Bad pixel detection");
04031     } else {
04032         cpl_msg_info(cpl_func, "Bad pixel detection"
04033              " for extension nb %d", which_ext);
04034     }
04035 
04036     if(detmon_lg_config.pix2pix) {
04037        *bpms_ptr = irplib_detmon_bpixs(*coeffs_ptr, detmon_lg_config.bpmbin, 
04038                                        detmon_lg_config.kappa, &nbpixs);
04039     skip_if(*bpms_ptr == NULL);
04040     }
04041 
04042     skip_if(cpl_propertylist_append_int(qclist, DETMON_QC_NUM_BPM, nbpixs));
04043     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_NUM_BPM,
04044                                          DETMON_QC_NUM_BPM_C));
04045 
04046     if(detmon_lg_config.lamp_stability != 0.0) {
04047     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LAMP_STAB,
04048                            detmon_lg_config.lamp_stability));
04049     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LAMP_STAB,
04050                          DETMON_QC_LAMP_STAB_C));
04051     }
04052     end_skip;
04053 
04054     cpl_free(pcoeffs);
04055     cpl_free(name_o1);
04056     cpl_free(name_o2);
04057     cpl_image_delete(fiterror);
04058     cpl_polynomial_delete(poly_linfit);
04059 
04060     return cpl_error_get_code();
04061 }
04062 
04063 /*---------------------------------------------------------------------------*/
04071 /*---------------------------------------------------------------------------*/
04072 static cpl_error_code
04073 irplib_detmon_lg_lineff(double * pcoeffs,
04074                         cpl_propertylist * qclist,
04075                         int ref_level, 
04076                         int order)
04077 {
04078     double           lineff = 0;
04079     double           root = 0;
04080     cpl_polynomial * poly = cpl_polynomial_new(1);
04081     int i;
04082 
04083     double residual, slope;
04084 
04085     /*
04086      * Construction of the polynomial F_m(F_r) from F_m(t),
04087      * using F_r = a_1 * t.
04088      */
04089     pcoeffs[0] -= ref_level;
04090 
04091     for (i = 2; i <= order; i++) {
04092     int j;
04093     for(j = 0; j < i; j++) {
04094         pcoeffs[i] /= pcoeffs[1];
04095     }
04096     }
04097 
04098     pcoeffs[1] = 1;
04099 
04100     for (i = 0; i <= order; i++) {
04101     skip_if(cpl_polynomial_set_coeff(poly, &i, pcoeffs[i]));
04102     }
04103 
04104     /*
04105      * Verification of validity of first guess (0).
04106      * The root to be found will be in the same interval of monotony
04107      * of the first guess; therefore, slope must be greater than 0.
04108      * Slope > 0 and poly(root) = 0 force also residual to be negative.
04109      */
04110     residual = cpl_polynomial_eval_1d(poly, 0.0, &slope);
04111 
04112     if (slope <= 0.0 && residual >= 0.0) {
04113     cpl_msg_warning(cpl_func, "Reference level (--ref_level) outside"
04114             " linearity range of the detector. Cannot compute"
04115             " linearity efficiency (QC.LINEFF).");
04116     lineff = -1;
04117     } else {
04118     skip_if(cpl_polynomial_solve_1d(poly, 0.0, &root, 1));
04119 
04120     lineff = (root - ref_level) / ref_level;
04121     }
04122 
04123     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LIN_EFF,
04124                        lineff));
04125     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LIN_EFF,
04126                      DETMON_QC_LIN_EFF_C));
04127 
04128     end_skip;
04129 
04130     cpl_polynomial_delete(poly);
04131 
04132     return cpl_error_get_code();
04133 }
04134 
04135 /*---------------------------------------------------------------------------*/
04142 /*---------------------------------------------------------------------------*/
04143 static cpl_error_code
04144 irplib_detmon_lg_qc_ptc(const cpl_table  * gain_table,
04145             cpl_propertylist * qclist, unsigned mode)
04146 {
04147     double                  mse = 0;
04148     cpl_polynomial         *poly_fit = NULL;
04149     cpl_polynomial         *poly_fit2 = NULL;
04150     int i;
04151     const int               nsets = cpl_table_get_nrow(gain_table);
04152 
04153     /* The following 2 vectors are declared 'const' as they shouldn't be 
04154        modified. However, the data to be wrapped are casted as 'non-const'
04155        to avoid warning in cpl_vector_wrap, where API is 'non-const' */
04156 
04157     const cpl_vector             *x;
04158     const cpl_vector             *y;
04159 
04160     cpl_errorstate                prestate;
04161     double coef = 0;
04162 
04163     cpl_ensure_code(gain_table != NULL, CPL_ERROR_NULL_INPUT);
04164     cpl_ensure_code(qclist     != NULL, CPL_ERROR_NULL_INPUT);
04165 
04166     x = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT"));
04167     
04168     y = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
04169 
04170     skip_if(x == NULL || y == NULL);
04171 
04172     poly_fit = cpl_polynomial_fit_1d_create(x, y, 1, &mse);
04173     skip_if(poly_fit == NULL);
04174 
04175     /* Write the QC params corresponding to the fitting of the GAIN */
04176     i = 1;
04177     prestate = cpl_errorstate_get();
04178     coef = cpl_polynomial_get_coeff(poly_fit, &i);
04179     skip_if (!cpl_errorstate_is_equal(prestate) || coef == 0);
04180 
04181     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD, coef));
04182     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
04183                      DETMON_QC_CONAD_C));
04184 
04185     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,
04186                        1 / coef));
04187     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
04188                      DETMON_QC_GAIN_C));
04189 
04190     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE, mse));
04191     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
04192                      DETMON_QC_GAIN_MSE_C));
04193     i = 0;
04194     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_RON,
04195                        cpl_polynomial_get_coeff(poly_fit, &i)));
04196     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_RON,
04197                      DETMON_QC_RON_C));
04198     
04199     if(mode & IRPLIB_GAIN_WITH_AUTOCORR){
04200     const cpl_vector             *x2 =
04201         cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT_CORR"));
04202     const cpl_vector             *y2 =
04203         cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
04204 
04205     if(x2 == NULL || y2 == NULL) {
04206         cpl_vector_unwrap((cpl_vector *)x2);
04207         cpl_vector_unwrap((cpl_vector *)y2);
04208         /*
04209          * As x and y are const vectors, if they would be defined at the
04210          * beginning of the function (required for skip_if - end_skip
04211          * scheme), they couldn't be initialised to NULL (required too).
04212          * Therefore, they are considered apart from the scheme.
04213          */
04214         skip_if(1);
04215     }
04216 
04217     /* Revise mse, maybe used afterwards */
04218     poly_fit2 = cpl_polynomial_fit_1d_create(x2, y2, 1, &mse);
04219     if(poly_fit2 == NULL) {
04220         cpl_vector_unwrap((cpl_vector *)x2);
04221         cpl_vector_unwrap((cpl_vector *)y2);
04222         /* See comment in previous error checking if() statement */
04223         skip_if(1);
04224     }
04225 
04226     cpl_vector_unwrap((cpl_vector *)x2);
04227     cpl_vector_unwrap((cpl_vector *)y2);
04228 
04229     /* Write the QC params corresponding to the fitting of the GAIN */
04230     i = 1;
04231     prestate = cpl_errorstate_get();
04232     coef = cpl_polynomial_get_coeff(poly_fit2, &i);
04233     skip_if (!cpl_errorstate_is_equal(prestate) || coef == 0);
04234 
04235     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
04236                            1 / coef));
04237     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
04238                          DETMON_QC_GAIN_CORR_C));
04239     }
04240 
04241     end_skip;
04242 
04243     /* Cast back to 'non-const' to avoid warning. See comment above */
04244     cpl_vector_unwrap((cpl_vector *)x);
04245     cpl_vector_unwrap((cpl_vector *)y);
04246     cpl_polynomial_delete(poly_fit);
04247     cpl_polynomial_delete(poly_fit2);
04248 
04249     return cpl_error_get_code();
04250 }
04251 
04252 /*---------------------------------------------------------------------------*/
04261 /*---------------------------------------------------------------------------*/
04262 static cpl_error_code
04263 irplib_detmon_lg_qc_med(const cpl_table * gain_table,
04264                 cpl_propertylist * qclist)
04265 {
04266 
04267    double gain=0;
04268    gain=cpl_table_get_column_median(gain_table, "GAIN");
04269 
04270    skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,gain));
04271 
04272    skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
04273                                         DETMON_QC_GAIN_C));
04274 
04275    skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE,
04276                                           cpl_table_get_column_stdev
04277                                           (gain_table, "GAIN")));
04278    skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
04279                                         DETMON_QC_GAIN_MSE_C));
04280 
04281    skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD,1./gain));
04282    skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
04283                                         DETMON_QC_CONAD_C));
04284 
04285 
04286    gain=cpl_table_get_column_median(gain_table, "GAIN_CORR");
04287 
04288    skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
04289                                           gain));
04290    skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
04291                                         DETMON_QC_GAIN_CORR_C));
04292 
04293 
04294    skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD_CORR,1./gain));
04295    skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD_CORR,
04296                                         DETMON_QC_CONAD_CORR_C));
04297 
04298 
04299     end_skip;
04300 
04301     return cpl_error_get_code();
04302 }
04303 
04304 
04305 /*---------------------------------------------------------------------------*/
04314 /*---------------------------------------------------------------------------*/
04315 static cpl_error_code
04316 irplib_detmon_lg_rescale(cpl_imagelist * to_rescale)
04317 {
04318     double                  med1 =
04319         cpl_image_get_median(cpl_imagelist_get(to_rescale, 0));
04320     double                  med2 =
04321         cpl_image_get_median(cpl_imagelist_get(to_rescale, 1));
04322 
04323     skip_if(0);
04324 
04325     if(fabs(med1 / med2 - 1) > 0.001) {
04326         if(med1 > med2)
04327             skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 0),
04328                                             med1 / med2));
04329         else
04330             skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 1),
04331                                             med2 / med1));
04332     }
04333     
04334     end_skip;
04335 
04336     return cpl_error_get_code();
04337 }
04338 
04339 /*---------------------------------------------------------------------------*/
04357 /*---------------------------------------------------------------------------*/
04358 static cpl_error_code
04359 irplib_detmon_pair_extract(const cpl_frameset * set,
04360                            int * selection, int selected,
04361                            int nsets_extracted,
04362                            int * with_equal_dit,
04363                            int onoff,
04364                            cpl_frameset ** pair)
04365 {
04366     int new_with_equal_dit = 0;
04367 
04368     cpl_ensure_code(set             != NULL, CPL_ERROR_NULL_INPUT);
04369     cpl_ensure_code(selection       != NULL, CPL_ERROR_NULL_INPUT);
04370     cpl_ensure_code(with_equal_dit  != NULL, CPL_ERROR_NULL_INPUT);
04371     cpl_ensure_code(pair            != NULL, CPL_ERROR_NULL_INPUT);
04372 
04373     *pair = cpl_frameset_extract(set, selection, selected);
04374     cpl_ensure_code(*pair != NULL, cpl_error_get_code());
04375 
04376     /* FIXME: Error checkin to be done here */
04377 
04378     /* It must be even (a single pair or multiple pairs of same DIT) */
04379     skip_if(cpl_frameset_get_size(*pair) % 2 != 0);
04380 
04381     /* See how many pairs with same DIT */
04382     if(cpl_frameset_get_size(*pair) != 2) {
04383         new_with_equal_dit = cpl_frameset_get_size(*pair) / 2;
04384         if(onoff == 1) {
04385             *with_equal_dit = new_with_equal_dit;
04386         } else {
04387             skip_if (*with_equal_dit    != 0 &&
04388              new_with_equal_dit != *with_equal_dit);
04389         }
04390     }
04391 
04392     /* If more than a pair, update selection array */
04393     if (new_with_equal_dit != 0) {
04394         int                     found = 0;
04395         int j;
04396         for(j = 0; j < cpl_frameset_get_size(set); j++) {
04397 
04398             if(selection[j] == selected) {
04399                 found++;
04400 
04401                 if((found - 1) / 2 != 0) {
04402                     selection[j] =
04403                         nsets_extracted + (found - 1) / 2 - 1;
04404                 }
04405             }
04406         }
04407         cpl_frameset_delete(*pair);
04408         *pair = cpl_frameset_extract(set, selection, selected);
04409         /* FIXME: Error checking missing here */
04410     }
04411 
04412     end_skip;
04413 
04414     return cpl_error_get_code();
04415 }
04416 /*---------------------------------------------------------------------------*/
04434 /*---------------------------------------------------------------------------*/
04435 static cpl_error_code
04436 irplib_detmon_single_extract(const cpl_frameset * set,
04437                  int * selection, int selected,
04438                  int nsets_extracted,
04439                  int * with_equal_dit,
04440                  int onoff,
04441                  cpl_frameset ** single)
04442 {
04443     int new_with_equal_dit = 0;
04444 
04445     cpl_ensure_code(set             != NULL, CPL_ERROR_NULL_INPUT);
04446     cpl_ensure_code(selection       != NULL, CPL_ERROR_NULL_INPUT);
04447     cpl_ensure_code(with_equal_dit  != NULL, CPL_ERROR_NULL_INPUT);
04448     cpl_ensure_code(single          != NULL, CPL_ERROR_NULL_INPUT);
04449 
04450     *single = cpl_frameset_extract(set, selection, selected);
04451     cpl_ensure_code(*single != NULL, cpl_error_get_code());
04452 
04453     /* FIXME: Error checkin to be done here */
04454 
04455     /* See how many singles with same DIT */
04456     if(cpl_frameset_get_size(*single) != 1) {
04457         new_with_equal_dit = cpl_frameset_get_size(*single);
04458         if(onoff == 1) {
04459             *with_equal_dit = new_with_equal_dit;
04460         } else {
04461             skip_if (*with_equal_dit    != 0 &&
04462              new_with_equal_dit != *with_equal_dit);
04463         }
04464     }
04465 
04466     /* If more than a single, update selection array */
04467     if (new_with_equal_dit != 0) {
04468         int                     found = 0;
04469         int j;
04470         for(j = 0; j < cpl_frameset_get_size(set); j++) {
04471 
04472             if(selection[j] == selected) {
04473                 found++;
04474 
04475                 if(found > 1) {
04476                     selection[j] =
04477                         nsets_extracted + (found - 2);
04478                 }
04479             }
04480         }
04481         cpl_frameset_delete(*single);
04482         *single = cpl_frameset_extract(set, selection, selected);
04483         /* FIXME: Error checking missing here */
04484     }
04485 
04486     end_skip;
04487 
04488     return cpl_error_get_code();
04489 }
04490 /*--------------------------------------------------------------------------*/
04491 
04492 /*
04493  * @brief    Comparison function to identify different settings
04494  * @param    frame1  First frame 
04495  * @param    frame2  Second frame 
04496  * @return   0 if different, 1 if equal, -1 in error case
04497  */
04498 
04499 /*--------------------------------------------------------------------------*/
04500 
04501 static int
04502 irplib_detmon_lg_compare_pairs(const cpl_frame * frame1,
04503                    const cpl_frame * frame2)
04504 {
04505     int                     comparison;
04506     cpl_propertylist       *plist1;
04507     cpl_propertylist       *plist2;
04508     double                  dval1, dval2;
04509 
04510     /* Test entries */
04511     if(frame1 == NULL || frame2 == NULL)
04512         return -1;
04513 
04514     /* Get property lists */
04515     if((plist1 = cpl_propertylist_load(cpl_frame_get_filename(frame1),
04516                                        0)) == NULL) {
04517         cpl_msg_error(cpl_func, "getting header from reference frame");
04518         return -1;
04519     }
04520     if((plist2 = cpl_propertylist_load(cpl_frame_get_filename(frame2),
04521                                        0)) == NULL) {
04522         cpl_msg_error(cpl_func, "getting header from reference frame");
04523         cpl_propertylist_delete(plist1);
04524         return -1;
04525     }
04526 
04527     /* Test status */
04528     if(cpl_error_get_code()) {
04529         cpl_propertylist_delete(plist1);
04530         cpl_propertylist_delete(plist2);
04531         return -1;
04532     }
04533 
04534     /* Compare exposure time */
04535     comparison = 1;
04536     dval1 = irplib_pfits_get_exptime(plist1);
04537     dval2 = irplib_pfits_get_exptime(plist2);
04538     if(cpl_error_get_code()) {
04539         cpl_msg_error(cpl_func, "cannot get exposure time");
04540         cpl_propertylist_delete(plist1);
04541         cpl_propertylist_delete(plist2);
04542         return -1;
04543     }
04544     if(fabs(dval1 - dval2) > detmon_lg_config.tolerance)
04545         comparison = 0;
04546 
04547     /* Free and return */
04548     cpl_propertylist_delete(plist1);
04549     cpl_propertylist_delete(plist2);
04550     return comparison;
04551 }
04552 
04553 /*---------------------------------------------------------------------------*/
04642 /*---------------------------------------------------------------------------*/
04643 
04644 cpl_table *
04645 irplib_detmon_gain(const cpl_imagelist  * imlist_on,
04646            const cpl_imagelist  * imlist_off,
04647            const cpl_vector     * exptimes,
04648            double                 tolerance,
04649            int                    llx,
04650            int                    lly,
04651            int                    urx,
04652            int                    ury,
04653                    double                 kappa,
04654                    int                    nclip,
04655                    int                    xshift,
04656                    int                    yshift,
04657            cpl_propertylist     * qclist,
04658            unsigned               mode,
04659            cpl_imagelist       ** diff_imlist,
04660            cpl_imagelist       ** autocorr_imlist)
04661 {
04662     cpl_table     * gain_table   = NULL;
04663     cpl_imagelist * difflist     = NULL;
04664     cpl_imagelist * autocorrlist = NULL;
04665     cpl_imagelist * c_onlist     = NULL;
04666     cpl_imagelist * c_offlist    = NULL;
04667     cpl_vector    * diffdits     = NULL;
04668     int             ndiffdits, ndits;
04669     int             i, j;
04670     cpl_boolean     opt_nir      = mode & IRPLIB_GAIN_OPT ? OPT : NIR;
04671 
04672     cpl_ensure(imlist_on  != NULL, CPL_ERROR_NULL_INPUT, NULL);
04673     cpl_ensure(imlist_off != NULL, CPL_ERROR_NULL_INPUT, NULL);
04674     cpl_ensure(exptimes   != NULL, CPL_ERROR_NULL_INPUT, NULL);
04675     cpl_ensure(qclist     != NULL, CPL_ERROR_NULL_INPUT, NULL);
04676 
04677     /* Create table with columns */
04678     gain_table = cpl_table_new(cpl_vector_get_size(exptimes) / 2);
04679     skip_if(irplib_detmon_gain_table_create(gain_table, opt_nir));
04680 
04681     /* Search for different EXPTIME values */
04682     diffdits  = irplib_detmon_lg_find_dits(exptimes, tolerance);
04683     ndiffdits = cpl_vector_get_size(diffdits);
04684 
04685     ndits     = cpl_vector_get_size(exptimes);
04686 
04687     /* AUTOCORR processing requires both. They will become outputs later. */
04688     if (mode & IRPLIB_GAIN_WITH_AUTOCORR && (diff_imlist || autocorr_imlist)) {
04689     difflist     = cpl_imagelist_new();
04690     autocorrlist = cpl_imagelist_new();
04691     }
04692 
04693     if (mode & IRPLIB_GAIN_COLLAPSE) {
04694         if (mode & IRPLIB_GAIN_WITH_RESCALE) {
04695         c_offlist = cpl_imagelist_duplicate(imlist_off);
04696         skip_if(irplib_detmon_lg_rescale(c_offlist));
04697         } else {
04698             c_offlist = (cpl_imagelist *) imlist_off;
04699         }
04700     }
04701 
04702     /* Loop over the different DITs found in EXPTIMEs */
04703     for (i = 0; i < ndiffdits; i++) {
04704         int c_nons;
04705         int c_noffs = 0; /* False (uninit) warning */
04706 
04707     double c_dit = cpl_vector_get(diffdits, i);
04708 
04709     c_onlist  = cpl_imagelist_new();
04710     c_nons = 0;
04711 
04712     if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
04713         c_offlist = cpl_imagelist_new();
04714         c_noffs = 0;
04715     }
04716 
04717     /* Extraction of images of EXPTIME i */
04718     for(j = 0; j < ndits; j++) {
04719         if (fabs(c_dit - cpl_vector_get(exptimes, j)) <= tolerance) {
04720                 /*
04721                  * First we get the corresponding image from the ON imlist. 
04722                  * The option IRPLIB_GAIN_WITH_RESCALE requires to modify
04723                  * the input pixel buffer; therefore we must duplicate it.
04724                  * On the other hand, if this option is not required, there
04725                  * is no need for that duplication. We must only care that
04726                  * c_onlist must not be deleted but only unset.
04727                  */
04728                 cpl_image * im_on;
04729                 if (mode & IRPLIB_GAIN_WITH_RESCALE) {
04730                     const cpl_image * im =
04731                         cpl_imagelist_get_const(imlist_on, j);
04732                     im_on = cpl_image_duplicate(im);
04733                 } else {
04734                     im_on = (cpl_image *)cpl_imagelist_get_const(imlist_on, j);
04735                 }
04736                 skip_if(cpl_imagelist_set(c_onlist, im_on, c_nons));
04737                 c_nons++;
04738 
04739                 /*
04740                  * Same explanation as above but for OFF imlist.
04741                  * Only necessary when IRPLIB_GAIN_NO_COLLAPSE required.
04742                  */
04743         if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
04744                     cpl_image * im_off;
04745                     if (mode & IRPLIB_GAIN_WITH_RESCALE) {
04746                         const cpl_image * im = 
04747                           cpl_imagelist_get_const(imlist_off, j);
04748                         im_off = cpl_image_duplicate(im);
04749                     } else {
04750                         im_off = 
04751                           (cpl_image *) cpl_imagelist_get_const(imlist_off, j);
04752                     }
04753             skip_if(cpl_imagelist_set(c_offlist, im_off, c_noffs));
04754             c_noffs++;
04755         }
04756         }
04757     }
04758 
04759     /* If NO_COLLAPSE, must be the same number of images! */
04760     if (mode & IRPLIB_GAIN_NO_COLLAPSE)
04761         skip_if (c_nons != c_noffs);
04762 
04763     /* There must be pairs! */
04764     skip_if (c_nons == 0 || c_nons % 2 != 0);
04765 
04766     /* Rescaling */
04767     if(mode & IRPLIB_GAIN_WITH_RESCALE) {
04768         skip_if(irplib_detmon_lg_rescale(c_onlist));
04769         if (mode & IRPLIB_GAIN_NO_COLLAPSE)
04770         skip_if(irplib_detmon_lg_rescale(c_offlist));
04771     }
04772         
04773     /* The following loop is necessary for the case of multiple pairs
04774        of same EXPTIME values */
04775     while(c_nons > 0) {
04776         skip_if(irplib_detmon_gain_table_fill_row(gain_table, c_dit,
04777                               autocorrlist,
04778                               difflist, c_onlist,
04779                               c_offlist, kappa, nclip,
04780                                                       llx, lly, urx, ury,
04781                                                       xshift, yshift, i, 
04782 mode));
04783             if (mode & IRPLIB_GAIN_WITH_RESCALE) {
04784                 cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
04785                 cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
04786                 if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
04787                   cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
04788                   cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
04789                 }
04790             } else {
04791             cpl_imagelist_unset(c_onlist, 0);
04792                 skip_if(0);
04793                 cpl_imagelist_unset(c_onlist, 0);
04794                 skip_if(0);
04795                 if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
04796                   cpl_imagelist_unset(c_offlist, 0);
04797                   skip_if(0);
04798                   cpl_imagelist_unset(c_offlist, 0);
04799                   skip_if(0);
04800                 }
04801             }
04802             skip_if(0);
04803         c_nons -= 2;
04804     }
04805 
04806     cpl_imagelist_delete(c_onlist);
04807     if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
04808           cpl_imagelist_delete(c_offlist);
04809     }
04810     }
04811 
04812     /* Computation of GAIN via polynomial fit */
04813     if (mode & IRPLIB_GAIN_PTC) {
04814       skip_if(irplib_detmon_lg_qc_ptc(gain_table, qclist, mode));
04815     } else {
04816     skip_if(irplib_detmon_lg_qc_med(gain_table, qclist));
04817     }
04818 
04819     if(mode & IRPLIB_GAIN_WITH_AUTOCORR) {
04820         double autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
04821     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_AUTOCORR,
04822                            autocorr));
04823     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_AUTOCORR,
04824                          DETMON_QC_AUTOCORR_C));
04825     }
04826 
04827     if (diff_imlist != NULL) *diff_imlist = difflist;
04828     if (autocorr_imlist != NULL) *autocorr_imlist = autocorrlist;
04829 
04830     end_skip;
04831 
04832     cpl_vector_delete(diffdits);
04833 
04834     return gain_table;
04835 }
04836 
04837 static cpl_error_code
04838 irplib_detmon_gain_table_create(cpl_table * gain_table,
04839                                 const cpl_boolean opt_nir)
04840 {
04841     if (opt_nir == NIR) {
04842     skip_if(cpl_table_new_column(gain_table, "DIT",     CPL_TYPE_DOUBLE));
04843     } else { /* OPT */
04844     skip_if(cpl_table_new_column(gain_table, "EXPTIME", CPL_TYPE_DOUBLE));
04845     }
04846     skip_if(cpl_table_new_column(gain_table, "MEAN_ON1",    CPL_TYPE_DOUBLE));
04847     skip_if(cpl_table_new_column(gain_table, "MEAN_ON2",    CPL_TYPE_DOUBLE));
04848     skip_if(cpl_table_new_column(gain_table, "MEAN_OFF1",   CPL_TYPE_DOUBLE));
04849     skip_if(cpl_table_new_column(gain_table, "MEAN_OFF2",   CPL_TYPE_DOUBLE));
04850     skip_if(cpl_table_new_column(gain_table, "SIG_ON_DIF",  CPL_TYPE_DOUBLE));
04851     skip_if(cpl_table_new_column(gain_table, "SIG_OFF_DIF", CPL_TYPE_DOUBLE));
04852     skip_if(cpl_table_new_column(gain_table, "GAIN",        CPL_TYPE_DOUBLE));
04853     skip_if(cpl_table_new_column(gain_table, "AUTOCORR",    CPL_TYPE_DOUBLE));
04854     skip_if(cpl_table_new_column(gain_table, "GAIN_CORR",   CPL_TYPE_DOUBLE));
04855     skip_if(cpl_table_new_column(gain_table, "ADU",         CPL_TYPE_DOUBLE));
04856     skip_if(cpl_table_new_column(gain_table, "X_FIT",       CPL_TYPE_DOUBLE));
04857     skip_if(cpl_table_new_column(gain_table, "X_FIT_CORR",  CPL_TYPE_DOUBLE));
04858     skip_if(cpl_table_new_column(gain_table, "Y_FIT",       CPL_TYPE_DOUBLE));
04859     skip_if(cpl_table_new_column(gain_table, "Y_FIT_CORR",  CPL_TYPE_DOUBLE));
04860 
04861     end_skip;
04862 
04863     return cpl_error_get_code();
04864 }
04865 
04866 static cpl_error_code
04867 irplib_detmon_lin_table_create(cpl_table * lin_table,
04868                                const cpl_boolean opt_nir)
04869 {
04870     if (opt_nir == NIR) {
04871     skip_if(cpl_table_new_column(lin_table, "DIT",     CPL_TYPE_DOUBLE));
04872     } else { /* OPT */
04873     skip_if(cpl_table_new_column(lin_table, "EXPTIME", CPL_TYPE_DOUBLE));
04874     }
04875     skip_if(cpl_table_new_column(lin_table, "MED",      CPL_TYPE_DOUBLE));
04876     skip_if(cpl_table_new_column(lin_table, "MEAN",     CPL_TYPE_DOUBLE));
04877     skip_if(cpl_table_new_column(lin_table, "MED_DIT",  CPL_TYPE_DOUBLE));
04878     skip_if(cpl_table_new_column(lin_table, "MEAN_DIT", CPL_TYPE_DOUBLE));
04879     skip_if(cpl_table_new_column(lin_table, "ADL",      CPL_TYPE_DOUBLE));
04880 
04881     end_skip;
04882 
04883     return cpl_error_get_code();
04884 }
04885 
04886 static cpl_vector *
04887 irplib_detmon_lg_find_dits(const cpl_vector * exptimes,
04888                            double             tolerance)
04889 {
04890     cpl_vector * dits  = cpl_vector_new(cpl_vector_get_size(exptimes) / 2);
04891     int          ndits = 0;
04892 
04893     int          i, j;
04894 
04895     /* First different EXPTIME */
04896     cpl_vector_set(dits, 0, cpl_vector_get(exptimes, 0));
04897     ndits = 1;
04898 
04899     /* Search for all different EXPTIMEs */
04900     for(i = 1; i < cpl_vector_get_size(exptimes); i++) {
04901       int ndiffs = 0;
04902     for (j = 0; j < ndits; j++) {
04903         if (fabs(cpl_vector_get(exptimes, i) -
04904              cpl_vector_get(dits,     j)) > tolerance)
04905               ndiffs++;
04906     }
04907         if(ndiffs == ndits) {
04908           cpl_vector_set(dits, ndits, cpl_vector_get(exptimes, i));
04909           ndits++;
04910         }
04911     }
04912 
04913     cpl_vector_set_size(dits, ndits);
04914 
04915     return dits;
04916 }
04917 
04918 
04919 /*---------------------------------------------------------------------------*/
05000 /*---------------------------------------------------------------------------*/
05001 
05002 cpl_table *
05003 irplib_detmon_lin(const cpl_imagelist  * imlist_on,
05004           const cpl_imagelist  * imlist_off,
05005           const cpl_vector     * exptimes,
05006           double                 tolerance,
05007           int                    llx,
05008           int                    lly,
05009           int                    urx,
05010           int                    ury,
05011           int                    order,
05012                   int                    ref_level,
05013                   double kappa,
05014                   cpl_boolean bpmbin,
05015           cpl_propertylist     * qclist,
05016           unsigned               mode,
05017           cpl_imagelist       ** coeffs_cube,
05018           cpl_image           ** bpm)
05019 {
05020     cpl_table     * lin_table    = NULL;
05021     cpl_imagelist * c_onlist     = NULL;
05022     cpl_imagelist * c_offlist    = NULL;
05023     cpl_vector    * diffdits     = NULL;
05024     cpl_imagelist * lin_inputs   = NULL;
05025     cpl_polynomial * poly_linfit = NULL;
05026     cpl_image     * fiterror     = NULL;
05027     cpl_vector    * vcoeffs      = NULL;
05028     double        * pcoeffs      = NULL;
05029     int             ndiffdits, ndits;
05030     int             i, j;
05031     cpl_boolean     opt_nir      = mode & IRPLIB_LIN_OPT ? OPT : NIR;
05032     const cpl_vector *x = NULL;
05033     const cpl_vector *y = NULL;
05034 
05035 
05036     cpl_ensure(imlist_on  != NULL, CPL_ERROR_NULL_INPUT, NULL);
05037     cpl_ensure(imlist_off != NULL, CPL_ERROR_NULL_INPUT, NULL);
05038     cpl_ensure(exptimes   != NULL, CPL_ERROR_NULL_INPUT, NULL);
05039     cpl_ensure(qclist     != NULL, CPL_ERROR_NULL_INPUT, NULL);
05040     cpl_ensure(order      >  0   , CPL_ERROR_ILLEGAL_INPUT, NULL);
05041     
05042     vcoeffs      = cpl_vector_new(order + 1);
05043     pcoeffs      = cpl_vector_get_data(vcoeffs);
05044 
05045     /* This mode requires optional outputs */
05046     if (mode & IRPLIB_LIN_PIX2PIX) {
05047     lin_inputs = cpl_imagelist_new();
05048     cpl_ensure(coeffs_cube != NULL, CPL_ERROR_NULL_INPUT, NULL);
05049     cpl_ensure(bpm         != NULL, CPL_ERROR_NULL_INPUT, NULL);
05050     }
05051 
05052     /* Create table with columns */
05053     lin_table = cpl_table_new(cpl_vector_get_size(exptimes) / 2);
05054     skip_if(irplib_detmon_lin_table_create(lin_table, opt_nir));
05055 
05056     /* Search for different EXPTIME values */
05057     /* Search for different EXPTIME values */
05058     diffdits  = irplib_detmon_lg_find_dits(exptimes, tolerance);
05059     ndiffdits = cpl_vector_get_size(diffdits);
05060 
05061     ndits     = cpl_vector_get_size(exptimes);
05062 
05063 
05064 
05065 
05066 
05067 
05068 /* TO BE IMPLEMENTED SIMILARLY TO UPPER LEVEL FUNCTION (search for nskip)
05069    if(filter > 0) {
05070     double med1 =
05071         cpl_image_get_median_window(cpl_imagelist_get(imlist_on, 0),
05072                     llx,lly,urx,ury);
05073     double med2 = 
05074            cpl_image_get_median_window(cpl_imagelist_get(imlist_on, 1),
05075                     llx,lly,urx,ury);
05076     if ( med1 > (double)filter ||
05077          med2 > (double)filter) {
05078         follow = CPL_FALSE;
05079         cpl_table_select_row(lin_table, dit_nb);
05080             dit_nskip++;
05081         cpl_msg_warning(cpl_func, "Frames of EXPTIME nb %d "
05082                 "will not be taken into account for computation "
05083                 "as they are above --filter threshold", dit_nb);
05084     }
05085     }
05086 */
05087 
05088 
05089 
05090 
05091     if (mode & IRPLIB_LIN_COLLAPSE) {
05092     /*
05093      * The master bias is required only for 
05094      * linearity computation in the OPT domain
05095      */
05096     cpl_image * collapse = cpl_imagelist_collapse_create(imlist_off);
05097     skip_if(collapse == NULL);
05098 
05099     c_offlist = cpl_imagelist_new();
05100     skip_if(cpl_imagelist_set(c_offlist, collapse, 0));
05101     }
05102 
05103     /* Loop over the different DITs found in EXPTIMEs */
05104     for (i = 0; i < ndiffdits; i++) {
05105         int c_nons;
05106         int c_noffs = 0; /* False (uninit) warning */
05107 
05108     double c_dit = cpl_vector_get(diffdits, i);
05109 
05110     c_onlist  = cpl_imagelist_new();
05111     c_nons = 0;
05112 
05113     if (mode & IRPLIB_LIN_NO_COLLAPSE) {
05114         c_offlist = cpl_imagelist_new();
05115         c_noffs = 0;
05116     }
05117 
05118     for(j = 0; j < ndits; j++) {
05119         if (fabs(c_dit - cpl_vector_get(exptimes, j)) <= tolerance) {
05120                 /*
05121                  * First we get the corresponding image from the ON imlist. 
05122                  * The option IRPLIB_GAIN_WITH_RESCALE requires to modify
05123                  * the input pixel buffer; therefore we must duplicate it.
05124                  * On the other hand, if this option is not required, there
05125                  * is no need for that duplication. We must only care that
05126                  * c_onlist must not be deleted but only unset.
05127                  */
05128                 cpl_image * im_on;
05129                 if (mode & IRPLIB_LIN_WITH_RESCALE) {
05130                     const cpl_image * im =
05131                         cpl_imagelist_get_const(imlist_on, j);
05132                     im_on = cpl_image_duplicate(im);
05133                 } else {
05134                     im_on = (cpl_image *)cpl_imagelist_get_const(imlist_on, j);
05135                 }
05136                 skip_if(cpl_imagelist_set(c_onlist, im_on, c_nons));
05137                 c_nons++;
05138 
05139                 /*
05140                  * Same explanation as above but for OFF imlist.
05141                  * Only necessary when IRPLIB_GAIN_NO_COLLAPSE required.
05142                  */
05143         if (mode & IRPLIB_LIN_NO_COLLAPSE) {
05144                     cpl_image * im_off;
05145                     if (mode & IRPLIB_LIN_WITH_RESCALE) {
05146                         const cpl_image * im = 
05147                           cpl_imagelist_get_const(imlist_off, j);
05148                         im_off = cpl_image_duplicate(im);
05149                     } else {
05150                         im_off = 
05151                           (cpl_image *) cpl_imagelist_get_const(imlist_off, j);
05152                     }
05153             skip_if(cpl_imagelist_set(c_offlist, im_off, c_noffs));
05154             c_noffs++;
05155         }
05156         }
05157     }
05158 
05159     /* If NO_COLLAPSE, must be the same number of images! */
05160     if (mode & IRPLIB_LIN_NO_COLLAPSE)
05161         skip_if (c_nons != c_noffs);
05162 
05163     /* There must be pairs! */
05164     skip_if (c_nons == 0 || c_nons % 2 != 0);
05165 
05166     /* Rescaling */
05167     if(mode & IRPLIB_LIN_WITH_RESCALE) {
05168         skip_if(irplib_detmon_lg_rescale(c_onlist));
05169         if (mode & IRPLIB_LIN_NO_COLLAPSE)
05170         skip_if(irplib_detmon_lg_rescale(c_offlist));
05171     }
05172         
05173     /* The following loop is necessary for the case of multiple pairs
05174        of same EXPTIME values */
05175     while(c_nons > 0) {
05176 
05177         skip_if(irplib_detmon_lin_table_fill_row(lin_table, c_dit,
05178                              lin_inputs,
05179                              c_onlist, c_offlist,
05180                              llx, lly, urx, ury,
05181                              i, 0, mode));
05182 
05183             if (mode & IRPLIB_LIN_WITH_RESCALE) {
05184                 cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
05185                 cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
05186                 if (mode & IRPLIB_LIN_NO_COLLAPSE) {
05187                   cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
05188                   cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
05189                 }
05190             } else {
05191             cpl_imagelist_unset(c_onlist, 0);
05192                 skip_if(0);
05193                 cpl_imagelist_unset(c_onlist, 0);
05194                 skip_if(0);
05195                 if (mode & IRPLIB_LIN_NO_COLLAPSE) {
05196                   cpl_imagelist_unset(c_offlist, 0);
05197                   skip_if(0);
05198                   cpl_imagelist_unset(c_offlist, 0);
05199                   skip_if(0);
05200                 }
05201             }
05202             skip_if(0);
05203         c_nons -= 2;
05204     }
05205 
05206     cpl_imagelist_delete(c_onlist);
05207     if (mode & IRPLIB_LIN_NO_COLLAPSE) {
05208           cpl_imagelist_delete(c_offlist);
05209     }
05210     }
05211 
05212     skip_if(irplib_detmon_add_adl_column(lin_table, opt_nir));
05213 
05214     if(!(mode & IRPLIB_LIN_PIX2PIX)) {
05215     double mse = 0;
05216         /* Computation of LINEARITY via polynomial fit */
05217     y = cpl_vector_wrap(cpl_table_get_nrow(lin_table),
05218                 (double *)cpl_table_get_data_double_const(lin_table,
05219                                   "MED"));
05220         if (opt_nir == NIR) {
05221            x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
05222                              (double *)cpl_table_get_data_double_const(lin_table,                                                                                                 "DIT"));
05223         } else {
05224            x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
05225                              (double *)cpl_table_get_data_double_const(lin_table,                                                                                                 "EXPTIME"));
05226         }
05227         if(x == NULL || y == NULL) {
05228         cpl_vector_unwrap((cpl_vector *)x);
05229         cpl_vector_unwrap((cpl_vector *)y);
05230         /*
05231          * As x and y are const vectors, if they would be defined at the
05232          * beginning of the function (required for skip_if - end_skip
05233          * scheme), they couldn't be initialised to NULL (required too).
05234          * Therefore, they are considered apart from the scheme.
05235          */
05236         skip_if(1);
05237     }
05238 
05239         cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
05240         poly_linfit = cpl_polynomial_fit_1d_create(x, y, order, &mse);
05241 
05242     if(order == cpl_vector_get_size(x) - 1) {
05243         cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
05244         mse = 0;
05245     }
05246 
05247     if(poly_linfit == NULL) {
05248         cpl_vector_unwrap((cpl_vector *)x);
05249         cpl_vector_unwrap((cpl_vector *)y);
05250         /* See comment in previous error checking if() statement */
05251         skip_if(1);
05252     }
05253 
05254     cpl_vector_unwrap((cpl_vector *)x);
05255     cpl_vector_unwrap((cpl_vector *)y);
05256 
05257         for(i = 0; i <= order; i++) {
05258             const double            coeff =
05259                 cpl_polynomial_get_coeff(poly_linfit, &i);
05260             char                   *name_o =
05261                 cpl_sprintf("ESO QC LIN COEF%d", i);
05262             assert(name_o != NULL);
05263             skip_if(cpl_propertylist_append_double(qclist, name_o, coeff));
05264             skip_if(cpl_propertylist_set_comment(qclist,name_o,
05265                          DETMON_QC_LIN_COEF_C));
05266             cpl_free(name_o);
05267         pcoeffs[i] = coeff;
05268         }
05269     skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT, mse));
05270             skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
05271                          DETMON_QC_ERRFIT_MSE_C));
05272 
05273 
05274     } else {
05275        if (opt_nir == NIR) {
05276           x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
05277                 (double *)cpl_table_get_data_double_const(lin_table,
05278                                                                       "DIT"));
05279        } else {
05280           x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
05281                 (double *)cpl_table_get_data_double_const(lin_table,
05282                                                                       "EXPTIME"));
05283        }
05284     const cpl_image * first = cpl_imagelist_get_const(lin_inputs, 0);
05285     int sizex = cpl_image_get_size_x(first);
05286     int sizey = cpl_image_get_size_y(first);
05287 
05288     double vsize = cpl_vector_get_size(x);
05289 
05290     fiterror = cpl_image_new(sizex, sizey, CPL_TYPE_FLOAT);
05291 
05292         *coeffs_cube =
05293             cpl_fit_imagelist_polynomial(x, lin_inputs, 0,
05294                                          order, FALSE, CPL_TYPE_FLOAT,
05295                      fiterror);
05296 
05297     cpl_vector_unwrap((cpl_vector*)x);
05298     irplib_ensure(*coeffs_cube != NULL, CPL_ERROR_UNSPECIFIED, 
05299               "Failed polynomial fit");
05300     
05301         for(i = 0; i <= order; i++) {
05302             cpl_image              *image = cpl_imagelist_get(*coeffs_cube, i);
05303         const double coeff = cpl_image_get_median(image);
05304             char * name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
05305             char * name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
05306         pcoeffs[i] = coeff;
05307             assert(name_o1 != NULL);
05308             assert(name_o2 != NULL);
05309             skip_if(cpl_propertylist_append_double(qclist, name_o1, coeff));
05310             skip_if(cpl_propertylist_set_comment(qclist,name_o1,
05311                          DETMON_QC_LIN_COEF_C));
05312             cpl_free(name_o1);
05313         name_o1= NULL;
05314             skip_if(cpl_propertylist_append_double(qclist, name_o2,
05315                        cpl_image_get_stdev(image)));
05316             skip_if(cpl_propertylist_set_comment(qclist,name_o2,
05317                          DETMON_QC_LIN_COEF_ERR_C));
05318             cpl_free(name_o2);
05319         name_o2= NULL;
05320         }
05321 
05322     if(order == vsize - 1) {
05323         cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
05324         skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
05325                            0.0));
05326             skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
05327                          DETMON_QC_ERRFIT_C));
05328 
05329 
05330     } else {
05331         skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
05332                            cpl_image_get_median(fiterror)));
05333             skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
05334                          DETMON_QC_ERRFIT_C));
05335 
05336     }
05337     }
05338 
05339     skip_if(irplib_detmon_lg_lineff(pcoeffs, qclist, ref_level, order));
05340 
05341     if(mode & IRPLIB_LIN_PIX2PIX) {
05342     int nbpixs;
05343         *bpm = irplib_detmon_bpixs(*coeffs_cube, bpmbin, kappa, &nbpixs);
05344     skip_if(*bpm == NULL);
05345     skip_if(cpl_propertylist_append_int(qclist, DETMON_QC_NUM_BPM,
05346                         nbpixs));
05347     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_NUM_BPM,
05348                          DETMON_QC_NUM_BPM_C));
05349     }
05350 
05351     end_skip;
05352 
05353     cpl_vector_delete(diffdits);
05354     cpl_polynomial_delete(poly_linfit);
05355     cpl_imagelist_delete(lin_inputs);
05356     cpl_vector_delete(vcoeffs);
05357     cpl_image_delete(fiterror);
05358 
05359     return lin_table;
05360 
05361 }
05362 
05363 /*--------------------------------------------------------------------------*/
05387 /*--------------------------------------------------------------------------*/
05388 static cpl_error_code
05389 irplib_detmon_lin_table_fill_row(cpl_table * lin_table, double c_dit,
05390                  cpl_imagelist * linearity_inputs,
05391                  const cpl_imagelist * ons,
05392                  const cpl_imagelist * offs,
05393                  int llx,
05394                  int lly,
05395                  int urx,
05396                  int ury,
05397                  const int pos,
05398                                  const int nskip,
05399                  unsigned mode)
05400 {
05401     cpl_image              * dif1=NULL;
05402     cpl_image              * dif2=NULL;
05403     cpl_image              * dif_avg=NULL;
05404 
05405     double                   med_dit=0;
05406     double                   mean_dit=0;
05407     cpl_error_code           error;
05408     cpl_image * extracted=NULL;
05409     int offsize=0;
05410 
05411     cpl_ensure_code(lin_table != NULL, CPL_ERROR_NULL_INPUT);
05412     cpl_ensure_code(ons != NULL, CPL_ERROR_NULL_INPUT);
05413     cpl_ensure_code(offs != NULL, CPL_ERROR_NULL_INPUT);
05414 
05415     if (mode & IRPLIB_LIN_PIX2PIX) {
05416        cpl_msg_debug(cpl_func,"checking linearity inputs");
05417     cpl_ensure_code(linearity_inputs != NULL, CPL_ERROR_NULL_INPUT);
05418     }
05419 
05420 
05421     if (mode & IRPLIB_LIN_NIR) {
05422     cpl_table_set(lin_table, "DIT", pos, c_dit);
05423     } else if (mode & IRPLIB_LIN_OPT) { /*OPT */
05424         cpl_table_set(lin_table, "EXPTIME", pos, c_dit);
05425     } else {
05426     cpl_msg_error(cpl_func, "Mandatory mode not given");
05427     }
05428 
05429 
05430     offsize = cpl_imagelist_get_size(offs);
05431 
05432     /* Algorithm defined: substract ON - OFF and average 2 differences */
05433     dif1 = cpl_image_subtract_create(cpl_imagelist_get_const(ons, 0),
05434                                      cpl_imagelist_get_const(offs, 0));
05435 
05436     if (mode & IRPLIB_LIN_NO_COLLAPSE && offsize > 1)
05437         dif2 = cpl_image_subtract_create(cpl_imagelist_get_const(ons, 1),
05438                                          cpl_imagelist_get_const(offs, 1));
05439     else 
05440         dif2 = cpl_image_subtract_create(cpl_imagelist_get_const(ons, 1),
05441                                          cpl_imagelist_get_const(offs, 0)); 
05442 
05443     dif_avg = cpl_image_average_create(dif1, dif2);
05444 
05445     cpl_image_abs(dif_avg);
05446     extracted = cpl_image_extract(dif_avg, llx, lly, urx, ury);
05447 
05448     cpl_ensure_code(extracted != NULL, cpl_error_get_code());
05449 
05450     cpl_table_set(lin_table, "MED", pos, cpl_image_get_median(extracted));
05451     cpl_table_set(lin_table, "MEAN", pos, cpl_image_get_mean(extracted));
05452     med_dit = cpl_image_get_median(extracted) / c_dit;
05453     mean_dit = cpl_image_get_mean(extracted)  / c_dit;
05454 
05455     cpl_table_set(lin_table, "MED_DIT", pos, med_dit);
05456     cpl_table_set(lin_table, "MEAN_DIT", pos, mean_dit);
05457 
05458     cpl_image_delete(dif1);
05459     cpl_image_delete(dif2);
05460 
05461     /* Insert to the imagelist used to fit the polynomial */
05462     if(mode & IRPLIB_LIN_PIX2PIX) {
05463         error = cpl_imagelist_set(linearity_inputs, extracted, pos-nskip);
05464         cpl_ensure_code(!error, error);
05465     } else {
05466         cpl_image_delete(extracted);
05467     }
05468 
05469 
05470     cpl_image_delete(dif_avg);
05471 
05472     return cpl_error_get_code();
05473 }

This file is part of the GIRAFFE Pipeline Reference Manual 2.8.1.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Mon Aug 3 13:13:35 2009 by doxygen 1.5.1 written by Dimitri van Heesch, © 1997-2004