irplib_detmon_lg.c

00001 /* $Id: irplib_detmon_lg.c,v 1.11 2007/11/14 16:53:22 lbilbao Exp $
00002  *
00003  * This file is part of the irplib package
00004  * Copyright (C) 2002, 2003 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
00019  */
00020 
00021 /*
00022  * $Author: lbilbao $
00023  * $Date: 2007/11/14 16:53:22 $
00024  * $Revision: 1.11 $
00025  * $Name: uves-3_4_5 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*---------------------------------------------------------------------------
00033                                   Includes
00034  ---------------------------------------------------------------------------*/
00035 
00036 #ifdef HAVE_FFTW
00037 #include <complex.h>
00038 #include <fftw3.h>
00039 #endif
00040 
00041 #include <math.h>
00042 #include <string.h>
00043 #include <assert.h>
00044 
00045 #include <cpl.h>
00046 
00047 #include "irplib_detmon.h"
00048 #include "irplib_detmon_lg.h"
00049 
00050 #include "irplib_utils.h"
00051 
00052 #include "irplib_math_const.h"
00053 
00054 
00055 /*--------------------------------------------------------------------------*/
00056 
00057 /*
00058  * @defgroup irplib_detmon        Detector monitoring functions
00059  */
00060 
00061 /*--------------------------------------------------------------------------*/
00062 
00063 /*---------------------------------------------------------------------------
00064                                   Defines
00065  ---------------------------------------------------------------------------*/
00066 static struct
00067 {
00068     const char            * method;
00069     /* Inputs */
00070     int                     order;
00071     int                     kappa;
00072     int                     niter;
00073     int                     threshold_min;
00074     int                     threshold_max;
00075     int                     llx;
00076     int                     lly;
00077     int                     urx;
00078     int                     ury;
00079     int                     ref_level;
00080     int                     threshold;
00081     int                     m;
00082     int                     n;
00083     int                     llx1;
00084     int                     lly1;
00085     int                     urx1;
00086     int                     ury1;
00087     int                     llx2;
00088     int                     lly2;
00089     int                     urx2;
00090     int                     ury2;
00091     int                     llx3;
00092     int                     lly3;
00093     int                     urx3;
00094     int                     ury3;
00095     int                     llx4;
00096     int                     lly4;
00097     int                     urx4;
00098     int                     ury4;
00099     int                     llx5;
00100     int                     lly5;
00101     int                     urx5;
00102     int                     ury5;
00103     cpl_boolean             autocorr;
00104     cpl_boolean             intermediate;
00105     cpl_boolean             collapse;
00106     int                     filter;
00107     /* Outputs */
00108     double                  cr;
00109     int                     exts;
00110     int                     nb_extensions;
00111     double                  avg_off1;
00112     double                  avg_off2;
00113     double                  sig_off_dif;
00114 } detmon_lg_config;
00115 
00116 #define NIR TRUE
00117 #define OPT FALSE
00118 
00119 #define DETMON_QC_CONAD       "ESO QC CONAD"
00120 #define DETMON_QC_CONAD_C     "CONAD value (inverse of GAIN)"
00121 
00122 #define DETMON_QC_GAIN        "ESO QC GAIN"
00123 #define DETMON_QC_GAIN_C      "GAIN (see QC.METHOD)"
00124 
00125 #define DETMON_QC_GAIN_MSE    "ESO QC GAIN MSE"
00126 #define DETMON_QC_GAIN_MSE_C  "Error of the GAIN computation"
00127 
00128 #define DETMON_QC_RON         "ESO QC RON"
00129 #define DETMON_QC_RON_C       "RON obtained as independent term (PTC method)"
00130 
00131 #define DETMON_QC_AUTOCORR    "ESO QC AUTOCORR"
00132 #define DETMON_QC_AUTOCORR_C  "Autocorrelation factor computed as sum of " \
00133                               "all pixels in autocorrelation image"
00134 #define DETMON_QC_GAIN_CORR   "ESO QC GAIN CORR"
00135 #define DETMON_QC_GAIN_CORR_C "GAIN taken QC.AUTOCORR into account"
00136 
00137 #define DETMON_QC_LAMP_FLUX   "ESO QC LAMP FLUX"
00138 #define DETMON_QC_LAMP_FLUX_C "Lamp flux"
00139 
00140 #define DETMON_QC_NUM_BPM     "ESO QC NUM BPM"
00141 #define DETMON_QC_NUM_BPM_C   "Number of bad pixels detected according to "\
00142                               "polynomial information"
00143 
00144 /*---------------------------------------------------------------------------
00145                                   Private function prototypes
00146  ---------------------------------------------------------------------------*/
00147 /*  Functions for the Linearity/Gain recipe, irplib_detmon_lg() */
00148 
00149 /*  Parameters */
00150 static cpl_error_code
00151 irplib_detmon_lg_retrieve_parlist(const char *,
00152                               const char *, const cpl_parameterlist *);
00153 
00154 
00155 static cpl_error_code
00156 irplib_detmon_lg_split_onoff(const cpl_frameset *,
00157                              cpl_frameset *,
00158                              cpl_frameset *,
00159                              const char *, const char *, const cpl_boolean);
00160 
00161 static cpl_error_code
00162 irplib_detmon_lg_reduce(const cpl_frameset *,
00163                         const cpl_frameset *,
00164                         int *,
00165                         int *,
00166                         int,
00167                         cpl_imagelist **,
00168                         cpl_table **,
00169                         cpl_table **,
00170                         cpl_image **,
00171                         cpl_imagelist **,
00172                         cpl_imagelist **,
00173                         cpl_propertylist **,
00174          int                    (* load_fset) (const cpl_frameset *,
00175                                cpl_type,
00176                                                cpl_imagelist *),
00177                         const cpl_boolean);
00178 
00179 static cpl_error_code
00180 irplib_detmon_linearity(const cpl_frameset *,
00181                         cpl_table **,
00182                         cpl_table **,
00183                         cpl_imagelist **,
00184                         cpl_vector **,
00185                         cpl_imagelist **,
00186                         cpl_imagelist **,
00187                         const int,
00188                         const int, cpl_propertylist **,
00189             const int, const cpl_boolean);
00190 
00191 static cpl_error_code
00192 irplib_detmon_gain(cpl_table *,
00193                    cpl_table *,
00194                    cpl_imagelist *,
00195                    cpl_imagelist *,
00196                    cpl_imagelist *,
00197                    cpl_imagelist *,
00198                    const int);
00199 
00200 static                  cpl_error_code
00201 irplib_detmon_lg_save(const cpl_parameterlist *,
00202                       cpl_frameset *,
00203                       const char *,
00204                       const char *,
00205                       const char *,
00206                       const char *,
00207                       const char *,
00208                       const char *,
00209                       const char *,
00210                       const char *,
00211                       const char *,
00212                       const char *,
00213                       cpl_imagelist **,
00214                       cpl_table **,
00215                       cpl_table **,
00216                       cpl_image **,
00217                       cpl_imagelist **,
00218                       cpl_imagelist **,
00219                       cpl_propertylist **,
00220                       const int, const int, const cpl_frameset *,
00221                       cpl_boolean);
00222 
00223 static cpl_error_code
00224 irplib_detmon_lg_qc_ptc(const cpl_table  *,
00225             const cpl_table  *,
00226             cpl_propertylist *);
00227 
00228 static cpl_error_code
00229 irplib_detmon_lg_qc_med(const cpl_table  *,
00230             cpl_propertylist *);
00231 
00232 
00233 
00234 cpl_imagelist **
00235 irplib_detmon_ilist_load_fset(const cpl_frameset *,
00236                               cpl_type);
00237 
00238 cpl_frameset *
00239 irplib_detmon_pair_extract(const cpl_frameset *,
00240                            int *, int,
00241                            int * ,
00242                            int *,
00243                            int);
00244 
00245 
00246 /*
00247 static double
00248 irplib_pfits_get_exptime(const cpl_propertylist *);
00249 */
00250 
00251 static cpl_image       *irplib_detmon_bpixs(const cpl_imagelist *, int *);
00252 
00253 static double
00254 irplib_detmon_autocorr_factor(const cpl_image *,
00255                               const int,
00256                               cpl_imagelist *);
00257 
00258 /*
00259 #ifdef HAVE_FFTW
00260 static cpl_image       *irplib_detmon_image_autocorrelate_fftw(const cpl_image
00261                                                                *, const int,
00262                                                                const int);
00263 #endif
00264 */
00265 
00266 
00267 
00268 static                  cpl_error_code
00269 irplib_detmon_opt_contamination(const cpl_image *, cpl_propertylist *);
00270 
00271 static int              
00272 irplib_detmon_opt_lampcr(cpl_frameset *);
00273 
00274 int
00275 irplib_detmon_lg_dfs_set_groups(cpl_frameset *, const char *, const char *);
00276 
00277 cpl_error_code
00278 irplib_detmon_lg_reduce_all(const cpl_table *,
00279                              cpl_table *,
00280                              cpl_propertylist *,
00281                              cpl_imagelist **,
00282                              cpl_image **,
00283                              cpl_vector *,
00284                             cpl_imagelist *, cpl_table *, cpl_boolean, int);
00285 
00286 static cpl_error_code          
00287 irplib_detmon_lg_check_defaults(const cpl_image *);
00288 
00289 static cpl_error_code          
00290 irplib_detmon_lg_rescale(cpl_imagelist *);
00291 
00292 static cpl_error_code
00293 irplib_detmon_lg_reduce_init(cpl_boolean,
00294                              cpl_table **,
00295                              cpl_table **,
00296                              cpl_table **,
00297                              cpl_imagelist **,
00298                              cpl_vector **,
00299                              cpl_propertylist **,
00300                              int);
00301 
00302 
00303 
00304 cpl_error_code          
00305 irplib_detmon_add_adl_column(cpl_table *);
00306 
00307 
00308 
00309 static cpl_error_code
00310 irplib_detmon_lg_reduce_dit(const cpl_frameset * set_on,
00311                 int * selection_on,
00312                 int dit_nb,
00313                 int * nsets_extracted,
00314                 const cpl_frameset * set_off,
00315                 int * selection_off,
00316                 cpl_table ** linear_table_ptr,
00317                 cpl_table ** gain_table_ptr,
00318                 cpl_imagelist ** linearity_inputs,
00319                 cpl_vector ** x_pos,
00320                 cpl_propertylist ** qclist,
00321                 cpl_boolean opt_nir,
00322                 cpl_table ** fit_table,
00323                 cpl_imagelist ** autocorr_images,
00324                 cpl_imagelist ** diff_flats,
00325                             int nsets,
00326                             cpl_imagelist ** opt_offs,
00327          int                    (* load_fset) (const cpl_frameset *,
00328                                cpl_type,
00329                                                cpl_imagelist *));
00330 
00331 
00332 /*--------------------------------------------------------------------------*/
00333 
00334 /*
00335  * @brief  Reduce linearity and gain in the IR domain
00336  * @param  parlist              List of required parameters
00337  * @param  frameset             Input frameset
00338  * @param  tag_on               Tag to identify the ON frames
00339  * @param  tag_off              Tag to identify the OFF frames
00340  * @param  recipe_name          Name of the recipe calling this function
00341  * @param  pipeline_name        Name of the pipeline calling this function
00342  * @param  procatg_lintbl       PRO.CATG keyword for the Linearity Table
00343  * @param  procatg_gaintbl      PRO.CATG keyword for the Gain Table
00344  * @param  procatg_lincoeff     PRO.CATG keyword for the
00345  *                              Linearity Coefficients' Images
00346  * @param  procatg_bpm          PRO.CATG required for the Bad Pixel Map
00347  * @param  procatg_corr     PRO.CATG required for the Autocorrelation Images
00348  *                              (Intermediate product - only created if required)
00349  * @param  procatg_diff         PRO.CATG required for the Difference Images
00350  *                              (Intermediate Product - only created if required)
00351  * @param  package              PACKAGE (incl. VERSION) required
00352  *                              for the DFS keywords
00353  * @param  compare              Compare function used to classified frameset into
00354  *                              different settings, if any.
00355  * @param  opt_nir              Boolean parameter to activate/deactivate
00356  *                              OPT-only / IR-only parts of the recipe
00357  * @return 0 on success, -1 on fail.
00358  * @note: The parlist contains the following parameters:
00359  *
00360  * @par1  kappa                 Kappa value used for the kappa-sigma clipping
00361  *                              rejection of bad pixels when computing sigma for
00362  *                              gain calculation
00363  * @par2  niter                 Number of iterations for the kappa-sigma clipping
00364  * @par3  threshold_min         Minimum threshold of the k-sigma (Not applied)
00365  * @par4  threshold_max         Maximum threshold of the k-sigma (Not applied)
00366  * @par5  llx                   Region of Interest (Default to the whole area)
00367  * @par6  lly                   Region of Interest (Default to the whole area)
00368  * @par7  urx                   Region of Interest (Default to the whole area)
00369  * @par8  ury                   Region of Interest (Default to the whole area)
00370  * @par9  ref_level             Reference Level (Not applied)
00371  * @par10 threshold             Threshold (Not applied)
00372  * @par11 intermediate          Boolean to activate the production of
00373  *                              Intermediate Products
00374  * @par12 autocorr              Boolean to activate autocorr method
00375  * @par13 collapse              Boolean to activate collapse of OFF frames
00376  * @par14 rescale               Boolean to activate pair rescaling
00377  * @par15 m                     X-Shift of the autocorrelation
00378  * @par16 n                     Y-Shift of the autocorrelation
00379  * @par17 llx1                  Region of Interest 1 (Only OPT)
00380  * @par18 lly1                  Region of Interest 1 (Only OPT)
00381  * @par19 urx1                  Region of Interest 1 (Only OPT)
00382  * @par20 ury1                  Region of Interest 1 (Only OPT)
00383  * @par21 llx2                  Region of Interest 2 (Only OPT)
00384  * @par22 lly2                  Region of Interest 2 (Only OPT)
00385  * @par23 urx2                  Region of Interest 2 (Only OPT)
00386  * @par24 ury2                  Region of Interest 2 (Only OPT)
00387  * @par25 llx3                  Region of Interest 3 (Only OPT)
00388  * @par26 lly3                  Region of Interest 3 (Only OPT)
00389  * @par27 urx3                  Region of Interest 3 (Only OPT)
00390  * @par28 ury3                  Region of Interest 3 (Only OPT)
00391  * @par29 llx4                  Region of Interest 4 (Only OPT)
00392  * @par30 lly4                  Region of Interest 4 (Only OPT)
00393  * @par31 urx4                  Region of Interest 4 (Only OPT)
00394  * @par32 ury4                  Region of Interest 4 (Only OPT)
00395  * @par33 llx5                  Region of Interest 5 (Only OPT)
00396  * @par34 lly5                  Region of Interest 5 (Only OPT)
00397  * @par35 urx5                  Region of Interest 5 (Only OPT)
00398  * @par36 ury5                  Region of Interest 5 (Only OPT)
00399  * @par37 exts                  Integer to select extension 
00400  */
00401 
00402 /*--------------------------------------------------------------------------*/
00403 
00404 cpl_error_code
00405 irplib_detmon_lg(cpl_frameset            * frameset,
00406                  const cpl_parameterlist * parlist,
00407                  const char              * tag_on,
00408                  const char              * tag_off,
00409                  const char              * recipe_name,
00410                  const char              * pipeline_name,
00411                  const char              * pafregexp,
00412                  const char              * procatg_lintbl,
00413                  const char              * procatg_gaintbl,
00414                  const char              * procatg_lincoeff,
00415                  const char              * procatg_bpm,
00416                  const char              * procatg_corr,
00417                  const char              * procatg_diff,
00418                  const char              * package,
00419                  int                    (* compare) (const cpl_frame *,
00420                              const cpl_frame *),
00421          int                    (* load_fset) (const cpl_frameset *,
00422                                cpl_type,
00423                                                cpl_imagelist *),
00424                  const cpl_boolean         opt_nir)
00425 {
00426     int              nsets;
00427     int            * selection = NULL;
00428     int              i;
00429     cpl_frame      * first     = NULL;
00430     cpl_image      * reference = NULL;
00431 
00432     /*
00433      * Variables used only inside the for() statement.
00434      * However, there are declared here to ease
00435      * memory management in error case.
00436      */
00437     int              *  selection_on    = NULL;
00438     int              *  selection_off   = NULL;
00439     cpl_frameset     *  cur_fset        = NULL;
00440     cpl_frameset     *  cur_fset_on     = NULL;        
00441     cpl_frameset     *  cur_fset_off    = NULL;
00442     cpl_table        ** gain_table      = NULL;
00443     cpl_table        ** linear_table    = NULL;
00444     cpl_imagelist    ** coeffs          = NULL;
00445     cpl_image        ** bpm             = NULL;
00446     cpl_imagelist    ** autocorr_images = NULL;
00447     cpl_imagelist    ** diff_flats      = NULL;
00448     cpl_propertylist ** qclist          = NULL;
00449 
00450     /* Test entries */
00451     cpl_ensure_code(frameset         != NULL, CPL_ERROR_NULL_INPUT);
00452     cpl_ensure_code(parlist          != NULL, CPL_ERROR_NULL_INPUT);
00453     cpl_ensure_code(tag_on           != NULL, CPL_ERROR_NULL_INPUT);
00454     cpl_ensure_code(tag_off          != NULL, CPL_ERROR_NULL_INPUT);
00455     cpl_ensure_code(recipe_name      != NULL, CPL_ERROR_NULL_INPUT);
00456     cpl_ensure_code(pipeline_name    != NULL, CPL_ERROR_NULL_INPUT);
00457     cpl_ensure_code(procatg_lintbl   != NULL, CPL_ERROR_NULL_INPUT);
00458     cpl_ensure_code(procatg_gaintbl  != NULL, CPL_ERROR_NULL_INPUT);
00459     cpl_ensure_code(procatg_lincoeff != NULL, CPL_ERROR_NULL_INPUT);
00460     cpl_ensure_code(procatg_bpm      != NULL, CPL_ERROR_NULL_INPUT);
00461     cpl_ensure_code(procatg_corr     != NULL, CPL_ERROR_NULL_INPUT);
00462     cpl_ensure_code(procatg_diff     != NULL, CPL_ERROR_NULL_INPUT);
00463     cpl_ensure_code(package          != NULL, CPL_ERROR_NULL_INPUT);
00464 
00465     skip_if (irplib_detmon_lg_dfs_set_groups(frameset, tag_on, tag_off));
00466 
00467     /*
00468      * First check of input consistency in NIR case:
00469      * There must be a pair ON and a pair OFF for each DIT.
00470      */
00471     skip_if (opt_nir == NIR && cpl_frameset_get_size(frameset) % 4 != 0);
00472  
00473     skip_if (irplib_detmon_lg_retrieve_parlist(pipeline_name, recipe_name,
00474                            parlist));
00475 
00476     /*
00477      * Retrieve first image to check some parameters' values and
00478      * set default values which refer to the image.
00479      */
00480 
00481     first = cpl_frameset_get_first(frameset);
00482     skip_if (first == NULL);
00483 
00484     if (detmon_lg_config.exts < 0) {
00485         reference = cpl_image_load(cpl_frame_get_filename(first),
00486                                    CPL_TYPE_FLOAT, 0, 1);
00487     } else {
00488     if (load_fset != NULL) {
00489         cpl_frameset * new = cpl_frameset_new();
00490         cpl_imagelist * p = cpl_imagelist_new();
00491         cpl_frameset_insert(new, cpl_frame_duplicate(first));
00492         (*load_fset)(new, CPL_TYPE_FLOAT, p);
00493         reference = cpl_image_duplicate(cpl_imagelist_get(p, 0));
00494         cpl_imagelist_delete(p);
00495         cpl_frameset_delete(new);
00496     } else {
00497         reference = cpl_image_load(cpl_frame_get_filename(first),
00498                        CPL_TYPE_FLOAT, 0, detmon_lg_config.exts);
00499     }
00500     }
00501     skip_if (reference == NULL);
00502 
00503     skip_if (irplib_detmon_lg_check_defaults(reference));
00504 
00505     /* Labelise all input frames */
00506     if (compare == NULL) {
00507         nsets = 1;
00508     } else {
00509         cpl_msg_info(cpl_func, "Identifying different settings");
00510         selection = cpl_frameset_labelise(frameset, compare, &nsets);
00511         skip_if (selection == NULL);
00512     }
00513 
00514     /* Extract settings and reduce each of them */
00515     for(i = 0; i < nsets; i++) {
00516         int  nsets_on  = 0;
00517         int  nsets_off = 0;
00518         int  j;
00519 
00520     cur_fset = nsets == 1 ?
00521         cpl_frameset_duplicate(frameset) : 
00522         cpl_frameset_extract(frameset, selection, i);   
00523 
00524         /* Reduce data set nb i */
00525         cpl_msg_info(cpl_func, "Reduce data set nb %d out of %d",
00526              i + 1, nsets);
00527 
00528     /* Get the nb of extensions */
00529         detmon_lg_config.nb_extensions = 1;
00530         if (detmon_lg_config.exts < 0) {
00531             const cpl_frame * cur_frame =
00532         cpl_frameset_get_first_const(cur_fset);
00533             detmon_lg_config.nb_extensions =
00534                 cpl_frame_get_nextensions(cur_frame);
00535         }
00536 
00537         /*
00538          * In the optical domain, the first 2 frames
00539          * are used apart from the pairs.
00540          */
00541         if (opt_nir == OPT) {
00542             irplib_detmon_opt_lampcr(cur_fset);
00543             detmon_lg_config.collapse = TRUE;
00544         }
00545 
00546         /* Split input frameset into 2 sub-framesets for ON and OFF frames */
00547         cur_fset_on  = cpl_frameset_new();
00548         cur_fset_off = cpl_frameset_new();
00549         cpl_msg_info(cpl_func, "Splitting into ON and OFF sub-framesets");
00550         skip_if (irplib_detmon_lg_split_onoff(cur_fset,
00551                           cur_fset_on, cur_fset_off,
00552                           tag_on, tag_off, opt_nir));
00553 
00554         /* Labelise each sub-frameset according to DIT values */
00555         selection_on = cpl_frameset_labelise(cur_fset_on,
00556                          irplib_detmon_compare_dits,
00557                          &nsets_on);
00558     skip_if (selection_on == NULL);
00559 
00560         if (!detmon_lg_config.collapse) {
00561             selection_off = cpl_frameset_labelise(cur_fset_off,
00562                           irplib_detmon_compare_dits,
00563                           &nsets_off);
00564         skip_if (selection_off == NULL);
00565     }
00566 
00567         /* Test if they have equal nb of labels */
00568         if (!detmon_lg_config.collapse) {
00569             skip_if(nsets_on != nsets_off);
00570     }
00571 
00572 
00573         /* Initialise memory for products */
00574         gain_table   = irplib_detmon_table_new(detmon_lg_config.nb_extensions);
00575         linear_table = irplib_detmon_table_new(detmon_lg_config.nb_extensions);
00576         qclist       = irplib_detmon_propertylist_new(detmon_lg_config.nb_extensions);
00577 
00578 
00579         if (opt_nir == NIR) {
00580             coeffs = irplib_detmon_imagelist_new(detmon_lg_config.nb_extensions);
00581             bpm    = irplib_detmon_image_new(detmon_lg_config.nb_extensions);
00582         }
00583 
00584     autocorr_images = irplib_detmon_imagelist_new(detmon_lg_config.nb_extensions);
00585     diff_flats      = irplib_detmon_imagelist_new(detmon_lg_config.nb_extensions);
00586     if (detmon_lg_config.intermediate) {
00587         for(j = 0; j < detmon_lg_config.nb_extensions; j++) {
00588                 autocorr_images[j] = cpl_imagelist_new();
00589                 diff_flats[j]      = cpl_imagelist_new();
00590             }
00591         }
00592 
00593         /* Reduction done here */
00594         cpl_msg_info(cpl_func, "Starting data reduction");
00595         skip_if(irplib_detmon_lg_reduce(cur_fset_on, cur_fset_off,
00596                                         selection_on, selection_off,
00597                                         nsets_on, coeffs, gain_table,
00598                                         linear_table, bpm, autocorr_images,
00599                                         diff_flats, qclist, load_fset,
00600                     opt_nir));
00601 
00602         /* Save the products for each setting */
00603         cpl_msg_info(cpl_func, "Saving the products");
00604         if(nsets == 1) {
00605             skip_if(irplib_detmon_lg_save(parlist, frameset, recipe_name,
00606                       pipeline_name, pafregexp,
00607                       procatg_lintbl, procatg_gaintbl,
00608                       procatg_lincoeff, procatg_bpm,
00609                       procatg_corr, procatg_diff, package,
00610                       coeffs, gain_table, linear_table,
00611                       bpm, autocorr_images, diff_flats,
00612                       qclist, 0, 0, cur_fset,
00613                       opt_nir));
00614         } else {
00615             skip_if(irplib_detmon_lg_save(parlist, frameset, recipe_name,
00616                       pipeline_name, pafregexp,
00617                       procatg_lintbl, procatg_gaintbl,
00618                       procatg_lincoeff, procatg_bpm,
00619                       procatg_corr, procatg_diff, package,
00620                       coeffs, gain_table, linear_table,
00621                       bpm, autocorr_images, diff_flats,
00622                       qclist, 1, i + 1, cur_fset,
00623                       opt_nir));
00624         }
00625 
00626         /* Free for each setting */
00627         cpl_free(selection_on);
00628         cpl_free(selection_off);
00629 
00630         cpl_frameset_delete(cur_fset);
00631         cpl_frameset_delete(cur_fset_on);
00632         cpl_frameset_delete(cur_fset_off);
00633 
00634     irplib_detmon_table_delete(gain_table,
00635         detmon_lg_config.nb_extensions);
00636     irplib_detmon_table_delete(linear_table,
00637         detmon_lg_config.nb_extensions);
00638     irplib_detmon_imagelist_delete(coeffs,
00639         detmon_lg_config.nb_extensions);
00640     irplib_detmon_propertylist_delete(qclist,
00641         detmon_lg_config.nb_extensions);
00642     irplib_detmon_image_delete(bpm,
00643         detmon_lg_config.nb_extensions);
00644     irplib_detmon_imagelist_delete(autocorr_images,
00645         detmon_lg_config.nb_extensions);
00646     irplib_detmon_imagelist_delete(diff_flats,
00647         detmon_lg_config.nb_extensions);
00648 
00649     selection_on    = NULL;
00650     selection_off   = NULL;
00651     cur_fset        = NULL;
00652     cur_fset_on     = NULL;
00653     cur_fset_off    = NULL;
00654     gain_table      = NULL;
00655     linear_table    = NULL;
00656     coeffs          = NULL;
00657     qclist          = NULL;
00658     bpm             = NULL;
00659     autocorr_images = NULL;
00660     diff_flats      = NULL;
00661     }
00662 
00663     end_skip;
00664 
00665     cpl_free(selection_on);
00666     cpl_free(selection_off);
00667 
00668     cpl_frameset_delete(cur_fset);
00669     cpl_frameset_delete(cur_fset_on);
00670     cpl_frameset_delete(cur_fset_off);
00671 
00672     irplib_detmon_table_delete(gain_table,
00673                    detmon_lg_config.nb_extensions);
00674     irplib_detmon_table_delete(linear_table,
00675                    detmon_lg_config.nb_extensions);
00676     irplib_detmon_imagelist_delete(coeffs,
00677                    detmon_lg_config.nb_extensions);
00678     irplib_detmon_propertylist_delete(qclist,
00679                       detmon_lg_config.nb_extensions);
00680     irplib_detmon_image_delete(bpm,
00681                    detmon_lg_config.nb_extensions);
00682     irplib_detmon_imagelist_delete(autocorr_images,
00683                    detmon_lg_config.nb_extensions);
00684     irplib_detmon_imagelist_delete(diff_flats,
00685                    detmon_lg_config.nb_extensions);
00686 
00687     cpl_free(selection);
00688     cpl_image_delete(reference);
00689 
00690     return cpl_error_get_code();
00691 }
00692 
00693 
00694 /*--------------------------------------------------------------------------*/
00695 
00696 /*
00697  * @brief  Correlate two images with a given range of shifts
00698  * @param  image1       Input image
00699  * @param  image2       Input image
00700  * @param  m            Shift to apply on the x-axis
00701  * @param  n            Shift to apply on the y-axis
00702  * @return              An image of size 2m+1 by 2n+1. Each pixel value
00703  *                      corresponds to the correlation of shift the position
00704  *                      of the pixel. Pixel in the centre (m+1, n+1),
00705  *                      corresponds to shift (0,0). Pixels to the left and
00706  *                      down correspond to negative shifts.
00707  *
00708  * @note                At this moment, this function only accepts images to
00709  *                      have both the same size.
00710  */
00711 
00712 /*--------------------------------------------------------------------------*/
00713 #ifdef HAVE_FFTW
00714 
00715 cpl_image              *
00716 irplib_detmon_image_correlate(const cpl_image * image1,
00717                               const cpl_image * image2,
00718                               const int m, const int n)
00719 {
00720     cpl_image              *image1_padded;
00721     cpl_image              *image2_padded;
00722     float                  *data1;
00723     float                  *data2;
00724     int                     nx, ny;
00725     int                     nx2, ny2;
00726     int                     i;
00727 
00728     fftwf_plan              p1;
00729     fftwf_complex          *in1;
00730     fftwf_complex          *ri1;
00731 
00732     fftwf_plan              p2;
00733     fftwf_complex          *in2;
00734     fftwf_complex          *ri2;
00735 
00736     fftwf_plan              p_inv;
00737     fftwf_complex          *in_inv;
00738     fftwf_complex          *ri_inv;
00739 
00740     fftwf_complex          *corr;
00741     float                  *corr_r;
00742 
00743     cpl_image              *corr_image;
00744     cpl_image              *corr_image_window;
00745     cpl_image              *reorganised;
00746     cpl_image              *image;
00747 
00748     /* Test the entries */
00749     cpl_ensure(image1 != NULL, CPL_ERROR_NULL_INPUT, NULL);
00750     cpl_ensure(image2 != NULL, CPL_ERROR_NULL_INPUT, NULL);
00751 
00752     cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
00753     cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
00754 
00755     nx = cpl_image_get_size_x(image1);
00756     ny = cpl_image_get_size_y(image1);
00757 
00758     nx2 = cpl_image_get_size_x(image2);
00759     ny2 = cpl_image_get_size_y(image2);
00760 
00761     /* At this moment, the images must be of the same size */
00762     cpl_ensure(nx == nx2 && ny == ny2, CPL_ERROR_ILLEGAL_INPUT, NULL);
00763 
00764     /* Pad the images with zeroes to avoid periodical effects of DFT */
00765     image1_padded = cpl_image_new(nx + 2 * m, ny + 2 * n, CPL_TYPE_FLOAT);
00766     cpl_image_copy(image1_padded, image1, m + 1, n + 1);
00767 
00768     image2_padded = cpl_image_new(nx + 2 * m, ny + 2 * n, CPL_TYPE_FLOAT);
00769     cpl_image_copy(image2_padded, image2, m + 1, n + 1);
00770 
00771     /* Get pointers to the pixel data */
00772     data1 = cpl_image_get_data_float(image1_padded);
00773     data2 = cpl_image_get_data_float(image2_padded);
00774 
00775     /*New dimensions of the padded images */
00776     nx = nx + 2 * m;
00777     ny = ny + 2 * n;
00778 
00779     /* Establish the input/output data arrays and the FFT plan */
00780     in1 = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * nx * ny);
00781     ri1 = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * nx * ny);
00782     p1 = fftwf_plan_dft_2d(ny, nx, in1, ri1, FFTW_FORWARD, FFTW_ESTIMATE);
00783 
00784     /* Pack the CPL image data into the FFTW input array */
00785     for(i = 0; i < nx * ny; i++) {
00786         *(in1 + i) = (*(data1 + i) + 0.0 * I);
00787     }
00788 
00789     /* Actually perform the FFT */
00790     fftwf_execute(p1);
00791 
00792     /* Cleanup resources */
00793     fftwf_destroy_plan(p1);
00794     cpl_image_delete(image1_padded);
00795 
00796     /* Establish the input/output data arrays and the FFT plan */
00797     in2 = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * nx * ny);
00798     ri2 = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * nx * ny);
00799     p2 = fftwf_plan_dft_2d(ny, nx, in2, ri2, FFTW_FORWARD, FFTW_ESTIMATE);
00800 
00801     /* Pack the CPL image data into the FFTW input array */
00802     for(i = 0; i < nx * ny; i++) {
00803         *(in2 + i) = (*(data2 + i) + 0.0 * I);
00804     }
00805 
00806     /* Actually perform the FFT */
00807     fftwf_execute(p2);
00808 
00809     /* Cleanup resources */
00810     fftwf_destroy_plan(p2);
00811     cpl_image_delete(image2_padded);
00812 
00813     /* Establish the input/output data arrays and the FFT plan */
00814     in_inv = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * nx * ny);
00815     ri_inv = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * nx * ny);
00816     p_inv = fftwf_plan_dft_2d(ny, nx, in_inv, ri_inv,
00817                               FFTW_BACKWARD, FFTW_ESTIMATE);
00818 
00819     /* Correlation in the Fourier domain: G*[n]·H[n] */
00820     for(i = 0; i < nx * ny; i++) {
00821         in_inv[i] = conjf(ri1[i]) * ri2[i];
00822     }
00823 
00824     /* Cleanup resources */
00825     fftwf_free(in1);
00826     fftwf_free(ri1);
00827 
00828     fftwf_free(in2);
00829     fftwf_free(ri2);
00830 
00831     /* Actually perform the FFT */
00832     fftwf_execute(p_inv);
00833 
00834     /* Cleanup FFTW resources */
00835     fftwf_destroy_plan(p_inv);
00836 
00837     /* Get the module of the inversed signal */
00838     corr = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * nx * ny);
00839     corr_r = (float *) cpl_malloc(sizeof(float) * nx * ny);
00840 
00841     for(i = 0; i < nx * ny; i++) {
00842         *(corr + i) = conjf(*(ri_inv + i));
00843         *(corr + i) *= *(ri_inv + i);
00844         corr_r[i] = crealf(*(corr + i));
00845     }
00846     fftwf_free(in_inv);
00847     fftwf_free(ri_inv);
00848 
00849     /* Wrap the data onto an image */
00850     corr_image = cpl_image_wrap_float(nx, ny, corr_r);
00851 
00852     /* Cleanup resources */
00853     fftwf_free(corr);
00854 
00855     /* Reorganise the pixels to the output */
00856     reorganised = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00857 
00858     image = cpl_image_extract(corr_image, nx / 2 + 1, 1, nx, ny);
00859     cpl_image_copy(reorganised, image, 1, 1);
00860     cpl_image_delete(image);
00861 
00862     image = cpl_image_extract(corr_image, 1, 1, nx / 2, ny);
00863     cpl_image_copy(reorganised, image, nx / 2 + 1, 1);
00864     cpl_image_delete(image);
00865 
00866     cpl_image_unwrap(corr_image);
00867     cpl_free(corr_r);
00868 
00869     corr_image = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00870 
00871     image = cpl_image_extract(reorganised, 1, ny / 2 + 1, nx, ny);
00872     cpl_image_copy(corr_image, image, 1, 1);
00873     cpl_image_delete(image);
00874 
00875     image = cpl_image_extract(reorganised, 1, 1, nx, ny / 2);
00876     cpl_image_copy(corr_image, image, 1, ny / 2 + 1);
00877     cpl_image_delete(image);
00878 
00879     /* Extract a window with the desired shifts */
00880     corr_image_window = cpl_image_extract(corr_image,
00881                                           nx / 2 + 1 - m,
00882                                           ny / 2 + 1 - n,
00883                                           nx / 2 + 1 + m, ny / 2 + 1 + n);
00884 
00885     /* Free and return */
00886     cpl_image_delete(reorganised);
00887     cpl_image_delete(corr_image);
00888 
00889     if(cpl_image_divide_scalar(corr_image_window,
00890                                cpl_image_get_max(corr_image_window))) {
00891         cpl_image_delete(corr_image_window);
00892         return NULL;
00893     }
00894 
00895     return corr_image_window;
00896 }
00897 
00898 /*
00899 static cpl_image       *
00900 irplib_detmon_image_autocorrelate_fftw(const cpl_image * image,
00901                                        const int m, const int n)
00902 {
00903     cpl_image              *input;
00904     cpl_image              *image_padded;
00905 
00906     int                     nx, ny;
00907     int                     i;
00908 
00909     fftwf_plan              p1;
00910     fftwf_complex          *fourier;
00911     fftwf_plan              p_inv;
00912 
00913     cpl_image              *corr_image;
00914     cpl_image              *corr_image_window;
00915     cpl_image              *reorganised;
00916     cpl_image              *image1;
00917     int                     npix;
00918     size_t                  bigsize;
00919     float                  *in;
00920 
00921 
00922     cpl_ensure(image != NULL, CPL_ERROR_NULL_INPUT, NULL);
00923 
00924     cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
00925     cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
00926 
00927     nx = cpl_image_get_size_x(image);
00928     ny = cpl_image_get_size_y(image);
00929 
00930     npix = (nx + 2 * m) * (ny + 2 * n);
00931 
00932 
00933     bigsize = 2 * (npix / 2 + 1);
00934 
00935 
00936     in = (float *) fftw_malloc(sizeof(float) * bigsize);
00937 
00938 
00939     input = cpl_image_cast(image, CPL_TYPE_FLOAT);
00940 
00941     image_padded = cpl_image_wrap_float(nx, ny, in);
00942     cpl_image_copy(image_padded, input, m + 1, n + 1);
00943     cpl_image_delete(input);
00944 
00945 
00946     nx = nx + 2 * m;
00947     ny = ny + 2 * n;
00948 
00949 
00950     fourier = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * nx * ny);
00951     p1 = fftwf_plan_dft_r2c_2d(ny, nx, in, fourier, FFTW_FORWARD);
00952 
00953 
00954     fftwf_execute(p1);
00955 
00956 
00957     fftwf_destroy_plan(p1);
00958     cpl_image_unwrap(image_padded);
00959 
00960 
00961     p_inv = fftwf_plan_dft_c2r_2d(ny, nx, fourier, in, FFTW_BACKWARD);
00962 
00963 
00964     for(i = 0; i < nx * ny; i++) {
00965         fourier[i] = conj(fourier[i]) * fourier[i];
00966     }
00967 
00968 
00969     fftwf_execute(p_inv);
00970 
00971 
00972     fftwf_destroy_plan(p_inv);
00973 
00974     fftwf_free(fourier);
00975 
00976 
00977     corr_image = cpl_image_wrap_float(nx, ny, in);
00978 
00979 
00980     reorganised = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00981 
00982     image1 = cpl_image_extract(corr_image, nx / 2 + 1, 1, nx, ny);
00983     cpl_image_copy(reorganised, image1, 1, 1);
00984     cpl_image_delete(image1);
00985 
00986     image1 = cpl_image_extract(corr_image, 1, 1, nx / 2, ny);
00987     cpl_image_copy(reorganised, image1, nx / 2 + 1, 1);
00988     cpl_image_delete(image1);
00989 
00990     cpl_image_unwrap(corr_image);
00991     fftwf_free(in);
00992 
00993     corr_image = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00994     image1 = cpl_image_extract(reorganised, 1, ny / 2 + 1, nx, ny);
00995     cpl_image_copy(corr_image, image1, 1, 1);
00996     cpl_image_delete(image1);
00997 
00998     image1 = cpl_image_extract(reorganised, 1, 1, nx, ny / 2);
00999     cpl_image_copy(corr_image, image1, 1, ny / 2 + 1);
01000     cpl_image_delete(image1);
01001 
01002 
01003     corr_image_window = cpl_image_extract(corr_image,
01004                                           nx / 2 + 1 - m,
01005                                           ny / 2 + 1 - n,
01006                                           nx / 2 + 1 + m, ny / 2 + 1 + n);
01007 
01008 
01009     cpl_image_delete(reorganised);
01010     cpl_image_delete(corr_image);
01011 
01012     if(cpl_image_divide_scalar(corr_image_window,
01013                                cpl_image_get_max(corr_image_window))) {
01014         cpl_image_delete(corr_image_window);
01015         return NULL;
01016     }
01017 
01018     return corr_image_window;
01019 }
01020 */
01021 
01022 #endif
01023 
01024 /*--------------------------------------------------------------------------*/
01025 
01026 /*
01027  * @brief  Autocorrelate an image with a given range of shifts, using
01028  *         cpl_image_fft()
01029  * @param  input        Input image
01030  * @param  m            Shift to apply on the x-axis
01031  * @param  n            Shift to apply on the y-axis
01032  * @return              An image of size 2m+1 by 2n+1. Each pixel value
01033  *                      corresponds to the correlation of shift the position
01034  *                      of the pixel. Pixel in the centre (m+1, n+1),
01035  *                      corresponds to shift (0,0). Pixels to the left and
01036  *                      down correspond to negative shifts.
01037  */
01038 
01039 /*--------------------------------------------------------------------------*/
01040 
01041 cpl_image              *
01042 irplib_detmon_autocorrelate(const cpl_image * input2, const int m,
01043                             const int n)
01044 {
01045     cpl_image              *im_re = NULL;
01046     cpl_image              *im_im = NULL;
01047     int                     nx, ny;
01048     cpl_image              *ifft_re = NULL;
01049     cpl_image              *ifft_im = NULL;
01050     cpl_image              *autocorr = NULL;
01051     cpl_image              *autocorr_norm_double = NULL;
01052     cpl_image              *autocorr_norm = NULL;
01053 
01054 //    double                  max;
01055     cpl_image              *reorganised = NULL;
01056     cpl_image              *image = NULL;
01057     int                     p;
01058     cpl_error_code          error;
01059     cpl_image              *input;
01060 
01061     cpl_ensure(input2 != NULL, CPL_ERROR_NULL_INPUT, NULL);
01062 
01063     cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
01064     cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
01065 
01066     nx = cpl_image_get_size_x(input2) + 2 * m;
01067     ny = cpl_image_get_size_y(input2) + 2 * n;
01068 
01069     p = 128;
01070     while(nx > p || ny > p) {
01071         p *= 2;
01072     }
01073 
01074     input = cpl_image_cast(input2, CPL_TYPE_DOUBLE);
01075 
01076     im_re = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01077     error = cpl_image_copy(im_re, input, 1, 1);
01078     cpl_ensure(!error, error, NULL);
01079 
01080     im_im = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01081 
01082     error = cpl_image_fft(im_re, im_im, CPL_FFT_DEFAULT);
01083     cpl_ensure(!error, error, NULL);
01084 
01085     ifft_re = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01086     //ifft_im = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
01087 
01088     error = cpl_image_power(im_re, 2);
01089     cpl_ensure(!error, error, NULL);
01090 
01091     error = cpl_image_add(ifft_re, im_re);
01092     cpl_ensure(!error, error, NULL);
01093 
01094     cpl_image_delete(im_re);
01095 
01096     error = cpl_image_power(im_im, 2);
01097     cpl_ensure(!error, error, NULL);
01098 
01099     error = cpl_image_add(ifft_re, im_im);
01100     cpl_ensure(!error, error, NULL);
01101 
01102     cpl_image_delete(im_im);
01103 
01104     ifft_im = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01105 
01106     error = cpl_image_fft(ifft_re, ifft_im, CPL_FFT_INVERSE);
01107     cpl_ensure(!error, error, NULL);
01108 
01109     autocorr = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01110 
01111     error = cpl_image_power(ifft_re, 2);
01112     cpl_ensure(!error, error, NULL);
01113 
01114     error = cpl_image_add(autocorr, ifft_re);
01115     cpl_ensure(!error, error, NULL);
01116 
01117     cpl_image_delete(ifft_re);
01118 
01119     error = cpl_image_power(ifft_im, 2);
01120     cpl_ensure(!error, error, NULL);
01121 
01122     error = cpl_image_add(autocorr, ifft_im);
01123     cpl_ensure(!error, error, NULL);
01124 
01125     cpl_image_delete(ifft_im);
01126 
01127 //    max = cpl_image_get_max(autocorr);
01128 
01129     //   cpl_image_divide_scalar(autocorr, max);
01130 
01131     /* Reorganise the pixels to the output */
01132     reorganised = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01133 
01134     image = cpl_image_extract(autocorr, p / 2 + 1, 1, p, p);
01135     cpl_image_copy(reorganised, image, 1, 1);
01136     cpl_image_delete(image);
01137 
01138     image = cpl_image_extract(autocorr, 1, 1, p / 2, p);
01139     cpl_image_copy(reorganised, image, p / 2 + 1, 1);
01140     cpl_image_delete(image);
01141 
01142     cpl_image_delete(autocorr);
01143 
01144     autocorr = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01145 
01146     image = cpl_image_extract(reorganised, 1, p / 2 + 1, p, p);
01147     cpl_image_copy(autocorr, image, 1, 1);
01148     cpl_image_delete(image);
01149 
01150     image = cpl_image_extract(reorganised, 1, 1, p, p / 2);
01151     cpl_image_copy(autocorr, image, 1, p / 2 + 1);
01152     cpl_image_delete(image);
01153 
01154     cpl_image_delete(reorganised);
01155 
01156     autocorr_norm_double =
01157         cpl_image_extract(autocorr, p / 2 + 1 - m, p / 2 + 1 - n,
01158                           p / 2 + 1 + m, p / 2 + 1 + n);
01159 
01160     cpl_image_delete(autocorr);
01161 
01162     if(cpl_image_divide_scalar(autocorr_norm_double,
01163                                cpl_image_get_max(autocorr_norm_double))) {
01164         cpl_image_delete(autocorr_norm_double);
01165         cpl_ensure(0, cpl_error_get_code(), NULL);
01166     }
01167 
01168 
01169     autocorr_norm = cpl_image_cast(autocorr_norm_double, CPL_TYPE_FLOAT);
01170     cpl_image_delete(autocorr_norm_double);
01171 
01172     cpl_image_delete(input);
01173 
01174     return autocorr_norm;
01175 }
01176 
01177 /*--------------------------------------------------------------------------*/
01178 
01179 /*
01180  * @brief  Fill the necessary parameters for linearity/gain
01181 
01182  * used called from rrrecipe_create()
01183  * @param parlist       Parameterlist
01184  */
01185 
01186 /*--------------------------------------------------------------------------*/
01187 
01188 int
01189 irplib_detmon_fill_params_default(cpl_parameterlist * parlist,
01190                                   const char *recipe_name,
01191                                   const char *pipeline_name)
01192 {
01193     irplib_detmon_fill_params(parlist, recipe_name, pipeline_name,
01194                   "PTC", /* --method */
01195                   3,   /* --order         */
01196                               3,        /* --kappa         */
01197                               25,       /* --niter         */
01198                               0,        /* --threshold_min */
01199                               10000,    /* --threshold_max */
01200                               -1,       /* --llx           */
01201                               -1,       /* --lly           */
01202                               -1,       /* --urx           */
01203                               -1,       /* --ury           */
01204                               10000,    /* --ref_level     */
01205                               10000,    /* --threshold     */
01206                               "CPL_FALSE",      /* --intermediate  */
01207                               "CPL_FALSE",      /* --autocorr      */
01208                               "CPL_FALSE",      /* --collapse      */
01209                               "CPL_TRUE",       /* --rescale       */
01210                               -1,       /* --filter        */
01211                               26,       /* --m             */
01212                               26,       /* --n             */
01213                               -1,       /* --llx1          */
01214                               -1,       /* --lly1          */
01215                               -1,       /* --urx1          */
01216                               -1,       /* --ury1          */
01217                               -1,       /* --llx2          */
01218                               -1,       /* --lly2          */
01219                               -1,       /* --urx2          */
01220                               -1,       /* --ury2          */
01221                               -1,       /* --llx3          */
01222                               -1,       /* --lly3          */
01223                               -1,       /* --urx3          */
01224                               -1,       /* --ury3          */
01225                               -1,       /* --llx4          */
01226                               -1,       /* --lly4          */
01227                               -1,       /* --urx4          */
01228                               -1,       /* --ury4          */
01229                               -1,       /* --llx5          */
01230                               -1,       /* --lly5          */
01231                               -1,       /* --urx5          */
01232                               -1,       /* --ury5          */
01233                               0);       /* --exts          */
01234 
01235     return 0;
01236 
01237 }
01238 
01239 int
01240 irplib_detmon_fill_params(cpl_parameterlist * parlist,
01241                           const char *recipe_name, const char *pipeline_name,
01242               const char *method,
01243                           int order,
01244                           int kappa,
01245                           int niter,
01246                           int threshold_min,
01247                           int threshold_max,
01248                           int llx,
01249                           int lly,
01250                           int urx,
01251                           int ury,
01252                           int ref_level,
01253                           int threshold,
01254                           const char *intermediate,
01255                           const char *autocorr,
01256                           const char *collapse,
01257                           const char *rescale,
01258                           int filter,
01259                           int m,
01260                           int n,
01261                           int llx1,
01262                           int lly1,
01263                           int urx1,
01264                           int ury1,
01265                           int llx2,
01266                           int lly2,
01267                           int urx2,
01268                           int ury2,
01269                           int llx3,
01270                           int lly3,
01271                           int urx3,
01272                           int ury3,
01273                           int llx4,
01274                           int lly4,
01275                           int urx4,
01276                           int ury4,
01277                           int llx5, int lly5, int urx5, int ury5, int exts)
01278 {
01279     irplib_detmon_fill_parlist(parlist, recipe_name, pipeline_name, 40,
01280                    "method",
01281                    "Method to be used when computing GAIN. Methods appliable: <PTC | MED>. By default PTC method will be applied.",
01282                                    "CPL_TYPE_STRING", method,
01283 
01284                                "order",
01285                                "Polynomial order for the fit (Linearity)",
01286                                "CPL_TYPE_INT", order,
01287                                "kappa",
01288                                "Kappa value for the kappa-sigma clipping (Gain)",
01289                                "CPL_TYPE_INT", kappa,
01290                                "niter",
01291                                "Number of iterations to compute rms (Gain)",
01292                                "CPL_TYPE_INT", niter,
01293                                "threshold_min",
01294                                "Minimum optional threshold for clean mean method",
01295                                "CPL_TYPE_INT", threshold_min,
01296                                "threshold_max",
01297                                "Maximum optional threshold for clean mean method",
01298                                "CPL_TYPE_INT", threshold_max,
01299                                "llx",
01300                                "x coordinate of the lower-left "
01301                                "point of the region of interest. If not modified, default value will be 1.",
01302                                "CPL_TYPE_INT", llx,
01303                                "lly",
01304                                "y coordinate of the lower-left "
01305                                "point of the region of interest. If not modified, default value will be 1.",
01306                                "CPL_TYPE_INT", lly,
01307                                "urx",
01308                                "x coordinate of the upper-right "
01309                                "point of the region of interest. If not modified, default value will be X dimension of the input image.",
01310                                "CPL_TYPE_INT", urx,
01311                                "ury",
01312                                "y coordinate of the upper-right "
01313                                "point of the region of interest. If not modified, default value will be Y dimension of the input image.",
01314                                "CPL_TYPE_INT", ury,
01315                                "ref_level",
01316                                "User reference level",
01317                                "CPL_TYPE_INT", ref_level,
01318                                "threshold",
01319                                "Intensity of threshold pixels",
01320                                "CPL_TYPE_INT", threshold,
01321                                "intermediate",
01322                                "De-/Activate intermediate products",
01323                                "CPL_TYPE_BOOL", intermediate,
01324                                "autocorr",
01325                                "De-/Activate the autocorr option",
01326                                "CPL_TYPE_BOOL", autocorr,
01327                                "collapse",
01328                                "De-/Activate the collapse option",
01329                                "CPL_TYPE_BOOL", collapse,
01330                                "rescale",
01331                                "De-/Activate the collapse option",
01332                                "CPL_TYPE_BOOL", rescale,
01333                                "m",
01334                                "Maximum x-shift for the autocorr",
01335                                "CPL_TYPE_INT", m,
01336                                "filter",
01337                                "Upper limit of Median flux to be filtered",
01338                                "CPL_TYPE_INT", filter,
01339                                "n",
01340                                "Maximum y-shift for the autocorr",
01341                                "CPL_TYPE_INT", n,
01342                                "llx1",
01343                                "x coord of the lower-left point of the first "
01344                                "field used for contamination measurement. If not modified, default value will be 1.",
01345                                "CPL_TYPE_INT", llx1,
01346                                "lly1",
01347                                "y coord of the lower-left point of the first "
01348                                "field used for contamination measurement. If not modified, default value will be 1.",
01349                                "CPL_TYPE_INT", lly1,
01350                                "urx1",
01351                                "x coord of the upper-right point of the first "
01352                                "field used for contamination measurement. If not modified, default value will be X dimension of the input image.",
01353                                "CPL_TYPE_INT", urx1,
01354                                "ury1",
01355                                "y coord of the upper-right point of the first "
01356                                "field used for contamination measurement. If not modified, default value will be Y dimension of the input image.",
01357                                "CPL_TYPE_INT", ury1,
01358                                "llx2",
01359                                "x coord of the lower-left point of the second "
01360                                "field used for contamination measurement. If not modified, default value will be 1.",
01361                                "CPL_TYPE_INT", llx2,
01362                                "lly2",
01363                                "y coord of the lower-left point of the second "
01364                                "field used for contamination measurement. If not modified, default value will be 1.",
01365                                "CPL_TYPE_INT", lly2,
01366                                "urx2",
01367                                "x coord of the upper-right point of the second "
01368                                "field used for contamination measurement. If not modified, default value will be half of the X dimension of the input image.",
01369                                "CPL_TYPE_INT", urx2,
01370                                "ury2",
01371                                "y coord of the upper-right point of the second "
01372                                "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
01373                                "CPL_TYPE_INT", ury2,
01374                                "llx3",
01375                                "x coord of the lower-left point of the third "
01376                                "field used for contamination measurement. If not modified, default value will be 1.",
01377                                "CPL_TYPE_INT", llx3,
01378                                "lly3",
01379                                "y coord of the lower-left point of the third "
01380                                "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
01381                                "CPL_TYPE_INT", lly3,
01382                                "urx3",
01383                                "x coord of the upper-right point of the third "
01384                                "field used for contamination measurement. If not modified, default value will be half of X dimension of the image.",
01385                                "CPL_TYPE_INT", urx3,
01386                                "ury3",
01387                                "y coord of the upper-right point of the third "
01388                                "field used for contamination measurement. If not modified, default value will be Y dimension of the image.",
01389                                "CPL_TYPE_INT", ury3,
01390                                "llx4",
01391                                "x coord of the lower-left point of the fourth "
01392                                "field used for contamination measurement. If not modified, default value will be half of X dimension of the image.",
01393                                "CPL_TYPE_INT", llx4,
01394                                "lly4",
01395                                "y coord of the lower-left point of the fourth "
01396                                "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
01397                                "CPL_TYPE_INT", lly4,
01398                                "urx4",
01399                                "x coord of the upper-right point of the fourth "
01400                                "field used for contamination measurement. If not modified, default value will be X dimension of the image.",
01401                                "CPL_TYPE_INT", urx4,
01402                                "ury4",
01403                                "y coord of the upper-right point of the fourth "
01404                                "field used for contamination measurement. If not modified, default value will be Y dimension of the input image.",
01405                                "CPL_TYPE_INT", ury4,
01406                                "llx5",
01407                                "x coord of the lower-left point of the fifth "
01408                                "field used for contamination measurement. If not modified, default value will be half of the X dimension of the input image.",
01409                                "CPL_TYPE_INT", llx5,
01410                                "lly5",
01411                                "y coord of the lower-left point of the fifth "
01412                                "field used for contamination measurement. If not modified, default value will be 1.",
01413                                "CPL_TYPE_INT", lly5,
01414                                "urx5",
01415                                "x coord of the upper-right point of the fifth "
01416                                "field used for contamination measurement. If not modified, default value will be X dimension of the image.",
01417                                "CPL_TYPE_INT", urx5,
01418                                "ury5",
01419                                "y coord of the upper-right point of the fifth "
01420                                "field used for contamination measurement. If not modified, default value will be half of Y dimension of the input image.",
01421                                "CPL_TYPE_INT", ury5,
01422                                "exts",
01423                                "Activate the multi-exts option",
01424                                "CPL_TYPE_INT", exts);
01425 
01426     return 0;
01427 }
01428 
01429 static cpl_error_code
01430 irplib_detmon_lg_retrieve_parlist(const char *pipeline_name,
01431                               const char *recipe_name,
01432                               const cpl_parameterlist * parlist)
01433 {
01434 
01435     char                   *par_name;
01436     cpl_parameter          *par;
01437 
01438     /* --method */
01439     par_name = cpl_sprintf("%s.%s.method", pipeline_name, recipe_name);
01440     assert(par_name != NULL);
01441     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01442     detmon_lg_config.method = cpl_parameter_get_string(par);
01443     cpl_free(par_name);
01444 
01445     /* --order */
01446     detmon_lg_config.order =
01447         irplib_detmon_retrieve_par("order", pipeline_name, recipe_name,
01448                                    parlist);
01449 
01450     /* --kappa */
01451     detmon_lg_config.kappa =
01452         irplib_detmon_retrieve_par("kappa", pipeline_name, recipe_name,
01453                                    parlist);
01454 
01455     /* --niter */
01456     detmon_lg_config.niter =
01457         irplib_detmon_retrieve_par("niter", pipeline_name, recipe_name,
01458                                    parlist);
01459 
01460     /* --threshold_min */
01461     detmon_lg_config.threshold_min =
01462         irplib_detmon_retrieve_par("threshold_min", pipeline_name,
01463                                    recipe_name, parlist);
01464 
01465     /* --threshold_max */
01466     detmon_lg_config.threshold_max =
01467         irplib_detmon_retrieve_par("threshold_max", pipeline_name,
01468                                    recipe_name, parlist);
01469 
01470     /* --llx */
01471     detmon_lg_config.llx =
01472         irplib_detmon_retrieve_par("llx", pipeline_name, recipe_name,
01473                                    parlist);
01474 
01475     /* --lly */
01476     detmon_lg_config.lly =
01477         irplib_detmon_retrieve_par("lly", pipeline_name, recipe_name,
01478                                    parlist);
01479 
01480     /* --urx */
01481     detmon_lg_config.urx =
01482         irplib_detmon_retrieve_par("urx", pipeline_name, recipe_name,
01483                                    parlist);
01484 
01485     /* --ury */
01486     detmon_lg_config.ury =
01487         irplib_detmon_retrieve_par("ury", pipeline_name, recipe_name,
01488                                    parlist);
01489 
01490     /* --ref_level */
01491     detmon_lg_config.ref_level =
01492         irplib_detmon_retrieve_par("ref_level", pipeline_name, recipe_name,
01493                                    parlist);
01494 
01495     /* --threshold */
01496     detmon_lg_config.threshold =
01497         irplib_detmon_retrieve_par("threshold", pipeline_name, recipe_name,
01498                                    parlist);
01499 
01500     /* --intermediate */
01501     par_name =
01502         cpl_sprintf("%s.%s.intermediate", pipeline_name, recipe_name);
01503     assert(par_name != NULL);
01504     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01505     detmon_lg_config.intermediate = cpl_parameter_get_bool(par);
01506     cpl_free(par_name);
01507  
01508     /* --autocorr */
01509     par_name = cpl_sprintf("%s.%s.autocorr", pipeline_name, recipe_name);
01510     assert(par_name != NULL);
01511     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01512     detmon_lg_config.autocorr = cpl_parameter_get_bool(par);
01513     cpl_free(par_name);
01514 
01515     /* --collapse */
01516     par_name = cpl_sprintf("%s.%s.collapse", pipeline_name, recipe_name);
01517     assert(par_name != NULL);
01518     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01519     detmon_lg_config.collapse = cpl_parameter_get_bool(par);
01520     cpl_free(par_name);
01521 
01522     /* --filter */
01523     detmon_lg_config.filter =
01524         irplib_detmon_retrieve_par("filter", pipeline_name,
01525                                    recipe_name, parlist);
01526 
01527     /* --m */
01528     detmon_lg_config.m =
01529         irplib_detmon_retrieve_par("m", pipeline_name, recipe_name, parlist);
01530 
01531     /* --n */
01532     detmon_lg_config.n =
01533         irplib_detmon_retrieve_par("n", pipeline_name, recipe_name, parlist);
01534 
01535     /* --llx1 */
01536     detmon_lg_config.llx1 =
01537         irplib_detmon_retrieve_par("llx1", pipeline_name, recipe_name,
01538                                    parlist);
01539 
01540     /* --lly1 */
01541     detmon_lg_config.lly1 =
01542         irplib_detmon_retrieve_par("lly1", pipeline_name, recipe_name,
01543                                    parlist);
01544 
01545     /* --urx1 */
01546     detmon_lg_config.urx1 =
01547         irplib_detmon_retrieve_par("urx1", pipeline_name, recipe_name,
01548                                    parlist);
01549 
01550     /* --ury1 */
01551     detmon_lg_config.ury1 =
01552         irplib_detmon_retrieve_par("ury1", pipeline_name, recipe_name,
01553                                    parlist);
01554 
01555     /* --llx2 */
01556     detmon_lg_config.llx2 =
01557         irplib_detmon_retrieve_par("llx2", pipeline_name, recipe_name,
01558                                    parlist);
01559 
01560     /* --lly2 */
01561     detmon_lg_config.lly2 =
01562         irplib_detmon_retrieve_par("lly2", pipeline_name, recipe_name,
01563                                    parlist);
01564 
01565     /* --urx2 */
01566     detmon_lg_config.urx2 =
01567         irplib_detmon_retrieve_par("urx2", pipeline_name, recipe_name,
01568                                    parlist);
01569 
01570     /* --ury2 */
01571     detmon_lg_config.ury2 =
01572         irplib_detmon_retrieve_par("ury2", pipeline_name, recipe_name,
01573                                    parlist);
01574 
01575     /* --llx3 */
01576     detmon_lg_config.llx3 =
01577         irplib_detmon_retrieve_par("llx3", pipeline_name, recipe_name,
01578                                    parlist);
01579 
01580     /* --lly3 */
01581     detmon_lg_config.lly3 =
01582         irplib_detmon_retrieve_par("lly3", pipeline_name, recipe_name,
01583                                    parlist);
01584 
01585     /* --urx3 */
01586     detmon_lg_config.urx3 =
01587         irplib_detmon_retrieve_par("urx3", pipeline_name, recipe_name,
01588                                    parlist);
01589 
01590     /* --ury3 */
01591     detmon_lg_config.ury3 =
01592         irplib_detmon_retrieve_par("ury3", pipeline_name, recipe_name,
01593                                    parlist);
01594 
01595     /* --llx4 */
01596     detmon_lg_config.llx4 =
01597         irplib_detmon_retrieve_par("llx4", pipeline_name, recipe_name,
01598                                    parlist);
01599 
01600     /* --lly4 */
01601     detmon_lg_config.lly4 =
01602         irplib_detmon_retrieve_par("lly4", pipeline_name, recipe_name,
01603                                    parlist);
01604 
01605     /* --urx4 */
01606     detmon_lg_config.urx4 =
01607         irplib_detmon_retrieve_par("urx4", pipeline_name, recipe_name,
01608                                    parlist);
01609 
01610     /* --ury4 */
01611     detmon_lg_config.ury4 =
01612         irplib_detmon_retrieve_par("ury4", pipeline_name, recipe_name,
01613                                    parlist);
01614 
01615     /* --llx5 */
01616     detmon_lg_config.llx5 =
01617         irplib_detmon_retrieve_par("llx5", pipeline_name, recipe_name,
01618                                    parlist);
01619 
01620     /* --lly5 */
01621     detmon_lg_config.lly5 =
01622         irplib_detmon_retrieve_par("lly5", pipeline_name, recipe_name,
01623                                    parlist);
01624 
01625     /* --urx5 */
01626     detmon_lg_config.urx5 =
01627         irplib_detmon_retrieve_par("urx5", pipeline_name, recipe_name,
01628                                    parlist);
01629 
01630     /* --ury5 */
01631     detmon_lg_config.ury5 =
01632         irplib_detmon_retrieve_par("ury5", pipeline_name, recipe_name,
01633                                    parlist);
01634 
01635     /* --exts */
01636     detmon_lg_config.exts =
01637         irplib_detmon_retrieve_par("exts", pipeline_name, recipe_name,
01638                                    parlist);
01639 
01640     if(cpl_error_get_code()) {
01641         cpl_msg_error(cpl_func, "Failed to retrieve the input parameters");
01642         cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
01643     }
01644 
01645 
01646     return CPL_ERROR_NONE;
01647 }
01648 
01649 /*---------------------------------------------------------------------------*/
01650 
01651 /*
01652  * @brief  Retrieve input parameters
01653  * @param  pipeline_name        Input image
01654  * @param  recipe_name          Input image
01655  * @param  parlist              Shift to apply on the x-axis
01656  * @return CPL_ERROR_NONE on success.
01657  */
01658 
01659 /*---------------------------------------------------------------------------*/
01660 static cpl_error_code
01661 irplib_detmon_lg_check_defaults(const cpl_image * reference)
01662 {
01663     const int               nx = cpl_image_get_size_x(reference);
01664     const int               ny = cpl_image_get_size_y(reference);
01665 
01666     if(detmon_lg_config.llx == -1)
01667         detmon_lg_config.llx = 1;
01668     if(detmon_lg_config.lly == -1)
01669         detmon_lg_config.lly = 1;
01670     if(detmon_lg_config.urx == -1)
01671         detmon_lg_config.urx = nx;
01672     if(detmon_lg_config.ury == -1)
01673         detmon_lg_config.ury = ny;
01674 
01675     if(detmon_lg_config.llx1 == -1)
01676         detmon_lg_config.llx1 = 1;
01677     if(detmon_lg_config.lly1 == -1)
01678         detmon_lg_config.lly1 = 1;
01679     if(detmon_lg_config.urx1 == -1)
01680         detmon_lg_config.urx1 = nx;
01681     if(detmon_lg_config.ury1 == -1)
01682         detmon_lg_config.ury1 = ny;
01683 
01684     if(detmon_lg_config.llx2 == -1)
01685         detmon_lg_config.llx2 = 1;
01686     if(detmon_lg_config.lly2 == -1)
01687         detmon_lg_config.lly2 = 1;
01688     if(detmon_lg_config.urx2 == -1)
01689         detmon_lg_config.urx2 = nx / 2;
01690     if(detmon_lg_config.ury2 == -1)
01691         detmon_lg_config.ury2 = ny / 2;
01692 
01693     if(detmon_lg_config.llx3 == -1)
01694         detmon_lg_config.llx3 = 1;
01695     if(detmon_lg_config.lly3 == -1)
01696         detmon_lg_config.lly3 = ny / 2;
01697     if(detmon_lg_config.urx3 == -1)
01698         detmon_lg_config.urx3 = nx / 2;
01699     if(detmon_lg_config.ury3 == -1)
01700         detmon_lg_config.ury3 = ny;
01701 
01702     if(detmon_lg_config.llx4 == -1)
01703         detmon_lg_config.llx4 = nx / 2;
01704     if(detmon_lg_config.lly4 == -1)
01705         detmon_lg_config.lly4 = ny / 2;
01706     if(detmon_lg_config.urx4 == -1)
01707         detmon_lg_config.urx4 = nx;
01708     if(detmon_lg_config.ury4 == -1)
01709         detmon_lg_config.ury4 = ny;
01710 
01711     if(detmon_lg_config.llx5 == -1)
01712         detmon_lg_config.llx5 = nx / 2;
01713     if(detmon_lg_config.lly5 == -1)
01714         detmon_lg_config.lly5 = 1;
01715     if(detmon_lg_config.urx5 == -1)
01716         detmon_lg_config.urx5 = nx;
01717     if(detmon_lg_config.ury5 == -1)
01718         detmon_lg_config.ury5 = ny / 2;
01719 
01720     if(detmon_lg_config.intermediate == TRUE) {
01721         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.");
01722         detmon_lg_config.autocorr = TRUE;
01723     }
01724 
01725 #ifndef HAVE_FFTW
01726     if(detmon_lg_config.autocorr == TRUE)
01727         cpl_msg_warning(cpl_func,
01728                         "You don't have FFTW installed in your system."
01729                         " Please note that use of --autocorr option without it "
01730                         "will result in an execution time close to 10 minutes.");
01731 
01732 #endif
01733 
01734     return CPL_ERROR_NONE;
01735 }
01736 
01737 
01738 /*--------------------------------------------------------------------------*/
01739 
01740 /*
01741  * @brief  Split the input frameset into two sub-framesets (ON and OFF)
01742  * @param  cur_fset             Pointer to input frameset
01743  * @param  cur_fset_on          Pointer to output ON sub-frameset
01744  * @param  cur_fset_off         Pointer to output OFF sub-frameset
01745  * @param  tag_on               Tag to identify ON frames
01746  * @param  tag_off              Tag to identify OFF frames
01747  * @return cpl_error_code.
01748  */
01749 
01750 /*--------------------------------------------------------------------------*/
01751 
01752 static                  cpl_error_code
01753 irplib_detmon_lg_split_onoff(const cpl_frameset * cur_fset,
01754                              cpl_frameset * cur_fset_on,
01755                              cpl_frameset * cur_fset_off,
01756                              const char *tag_on,
01757                              const char *tag_off, const cpl_boolean opt_nir)
01758 {
01759     int                     nframes;
01760     int                     i;
01761 
01762     nframes = cpl_frameset_get_size(cur_fset);
01763     for(i = opt_nir == NIR ? 0 : 2; i < nframes; i++) {
01764         const cpl_frame        *cur_frame =
01765             cpl_frameset_get_frame_const(cur_fset, i);
01766         /* Duplication is required for insertion to a different frameset */
01767         cpl_frame              *cur_frame_dup =
01768             cpl_frame_duplicate(cur_frame);
01769         char                   *tag =
01770             (char *) cpl_frame_get_tag(cur_frame_dup);
01771 
01772         /* Insertion in the corresponding sub-frameset */
01773         if(!strcmp(tag, tag_on)) {
01774             cpl_error_reset();
01775             cpl_frameset_insert(cur_fset_on, cur_frame_dup);
01776             if(cpl_error_get_code() != CPL_ERROR_NONE) {
01777                 cpl_msg_error(cpl_func,
01778                               "Cannot insert ON frame nb %d into "
01779                               "corresponding sub-frameset", i + 1);
01780                 cpl_frame_delete(cur_frame_dup);
01781                 cpl_ensure_code(0, cpl_error_get_code());
01782             }
01783         } else if(!strcmp(tag, tag_off)) {
01784             cpl_error_reset();
01785             cpl_frameset_insert(cur_fset_off, cur_frame_dup);
01786             if(cpl_error_get_code() != CPL_ERROR_NONE) {
01787                 cpl_msg_error(cpl_func, "Cannot insert OFF frame nb %d into "
01788                               "corresponding sub-frameset", i + 1);
01789                 cpl_frame_delete(cur_frame_dup);
01790                 cpl_ensure_code(0, cpl_error_get_code());
01791             }
01792         } else {
01793             cpl_frame_delete(cur_frame_dup);
01794         }
01795     }
01796 
01797     return CPL_ERROR_NONE;
01798 }
01799 
01800 /*--------------------------------------------------------------------------*/
01801 
01802 /*
01803  * @brief  Apply linearity and gain reduction algorithms
01804  * @param  set_on               ON sub-frameset
01805  * @param  set_off              OFF sub-frameset
01806  * @param  selection_on         Array of labels to identify pairs in set_on
01807  * @param  selection_off        Array of labels to identify pairs in set_off
01808  * @param  nsets_extracted      Number of pairs in each sub-frameset
01809  * @param  coeffs_ptr           Pointer to output coeffs imagelist
01810  * @param  gain_table_ptr       Pointer to output gain table
01811  * @param  linear_table_ptr     Pointer to output linearity table
01812  * @param  bpm_ptr              Pointer to output bad pixel map
01813  * @param  autocorr_images      Pointer to output corr imagelist (intermediate)
01814  * @param  diff_flats           Pointer to output diff imagelist (intermediate)
01815  * @param  qclist               Pointer to output qclist
01816  * @param  opt_nir              Boolean to differ OPT and NIR cases
01817  * @return cpl_error_code.
01818  */
01819 
01820 /*--------------------------------------------------------------------------*/
01821 
01822 static cpl_error_code
01823 irplib_detmon_lg_reduce(const cpl_frameset * set_on,
01824                         const cpl_frameset * set_off,
01825                         int *selection_on,
01826                         int *selection_off,
01827                         int nsets_extracted,
01828                         cpl_imagelist ** coeffs_ptr,
01829                         cpl_table ** gain_table_ptr,
01830                         cpl_table ** linear_table_ptr,
01831                         cpl_image ** bpm_ptr,
01832                         cpl_imagelist ** autocorr_images,
01833                         cpl_imagelist ** diff_flats,
01834                         cpl_propertylist ** qclist,
01835          int                    (* load_fset) (const cpl_frameset *,
01836                                cpl_type,
01837                                                cpl_imagelist *),
01838             const cpl_boolean opt_nir)
01839 {
01840     int                     i, j;
01841     cpl_imagelist         **linearity_inputs = NULL;
01842     cpl_table             **fit_table = NULL;
01843     cpl_vector            **x_pos = NULL;
01844     cpl_imagelist         **opt_offs = NULL;
01845     cpl_error_code          error;
01846     int                     nsets;
01847     cpl_propertylist       *reflist = NULL;
01848 
01849     /* Test entries */
01850     cpl_ensure(set_on != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
01851     cpl_ensure(set_off != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
01852 
01853     nsets = cpl_frameset_get_size(set_on) / 2;
01854 
01855     /* Initialise memory for products */
01856     fit_table = (cpl_table **) cpl_malloc(detmon_lg_config.nb_extensions *
01857                                           sizeof(cpl_table *));
01858     if(opt_nir == NIR) {
01859         linearity_inputs =
01860             (cpl_imagelist **) cpl_malloc(detmon_lg_config.nb_extensions *
01861                                           sizeof(cpl_imagelist *));
01862         x_pos =
01863             (cpl_vector **) cpl_malloc(detmon_lg_config.nb_extensions *
01864                                        sizeof(cpl_vector *));
01865     } else {
01866 
01867     // if(detmon_lg_config.collapse) {
01868         /*
01869          * When the 'collapse' option is used, there are no OFF pairs. We
01870          * construct a pair with the 2 first raw OFF frames, which will be
01871          * passed for each DIT value, to maintain the same API in the function
01872          * irplib_detmon_gain().
01873          */
01874 
01875         const cpl_frame        *first = cpl_frameset_get_first_const(set_off);
01876         cpl_frame              *dup_first = cpl_frame_duplicate(first);
01877 
01878         const cpl_frame        *second = cpl_frameset_get_next_const(set_off);
01879         cpl_frame              *dup_second = cpl_frame_duplicate(second);
01880 
01881         cpl_frameset           *raw_offs = cpl_frameset_new();
01882 
01883         cpl_frameset_insert(raw_offs, dup_first);
01884         cpl_frameset_insert(raw_offs, dup_second);
01885 
01886     opt_offs = irplib_detmon_ilist_load_fset(raw_offs, CPL_TYPE_FLOAT);
01887 
01888         cpl_frameset_delete(raw_offs);
01889 
01891 
01892     }
01893 
01894     irplib_detmon_lg_reduce_init(opt_nir, gain_table_ptr,
01895                                  linear_table_ptr, fit_table,
01896                                  linearity_inputs, x_pos, qclist, nsets);
01897 
01898 //    irplib_detmon_lg_lamp_stab(
01899 
01900     /* Loop on every DIT value */
01901     for(i = 0; i < nsets_extracted; i++) {
01902     skip_if(irplib_detmon_lg_reduce_dit(set_on, selection_on, i,
01903                         &nsets_extracted, set_off,
01904                         selection_off, linear_table_ptr,
01905                         gain_table_ptr, linearity_inputs,
01906                         x_pos, qclist, opt_nir, fit_table,
01907                         autocorr_images, diff_flats,nsets,
01908                         opt_offs, load_fset));
01909     }
01910 
01911     for(i = 0; i < detmon_lg_config.nb_extensions; i++) {
01912         reflist = cpl_propertylist_new();
01913         skip_if(cpl_propertylist_append_bool(reflist, "ADU", FALSE));
01914         skip_if(cpl_table_sort(gain_table_ptr[i], reflist));
01915     }
01916 
01917     /*
01918      * --Final reduction--
01919      * The following call to irplib_detmon_lg_reduce_all() makes the
01920      * computations which are over all posible DIT values.
01921      */
01922 
01923     /* FIXME: error checking should be done here, and function returned
01924      * if any error present
01925      */
01926     for(i = 0; i < detmon_lg_config.nb_extensions; i++) {
01927         if(opt_nir == NIR) {
01928             error = irplib_detmon_lg_reduce_all(linear_table_ptr[i], fit_table[i],
01929                                         qclist[i], &coeffs_ptr[i], &bpm_ptr[i],
01930                                         x_pos[i], linearity_inputs[i],
01931                                                 gain_table_ptr[i], opt_nir, i+1);
01932         } else {
01933             error = irplib_detmon_lg_reduce_all(linear_table_ptr[i], fit_table[i],
01934                                         qclist[i], NULL, NULL, NULL, NULL,
01935                                                 gain_table_ptr[i], opt_nir, i+1);
01936         }
01937         cpl_ensure_code(!error, error);
01938     }
01939 
01940     end_skip;
01941 
01942     if(linearity_inputs) {
01943         for(i = 0; i < detmon_lg_config.nb_extensions; i++) {
01944             cpl_imagelist_delete(linearity_inputs[i]);
01945         }
01946         cpl_free(linearity_inputs);
01947         linearity_inputs = NULL;
01948     }
01949     if(x_pos) {
01950         for(i = 0; i < detmon_lg_config.nb_extensions; i++) {
01951             cpl_vector_delete(x_pos[i]);
01952         }
01953         cpl_free(x_pos);
01954         x_pos = NULL;
01955     }
01956     if(fit_table) {
01957         for(i = 0; i < detmon_lg_config.nb_extensions; i++) {
01958             cpl_table_delete(fit_table[i]);
01959         }
01960         cpl_free(fit_table);
01961         fit_table = NULL;
01962     }
01963 
01964     if(detmon_lg_config.collapse) {
01965         for(j = 0; j < detmon_lg_config.nb_extensions; j++) {
01966             cpl_imagelist_delete(opt_offs[j]);
01967         }
01968         cpl_free(opt_offs);
01969         opt_offs = NULL;
01970     }
01971 
01972     cpl_propertylist_delete(reflist);
01973 
01974     return CPL_ERROR_NONE;
01975 }
01976 
01977 static cpl_error_code
01978 irplib_detmon_lg_reduce_dit(const cpl_frameset * set_on,
01979                 int * selection_on,
01980                 int dit_nb,
01981                 int * nsets_extracted,
01982                 const cpl_frameset * set_off,
01983                 int * selection_off,
01984                 cpl_table ** linear_table_ptr,
01985                 cpl_table ** gain_table_ptr,
01986                 cpl_imagelist ** linearity_inputs,
01987                 cpl_vector ** x_pos,
01988                 cpl_propertylist ** qclist,
01989                 cpl_boolean opt_nir,
01990                 cpl_table ** fit_table,
01991                 cpl_imagelist ** autocorr_images,
01992                 cpl_imagelist ** diff_flats,
01993                             int nsets,
01994                             cpl_imagelist ** opt_offs,
01995                 int                    (* load_fset) (const cpl_frameset *,
01996                                cpl_type,
01997                                   cpl_imagelist *))
01998 {
01999     cpl_frameset           *pair_on = NULL;
02000     cpl_frameset           *pair_off = NULL;
02001     cpl_imagelist         **ons = NULL;
02002     cpl_imagelist         **offs = NULL;
02003     int                     with_equal_dit = 0;
02004     cpl_boolean             follow = CPL_TRUE;
02005     int j;
02006     cpl_imagelist ** masterl = NULL;
02007 
02008     /* ON pair extraction */
02009     pair_on = irplib_detmon_pair_extract(set_on, selection_on, dit_nb, nsets_extracted, &with_equal_dit, 1);
02010 
02011     skip_if(pair_on == NULL);
02012 
02013     /* Load the ON images */
02014     if (load_fset != NULL) {
02015     cpl_imagelist * p = cpl_imagelist_new();
02016     (*load_fset)(pair_on, CPL_TYPE_FLOAT, p);
02017     ons = &p;
02018     } else {
02019     ons = irplib_detmon_ilist_load_fset(pair_on, CPL_TYPE_FLOAT);
02020     }
02021     skip_if(*ons == NULL);
02022     
02023     if(detmon_lg_config.filter > 0) {
02024     for (j = 0; j < detmon_lg_config.nb_extensions; j++) {
02025         double med1 =
02026         cpl_image_get_median_window(cpl_imagelist_get(ons[j], 0),
02027                         detmon_lg_config.llx,
02028                         detmon_lg_config.lly,
02029                         detmon_lg_config.urx,
02030                         detmon_lg_config.ury);
02031         double med2 = 
02032         cpl_image_get_median_window(cpl_imagelist_get(ons[j], 1),
02033                         detmon_lg_config.llx,
02034                         detmon_lg_config.lly,
02035                         detmon_lg_config.urx,
02036                         detmon_lg_config.ury);
02037         if ( med1 > (double)detmon_lg_config.filter ||
02038          med2 > (double)detmon_lg_config.filter) {
02039         follow = CPL_FALSE;
02040         break;
02041         }
02042     }
02043     }
02044 
02045     if (follow || detmon_lg_config.filter < 0) {
02046     /*
02047      * If the --collapse option is not activated by the user, the OFF 
02048      * sub-frameset is also supposed to be organized into pairs and,
02049      * therefore, processed as the ON sub-frameset.
02050      */
02051     if(!detmon_lg_config.collapse) {
02052         pair_off = 
02053         irplib_detmon_pair_extract(set_off, selection_off, dit_nb, nsets_extracted, &with_equal_dit, 0);
02054 
02055         skip_if(pair_off == NULL || cpl_error_get_code());
02056         /* Load the OFF images */
02057         if (load_fset != NULL) {
02058         cpl_imagelist * p = cpl_imagelist_new();
02059         (*load_fset)(pair_off, CPL_TYPE_FLOAT, p);
02060         offs = &p;
02061         } else {
02062         offs = irplib_detmon_ilist_load_fset(pair_off, CPL_TYPE_FLOAT);
02063         }
02064         skip_if(*offs == NULL);
02065         skip_if(cpl_error_get_code());
02066         /* Exchange by skip_if(offs == NULL); ? */
02067     } else {
02068         /*
02069          * The master bias is required only for 
02070          * linearity computation in the OPT domain
02071          */
02072         masterl = irplib_detmon_ilist_load_fset(set_off, CPL_TYPE_FLOAT);
02073         skip_if(cpl_error_get_code());
02074         /* Exchange by skip_if(offs == NULL); ? */
02075         for(j = 0; j < detmon_lg_config.nb_extensions; j++) {
02076         cpl_image * collapse = 
02077             cpl_imagelist_collapse_create(masterl[j]);
02078         /* Error checking missing here */
02079         skip_if(cpl_imagelist_set(masterl[j], collapse, 0));
02080         }
02081         /* Any extra error checking needed here? */
02082         offs = (cpl_imagelist **)masterl;
02083     }
02084 
02085     /* Linearity reduction */
02086     for(j = 0; j < detmon_lg_config.nb_extensions; j++) {
02087         skip_if(irplib_detmon_linearity(pair_on, linear_table_ptr,
02088                         gain_table_ptr,
02089                         linearity_inputs, x_pos,
02090                         ons, offs, dit_nb,
02091                         nsets, qclist,j, opt_nir));
02092         skip_if(irplib_detmon_add_adl_column(linear_table_ptr[j]));
02093     }
02094 
02095 
02096     /*
02097      * --GAIN part for each DIT value--
02098      * The following call to irplib_detmon_gain() fills in the row nb i
02099      * of the GAIN table (output) and of the FIT table (by-product to be
02100      * used later for the polynomial computation of the GAIN)
02101      */
02102     if(detmon_lg_config.collapse) {
02103         offs = (cpl_imagelist **) opt_offs;
02104     }
02105 
02106     cpl_msg_info(cpl_func, "Computing GAIN for EXPTIME value nb %d",
02107              dit_nb + 1);
02108     for(j = 0; j < detmon_lg_config.nb_extensions; j++) {
02109         skip_if(irplib_detmon_gain(gain_table_ptr[j], fit_table[j],
02110                        autocorr_images[j], diff_flats[j],
02111                        ons[j], offs[j], dit_nb));
02112     }
02113     }
02114 
02115     end_skip;
02116 
02117     cpl_frameset_delete(pair_on);
02118     for(j = 0; j < detmon_lg_config.nb_extensions; j++) {
02119     cpl_imagelist_delete(ons[j]);
02120     }
02121     if(load_fset == NULL) cpl_free(ons);
02122     ons = NULL;
02123 
02124     if(!detmon_lg_config.collapse ) {
02125     for(j = 0; j < detmon_lg_config.nb_extensions; j++) {
02126         cpl_imagelist_delete(offs[j]);
02127     }
02128     if(load_fset == NULL)cpl_free(offs);
02129     offs = NULL;
02130     }
02131 
02132     if(!detmon_lg_config.collapse) {
02133     cpl_frameset_delete(pair_off);
02134     }
02135 
02136     if(detmon_lg_config.collapse) {
02137     for(j = 0; j < detmon_lg_config.nb_extensions; j++) {
02138         cpl_imagelist_delete(masterl[j]);
02139     }
02140     cpl_free(masterl);
02141     }
02142 
02143 
02144     return cpl_error_get_code();
02145 }
02146 /*---------------------------------------------------------------------------*/
02147 
02148 /*
02149  * @brief  Retrieve input parameters
02150  * @param  pipeline_name        Input image
02151  * @param  recipe_name          Input image
02152  * @param  parlist              Shift to apply on the x-axis
02153  * @return CPL_ERROR_NONE on success.
02154  */
02155 
02156 /*---------------------------------------------------------------------------*/
02157 cpl_error_code
02158 irplib_detmon_add_adl_column(cpl_table * table)
02159 {
02160     cpl_error_code          error;
02161     double                  mean_med_dit =
02162         cpl_table_get_column_mean(table, "MED_DIT");
02163     double                 *dits = cpl_table_get_data_double(table, "DIT");
02164 
02165     error = cpl_table_copy_data_double(table, "ADL", dits);
02166     cpl_ensure_code(!error, error);
02167     error = cpl_table_multiply_scalar(table, "ADL", mean_med_dit);
02168     cpl_ensure_code(!error, error);
02169 
02170     return CPL_ERROR_NONE;
02171 }
02172 
02173 /*---------------------------------------------------------------------------*/
02174 
02175 /*
02176  * @brief  Retrieve input parameters
02177  * @param  pipeline_name        Input image
02178  * @param  recipe_name          Input image
02179  * @param  parlist              Shift to apply on the x-axis
02180  * @return CPL_ERROR_NONE on success.
02181  */
02182 
02183 /*---------------------------------------------------------------------------*/
02184 static cpl_error_code
02185 irplib_detmon_lg_reduce_init(cpl_boolean opt_nir,
02186                              cpl_table ** gain_table_ptr,
02187                              cpl_table ** linear_table_ptr,
02188                              cpl_table ** fit_table,
02189                              cpl_imagelist ** linearity_inputs,
02190                              cpl_vector ** x_pos,
02191                              cpl_propertylist ** qclist,
02192                              int nsets)
02193 {
02194     int                     i;
02195 
02196     for(i = 0; i < detmon_lg_config.nb_extensions; i++) {
02197         /* Initialise */
02198         gain_table_ptr[i] = cpl_table_new(nsets);
02199         cpl_table_new_column(gain_table_ptr[i], "DIT", CPL_TYPE_DOUBLE);
02200         cpl_table_new_column(gain_table_ptr[i], "EXPTIME", CPL_TYPE_DOUBLE);
02201         cpl_table_new_column(gain_table_ptr[i], "MEAN_ON1", CPL_TYPE_DOUBLE);
02202         cpl_table_new_column(gain_table_ptr[i], "MEAN_ON2", CPL_TYPE_DOUBLE);
02203         cpl_table_new_column(gain_table_ptr[i], "MEAN_OFF1", CPL_TYPE_DOUBLE);
02204         cpl_table_new_column(gain_table_ptr[i], "MEAN_OFF2", CPL_TYPE_DOUBLE);
02205         cpl_table_new_column(gain_table_ptr[i], "SIG_ON_DIF",
02206                              CPL_TYPE_DOUBLE);
02207         cpl_table_new_column(gain_table_ptr[i], "SIG_OFF_DIF",
02208                              CPL_TYPE_DOUBLE);
02209         cpl_table_new_column(gain_table_ptr[i], "GAIN", CPL_TYPE_DOUBLE);
02210         cpl_table_new_column(gain_table_ptr[i], "AUTOCORR", CPL_TYPE_DOUBLE);
02211         cpl_table_new_column(gain_table_ptr[i], "GAIN_CORR", CPL_TYPE_DOUBLE);
02212         cpl_table_new_column(gain_table_ptr[i], "ADU", CPL_TYPE_DOUBLE);
02213         cpl_table_new_column(gain_table_ptr[i], "X_FIT", CPL_TYPE_DOUBLE);
02214         cpl_table_new_column(gain_table_ptr[i], "Y_FIT", CPL_TYPE_DOUBLE);
02215 
02216 
02217         linear_table_ptr[i] = cpl_table_new(nsets);
02218         cpl_table_new_column(linear_table_ptr[i], "DIT", CPL_TYPE_DOUBLE);
02219         cpl_table_new_column(linear_table_ptr[i], "EXPTIME", CPL_TYPE_DOUBLE);
02220         cpl_table_new_column(linear_table_ptr[i], "MED", CPL_TYPE_DOUBLE);
02221         cpl_table_new_column(linear_table_ptr[i], "MEAN", CPL_TYPE_DOUBLE);
02222         cpl_table_new_column(linear_table_ptr[i], "MED_DIT", CPL_TYPE_DOUBLE);
02223         cpl_table_new_column(linear_table_ptr[i], "MEAN_DIT",
02224                              CPL_TYPE_DOUBLE);
02225         cpl_table_new_column(linear_table_ptr[i], "ADL", CPL_TYPE_DOUBLE);
02226 
02227         fit_table[i] = cpl_table_new(nsets);
02228         cpl_table_new_column(fit_table[i], "Y", CPL_TYPE_DOUBLE);
02229         cpl_table_new_column(fit_table[i], "X", CPL_TYPE_DOUBLE);
02230 
02231         qclist[i] = cpl_propertylist_new();
02232 
02233         if(opt_nir == NIR) {
02234             linearity_inputs[i] = cpl_imagelist_new();
02235             x_pos[i] = cpl_vector_new(nsets);
02236         }
02237     }
02238 
02239     return cpl_error_get_code();
02240 }
02241 
02242 /*--------------------------------------------------------------------------*/
02243 
02244 /*
02245  * @brief    Find out the character string associated to the DIT keyword
02246  *           in a propertylist
02247  * @param    plist      Propertylist 
02248  * @return   DIT value
02249  */
02250 
02251 /*--------------------------------------------------------------------------*/
02252 
02253 /*
02254 double
02255 irplib_pfits_get_exptime(const cpl_propertylist * plist)
02256 {
02257     double                  dit;
02258 
02259     dit = cpl_propertylist_get_double(plist, "ESO DET DIT");
02260 
02261     if(cpl_error_get_code() != CPL_ERROR_NONE) {
02262         cpl_msg_error(cpl_func, cpl_error_get_where());
02263     }
02264     return dit;
02265 }*/
02266 
02267 /*--------------------------------------------------------------------------*/
02268 
02269 /*
02270  * @brief    Find out the character string associated to the DIT keyword
02271  *           in a propertylist
02272  * @param    plist      Propertylist 
02273  * @return   DIT value
02274  */
02275 
02276 /*--------------------------------------------------------------------------*/
02277 
02278 /*--------------------------------------------------------------------------*/
02279 
02280 /*
02281  * @brief    Operate on input ON and OFF images related to linearity
02282  * @param    pair                       Frameset to retrieve DIT value 
02283  * @param    linearity_inputs_ptr       Pointer to the imagelist where image
02284  *                                      is to be stored 
02285  * @param    x_pos_ptr                  Pointer to the vector where DIT values
02286  *                                      are to be stored
02287  * @param    ons                        Images of the ON pair
02288  * @param    offs                       Images of the OFF pair
02289  * @param    pos                        Position to store image in both
02290  *                                      imagelist and vector
02291  * @return   cpl_error_code.
02292  */
02293 
02294 /*--------------------------------------------------------------------------*/
02295 
02296 static                  cpl_error_code
02297 irplib_detmon_linearity(const cpl_frameset * pair,
02298                         cpl_table ** linear_table,
02299                         cpl_table ** gain_table,
02300                         cpl_imagelist ** linearity_inputs,
02301                         cpl_vector ** x_pos,
02302                         cpl_imagelist ** ons,
02303                         cpl_imagelist ** offs,
02304                         const int pos,
02305                         const int nsets,
02306                         cpl_propertylist ** qclist,
02307             const int whichext, const cpl_boolean opt_nir)
02308 {
02309     const char             *filename;
02310     cpl_propertylist       *plist;
02311     cpl_image              *dif1;
02312     cpl_image              *dif2;
02313     cpl_image              *dif_avg;
02314     double                  med_dit;
02315     double                  mean_dit;
02316     double                  exptime, dit;
02317     cpl_error_code          error;
02318 
02319     cpl_ensure_code(ons[whichext] != NULL, CPL_ERROR_NULL_INPUT);
02320     cpl_ensure_code(offs[whichext] != NULL, CPL_ERROR_NULL_INPUT);
02321     /* DIT needed for linearity */
02322     filename = cpl_frame_get_filename(cpl_frameset_get_first_const(pair));
02323     if((plist = cpl_propertylist_load(filename, 0)) == NULL) {
02324         cpl_msg_error(cpl_func, "getting header from reference frame");
02325         cpl_ensure_code(0, cpl_error_get_code());
02326     }
02327 
02328     dit = irplib_pfits_get_exptime(plist);
02329     /*FIXME: These 2 calls shouldn't be the same... */
02330     exptime = irplib_pfits_get_exptime(plist);
02331 
02332     cpl_table_set(linear_table[whichext], "DIT", pos, dit);
02333     cpl_table_set(gain_table[whichext], "DIT", pos, dit);
02334 
02335     cpl_table_set(linear_table[whichext], "EXPTIME", pos, exptime);
02336     cpl_table_set(gain_table[whichext], "EXPTIME", pos, exptime);
02337 
02338     /* Algorithm defined: substract ON - OFF and average 2 differences */
02339     dif1 = cpl_image_subtract_create(cpl_imagelist_get_const(ons[whichext], 0),
02340                                      cpl_imagelist_get_const(offs[whichext], 0));
02341     if(!detmon_lg_config.collapse)
02342         dif2 = cpl_image_subtract_create(cpl_imagelist_get_const(ons[whichext], 1),
02343                                          cpl_imagelist_get_const(offs[whichext], 1));
02344     else
02345         dif2 = cpl_image_subtract_create(cpl_imagelist_get_const(ons[whichext], 1),
02346                                          cpl_imagelist_get_const(offs[whichext], 0));
02347 
02348     dif_avg = cpl_image_average_create(dif1, dif2);
02349     cpl_ensure_code(dif_avg != NULL, cpl_error_get_code());
02350 
02351     if(opt_nir == OPT && pos == nsets / 2) {
02352         irplib_detmon_opt_contamination(dif_avg, qclist[whichext]);
02353     }
02354 
02355     cpl_table_set(linear_table[whichext], "MED", pos, cpl_image_get_median(dif_avg));
02356     cpl_table_set(linear_table[whichext], "MEAN", pos, cpl_image_get_mean(dif_avg));
02357     med_dit = cpl_image_get_median(dif_avg) / irplib_pfits_get_exptime(plist);
02358     mean_dit = cpl_image_get_mean(dif_avg) / irplib_pfits_get_exptime(plist);
02359 
02360     cpl_table_set(linear_table[whichext], "MED_DIT", pos, med_dit);
02361     cpl_table_set(linear_table[whichext], "MEAN_DIT", pos, mean_dit);
02362 
02363     /* Compute lamp count rate */
02364     if(pos == 0)
02365         detmon_lg_config.cr = cpl_image_get_mean(dif_avg) / dit;
02366 
02367     cpl_image_delete(dif1);
02368     cpl_image_delete(dif2);
02369     cpl_propertylist_delete(plist);
02370 
02371     /* Insert to the imagelist used to fit the polynomial */
02372     if(opt_nir == NIR) {
02373         error = cpl_imagelist_set(linearity_inputs[whichext], dif_avg, pos);
02374         cpl_ensure_code(!error, error);
02375         cpl_vector_set(x_pos[whichext], pos, dit);
02376     } else {
02377         cpl_image_delete(dif_avg);
02378     }
02379 
02380     return CPL_ERROR_NONE;
02381 }
02382 
02383 /*---------------------------------------------------------------------------*/
02384 
02385 /*
02386  * @brief    Operate on input ON and OFF images related to gain
02387  * @param    gain_table_ptr             Pointer to the table to store values
02388  * @param    ons                        Images of the ON pair
02389  * @param    offs                       Images of the OFF pair
02390  * @param    pos                        Position to store image in both
02391  *                                      imagelist and vector
02392  * @return   cpl_error_code.
02393  */
02394 
02395 /*---------------------------------------------------------------------------*/
02396 
02397 static                  cpl_error_code
02398 irplib_detmon_gain(cpl_table * gain_table,
02399                    cpl_table * fit_table,
02400                    cpl_imagelist * autocorr_images,
02401                    cpl_imagelist * diff_flats,
02402                    cpl_imagelist * ons, cpl_imagelist * offs, const int pos)
02403 {
02404     const cpl_image        *image;
02405     double                  std;
02406     cpl_image              *on_dif;
02407     cpl_image              *off_dif;
02408     double                  avg_on1, avg_on2;
02409     double                  avg_off1, avg_off2;
02410     double                  avg_on_dif, sig_on_dif;
02411     double                  avg_off_dif, sig_off_dif;
02412     double                  double_adu, autocorr, gain, gain_corr;
02413     double                  sigma, sigma_corr;
02414     cpl_error_code          error;
02415 
02416     std = 0;
02417 
02418     error = irplib_detmon_lg_rescale(ons);
02419     cpl_ensure_code(!error, error);
02420 
02421     error = irplib_detmon_lg_rescale(offs);
02422     cpl_ensure_code(!error, error);
02423 
02424 
02425     if((image = cpl_imagelist_get_const(ons, 0)) == NULL) {
02426         cpl_ensure_code(0, cpl_error_get_code());
02427     }
02428     
02429     irplib_get_clean_mean_window(image,
02430                                  detmon_lg_config.llx,
02431                                  detmon_lg_config.lly,
02432                                  detmon_lg_config.urx,
02433                                  detmon_lg_config.ury,
02434                                  detmon_lg_config.kappa,
02435                                  detmon_lg_config.niter, &avg_on1, &std);
02436     cpl_ensure_code(cpl_error_get_code() == CPL_ERROR_NONE,
02437                     cpl_error_get_code());
02438     cpl_table_set_double(gain_table, "MEAN_ON1", pos, avg_on1);
02439 
02440     if((image = cpl_imagelist_get_const(ons, 1)) == NULL) {
02441         cpl_ensure_code(0, cpl_error_get_code());
02442     }
02443 
02444     irplib_get_clean_mean_window(image,
02445                                  detmon_lg_config.llx,
02446                                  detmon_lg_config.lly,
02447                                  detmon_lg_config.urx,
02448                                  detmon_lg_config.ury,
02449                                  detmon_lg_config.kappa,
02450                                  detmon_lg_config.niter, &avg_on2, &std);
02451     cpl_ensure_code(cpl_error_get_code() == CPL_ERROR_NONE,
02452                     cpl_error_get_code());
02453     cpl_table_set_double(gain_table, "MEAN_ON2", pos, avg_on2);
02454 
02455     on_dif =
02456         cpl_image_subtract_create(cpl_imagelist_get_const(ons, 0),
02457                                   cpl_imagelist_get_const(ons, 1));
02458 
02459     irplib_get_clean_mean_window(on_dif, detmon_lg_config.llx,
02460                                  detmon_lg_config.lly,
02461                                  detmon_lg_config.urx,
02462                                  detmon_lg_config.ury,
02463                                  detmon_lg_config.kappa,
02464                                  detmon_lg_config.niter, &avg_on_dif,
02465                                  &sig_on_dif);
02466     cpl_ensure_code(cpl_error_get_code() == CPL_ERROR_NONE,
02467                     cpl_error_get_code());
02468     // sig_on_dif=0.5;
02469     error = cpl_table_set_double(gain_table, "SIG_ON_DIF", pos, sig_on_dif);
02470     cpl_ensure_code(!error, error);
02471 
02472     autocorr = irplib_detmon_autocorr_factor(on_dif, pos, autocorr_images);
02473 
02474     if(detmon_lg_config.intermediate) {
02475         error = cpl_imagelist_set(diff_flats, on_dif, pos);
02476         cpl_ensure_code(!error, error);
02477     }
02478 
02479 
02480     cpl_ensure_code(cpl_error_get_code() == CPL_ERROR_NONE,
02481                     cpl_error_get_code());
02482 
02483     if (!detmon_lg_config.collapse || pos == 0) {
02484         irplib_get_clean_mean_window(cpl_imagelist_get_const(offs, 0),
02485                                      detmon_lg_config.llx,
02486                                      detmon_lg_config.lly,
02487                                      detmon_lg_config.urx,
02488                                      detmon_lg_config.ury,
02489                                      detmon_lg_config.kappa,
02490                                      detmon_lg_config.niter, &avg_off1, &std);
02491         cpl_ensure_code(cpl_error_get_code() == CPL_ERROR_NONE,
02492                         cpl_error_get_code());
02493         cpl_table_set_double(gain_table, "MEAN_OFF1", pos, avg_off1);
02494         detmon_lg_config.avg_off1 = avg_off1;
02495         irplib_get_clean_mean_window(cpl_imagelist_get_const(offs, 1),
02496                                      detmon_lg_config.llx,
02497                                      detmon_lg_config.lly,
02498                                      detmon_lg_config.urx,
02499                                      detmon_lg_config.ury,
02500                                      detmon_lg_config.kappa,
02501                                      detmon_lg_config.niter, &avg_off2, &std);
02502         cpl_ensure_code(cpl_error_get_code() == CPL_ERROR_NONE,
02503                         cpl_error_get_code());
02504         cpl_table_set_double(gain_table, "MEAN_OFF2", pos, avg_off2);
02505         detmon_lg_config.avg_off2 = avg_off2;
02506         off_dif =
02507             cpl_image_subtract_create(cpl_imagelist_get_const(offs, 0),
02508                                       cpl_imagelist_get_const(offs, 1));
02509         irplib_get_clean_mean_window(off_dif, detmon_lg_config.llx,
02510                                      detmon_lg_config.lly,
02511                                      detmon_lg_config.urx,
02512                                      detmon_lg_config.ury,
02513                                      detmon_lg_config.kappa,
02514                                      detmon_lg_config.niter, &avg_off_dif,
02515                                      &sig_off_dif);
02516         cpl_ensure_code(cpl_error_get_code() == CPL_ERROR_NONE,
02517                         cpl_error_get_code());
02518         cpl_table_set_double(gain_table, "SIG_OFF_DIF", pos, sig_off_dif);
02519         detmon_lg_config.sig_off_dif = sig_off_dif;
02520         cpl_image_delete(off_dif);
02521     } else {
02522         cpl_table_set_double(gain_table, "MEAN_OFF1", pos,
02523                              detmon_lg_config.avg_off1);
02524         cpl_table_set_double(gain_table, "MEAN_OFF2", pos,
02525                              detmon_lg_config.avg_off2);
02526         cpl_table_set_double(gain_table, "SIG_OFF_DIF", pos,
02527                              detmon_lg_config.sig_off_dif);
02528     }
02529 
02530     double_adu = (avg_on1 + avg_on2) - (avg_off1 + avg_off2);
02531 
02532     sigma = (sig_on_dif * sig_on_dif) - (sig_off_dif * sig_off_dif);
02533 
02534     sigma_corr = autocorr * sigma;
02535 
02536     gain = double_adu / sigma;
02537 
02538     gain_corr = double_adu / sigma_corr;
02539 
02540     if(cpl_table_set_double(gain_table, "GAIN", pos, gain)) {
02541         cpl_ensure_code(0, cpl_error_get_code());
02542     }
02543     if(cpl_table_set_double(gain_table, "AUTOCORR", pos, autocorr)) {
02544         cpl_ensure_code(0, cpl_error_get_code());
02545     }
02546     if(cpl_table_set_double(gain_table, "GAIN_CORR", pos, gain_corr)) {
02547         cpl_ensure_code(0, cpl_error_get_code());
02548     }
02549     if(cpl_table_set_double(gain_table, "ADU", pos, double_adu / 2)) {
02550         cpl_ensure_code(0, cpl_error_get_code());
02551     }
02552 
02553     /* FIXME: Remove the following 2 calls to CPL after testing period */
02554     if(cpl_table_set_double
02555        (gain_table, "Y_FIT", pos, sig_on_dif * sig_on_dif)) {
02556         cpl_ensure_code(0, cpl_error_get_code());
02557     }
02558     if(cpl_table_set_double(gain_table, "X_FIT", pos, double_adu)) {
02559         cpl_ensure_code(0, cpl_error_get_code());
02560     }
02561 
02562     /* Changed for the new fitting formula */
02563     if(cpl_table_set_double(fit_table, "Y", pos, sig_on_dif * sig_on_dif)) {
02564         cpl_ensure_code(0, cpl_error_get_code());
02565     }
02566     if(cpl_table_set_double(fit_table, "X", pos, double_adu / autocorr)) {
02567         cpl_ensure_code(0, cpl_error_get_code());
02568     }
02569     return CPL_ERROR_NONE;
02570 }
02571 
02572 /*--------------------------------------------------------------------------*/
02573 
02574 /*
02575  * @brief  Detect bad pixels based on polynomial coefficients obtained
02576  *         for each pixel
02577  * @param  imagelist    Input cube; each plane correspond to a coefficient
02578  * @return              Cube with bad pixels on each plane
02579  */
02580 
02581 /*--------------------------------------------------------------------------*/
02582 
02583 static cpl_image       *
02584 irplib_detmon_bpixs(const cpl_imagelist * coeffs, int *nbpixs)
02585 {
02586     int                     size;
02587     int                     i;
02588     const cpl_image        *cur_coeff;
02589     cpl_stats              *stats;
02590     double                  cur_mean;
02591     double                  cur_stdev;
02592     double                  lo_cut;
02593     double                  hi_cut;
02594     cpl_mask               *cur_mask;
02595     cpl_image              *cur_image;
02596     cpl_image              *bpm = NULL;
02597     double                  p;
02598 
02599     size = cpl_imagelist_get_size(coeffs);
02600 
02601     for(i = 0; i < size; i++) {
02602         cur_coeff = cpl_imagelist_get_const(coeffs, i);
02603         if(!i) {
02604             bpm = cpl_image_new(cpl_image_get_size_x(cur_coeff),
02605                                 cpl_image_get_size_y(cur_coeff),
02606                                 CPL_TYPE_INT);
02607         }
02608         stats = cpl_stats_new_from_image(cur_coeff,
02609                                          CPL_STATS_MEAN | CPL_STATS_STDEV);
02610         cur_mean = cpl_stats_get_mean(stats);
02611         cur_stdev = cpl_stats_get_stdev(stats);
02612 
02613         lo_cut = cur_mean - detmon_lg_config.kappa * cur_stdev;
02614         hi_cut = cur_mean + detmon_lg_config.kappa * cur_stdev;
02615 
02616         cur_mask = cpl_mask_threshold_image_create(cur_coeff, lo_cut, hi_cut);
02617         cpl_mask_not(cur_mask);
02618 
02619         *nbpixs += cpl_mask_count(cur_mask);
02620 
02621         cur_image = cpl_image_new_from_mask(cur_mask);
02622         p = pow(2, i);
02623         cpl_image_power(cur_image, p);
02624         cpl_image_add(bpm, cur_image);
02625 
02626         cpl_mask_delete(cur_mask);
02627         cpl_image_delete(cur_image);
02628         cpl_stats_delete(stats);
02629     }
02630 
02631     return bpm;
02632 }
02633 
02634 
02635 /*---------------------------------------------------------------------------*/
02636 
02637 /*
02638  * @brief  Compute autocorr factor
02639  * @param  image        Input image
02640  * @return              Autocorrelation factor used as correction for gain
02641  *                      formula
02642  */
02643 
02644 /*---------------------------------------------------------------------------*/
02645 
02646 static double
02647 irplib_detmon_autocorr_factor(const cpl_image * image, const int pos,
02648                               cpl_imagelist * autocorr_images)
02649 {
02650     cpl_image *autocorr_image;
02651 #ifdef HAVE_FFTW
02652     if(detmon_lg_config.autocorr) {
02653         cpl_msg_info(cpl_func,
02654                      "Computing autocorr factor for DIT value nb %d ", pos + 1);
02655 
02656 //        autocorr_image = irplib_detmon_image_autocorrelate_fftw(image, detmon_lg_config.m, detmon_lg_config.m);
02657         autocorr_image =
02658             irplib_detmon_image_correlate(image, image, detmon_lg_config.m,
02659                                           detmon_lg_config.m);
02660         if(autocorr_image == NULL) {
02661             return -1;
02662         }
02663     } else {
02664         return 1.0;
02665     }
02666 #else
02667     if(detmon_lg_config.autocorr) {
02668         cpl_msg_info(cpl_func,
02669                      "Computing autocorr factor for DIT value nb %d ", pos + 1);
02670 
02671         autocorr_image =
02672             irplib_detmon_autocorrelate(image, detmon_lg_config.m,
02673                                         detmon_lg_config.m);
02674         if(autocorr_image == NULL) {
02675             return -1;
02676         }
02677     } else {
02678         return 1.0;
02679     }
02680 #endif
02681     cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), -1);
02682 
02683 //    cpl_image_subtract_scalar(autocorr_image,
02684 //                cpl_image_get_median(autocorr_image));
02685 
02686     if (detmon_lg_config.intermediate) {
02687         cpl_imagelist_set(autocorr_images, autocorr_image, pos);
02688         return cpl_image_get_flux(autocorr_image);
02689     } else {
02690         double autocorr = cpl_image_get_flux(autocorr_image);
02691         cpl_image_delete(autocorr_image);
02692         return autocorr;
02693     }
02694 }
02695 
02696 
02697 /*--------------------------------------------------------------------------*/
02698 
02699 /*
02700  * @brief  Function to save the products
02701  */
02702 
02703 /*--------------------------------------------------------------------------*/
02704 
02705 static cpl_error_code
02706 irplib_detmon_lg_save(const cpl_parameterlist * parlist,
02707                       cpl_frameset * frameset,
02708                       const char *recipe_name,
02709                       const char *pipeline_name,
02710                       const char *pafregexp,
02711                       const char *procatg_lintbl,
02712                       const char *procatg_gaintbl,
02713                       const char *procatg_lincoeff,
02714                       const char *procatg_bpm,
02715                       const char *procatg_corr,
02716                       const char *procatg_diff,
02717                       const char *package,
02718                       cpl_imagelist ** coeffs,
02719                       cpl_table ** gain_table,
02720                       cpl_table ** linear_table,
02721                       cpl_image ** bpms,
02722                       cpl_imagelist ** autocorr_images,
02723                       cpl_imagelist ** diff_flats,
02724                       cpl_propertylist ** qclist,
02725                       const int flag_sets,
02726                       const int which_set,
02727                       const cpl_frameset * usedframes, cpl_boolean opt_nir)
02728 {
02729 
02730     cpl_frame              *ref_frame;
02731     cpl_propertylist       *plist;
02732     cpl_propertylist       *mainplist;
02733     char                   *name_o = NULL; /* Avoid (false) uninit warning */
02734 //    char                   *name_coeff;
02735 
02736 //    cpl_frame              *product_frame;
02737     int                     nb_images;
02738     int                     i;
02739     cpl_error_code          error;
02740     cpl_propertylist **     xplist = NULL;
02741 
02742 
02743     /* Extract extension headers if multi-extension */
02744     if (detmon_lg_config.exts < 0) {
02745         const char * filename =
02746             cpl_frame_get_filename(cpl_frameset_get_first(frameset));
02747         xplist = 
02748             (cpl_propertylist **) cpl_malloc(detmon_lg_config.nb_extensions *
02749                                       sizeof(cpl_propertylist *));
02750         for (i = 0; i < detmon_lg_config.nb_extensions; i ++) {
02751             xplist[i] = cpl_propertylist_load_regexp(filename, i+1,
02752                                                      "ESO DET", 0);
02753             error = cpl_propertylist_append(xplist[i], qclist[i]);
02754             cpl_ensure_code(!error, error);
02755         }
02756     }
02757 
02758     /* This is only used later for PAF and temporarily for COEFFS_CUBE
02759        (see if defined)*/
02760     /* Get FITS header from reference file */
02761     ref_frame = cpl_frameset_get_first(frameset);
02762 
02763     if((mainplist =
02764     cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
02765                   0)) == NULL) {
02766     cpl_msg_error(cpl_func, "getting header from reference frame");
02767     cpl_ensure_code(0, cpl_error_get_code());
02768     }
02769 
02770 
02771     /*******************************/
02772     /*  Write the LINEARITY TABLE  */
02773 
02774     /*******************************/
02775 
02776     /* Set the file name for the table */
02777     if(!flag_sets) {
02778         name_o = cpl_sprintf("%s_linearity_table.fits", recipe_name);
02779         assert(name_o != NULL);
02780     } else {
02781         name_o =
02782             cpl_sprintf("%s_linearity_table_set%02d.fits", recipe_name,
02783                            which_set);
02784         assert(name_o != NULL);
02785     }
02786 
02787     if (detmon_lg_config.exts >= 0) {
02788         /* Save the table */
02789         if(cpl_dfs_save_table(frameset, parlist, usedframes, linear_table[0],
02790                               NULL, recipe_name, procatg_lintbl, qclist[0], NULL,
02791                               package, name_o)) {
02792             cpl_msg_error(cpl_func, "Cannot save the product: %s", name_o);
02793             cpl_free(name_o);
02794             cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
02795         }
02796     } else {
02797         /* Save the 1. extension table */
02798         if(cpl_dfs_save_table(frameset, parlist, usedframes, linear_table[0],
02799                               xplist[0], recipe_name, procatg_lintbl, NULL,
02800                               NULL, package, name_o)) {
02801             cpl_msg_error(cpl_func, "Cannot save the product: %s", name_o);
02802             cpl_free(name_o);
02803             cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
02804         }
02805         for(i = 1; i < detmon_lg_config.nb_extensions; i++) {
02806             error =
02807                 cpl_table_save(linear_table[i], NULL, xplist[i], name_o,
02808                                CPL_IO_EXTEND);
02809             cpl_ensure_code(!error, error);
02810         }
02811     }
02812 
02813     /* Free */
02814     cpl_free(name_o);
02815 
02816     /**************************/
02817     /*  Write the GAIN TABLE  */
02818 
02819     /**************************/
02820 
02821     /* Set the file name for the table */
02822     if(!flag_sets) {
02823         name_o = cpl_sprintf("%s_gain_table.fits", recipe_name);
02824         assert(name_o != NULL);
02825     } else {
02826         name_o =
02827             cpl_sprintf("%s_gain_table_set%02d.fits", recipe_name,
02828                            which_set);
02829         assert(name_o != NULL);
02830     }
02831 
02832     if (detmon_lg_config.exts >= 0) {
02833         /* Save the table */
02834         if(cpl_dfs_save_table(frameset, parlist, usedframes, gain_table[0],
02835                               NULL, recipe_name, procatg_gaintbl, qclist[0],
02836                               NULL, package, name_o)) {
02837             cpl_msg_error(cpl_func, "Cannot save the product: %s", name_o);
02838             cpl_free(name_o);
02839             cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
02840         }
02841     } else {
02842         /* Save the 1. extension table */
02843         if(cpl_dfs_save_table(frameset, parlist, usedframes, gain_table[0],
02844                               xplist[0], recipe_name, procatg_gaintbl, NULL,
02845                               NULL, package, name_o)) {
02846             cpl_msg_error(cpl_func, "Cannot save the product: %s", name_o);
02847             cpl_free(name_o);
02848             cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
02849         }
02850         for(i = 1; i < detmon_lg_config.nb_extensions; i++) {
02851             error =
02852                 cpl_table_save(gain_table[i], NULL, xplist[i], name_o,
02853                                CPL_IO_EXTEND);
02854             cpl_ensure_code(!error, error);
02855         }
02856     }
02857 
02858     /* Free */
02859     cpl_free(name_o);
02860 
02861     if(opt_nir == NIR) {
02862 
02863     /***************************/
02864     /*  Write the COEFFS FITS  */
02865     /***************************/
02866 
02867     /* Set the file name for each image */
02868     if(!flag_sets) {
02869         name_o =
02870         cpl_sprintf("%s_coeffs_cube.fits", recipe_name);
02871         assert(name_o != NULL);
02872     } else {
02873         name_o =
02874         cpl_sprintf("%s_coeffs_cube_set%02d.fits",
02875                 recipe_name, which_set);
02876         assert(name_o != NULL);
02877     }
02878 
02879     /* Save the imagelist */
02880     if(detmon_lg_config.exts >= 0) {
02881 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE > CPL_VERSION(4, 0, 1)
02882         if(cpl_dfs_save_imagelist
02883            (frameset, parlist, usedframes, *coeffs, CPL_BPP_IEEE_FLOAT,
02884         recipe_name, procatg_lincoeff, qclist[0], NULL, package,
02885         name_o)) {
02886         cpl_msg_error(cpl_func, "Cannot save the product: %s",
02887                   name_o);
02888         cpl_free(name_o);
02889         cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
02890 
02891         }
02892 #else
02893         cpl_propertylist * hlist = cpl_propertylist_new();
02894         cpl_frame * product_frame = NULL;
02895 
02896         product_frame = cpl_frame_new() ;
02897         cpl_frame_set_filename(product_frame, name_o);
02898         cpl_frame_set_tag(product_frame, procatg_lincoeff);
02899         cpl_frame_set_type(product_frame, CPL_FRAME_TYPE_IMAGE);
02900         cpl_frame_set_group(product_frame, CPL_FRAME_GROUP_PRODUCT);
02901         cpl_frame_set_level(product_frame, CPL_FRAME_LEVEL_FINAL);
02902 
02903         if(cpl_dfs_setup_product_header(hlist,product_frame,frameset,
02904                         parlist,recipe_name,
02905                         package, "PRO-1.15") !=
02906            CPL_ERROR_NONE) {
02907         cpl_msg_error(cpl_func,
02908                   "Problem in the product DFS-compliance");
02909         }
02910 
02911         cpl_propertylist_append(hlist, mainplist);
02912 
02913         error = cpl_imagelist_save(coeffs[0], name_o, CPL_BPP_IEEE_FLOAT,
02914                        hlist, CPL_IO_DEFAULT);
02915         cpl_ensure_code(!error, error);
02916         cpl_propertylist_delete(hlist);
02917         cpl_frame_delete(product_frame);
02918 #endif
02919     } else {
02920         if(cpl_dfs_save_image(frameset, parlist, usedframes, NULL,
02921                   CPL_BPP_IEEE_FLOAT, recipe_name,
02922                   procatg_lincoeff, NULL, NULL,
02923                   package, name_o)) {
02924         cpl_msg_error(cpl_func, "Cannot save the product: %s",
02925                   name_o);
02926         cpl_free(name_o);
02927         cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
02928         }
02929 
02930         for(i = 0; i < detmon_lg_config.nb_extensions; i++) {
02931         error =
02932             cpl_imagelist_save(coeffs[i],
02933                    name_o, CPL_BPP_IEEE_FLOAT, xplist[i],
02934                    CPL_IO_EXTEND);
02935         cpl_ensure_code(!error, error);
02936         }
02937     }
02938     cpl_free(name_o);
02939 
02940 
02941         /*******************************/
02942         /*  Write the BAD PIXEL MAP    */
02943 
02944         /*******************************/
02945 
02946         /* Set the file name for the bpm */
02947         if(!flag_sets) {
02948             name_o = cpl_sprintf("%s_bpm.fits", recipe_name);
02949             assert(name_o != NULL);
02950         } else {
02951             name_o =
02952                 cpl_sprintf("%s_bpm_set%02d.fits", recipe_name, which_set);
02953             assert(name_o != NULL);
02954         }
02955 
02956         /* Save the image */
02957         if(detmon_lg_config.exts >= 0) {
02958             if(cpl_dfs_save_image(frameset, parlist, usedframes, *bpms,
02959                                   CPL_BPP_IEEE_FLOAT, recipe_name,
02960                                   procatg_bpm, qclist[0], NULL, package,
02961                                   name_o)) {
02962                 cpl_msg_error(cpl_func, "Cannot save the product: %s",
02963                               name_o);
02964                 cpl_free(name_o);
02965                 cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
02966             }
02967         } else {
02968             if(cpl_dfs_save_image(frameset, parlist, usedframes, NULL,
02969                                   CPL_BPP_IEEE_FLOAT, recipe_name,
02970                                   procatg_bpm, NULL, NULL, package,
02971                                   name_o)) {
02972                 cpl_msg_error(cpl_func, "Cannot save the product: %s",
02973                               name_o);
02974                 cpl_free(name_o);
02975                 cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
02976             }
02977 
02978             for(i = 0; i < detmon_lg_config.nb_extensions; i++) {
02979                 error =
02980                     cpl_image_save(bpms[i], name_o, CPL_BPP_IEEE_FLOAT,
02981                                    xplist[i], CPL_IO_EXTEND);
02982                 cpl_ensure_code(!error, error);
02983             }
02984         }
02985         /* Free */
02986         cpl_free(name_o);
02987 
02988 
02989     } /* End of if(NIR) */
02990 
02991     if(detmon_lg_config.intermediate) {
02992         /***************************/
02993         /*  Write the AUTOCORRS FITS  */
02994 
02995         /***************************/
02996         int                     j;
02997 
02998         nb_images = cpl_imagelist_get_size(autocorr_images[0]);
02999         cpl_ensure_code(nb_images > 0, CPL_ERROR_DATA_NOT_FOUND);
03000 
03001 
03002         for(i = 0; i < nb_images; i++) {
03003             /* Set the file name for each image */
03004             if(!flag_sets) {
03005                 name_o =
03006                     cpl_sprintf("%s_autocorr_%d.fits", recipe_name, i);
03007                 assert(name_o != NULL);
03008             } else {
03009                 name_o =
03010                     cpl_sprintf("%s_autocorr_%d_set%02d.fits",
03011                                    recipe_name, i, which_set);
03012                 assert(name_o != NULL);
03013             }
03014 
03015 
03016             /* Save the image */
03017             if(detmon_lg_config.exts >= 0) {
03018                 if(cpl_dfs_save_image
03019                    (frameset, parlist, usedframes,
03020                     cpl_imagelist_get(*autocorr_images, i), CPL_BPP_IEEE_FLOAT,
03021                     recipe_name, procatg_corr, qclist[0], NULL, package,
03022                     name_o)) {
03023                     cpl_msg_error(cpl_func, "Cannot save the product: %s",
03024                                   name_o);
03025                     cpl_free(name_o);
03026                     cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
03027 
03028                 }
03029             } else {
03030                 if(cpl_dfs_save_image(frameset, parlist, usedframes, NULL,
03031                                       CPL_BPP_IEEE_FLOAT, recipe_name,
03032                                       procatg_corr, NULL, NULL,
03033                                       package, name_o)) {
03034                     cpl_msg_error(cpl_func, "Cannot save the product: %s",
03035                                   name_o);
03036                     cpl_free(name_o);
03037                     cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
03038                 }
03039 
03040                 for(j = 0; j < detmon_lg_config.nb_extensions; j++) {
03041                     error =
03042                         cpl_image_save(cpl_imagelist_get(autocorr_images[j], i),
03043                                        name_o, CPL_BPP_IEEE_FLOAT, xplist[j],
03044                                        CPL_IO_EXTEND);
03045                     cpl_ensure_code(!error, error);
03046                 }
03047             }
03048             cpl_free(name_o);
03049         }
03050 
03051         /***************************/
03052         /*  Write the DIFFS FITS  */
03053 
03054         /***************************/
03055 
03056         for(i = 0; i < nb_images; i++) {
03057             /* Set the file name for each image */
03058             if(!flag_sets) {
03059                 name_o =
03060                     cpl_sprintf("%s_diff_flat_%d.fits", recipe_name, i);
03061                 assert(name_o != NULL);
03062             } else {
03063                 name_o =
03064                     cpl_sprintf("%s_diff_flat_%d_set%02d.fits",
03065                                    recipe_name, i, which_set);
03066                 assert(name_o != NULL);
03067             }
03068 
03069 
03070             /* Save the image */
03071             if(detmon_lg_config.exts >= 0) {
03072                 if(cpl_dfs_save_image
03073                    (frameset, parlist, usedframes,
03074                     cpl_imagelist_get(*diff_flats, i), CPL_BPP_IEEE_FLOAT,
03075                     recipe_name, procatg_diff, qclist[0], NULL, package,
03076                     name_o)) {
03077                     cpl_msg_error(cpl_func, "Cannot save the product: %s",
03078                                   name_o);
03079                     cpl_free(name_o);
03080                     cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
03081 
03082                 }
03083             } else {
03084                 if(cpl_dfs_save_image(frameset, parlist, usedframes, NULL,
03085                                       CPL_BPP_IEEE_FLOAT, recipe_name,
03086                                       procatg_diff, NULL, NULL,
03087                                       package, name_o)) {
03088                     cpl_msg_error(cpl_func, "Cannot save the product: %s",
03089                                   name_o);
03090                     cpl_free(name_o);
03091                     cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
03092                 }
03093 
03094                 for(j = 0; j < detmon_lg_config.nb_extensions; j++) {
03095                     error =
03096                         cpl_image_save(cpl_imagelist_get(diff_flats[j], i),
03097                                        name_o, CPL_BPP_IEEE_FLOAT, xplist[j],
03098                                        CPL_IO_EXTEND);
03099                     cpl_ensure_code(!error, error);
03100                 }
03101             }
03102             cpl_free(name_o);
03103         }
03104 
03105     } /* End of if(intermediate) */
03106 
03107     /*******************************/
03108     /*  Write the PAF file(s)      */
03109     /*******************************/
03110 
03111 
03112     for(i = 0; i < detmon_lg_config.nb_extensions; i++) {
03113         cpl_propertylist * paflist = cpl_propertylist_new();
03114 
03115 
03116         /* Set the file name for the bpm */
03117         if(detmon_lg_config.exts >= 0) {
03118         if((plist =
03119         cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
03120                       detmon_lg_config.exts)) == NULL) {
03121         cpl_msg_error(cpl_func, "getting header from reference frame");
03122         cpl_ensure_code(0, cpl_error_get_code());
03123         }
03124 
03125             if(!flag_sets) {
03126                 name_o = cpl_sprintf("%s.paf", recipe_name);
03127                 assert(name_o != NULL);
03128             } else {
03129                 name_o = cpl_sprintf("%s_set%02d.paf", recipe_name, which_set);
03130                 assert(name_o != NULL);
03131             }
03132         } else {
03133         if((plist =
03134         cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
03135                       i+1)) == NULL) {
03136         cpl_msg_error(cpl_func, "getting header from reference frame");
03137         cpl_ensure_code(0, cpl_error_get_code());
03138         }
03139 
03140             if(!flag_sets) {
03141                 name_o = cpl_sprintf("%s_ext%02d.paf", recipe_name, i+1);
03142                 assert(name_o != NULL);
03143             } else {
03144                 name_o = cpl_sprintf("%s_set%02d_ext%02d.paf", recipe_name, which_set, i+1);
03145                 assert(name_o != NULL);
03146             }
03147         }
03148 
03149     /* Get the keywords for the paf file */
03150     cpl_propertylist_copy_property_regexp(paflist, plist,
03151                           pafregexp, 0);
03152     cpl_propertylist_copy_property_regexp(paflist, mainplist,
03153                           pafregexp, 0);
03154 
03155         error = cpl_propertylist_append(paflist, qclist[i]);
03156         cpl_ensure_code(!error, error);
03157 
03158         /* Save the PAF */
03159         if(cpl_dfs_save_paf(pipeline_name, recipe_name, paflist, name_o)) {
03160             cpl_msg_error(cpl_func, "Cannot save the product: %s", name_o);
03161             cpl_free(name_o);
03162             cpl_propertylist_delete(paflist);
03163             cpl_propertylist_delete(plist);
03164         cpl_propertylist_delete(mainplist);
03165             cpl_free(name_o);
03166             cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
03167         }
03168         cpl_propertylist_delete(paflist);
03169         cpl_propertylist_delete(plist);
03170         cpl_free(name_o);
03171     } 
03172 
03173     cpl_propertylist_delete(mainplist);
03174 
03175     return cpl_error_get_code();
03176 }
03177 
03178 /*---------------------------------------------------------------------------*/
03179 
03180 /*
03181  * @brief  Function to save the products
03182 
03183  */
03184 
03185 /*---------------------------------------------------------------------------*/
03186 
03187 static                  cpl_error_code
03188 irplib_detmon_opt_contamination(const cpl_image * reduced,
03189                                 cpl_propertylist * qclist)
03190 {
03191     cpl_error_code error;
03192     double                  median[5];
03193 
03194     median[0] = cpl_image_get_median_window(reduced,
03195                                         detmon_lg_config.llx1,
03196                                         detmon_lg_config.lly1,
03197                                         detmon_lg_config.urx1,
03198                                         detmon_lg_config.ury1);
03199     error = cpl_propertylist_append_double(qclist, "ESO QC CONTAM1",
03200                                            median[0]);
03201     cpl_ensure_code(!error, error);
03202 
03203     median[1] = cpl_image_get_median_window(reduced,
03204                                         detmon_lg_config.llx2,
03205                                         detmon_lg_config.lly2,
03206                                         detmon_lg_config.urx2,
03207                                         detmon_lg_config.ury2);
03208     error = cpl_propertylist_append_double(qclist, "ESO QC CONTAM2",
03209                                            median[1]);
03210     cpl_ensure_code(!error, error);
03211 
03212     median[2] = cpl_image_get_median_window(reduced,
03213                                         detmon_lg_config.llx3,
03214                                         detmon_lg_config.lly3,
03215                                         detmon_lg_config.urx3,
03216                                         detmon_lg_config.ury3);
03217     error = cpl_propertylist_append_double(qclist, "ESO QC CONTAM3",
03218                                            median[2]);
03219     cpl_ensure_code(!error, error);
03220 
03221     median[3] = cpl_image_get_median_window(reduced,
03222                                         detmon_lg_config.llx4,
03223                                         detmon_lg_config.lly4,
03224                                         detmon_lg_config.urx4,
03225                                         detmon_lg_config.ury4);
03226     error = cpl_propertylist_append_double(qclist, "ESO QC CONTAM4",
03227                                            median[3]);
03228     cpl_ensure_code(!error, error);
03229 
03230     median[4] = cpl_image_get_median_window(reduced,
03231                                         detmon_lg_config.llx5,
03232                                         detmon_lg_config.lly5,
03233                                         detmon_lg_config.urx5,
03234                                         detmon_lg_config.ury5);
03235     error = cpl_propertylist_append_double(qclist, "ESO QC CONTAM5",
03236                                            median[4]);
03237     cpl_ensure_code(!error, error);
03238 
03239     return CPL_ERROR_NONE;
03240 }
03241 
03242 static int
03243 irplib_detmon_opt_lampcr(cpl_frameset * cur_fset)
03244 {
03245     cpl_image              *on;
03246     cpl_image              *off;
03247     cpl_frame              *first_off;
03248     cpl_frame              *first_on;
03249     cpl_propertylist       *plist;
03250     double                  dit;
03251 
03252     if((first_off = cpl_frameset_get_first(cur_fset)) == NULL) {
03253         cpl_ensure_code(0, cpl_error_get_code());
03254     }
03255     if((first_on = cpl_frameset_get_next(cur_fset)) == NULL) {
03256         cpl_ensure_code(0, cpl_error_get_code());
03257     }
03258 
03259     on = cpl_image_load(cpl_frame_get_filename(first_on),
03260                         CPL_TYPE_FLOAT, 0, 0);
03261     off = cpl_image_load(cpl_frame_get_filename(first_off),
03262                          CPL_TYPE_FLOAT, 0, 0);
03263     cpl_image_subtract(on, off);
03264 
03265     plist = cpl_propertylist_load(cpl_frame_get_filename(first_on), 0);
03266     if(plist == NULL) {
03267         cpl_msg_error(cpl_func, "getting header from reference frame");
03268         cpl_image_delete(on);
03269         cpl_image_delete(off);
03270         cpl_ensure_code(0, cpl_error_get_code());
03271     }
03272 
03273     dit = irplib_pfits_get_exptime(plist);
03274 
03275     detmon_lg_config.cr = cpl_image_get_mean(on) / dit;
03276 
03277     cpl_image_delete(on);
03278     cpl_image_delete(off);
03279     cpl_propertylist_delete(plist);
03280 
03281     return 0;
03282 }
03283 
03284 int
03285 irplib_detmon_lg_dfs_set_groups(cpl_frameset * set,
03286                                 const char *tag_on, const char *tag_off)
03287 {
03288     cpl_frame              *cur_frame;
03289     const char             *tag;
03290     int                     nframes;
03291     int                     i;
03292 
03293     /* Check entries */
03294     if(set == NULL)
03295         return -1;
03296 
03297     /* Initialize */
03298     nframes = cpl_frameset_get_size(set);
03299 
03300     /* Loop on frames */
03301     for(i = 0; i < nframes; i++) {
03302         cur_frame = cpl_frameset_get_frame(set, i);
03303         tag = cpl_frame_get_tag(cur_frame);
03304 
03305         /* RAW frames */
03306         if(!strcmp(tag, tag_on) || !strcmp(tag, tag_off))
03307             cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW);
03308         /* CALIB frames */
03309 
03310 /*        else if (!strcmp(tag, IIINSTRUMENT_CALIB_FLAT))
03311             cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB) ;
03312 */
03313     }
03314     return 0;
03315 }
03316 
03317 /*---------------------------------------------------------------------------*/
03318 
03319 /*
03320  * @brief  Retrieve input parameters
03321  * @param  pipeline_name        Input image
03322  * @param  recipe_name          Input image
03323  * @param  parlist              Shift to apply on the x-axis
03324  * @return CPL_ERROR_NONE on success.
03325  */
03326 
03327 /*---------------------------------------------------------------------------*/
03328 cpl_error_code
03329 irplib_detmon_lg_reduce_all(const cpl_table * linear_table,
03330                             cpl_table * fit_table,
03331                             cpl_propertylist * qclist,
03332                             cpl_imagelist ** coeffs_ptr,
03333                             cpl_image ** bpms_ptr,
03334                             cpl_vector * x_pos,
03335                             cpl_imagelist * linearity_inputs,
03336                             cpl_table * gain_table, cpl_boolean opt_nir,
03337                 int which_ext)
03338 {
03339 
03340     int                     nbpixs = 0;
03341     const int               nsets = cpl_table_get_nrow(linear_table);
03342     int                     i;
03343     double autocorr;
03344     cpl_polynomial         *poly_linfit = NULL;
03345     cpl_image              *fiterror = NULL;
03346     char * name_o1 = NULL;
03347     char * name_o2 = NULL;
03348 
03349     /* FIXME: This should go before the x and y vectors.
03350        Checking for all the inputs */
03351     cpl_ensure_code(qclist != NULL, CPL_ERROR_NULL_INPUT);
03352 
03353     if (!strcmp(detmon_lg_config.method, "PTC")) {
03354     /* Computation of GAIN via polynomial fit */
03355     if (detmon_lg_config.exts >= 0) { 
03356         cpl_msg_info(cpl_func,
03357              "Polynomial fitting for the GAIN (constant term method)");
03358     } else {
03359         cpl_msg_info(cpl_func,
03360              "Polynomial fitting for the GAIN (constant term method)"
03361              " for extension nb %d", which_ext);
03362     }
03363     skip_if(irplib_detmon_lg_qc_ptc(gain_table, fit_table, qclist));
03364     } else {
03365     skip_if(irplib_detmon_lg_qc_med(gain_table, qclist));
03366     }
03367 
03368     /*^FIXME: This shouldn't be written when no applied */
03369     /* Lamp flux */
03370     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LAMP_FLUX,
03371                        detmon_lg_config.cr));
03372     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LAMP_FLUX,
03373                                          DETMON_QC_LAMP_FLUX_C));
03374 
03375     /*^FIXME: This shouldn't be written when no applied */
03376     autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
03377     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_AUTOCORR,
03378                                            autocorr));
03379     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_AUTOCORR,
03380                                          DETMON_QC_AUTOCORR_C));
03381 
03382     if (detmon_lg_config.exts >= 0) { 
03383         cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix");
03384     } else {
03385         cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix"
03386                                " for extension nb %d", which_ext);
03387     }
03388 
03389     if(opt_nir == OPT) {
03390     double mse;
03391         /* Computation of LINEARITY via polynomial fit */
03392     const cpl_vector *x =
03393         cpl_vector_wrap(nsets,
03394                 (double *)cpl_table_get_data_double_const(linear_table,
03395                                   "MED"));
03396     const cpl_vector *y =
03397         cpl_vector_wrap(nsets,
03398                 (double *)cpl_table_get_data_double_const(linear_table,
03399                                   "DIT"));
03400 
03401         if(x == NULL || y == NULL) {
03402         cpl_vector_unwrap((cpl_vector *)x);
03403         cpl_vector_unwrap((cpl_vector *)y);
03404         /*
03405          * As x and y are const vectors, if they would be defined at the
03406          * beginning of the function (required for skip_if - end_skip
03407          * scheme), they couldn't be initialised to NULL (required too).
03408          * Therefore, they are considered apart from the scheme.
03409          */
03410         skip_if(1);
03411     }
03412 
03413         cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
03414         poly_linfit = cpl_polynomial_fit_1d_create(x, y,
03415                            detmon_lg_config.order,
03416                            &mse);
03417     if(poly_linfit == NULL) {
03418         cpl_vector_unwrap((cpl_vector *)x);
03419         cpl_vector_unwrap((cpl_vector *)y);
03420         /* See comment in previous error checking if() statement */
03421         skip_if(1);
03422     }
03423 
03424     cpl_vector_unwrap((cpl_vector *)x);
03425     cpl_vector_unwrap((cpl_vector *)y);
03426 
03427         for(i = 1; i <= detmon_lg_config.order; i++) {
03428             const double            coeff =
03429                 cpl_polynomial_get_coeff(poly_linfit, &i);
03430             char                   *name_o =
03431                 cpl_sprintf("ESO QC LIN COEF%d", i);
03432             assert(name_o != NULL);
03433             skip_if(cpl_propertylist_append_double(qclist, name_o, coeff));
03434             cpl_free(name_o);
03435         }
03436     } else {
03437         *coeffs_ptr =
03438             cpl_fit_imagelist_polynomial(x_pos, linearity_inputs, 0,
03439                                          detmon_lg_config.order, FALSE,
03440                                          CPL_TYPE_FLOAT, fiterror);
03441     skip_if(*coeffs_ptr == NULL);
03442 
03443         for(i = 0; i < detmon_lg_config.order; i++) {
03444             cpl_image              *image = cpl_imagelist_get(*coeffs_ptr, i);
03445             name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
03446             name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
03447             assert(name_o1 != NULL);
03448             assert(name_o2 != NULL);
03449             skip_if(cpl_propertylist_append_double(qclist, name_o1,
03450                       cpl_image_get_median(image)));
03451             cpl_free(name_o1);
03452         name_o1= NULL;
03453             skip_if(cpl_propertylist_append_double(qclist, name_o2,
03454                        cpl_image_get_stdev(image)));
03455             cpl_free(name_o2);
03456         name_o2= NULL;
03457         }
03458     }
03459 
03460 
03461     /* Detection of bad pixels */
03462     if (detmon_lg_config.exts >= 0) { 
03463         cpl_msg_info(cpl_func, "Bad pixel detection");
03464     } else {
03465         cpl_msg_info(cpl_func, "Bad pixel detection"
03466                                " for extension nb %d", which_ext);
03467     }
03468 
03469     if(opt_nir == NIR) {
03470         *bpms_ptr = irplib_detmon_bpixs(*coeffs_ptr, &nbpixs);
03471     skip_if(*bpms_ptr == NULL);
03472     }
03473 
03474     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_NUM_BPM, nbpixs));
03475     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_NUM_BPM,
03476                                          DETMON_QC_NUM_BPM_C));
03477 
03478     end_skip;
03479 
03480     cpl_free(name_o1);
03481     cpl_free(name_o2);
03482     cpl_image_delete(fiterror);
03483     cpl_polynomial_delete(poly_linfit);
03484 
03485     return cpl_error_get_code();
03486 }
03487 
03488 static cpl_error_code
03489 irplib_detmon_lg_qc_ptc(const cpl_table  * gain_table,
03490             const cpl_table  * fit_table,
03491             cpl_propertylist * qclist)
03492 {
03493     double                  mse;
03494     cpl_polynomial         *poly_fit = NULL;
03495     cpl_polynomial         *poly_fit2 = NULL;
03496     int i;
03497     const int               nsets = cpl_table_get_nrow(gain_table);
03498 
03499     /* The following 2 vectors are declared 'const' as they shouldn't be 
03500        modified. However, the data to be wrapped are casted as 'non-const'
03501        to avoid warning in cpl_vector_wrap, where API is 'non-const' */
03502 
03503     const cpl_vector             *x;
03504     const cpl_vector             *y;
03505 
03506     cpl_ensure_code(gain_table != NULL, CPL_ERROR_NULL_INPUT);
03507     cpl_ensure_code(fit_table  != NULL, CPL_ERROR_NULL_INPUT);
03508     cpl_ensure_code(qclist     != NULL, CPL_ERROR_NULL_INPUT);
03509 
03510     x = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT"));
03511     
03512     y = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
03513 
03514     skip_if(x == NULL || y == NULL);
03515 
03516     poly_fit = cpl_polynomial_fit_1d_create(x, y, 1, &mse);
03517     skip_if(poly_fit == NULL);
03518 
03519     /* Write the QC params corresponding to the fitting of the GAIN */
03520     i = 1;
03521     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD,
03522                        cpl_polynomial_get_coeff(poly_fit, &i)));
03523     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
03524                      DETMON_QC_CONAD_C));
03525 
03526     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,
03527                        1 / cpl_polynomial_get_coeff(poly_fit,
03528                                     &i)));
03529     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
03530                      DETMON_QC_GAIN_C));
03531     
03532     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE, mse));
03533     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
03534                      DETMON_QC_GAIN_MSE_C));
03535     i = 0;
03536     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_RON,
03537                        cpl_polynomial_get_coeff(poly_fit, &i)));
03538     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_RON,
03539                      DETMON_QC_RON_C));
03540     
03541     if(detmon_lg_config.autocorr){
03542     const cpl_vector             *x2 =
03543         cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(fit_table, "X"));
03544     const cpl_vector             *y2 =
03545         cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(fit_table, "Y"));
03546 
03547     if(x2 == NULL || y2 == NULL) {
03548         cpl_vector_unwrap((cpl_vector *)x2);
03549         cpl_vector_unwrap((cpl_vector *)y2);
03550         /*
03551          * As x and y are const vectors, if they would be defined at the
03552          * beginning of the function (required for skip_if - end_skip
03553          * scheme), they couldn't be initialised to NULL (required too).
03554          * Therefore, they are considered apart from the scheme.
03555          */
03556         skip_if(1);
03557     }
03558 
03559     /* Revise mse, maybe used afterwards */
03560     poly_fit2 = cpl_polynomial_fit_1d_create(x2, y2, 1, &mse);
03561     if(poly_fit2 == NULL) {
03562         cpl_vector_unwrap((cpl_vector *)x2);
03563         cpl_vector_unwrap((cpl_vector *)y2);
03564         /* See comment in previous error checking if() statement */
03565         skip_if(1);
03566     }
03567 
03568     cpl_vector_unwrap((cpl_vector *)x2);
03569     cpl_vector_unwrap((cpl_vector *)y2);
03570 
03571     /* Write the QC params corresponding to the fitting of the GAIN */
03572     i = 1;
03573     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
03574                            1 / cpl_polynomial_get_coeff(poly_fit, &i)));
03575     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
03576                          DETMON_QC_GAIN_CORR_C));
03577     }
03578 
03579     end_skip;
03580 
03581     /* Cast back to 'non-const' to avoid warning. See comment above */
03582     cpl_vector_unwrap((cpl_vector *)x);
03583     cpl_vector_unwrap((cpl_vector *)y);
03584     cpl_polynomial_delete(poly_fit);
03585     cpl_polynomial_delete(poly_fit2);
03586 
03587     return cpl_error_get_code();
03588 }
03589 
03590 static cpl_error_code
03591 irplib_detmon_lg_qc_med(const cpl_table * gain_table,
03592                 cpl_propertylist * qclist)
03593 {
03594     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,
03595                        cpl_table_get_column_median
03596                        (gain_table, "GAIN")));
03597     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
03598                      DETMON_QC_GAIN_C));
03599 
03600     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE,
03601                        cpl_table_get_column_stdev
03602                        (gain_table, "GAIN")));
03603     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
03604                      DETMON_QC_GAIN_MSE_C));
03605 
03606     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
03607                        cpl_table_get_column_median
03608                        (gain_table, "GAIN_CORR")));
03609     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
03610                      DETMON_QC_GAIN_CORR_C));
03611     end_skip;
03612 
03613     return cpl_error_get_code();
03614 }
03615 
03616 
03617 /*---------------------------------------------------------------------------*/
03618 
03619 /*
03620  * @brief  Retrieve input parameters
03621  * @param  pipeline_name        Input image
03622  * @param  recipe_name          Input image
03623  * @param  parlist              Shift to apply on the x-axis
03624  * @return CPL_ERROR_NONE on success.
03625  */
03626 
03627 /*---------------------------------------------------------------------------*/
03628 static cpl_error_code
03629 irplib_detmon_lg_rescale(cpl_imagelist * to_rescale)
03630 {
03631     cpl_error_code          error;
03632 
03633     double                  med1 =
03634         cpl_image_get_median(cpl_imagelist_get(to_rescale, 0));
03635     double                  med2 =
03636         cpl_image_get_median(cpl_imagelist_get(to_rescale, 1));
03637 
03638     error = cpl_error_get_code();
03639     cpl_ensure_code(!error, error);
03640 
03641     if(fabs(med1 / med2 - 1) > 0.001) {
03642         if(med1 > med2)
03643             error = cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 0),
03644                                             med1 / med2);
03645         else
03646             error = cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 1),
03647                                             med2 / med1);
03648     }
03649     cpl_ensure_code(!error, error);
03650 
03651     return CPL_ERROR_NONE;
03652 }
03653 
03654 cpl_imagelist **
03655 irplib_detmon_ilist_load_fset(const cpl_frameset * set, cpl_type type)
03656 {
03657     int j;
03658     cpl_error_code error;
03659 
03660     /* Initialise memory for products */
03661     cpl_imagelist ** lists =
03662         (cpl_imagelist **) cpl_malloc(detmon_lg_config.nb_extensions *
03663                                       sizeof(cpl_imagelist *));
03664     if(detmon_lg_config.exts < 0) {
03665         for(j = 0; j < detmon_lg_config.nb_extensions; j++) {
03666             lists[j] = cpl_imagelist_new();
03667         }
03668     }
03669 
03670     if(detmon_lg_config.exts >= 0) {
03671         *lists = cpl_imagelist_load_frameset(set, type, 1,
03672                                              detmon_lg_config.exts);
03673         /*FIXME: Error checking to be added here */
03674     } else {
03675         cpl_imagelist          *lists_all_exts =
03676             cpl_imagelist_load_frameset(set, type, 1, -1);
03677         for(j = 0; j < detmon_lg_config.nb_extensions; j++) {
03678         int nframes = cpl_frameset_get_size(set);
03679         int k;
03680         for(k = 0; k < nframes; k++) {
03681         cpl_image              *image =
03682             cpl_imagelist_unset(lists_all_exts,
03683                     (detmon_lg_config.
03684                      nb_extensions - 1 - j) * k);
03685         cpl_ensure(image != NULL, CPL_ERROR_ILLEGAL_INPUT, NULL);
03686         error = cpl_imagelist_set(lists[j], image, k);
03687         cpl_ensure(!error, error, NULL);
03688         }
03689         }
03690 
03691         cpl_imagelist_delete(lists_all_exts);
03692     }
03693 
03694     return lists;
03695 }
03696 
03697 /*---------------------------------------------------------------------------*/
03698 
03699 /*
03700  * @brief  Extract a pair of frames of equal DIT from a frameset
03701  * @param  set             Input frameset
03702  * @param  selection       Array of labels associated to frames in the frameset
03703  * @param  selected        Label (DIT) to be extracted
03704  * @param  nsets_extracted Pointer to the number of different labels (found by
03705  *                         cpl_frameset_labelise().
03706  * @param  with_equal_dit  Pointer to number of pairs of equal DIT
03707  *                         previously found
03708  * @param  onoff           Flag for ON / OFF frameset
03709  * @return Extracted pair
03710  * Add NOTE here
03711  */
03712 
03713 /*---------------------------------------------------------------------------*/
03714 cpl_frameset *
03715 irplib_detmon_pair_extract(const cpl_frameset * set,
03716                            int * selection, int selected,
03717                            int * nsets_extracted,
03718                            int * with_equal_dit,
03719                            int onoff)
03720 {
03721     cpl_frameset * pair = NULL;
03722     int new_with_equal_dit = 0;
03723 
03724     cpl_ensure(set != NULL, CPL_ERROR_NULL_INPUT, NULL);
03725     cpl_ensure(selection != NULL, CPL_ERROR_NULL_INPUT, NULL);
03726     cpl_ensure(nsets_extracted != NULL, CPL_ERROR_NULL_INPUT, NULL);
03727     cpl_ensure(with_equal_dit != NULL, CPL_ERROR_NULL_INPUT, NULL);
03728 //    cpl_ensure(which != NULL, CPL_ERROR_NULL_INPUT, NULL);
03729 
03730     cpl_ensure(selected < *nsets_extracted, CPL_ERROR_ILLEGAL_INPUT, NULL);
03731 
03732     pair = cpl_frameset_extract(set, selection, selected);
03733     cpl_ensure(pair != NULL, cpl_error_get_code(), NULL);
03734 
03735 
03736     /* FIXME: Error checkin to be done here */
03737 
03738     /* Test if it is really a pair */
03739     if(cpl_frameset_get_size(pair) % 2 != 0) {
03740 //      cpl_msg_error(cpl_func, "Some %s frames are not a pair", which);
03741         cpl_frameset_delete(pair);
03742         return NULL;
03743     }
03744 
03745     /* See how many pairs with same DIT */
03746     if(cpl_frameset_get_size(pair) != 2) {
03747         new_with_equal_dit = cpl_frameset_get_size(pair) / 2;
03748         if(onoff == 1) {
03749             *with_equal_dit = new_with_equal_dit;
03750         } else {
03751             if (*with_equal_dit != 0 && new_with_equal_dit != *with_equal_dit) {
03752                 cpl_msg_error(cpl_func, "Mismatch between ON and OFF pairs of frames of equal DIT value");
03753                 cpl_frameset_delete(pair);
03754                 return NULL;
03755             }
03756         }
03757     }
03758 
03759     /* If more than a pair, update selection array */
03760     if (new_with_equal_dit != 0) {
03761         int                     found = 0;
03762         int j;
03763         for(j = 0; j < cpl_frameset_get_size(set); j++) {
03764 
03765             if(selection[j] == selected) {
03766                 found++;
03767 
03768                 if((found - 1) / 2 != 0) {
03769                     selection[j] =
03770                         *nsets_extracted + (found - 1) / 2 - 1;
03771                     /* Updating the nsets can only be done once (if done here, it would be manipulated and produce incorrect results when re-organizing corresponding OFF Pair; it is done only when OFF pairs are not computed (collapse == TRUE) */
03772                 }
03773             }
03774         }
03775 
03776         if((onoff == 1 && detmon_lg_config.collapse == TRUE ) ||
03777            (onoff == 0 && detmon_lg_config.collapse == FALSE) ){
03778             *nsets_extracted += (found - 1) / 2;
03779         }
03780         cpl_frameset_delete(pair);
03781         pair = cpl_frameset_extract(set, selection, selected);
03782         /* FIXME: Error checking missing here */
03783     }
03784 
03785     return pair;
03786 }

Generated on Thu Nov 15 14:32:26 2007 for UVES Pipeline Reference Manual by  doxygen 1.5.1