irplib_detmon_lg.c

00001 /* $Id: irplib_detmon_lg.c,v 1.192 2011/02/11 14:30:39 amodigli Exp $
00002  *
00003  * This file is part of the irplib package
00004  * Copyright (C) 2002, 2003 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
00019  */
00020 
00021 
00022 /*
00023  * $Author: amodigli $
00024  * $Date: 2011/02/11 14:30:39 $
00025  * $Revision: 1.192 $
00026  * $Name: sinfo-2_2_5 $
00027  *
00028  */
00029 
00030 #ifdef HAVE_CONFIG_H
00031 #include <config.h>
00032 #endif
00033 
00034 /*---------------------------------------------------------------------------
00035                                   Includes
00036  ---------------------------------------------------------------------------*/
00037 
00038 #include <complex.h>
00039 
00040 
00041 #include <math.h>
00042 #include <string.h>
00043 #include <assert.h>
00044 
00045 #include <cpl.h>
00046 #include <cpl_fft.h>
00047 #include "irplib_detmon.h"
00048 #include "irplib_detmon_lg.h"
00049 #include "irplib_detmon_lg_impl.h"
00050 
00051 #include "irplib_utils.h"
00052 #include "irplib_hist.h"
00053 
00054 /*
00055  * @defgroup irplib_detmon        Detector monitoring functions
00056  */
00057 
00058 /*--------------------------------------------------------------------------*/
00059 
00060 /*---------------------------------------------------------------------------
00061                                   Defines
00062  ---------------------------------------------------------------------------*/
00063 /*method for calculating Fixed Pattern Noise (FPN)*/
00064 enum _FPN_METHOD
00065 {
00066     FPN_UNKNOWN,
00067     FPN_HISTOGRAM, /*default*/
00068     FPN_SMOOTH,
00069 };
00070 typedef enum _FPN_METHOD FPN_METHOD;
00071 static struct
00072 {
00073     const char            * method;
00074     /* Inputs */
00075     int                     order;
00076     double                     kappa;
00077     int                     niter;
00078     int                     threshold_min;
00079     int                     threshold_max;
00080     int                     llx;
00081     int                     lly;
00082     int                     urx;
00083     int                     ury;
00084     int                     ref_level;
00085     int                     threshold;
00086     int                     m;
00087     int                     n;
00088     int                     llx1;
00089     int                     lly1;
00090     int                     urx1;
00091     int                     ury1;
00092     int                     llx2;
00093     int                     lly2;
00094     int                     urx2;
00095     int                     ury2;
00096     int                     llx3;
00097     int                     lly3;
00098     int                     urx3;
00099     int                     ury3;
00100     int                     llx4;
00101     int                     lly4;
00102     int                     urx4;
00103     int                     ury4;
00104     int                     llx5;
00105     int                     lly5;
00106     int                     urx5;
00107     int                     ury5;
00108     int                     nx;
00109     int                     ny;
00110     cpl_boolean             wholechip;
00111     cpl_boolean             autocorr;
00112     cpl_boolean             intermediate;
00113     cpl_boolean             collapse;
00114     cpl_boolean             rescale;
00115     cpl_boolean             pix2pix;
00116     cpl_boolean             bpmbin;
00117     int                     filter;
00118     double                  tolerance;
00119     cpl_boolean             pafgen;
00120     const char            * pafname;
00121     /* Outputs */
00122     double                  cr;
00123     int                     exts;
00124     int                     nb_extensions;
00125     double                  lamp_stability;
00126     cpl_boolean             lamp_ok;
00127     /* by kmirny */
00128     int                    (* load_fset) (
00129             const cpl_frameset *, cpl_type, cpl_imagelist *
00130             );
00131     cpl_imagelist *                    (* load_fset_wrp) (
00132             const cpl_frameset *, cpl_type, int
00133             );
00134     FPN_METHOD fpn_method;
00135     int fpn_smooth;
00136     double saturation_limit;
00137     cpl_boolean            split_coeffs;
00138 } detmon_lg_config;
00139 
00140 /* static const char* COL_NAME_DET1_WIN1_UIT1 = "DET1_WIN1_UIT1"; */
00141 /*---------------------------------------------------------------------------
00142                                   Private function prototypes
00143  ---------------------------------------------------------------------------*/
00144 /*  Functions for the Linearity/Gain recipe, irplib_detmon_lg() */
00145 
00146 /*  Parameters */
00147 static cpl_error_code
00148 irplib_detmon_lg_retrieve_parlist(const char *,
00149                   const char *, const cpl_parameterlist *,
00150                                   cpl_boolean);
00151 
00152 
00153 static cpl_error_code
00154 irplib_detmon_lg_split_onoff(const cpl_frameset *,
00155                              cpl_frameset *,
00156                              cpl_frameset *,
00157                              const char *, const char * /*, cpl_boolean*/);
00158 
00159 static cpl_error_code
00160 irplib_detmon_lg_reduce(const cpl_frameset *,
00161                         const cpl_frameset *,
00162 /*                        int *,
00163                           int *, */
00164                         int* index_on, int* index_off, double* exptime_on, double* exptime_off,
00165                         int *next_index_on, int* next_index_off,
00166                         cpl_imagelist **,
00167                         cpl_table *,
00168                         cpl_table *,
00169                         cpl_image **,
00170                         cpl_imagelist *,
00171                         cpl_imagelist *,
00172                         cpl_propertylist *,
00173                         cpl_propertylist *,
00174                         cpl_propertylist *,
00175                         cpl_propertylist *,
00176          int                    (* load_fset) (const cpl_frameset *,
00177                                cpl_type,
00178                                                cpl_imagelist *),
00179                         const cpl_boolean, int);
00180 
00181 static cpl_error_code
00182 irplib_detmon_lin_table_fill_row(cpl_table *, double,
00183                  cpl_imagelist *,
00184                  const cpl_imagelist *,
00185                  const cpl_imagelist *,
00186                  int, int, int, int,
00187                  const int,
00188                                  const int,
00189                  unsigned);
00190 
00191 static cpl_error_code
00192 irplib_detmon_gain_table_fill_row(cpl_table * gain_table,
00193                   double c_dit,int c_ndit,
00194           cpl_imagelist * autocorr_images,
00195           cpl_imagelist * diff_flats,
00196           const cpl_imagelist * ons,
00197                         const cpl_imagelist * offs,
00198                         double kappa, int nclip,
00199                         int llx, int lly, int urx, int ury,
00200                         int m, int n,
00201                         double saturation_limit,
00202           const int pos, unsigned mode, int* rows_affected);
00203 
00204 static                  cpl_error_code
00205 irplib_detmon_lg_save(const cpl_parameterlist *,
00206                       cpl_frameset *,
00207                       const char *,
00208                       const char *,
00209                       const char *,
00210               const cpl_propertylist  *,
00211               const cpl_propertylist  *,
00212               const cpl_propertylist  *,
00213               const cpl_propertylist  *,
00214               const cpl_propertylist  *,
00215               const cpl_propertylist  *,
00216                       const char *,
00217                       cpl_imagelist *,
00218                       cpl_table *,
00219                       cpl_table *,
00220                       cpl_image *,
00221                       cpl_imagelist *,
00222                       cpl_imagelist *,
00223                       cpl_propertylist *,
00224                       cpl_propertylist *,
00225                       cpl_propertylist *,
00226                       cpl_propertylist *,
00227                       const int, const int, const cpl_frameset *,
00228                       int);
00229 
00230 static cpl_error_code
00231 irplib_detmon_lg_qc_ptc(const cpl_table  *,
00232             cpl_propertylist *, unsigned, int);
00233 
00234 static cpl_error_code
00235 irplib_detmon_lg_qc_med(const cpl_table  *,
00236             cpl_propertylist *, int);
00237 
00238 
00239 static double
00240 irplib_pfits_get_dit(const cpl_propertylist *);
00241 
00242 static double
00243 irplib_pfits_get_dit_opt(const cpl_propertylist *);
00244 static double
00245 irplib_pfits_get_prop_double(const cpl_propertylist * plist, const char* prop_name);
00246 
00247 static cpl_image       *irplib_detmon_bpixs(const cpl_imagelist *, cpl_boolean, const double, int *);
00248 
00249 static double
00250 irplib_detmon_autocorr_factor(const cpl_image *,
00251                               cpl_image **, int, int);
00252 
00253 
00254 
00255 static                  cpl_error_code
00256 irplib_detmon_opt_contamination(const cpl_imagelist *,
00257                 const cpl_imagelist *,
00258                 unsigned mode, cpl_propertylist *);
00259 
00260 #if 0
00261 irplib_detmon_opt_lampcr(cpl_frameset *, int);
00262 #endif
00263 
00264 int
00265 irplib_detmon_lg_dfs_set_groups(cpl_frameset *, const char *, const char *);
00266 
00267 static cpl_error_code
00268 irplib_detmon_lg_reduce_all(const cpl_table *,
00269                 cpl_propertylist *,
00270                 cpl_propertylist *
00271 ,               cpl_propertylist *,
00272                 cpl_propertylist *,
00273                 cpl_imagelist **,
00274                 cpl_image **,
00275                             const cpl_imagelist *,
00276                 const cpl_table *, int, cpl_boolean);
00277 
00278 static cpl_error_code
00279 irplib_detmon_lg_check_defaults(const cpl_image *);
00280 
00281 static cpl_error_code
00282 irplib_detmon_lg_rescale(cpl_imagelist *);
00283 
00284 static cpl_error_code
00285 irplib_detmon_lg_reduce_init(cpl_table *,
00286                              cpl_table *,
00287                              cpl_imagelist **,
00288                              const cpl_boolean);
00289 
00290 
00291 
00292 static cpl_error_code
00293 irplib_detmon_add_adl_column(cpl_table *, cpl_boolean);
00294 
00295 static cpl_error_code
00296 irplib_detmon_lg_lamp_stab(const cpl_frameset *,
00297                const cpl_frameset *,
00298                            cpl_boolean, int);
00299 
00300 
00301 static cpl_error_code
00302 irplib_detmon_lg_reduce_dit(const cpl_frameset * set_on,
00303                 int* index_on, double* exptime_on,
00304                 const int dit_nb,
00305                 int * dit_nskip,
00306                 const cpl_frameset * set_off,
00307                 int * index_off, double* exptime_off,
00308                 int* next_on, int* next_off,
00309                 cpl_table * linear_table,
00310                 cpl_table * gain_table,
00311                 cpl_imagelist * linearity_inputs,
00312                 cpl_propertylist * qclist,
00313                 cpl_boolean opt_nir,
00314                 cpl_imagelist * autocorr_images,
00315                 cpl_imagelist * diff_flats,
00316                 cpl_imagelist * opt_offs,
00317                 int whichext,
00318                 int * rows_affected);
00319 
00320 static cpl_error_code
00321 irplib_detmon_lg_core(cpl_frameset * cur_fset_on,
00322               cpl_frameset * cur_fset_off,
00323               int * index_on,
00324               int * index_off,
00325               double * exptime_on,
00326               double * exptime_off,
00327               int whichext,
00328                       int whichset,
00329               const char              * recipe_name,
00330               const char              * pipeline_name,
00331               const char              * pafregexp,
00332               const cpl_propertylist  * pro_lintbl,
00333               const cpl_propertylist  * pro_gaintbl,
00334               const cpl_propertylist  * pro_coeffscube,
00335               const cpl_propertylist  * pro_bpm,
00336               const cpl_propertylist  * pro_corr,
00337               const cpl_propertylist  * pro_diff,
00338               const char              * package,
00339               int                    (* load_fset) (const cpl_frameset *,
00340                                 cpl_type,
00341                                 cpl_imagelist *),
00342               int nsets, cpl_boolean opt_nir,
00343                       cpl_frameset * frameset, const cpl_parameterlist * parlist,
00344                       cpl_frameset * cur_fset);
00345 
00346 static cpl_error_code
00347 irplib_detmon_lg_lineff(double *, cpl_propertylist *, int, int);
00348 
00349 /*
00350 static int
00351 irplib_detmon_lg_compare_pairs(const cpl_frame *,
00352                    const cpl_frame *);
00353 */
00354 static cpl_error_code
00355 irplib_detmon_gain_table_create(cpl_table *,
00356                                 const cpl_boolean);
00357 
00358 
00359 static cpl_error_code
00360 irplib_detmon_lin_table_create(cpl_table *,
00361                                const cpl_boolean);
00362 
00363 static cpl_vector *
00364 irplib_detmon_lg_find_dits(const cpl_vector *,
00365                            double            );
00366 
00367 static cpl_error_code
00368 irplib_detmon_lg_find_dits_ndits(const cpl_vector * exptimes,
00369                const cpl_vector * vec_ndits,
00370                            double             tolerance,
00371                            cpl_vector** diff_dits,
00372                  cpl_vector** diff_ndits);
00373 
00374 static cpl_error_code
00375 irplib_detmon_fpn_compute(const cpl_frameset *set_on,
00376         int * index_on,
00377         int last_best,
00378         cpl_propertylist *lint_qclist,
00379         int llx,
00380         int lly,
00381         int urx,
00382         int ury,
00383         double gain,
00384         int whichext,
00385         FPN_METHOD fpn_method,
00386         int smooth_size);
00387 static double irplib_fpn_lg(const cpl_image* f1, int* range, double gain,
00388         FPN_METHOD fpn_method, int, double* mse);
00389 static double irplib_calculate_total_noise(const cpl_image* pimage);
00390 
00391 static cpl_imagelist* irplib_load_fset_wrp(const cpl_frameset *, cpl_type, int whichext);
00392 static cpl_imagelist * irplib_load_fset_wrp_ext(const cpl_frameset *, cpl_type, int);
00393 
00394 static cpl_error_code irplib_table_create_column(cpl_table* ptable, cpl_propertylist* plist);
00395 static cpl_error_code irplib_fill_table_DETWINUIT(cpl_table* ptable, cpl_propertylist* plist, int row);
00396 
00397 static cpl_error_code
00398 irplib_detmon_pair_extract_next(const cpl_frameset * set,
00399                            int* index,
00400                            int* next_element,
00401                           double* dit_array,
00402 /*                           int * with_equal_dit,
00403                              int onoff, */
00404                            cpl_frameset ** pair,
00405                            double tolerance);
00406 static cpl_error_code
00407 irplib_detmon_single_extract_next(const cpl_frameset * set,
00408                            int* index,
00409                            int* next_element,
00410                            double* dit_array,
00411                            cpl_frameset ** pair);
00412 
00413 /*
00414 static int frame_get_ndit(const cpl_frame * pframe);
00415 static cpl_error_code
00416 irplib_frameset_get_ndit(const cpl_frameset *  self, int* ndit);
00417 */
00418 static cpl_error_code irplib_detmon_table_fill_invalid(cpl_table* ptable, double code);
00419 static void irplib_detmon_lg_add_empty_image(cpl_imagelist* imlist, int pos);
00420 static int irplib_detmon_lg_check_before_gain(const cpl_vector* x, const cpl_vector* y);
00421 /*---------------------------------------------------------------------------*/
00428 /*---------------------------------------------------------------------------*/
00429 static int irplib_pfits_get_ndit(const cpl_propertylist * plist)
00430 {
00431     return cpl_propertylist_get_int(plist,"ESO DET NDIT");
00432 }
00433 
00434 
00435 /*
00436 static int frame_get_ndit(const cpl_frame * pframe)
00437 {
00438     cpl_propertylist       *plist = 0;
00439     int                  ival = 0;
00440 
00441     plist = cpl_propertylist_load(cpl_frame_get_filename(pframe),0);
00442     if(plist)
00443     {
00444         ival = cpl_propertylist_get_int(plist, "NDIT");
00445     }
00446 
00447     cpl_propertylist_delete(plist);
00448     return ival;
00449 }
00450 */
00451 
00452 /*
00453 static cpl_error_code
00454 irplib_frameset_get_ndit(const cpl_frameset *  self, int* ndit)
00455 {
00456     int sz = 0;
00457     int i = 0;
00458     const cpl_frame* tmp_frame = 0;
00459     cpl_error_code error = CPL_ERROR_NONE;
00460     sz = cpl_frameset_get_size(self);
00461 
00462     tmp_frame = cpl_frameset_get_first_const(self);
00463     while(tmp_frame)
00464     {
00465         ndit[i] = frame_get_ndit(tmp_frame);
00466         tmp_frame = cpl_frameset_get_next_const(self);
00467         i++;
00468     }
00469 
00470     return error;
00471 }
00472 */
00473 
00474 static cpl_error_code irplib_detmon_lg_reduce_set(int i, cpl_frameset * frameset, int nsets,
00475         const char              * tag_on,
00476         const char              * tag_off,
00477         const char              * recipe_name,
00478         const char              * pipeline_name,
00479         const char              * pafregexp,
00480         const cpl_propertylist  * pro_lintbl,
00481         const cpl_propertylist  * pro_gaintbl,
00482         const cpl_propertylist  * pro_coeffscube,
00483         const cpl_propertylist  * pro_bpm,
00484         const cpl_propertylist  * pro_corr,
00485         const cpl_propertylist  * pro_diff,
00486         const char              * package,
00487         int                    (* load_fset)
00488             (const cpl_frameset *, cpl_type, cpl_imagelist *),
00489         const cpl_boolean         opt_nir,
00490         const cpl_parameterlist * parlist,
00491         int* selection
00492         );
00493 static double irplib_compute_err(double gain, double ron, double photon_noise);
00494 /* wrapper function for different cpl versions*/
00495 static cpl_error_code irplib_detmon_lg_dfs_save_imagelist(
00496         cpl_frameset * frameset,
00497         const cpl_parameterlist * parlist,
00498         const cpl_frameset *usedframes,
00499         const cpl_imagelist *coeffs,
00500         const char *recipe_name,
00501         const cpl_propertylist *mypro_coeffscube,
00502         const char * package,
00503         const char * name_o);
00504 
00505 /*--------------------------------------------------------------------------*/
00506 static cpl_error_code irplib_detmon_lg_reduce_set(int i, cpl_frameset * frameset, int nsets,
00507         const char              * tag_on,
00508         const char              * tag_off,
00509         const char              * recipe_name,
00510         const char              * pipeline_name,
00511         const char              * pafregexp,
00512         const cpl_propertylist  * pro_lintbl,
00513         const cpl_propertylist  * pro_gaintbl,
00514         const cpl_propertylist  * pro_coeffscube,
00515         const cpl_propertylist  * pro_bpm,
00516         const cpl_propertylist  * pro_corr,
00517         const cpl_propertylist  * pro_diff,
00518         const char              * package,
00519         int                    (* load_fset)
00520             (const cpl_frameset *, cpl_type, cpl_imagelist *),
00521         const cpl_boolean         opt_nir,
00522         const cpl_parameterlist * parlist,
00523         int* selection
00524         )
00525 {
00526     int  j;
00527     int nexts = detmon_lg_config.nb_extensions;
00528 
00529     double* exptime_on = 0;
00530     double* exptime_off = 0;
00531     int* index_on = 0;
00532     int* index_off = 0;
00533     cpl_frameset  * cur_fset = NULL;
00534     cpl_frameset* cur_fset_on = 0;
00535     cpl_frameset* cur_fset_off = 0;
00536 
00537     /* Reduce data set nb i */
00538     cur_fset =
00539            (nsets == 1) ? /* would be better (selection == 0) ? */
00540         cpl_frameset_duplicate(frameset) : cpl_frameset_extract(frameset, selection, i);
00541 
00542 
00543     skip_if(cur_fset == NULL);
00544 
00545     /* Split input frameset into 2 sub-framesets for ON and OFF frames */
00546     cur_fset_on  = cpl_frameset_new();
00547     cur_fset_off = cpl_frameset_new();
00548     cpl_msg_info(cpl_func, "Splitting into ON and OFF sub-framesets");
00549     skip_if (irplib_detmon_lg_split_onoff(cur_fset,
00550                           cur_fset_on, cur_fset_off,
00551                           tag_on, tag_off /*, opt_nir*/));
00552     if (cpl_frameset_get_size(cur_fset_on)  == 0)
00553     {
00554         cpl_msg_error(cpl_func, "No lamp frames in input");
00555         skip_if(1);
00556     }
00557 
00558     if (cpl_frameset_get_size(cur_fset_off)  == 0)
00559     {
00560         cpl_msg_error(cpl_func, "No dark / bias frames in input");
00561         skip_if(1);
00562     }
00563     cpl_msg_info(cpl_func, "found on-frames[%d] off-frames[%d]",cpl_frameset_get_size(cur_fset_on), cpl_frameset_get_size(cur_fset_off));
00564     /* Labelise each sub-frameset according to DIT values */
00565 /*      selection_on = cpl_frameset_labelise(cur_fset_on,
00566                          irplib_detmon_lg_compare_pairs,
00567                          &nsets_on);
00568 
00569     skip_if (selection_on == NULL);
00570 */
00571     exptime_on = cpl_malloc(sizeof(double)*cpl_frameset_get_size(cur_fset_on));
00572     exptime_off = cpl_malloc(sizeof(double)*cpl_frameset_get_size(cur_fset_off));
00573 
00574     index_on = cpl_malloc(sizeof(int)*cpl_frameset_get_size(cur_fset_on));
00575     index_off = cpl_malloc(sizeof(int)*cpl_frameset_get_size(cur_fset_off));
00576     irplib_frameset_sort(cur_fset_on, index_on, exptime_on);
00577     irplib_frameset_sort(cur_fset_off, index_off, exptime_off);
00578 /*  for (j = 0; j < cpl_frameset_get_size(cur_fset_on); j++)
00579     {
00580         cpl_msg_info(cpl_func, "%d: \t %d \t %f", j , index_on[j], exptime_on[j]);
00581     }
00582     */
00583     /* TODO Check that each ON frame pair has a corresponding OFF frame*/
00584 
00585     /* Test if they have equal nb of labels */
00586 /*      if (!detmon_lg_config.collapse) {
00587         skip_if(nsets_on != nsets_off);
00588     }
00589 */
00590     skip_if(irplib_detmon_check_order(exptime_on, cpl_frameset_get_size(cur_fset_on), detmon_lg_config.tolerance, detmon_lg_config.order));
00591 
00592     if(detmon_lg_config.exts >= 0)
00593     {
00594         /*
00595          * In the optical domain, the first 2 frames
00596          * are used apart from the pairs.
00597          */
00598 
00599 #if 0
00600         if (detmon_lg_config.lamp_ok) {
00601         skip_if(irplib_detmon_opt_lampcr(cur_fset, 0));
00602         }
00603 #endif
00604         skip_if(irplib_detmon_lg_core(cur_fset_on, cur_fset_off,
00605                           index_on,
00606                           index_off,
00607                           exptime_on,
00608                           exptime_off,
00609                           detmon_lg_config.exts,
00610                           i,
00611                 recipe_name, pipeline_name, pafregexp,
00612                 pro_lintbl, pro_gaintbl, pro_coeffscube, pro_bpm, pro_corr, pro_diff,
00613                 package, load_fset, nsets, opt_nir, frameset, parlist, cur_fset));
00614     } else {
00615         for(j = 1; j <= nexts; j++) {
00616         /*
00617          * In the optical domain, the first 2 frames
00618          * are used apart from the pairs.
00619          */
00620 
00621 #if 0
00622         if (detmon_lg_config.lamp_ok) {
00623             skip_if(irplib_detmon_opt_lampcr(cur_fset, j));
00624         }
00625 #endif
00626 
00627         skip_if(irplib_detmon_lg_core(cur_fset_on, cur_fset_off,
00628                           index_on,
00629                           index_off,
00630                           exptime_on,
00631                           exptime_off,
00632                           j, i,  recipe_name, pipeline_name,pafregexp,  pro_lintbl, pro_gaintbl, pro_coeffscube, pro_bpm, pro_corr, pro_diff, package, load_fset, nsets, opt_nir, frameset, parlist, cur_fset));
00633         }
00634     }
00635     end_skip;
00636 
00637     cpl_frameset_delete(cur_fset);
00638     cpl_frameset_delete(cur_fset_on);
00639     cpl_frameset_delete(cur_fset_off);
00640     cpl_free(index_on);
00641     cpl_free(index_off);
00642     cpl_free(exptime_on);
00643     cpl_free(exptime_off);
00644     return cpl_error_get_code();
00645 }
00646 /*
00647  * @brief  Reduce linearity and gain in the IR domain
00648  * @param  parlist              List of required parameters
00649  * @param  frameset             Input frameset
00650  * @param  tag_on               Tag to identify the ON frames
00651  * @param  tag_off              Tag to identify the OFF frames
00652  * @param  recipe_name          Name of the recipe calling this function
00653  * @param  pipeline_name        Name of the pipeline calling this function
00654  * @param  procatg_lintbl       PRO.CATG keyword for the Linearity Table
00655  * @param  procatg_gaintbl      PRO.CATG keyword for the Gain Table
00656  * @param  procatg_coeffscube     PRO.CATG keyword for the
00657  *                              Linearity Coefficients' Images
00658  * @param  procatg_bpm          PRO.CATG required for the Bad Pixel Map
00659  * @param  procatg_corr     PRO.CATG required for the Autocorrelation Images
00660  *                              (Intermediate product - only created if required)
00661  * @param  procatg_diff         PRO.CATG required for the Difference Images
00662  *                              (Intermediate Product - only created if required)
00663  * @param  package              PACKAGE (incl. VERSION) required
00664  *                              for the DFS keywords
00665  * @param  compare              Compare function used to classified frameset into
00666  *                              different settings, if any.
00667  * @param  load_fset            Loading function for preprocessing of input
00668                                 frames with special data format (needed for
00669                                 AMBER and MIDI processing)
00670 
00671  * @param  opt_nir              Boolean parameter to activate/deactivate
00672  *                              OPT-only / IR-only parts of the recipe
00673  * @return 0 on success, -1 on fail.
00674  * @note: The parlist contains the following parameters:
00675  *
00676  * @par1  kappa                 Kappa value used for the kappa-sigma clipping
00677  *                              rejection of bad pixels when computing sigma for
00678  *                              gain calculation
00679  * @par2  niter                 Number of iterations for the kappa-sigma clipping
00680  * @par3  threshold_min         Minimum threshold of the k-sigma (Not applied)
00681  * @par4  threshold_max         Maximum threshold of the k-sigma (Not applied)
00682  * @par5  llx                   Region of Interest (Default to the whole area)
00683  * @par6  lly                   Region of Interest (Default to the whole area)
00684  * @par7  urx                   Region of Interest (Default to the whole area)
00685  * @par8  ury                   Region of Interest (Default to the whole area)
00686  * @par9  ref_level             Reference Level (Not applied)
00687  * @par10 threshold             Threshold (Not applied)
00688  * @par11 intermediate          Boolean to activate the production of
00689  *                              Intermediate Products
00690  * @par12 autocorr              Boolean to activate autocorr method
00691  * @par13 collapse              Boolean to activate collapse of OFF frames
00692  * @par14 rescale               Boolean to activate pair rescaling
00693  * @par15 m                     X-Shift of the autocorrelation
00694  * @par16 n                     Y-Shift of the autocorrelation
00695  * @par17 llx1                  Region of Interest 1 (Only OPT)
00696  * @par18 lly1                  Region of Interest 1 (Only OPT)
00697  * @par19 urx1                  Region of Interest 1 (Only OPT)
00698  * @par20 ury1                  Region of Interest 1 (Only OPT)
00699  * @par21 llx2                  Region of Interest 2 (Only OPT)
00700  * @par22 lly2                  Region of Interest 2 (Only OPT)
00701  * @par23 urx2                  Region of Interest 2 (Only OPT)
00702  * @par24 ury2                  Region of Interest 2 (Only OPT)
00703  * @par25 llx3                  Region of Interest 3 (Only OPT)
00704  * @par26 lly3                  Region of Interest 3 (Only OPT)
00705  * @par27 urx3                  Region of Interest 3 (Only OPT)
00706  * @par28 ury3                  Region of Interest 3 (Only OPT)
00707  * @par29 llx4                  Region of Interest 4 (Only OPT)
00708  * @par30 lly4                  Region of Interest 4 (Only OPT)
00709  * @par31 urx4                  Region of Interest 4 (Only OPT)
00710  * @par32 ury4                  Region of Interest 4 (Only OPT)
00711  * @par33 llx5                  Region of Interest 5 (Only OPT)
00712  * @par34 lly5                  Region of Interest 5 (Only OPT)
00713  * @par35 urx5                  Region of Interest 5 (Only OPT)
00714  * @par36 ury5                  Region of Interest 5 (Only OPT)
00715  * @par37 exts                  Integer to select extension
00716  */
00717 
00718 /*--------------------------------------------------------------------------*/
00719 
00720 cpl_error_code
00721 irplib_detmon_lg(cpl_frameset            * frameset,
00722                  const cpl_parameterlist * parlist,
00723                  const char              * tag_on,
00724                  const char              * tag_off,
00725                  const char              * recipe_name,
00726                  const char              * pipeline_name,
00727                  const char              * pafregexp,
00728                  const cpl_propertylist  * pro_lintbl,
00729                  const cpl_propertylist  * pro_gaintbl,
00730                  const cpl_propertylist  * pro_coeffscube,
00731                  const cpl_propertylist  * pro_bpm,
00732                  const cpl_propertylist  * pro_corr,
00733                  const cpl_propertylist  * pro_diff,
00734                  const char              * package,
00735                  int                    (* compare) (const cpl_frame *,
00736                              const cpl_frame *),
00737          int                    (* load_fset) (const cpl_frameset *,
00738                                cpl_type,
00739                                                cpl_imagelist *),
00740                  const cpl_boolean         opt_nir)
00741 {
00742     int              nsets;
00743     int            * selection = NULL;
00744     int              i;
00745     cpl_frame      * first     = NULL;
00746     cpl_image      * reference = NULL;
00747 
00748     /*
00749      * Variables used only inside the for() statement.
00750      * However, there are declared here to ease
00751      * memory management in error case.
00752      */
00753     cpl_frameset     * cur_fset        = NULL;
00754     cpl_frameset     * cur_fset_on     = NULL;
00755     cpl_frameset     * cur_fset_off    = NULL;
00756 
00757     /* Test entries */
00758     cpl_ensure_code(frameset           != NULL, CPL_ERROR_NULL_INPUT);
00759     cpl_ensure_code(parlist            != NULL, CPL_ERROR_NULL_INPUT);
00760     cpl_ensure_code(tag_on             != NULL, CPL_ERROR_NULL_INPUT);
00761     cpl_ensure_code(tag_off            != NULL, CPL_ERROR_NULL_INPUT);
00762     cpl_ensure_code(recipe_name        != NULL, CPL_ERROR_NULL_INPUT);
00763     cpl_ensure_code(pipeline_name      != NULL, CPL_ERROR_NULL_INPUT);
00764     cpl_ensure_code(pro_lintbl         != NULL, CPL_ERROR_NULL_INPUT);
00765     cpl_ensure_code(pro_gaintbl        != NULL, CPL_ERROR_NULL_INPUT);
00766     cpl_ensure_code(pro_coeffscube     != NULL, CPL_ERROR_NULL_INPUT);
00767     cpl_ensure_code(pro_bpm            != NULL, CPL_ERROR_NULL_INPUT);
00768     cpl_ensure_code(pro_corr           != NULL, CPL_ERROR_NULL_INPUT);
00769     cpl_ensure_code(pro_diff           != NULL, CPL_ERROR_NULL_INPUT);
00770     cpl_ensure_code(package            != NULL, CPL_ERROR_NULL_INPUT);
00771 
00772     cpl_msg_info(cpl_func,"frameset size [%d]", cpl_frameset_get_size(frameset));
00773 
00774 
00775     skip_if (irplib_detmon_lg_dfs_set_groups(frameset, tag_on, tag_off));
00776 
00777     /*
00778      * First check of input consistency in NIR case:
00779      * There must be a pair ON and a pair OFF for each DIT.
00780      */
00781 
00782     skip_if (irplib_detmon_lg_retrieve_parlist(pipeline_name, recipe_name,
00783                            parlist, opt_nir));
00784 
00785     /*
00786      * Retrieve first image to check some parameters' values and
00787      * set default values which refer to the image.
00788      */
00789 
00790     first = cpl_frameset_get_first(frameset);
00791     irplib_ensure (first != NULL, CPL_ERROR_ILLEGAL_INPUT, "Empty data set!");
00792 
00793     detmon_lg_config.load_fset = load_fset;
00794     detmon_lg_config.load_fset_wrp = load_fset ? irplib_load_fset_wrp_ext : irplib_load_fset_wrp;
00795 
00796 
00797     if (detmon_lg_config.exts < 0) {
00798         reference = cpl_image_load(cpl_frame_get_filename(first),
00799                                    CPL_TYPE_FLOAT, 0, 1);
00800     } else {
00801     if (load_fset != NULL) {
00802         cpl_frameset * new = cpl_frameset_new();
00803         cpl_imagelist * p = cpl_imagelist_new();
00804         cpl_frameset_insert(new, cpl_frame_duplicate(first));
00805         (*load_fset)(new, CPL_TYPE_FLOAT, p);
00806         reference = cpl_image_duplicate(cpl_imagelist_get(p, 0));
00807         cpl_imagelist_delete(p);
00808         cpl_frameset_delete(new);
00809     } else {
00810            cpl_msg_info(cpl_func,"name=%s",cpl_frame_get_filename(first));
00811         reference = cpl_image_load(cpl_frame_get_filename(first),
00812                        CPL_TYPE_FLOAT, 0, detmon_lg_config.exts);
00813     }
00814     }
00815     skip_if (reference == NULL);
00816 
00817     skip_if (irplib_detmon_lg_check_defaults(reference));
00818 
00819     /* Labelise all input frames */
00820 
00821     /*
00822      * After each setting iteration, frameset will be modified (product
00823      * frames will have been added), so it is better to duplicate it, keep
00824      * it in its original state for the labelise-extract scheme.
00825      */
00826     if (compare == NULL) {
00827         nsets = 1;
00828     } else {
00829         cpl_msg_info(cpl_func, "Identifying different settings");
00830         selection = cpl_frameset_labelise(frameset, compare, &nsets);
00831         skip_if (selection == NULL);
00832     }
00833 
00834     /* Get the nb of extensions */
00835     detmon_lg_config.nb_extensions = 1;
00836     if (detmon_lg_config.exts < 0)
00837     {
00838         detmon_lg_config.nb_extensions = cpl_frame_get_nextensions(first);
00839     }
00840     /* Extract settings and reduce each of them */
00841     for(i = 0; i < nsets; i++)
00842     {
00843         int fr_size = cpl_frameset_get_size(frameset);
00844         int fr_size_new = 0;
00845         cpl_msg_info(cpl_func, "Reduce data set nb %d out of %d",
00846                  i + 1, nsets);
00847         skip_if(irplib_detmon_lg_reduce_set(i, frameset, nsets, tag_on, tag_off,
00848                 recipe_name,
00849                 pipeline_name,
00850                 pafregexp,
00851                 pro_lintbl,
00852                 pro_gaintbl,
00853                 pro_coeffscube,
00854                 pro_bpm,
00855                 pro_corr,
00856                 pro_diff,
00857                 package,
00858                 load_fset,
00859                 opt_nir,
00860                 parlist,
00861                 selection));
00862         fr_size_new = cpl_frameset_get_size(frameset);
00863         /* the size of the frameset could be changed during the irplib_detmon_lg_reduce_set call
00864          * so the size of the selection array should be adjusted with some fake values,
00865          * to avoid reading of the not allocated memory
00866          * see DFS08110 for the error description
00867          * */
00868         if (fr_size_new > fr_size)
00869         {
00870             selection = cpl_realloc(selection, fr_size_new  * sizeof(selection[0]));
00871             memset(selection + fr_size,  -1, (fr_size_new - fr_size) * sizeof(selection[0]));
00872         }
00873     }
00874 
00875     end_skip;
00876 
00877     cpl_frameset_delete(cur_fset);
00878     cpl_frameset_delete(cur_fset_on);
00879     cpl_frameset_delete(cur_fset_off);
00880     cpl_free(selection);
00881     cpl_image_delete(reference);
00882 
00883     return cpl_error_get_code();
00884 }
00885 
00886 /*---------------------------------------------------------------------------*/
00917 /*---------------------------------------------------------------------------*/
00918 
00919 static cpl_error_code
00920 irplib_detmon_lg_core(cpl_frameset * cur_fset_on,
00921               cpl_frameset * cur_fset_off,
00922               int * index_on,
00923               int * index_off,
00924               double * exptime_on,
00925               double * exptime_off,
00926               int whichext,
00927                       int whichset,
00928               const char              * recipe_name,
00929               const char              * pipeline_name,
00930               const char              * pafregexp,
00931               const cpl_propertylist  * pro_lintbl,
00932               const cpl_propertylist  * pro_gaintbl,
00933               const cpl_propertylist  * pro_coeffscube,
00934               const cpl_propertylist  * pro_bpm,
00935               const cpl_propertylist  * pro_corr,
00936               const cpl_propertylist  * pro_diff,
00937               const char              * package,
00938               int                    (* load_fset) (const cpl_frameset *,
00939                                 cpl_type,
00940                                 cpl_imagelist *),
00941               int nsets, cpl_boolean opt_nir,
00942                       cpl_frameset * frameset, const cpl_parameterlist * parlist,
00943                       cpl_frameset * cur_fset)
00944 {
00945     cpl_table        * gain_table      = cpl_table_new(cpl_frameset_get_size(cur_fset_on)/2);
00946     cpl_table        * linear_table    = cpl_table_new(cpl_frameset_get_size(cur_fset_on)/2);
00947     cpl_imagelist    * coeffs          = NULL;
00948     cpl_image        * bpm             = NULL;
00949     cpl_imagelist    * autocorr_images = NULL;
00950     cpl_imagelist    * diff_flats      = NULL;
00951     cpl_propertylist * gaint_qclist    = NULL;
00952     cpl_propertylist * lint_qclist     = NULL;
00953     cpl_propertylist * linc_qclist     = NULL;
00954     cpl_propertylist * bpm_qclist      = NULL;
00955 
00956     int next_index_on = 0;
00957     int next_index_off = 0;
00958 
00959 
00960     /* Reduce extension nb i */
00961     cpl_msg_info(cpl_func, "Reduce extension nb %d ",
00962          whichext);
00963 
00964     /* FIXME: All other memory objects in use should be
00965        initialised here (except coeffs which can not be) */
00966     if (detmon_lg_config.intermediate) {
00967     autocorr_images = cpl_imagelist_new();
00968     diff_flats      = cpl_imagelist_new();
00969     }
00970 
00971     gaint_qclist = cpl_propertylist_new();
00972     lint_qclist  = cpl_propertylist_new();
00973     linc_qclist  = cpl_propertylist_new();
00974     bpm_qclist   = cpl_propertylist_new();
00975 
00976     /* Reduction done here */
00977     cpl_msg_info(cpl_func, "Starting data reduction");
00978     skip_if(irplib_detmon_lg_reduce(cur_fset_on, cur_fset_off,
00979                     index_on, index_off, exptime_on, exptime_off,
00980                     &next_index_on, &next_index_off,
00981                     &coeffs, gain_table,
00982                     linear_table, &bpm, autocorr_images,
00983                     diff_flats, gaint_qclist, lint_qclist,
00984                     linc_qclist, bpm_qclist, load_fset,
00985                     opt_nir, whichext));
00986 
00987     /* Save the products for each setting */
00988     cpl_msg_info(cpl_func, "Saving the products");
00989     if(nsets == 1) {
00990     skip_if(irplib_detmon_lg_save(parlist, frameset, recipe_name,
00991                       pipeline_name, pafregexp,
00992                       pro_lintbl, pro_gaintbl,
00993                       pro_coeffscube, pro_bpm,
00994                       pro_corr, pro_diff, package,
00995                       coeffs, gain_table, linear_table,
00996                       bpm, autocorr_images, diff_flats,
00997                       gaint_qclist, lint_qclist, linc_qclist,
00998                       bpm_qclist, 0, 0, cur_fset, whichext));
00999     } else {
01000     skip_if(irplib_detmon_lg_save(parlist, frameset, recipe_name,
01001                       pipeline_name, pafregexp,
01002                       pro_lintbl, pro_gaintbl,
01003                       pro_coeffscube, pro_bpm,
01004                       pro_corr, pro_diff, package,
01005                       coeffs, gain_table, linear_table,
01006                       bpm, autocorr_images, diff_flats,
01007                       gaint_qclist, lint_qclist, linc_qclist,
01008                       bpm_qclist, 1, whichset+ 1, cur_fset,
01009                       whichext));
01010     }
01011 
01012     end_skip;
01013 
01014     /* Free for each extension */
01015     cpl_table_delete(gain_table);
01016     cpl_table_delete(linear_table);
01017     cpl_imagelist_delete(coeffs);
01018     cpl_propertylist_delete(gaint_qclist);
01019     cpl_propertylist_delete(lint_qclist);
01020     cpl_propertylist_delete(linc_qclist);
01021     cpl_propertylist_delete(bpm_qclist);
01022     cpl_image_delete(bpm);
01023     cpl_imagelist_delete(autocorr_images);
01024     cpl_imagelist_delete(diff_flats);
01025 
01026     return cpl_error_get_code();
01027 }
01028 /*--------------------------------------------------------------------------*/
01029 
01030 /*
01031  * @brief  Correlate two images with a given range of shifts
01032  * @param  image1       Input image
01033  * @param  image2       Input image
01034  * @param  m            Shift to apply on the x-axis
01035  * @param  n            Shift to apply on the y-axis
01036  * @return              An image of size 2m+1 by 2n+1. Each pixel value
01037  *                      corresponds to the correlation of shift the position
01038  *                      of the pixel. Pixel in the centre (m+1, n+1),
01039  *                      corresponds to shift (0,0). Pixels to the left and
01040  *                      down correspond to negative shifts.
01041  *
01042  * @note                At this moment, this function only accepts images to
01043  *                      have both the same size.
01044  */
01045 
01046 /*--------------------------------------------------------------------------*/
01047 
01048 cpl_image              *
01049 irplib_detmon_image_correlate(const cpl_image * image1,
01050                               const cpl_image * image2,
01051                               const int m, const int n)
01052 {
01053     cpl_image              *image1_padded = NULL;
01054     cpl_image              *image2_padded = NULL;
01055     int                     nx, ny;
01056     int                     nx2, ny2;
01057     int                     i,j;
01058 
01059     cpl_image              *corr_image = NULL;
01060     cpl_image              *corr_image_window = NULL;
01061     cpl_image              *reorganised= NULL;
01062     cpl_image              *image= NULL;
01063 
01064     cpl_image* image_ri_inv = NULL;
01065     cpl_image* image_in_inv = NULL;
01066     cpl_image* image_ri1 = NULL;
01067     cpl_image* image_ri2 = NULL;
01068     cpl_error_code err = CPL_ERROR_NONE;
01069 
01070     /* Test the entries */
01071     cpl_ensure(image1 != NULL, CPL_ERROR_NULL_INPUT, NULL);
01072     cpl_ensure(image2 != NULL, CPL_ERROR_NULL_INPUT, NULL);
01073 
01074     cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
01075     cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
01076 
01077     nx = cpl_image_get_size_x(image1);
01078     ny = cpl_image_get_size_y(image1);
01079 
01080     nx2 = cpl_image_get_size_x(image2);
01081     ny2 = cpl_image_get_size_y(image2);
01082 
01083     /* At this moment, the images must be of the same size */
01084     cpl_ensure(nx == nx2 && ny == ny2, CPL_ERROR_ILLEGAL_INPUT, NULL);
01085 
01086     /* Pad the images with zeroes to avoid periodical effects of DFT */
01087     image1_padded = cpl_image_new(nx + 2 * m, ny + 2 * n, CPL_TYPE_FLOAT);
01088     cpl_image_copy(image1_padded, image1, m + 1, n + 1);
01089 
01090     image2_padded = cpl_image_new(nx + 2 * m, ny + 2 * n, CPL_TYPE_FLOAT);
01091     cpl_image_copy(image2_padded, image2, m + 1, n + 1);
01092 
01093     /*New dimensions of the padded images */
01094     nx = nx + 2 * m;
01095     ny = ny + 2 * n;
01096 
01097     image_ri1 = cpl_image_new(nx, ny, CPL_TYPE_FLOAT_COMPLEX);
01098     image_ri2 = cpl_image_new(nx, ny , CPL_TYPE_FLOAT_COMPLEX);
01099     /* Actually perform the FFT */
01100     cpl_fft_image(image_ri1, image1_padded, CPL_FFT_FORWARD);
01101     cpl_fft_image(image_ri2, image2_padded, CPL_FFT_FORWARD);
01102     err = cpl_error_get_code();
01103     cpl_image_delete(image1_padded);
01104     image1_padded = NULL;
01105     cpl_image_delete(image2_padded);
01106     image2_padded = NULL;
01107     if (err == CPL_ERROR_NONE)
01108     {
01109     /* Cleanup resources */
01110         image_ri_inv = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01111         image_in_inv = cpl_image_new(nx, ny, CPL_TYPE_FLOAT_COMPLEX);
01112 
01113         for (i = 1; i <= nx; i++)
01114         {
01115             for (j = 1; j <= ny; j++)
01116             {
01117                 int rej = 0;
01118                 double complex value1, value2, value;
01119                 value1 = cpl_image_get_complex(image_ri1, i, j, &rej);
01120                 value2 = cpl_image_get_complex(image_ri2, i, j, &rej);;
01121                 value = conj(value1) * value2;
01122                 cpl_image_set_complex(image_in_inv, i, j, value);
01123             }
01124         }
01125         cpl_image_delete(image_ri1);
01126         image_ri1 = NULL;
01127         cpl_image_delete(image_ri2);
01128         image_ri2 = NULL;
01129 
01130         err = cpl_error_get_code();
01131         if (err == CPL_ERROR_NONE)
01132         {
01133 
01134         /* Actually perform the FFT */
01135         cpl_fft_image(image_ri_inv, image_in_inv,CPL_FFT_BACKWARD);
01136         cpl_image_delete(image_in_inv);
01137 
01138         /* Get the module of the inversed signal */
01139         corr_image = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01140         for (i = 1; i <= nx; i++)
01141         {
01142             for (j = 1; j <= ny; j++)
01143             {
01144                 int rej = 0;
01145                 double value =0;
01146                 value = cpl_image_get(image_ri_inv, i, j, &rej);
01147                 cpl_image_set(corr_image, i, j, value);
01148             }
01149         }
01150         cpl_image_delete(image_ri_inv);
01151         err = cpl_error_get_code();
01152         if (err == CPL_ERROR_NONE)
01153         {
01154         /* Reorganise the pixels to the output */
01155             reorganised = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01156 
01157             image = cpl_image_extract(corr_image, nx / 2 + 1, 1, nx, ny);
01158             cpl_image_copy(reorganised, image, 1, 1);
01159             cpl_image_delete(image);
01160             image = cpl_image_extract(corr_image, 1, 1, nx / 2, ny);
01161             cpl_image_copy(reorganised, image, nx / 2 + 1, 1);
01162             cpl_image_delete(image);
01163 
01164             cpl_image_delete(corr_image);
01165 
01166             corr_image = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01167             image = cpl_image_extract(reorganised, 1, ny / 2 + 1, nx, ny);
01168             cpl_image_copy(corr_image, image, 1, 1);
01169             cpl_image_delete(image);
01170 
01171             image = cpl_image_extract(reorganised, 1, 1, nx, ny / 2);
01172             cpl_image_copy(corr_image, image, 1, ny / 2 + 1);
01173             cpl_image_delete(image);
01174             /* Extract a window with the desired shifts */
01175             corr_image_window = cpl_image_extract(corr_image,
01176                                                   nx / 2 + 1 - m,
01177                                                   ny / 2 + 1 - n,
01178                                                   nx / 2 + 1 + m, ny / 2 + 1 + n);
01179             }
01180         /* Free and return */
01181 
01182         }
01183         cpl_image_delete(reorganised);
01184         cpl_image_delete(corr_image);
01185 
01186         if(cpl_image_divide_scalar(corr_image_window,
01187                                    cpl_image_get_max(corr_image_window))) {
01188             cpl_image_delete(corr_image_window);
01189             return NULL;
01190         }
01191     }
01192     cpl_image_delete (image_ri1);
01193     cpl_image_delete (image_ri2);
01194     cpl_image_delete (image1_padded);
01195     cpl_image_delete (image2_padded);
01196     return corr_image_window;
01197 }
01198 
01199 
01200 
01201 /*--------------------------------------------------------------------------*/
01202 
01203 /*
01204  * @brief  Autocorrelate an image with a given range of shifts, using
01205  *         cpl_image_fft()
01206  * @param  input2       Input image
01207  * @param  m            Shift to apply on the x-axis
01208  * @param  n            Shift to apply on the y-axis
01209  * @return              An image of size 2m+1 by 2n+1. Each pixel value
01210  *                      corresponds to the correlation of shift the position
01211  *                      of the pixel. Pixel in the centre (m+1, n+1),
01212  *                      corresponds to shift (0,0). Pixels to the left and
01213  *                      down correspond to negative shifts.
01214  */
01215 
01216 /*--------------------------------------------------------------------------*/
01217 
01218 cpl_image              *
01219 irplib_detmon_autocorrelate(const cpl_image * input2, const int m,
01220                             const int n)
01221 {
01222     cpl_image              *im_re = NULL;
01223     cpl_image              *im_im = NULL;
01224     int                     nx, ny;
01225     cpl_image              *ifft_re = NULL;
01226     cpl_image              *ifft_im = NULL;
01227     cpl_image              *autocorr = NULL;
01228     cpl_image              *autocorr_norm_double = NULL;
01229     cpl_image              *autocorr_norm = NULL;
01230     cpl_image              *reorganised = NULL;
01231     cpl_image              *image = NULL;
01232     int                     p;
01233     cpl_error_code          error;
01234     cpl_image              *input;
01235 
01236     cpl_ensure(input2 != NULL, CPL_ERROR_NULL_INPUT, NULL);
01237 
01238     cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
01239     cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
01240 
01241     nx = cpl_image_get_size_x(input2) + 2 * m;
01242     ny = cpl_image_get_size_y(input2) + 2 * n;
01243 
01244     p = 128;
01245     while(nx > p || ny > p) {
01246         p *= 2;
01247     }
01248 
01249     input = cpl_image_cast(input2, CPL_TYPE_DOUBLE);
01250 
01251     im_re = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01252     error = cpl_image_copy(im_re, input, 1, 1);
01253     cpl_ensure(!error, error, NULL);
01254 
01255     im_im = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01256 
01257     error = cpl_image_fft(im_re, im_im, CPL_FFT_DEFAULT);
01258     cpl_ensure(!error, error, NULL);
01259 
01260     ifft_re = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01261     error = cpl_image_power(im_re, 2);
01262     cpl_ensure(!error, error, NULL);
01263 
01264     error = cpl_image_add(ifft_re, im_re);
01265     cpl_ensure(!error, error, NULL);
01266 
01267     cpl_image_delete(im_re);
01268 
01269     error = cpl_image_power(im_im, 2);
01270     cpl_ensure(!error, error, NULL);
01271 
01272     error = cpl_image_add(ifft_re, im_im);
01273     cpl_ensure(!error, error, NULL);
01274 
01275     cpl_image_delete(im_im);
01276 
01277     ifft_im = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01278 
01279     error = cpl_image_fft(ifft_re, ifft_im, CPL_FFT_INVERSE);
01280     cpl_ensure(!error, error, NULL);
01281 
01282     autocorr = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01283 
01284     error = cpl_image_power(ifft_re, 2);
01285     cpl_ensure(!error, error, NULL);
01286 
01287     error = cpl_image_add(autocorr, ifft_re);
01288     cpl_ensure(!error, error, NULL);
01289 
01290     cpl_image_delete(ifft_re);
01291 
01292     error = cpl_image_power(ifft_im, 2);
01293     cpl_ensure(!error, error, NULL);
01294 
01295     error = cpl_image_add(autocorr, ifft_im);
01296     cpl_ensure(!error, error, NULL);
01297 
01298     cpl_image_delete(ifft_im);
01299 
01300     /* Reorganise the pixels to the output */
01301     reorganised = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01302 
01303     image = cpl_image_extract(autocorr, p / 2 + 1, 1, p, p);
01304     cpl_image_copy(reorganised, image, 1, 1);
01305     cpl_image_delete(image);
01306 
01307     image = cpl_image_extract(autocorr, 1, 1, p / 2, p);
01308     cpl_image_copy(reorganised, image, p / 2 + 1, 1);
01309     cpl_image_delete(image);
01310 
01311     cpl_image_delete(autocorr);
01312 
01313     autocorr = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
01314 
01315     image = cpl_image_extract(reorganised, 1, p / 2 + 1, p, p);
01316     cpl_image_copy(autocorr, image, 1, 1);
01317     cpl_image_delete(image);
01318 
01319     image = cpl_image_extract(reorganised, 1, 1, p, p / 2);
01320     cpl_image_copy(autocorr, image, 1, p / 2 + 1);
01321     cpl_image_delete(image);
01322 
01323     cpl_image_delete(reorganised);
01324 
01325     autocorr_norm_double =
01326         cpl_image_extract(autocorr, p / 2 + 1 - m, p / 2 + 1 - n,
01327                           p / 2 + 1 + m, p / 2 + 1 + n);
01328 
01329     cpl_image_delete(autocorr);
01330 
01331     if(cpl_image_divide_scalar(autocorr_norm_double,
01332                                cpl_image_get_max(autocorr_norm_double))) {
01333         cpl_image_delete(autocorr_norm_double);
01334         cpl_ensure(0, cpl_error_get_code(), NULL);
01335     }
01336 
01337 
01338     autocorr_norm = cpl_image_cast(autocorr_norm_double, CPL_TYPE_FLOAT);
01339     cpl_image_delete(autocorr_norm_double);
01340 
01341     cpl_image_delete(input);
01342 
01343     return autocorr_norm;
01344 }
01345 
01346 /*---------------------------------------------------------------------------*/
01357 /*---------------------------------------------------------------------------*/
01358 cpl_error_code
01359 irplib_detmon_lg_fill_parlist_nir_default(cpl_parameterlist * parlist,
01360                                   const char *recipe_name,
01361                                   const char *pipeline_name)
01362 {
01363     const cpl_error_code error =
01364     irplib_detmon_lg_fill_parlist(parlist, recipe_name, pipeline_name,
01365                   "PTC", /* --method */
01366                   3,   /* --order         */
01367                               3.,        /* --kappa         */
01368                               5,       /* --niter         */
01369                               -1,       /* --llx           */
01370                               -1,       /* --lly           */
01371                               -1,       /* --urx           */
01372                               -1,       /* --ury           */
01373                               10000,    /* --ref_level     */
01374                               "CPL_FALSE",      /* --intermediate  */
01375                               "CPL_FALSE",      /* --autocorr      */
01376                               "CPL_FALSE",      /* --collapse      */
01377                               "CPL_TRUE",       /* --rescale       */
01378                       "CPL_TRUE",/* --pix2pix */
01379                       "CPL_FALSE", /* --bpmbin */
01380                               -1,       /* --filter        */
01381                               26,       /* --m             */
01382                               26,       /* --n             */
01383                       1e-3, /* --tolerance */
01384                   "CPL_TRUE", /* --pafgen */
01385                       recipe_name, /* --pafname */
01386                               -1,       /* --llx1          */
01387                               -1,       /* --lly1          */
01388                               -1,       /* --urx1          */
01389                               -1,       /* --ury1          */
01390                               -1,       /* --llx2          */
01391                               -1,       /* --lly2          */
01392                               -1,       /* --urx2          */
01393                               -1,       /* --ury2          */
01394                               -1,       /* --llx3          */
01395                               -1,       /* --lly3          */
01396                               -1,       /* --urx3          */
01397                               -1,       /* --ury3          */
01398                               -1,       /* --llx4          */
01399                               -1,       /* --lly4          */
01400                               -1,       /* --urx4          */
01401                               -1,       /* --ury4          */
01402                               -1,       /* --llx5          */
01403                               -1,       /* --lly5          */
01404                               -1,       /* --urx5          */
01405                               -1,       /* --ury5          */
01406                       0,      /* --exts */
01407                           NIR);       /* This is to specify OPT params */
01408 
01409 
01410     cpl_ensure_code(!error, error);
01411 
01412     return cpl_error_get_code();
01413 }
01414 
01415 /*---------------------------------------------------------------------------*/
01426 /*---------------------------------------------------------------------------*/
01427 cpl_error_code
01428 irplib_detmon_lg_fill_parlist_opt_default(cpl_parameterlist * parlist,
01429                                   const char *recipe_name,
01430                                   const char *pipeline_name)
01431 {
01432     const cpl_error_code error =
01433     irplib_detmon_lg_fill_parlist(parlist, recipe_name, pipeline_name,
01434                   "PTC", /* --method */
01435                   3,   /* --order         */
01436                               3.,        /* --kappa         */
01437                               5,       /* --niter         */
01438                               -1,       /* --llx           */
01439                               -1,       /* --lly           */
01440                               -1,       /* --urx           */
01441                               -1,       /* --ury           */
01442                               10000,    /* --ref_level     */
01443                               "CPL_FALSE",      /* --intermediate  */
01444                               "CPL_FALSE",      /* --autocorr      */
01445                               "CPL_TRUE",      /* --collapse      */
01446                               "CPL_TRUE",       /* --rescale       */
01447                       "CPL_FALSE", /* --pix2pix */
01448                       "CPL_FALSE", /* --bpmbin */
01449                               -1,       /* --filter        */
01450                               26,       /* --m             */
01451                               26,       /* --n             */
01452                       1e-3, /* --tolerance */
01453                   "CPL_FALSE", /* --pafgen */
01454                       recipe_name, /* --pafname */
01455                               -1,       /* --llx1          */
01456                               -1,       /* --lly1          */
01457                               -1,       /* --urx1          */
01458                               -1,       /* --ury1          */
01459                               -1,       /* --llx2          */
01460                               -1,       /* --lly2          */
01461                               -1,       /* --urx2          */
01462                               -1,       /* --ury2          */
01463                               -1,       /* --llx3          */
01464                               -1,       /* --lly3          */
01465                               -1,       /* --urx3          */
01466                               -1,       /* --ury3          */
01467                               -1,       /* --llx4          */
01468                               -1,       /* --lly4          */
01469                               -1,       /* --urx4          */
01470                               -1,       /* --ury4          */
01471                               -1,       /* --llx5          */
01472                               -1,       /* --lly5          */
01473                               -1,       /* --urx5          */
01474                               -1,       /* --ury5          */
01475                       0,      /* --exts */
01476                           OPT);       /* This is to specify OPT params */
01477 
01478     cpl_ensure_code(!error, error);
01479 
01480     return cpl_error_get_code();
01481 }
01482 
01483 /*---------------------------------------------------------------------------*/
01537 /*---------------------------------------------------------------------------*/
01538 cpl_error_code
01539 irplib_detmon_lg_fill_parlist(cpl_parameterlist * parlist,
01540                           const char *recipe_name, const char *pipeline_name,
01541               const char *method,
01542                           int order,
01543                           double kappa,
01544                           int niter,
01545                           int llx,
01546                           int lly,
01547                           int urx,
01548                           int ury,
01549                           int ref_level,
01550                           const char *intermediate,
01551                           const char *autocorr,
01552                           const char *collapse,
01553                           const char *rescale,
01554                   const char *pix2pix,
01555                   const char *bpmbin,
01556                           int filter,
01557                           int m,
01558                           int n,
01559                   double tolerance,
01560                   const char *pafgen,
01561                   const char * pafname,
01562                           int llx1,
01563                           int lly1,
01564                           int urx1,
01565                           int ury1,
01566                           int llx2,
01567                           int lly2,
01568                           int urx2,
01569                           int ury2,
01570                           int llx3,
01571                           int lly3,
01572                           int urx3,
01573                           int ury3,
01574                           int llx4,
01575                           int lly4,
01576                           int urx4,
01577                           int ury4,
01578                   int llx5, int lly5, int urx5, int ury5, int exts,
01579                           cpl_boolean opt_nir)
01580 {
01581     const cpl_error_code error =
01582     irplib_detmon_fill_parlist(parlist, recipe_name, pipeline_name, 24,
01583                    "method",
01584                    "Method to be used when computing GAIN. Methods appliable: <PTC | MED>. By default PTC method will be applied.",
01585                                    "CPL_TYPE_STRING", method,
01586 
01587                                "order",
01588                                "Polynomial order for the fit (Linearity)",
01589                                "CPL_TYPE_INT", order,
01590                                "kappa",
01591                                "Kappa value for the kappa-sigma clipping (Gain)",
01592                                "CPL_TYPE_DOUBLE", kappa,
01593                                "niter",
01594                                "Number of iterations to compute rms (Gain)",
01595                                "CPL_TYPE_INT", niter,
01596                                "llx",
01597                                "x coordinate of the lower-left "
01598                                "point of the region of interest. If not modified, default value will be 1.",
01599                                "CPL_TYPE_INT", llx,
01600                                "lly",
01601                                "y coordinate of the lower-left "
01602                                "point of the region of interest. If not modified, default value will be 1.",
01603                                "CPL_TYPE_INT", lly,
01604                                "urx",
01605                                "x coordinate of the upper-right "
01606                                "point of the region of interest. If not modified, default value will be X dimension of the input image.",
01607                                "CPL_TYPE_INT", urx,
01608                                "ury",
01609                                "y coordinate of the upper-right "
01610                                "point of the region of interest. If not modified, default value will be Y dimension of the input image.",
01611                                "CPL_TYPE_INT", ury,
01612                                "ref_level",
01613                                "User reference level",
01614                                "CPL_TYPE_INT", ref_level,
01615                                "intermediate",
01616                                "De-/Activate intermediate products",
01617                                "CPL_TYPE_BOOL", intermediate,
01618                                
01619                                "autocorr",
01620                                "De-/Activate the autocorr option",
01621                                "CPL_TYPE_BOOL", autocorr,
01622                                
01623                                "collapse",
01624                                "De-/Activate the collapse option",
01625                                "CPL_TYPE_BOOL", collapse,
01626                                "rescale",
01627                                "De-/Activate the image rescale option",
01628                                "CPL_TYPE_BOOL", rescale,
01629                    "pix2pix",
01630                                "De-/Activate the computation with pixel to pixel accuracy",
01631                                "CPL_TYPE_BOOL", pix2pix,
01632                    "bpmbin",
01633                                "De-/Activate the binary bpm option",
01634                                "CPL_TYPE_BOOL", bpmbin,
01635                                "m",
01636                                "Maximum x-shift for the autocorr",
01637                                "CPL_TYPE_INT", m,
01638                                "filter",
01639                                "Upper limit of Median flux to be filtered",
01640                                "CPL_TYPE_INT", filter,
01641                                "n",
01642                                "Maximum y-shift for the autocorr",
01643                    "CPL_TYPE_INT", n,
01644                                "tolerance",
01645                                "Tolerance for pair discrimination",
01646                    "CPL_TYPE_DOUBLE", tolerance,
01647 
01648                                "pafgen",
01649                                "Generate PAF file",
01650                    "CPL_TYPE_BOOL", pafgen,
01651                                "pafname",
01652                                "Specific name for PAF file",
01653                    "CPL_TYPE_STRING", pafname,
01654 
01655 
01656                                "exts",
01657                                "Activate the multi-exts option. Choose -1 to process all extensions. Choose an extension number"
01658                                " to process the appropriate extension.",
01659                                "CPL_TYPE_INT", exts,
01660 
01661                                "fpn_method",
01662                                "Method for computing Fixed Pattern Noise (SMOOTH or HISTOGRAM)",
01663                                "CPL_TYPE_STRING", "HISTOGRAM",
01664 
01665                                "fpn_smooth",
01666                                "template size in pixels for smoothing during FPN computation (only for SMOOTH method)",
01667                                "CPL_TYPE_INT", 13,
01668 
01669                                "saturation_limit",
01670                                "all frames with mean saturation above the limit would not be used in calculation",
01671                                "CPL_TYPE_DOUBLE", 65535.0
01672     );
01673    irplib_detmon_fill_parlist(parlist, recipe_name, pipeline_name, 1,
01674                                "coeffs_cube_split",
01675                                "if TRUE, the recipe writes as many "
01676                                "COEFFS_CUBE_Pi (i=0..order) as the value of "
01677                                "the order parameter in a separate file",
01678                                "CPL_TYPE_BOOL", "CPL_FALSE");
01679     /* OPT specific parameters */
01680     if(opt_nir == FALSE) {
01681         const cpl_error_code erroropt =
01682         irplib_detmon_fill_parlist(parlist, recipe_name, pipeline_name, 20,
01683                                "llx1",
01684                                "x coord of the lower-left point of the first "
01685                                "field used for contamination measurement. If not modified, default value will be 1.",
01686                                "CPL_TYPE_INT", llx1,
01687                                "lly1",
01688                                "y coord of the lower-left point of the first "
01689                                "field used for contamination measurement. If not modified, default value will be 1.",
01690                                "CPL_TYPE_INT", lly1,
01691                                "urx1",
01692                                "x coord of the upper-right point of the first "
01693                                "field used for contamination measurement. If not modified, default value will be X dimension of the input image.",
01694                                "CPL_TYPE_INT", urx1,
01695                                "ury1",
01696                                "y coord of the upper-right point of the first "
01697                                "field used for contamination measurement. If not modified, default value will be Y dimension of the input image.",
01698                                "CPL_TYPE_INT", ury1,
01699                                "llx2",
01700                                "x coord of the lower-left point of the second "
01701                                "field used for contamination measurement. If not modified, default value will be 1.",
01702                                "CPL_TYPE_INT", llx2,
01703                                "lly2",
01704                                "y coord of the lower-left point of the second "
01705                                "field used for contamination measurement. If not modified, default value will be 1.",
01706                                "CPL_TYPE_INT", lly2,
01707                                "urx2",
01708                                "x coord of the upper-right point of the second "
01709                                "field used for contamination measurement. If not modified, default value will be half of the X dimension of the input image.",
01710                                "CPL_TYPE_INT", urx2,
01711                                "ury2",
01712                                "y coord of the upper-right point of the second "
01713                                "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
01714                                "CPL_TYPE_INT", ury2,
01715                                "llx3",
01716                                "x coord of the lower-left point of the third "
01717                                "field used for contamination measurement. If not modified, default value will be 1.",
01718                                "CPL_TYPE_INT", llx3,
01719                                "lly3",
01720                                "y coord of the lower-left point of the third "
01721                                "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
01722                                "CPL_TYPE_INT", lly3,
01723                                "urx3",
01724                                "x coord of the upper-right point of the third "
01725                                "field used for contamination measurement. If not modified, default value will be half of X dimension of the image.",
01726                                "CPL_TYPE_INT", urx3,
01727                                "ury3",
01728                                "y coord of the upper-right point of the third "
01729                                "field used for contamination measurement. If not modified, default value will be Y dimension of the image.",
01730                                "CPL_TYPE_INT", ury3,
01731                                "llx4",
01732                                "x coord of the lower-left point of the fourth "
01733                                "field used for contamination measurement. If not modified, default value will be half of X dimension of the image.",
01734                                "CPL_TYPE_INT", llx4,
01735                                "lly4",
01736                                "y coord of the lower-left point of the fourth "
01737                                "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
01738                                "CPL_TYPE_INT", lly4,
01739                                "urx4",
01740                                "x coord of the upper-right point of the fourth "
01741                                "field used for contamination measurement. If not modified, default value will be X dimension of the image.",
01742                                "CPL_TYPE_INT", urx4,
01743                                "ury4",
01744                                "y coord of the upper-right point of the fourth "
01745                                "field used for contamination measurement. If not modified, default value will be Y dimension of the input image.",
01746                                "CPL_TYPE_INT", ury4,
01747                                "llx5",
01748                                "x coord of the lower-left point of the fifth "
01749                                "field used for contamination measurement. If not modified, default value will be half of the X dimension of the input image.",
01750                                "CPL_TYPE_INT", llx5,
01751                                "lly5",
01752                                "y coord of the lower-left point of the fifth "
01753                                "field used for contamination measurement. If not modified, default value will be 1.",
01754                                "CPL_TYPE_INT", lly5,
01755                                "urx5",
01756                                "x coord of the upper-right point of the fifth "
01757                                "field used for contamination measurement. If not modified, default value will be X dimension of the image.",
01758                                "CPL_TYPE_INT", urx5,
01759 
01760                                "ury5",
01761                                "y coord of the upper-right point of the fifth "
01762                                "field used for contamination measurement. If not modified, default value will be half of Y dimension of the input image.",
01763                    "CPL_TYPE_INT", ury5);
01764         cpl_ensure_code(!erroropt, erroropt);
01765     }
01766 
01767     cpl_ensure_code(!error, error);
01768 
01769     return cpl_error_get_code();
01770 }
01771 
01772 /*---------------------------------------------------------------------------*/
01781 /*---------------------------------------------------------------------------*/
01782 static cpl_error_code
01783 irplib_detmon_lg_retrieve_parlist(const char              * pipeline_name,
01784                   const char              * recipe_name,
01785                   const cpl_parameterlist * parlist,
01786                   cpl_boolean               opt_nir)
01787 {
01788 
01789     char                   * par_name;
01790     cpl_parameter          * par;
01791 
01792     /* --method */
01793     par_name = cpl_sprintf("%s.%s.method", pipeline_name, recipe_name);
01794     assert(par_name != NULL);
01795     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01796     detmon_lg_config.method = cpl_parameter_get_string(par);
01797     cpl_free(par_name);
01798 
01799     /* --order */
01800     detmon_lg_config.order =
01801         irplib_detmon_retrieve_par_int("order", pipeline_name, recipe_name,
01802                                    parlist);
01803 
01804     /* --kappa */
01805     detmon_lg_config.kappa =
01806         irplib_detmon_retrieve_par_double("kappa", pipeline_name, recipe_name,
01807                                    parlist);
01808 
01809     /* --niter */
01810     detmon_lg_config.niter =
01811         irplib_detmon_retrieve_par_int("niter", pipeline_name, recipe_name,
01812                                    parlist);
01813 
01814     /* --llx */
01815     detmon_lg_config.llx =
01816         irplib_detmon_retrieve_par_int("llx", pipeline_name, recipe_name,
01817                                    parlist);
01818 
01819     /* --lly */
01820     detmon_lg_config.lly =
01821         irplib_detmon_retrieve_par_int("lly", pipeline_name, recipe_name,
01822                                    parlist);
01823 
01824     /* --urx */
01825     detmon_lg_config.urx =
01826         irplib_detmon_retrieve_par_int("urx", pipeline_name, recipe_name,
01827                                    parlist);
01828 
01829     /* --ury */
01830     detmon_lg_config.ury =
01831         irplib_detmon_retrieve_par_int("ury", pipeline_name, recipe_name,
01832                                    parlist);
01833 
01834     /* --ref_level */
01835     detmon_lg_config.ref_level =
01836         irplib_detmon_retrieve_par_int("ref_level", pipeline_name, recipe_name,
01837                                    parlist);
01838 
01839     /* --intermediate */
01840     par_name =
01841         cpl_sprintf("%s.%s.intermediate", pipeline_name, recipe_name);
01842     assert(par_name != NULL);
01843     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01844     detmon_lg_config.intermediate = cpl_parameter_get_bool(par);
01845     cpl_free(par_name);
01846 
01847     /* --autocorr */
01848     par_name = cpl_sprintf("%s.%s.autocorr", pipeline_name, recipe_name);
01849     assert(par_name != NULL);
01850     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01851     detmon_lg_config.autocorr = cpl_parameter_get_bool(par);
01852     cpl_free(par_name);
01853     
01854     /* --coeffs_cube_split */
01855     par_name = cpl_sprintf("%s.%s.coeffs_cube_split", pipeline_name, recipe_name);
01856     assert(par_name != NULL);
01857     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01858     detmon_lg_config.split_coeffs = cpl_parameter_get_bool(par);
01859     cpl_free(par_name);
01860     
01861     /* --collapse */
01862     par_name = cpl_sprintf("%s.%s.collapse", pipeline_name, recipe_name);
01863     assert(par_name != NULL);
01864     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01865     detmon_lg_config.collapse = cpl_parameter_get_bool(par);
01866     cpl_free(par_name);
01867 
01868     /* --rescale */
01869     par_name = cpl_sprintf("%s.%s.rescale", pipeline_name, recipe_name);
01870     assert(par_name != NULL);
01871     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01872     detmon_lg_config.rescale = cpl_parameter_get_bool(par);
01873     cpl_free(par_name);
01874 
01875     /* --pix2pix */
01876     par_name = cpl_sprintf("%s.%s.pix2pix", pipeline_name, recipe_name);
01877     assert(par_name != NULL);
01878     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01879     detmon_lg_config.pix2pix = cpl_parameter_get_bool(par);
01880     cpl_free(par_name);
01881 
01882     /* --bpmbin */
01883     par_name = cpl_sprintf("%s.%s.bpmbin", pipeline_name, recipe_name);
01884     assert(par_name != NULL);
01885     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01886     detmon_lg_config.bpmbin = cpl_parameter_get_bool(par);
01887     cpl_free(par_name);
01888 
01889     /* --filter */
01890     detmon_lg_config.filter =
01891         irplib_detmon_retrieve_par_int("filter", pipeline_name,
01892                                    recipe_name, parlist);
01893 
01894     /* --m */
01895     detmon_lg_config.m =
01896         irplib_detmon_retrieve_par_int("m", pipeline_name, recipe_name, parlist);
01897 
01898     /* --n */
01899     detmon_lg_config.n =
01900         irplib_detmon_retrieve_par_int("n", pipeline_name, recipe_name, parlist);
01901 
01902     /* --tolerance */
01903     par_name = cpl_sprintf("%s.%s.tolerance", pipeline_name, recipe_name);
01904     assert(par_name != NULL);
01905     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01906     detmon_lg_config.tolerance = cpl_parameter_get_double(par);
01907     cpl_free(par_name);
01908 
01909 
01910     /* --pafgen */
01911     par_name = cpl_sprintf("%s.%s.pafgen", pipeline_name, recipe_name);
01912     assert(par_name != NULL);
01913     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01914     detmon_lg_config.pafgen = cpl_parameter_get_bool(par);
01915     cpl_free(par_name);
01916 
01917     /* --pafname */
01918     par_name = cpl_sprintf("%s.%s.pafname", pipeline_name, recipe_name);
01919     assert(par_name != NULL);
01920     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01921     detmon_lg_config.pafname = cpl_parameter_get_string(par);
01922     cpl_free(par_name);
01923 
01924     if(opt_nir == OPT) {
01925     /* --llx1 */
01926     detmon_lg_config.llx1 =
01927         irplib_detmon_retrieve_par_int("llx1", pipeline_name, recipe_name,
01928                        parlist);
01929 
01930     /* --lly1 */
01931     detmon_lg_config.lly1 =
01932         irplib_detmon_retrieve_par_int("lly1", pipeline_name, recipe_name,
01933                        parlist);
01934 
01935     /* --urx1 */
01936     detmon_lg_config.urx1 =
01937         irplib_detmon_retrieve_par_int("urx1", pipeline_name, recipe_name,
01938                        parlist);
01939 
01940     /* --ury1 */
01941     detmon_lg_config.ury1 =
01942         irplib_detmon_retrieve_par_int("ury1", pipeline_name, recipe_name,
01943                        parlist);
01944 
01945     /* --llx2 */
01946     detmon_lg_config.llx2 =
01947         irplib_detmon_retrieve_par_int("llx2", pipeline_name, recipe_name,
01948                        parlist);
01949 
01950     /* --lly2 */
01951     detmon_lg_config.lly2 =
01952         irplib_detmon_retrieve_par_int("lly2", pipeline_name, recipe_name,
01953                        parlist);
01954 
01955     /* --urx2 */
01956     detmon_lg_config.urx2 =
01957         irplib_detmon_retrieve_par_int("urx2", pipeline_name, recipe_name,
01958                        parlist);
01959 
01960     /* --ury2 */
01961     detmon_lg_config.ury2 =
01962         irplib_detmon_retrieve_par_int("ury2", pipeline_name, recipe_name,
01963                        parlist);
01964 
01965     /* --llx3 */
01966     detmon_lg_config.llx3 =
01967         irplib_detmon_retrieve_par_int("llx3", pipeline_name, recipe_name,
01968                        parlist);
01969 
01970     /* --lly3 */
01971     detmon_lg_config.lly3 =
01972         irplib_detmon_retrieve_par_int("lly3", pipeline_name, recipe_name,
01973                        parlist);
01974 
01975     /* --urx3 */
01976     detmon_lg_config.urx3 =
01977         irplib_detmon_retrieve_par_int("urx3", pipeline_name, recipe_name,
01978                        parlist);
01979 
01980     /* --ury3 */
01981     detmon_lg_config.ury3 =
01982         irplib_detmon_retrieve_par_int("ury3", pipeline_name, recipe_name,
01983                        parlist);
01984 
01985     /* --llx4 */
01986     detmon_lg_config.llx4 =
01987         irplib_detmon_retrieve_par_int("llx4", pipeline_name, recipe_name,
01988                        parlist);
01989 
01990     /* --lly4 */
01991     detmon_lg_config.lly4 =
01992         irplib_detmon_retrieve_par_int("lly4", pipeline_name, recipe_name,
01993                        parlist);
01994 
01995     /* --urx4 */
01996     detmon_lg_config.urx4 =
01997         irplib_detmon_retrieve_par_int("urx4", pipeline_name, recipe_name,
01998                        parlist);
01999 
02000     /* --ury4 */
02001     detmon_lg_config.ury4 =
02002         irplib_detmon_retrieve_par_int("ury4", pipeline_name, recipe_name,
02003                        parlist);
02004 
02005     /* --llx5 */
02006     detmon_lg_config.llx5 =
02007         irplib_detmon_retrieve_par_int("llx5", pipeline_name, recipe_name,
02008                        parlist);
02009 
02010     /* --lly5 */
02011     detmon_lg_config.lly5 =
02012         irplib_detmon_retrieve_par_int("lly5", pipeline_name, recipe_name,
02013                        parlist);
02014 
02015     /* --urx5 */
02016     detmon_lg_config.urx5 =
02017         irplib_detmon_retrieve_par_int("urx5", pipeline_name, recipe_name,
02018                        parlist);
02019 
02020     /* --ury5 */
02021     detmon_lg_config.ury5 =
02022         irplib_detmon_retrieve_par_int("ury5", pipeline_name, recipe_name,
02023                        parlist);
02024     }
02025 
02026     /* --exts */
02027     detmon_lg_config.exts =
02028         irplib_detmon_retrieve_par_int("exts", pipeline_name, recipe_name,
02029                                    parlist);
02030     /* --fpn_method */
02031     {
02032         const char* str_method = 0;
02033         detmon_lg_config.fpn_method = FPN_HISTOGRAM;
02034         par_name =
02035             cpl_sprintf("%s.%s.fpn_method", pipeline_name, recipe_name);
02036         assert(par_name != NULL);
02037         par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
02038         if (par)
02039         {
02040             str_method = cpl_parameter_get_string(par);
02041             if (strcmp(str_method, "SMOOTH") == 0)
02042             {
02043                 detmon_lg_config.fpn_method = FPN_SMOOTH;
02044             }
02045             else if (strcmp(str_method, "HISTOGRAM") == 0)
02046             {
02047                 detmon_lg_config.fpn_method = FPN_HISTOGRAM;
02048             }
02049         }
02050         cpl_free(par_name);
02051     }
02052     /* --fpn_smooth */
02053     detmon_lg_config.fpn_smooth =
02054         irplib_detmon_retrieve_par_int("fpn_smooth", pipeline_name, recipe_name,
02055                                    parlist);
02056     /* --saturation_limit*/
02057     {
02058         detmon_lg_config.saturation_limit = 65535;
02059         par_name =
02060             cpl_sprintf("%s.%s.saturation_limit", pipeline_name, recipe_name);
02061         assert(par_name != NULL);
02062         par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
02063         if (par)
02064         {
02065             detmon_lg_config.saturation_limit  = cpl_parameter_get_double(par);
02066         }
02067         cpl_free(par_name);
02068     }
02069     if(cpl_error_get_code())
02070     {
02071         cpl_msg_error(cpl_func, "Failed to retrieve the input parameters");
02072         cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
02073     }
02074 
02075 
02076     return cpl_error_get_code();
02077 }
02078 
02079 /*---------------------------------------------------------------------------*/
02085 /*---------------------------------------------------------------------------*/
02086 static cpl_error_code
02087 irplib_detmon_lg_check_defaults(const cpl_image * reference)
02088 {
02089     const int               nx = cpl_image_get_size_x(reference);
02090     const int               ny = cpl_image_get_size_y(reference);
02091 
02092     detmon_lg_config.nx = nx;
02093     detmon_lg_config.ny = ny;
02094 
02095     detmon_lg_config.wholechip = CPL_FALSE;
02096 
02097     if(detmon_lg_config.llx == -1)
02098         detmon_lg_config.llx = 1;
02099     if(detmon_lg_config.lly == -1)
02100         detmon_lg_config.lly = 1;
02101     if(detmon_lg_config.urx == -1)
02102         detmon_lg_config.urx = nx;
02103     if(detmon_lg_config.ury == -1)
02104         detmon_lg_config.ury = ny;
02105 
02106     if (detmon_lg_config.llx == 1  &&
02107     detmon_lg_config.lly == 1  &&
02108     detmon_lg_config.urx == nx &&
02109     detmon_lg_config.ury == ny)
02110     detmon_lg_config.wholechip = CPL_TRUE;
02111 
02112     if(detmon_lg_config.llx1 == -1)
02113         detmon_lg_config.llx1 = 1;
02114     if(detmon_lg_config.lly1 == -1)
02115         detmon_lg_config.lly1 = 1;
02116     if(detmon_lg_config.urx1 == -1)
02117         detmon_lg_config.urx1 = nx;
02118     if(detmon_lg_config.ury1 == -1)
02119         detmon_lg_config.ury1 = ny;
02120 
02121     if(detmon_lg_config.llx2 == -1)
02122         detmon_lg_config.llx2 = 1;
02123     if(detmon_lg_config.lly2 == -1)
02124         detmon_lg_config.lly2 = 1;
02125     if(detmon_lg_config.urx2 == -1)
02126         detmon_lg_config.urx2 = nx / 2;
02127     if(detmon_lg_config.ury2 == -1)
02128         detmon_lg_config.ury2 = ny / 2;
02129 
02130     if(detmon_lg_config.llx3 == -1)
02131         detmon_lg_config.llx3 = 1;
02132     if(detmon_lg_config.lly3 == -1)
02133         detmon_lg_config.lly3 = ny / 2;
02134     if(detmon_lg_config.urx3 == -1)
02135         detmon_lg_config.urx3 = nx / 2;
02136     if(detmon_lg_config.ury3 == -1)
02137         detmon_lg_config.ury3 = ny;
02138 
02139     if(detmon_lg_config.llx4 == -1)
02140         detmon_lg_config.llx4 = nx / 2;
02141     if(detmon_lg_config.lly4 == -1)
02142         detmon_lg_config.lly4 = ny / 2;
02143     if(detmon_lg_config.urx4 == -1)
02144         detmon_lg_config.urx4 = nx;
02145     if(detmon_lg_config.ury4 == -1)
02146         detmon_lg_config.ury4 = ny;
02147 
02148     if(detmon_lg_config.llx5 == -1)
02149         detmon_lg_config.llx5 = nx / 2;
02150     if(detmon_lg_config.lly5 == -1)
02151         detmon_lg_config.lly5 = 1;
02152     if(detmon_lg_config.urx5 == -1)
02153         detmon_lg_config.urx5 = nx;
02154     if(detmon_lg_config.ury5 == -1)
02155         detmon_lg_config.ury5 = ny / 2;
02156 
02157     if(detmon_lg_config.intermediate == TRUE) {
02158         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.");
02159         detmon_lg_config.autocorr = TRUE;
02160     }
02161 
02162 
02163     detmon_lg_config.lamp_stability = 0.0;
02164 
02165     detmon_lg_config.lamp_ok = FALSE;
02166 
02167     detmon_lg_config.cr = 0.0;
02168 
02169     return cpl_error_get_code();
02170 }
02171 
02172 /*---------------------------------------------------------------------------*/
02183 /*---------------------------------------------------------------------------*/
02184 static cpl_error_code
02185 irplib_detmon_lg_split_onoff(const cpl_frameset * cur_fset,
02186                              cpl_frameset * cur_fset_on,
02187                              cpl_frameset * cur_fset_off,
02188                              const char *tag_on,
02189                              const char *tag_off)
02190 {
02191     int                     nframes;
02192     int                     i;
02193 
02194     const cpl_frame * first;
02195     const cpl_frame * second;
02196 
02197     const char * first_tag;
02198     const char * second_tag;
02199 
02200     cpl_frame * cur_frame_dup = NULL;
02201 
02202     skip_if((first   = cpl_frameset_get_first_const(cur_fset)) == NULL);
02203     skip_if((second  = cpl_frameset_get_next_const (cur_fset)) == NULL);
02204 
02205     skip_if((first_tag  = cpl_frame_get_tag(first))  == NULL);
02206     skip_if((second_tag = cpl_frame_get_tag(second)) == NULL);
02207 
02208 #if 0
02209     if (opt_nir == OPT &&
02210     ((!strcmp(first_tag, tag_on ) && !strcmp(second_tag, tag_off)) ||
02211      (!strcmp(first_tag, tag_off) && !strcmp(second_tag, tag_on )))) {
02212     detmon_lg_config.lamp_ok = TRUE;
02213     }
02214 #endif
02215 
02216     nframes = cpl_frameset_get_size(cur_fset);
02217     for(i = detmon_lg_config.lamp_ok ? 2 : 0; i < nframes; i++) {
02218         const cpl_frame * cur_frame =
02219         cpl_frameset_get_frame_const(cur_fset, i);
02220     char            * tag;
02221 
02222         /* Duplication is required for insertion to a different frameset */
02223         cur_frame_dup = cpl_frame_duplicate(cur_frame);
02224         tag = (char *) cpl_frame_get_tag(cur_frame_dup);
02225 
02226         /* Insertion in the corresponding sub-frameset */
02227         if(!strcmp(tag, tag_on)) {
02228             skip_if(cpl_frameset_insert(cur_fset_on, cur_frame_dup));
02229         } else if(!strcmp(tag, tag_off)) {
02230             skip_if(cpl_frameset_insert(cur_fset_off, cur_frame_dup));
02231         } else {
02232             cpl_frame_delete(cur_frame_dup);
02233         cur_frame_dup = NULL;
02234         }
02235     }
02236     cur_frame_dup = NULL;
02237 
02238     end_skip;
02239 
02240     cpl_frame_delete(cur_frame_dup);
02241 
02242     return cpl_error_get_code();
02243 }
02244 
02245 /*--------------------------------------------------------------------------*/
02267 /*--------------------------------------------------------------------------*/
02268 
02269 static cpl_error_code
02270 irplib_detmon_lg_reduce(const cpl_frameset * set_on,
02271                         const cpl_frameset * set_off,
02272                         int* index_on, int* index_off, double* exptime_on, double* exptime_off,
02273                         int *next_index_on, int* next_index_off,
02274                         cpl_imagelist ** coeffs_ptr,
02275                         cpl_table * gain_table,
02276                         cpl_table * linear_table,
02277                         cpl_image ** bpm_ptr,
02278                         cpl_imagelist * autocorr_images,
02279                         cpl_imagelist * diff_flats,
02280                         cpl_propertylist * gaint_qclist,
02281                         cpl_propertylist * lint_qclist,
02282                         cpl_propertylist * linc_qclist,
02283                         cpl_propertylist * bpm_qclist,
02284          int                    (* load_fset) (const cpl_frameset *,
02285                                cpl_type,
02286                                                cpl_imagelist *),
02287             const cpl_boolean opt_nir,
02288                         int whichext)
02289 {
02290     const double D_INVALID_VALUE = -999;
02291     int                     i;
02292     cpl_imagelist         * linearity_inputs = NULL;
02293     cpl_imagelist         * opt_offs = NULL;
02294     int                     nsets;
02295     cpl_propertylist      * reflist = NULL;
02296     int dit_nskip=0;
02297     int rows_affected = 1;
02298     int last_best = 0;
02299     /* Test entries */
02300     cpl_ensure(set_on != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
02301     cpl_ensure(set_off != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
02302 
02303     nsets = cpl_frameset_get_size(set_on) / 2;
02304 
02305     detmon_lg_config.load_fset = load_fset;
02306     if(detmon_lg_config.collapse) {
02307         /*
02308          * When the 'collapse' option is used, there are no OFF pairs. We
02309          * construct a pair with the 2 first raw OFF frames, which will be
02310          * passed for each DIT value, to maintain the same API in the function
02311          * irplib_detmon_gain_table_fill_row().
02312          */
02313         const cpl_frame        *first = cpl_frameset_get_first_const(set_off);
02314         cpl_frame              *dup_first = cpl_frame_duplicate(first);
02315 
02316         const cpl_frame        *second = cpl_frameset_get_next_const(set_off);
02317         cpl_frame              *dup_second = cpl_frame_duplicate(second);
02318 
02319         cpl_frameset           *raw_offs = cpl_frameset_new();
02320 
02321         skip_if(cpl_frameset_insert(raw_offs, dup_first));
02322         skip_if(cpl_frameset_insert(raw_offs, dup_second));
02323 
02324         opt_offs = cpl_imagelist_load_frameset(raw_offs, CPL_TYPE_FLOAT,
02325                            0, whichext);
02326 
02327         cpl_frameset_delete(raw_offs);
02328 
02329     }
02330 
02331     skip_if(irplib_detmon_lg_reduce_init(gain_table,
02332                      linear_table,
02333                      &linearity_inputs,
02334                                  opt_nir));
02335     if (!strcmp(detmon_lg_config.method, "PTC"))
02336     {
02337         cpl_msg_warning(cpl_func, "PTC method incompatible with lamp stability computation");
02338     }
02339     else if(!detmon_lg_config.collapse)
02340     {
02341         skip_if(irplib_detmon_lg_lamp_stab(set_on, set_off,
02342                        opt_nir, whichext));
02343     }
02344     /* Unselect all rows, to select only invalid ones */
02345     skip_if(cpl_table_unselect_all(linear_table));
02346     skip_if(cpl_table_unselect_all(gain_table));
02347 
02348     /* Loop on every DIT value */
02349 
02350     for(i = 0; i < nsets ; i++)
02351     {
02352             skip_if(irplib_detmon_lg_reduce_dit(set_on,
02353                     index_on, exptime_on,
02354                     i,
02355                     &dit_nskip,
02356                     set_off,
02357                     index_off, exptime_off,
02358                     next_index_on, next_index_off,
02359                     linear_table,
02360                     gain_table, linearity_inputs,
02361                     lint_qclist, opt_nir,
02362                     autocorr_images, diff_flats,
02363                     opt_offs,  whichext,
02364                     &rows_affected));
02365         if (rows_affected == 0)
02366         {
02367             cpl_msg_warning(cpl_func, "The rest frames would not be taken into calculation, check the messages above");
02368             cpl_table_select_row(linear_table, i);
02369             cpl_table_select_row(gain_table, i);
02370         }
02371         else
02372         {
02373             last_best = i;
02374         }
02375     }
02376     skip_if(irplib_detmon_add_adl_column(linear_table, opt_nir));
02377 
02378     /*
02379      * Removal of rows corresponding to frames above --filter threshold.
02380      * See calls to cpl_table_select_row() in irplib_detmon_lg_reduce_dit().
02381      */
02382     skip_if(cpl_table_erase_selected(gain_table));
02383     skip_if(cpl_table_erase_selected(linear_table));
02384 
02385     reflist = cpl_propertylist_new();
02386     skip_if(cpl_propertylist_append_bool(reflist, "ADU", FALSE));
02387     skip_if(cpl_table_sort(gain_table, reflist));
02388     /*
02389      * --Final reduction--
02390      * The following call to irplib_detmon_lg_reduce_all() makes the
02391      * computations which are over all posible DIT values.
02392      */
02393     skip_if(irplib_detmon_lg_reduce_all(linear_table,
02394                     gaint_qclist, lint_qclist, linc_qclist,
02395                     bpm_qclist, coeffs_ptr, bpm_ptr,
02396                     linearity_inputs,
02397                     gain_table, whichext, opt_nir));
02398     {
02399         /*FPN Computation*/
02400         double gain = cpl_propertylist_get_double(gaint_qclist, DETMON_QC_GAIN);
02401 //      cpl_propertylist_append_int(gaint_qclist, "NNNEXT", whichext);      
02402 //      cpl_msg_warning(cpl_func, "---------- ext %i" , whichext);
02403         cpl_error_code cplerr = cpl_error_get_code();
02404         if (cplerr != CPL_ERROR_NONE || (gain == 0.0))
02405         {
02406             cpl_msg_warning(cpl_func, "Cannot read gain from QC parameters - FPN will not be computed");
02407             cpl_error_reset();
02408         }
02409         else
02410         {
02411         irplib_detmon_fpn_compute(set_on, index_on, last_best, lint_qclist,
02412                 detmon_lg_config.llx,
02413                 detmon_lg_config.lly,
02414                 detmon_lg_config.urx,
02415                 detmon_lg_config.ury,
02416                 gain,
02417                 whichext,
02418                 detmon_lg_config.fpn_method,
02419                 detmon_lg_config.fpn_smooth);
02420         }
02421     }
02422     /* change NaN in the gain table to the invalid value D_INVALID_VALUE*/
02423     irplib_detmon_table_fill_invalid(gain_table, D_INVALID_VALUE);
02424     end_skip;
02425 
02426     cpl_imagelist_delete(linearity_inputs);
02427     cpl_imagelist_delete(opt_offs);
02428     cpl_propertylist_delete(reflist);
02429 
02430     return cpl_error_get_code();
02431 }
02432 
02433 static cpl_error_code irplib_detmon_table_fill_invalid(cpl_table* ptable, double code)
02434 {
02435     int ncols = cpl_table_get_ncol(ptable);
02436     cpl_array* pnames = cpl_table_get_column_names(ptable);
02437     int nrows = cpl_table_get_nrow(ptable);
02438     int i = 0;
02439     for (i=0; i < ncols; i++)
02440     {
02441         int j = 0;
02442         for (j = 0; j< nrows; j++)
02443         {
02444             const char* colname = cpl_array_get_data_string_const(pnames)[i];
02445             int isnull;
02446             cpl_type type = cpl_table_get_column_type(ptable, colname);
02447             cpl_table_get(ptable, colname, j, &isnull);
02448             if(isnull == 1)
02449             {
02450                 if (type == CPL_TYPE_DOUBLE)
02451                 {
02452                     cpl_table_set(ptable,colname,j, code);
02453                 }
02454                 else if (type == CPL_TYPE_FLOAT)
02455                 {
02456                     cpl_table_set_float(ptable,colname,j, (float)code);
02457                 }
02458             }
02459         }
02460     }
02461     cpl_array_delete(pnames);
02462     return cpl_error_get_code();
02463 }
02464 
02465 static cpl_error_code
02466 irplib_detmon_fpn_compute(const cpl_frameset *set_on,
02467         int * index_on,
02468         int last_best,
02469         cpl_propertylist *lint_qclist,
02470         int llx,
02471         int lly,
02472         int urx,
02473         int ury,
02474         double gain,
02475         int whichext,
02476         FPN_METHOD fpn_method,
02477         int smooth_size)
02478 {
02479     double fpn = 0;
02480     const cpl_image* im1 = 0;
02481     int range[4];
02482     cpl_imagelist* ons = 0;
02483     cpl_frameset          * pair_on = 0;
02484     int nsets_extracted = cpl_frameset_get_size(set_on);
02485     int * selection = 0;
02486     double mse = 0;
02487     range[0] = llx;
02488     range[1] = lly;
02489     range[2] = urx;
02490     range[3] = ury;
02491 
02492     /* Retrieve 2 ON frames with the highest DIT -
02493      * the last best 2 values in the index*/
02494     selection = cpl_malloc(sizeof(int) * nsets_extracted);
02495     memset(&selection[0], 0, sizeof(int) * nsets_extracted);
02496 
02497     selection[index_on[last_best*2 + 0] ] = 1;
02498     selection[index_on[last_best*2 + 1] ] = 1;
02499      pair_on = cpl_frameset_extract(set_on, selection, 1);
02500      ons = detmon_lg_config.load_fset_wrp(pair_on, CPL_TYPE_FLOAT, whichext);
02501 
02502     skip_if(ons == NULL);
02503     skip_if((im1 = cpl_imagelist_get_const(ons, 0)) == NULL);
02504 
02505     fpn = irplib_fpn_lg(im1, range, gain, fpn_method, smooth_size, &mse);
02506     skip_if(cpl_propertylist_append_double(lint_qclist, DETMON_QC_FPN,
02507                                fpn));
02508     skip_if(cpl_propertylist_append_double(lint_qclist, "ESO QC GAIN ERR",
02509                                mse));
02510 
02511     cleanup:
02512     cpl_frameset_delete(pair_on);
02513     cpl_imagelist_delete(ons);
02514     cpl_free(selection);
02515     return cpl_error_get_code();
02516 }
02517 
02518 /*--------------------------------------------------------------------------*/
02526 /*--------------------------------------------------------------------------*/
02527 static cpl_error_code
02528 irplib_detmon_lg_lamp_stab(const cpl_frameset * lamps,
02529                const cpl_frameset * darks,
02530                            cpl_boolean          opt_nir,
02531                            int                  whichext)
02532 {
02533     /*
02534      * NOTE:
02535      * Most of this code is copied (and modified) from
02536      * isaac_img_detlin_load(), in isaac_img_detlin.c v.1.25
02537      */
02538 
02539     int                     nb_lamps;
02540 
02541     cpl_vector          *   selection = NULL;
02542     cpl_propertylist    *   plist;
02543     double                  dit_lamp, dit_dark;
02544     int                     dit_stab;
02545     cpl_imagelist       *   lamps_data = NULL;
02546     cpl_imagelist       *   darks_data = NULL;
02547     double              *   stab_levels = NULL;
02548     int                     i, j;
02549     double              *   ditvals = NULL;
02550     int                     last_stab = 0; /* Avoid false uninit warning */
02551 
02552     /* Check that there are as many lamp as darks */
02553     cpl_ensure_code((nb_lamps = cpl_frameset_get_size(lamps)) >= 3,
02554             CPL_ERROR_ILLEGAL_INPUT);
02555     cpl_ensure_code(cpl_frameset_get_size(darks) == nb_lamps,
02556                 CPL_ERROR_ILLEGAL_INPUT);
02557 
02558     /* Check out that they have consistent integration times */
02559     cpl_msg_info(__func__, "Checking DIT consistency");
02560     selection = cpl_vector_new(nb_lamps);
02561     ditvals = cpl_malloc(nb_lamps * sizeof(double));
02562     dit_stab = 0;
02563     for (i = 0; i < nb_lamps; i++) {
02564     const cpl_frame           * c_lamp;
02565     const cpl_frame           * c_dark;
02566         /* Check if ok */
02567         skip_if (cpl_error_get_code());
02568 
02569         /* DIT from LAMP */
02570         c_lamp = cpl_frameset_get_frame_const(lamps, i);
02571         plist = cpl_propertylist_load(cpl_frame_get_filename(c_lamp), 0);
02572     if(opt_nir)
02573         dit_lamp = (double)irplib_pfits_get_dit(plist);
02574     else
02575         dit_lamp = (double)irplib_pfits_get_dit_opt(plist);
02576         cpl_propertylist_delete(plist);
02577         skip_if (cpl_error_get_code());
02578 
02579         /* DIT from DARK */
02580         c_dark = cpl_frameset_get_frame_const(darks, i);
02581         plist  = cpl_propertylist_load(cpl_frame_get_filename(c_dark), 0);
02582     if(opt_nir)
02583         dit_dark = (double)irplib_pfits_get_dit(plist);
02584     else
02585         dit_dark = (double)irplib_pfits_get_dit_opt(plist);
02586         cpl_propertylist_delete(plist);
02587         skip_if (cpl_error_get_code());
02588 
02589         /* Check consistency */
02590         if (fabs(dit_dark-dit_lamp) > 1e-3) {
02591             cpl_msg_error(__func__, "DIT not consistent between LAMP and DARK");
02592         /* FIXME: Should an error code be set here? */
02593         skip_if(1);
02594         }
02595         ditvals[i] = dit_lamp;
02596         /* Set selection */
02597         if (i==0) {
02598             cpl_vector_set(selection, i, -1.0);
02599             dit_stab ++;
02600         last_stab = 0;
02601         } else {
02602         /*
02603          * The second condition is to make sure that frames taken into
02604          * account for lamp stability are not consecutive.
02605          */
02606             if (fabs(dit_lamp - ditvals[0]) < 1e-5 && i - last_stab > 3) {
02607                 cpl_vector_set(selection, i, -1.0);
02608                 dit_stab ++;
02609         last_stab = i;
02610             } else {
02611                 cpl_vector_set(selection, i, 1.0);
02612             }
02613         }
02614     }
02615 
02616     /* Check if there are enough DITs for stability check */
02617     if (dit_stab < 2) {
02618         cpl_msg_info(__func__, "Not enough frames for stability check");
02619     } else {
02620 
02621     /* Load the data and compute lamp-dark */
02622     cpl_msg_info(__func__, "Compute the differences lamp - dark");
02623     lamps_data = cpl_imagelist_load_frameset(lamps, CPL_TYPE_FLOAT, 1,
02624                          whichext);
02625     darks_data = cpl_imagelist_load_frameset(darks, CPL_TYPE_FLOAT, 1,
02626                          whichext);
02627     skip_if(cpl_imagelist_subtract(lamps_data,darks_data));
02628 
02629     /* Check the lamp stability */
02630     cpl_msg_info(__func__, "Check the lamp stability");
02631     stab_levels = cpl_malloc(dit_stab * sizeof(double));
02632     j = 0;
02633     for (i=0; i<nb_lamps; i++) {
02634         if (cpl_vector_get(selection, i) < 0) {
02635         stab_levels[j] =
02636             cpl_image_get_mean(cpl_imagelist_get(lamps_data, i));
02637         j++;
02638         }
02639     }
02640 
02641     /* Compute the lamp stability */
02642     for (i=1; i<dit_stab; i++) {
02643         if ((fabs(stab_levels[i]-stab_levels[0]) / stab_levels[0]) >
02644                 detmon_lg_config.lamp_stability)
02645         detmon_lg_config.lamp_stability =
02646             fabs(stab_levels[i]-stab_levels[0]) / stab_levels[0];
02647     }
02648 
02649 
02650     /* Check the lamp stability */
02651     if (detmon_lg_config.lamp_stability > 0.01) {
02652             cpl_msg_warning(__func__,
02653                 "level difference too high - proceed anyway");
02654     }
02655     }
02656     end_skip;
02657 
02658     cpl_free(ditvals);
02659     cpl_vector_delete(selection);
02660     cpl_imagelist_delete(lamps_data);
02661     cpl_imagelist_delete(darks_data);
02662     cpl_free(stab_levels);
02663 
02664     return cpl_error_get_code();
02665 }
02666 
02667 /*--------------------------------------------------------------------------*/
02690 /*--------------------------------------------------------------------------*/
02691 static cpl_error_code
02692 irplib_detmon_lg_reduce_dit(const cpl_frameset * set_on,
02693                 int* index_on, double* exptime_on,
02694                 const int dit_nb,
02695                 int * dit_nskip,
02696                 const cpl_frameset * set_off,
02697                 int * index_off, double* exptime_off,
02698                 int* next_on, int* next_off,
02699                 cpl_table * linear_table,
02700                 cpl_table * gain_table,
02701                 cpl_imagelist * linearity_inputs,
02702                 cpl_propertylist * qclist,
02703                 cpl_boolean opt_nir,
02704                 cpl_imagelist * autocorr_images,
02705                 cpl_imagelist * diff_flats,
02706                 cpl_imagelist * opt_offs,
02707                 int whichext,
02708                 int* rows_affected)
02709 {
02710     cpl_frameset          * pair_on = NULL;
02711     cpl_frameset          * pair_off = NULL;
02712     cpl_imagelist         * ons = NULL;
02713     cpl_imagelist         * offs = NULL;
02714     cpl_boolean             follow = CPL_TRUE;
02715     cpl_imagelist *         masterl = NULL;
02716     unsigned mode = detmon_lg_config.autocorr ? IRPLIB_GAIN_WITH_AUTOCORR : 0;
02717     double c_dit;
02718     int c_ndit;
02719 
02720     double current_dit = 0;
02721 
02722     const char * filename;
02723 
02724     cpl_propertylist * plist = NULL;
02725     cpl_propertylist* pDETlist = NULL;
02726 
02727     mode = detmon_lg_config.collapse ?
02728     mode | IRPLIB_GAIN_COLLAPSE    | IRPLIB_LIN_COLLAPSE:
02729     mode | IRPLIB_GAIN_NO_COLLAPSE | IRPLIB_LIN_NO_COLLAPSE;
02730     mode = detmon_lg_config.pix2pix  ?
02731     mode | IRPLIB_LIN_PIX2PIX : mode;
02732     mode = opt_nir  ?
02733     mode | IRPLIB_GAIN_NIR | IRPLIB_LIN_NIR :
02734     mode | IRPLIB_GAIN_OPT | IRPLIB_LIN_OPT ;
02735 
02736 
02737     /* ON pair extraction */
02738     skip_if(irplib_detmon_pair_extract_next(set_on, index_on, next_on, exptime_on, &pair_on,  detmon_lg_config.tolerance));
02739     current_dit = exptime_on[*next_on - 1];
02740 
02741     /* Load the ON images */
02742     ons = detmon_lg_config.load_fset_wrp(pair_on, CPL_TYPE_FLOAT, whichext);
02743     skip_if(ons == NULL);
02744     cpl_msg_debug(cpl_func, " Loaded ON images: %d, exptime[%f]",cpl_imagelist_get_size(ons), current_dit );
02745     if(cpl_imagelist_get_size(ons) != 2)
02746     {
02747         cpl_msg_error(cpl_func, "cannot take ON pair, number of images[%d]", cpl_imagelist_get_size(ons));
02748         skip_if(TRUE);
02749     }
02750     if(detmon_lg_config.filter > 0)
02751     {
02752         double med1 =
02753             cpl_image_get_median_window(cpl_imagelist_get(ons, 0),
02754                         detmon_lg_config.llx,
02755                         detmon_lg_config.lly,
02756                         detmon_lg_config.urx,
02757                         detmon_lg_config.ury);
02758         double med2 =
02759             cpl_image_get_median_window(cpl_imagelist_get(ons, 1),
02760                         detmon_lg_config.llx,
02761                         detmon_lg_config.lly,
02762                         detmon_lg_config.urx,
02763                         detmon_lg_config.ury);
02764         if ( med1 > (double)detmon_lg_config.filter ||
02765              med2 > (double)detmon_lg_config.filter)
02766             {
02767                 follow = CPL_FALSE;
02768                 cpl_table_select_row(gain_table,   dit_nb);
02769                 cpl_table_select_row(linear_table, dit_nb);
02770                 (*dit_nskip)++;
02771                 cpl_msg_warning(cpl_func, "Frames of EXPTIME nb %d "
02772                         "will not be taken into account for computation "
02773                         "as they are above --filter threshold", dit_nb);
02774             }
02775     }
02776 
02777     if (follow || detmon_lg_config.filter < 0)
02778     {
02779 
02780         /*
02781          * If the --collapse option is not activated by the user, the OFF
02782          * sub-frameset is also supposed to be organized into pairs and,
02783          * therefore, processed as the ON sub-frameset.
02784          */
02785         if(!detmon_lg_config.collapse)
02786         {
02787             if (!strcmp(detmon_lg_config.method, "MED") ||
02788             cpl_frameset_get_size(set_on) == cpl_frameset_get_size(set_off))
02789             {
02790                 skip_if(irplib_detmon_pair_extract_next(set_off, index_off, next_off, exptime_off, &pair_off,  detmon_lg_config.tolerance));
02791             }
02792             else
02793             {
02794                 skip_if(irplib_detmon_single_extract_next(set_off, index_off, next_off, exptime_off, &pair_off));
02795             }
02796             /* Load the OFF images */
02797             cpl_msg_debug(cpl_func, "  Load the OFF images, ext[%d], exptime[%f]", whichext, exptime_off[*next_off - 1]);
02798             offs = detmon_lg_config.load_fset_wrp(pair_off, CPL_TYPE_FLOAT, whichext);
02799 
02800             skip_if(offs == NULL);
02801             skip_if(cpl_error_get_code());
02802         } else
02803         {
02804             /*
02805              * The master bias is required only for
02806              * linearity computation in the OPT domain
02807              */
02808             cpl_image * collapse;
02809             masterl = cpl_imagelist_load_frameset(set_off, CPL_TYPE_FLOAT,
02810                                               1, whichext);
02811             skip_if(masterl == NULL);
02812             skip_if(cpl_error_get_code());
02813 
02814             collapse = cpl_imagelist_collapse_create(masterl);
02815             skip_if(collapse == NULL);
02816             skip_if(cpl_imagelist_set(masterl, collapse, 0));
02817 
02818             /* Any extra error checking needed here? */
02819             offs = (cpl_imagelist *)masterl;
02820         }
02821 
02822         /* Rescaling */
02823         if(detmon_lg_config.rescale)
02824         {
02825             skip_if(irplib_detmon_lg_rescale(ons));
02826             if (!detmon_lg_config.collapse &&
02827             !strcmp(detmon_lg_config.method, "MED"))
02828             skip_if(irplib_detmon_lg_rescale(offs));
02829         }
02830         /* DIT or EXPTIME value extraction */
02831 
02832         filename =
02833             cpl_frame_get_filename(cpl_frameset_get_first_const(pair_on));
02834         skip_if ((plist = cpl_propertylist_load(filename, 0)) == NULL);
02835         /* Add columns to the tables DETi WINi UITi*/
02836         if (plist)
02837         {
02838             pDETlist = cpl_propertylist_new();
02839             cpl_propertylist_copy_property_regexp(pDETlist, plist, "DET[0-9]* WIN[0-9]* UIT[0-9]*",0);
02840             if (dit_nb == 0)
02841             {
02842                 irplib_table_create_column(gain_table, pDETlist);
02843                 irplib_table_create_column(linear_table, pDETlist);
02844             }
02845         }
02846         if(opt_nir == NIR) {
02847             c_dit = irplib_pfits_get_dit(plist);
02848             c_ndit = irplib_pfits_get_ndit(plist);
02849         } else {
02850             c_dit = irplib_pfits_get_exptime(plist);
02851             c_ndit=1;
02852         }
02853 
02854         /*
02855          * --GAIN part for each DIT value--
02856          * The following call to irplib_detmon_gain_table_fill_row() fills
02857          * in the row nb i
02858          * of the GAIN table (output) and of the FIT table (by-product to be
02859          * used later for the polynomial computation of the GAIN)
02860          */
02861         if(detmon_lg_config.collapse) {
02862             offs = (cpl_imagelist *) opt_offs;
02863         }
02864 
02865         cpl_msg_info(cpl_func, "Computing GAIN for EXPTIME value nb %d",
02866                  dit_nb + 1);
02867 
02868         /* In case PTC is applied, this is allowed */
02869         if(cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE && dit_nb == 0)
02870         {
02871             cpl_table_erase_column(gain_table, "MEAN_OFF1");
02872             cpl_table_erase_column(gain_table, "MEAN_OFF2");
02873             cpl_table_erase_column(gain_table, "SIG_OFF_DIF");
02874             cpl_table_erase_column(gain_table, "GAIN");
02875             cpl_table_erase_column(gain_table, "GAIN_CORR");
02876             cpl_table_new_column(gain_table, "MEAN_OFF", CPL_TYPE_DOUBLE);
02877         }
02878 
02879         skip_if(irplib_detmon_gain_table_fill_row(gain_table,
02880                               c_dit,c_ndit,
02881                           autocorr_images,
02882                           diff_flats, ons, offs,
02883                           detmon_lg_config.kappa,
02884                           detmon_lg_config.niter,
02885                           detmon_lg_config.llx,
02886                           detmon_lg_config.lly,
02887                           detmon_lg_config.urx,
02888                           detmon_lg_config.ury,
02889                           detmon_lg_config.m,
02890                           detmon_lg_config.n,
02891                           detmon_lg_config.saturation_limit,
02892                           dit_nb, mode, rows_affected));
02893 
02894 
02895         if (*rows_affected)
02896         {
02897             /* fill DETi WINi OPTi columns - see DFS06921*/
02898             skip_if(irplib_fill_table_DETWINUIT(gain_table, pDETlist, dit_nb));
02899             /* Linearity reduction */
02900             cpl_msg_info(cpl_func, "Linearity reduction for nb %d",
02901                              dit_nb + 1);
02902             skip_if(irplib_detmon_lin_table_fill_row(linear_table, c_dit,
02903                                  linearity_inputs, ons, offs,
02904                                  detmon_lg_config.llx,
02905                                  detmon_lg_config.lly,
02906                                  detmon_lg_config.urx,
02907                                  detmon_lg_config.ury,
02908                                  dit_nb, *dit_nskip, mode));
02909             /* fill DETi WINi OPTi columns - see DFS06921*/
02910             skip_if(irplib_fill_table_DETWINUIT(linear_table, pDETlist, dit_nb));
02911         }
02912 
02913 
02914                 /* as we know only at this point if a frame is
02915                    saturated or not, and we would like to compute the
02916                    contamination only on the last non saturated frame,
02917                    we need de facto to compute saturation on any non saturated
02918                    frame, by overwriting the QC parameter. In the end it will
02919                    remain only the last value corresponding to a non saturated
02920                    frame */
02921 
02922         if(opt_nir == OPT &&
02923                    *rows_affected != 0 ) {
02924                    irplib_detmon_opt_contamination(ons, offs, mode, qclist);
02925         }
02926 
02927     }
02928 
02929     end_skip;
02930 
02931     cpl_frameset_delete(pair_on);
02932     cpl_imagelist_delete(ons);
02933 
02934     if(!detmon_lg_config.collapse ) {
02935     cpl_imagelist_delete(offs);
02936     }
02937 
02938     if(!detmon_lg_config.collapse) {
02939     cpl_frameset_delete(pair_off);
02940     }
02941 
02942     if(detmon_lg_config.collapse) {
02943     cpl_imagelist_delete(masterl);
02944     }
02945 
02946     cpl_propertylist_delete(plist);
02947     cpl_propertylist_delete(pDETlist);
02948     return cpl_error_get_code();
02949 }
02950 
02951 /*---------------------------------------------------------------------------*/
02957 /*---------------------------------------------------------------------------*/
02958 static cpl_error_code
02959 irplib_detmon_add_adl_column(cpl_table * table,
02960                              cpl_boolean opt_nir)
02961 {
02962     cpl_error_code          error;
02963     double                  mean_med_dit;
02964     double                 *dits;
02965 
02966     cpl_ensure_code(table != NULL, CPL_ERROR_NULL_INPUT);
02967 
02968     mean_med_dit = cpl_table_get_column_mean(table, "MED_DIT");
02969     if (opt_nir == OPT)
02970     dits = cpl_table_get_data_double(table, "EXPTIME");
02971     else
02972     dits = cpl_table_get_data_double(table, "DIT");
02973 
02974     error = cpl_table_copy_data_double(table, "ADL", dits);
02975     cpl_ensure_code(!error, error);
02976     error = cpl_table_multiply_scalar(table, "ADL", mean_med_dit);
02977     cpl_ensure_code(!error, error);
02978 
02979     return cpl_error_get_code();
02980 }
02981 
02982 /*---------------------------------------------------------------------------*/
02990 /*---------------------------------------------------------------------------*/
02991 static cpl_error_code
02992 irplib_detmon_lg_reduce_init(cpl_table * gain_table,
02993                              cpl_table * linear_table,
02994                              cpl_imagelist ** linearity_inputs,
02995                              const cpl_boolean opt_nir)
02996 {
02997     skip_if(irplib_detmon_gain_table_create(gain_table, opt_nir));
02998     skip_if(irplib_detmon_lin_table_create(linear_table, opt_nir));
02999 
03000     if(detmon_lg_config.pix2pix) {
03001     *linearity_inputs = cpl_imagelist_new();
03002     skip_if(*linearity_inputs == NULL);
03003     }
03004 
03005     end_skip;
03006 
03007     return cpl_error_get_code();
03008 }
03009 
03010 /*--------------------------------------------------------------------------*/
03016 /*--------------------------------------------------------------------------*/
03017 static double
03018 irplib_pfits_get_dit(const cpl_propertylist * plist)
03019 {
03020     return irplib_pfits_get_prop_double(plist, "ESO DET DIT");
03021 }
03022 
03023 /*--------------------------------------------------------------------------*/
03029 /*--------------------------------------------------------------------------*/
03030 static double
03031 irplib_pfits_get_dit_opt(const cpl_propertylist * plist)
03032 {
03033     return irplib_pfits_get_prop_double(plist, "ESO DET WIN1 UIT1");
03034 }
03035 
03036 
03037 /*---------------------------------------------------------------------------*/
03042 static cpl_propertylist*
03043 irplib_detmon_load_pro_keys(const char* NAME_O)
03044 {
03045    cpl_propertylist* pro_keys=NULL;
03046    pro_keys=cpl_propertylist_load_regexp(NAME_O,0,"^(ESO PRO)",0);
03047    return pro_keys;
03048 }
03049 
03050 
03051 static double irplib_pfits_get_prop_double(const cpl_propertylist * plist, const char* prop_name)
03052 {
03053    double dit;
03054    dit = cpl_propertylist_get_double(plist, prop_name);
03055    if(cpl_error_get_code() != CPL_ERROR_NONE)
03056    {
03057        cpl_msg_error(cpl_func, "Cannot read property '%s', err[%s]",prop_name, cpl_error_get_where());
03058    }
03059    return dit;
03060 }
03061 /*---------------------------------------------------------------------------*/
03093 /*---------------------------------------------------------------------------*/
03094 static cpl_error_code
03095 irplib_detmon_gain_table_fill_row(cpl_table * gain_table,
03096                   double c_dit,int c_ndit,
03097                   cpl_imagelist * autocorr_images,
03098                   cpl_imagelist * diff_flats,
03099                   const cpl_imagelist * ons,
03100                                   const cpl_imagelist * offs,
03101                                   double kappa, int nclip,
03102                                   int llx, int lly, int urx, int ury,
03103                                   int m, int n,
03104                                   double saturation_limit,
03105                   const int pos, unsigned mode, int* rows_affected)
03106 {
03107     const cpl_image        *image;
03108     double                  std = 0;
03109     cpl_image              *on_dif = NULL;
03110     cpl_image              *off_dif = NULL;
03111     double                  avg_on1, avg_on2;
03112     double                  avg_off1, avg_off2;
03113     double                  avg_on_dif, sig_on_dif;
03114     double                  avg_off_dif, sig_off_dif;
03115     double                  double_adu, autocorr, gain, gain_corr;
03116     double                  sigma, sigma_corr;
03117 
03118     cpl_table_set(gain_table, "FLAG", pos, 1);
03119     if (mode & IRPLIB_GAIN_NIR)
03120     {
03121         cpl_table_set(gain_table, "DIT", pos, c_dit);
03122         cpl_table_set(gain_table, "NDIT", pos, c_ndit);
03123     } else if (mode & IRPLIB_GAIN_OPT)
03124     {
03125         cpl_table_set(gain_table, "EXPTIME", pos, c_dit);
03126     } else
03127     {
03128         cpl_msg_error(cpl_func, "Mandatory mode (OPT or NIR) not provided");
03129         skip_if(1);
03130     }
03131     if(*rows_affected == 0)
03132     {
03133         cpl_msg_info(cpl_func, "skip the frame #%d", pos + 1);
03134         cpl_table_set(gain_table, "FLAG", pos, 0);
03135         if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
03136         {
03137           autocorr = -1;
03138           if (diff_flats)
03139           {
03140               irplib_detmon_lg_add_empty_image(diff_flats, pos);
03141           }
03142           if (autocorr_images)
03143           {
03144               irplib_detmon_lg_add_empty_image(autocorr_images, pos);
03145           }
03146         }
03147         return cpl_error_get_code();
03148     }
03149     skip_if((image = cpl_imagelist_get_const(ons, 0)) == NULL);
03150     skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
03151                                          nclip, 1e-5, &avg_on1, &std));
03152     skip_if((image = cpl_imagelist_get_const(ons, 1)) == NULL);
03153     skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
03154                      nclip, 1e-5, &avg_on2, &std));
03155 
03156     if ((avg_on1 > saturation_limit) || (avg_on2 > saturation_limit))
03157     {
03158         cpl_msg_warning(cpl_func, "Average saturation is above the limit, the frames would not be taken into calculation");
03159         cpl_msg_warning(cpl_func, "saturation levels [%f ; %f], limit [%f]", avg_on1, avg_on2, saturation_limit);
03160         cpl_msg_info(cpl_func, "skip the frame #%d", pos + 1);
03161         cpl_table_set(gain_table, "FLAG", pos, 0);
03162         if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
03163         {
03164           autocorr = -1;
03165           if (diff_flats)
03166           {
03167               irplib_detmon_lg_add_empty_image(diff_flats, pos);
03168           }
03169           if (autocorr_images)
03170           {
03171               irplib_detmon_lg_add_empty_image(autocorr_images, pos);
03172           }
03173         }
03174         *rows_affected = 0;
03175     }
03176     else
03177     {
03178         *rows_affected = 1;
03179         skip_if(cpl_table_set_double(gain_table, "MEAN_ON1", pos, avg_on1));
03180         skip_if(cpl_table_set_double(gain_table, "MEAN_ON2", pos, avg_on2));
03181         on_dif =
03182         cpl_image_subtract_create(cpl_imagelist_get_const(ons, 0),
03183                       cpl_imagelist_get_const(ons, 1));
03184         skip_if(on_dif == NULL);
03185         skip_if(irplib_ksigma_clip(on_dif, llx, lly, urx, ury, kappa,
03186                          nclip, 1e-5,
03187                                              &avg_on_dif, &sig_on_dif));
03188         skip_if(cpl_table_set_double(gain_table, "SIG_ON_DIF", pos, sig_on_dif));
03189 
03190         if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
03191         {
03192           if (diff_flats)
03193           {
03194               cpl_image * diff = cpl_image_duplicate(on_dif);
03195               skip_if(cpl_imagelist_set(diff_flats, diff, pos));
03196           }
03197           if (autocorr_images)
03198           {
03199             cpl_image * corr = NULL;
03200             autocorr = irplib_detmon_autocorr_factor(on_dif, &corr, m, n);
03201             if(corr)
03202             {
03203                 skip_if(cpl_imagelist_set(autocorr_images, corr, pos));
03204             }
03205             else
03206             {
03207                 irplib_detmon_lg_add_empty_image(autocorr_images, pos);
03208             }
03209           } else
03210           {
03211             autocorr = irplib_detmon_autocorr_factor(on_dif, NULL, m, n);
03212           }
03213           autocorr = isnan(autocorr) ? 1.0 : autocorr;
03214         } else
03215         {
03216             autocorr = 1.0;
03217         }
03218 
03219         if (cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE)
03220         {
03221 
03222             skip_if(irplib_ksigma_clip(cpl_imagelist_get_const(offs, 0),
03223                        llx, lly, urx, ury, kappa, nclip,
03224                        1e-5, &avg_off1, &std));
03225             skip_if(cpl_table_set_double(gain_table, "MEAN_OFF", pos, avg_off1));
03226 
03227         } else if (mode & IRPLIB_GAIN_NO_COLLAPSE ||
03228              ( pos == 0 && mode & IRPLIB_GAIN_COLLAPSE )) {
03229             skip_if(irplib_ksigma_clip(cpl_imagelist_get_const(offs, 0),
03230                                                  llx, lly, urx, ury, kappa, nclip,
03231                                                  1e-5, &avg_off1, &std));
03232             skip_if(cpl_table_set_double(gain_table, "MEAN_OFF1", pos, avg_off1));
03233             skip_if(irplib_ksigma_clip(cpl_imagelist_get_const(offs, 1),
03234                                                  llx, lly, urx, ury, kappa, nclip,
03235                              1e-5, &avg_off2, &std));
03236             skip_if(cpl_table_set_double(gain_table, "MEAN_OFF2", pos, avg_off2));
03237             off_dif =
03238                 cpl_image_subtract_create(cpl_imagelist_get_const(offs, 0),
03239                                           cpl_imagelist_get_const(offs, 1));
03240             skip_if(off_dif == NULL);
03241             skip_if(irplib_ksigma_clip(off_dif, llx, lly, urx, ury,
03242                                                  kappa, nclip, 1e-5,
03243                              &avg_off_dif, &sig_off_dif));
03244             skip_if(cpl_table_set_double(gain_table, "SIG_OFF_DIF",
03245                          pos, sig_off_dif));
03246         } else if (pos > 0 && mode & IRPLIB_GAIN_COLLAPSE)
03247         {
03248             int status;
03249             avg_off1 = cpl_table_get_double(gain_table, "MEAN_OFF1", 0, &status);
03250             skip_if(cpl_table_set_double(gain_table, "MEAN_OFF1", pos, avg_off1));
03251             avg_off2 = cpl_table_get_double(gain_table, "MEAN_OFF2", 0, &status);
03252             skip_if(cpl_table_set_double(gain_table, "MEAN_OFF2", pos, avg_off2));
03253             sig_off_dif = cpl_table_get_double(gain_table, "SIG_OFF_DIF",
03254                                                0, &status);
03255             skip_if(cpl_table_set_double(gain_table, "SIG_OFF_DIF",
03256                                          pos, sig_off_dif));
03257         }
03258 
03259         if (cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE)
03260         {
03261             double_adu = (avg_on1 + avg_on2) - 2 * avg_off1;
03262         }
03263         else
03264         {
03265             double_adu = (avg_on1 + avg_on2) - (avg_off1 + avg_off2);
03266 
03267             sigma = (sig_on_dif * sig_on_dif) - (sig_off_dif * sig_off_dif);
03268 
03269             sigma_corr = autocorr * sigma;
03270 
03271             gain = double_adu / (c_ndit * sigma);
03272 
03273             gain_corr = double_adu / (c_dit*sigma_corr);
03274 
03275             skip_if(cpl_table_set_double(gain_table, "GAIN", pos, gain));
03276             skip_if(cpl_table_set_double(gain_table, "GAIN_CORR", pos, gain_corr));
03277         }
03278 
03279         skip_if(cpl_table_set_double(gain_table, "AUTOCORR", pos, autocorr));
03280         skip_if(cpl_table_set_double(gain_table, "ADU", pos, double_adu / 2));
03281 
03282         /* FIXME: Remove the following 3 columns after testing period */
03283         skip_if(cpl_table_set_double(gain_table, "Y_FIT",
03284                          pos,
03285                          c_ndit* sig_on_dif * sig_on_dif));
03286         skip_if(cpl_table_set_double(gain_table, "Y_FIT_CORR",
03287                          pos,
03288                          c_ndit * sig_on_dif * sig_on_dif));
03289         skip_if(cpl_table_set_double(gain_table, "X_FIT", pos, double_adu));
03290         skip_if(cpl_table_set_double(gain_table, "X_FIT_CORR",
03291                      pos, double_adu / autocorr));
03292     }
03293     end_skip;
03294 
03295     cpl_image_delete(on_dif);
03296     cpl_image_delete(off_dif);
03297 
03298     return cpl_error_get_code();
03299 }
03300 
03301 /*--------------------------------------------------------------------------*/
03308 /*--------------------------------------------------------------------------*/
03309 
03310 static cpl_image       *
03311 irplib_detmon_bpixs(const cpl_imagelist * coeffs,
03312                     cpl_boolean bpmbin,
03313                     const double kappa,
03314                     int *nbpixs)
03315 {
03316     int                     size;
03317     int                     i;
03318     const cpl_image        *first= cpl_imagelist_get_const(coeffs, 0);
03319     cpl_stats              *stats;
03320     double                  cur_mean;
03321     double                  cur_stdev;
03322     double                  lo_cut;
03323     double                  hi_cut;
03324     cpl_mask               *cur_mask;
03325     cpl_mask               *mask = cpl_mask_new(cpl_image_get_size_x(first),
03326                                             cpl_image_get_size_y(first));
03327     cpl_image              *cur_image = NULL;
03328     cpl_image              *bpm = NULL; /* Avoid false uninit warning */
03329     double                  p;
03330 
03331     size = cpl_imagelist_get_size(coeffs);
03332 
03333     if(!bpmbin) {
03334     bpm = cpl_image_new(cpl_image_get_size_x(first),
03335                 cpl_image_get_size_y(first),
03336                 CPL_TYPE_INT);
03337     }
03338 
03339 
03340     for(i = 0; i < size; i++) {
03341         const cpl_image * cur_coeff = cpl_imagelist_get_const(coeffs, i);
03342 
03343         stats = cpl_stats_new_from_image(cur_coeff,
03344                                          CPL_STATS_MEAN | CPL_STATS_STDEV);
03345         cur_mean = cpl_stats_get_mean(stats);
03346         cur_stdev = cpl_stats_get_stdev(stats);
03347 
03348         lo_cut = cur_mean - kappa * cur_stdev;
03349         hi_cut = cur_mean + kappa * cur_stdev;
03350 
03351         cur_mask = cpl_mask_threshold_image_create(cur_coeff, lo_cut, hi_cut);
03352         cpl_mask_not(cur_mask);
03353 
03354     if(!bpmbin) {
03355         cur_image = cpl_image_new_from_mask(cur_mask);
03356         p = pow(2, i);
03357         cpl_image_power(cur_image, p);
03358         cpl_image_add(bpm, cur_image);
03359         cpl_image_delete(cur_image);
03360     }
03361 
03362     cpl_mask_or(mask, cur_mask);
03363 
03364         cpl_mask_delete(cur_mask);
03365         cpl_stats_delete(stats);
03366     }
03367 
03368     if(bpmbin) {
03369     bpm = cpl_image_new_from_mask(mask);
03370     }
03371 
03372     *nbpixs += cpl_mask_count(mask);
03373 
03374     cpl_mask_delete(mask);
03375 
03376     return bpm;
03377 }
03378 
03379 /*---------------------------------------------------------------------------*/
03391 /*---------------------------------------------------------------------------*/
03392 
03393 static double
03394 irplib_detmon_autocorr_factor(const cpl_image * image,
03395                               cpl_image ** autocorr_image, int m, int n)
03396 {
03397     cpl_image * mycorr_image = NULL;
03398     double      autocorr = 0;
03399     cpl_error_code err = CPL_ERROR_NONE;
03400 
03401     mycorr_image = irplib_detmon_image_correlate(image, image, m, n);
03402     err=cpl_error_get_code();
03403     if (err == CPL_ERROR_UNSUPPORTED_MODE)
03404     {
03405         cpl_msg_warning(cpl_func, "FFTW is not supported by CPL, autocorrelation "
03406                 "would be computed using internal implementation");
03407         cpl_error_reset();
03408         if (mycorr_image)
03409             cpl_image_delete(mycorr_image);
03410         mycorr_image = irplib_detmon_autocorrelate(image, m, n);
03411     }
03412     if(mycorr_image == NULL) {
03413         return -1;
03414     }
03415 
03416     cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), -1);
03417 
03418     autocorr = cpl_image_get_flux(mycorr_image);
03419 
03420     if (autocorr_image) *autocorr_image = mycorr_image;
03421     else cpl_image_delete(mycorr_image);
03422 
03423     return autocorr;
03424 }
03425 
03426 static cpl_propertylist*
03427 detmon_lg_extract_qclist_4plane(cpl_propertylist* linc_qclist,const int ip)
03428 {
03429 
03430    cpl_propertylist* sub_set=NULL;
03431    char qc_key[40];
03432 
03433    sub_set=cpl_propertylist_new();
03434    sprintf(qc_key,"QC LIN COEF%d",ip);
03435    cpl_propertylist_copy_property_regexp(sub_set,linc_qclist,qc_key,0);
03436 
03437    return sub_set;
03438 
03439 }
03440 
03441 
03451 static cpl_error_code
03452 irplib_detmon_lg_extract_extention_header(cpl_frameset* frameset,
03453                                           cpl_propertylist* gaint_qclist,
03454                                           cpl_propertylist* lint_qclist,
03455                                           cpl_propertylist* linc_qclist, 
03456                                           cpl_propertylist* bpm_qclist,
03457                                           int whichext)
03458 {
03459 
03460    cpl_propertylist *      xplist = NULL;
03461 
03462    const char * filename =
03463       cpl_frame_get_filename(cpl_frameset_get_first(frameset));
03464 
03465    xplist = cpl_propertylist_load_regexp(filename, whichext,
03466                                          "ESO DET|EXTNAME", 0);
03467    if (detmon_lg_config.exts >= 0) 
03468    {
03469       /* for one extension, copy only extname keyword (if any) - DFS09856 */
03470       cpl_property* propExtname = NULL;            
03471       propExtname = cpl_propertylist_get_property(xplist, "EXTNAME");
03472       cpl_error_reset();
03473       if (NULL != propExtname)
03474       {            
03475          propExtname = cpl_property_duplicate(propExtname);
03476       }
03477       cpl_propertylist_delete(xplist);
03478       xplist = NULL;                        
03479       if (NULL != propExtname)
03480       {
03481          xplist = cpl_propertylist_new();
03482          cpl_propertylist_append_property(xplist, propExtname);
03483          cpl_property_delete(propExtname);
03484       }
03485    }
03486    if (NULL != xplist)
03487    {
03488       cpl_propertylist_append(gaint_qclist, xplist);
03489       cpl_propertylist_append(lint_qclist,  xplist);
03490       cpl_propertylist_append(linc_qclist,  xplist);
03491       cpl_propertylist_append(bpm_qclist,   xplist);
03492       cpl_propertylist_delete(xplist);
03493    }
03494 
03495    return cpl_error_get_code();
03496 }
03497 
03498 
03499 
03500 
03501 
03502 /*---------------------------------------------------------------------------*/
03511 /*---------------------------------------------------------------------------*/
03512 static cpl_error_code
03513 irplib_detmon_lg_save_table_with_pro_keys(cpl_table* table,
03514                       const char* name_o,
03515                       cpl_propertylist* xheader,
03516                                           unsigned CPL_IO_MODE)
03517 {
03518 
03519    cpl_propertylist* pro_keys=NULL;
03520    cpl_propertylist* pri_head=NULL;
03521 
03522    pro_keys=irplib_detmon_load_pro_keys(name_o);
03523    cpl_propertylist_append(xheader,pro_keys);
03524 
03525    if(CPL_IO_MODE==CPL_IO_DEFAULT) {
03526       pri_head=cpl_propertylist_load(name_o,0);
03527       cpl_table_save(table, pri_head,xheader,name_o,
03528                      CPL_IO_DEFAULT);
03529       cpl_propertylist_delete(pri_head);
03530 
03531    } else {
03532       cpl_table_save(table,NULL,xheader,name_o,
03533                      CPL_IO_EXTEND);
03534    }
03535    cpl_propertylist_delete(pro_keys);
03536 
03537    return cpl_error_get_code();
03538 }
03539 
03540 /*---------------------------------------------------------------------------*/
03548 /*---------------------------------------------------------------------------*/
03549 static cpl_error_code
03550 irplib_detmon_lg_save_image_with_pro_keys(cpl_image* image,
03551                       const char* name_o,
03552                       cpl_propertylist* xheader)
03553 {
03554 
03555   cpl_propertylist* pro_keys=NULL;
03556   pro_keys=irplib_detmon_load_pro_keys(name_o);
03557   cpl_propertylist_append(xheader,pro_keys);
03558 
03559   cpl_image_save(image,name_o, CPL_BPP_IEEE_FLOAT, 
03560          xheader,CPL_IO_EXTEND);      
03561   cpl_propertylist_delete(pro_keys);
03562       
03563 
03564   return cpl_error_get_code();
03565 }
03566 
03567 /*---------------------------------------------------------------------------*/
03575 /*---------------------------------------------------------------------------*/
03576 static cpl_error_code
03577 irplib_detmon_lg_save_imagelist_with_pro_keys(cpl_imagelist* imagelist,
03578                       const char* name_o,
03579                       cpl_propertylist* xheader)
03580 {
03581 
03582   cpl_propertylist* pro_keys=NULL;
03583   pro_keys=irplib_detmon_load_pro_keys(name_o);
03584   cpl_propertylist_append(xheader,pro_keys);
03585 
03586   cpl_imagelist_save(imagelist,name_o, CPL_BPP_IEEE_FLOAT, 
03587                      xheader,CPL_IO_EXTEND);      
03588 
03589   cpl_propertylist_delete(pro_keys);
03590       
03591 
03592   return cpl_error_get_code();
03593 }
03594 
03595 /*---------------------------------------------------------------------------*/
03612 static cpl_error_code
03613 irplib_detmon_lg_save_plane(const cpl_parameterlist * parlist,
03614                             cpl_frameset* frameset, 
03615                             const cpl_frameset * usedframes,      
03616                             int whichext,
03617                             const char* recipe_name,
03618                             cpl_propertylist* mypro_coeffscube,
03619                             cpl_propertylist* linc_plane_qclist,
03620                             const char* package,
03621                             const char* NAME_O,
03622                             cpl_image* plane)
03623 {
03624    cpl_propertylist* plist=NULL;
03625    cpl_propertylist* pro_keys=NULL;
03626 
03627    if(detmon_lg_config.exts == 0) {
03628       cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
03629                          NULL, NULL,
03630                          CPL_BPP_IEEE_FLOAT, recipe_name,
03631                          mypro_coeffscube, NULL,
03632                          package, NAME_O);
03633       plist=cpl_propertylist_load(NAME_O,0);
03634      cpl_image_save(plane,NAME_O, CPL_BPP_IEEE_FLOAT, 
03635                     plist,CPL_IO_DEFAULT);      
03636      cpl_propertylist_delete(plist);
03637 
03638    } else if(detmon_lg_config.exts > 0) {
03639      cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
03640                          NULL, NULL,
03641                          CPL_BPP_IEEE_FLOAT, recipe_name,
03642                          mypro_coeffscube, NULL,
03643                          package, NAME_O);
03644 
03645      irplib_detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
03646    } else {
03647       if(whichext == 1) 
03648       {
03649          cpl_dfs_save_image(frameset, NULL, parlist, 
03650                             usedframes,NULL, NULL,
03651                             CPL_BPP_IEEE_FLOAT, recipe_name,
03652                             mypro_coeffscube, NULL,
03653                             package, NAME_O);
03654     irplib_detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
03655       } else {
03656 
03657     irplib_detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
03658 
03659       }
03660 
03661    }
03662   
03663    return cpl_error_get_code();
03664 }
03665 
03666 
03667 
03668 /*---------------------------------------------------------------------------*/
03686 static cpl_error_code
03687 irplib_detmon_lg_save_cube(const cpl_parameterlist * parlist,
03688                            cpl_frameset* frameset, 
03689                            const cpl_frameset * usedframes,      
03690                            int whichext,
03691                            const char* recipe_name,
03692                            cpl_propertylist* mypro_coeffscube,
03693                            cpl_propertylist* linc_qclist,
03694                            const char* package,
03695                            const char* NAME_O,
03696                            cpl_imagelist* coeffs)
03697 {
03698    cpl_propertylist* pro_keys=NULL;
03699    if(detmon_lg_config.exts == 0) {  
03700       cpl_propertylist_append(mypro_coeffscube, linc_qclist);
03701       irplib_detmon_lg_dfs_save_imagelist
03702          (frameset,  parlist, usedframes, coeffs,
03703           recipe_name, mypro_coeffscube, package,
03704           NAME_O);   
03705    } else if(detmon_lg_config.exts > 0)  {
03706       cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
03707                          NULL, NULL,
03708                          CPL_BPP_IEEE_FLOAT, recipe_name,
03709                          mypro_coeffscube, NULL,
03710                          package, NAME_O);
03711 
03712       irplib_detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
03713 
03714    } else {
03715       if(whichext == 1) {
03716          cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
03717                             NULL, NULL,
03718                             CPL_BPP_IEEE_FLOAT, recipe_name,
03719                             mypro_coeffscube, NULL,
03720                             package, NAME_O);
03721     irplib_detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
03722       } else {
03723     irplib_detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
03724       }
03725    }
03726    
03727    return cpl_error_get_code();
03728 }
03729 
03730 static char*
03731 irplib_detmon_lg_set_paf_name_and_header(cpl_frame* ref_frame,
03732                                          int flag_sets,int which_set,
03733                                          int whichext,
03734                                          const char* paf_suf,
03735                                          cpl_propertylist** plist)
03736 {
03737    char * paf_name=NULL;
03738 
03739    if(detmon_lg_config.exts >= 0) 
03740    {
03741       *plist =cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
03742                                     detmon_lg_config.exts);
03743 
03744       if(!flag_sets) 
03745       {
03746          paf_name=cpl_sprintf("%s_%s.paf", detmon_lg_config.pafname,paf_suf);
03747       } 
03748       else 
03749       {
03750          paf_name=cpl_sprintf("%s_%s_set%02d.paf",
03751                               detmon_lg_config.pafname, paf_suf,which_set);
03752       }
03753    } 
03754    else 
03755    {
03756       *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
03757                                      whichext);
03758 
03759 
03760       if(!flag_sets) 
03761       {
03762          paf_name=cpl_sprintf("%s_%s_ext%02d.paf",
03763                               detmon_lg_config.pafname, paf_suf,whichext);
03764       } 
03765       else 
03766       {
03767          paf_name=cpl_sprintf("%s_%s_set%02d_ext%02d.paf",
03768                               detmon_lg_config.pafname,paf_suf,
03769                               which_set, whichext);
03770       }
03771    }
03772 
03773    return paf_name;
03774 }
03775 
03776 
03777 static char*
03778 irplib_detmon_lg_set_paf_name_and_header_ext(cpl_frame* ref_frame,
03779                                          int flag_sets,int which_set,
03780                                          int whichext,
03781                                          const char* paf_suf,
03782                                          cpl_propertylist** plist)
03783 {
03784    char* paf_name=NULL;
03785 
03786    if(detmon_lg_config.exts >= 0) 
03787    {
03788       *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
03789                                      detmon_lg_config.exts);
03790 
03791       if(!flag_sets) 
03792       {
03793          paf_name=cpl_sprintf("%s_%s.paf", detmon_lg_config.pafname,paf_suf);
03794       } else 
03795       {
03796          paf_name=cpl_sprintf("%s_%s_set%02d.paf",
03797                               detmon_lg_config.pafname, paf_suf,which_set);
03798       }
03799    } else 
03800    {
03801       *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
03802                                      whichext);
03803       if(!flag_sets) 
03804       {
03805          paf_name=cpl_sprintf("%s_%s_ext%02d.paf",
03806                               detmon_lg_config.pafname, paf_suf,whichext);
03807       } else 
03808       {
03809          paf_name=cpl_sprintf("%s_%s_set%02d_ext%02d.paf",
03810                               detmon_lg_config.pafname,paf_suf,
03811                               which_set, whichext);
03812       }
03813    }
03814   return paf_name;
03815 
03816 }
03817 
03818 static cpl_error_code    
03819 irplib_detmon_lg_save_paf_product(cpl_frame* ref_frame,int flag_sets,
03820                                  int which_set,int whichext,
03821                                  const char* pafregexp,
03822                                  const char* procatg,
03823                                  const char* pipeline_name,
03824                                  const char* recipe_name,
03825                                   const char* paf_suf,
03826                                   cpl_propertylist* qclist,
03827                                   const int ext)
03828 
03829 {
03830 
03831    /* Set the file name for the linearity table PAF */
03832    char* paf_name=NULL;
03833    char NAME_O[128];
03834    cpl_propertylist* plist=NULL;
03835    cpl_propertylist* paflist = NULL;
03836    cpl_propertylist* mainplist=NULL;
03837 
03838    mainplist =cpl_propertylist_load(cpl_frame_get_filename(ref_frame),0);
03839    if(ext==0) {
03840       paf_name=irplib_detmon_lg_set_paf_name_and_header(ref_frame,flag_sets,
03841                                                         which_set,whichext,
03842                                                         paf_suf,&plist);
03843    } else {
03844       paf_name=irplib_detmon_lg_set_paf_name_and_header_ext(ref_frame,flag_sets,
03845                                                             which_set,whichext,
03846                                                             paf_suf,&plist);
03847    }
03848    sprintf(NAME_O,paf_name);
03849 
03850    paflist = cpl_propertylist_new();
03851    cpl_propertylist_append_string(paflist, CPL_DFS_PRO_CATG,procatg);
03852 
03853    /* Get the keywords for the paf file */
03854    cpl_propertylist_copy_property_regexp(paflist, plist,pafregexp, 0);
03855    cpl_propertylist_copy_property_regexp(paflist, mainplist,pafregexp, 0);
03856    cpl_propertylist_append(paflist,qclist);
03857 
03858    /* Save the PAF */
03859    cpl_dfs_save_paf(pipeline_name, recipe_name,paflist, NAME_O);
03860 
03861    /* free memory */
03862    cpl_propertylist_delete(mainplist);
03863    cpl_propertylist_delete(paflist);
03864    cpl_propertylist_delete(plist);
03865    cpl_free(paf_name);
03866 
03867    return cpl_error_get_code();
03868 
03869 }
03870 
03871 
03872 
03873 /*---------------------------------------------------------------------------*/
03904 static cpl_error_code
03905 irplib_detmon_lg_save(const cpl_parameterlist * parlist,
03906                       cpl_frameset * frameset,
03907                       const char *recipe_name,
03908                       const char *pipeline_name,
03909                       const char *pafregexp,
03910               const cpl_propertylist  * pro_lintbl,
03911               const cpl_propertylist  * pro_gaintbl,
03912               const cpl_propertylist  * pro_coeffscube,
03913               const cpl_propertylist  * pro_bpm,
03914               const cpl_propertylist  * pro_corr,
03915               const cpl_propertylist  * pro_diff,
03916                       const char *package,
03917                       cpl_imagelist * coeffs,
03918                       cpl_table * gain_table,
03919                       cpl_table * linear_table,
03920                       cpl_image * bpms,
03921                       cpl_imagelist * autocorr_images,
03922                       cpl_imagelist * diff_flats,
03923                       cpl_propertylist * gaint_qclist,
03924                       cpl_propertylist * lint_qclist,
03925                       cpl_propertylist * linc_qclist,
03926                       cpl_propertylist * bpm_qclist,
03927                       const int flag_sets,
03928                       const int which_set,
03929                       const cpl_frameset * usedframes,
03930                       int whichext)
03931 {
03932 
03933     cpl_frame              *ref_frame;
03934     cpl_propertylist       *plist = NULL;
03935     cpl_propertylist       *mainplist = NULL;
03936     const int NAME_O_BUF_SIZE = 4096;
03937     char                   NAME_O[NAME_O_BUF_SIZE];
03938     char                   PREF_O[NAME_O_BUF_SIZE];
03939     int                     nb_images;
03940     int                     i;
03941 
03942     cpl_propertylist *      xplist = NULL;
03943 
03944     cpl_propertylist* linc_plane_qclist=NULL;
03945     cpl_image* plane=NULL;
03946     int ip=0;
03947     char pcatg_plane[40];
03948 
03949     cpl_propertylist  * mypro_lintbl     =
03950     cpl_propertylist_duplicate(pro_lintbl);
03951     cpl_propertylist  * mypro_gaintbl    =
03952     cpl_propertylist_duplicate(pro_gaintbl);
03953     cpl_propertylist  * mypro_coeffscube =
03954     cpl_propertylist_duplicate(pro_coeffscube);
03955     cpl_propertylist  * mypro_bpm        =
03956     cpl_propertylist_duplicate(pro_bpm);
03957     cpl_propertylist  * mypro_corr       =
03958     cpl_propertylist_duplicate(pro_corr);
03959     cpl_propertylist  * mypro_diff       =
03960     cpl_propertylist_duplicate(pro_diff);
03961 
03962     const char * procatg_lintbl =
03963     cpl_propertylist_get_string(mypro_lintbl, CPL_DFS_PRO_CATG);
03964 
03965     const char * procatg_gaintbl =
03966     cpl_propertylist_get_string(mypro_gaintbl, CPL_DFS_PRO_CATG);
03967 
03968     const char * procatg_coeffscube =
03969     cpl_propertylist_get_string(mypro_coeffscube, CPL_DFS_PRO_CATG);
03970     const char * procatg_bpm =
03971     cpl_propertylist_get_string(mypro_bpm, CPL_DFS_PRO_CATG);
03972     cpl_propertylist* pro_keys=NULL;
03973     cpl_propertylist* pri_head=NULL;
03974 
03975 
03976     /* Extract extension headers if multi-extension */
03977     irplib_detmon_lg_extract_extention_header(frameset,gaint_qclist,lint_qclist,
03978                                               linc_qclist,bpm_qclist,whichext);
03979 
03980     /* This is only used later for PAF and temporarily for COEFFS_CUBE
03981        (see if defined)*/
03982     /* Get FITS header from reference file */
03983     ref_frame = cpl_frameset_get_first(frameset);
03984 
03985     skip_if((mainplist =
03986     cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
03987                   0)) == NULL);
03988 
03989     /*******************************/
03990     /*  Write the LINEARITY TABLE  */
03991     /*******************************/
03992    
03993     /* Set the file name for the table */
03994     if(!flag_sets) {
03995         sprintf(NAME_O,"%s_linearity_table.fits", recipe_name);
03996     } else {
03997        sprintf(NAME_O,"%s_linearity_table_set%02d.fits", recipe_name,
03998                            which_set);
03999     }
04000 
04001     if (detmon_lg_config.exts >= 0) {
04002        /* Save the table */
04003        cpl_propertylist_append(mypro_lintbl, lint_qclist);
04004        skip_if(cpl_dfs_save_table(frameset, NULL,parlist, usedframes, NULL,
04005                                   linear_table,NULL, recipe_name,
04006                                   mypro_lintbl, NULL, package, NAME_O));
04007     
04008        irplib_detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
04009                                                  lint_qclist,CPL_IO_DEFAULT);
04010 
04011     } else {
04012        if(whichext == 1) {
04013           /* Save the 1. extension table */
04014           skip_if(cpl_dfs_save_table(frameset,NULL, parlist, usedframes, NULL, 
04015                                      linear_table,lint_qclist, recipe_name, 
04016                                      mypro_lintbl,NULL, package, NAME_O));
04017           irplib_detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
04018                                                     lint_qclist,CPL_IO_DEFAULT);
04019 
04020 
04021 
04022 
04023        } else {
04024 
04025           irplib_detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
04026                                                     lint_qclist,CPL_IO_EXTEND);
04027        }
04028     }
04029     /**************************/
04030     /*  Write the GAIN TABLE  */
04031     /**************************/
04032 
04033     /* Set the file name for the table */
04034     if(!flag_sets) {
04035         sprintf(NAME_O,"%s_gain_table.fits", recipe_name);
04036     } else {
04037         sprintf(NAME_O,"%s_gain_table_set%02d.fits", recipe_name,
04038                            which_set);
04039     }
04040 
04041     if (detmon_lg_config.exts >= 0) 
04042     {
04043        /* Save the table */
04044 
04045        cpl_propertylist_append(mypro_gaintbl, gaint_qclist);
04046        skip_if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL,
04047                                   gain_table,NULL, recipe_name, mypro_gaintbl,
04048                                   NULL, package, NAME_O));
04049        irplib_detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
04050                                                  gaint_qclist,CPL_IO_DEFAULT);
04051 
04052     } 
04053     else 
04054     {
04055        if(whichext == 1) 
04056        {
04057           /* Save the 1. extension table */
04058           skip_if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL, gain_table,
04059                                      gaint_qclist, recipe_name, mypro_gaintbl,
04060                                      NULL, package, NAME_O));
04061           irplib_detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
04062                                                     gaint_qclist,CPL_IO_DEFAULT);
04063 
04064        } 
04065        else 
04066        {
04067 
04068           irplib_detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
04069                                                     gaint_qclist,CPL_IO_EXTEND);
04070        }
04071     }
04072 
04073     if(detmon_lg_config.pix2pix) 
04074     {
04075 
04076       /***************************/
04077       /*  Write the COEFFS FITS  */
04078       /***************************/
04079    
04080       if(!flag_sets) 
04081       {
04082         sprintf(PREF_O,"%s_coeffs_cube", recipe_name);
04083       } else 
04084       {
04085          sprintf(PREF_O,"%s_coeffs_cube_set%02d",
04086                recipe_name, which_set);
04087       }
04088       if (detmon_lg_config.split_coeffs == 0) {
04089          sprintf(NAME_O,"%s.fits", PREF_O);
04090       }
04091 
04092 
04093       /* Save the imagelist */
04094       if(detmon_lg_config.split_coeffs != 0){ 
04095 
04096 
04097          nb_images = cpl_imagelist_get_size(coeffs);
04098          for(ip=0;ip<nb_images;ip++) {
04099 
04100             sprintf(NAME_O,"%s_P%d.fits", PREF_O,ip);
04101             sprintf(pcatg_plane,"COEFFS_CUBE_P%d",ip);
04102             cpl_propertylist_delete(mypro_coeffscube);
04103             mypro_coeffscube=cpl_propertylist_duplicate(pro_coeffscube);
04104             cpl_propertylist_set_string(mypro_coeffscube,CPL_DFS_PRO_CATG,
04105                                         pcatg_plane);
04106             linc_plane_qclist=detmon_lg_extract_qclist_4plane(linc_qclist,ip);
04107             cpl_propertylist_append(mypro_coeffscube, linc_plane_qclist);
04108             plane=cpl_imagelist_get(coeffs,ip);
04109             irplib_detmon_lg_save_plane(parlist,frameset,usedframes,whichext,
04110                                         recipe_name,mypro_coeffscube,
04111                                         linc_plane_qclist,package,NAME_O,plane);
04112           
04113             if(NULL!=linc_plane_qclist) {
04114                cpl_propertylist_delete(linc_plane_qclist);
04115             }
04116 
04117          } /* end for loop over cube planes */
04118       } else {
04119 
04120          irplib_detmon_lg_save_cube(parlist,frameset,usedframes,whichext,
04121                                     recipe_name,mypro_coeffscube,
04122                                     linc_qclist,package,NAME_O,coeffs);
04123       }
04124 
04125       /*******************************/
04126       /*  Write the BAD PIXEL MAP    */
04127       /*******************************/
04128    
04129       /* Set the file name for the bpm */
04130       if(!flag_sets) 
04131       {
04132          sprintf(NAME_O,"%s_bpm.fits", recipe_name);
04133       } else 
04134       {
04135          sprintf(NAME_O,"%s_bpm_set%02d.fits", recipe_name, which_set);
04136       }
04137    
04138 
04139       /* Save the image */
04140       if(detmon_lg_config.exts == 0) 
04141       {
04142          cpl_propertylist_append(mypro_bpm, bpm_qclist);
04143          skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL, bpms,
04144                                  CPL_BPP_IEEE_FLOAT, recipe_name,
04145                                  mypro_bpm, NULL, package,
04146                                  NAME_O));
04147       }
04148       else if(detmon_lg_config.exts > 0) 
04149       { 
04150          skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,NULL,  NULL,
04151                                     CPL_BPP_IEEE_FLOAT, recipe_name,
04152                                     mypro_bpm, NULL, package,
04153                                     NAME_O));
04154          irplib_detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
04155 
04156       } else 
04157       {
04158          if (whichext == 1) 
04159          {
04160             skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,NULL,  NULL,
04161                      CPL_BPP_IEEE_FLOAT, recipe_name,
04162                      mypro_bpm, NULL, package,
04163                      NAME_O));
04164             irplib_detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
04165          } else 
04166          {
04167             irplib_detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
04168          }
04169       }
04170     } /* End of if(pix2pix) */
04171 
04172     if(detmon_lg_config.intermediate) 
04173     {
04174         /******************************/
04175         /*  Write the AUTOCORRS FITS  */
04176         /******************************/
04177       nb_images = cpl_imagelist_get_size(autocorr_images);
04178       cpl_ensure_code(nb_images > 0, CPL_ERROR_DATA_NOT_FOUND);
04179       for(i = 0; i < nb_images; i++)
04180       {
04181          cpl_propertylist* pplist = cpl_propertylist_duplicate(mypro_corr);
04182          int inull = 0;
04183          cpl_array* pnames = cpl_table_get_column_names(linear_table);
04184          double ddit = 0;
04185          if(i < cpl_table_get_nrow(linear_table))
04186          {
04187             ddit = cpl_table_get_double(linear_table,
04188             cpl_array_get_data_string_const(pnames)[0], i, &inull);
04189          }
04190          cpl_array_delete(pnames);
04191          /*cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);*/
04192             /* Set the file name for each image */
04193             if(!flag_sets)
04194             {
04195                 sprintf(NAME_O,"%s_autocorr_%d.fits", recipe_name, i);
04196                 assert(NAME_O != NULL);
04197             } else
04198             {
04199                 sprintf(NAME_O,"%s_autocorr_%02d_set%02d.fits",
04200                                    recipe_name, i, which_set);
04201                 assert(NAME_O != NULL);
04202             }
04203             /* Save the image */
04204             if(detmon_lg_config.exts > 0)
04205             {
04206                cpl_propertylist* pextlist = cpl_propertylist_new();
04207                cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
04208                skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL,NULL,
04209                         CPL_BPP_IEEE_FLOAT, recipe_name,
04210                         pplist, NULL,
04211                         package, NAME_O));
04212                         skip_if(cpl_image_save(cpl_imagelist_get(autocorr_images, i),
04213                                        NAME_O, CPL_BPP_IEEE_FLOAT, pextlist,
04214                                        CPL_IO_EXTEND));
04215                 cpl_propertylist_delete(pextlist);
04216             } else
04217             if(detmon_lg_config.exts == 0)
04218             {
04219                 cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);            
04220                 skip_if(cpl_dfs_save_image
04221                    (frameset, NULL, parlist, usedframes, NULL,
04222                     cpl_imagelist_get(autocorr_images, i), CPL_BPP_IEEE_FLOAT,
04223                     recipe_name, pplist, NULL, package,
04224                     NAME_O));
04225             }
04226             else
04227             {
04228                cpl_propertylist* pextlist = cpl_propertylist_new();
04229                cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
04230                if(whichext == 1)
04231                {
04232                   skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL,NULL,
04233                         CPL_BPP_IEEE_FLOAT, recipe_name,
04234                         pplist, NULL,
04235                         package, NAME_O));
04236                         skip_if(cpl_image_save(cpl_imagelist_get(autocorr_images, i),
04237                                        NAME_O, CPL_BPP_IEEE_FLOAT, pextlist,
04238                                        CPL_IO_EXTEND));
04239                } else
04240                {
04241                      skip_if(cpl_image_save(cpl_imagelist_get(autocorr_images, i),
04242                                           NAME_O, CPL_BPP_IEEE_FLOAT, pextlist,
04243                                           CPL_IO_EXTEND));
04244                }
04245                cpl_propertylist_delete(pextlist);
04246             }
04247             cpl_propertylist_delete (pplist);
04248         }
04249     
04250 
04251         /*
04252         cpl_msg_info(cpl_func, "-----before Write the DIFFS FITS %d", __LINE__);
04253         */
04254         /***************************/
04255         /*   Write the DIFFS FITS  */
04256         /***************************/
04257          for(i = 0; i < nb_images; i++)
04258          {
04259             cpl_propertylist* pplist = cpl_propertylist_duplicate(mypro_diff);
04260             int inull = 0;
04261             cpl_array* pnames = cpl_table_get_column_names(linear_table);
04262             double ddit = 0;
04263             if(i < cpl_table_get_nrow(linear_table))
04264             {
04265                ddit = cpl_table_get_double(linear_table,
04266                cpl_array_get_data_string_const(pnames)[0], i, &inull);
04267             }
04268             cpl_array_delete(pnames);
04269             /*cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);*/
04270             /* Set the file name for each image */
04271             if(!flag_sets)
04272             {
04273                 sprintf(NAME_O,"%s_diff_flat_%d.fits", recipe_name, i);
04274             } else
04275             {
04276                 sprintf(NAME_O,"%s_diff_flat_%d_set%02d.fits",
04277                                    recipe_name, i, which_set);
04278             }
04279             /* Save the image */
04280             if(detmon_lg_config.exts > 0)
04281             {
04282                cpl_propertylist* pextlist = cpl_propertylist_new();
04283                cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);            
04284                cpl_propertylist_append_double(mypro_diff, "ESO DET DIT", ddit);              
04285                skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL,NULL,
04286                   CPL_BPP_IEEE_FLOAT, recipe_name,
04287                   mypro_diff, NULL,
04288                   package, NAME_O));
04289                skip_if(cpl_image_save(cpl_imagelist_get(diff_flats, i),
04290                                     NAME_O, CPL_BPP_IEEE_FLOAT, pextlist,
04291                                     CPL_IO_EXTEND));
04292                cpl_propertylist_delete(pextlist);
04293             }
04294             else if(detmon_lg_config.exts == 0)
04295             {
04296                cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);            
04297                 skip_if(cpl_dfs_save_image
04298                    (frameset, NULL, parlist, usedframes, NULL,
04299                     cpl_imagelist_get(diff_flats, i), CPL_BPP_IEEE_FLOAT,
04300                     recipe_name, pplist, NULL, package,
04301                     NAME_O));
04302             } else
04303             {
04304                cpl_propertylist* pextlist = cpl_propertylist_new();
04305                cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);            
04306                if(whichext == 1)
04307                {
04308                   cpl_propertylist_append_double(mypro_diff, "ESO DET DIT", ddit);              
04309 //                  cpl_propertylist_erase(mypro_diff, "ESO DET DIT");
04310                   skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL,NULL,
04311                      CPL_BPP_IEEE_FLOAT, recipe_name,
04312                      mypro_diff, NULL,
04313                      package, NAME_O));
04314                   skip_if(cpl_image_save(cpl_imagelist_get(diff_flats, i),
04315                                        NAME_O, CPL_BPP_IEEE_FLOAT, pextlist,
04316                                        CPL_IO_EXTEND));
04317                } else
04318                {
04319                     skip_if(cpl_image_save(cpl_imagelist_get(diff_flats, i),
04320                                        NAME_O, CPL_BPP_IEEE_FLOAT, pextlist,
04321                                        CPL_IO_EXTEND));
04322                 }
04323                 cpl_propertylist_delete(pextlist);
04324             }
04325             cpl_propertylist_delete(pplist);
04326         }
04327     } /* End of if(intermediate) */
04328 
04329 
04330     /*******************************/
04331     /*  Write the PAF file(s)      */
04332     /*******************************/
04333     if(detmon_lg_config.pafgen) {
04334 
04335        irplib_detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,whichext,
04336                                          pafregexp,procatg_gaintbl,
04337                                          pipeline_name,recipe_name,
04338                                          "qc01",gaint_qclist,0);
04339 
04340        irplib_detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,whichext,
04341                                          pafregexp,procatg_lintbl,
04342                                          pipeline_name,recipe_name,
04343                                          "qc02",lint_qclist,0);
04344 
04345        if(detmon_lg_config.pix2pix) 
04346        {
04347 
04348           irplib_detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,
04349                                             whichext,pafregexp,
04350                                             procatg_coeffscube,
04351                                             pipeline_name,recipe_name,
04352                                             "qc03",linc_qclist,1);
04353 
04354           irplib_detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,
04355                                             whichext,pafregexp,procatg_bpm,
04356                                             pipeline_name,recipe_name,
04357                                             "qc04",bpm_qclist,1);
04358        }
04359     }
04360 
04361     end_skip;
04362 
04363     cpl_propertylist_delete(xplist);
04364     if(plist!=NULL) {
04365        cpl_propertylist_delete(plist);
04366        plist=NULL;
04367     }
04368     cpl_propertylist_delete(mainplist);
04369     cpl_propertylist_delete(mypro_lintbl);
04370     cpl_propertylist_delete(mypro_gaintbl);
04371     cpl_propertylist_delete(mypro_coeffscube);
04372     cpl_propertylist_delete(mypro_bpm);
04373     cpl_propertylist_delete(mypro_corr);
04374     cpl_propertylist_delete(mypro_diff);
04375     return cpl_error_get_code();
04376 }
04377 
04378 
04379 /*---------------------------------------------------------------------------*/
04387 /*---------------------------------------------------------------------------*/
04388 static cpl_error_code
04389 irplib_detmon_opt_contamination(const cpl_imagelist * ons,
04390                 const cpl_imagelist * offs,
04391                 unsigned mode,
04392                                 cpl_propertylist * qclist)
04393 {
04394 
04395     double                  median[5] = {0, 0, 0, 0, 0};
04396 
04397     cpl_image * dif1=NULL;
04398     cpl_image * dif2=NULL;
04399     cpl_image * dif_avg=NULL;
04400     char kname[2048];
04401     int offsize = cpl_imagelist_get_size(offs);
04402 
04403     /* Algorithm defined: substract ON - OFF and average 2 differences */
04404     dif1 = cpl_image_subtract_create(cpl_imagelist_get_const(ons, 0),
04405                                      cpl_imagelist_get_const(offs, 0));
04406 
04407     if (offsize == 1 || mode & IRPLIB_LIN_COLLAPSE)
04408         dif2 = cpl_image_subtract_create(cpl_imagelist_get_const(ons, 1),
04409                                          cpl_imagelist_get_const(offs, 0));
04410     else if (mode & IRPLIB_LIN_NO_COLLAPSE)
04411         dif2 = cpl_image_subtract_create(cpl_imagelist_get_const(ons, 1),
04412                                          cpl_imagelist_get_const(offs, 1));
04413 
04414     dif_avg = cpl_image_average_create(dif1, dif2);
04415 
04416     cpl_image_abs(dif_avg);
04417 
04418     median[0] = cpl_image_get_median_window(dif_avg,
04419                         detmon_lg_config.llx1,
04420                         detmon_lg_config.lly1,
04421                         detmon_lg_config.urx1,
04422                         detmon_lg_config.ury1);
04423 
04424     skip_if(0);
04425     sprintf(kname, "%s%d", DETMON_QC_CONTAM,1);
04426 
04427     if(cpl_propertylist_has(qclist,kname)){
04428        skip_if(cpl_propertylist_update_double(qclist,kname,median[0]));
04429     } else {
04430        skip_if(cpl_propertylist_append_double(qclist,kname,median[0]));
04431        skip_if(cpl_propertylist_set_comment(qclist,kname,DETMON_QC_CONTAM_C));
04432     }
04433     median[1] = cpl_image_get_median_window(dif_avg,
04434                         detmon_lg_config.llx2,
04435                         detmon_lg_config.lly2,
04436                         detmon_lg_config.urx2,
04437                         detmon_lg_config.ury2);
04438 
04439     skip_if(0);
04440     sprintf(kname, "%s%d", DETMON_QC_CONTAM,2);
04441     if(cpl_propertylist_has(qclist,kname)){
04442        skip_if(cpl_propertylist_update_double(qclist,kname,median[1]));
04443     } else {
04444        skip_if(cpl_propertylist_append_double(qclist,kname,median[1]));
04445        skip_if(cpl_propertylist_set_comment(qclist,kname,DETMON_QC_CONTAM_C));
04446     }
04447     median[2] = cpl_image_get_median_window(dif_avg,
04448                         detmon_lg_config.llx3,
04449                         detmon_lg_config.lly3,
04450                         detmon_lg_config.urx3,
04451                         detmon_lg_config.ury3);
04452     skip_if(0);
04453 
04454     sprintf(kname, "%s%d", DETMON_QC_CONTAM,3);
04455     if(cpl_propertylist_has(qclist,kname)){
04456        skip_if(cpl_propertylist_update_double(qclist,kname,median[2]));
04457     } else {
04458        skip_if(cpl_propertylist_append_double(qclist,kname,median[2]));
04459        skip_if(cpl_propertylist_set_comment(qclist,kname,DETMON_QC_CONTAM_C));
04460     }
04461 
04462     median[3] = cpl_image_get_median_window(dif_avg,
04463                         detmon_lg_config.llx4,
04464                         detmon_lg_config.lly4,
04465                         detmon_lg_config.urx4,
04466                         detmon_lg_config.ury4);
04467     skip_if(0);
04468 
04469     sprintf(kname,"%s%d", DETMON_QC_CONTAM,4);
04470     if(cpl_propertylist_has(qclist,kname)){
04471        skip_if(cpl_propertylist_update_double(qclist,kname,median[3]));
04472     } else {
04473        skip_if(cpl_propertylist_append_double(qclist,kname,median[3]));
04474        skip_if(cpl_propertylist_set_comment(qclist,kname,DETMON_QC_CONTAM_C));
04475     }
04476 
04477     median[4] = cpl_image_get_median_window(dif_avg,
04478                         detmon_lg_config.llx5,
04479                         detmon_lg_config.lly5,
04480                         detmon_lg_config.urx5,
04481                         detmon_lg_config.ury5);
04482     skip_if(0);
04483 
04484     sprintf(kname,"%s%d", DETMON_QC_CONTAM,5);
04485     if(cpl_propertylist_has(qclist,kname)){
04486        skip_if(cpl_propertylist_update_double(qclist,kname,median[4]));
04487     } else {
04488        skip_if(cpl_propertylist_append_double(qclist,kname,median[4]));
04489        skip_if(cpl_propertylist_set_comment(qclist,kname,DETMON_QC_CONTAM_C));
04490     }
04491     end_skip;
04492 
04493     cpl_image_delete(dif1);
04494     cpl_image_delete(dif2);
04495     cpl_image_delete(dif_avg);
04496 
04497     return cpl_error_get_code();
04498 }
04499 
04500 /*---------------------------------------------------------------------------*/
04507 /*---------------------------------------------------------------------------*/
04508 /*
04509 static cpl_error_code
04510 irplib_detmon_opt_lampcr(cpl_frameset * cur_fset, int ext)
04511 {
04512     cpl_image        * on        = NULL;
04513     cpl_image        * off       = NULL;
04514     cpl_frame        * first_off = NULL;
04515     cpl_frame        * first_on  = NULL;
04516     cpl_propertylist * plist     = NULL;
04517     double             dit;
04518 
04519     cpl_ensure_code(cur_fset != NULL, CPL_ERROR_NULL_INPUT);
04520 
04521     skip_if((first_off = cpl_frameset_get_first(cur_fset)) == NULL);
04522     skip_if((first_on  = cpl_frameset_get_next (cur_fset)) == NULL);
04523 
04524     on = cpl_image_load(cpl_frame_get_filename(first_on),
04525                         CPL_TYPE_FLOAT, 0, ext);
04526     off = cpl_image_load(cpl_frame_get_filename(first_off),
04527                          CPL_TYPE_FLOAT, 0, ext);
04528     skip_if(cpl_image_subtract(on, off));
04529 
04530     plist = cpl_propertylist_load(cpl_frame_get_filename(first_on), 0);
04531     skip_if(plist == NULL);
04532 
04533     dit = irplib_pfits_get_dit_opt(plist);
04534 
04535     detmon_lg_config.cr = cpl_image_get_mean(on) / dit;
04536 
04537     end_skip;
04538 
04539     cpl_image_delete(on);
04540     cpl_image_delete(off);
04541     cpl_propertylist_delete(plist);
04542 
04543     return cpl_error_get_code();
04544 }
04545 */
04546 /*---------------------------------------------------------------------------*/
04554 /*---------------------------------------------------------------------------*/
04555 int
04556 irplib_detmon_lg_dfs_set_groups(cpl_frameset * set,
04557                                 const char *tag_on, const char *tag_off)
04558 {
04559     cpl_frame              *cur_frame;
04560     const char             *tag;
04561     int                     nframes;
04562     int                     i;
04563 
04564     /* Check entries */
04565     if(set == NULL)
04566         return -1;
04567 
04568     /* Initialize */
04569     nframes = cpl_frameset_get_size(set);
04570 
04571     /* Loop on frames */
04572     for(i = 0; i < nframes; i++) {
04573         cur_frame = cpl_frameset_get_frame(set, i);
04574         tag = cpl_frame_get_tag(cur_frame);
04575 
04576         /* RAW frames */
04577         if(!strcmp(tag, tag_on) || !strcmp(tag, tag_off))
04578             cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW);
04579         /* CALIB frames */
04580 
04581 /*        else if (!strcmp(tag, IIINSTRUMENT_CALIB_FLAT))
04582             cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB);
04583 */
04584     }
04585     return 0;
04586 }
04587 
04588 
04589 /*---------------------------------------------------------------------------*/
04597 /*---------------------------------------------------------------------------*/
04598 static cpl_error_code
04599 irplib_detmon_lg_fits_coeffs_and_bpm2chip(cpl_imagelist ** coeffs_ptr,
04600                                           cpl_image **bpms_ptr)
04601 {
04602    cpl_image* dummy_bpm=NULL;
04603    cpl_image * dummy_coeff=NULL;
04604    cpl_imagelist * dummy_coeffs=NULL;
04605    int * db_p=NULL;
04606    int * rb_p =NULL;
04607    float ** dcs_p;
04608    float ** rcs_p;
04609    int dlength=0;
04610    int rlength=0;
04611    int shift_idx=0;
04612    int i=0;
04613    int k=0;
04614    int j=0;
04615 
04616    dummy_bpm = cpl_image_new(detmon_lg_config.nx,
04617                              detmon_lg_config.ny,
04618                              CPL_TYPE_INT);
04619    dummy_coeffs = cpl_imagelist_new();
04620 
04621    db_p = cpl_image_get_data_int(dummy_bpm);
04622    rb_p = cpl_image_get_data_int(*bpms_ptr);;  
04623    dcs_p = cpl_malloc(sizeof(float *) * (detmon_lg_config.order + 1));
04624    rcs_p = cpl_malloc(sizeof(float *) * (detmon_lg_config.order + 1));
04625    dlength = detmon_lg_config.nx;
04626    rlength = detmon_lg_config.urx - detmon_lg_config.llx + 1;
04627    for (i = 0; i <= detmon_lg_config.order; i++) 
04628    {
04629       dummy_coeff = cpl_image_new(detmon_lg_config.nx,
04630                                   detmon_lg_config.ny,
04631                                   CPL_TYPE_FLOAT);
04632 
04633       cpl_imagelist_set(dummy_coeffs, dummy_coeff, i);
04634       dcs_p[i] = cpl_image_get_data_float(dummy_coeff);
04635       rcs_p[i] = cpl_image_get_data_float(cpl_imagelist_get(*coeffs_ptr, i));
04636    }
04637    /*copy the coefficients from temporary image to the dummy_bpm*/  
04638    for (i = detmon_lg_config.lly - 1; i < detmon_lg_config.ury; i++) 
04639    {
04640       for (j = detmon_lg_config.llx - 1; j < detmon_lg_config.urx; j++) 
04641       {
04642          shift_idx=(i - detmon_lg_config.lly + 1) * rlength +
04643             j - detmon_lg_config.llx + 1;
04644          *(db_p + i * dlength + j) = *(rb_p + shift_idx);
04645          for (k = 0; k <= detmon_lg_config.order; k++) 
04646          {
04647             *(dcs_p[k] + i * dlength + j) =
04648                *(rcs_p[k] + (i - detmon_lg_config.lly + 1) * rlength +
04649                  j - detmon_lg_config.llx + 1);
04650          }
04651       }
04652    }
04653    cpl_imagelist_delete(*coeffs_ptr);
04654    cpl_image_delete(*bpms_ptr);
04655    *coeffs_ptr = dummy_coeffs;
04656    *bpms_ptr = dummy_bpm;
04657    cpl_free(dcs_p);
04658    cpl_free(rcs_p);
04659 
04660    return cpl_error_get_code();
04661 }
04662 
04663 /*---------------------------------------------------------------------------*/
04677 /*---------------------------------------------------------------------------*/
04678 static cpl_error_code
04679 irplib_detmon_lg_reduce_all(const cpl_table * linear_table,
04680                             cpl_propertylist * gaint_qclist,
04681                             cpl_propertylist * lint_qclist,
04682                             cpl_propertylist * linc_qclist,
04683                             cpl_propertylist * bpm_qclist,
04684                             cpl_imagelist ** coeffs_ptr,
04685                             cpl_image ** bpms_ptr,
04686                             const cpl_imagelist * linearity_inputs,
04687                             const cpl_table * gain_table,
04688                 int which_ext, cpl_boolean opt_nir)
04689 {
04690 
04691     int                     nbpixs = 0;
04692     const int               nsets = cpl_table_get_nrow(linear_table);
04693     int                     i;
04694     double autocorr;
04695     cpl_polynomial         *poly_linfit = NULL;
04696     cpl_image              *fiterror = NULL;
04697     char * name_o1 = NULL;
04698     char * name_o2 = NULL;
04699     double * pcoeffs = cpl_malloc(sizeof(double)*(detmon_lg_config.order + 1));
04700     unsigned mode = detmon_lg_config.autocorr ? IRPLIB_GAIN_WITH_AUTOCORR : 0;
04701     double min_val=0;
04702     double max_val=0;
04703     cpl_vector *x =NULL;
04704     const cpl_vector *y =NULL;
04705 
04706 
04707     const cpl_image * first = NULL;
04708     int sizex = 0;
04709     int sizey = 0;
04710 
04711     int vsize = 0;
04712 
04713     /* FIXME: This should go before the x and y vectors.
04714        Checking for all the inputs */
04715     cpl_ensure_code(gaint_qclist != NULL, CPL_ERROR_NULL_INPUT);
04716     cpl_ensure_code(lint_qclist != NULL, CPL_ERROR_NULL_INPUT);
04717     cpl_ensure_code(linc_qclist != NULL, CPL_ERROR_NULL_INPUT);
04718     cpl_ensure_code(bpm_qclist != NULL, CPL_ERROR_NULL_INPUT);
04719 
04720     skip_if(cpl_propertylist_append_string(gaint_qclist, DETMON_QC_METHOD,
04721                        detmon_lg_config.method));
04722     skip_if(cpl_propertylist_set_comment(gaint_qclist, DETMON_QC_METHOD,
04723                      DETMON_QC_METHOD_C));
04724 
04725     if (!strcmp(detmon_lg_config.method, "PTC")) {
04726     /* Computation of GAIN via polynomial fit */
04727     if (detmon_lg_config.exts >= 0) {
04728         cpl_msg_info(cpl_func,
04729              "Polynomial fitting for the GAIN (constant term method)");
04730     } else {
04731         cpl_msg_info(cpl_func,
04732              "Polynomial fitting for the GAIN (constant term method)"
04733              " for extension nb %d", which_ext);
04734     }
04735     skip_if(irplib_detmon_lg_qc_ptc(gain_table, gaint_qclist, mode, nsets));
04736     } else {
04737     skip_if(irplib_detmon_lg_qc_med(gain_table, gaint_qclist, nsets));
04738     }
04739 
04740     /*^FIXME: This shouldn't be written when no applied */
04741     /* Lamp flux */
04742     if(detmon_lg_config.lamp_ok) {
04743     skip_if(cpl_propertylist_append_double(lint_qclist, DETMON_QC_LAMP_FLUX,
04744                            detmon_lg_config.cr));
04745     skip_if(cpl_propertylist_set_comment(lint_qclist, DETMON_QC_LAMP_FLUX,
04746                          DETMON_QC_LAMP_FLUX_C));
04747     }
04748 
04749     /*^FIXME: This shouldn't be written when no applied */
04750     if(detmon_lg_config.autocorr == TRUE) {
04751     autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
04752     skip_if(cpl_propertylist_append_double(gaint_qclist, DETMON_QC_AUTOCORR,
04753                            autocorr));
04754     skip_if(cpl_propertylist_set_comment(gaint_qclist, DETMON_QC_AUTOCORR,
04755                          DETMON_QC_AUTOCORR_C));
04756     }
04757     if (detmon_lg_config.exts >= 0) {
04758         cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix");
04759     } else {
04760         cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix"
04761                                " for extension nb %d", which_ext);
04762     }
04763 
04764     if(!detmon_lg_config.pix2pix) {
04765     double mse = 0;
04766         /* Computation of LINEARITY via polynomial fit */
04767     y = cpl_vector_wrap(nsets,
04768                 (double *)cpl_table_get_data_double_const(linear_table,
04769                                   "MED"));
04770 
04771     if (opt_nir == NIR)
04772         x = cpl_vector_wrap(nsets,
04773                 (double *)cpl_table_get_data_double_const(linear_table,
04774                                   "DIT"));
04775     else
04776         x = cpl_vector_wrap(nsets,
04777                 (double *)cpl_table_get_data_double_const(linear_table,
04778                                   "EXPTIME"));
04779 
04780 
04781         if(x == NULL || y == NULL) {
04782         cpl_vector_unwrap((cpl_vector *)x);
04783         cpl_vector_unwrap((cpl_vector *)y);
04784         /*
04785          * As x and y are const vectors, if they would be defined at the
04786          * beginning of the function (required for skip_if - end_skip
04787          * scheme), they couldn't be initialised to NULL (required too).
04788          * Therefore, they are considered apart from the scheme.
04789          */
04790         skip_if(1);
04791     }
04792 
04793         cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
04794         poly_linfit = irplib_polynomial_fit_1d_create(x, y,
04795                            detmon_lg_config.order,
04796                            &mse);
04797 
04798     if(detmon_lg_config.order == cpl_vector_get_size(x) - 1) {
04799         cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
04800         mse = 0;
04801     }
04802 
04803     if(poly_linfit == NULL) {
04804         cpl_vector_unwrap((cpl_vector *)x);
04805         cpl_vector_unwrap((cpl_vector *)y);
04806         /* See comment in previous error checking if() statement */
04807         skip_if(1);
04808     }
04809 
04810 
04811         min_val=cpl_vector_get_min(y);
04812         max_val=cpl_vector_get_max(y);
04813 
04814     cpl_vector_unwrap((cpl_vector *)x);
04815     cpl_vector_unwrap((cpl_vector *)y);
04816 
04817         for(i = 0; i <= detmon_lg_config.order; i++) {
04818             const double            coeff =
04819                 cpl_polynomial_get_coeff(poly_linfit, &i);
04820             char                   *name_o =
04821                 cpl_sprintf("ESO QC LIN COEF%d", i);
04822             assert(name_o != NULL);
04823             skip_if(cpl_propertylist_append_double(lint_qclist, name_o, coeff));
04824             skip_if(cpl_propertylist_set_comment(lint_qclist,name_o,
04825                          DETMON_QC_LIN_COEF_C));
04826 
04827             cpl_free(name_o);
04828         pcoeffs[i] = coeff;
04829         }
04830     skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_ERRFIT, mse));
04831         skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_ERRFIT,
04832                          DETMON_QC_ERRFIT_MSE_C));
04833 
04834 
04835     } else 
04836     {
04837          y = cpl_vector_wrap(nsets,
04838                 (double *)cpl_table_get_data_double_const(linear_table,
04839                                   "MED"));
04840         if (opt_nir == NIR) 
04841         {
04842             x = cpl_vector_wrap(nsets,
04843                 (double *)cpl_table_get_data_double_const(linear_table,
04844                                   "DIT"));
04845         } else 
04846         {
04847             x = cpl_vector_wrap(nsets,
04848                 (double *)cpl_table_get_data_double_const(linear_table,
04849                                   "EXPTIME"));
04850 
04851         }
04852         first = cpl_imagelist_get_const(linearity_inputs, 0);
04853         sizex = cpl_image_get_size_x(first);
04854         sizey = cpl_image_get_size_y(first);
04855         vsize = cpl_vector_get_size(x);
04856         fiterror = cpl_image_new(sizex, sizey, CPL_TYPE_FLOAT);
04857          *coeffs_ptr =
04858             cpl_fit_imagelist_polynomial(x, linearity_inputs, 0,
04859                      detmon_lg_config.order, FALSE,
04860                      CPL_TYPE_FLOAT, fiterror);
04861         min_val=cpl_vector_get_min(y);
04862         max_val=cpl_vector_get_max(y);
04863         cpl_vector_unwrap((cpl_vector*)x);
04864         cpl_vector_unwrap((cpl_vector*)y);
04865         irplib_ensure(*coeffs_ptr != NULL, CPL_ERROR_UNSPECIFIED,
04866               "Failed polynomial fit");
04867         for(i = 0; i <= detmon_lg_config.order; i++) 
04868         {
04869             cpl_image *image = cpl_imagelist_get(*coeffs_ptr, i);
04870              const double coeff = cpl_image_get_median(image);
04871              pcoeffs[i] = coeff;
04872             name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
04873             name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
04874             assert(name_o1 != NULL);
04875             assert(name_o2 != NULL);
04876             skip_if(cpl_propertylist_append_double(linc_qclist, name_o1, coeff));
04877               skip_if(cpl_propertylist_set_comment(linc_qclist,name_o1,
04878                          DETMON_QC_LIN_COEF_C));
04879             cpl_free(name_o1);
04880              name_o1= NULL;
04881             skip_if(cpl_propertylist_append_double(linc_qclist, name_o2,
04882                        cpl_image_get_stdev(image)));
04883               skip_if(cpl_propertylist_set_comment(linc_qclist,name_o2,
04884                          DETMON_QC_LIN_COEF_ERR_C));
04885             cpl_free(name_o2);
04886              name_o2= NULL;
04887         }
04888          if(detmon_lg_config.order == vsize - 1) 
04889         {
04890             cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
04891             skip_if(cpl_propertylist_append_double(linc_qclist,DETMON_QC_ERRFIT,
04892                            0.0));
04893             skip_if(cpl_propertylist_set_comment(linc_qclist,DETMON_QC_ERRFIT,
04894                          DETMON_QC_ERRFIT_C));
04895          } else 
04896         {
04897             skip_if(cpl_propertylist_append_double(linc_qclist,DETMON_QC_ERRFIT,
04898                            cpl_image_get_median(fiterror)));
04899              skip_if(cpl_propertylist_set_comment(linc_qclist,DETMON_QC_ERRFIT,
04900                          DETMON_QC_ERRFIT_C));
04901          }
04902    }
04903     skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_COUNTS_MIN,
04904                                            min_val));
04905     skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_COUNTS_MIN,
04906                                          DETMON_QC_COUNTS_MIN_C));
04907     skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_COUNTS_MAX,
04908                                            max_val));
04909     skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_COUNTS_MAX,
04910                                          DETMON_QC_COUNTS_MAX_C));
04911     skip_if(irplib_detmon_lg_lineff(pcoeffs,lint_qclist,detmon_lg_config.ref_level,
04912                                     detmon_lg_config.order));
04913     /* Detection of bad pixels */
04914     if (detmon_lg_config.exts >= 0) 
04915     {
04916         cpl_msg_info(cpl_func, "Bad pixel detection");
04917     } else 
04918     {
04919         cpl_msg_info(cpl_func, "Bad pixel detection"
04920              " for extension nb %d", which_ext);
04921     }
04922     if(detmon_lg_config.pix2pix) 
04923     {
04924        *bpms_ptr = irplib_detmon_bpixs(*coeffs_ptr, detmon_lg_config.bpmbin,
04925                                        detmon_lg_config.kappa, &nbpixs);
04926          skip_if(*bpms_ptr == NULL);
04927     }
04928     skip_if(cpl_propertylist_append_int(bpm_qclist, DETMON_QC_NUM_BPM, nbpixs));
04929     skip_if(cpl_propertylist_set_comment(bpm_qclist, DETMON_QC_NUM_BPM,
04930                                          DETMON_QC_NUM_BPM_C));
04931     if(detmon_lg_config.lamp_stability != 0.0) 
04932     {
04933          skip_if(cpl_propertylist_append_double(lint_qclist, DETMON_QC_LAMP_STAB,
04934                            detmon_lg_config.lamp_stability));
04935          skip_if(cpl_propertylist_set_comment(lint_qclist, DETMON_QC_LAMP_STAB,
04936                          DETMON_QC_LAMP_STAB_C));
04937     }
04938     /* Fit COEFFS_CUBE and BPM outputs to whole-chip size images (DFS05711) */
04939     if (!detmon_lg_config.wholechip && detmon_lg_config.pix2pix) 
04940     {
04941        irplib_detmon_lg_fits_coeffs_and_bpm2chip(coeffs_ptr,bpms_ptr);
04942     }
04943     end_skip;
04944 
04945     cpl_free(pcoeffs);
04946     cpl_free(name_o1);
04947     cpl_free(name_o2);
04948     cpl_image_delete(fiterror);
04949     cpl_polynomial_delete(poly_linfit);
04950 
04951     return cpl_error_get_code();
04952 }
04953 
04954 /*---------------------------------------------------------------------------*/
04962 /*---------------------------------------------------------------------------*/
04963 static cpl_error_code
04964 irplib_detmon_lg_lineff(double * pcoeffs,
04965                         cpl_propertylist * qclist,
04966                         int ref_level,
04967                         int order)
04968 {
04969     double           lineff = 0;
04970     double           root = 0;
04971     cpl_polynomial * poly = cpl_polynomial_new(1);
04972     int i;
04973 
04974     double residual, slope;
04975 
04976     /*
04977      * Construction of the polynomial F_m(F_r) from F_m(t),
04978      * using F_r = a_1 * t.
04979      */
04980     pcoeffs[0] -= ref_level;
04981 
04982     for (i = 2; i <= order; i++)
04983     {
04984         int j;
04985         for(j = 0; j < i; j++)
04986         {
04987             pcoeffs[i] /= pcoeffs[1];
04988         }
04989     }
04990 
04991     pcoeffs[1] = 1;
04992 
04993     for (i = 0; i <= order; i++) {
04994     skip_if(cpl_polynomial_set_coeff(poly, &i, pcoeffs[i]));
04995     }
04996 
04997     /*
04998      * Verification of validity of first guess (0).
04999      * The root to be found will be in the same interval of monotony
05000      * of the first guess; therefore, slope must be greater than 0.
05001      * Slope > 0 and poly(root) = 0 force also residual to be negative.
05002      */
05003     residual = cpl_polynomial_eval_1d(poly, 0.0, &slope);
05004 
05005     if (slope <= 0.0 && residual >= 0.0) {
05006     cpl_msg_warning(cpl_func, "Reference level (--ref_level) outside"
05007             " linearity range of the detector. Cannot compute"
05008             " linearity efficiency (QC.LINEFF).");
05009     lineff = -1;
05010     }
05011     else
05012     {
05013         cpl_error_code err = cpl_polynomial_solve_1d(poly, 0.0, &root, 1);
05014         if (err == CPL_ERROR_NONE)
05015         {
05016             lineff = (root - ref_level) / ref_level;
05017         }
05018         else
05019         {
05020             cpl_error_reset();
05021             cpl_msg_warning(cpl_func,
05022                     "Cannot compute linearity efficiency (QC.LINEFF)"
05023                     "for the current combination "
05024                     " of (--ref-level equal %d) and (--order equal %d) parameters. Try "
05025                     "to decrease (--ref-level) value.", ref_level, order);
05026         }
05027     }
05028     cpl_msg_warning(cpl_func, "DETMON_QC_LIN_EFF=%f",lineff );
05029     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LIN_EFF,
05030                        lineff));
05031     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LIN_EFF,
05032                      DETMON_QC_LIN_EFF_C));
05033 
05034     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LIN_EFF_FLUX,
05035                        ref_level));
05036     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LIN_EFF_FLUX,
05037                      DETMON_QC_LIN_EFF_FLUX_C));
05038 
05039     end_skip;
05040 
05041     cpl_polynomial_delete(poly);
05042 
05043     return cpl_error_get_code();
05044 }
05045 
05046 /*---------------------------------------------------------------------------*/
05053 /*---------------------------------------------------------------------------*/
05054 static cpl_error_code
05055 irplib_detmon_lg_qc_ptc(const cpl_table  * gain_table,
05056             cpl_propertylist * qclist, unsigned mode, int rows_in_gain)
05057 {
05058     double                  mse = 0;
05059     cpl_polynomial         *poly_fit = NULL;
05060     cpl_polynomial         *poly_fit2 = NULL;
05061     int i;
05062     const int               nsets = rows_in_gain;
05063 
05064     cpl_vector             *x = NULL;
05065     cpl_vector             *y = NULL;
05066 
05067     cpl_errorstate                prestate;
05068     double coef = 0;
05069     cpl_ensure_code(gain_table != NULL, CPL_ERROR_NULL_INPUT);
05070     cpl_ensure_code(qclist     != NULL, CPL_ERROR_NULL_INPUT);
05071 
05072     x = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT"));
05073 
05074     y = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
05075 
05076     skip_if(x == NULL || y == NULL);
05077    if (0 == irplib_detmon_lg_check_before_gain(x, y))
05078    {
05079       if (x)
05080       {
05081          cpl_vector_unwrap(x);
05082       }
05083       if (y)
05084       {
05085          cpl_vector_unwrap(y);
05086       }   
05087       return CPL_ERROR_NONE;
05088    }
05089     /*it is not really a MSE, but chi square of the fit, see cpl_vector_fill_polynomial_fit_residual for details*/
05090     poly_fit = irplib_polynomial_fit_1d_create_chiq(x, y, 1, &mse);
05091     skip_if(poly_fit == NULL);
05092 
05093     /* Write the QC params corresponding to the fitting of the GAIN */
05094     i = 1;
05095     prestate = cpl_errorstate_get();
05096     coef = cpl_polynomial_get_coeff(poly_fit, &i);
05097     skip_if (!cpl_errorstate_is_equal(prestate) || coef==0);
05098     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD, coef));
05099     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
05100                      DETMON_QC_CONAD_C));
05101    if (coef != 0)
05102    {
05103       skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,
05104                        1 / coef));
05105       skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
05106                      DETMON_QC_GAIN_C));
05107     }          
05108 /*  MSE is removed - see DFS07358 for details
05109     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE, mse));
05110     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
05111                      DETMON_QC_GAIN_MSE_C));
05112                      */
05113     i = 0;
05114 /* QC.RON computation is disabled, see DFS05852 for details*/
05115 
05116 /* *     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_RON,
05117                        cpl_polynomial_get_coeff(poly_fit, &i)));
05118     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_RON,
05119                      DETMON_QC_RON_C));
05120 */
05121    if(mode & IRPLIB_GAIN_WITH_AUTOCORR){
05122    const cpl_vector             *x2 =
05123       cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT_CORR"));
05124    const cpl_vector             *y2 =
05125       cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
05126 
05127     if(x2 == NULL || y2 == NULL) {
05128         cpl_vector_unwrap((cpl_vector *)x2);
05129         cpl_vector_unwrap((cpl_vector *)y2);
05130         /*
05131          * As x and y are const vectors, if they would be defined at the
05132          * beginning of the function (required for skip_if - end_skip
05133          * scheme), they couldn't be initialised to NULL (required too).
05134          * Therefore, they are considered apart from the scheme.
05135          */
05136         skip_if(1);
05137     }
05138 
05139     /* Revise mse, maybe used afterwards */
05140     poly_fit2 = irplib_polynomial_fit_1d_create(x2, y2, 1, &mse);
05141     if(poly_fit2 == NULL) {
05142         cpl_vector_unwrap((cpl_vector *)x2);
05143         cpl_vector_unwrap((cpl_vector *)y2);
05144 
05145         cpl_msg_error(cpl_func, "Error during polynomial fit, err[%s]", cpl_error_get_where());
05146         /* See comment in previous error checking if() statement */
05147         skip_if(1);
05148     }
05149     skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
05150     cpl_vector_unwrap((cpl_vector *)x2);
05151     cpl_vector_unwrap((cpl_vector *)y2);
05152     skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
05153     /* Write the QC params corresponding to the fitting of the GAIN */
05154     i = 1;
05155     prestate = cpl_errorstate_get();
05156     coef = cpl_polynomial_get_coeff(poly_fit2, &i);
05157     skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
05158     skip_if (!cpl_errorstate_is_equal(prestate) || coef == 0);
05159 
05160     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD_CORR,
05161                            coef));
05162     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD_CORR,
05163                          DETMON_QC_CONAD_CORR_C));
05164 
05165     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
05166                            1 / coef));
05167     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
05168                          DETMON_QC_GAIN_CORR_C));
05169     }
05170 
05171     end_skip;
05172 
05173    /*cleanup*/
05174     cpl_vector_unwrap(x);
05175     cpl_vector_unwrap(y);
05176     cpl_polynomial_delete(poly_fit);
05177     cpl_polynomial_delete(poly_fit2);
05178 
05179     return cpl_error_get_code();
05180 }
05181 
05188 static int irplib_detmon_lg_check_before_gain(const cpl_vector* x, const cpl_vector* y)
05189 {
05190    const double TOLERANCE = 1e-37;/*MINDOUBLE is not everywhere defined (Mac);*/
05191    double xmin = cpl_vector_get_min(x);
05192    double xmax = cpl_vector_get_max(x);
05193    double ymin = cpl_vector_get_min(y);
05194    double ymax = cpl_vector_get_max(y);
05195    double ystdev = cpl_vector_get_stdev(y);
05196    double xstdev = cpl_vector_get_stdev(x);   
05197    int retval = 1;
05198    if (fabs(xmax-xmin) < TOLERANCE && 
05199        fabs(ymax - ymin) < TOLERANCE &&
05200        xstdev < TOLERANCE &&
05201        ystdev < TOLERANCE)
05202    {
05203       cpl_msg_warning(cpl_func, "An empty frame has been detected, linearity, coeffs, gain, FPN values will not be computed.");
05204       retval = 0;
05205    }
05206    return retval;
05207 }
05208 /*---------------------------------------------------------------------------*/
05217 /*---------------------------------------------------------------------------*/
05218 static cpl_error_code
05219 irplib_detmon_lg_qc_med(const cpl_table * gain_table,
05220                 cpl_propertylist * qclist, int rows_in_gain)
05221 {
05222 
05223    double gain=0;
05224    int q_STUB; /* dummy variable to remove warning "unused var" */
05225    cpl_vector             *x = NULL;
05226    cpl_vector             *y = NULL;   
05227    int check_result = 0;
05228    
05229    q_STUB = rows_in_gain;
05230    
05231     x = cpl_vector_wrap(rows_in_gain, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT"));
05232     y = cpl_vector_wrap(rows_in_gain, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
05233     check_result = irplib_detmon_lg_check_before_gain(x, y);
05234    if (x)
05235    {
05236       cpl_vector_unwrap(x);
05237    }
05238    if (y)
05239    {
05240       cpl_vector_unwrap(y);
05241    }   
05242    if (0 == check_result)
05243    {
05244       return CPL_ERROR_NONE;
05245    }
05246 
05247    gain=cpl_table_get_column_median(gain_table, "GAIN");
05248 
05249    skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,gain));
05250 
05251    skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
05252                                         DETMON_QC_GAIN_C));
05253 
05254    skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE,
05255                                           cpl_table_get_column_stdev
05256                                           (gain_table, "GAIN")));
05257    skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
05258                                         DETMON_QC_GAIN_MSE_C));
05259 
05260    skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD,1./gain));
05261    skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
05262                                         DETMON_QC_CONAD_C));
05263 
05264 
05265    gain=cpl_table_get_column_median(gain_table, "GAIN_CORR");
05266 
05267    skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
05268                                           gain));
05269    skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
05270                                         DETMON_QC_GAIN_CORR_C));
05271 
05272 
05273    skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD_CORR,1./gain));
05274    skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD_CORR,
05275                                         DETMON_QC_CONAD_CORR_C));
05276 
05277 
05278     end_skip;
05279 
05280     return cpl_error_get_code();
05281 }
05282 
05283 
05284 /*---------------------------------------------------------------------------*/
05293 /*---------------------------------------------------------------------------*/
05294 static cpl_error_code
05295 irplib_detmon_lg_rescale(cpl_imagelist * to_rescale)
05296 {
05297     double                  med1 =
05298         cpl_image_get_median(cpl_imagelist_get(to_rescale, 0));
05299     double                  med2 =
05300         cpl_image_get_median(cpl_imagelist_get(to_rescale, 1));
05301 
05302     skip_if(0);
05303 
05304     if(fabs(med1 / med2 - 1) > 0.001) {
05305         if(med1 > med2)
05306             skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 0),
05307                                             med1 / med2));
05308         else
05309             skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 1),
05310                                             med2 / med1));
05311     }
05312 
05313     end_skip;
05314 
05315     return cpl_error_get_code();
05316 }
05317 
05318 static cpl_error_code
05319 irplib_detmon_pair_extract_next(const cpl_frameset * set,
05320                            int* iindex,
05321                            int* next_element,
05322                            double* dit_array,
05323                            cpl_frameset ** pair,
05324                                 double tolerance) /* detmon_lg_config.tolerance */
05325 {
05326     double dit = -100;
05327     double dit_next = -100;
05328     int* selection;
05329     int nsets_extracted = 0;
05330     cpl_ensure_code(set             != NULL, CPL_ERROR_NULL_INPUT);
05331     cpl_ensure_code(dit_array       != NULL, CPL_ERROR_NULL_INPUT);
05332     cpl_ensure_code(iindex          != NULL, CPL_ERROR_NULL_INPUT);
05333     cpl_ensure_code(pair            != NULL, CPL_ERROR_NULL_INPUT);
05334 
05335     nsets_extracted = cpl_frameset_get_size(set);
05336     selection = cpl_malloc(sizeof(int) * nsets_extracted);
05337     memset(&selection[0], 0, sizeof(int) * nsets_extracted);
05338 
05339 
05340     dit = dit_array[*next_element ];
05341 /*  cpl_msg_info(cpl_func, "%d: dit %f",*next_element, dit ); */
05342     if (*next_element < nsets_extracted - 1)
05343     {
05344         dit_next = dit_array[*next_element + 1 ];
05345                 /* cpl_msg_info(cpl_func, "%d: dit %f",*next_element + 1, dit_next ); */
05346     }
05347     /* one element would be returned always */
05348     selection[iindex[*next_element] ] = 1;
05349     if (fabs(dit - dit_next) < tolerance)
05350     {
05351            /* return a second element of the pair */
05352         selection[iindex[*next_element + 1] ] = 1;
05353         (*next_element)++;
05354     }
05355     else
05356     {
05357         cpl_msg_warning(cpl_func, "DIT for the second frame in the pair is above tolerance level - could not be taken, dit1[%f] dit2[%f] next_element: %d ", dit, dit_next, *next_element);
05358     }
05359     (*next_element)++;
05360     /* prepare frameset */
05361     cpl_frameset_delete(*pair);
05362     *pair = cpl_frameset_extract(set, selection, 1);
05363 
05364 
05365     cpl_free(selection);
05366     return cpl_error_get_code();
05367 }
05368 static cpl_error_code
05369 irplib_detmon_single_extract_next(const cpl_frameset * set,
05370                            int* iindex,
05371                            int* next_element,
05372                            double* dit_array,
05373                            cpl_frameset ** pair)
05374 {
05375     double dit = -100;
05376     int* selection;
05377     int nsets_extracted = 0;
05378     cpl_ensure_code(set             != NULL, CPL_ERROR_NULL_INPUT);
05379     cpl_ensure_code(dit_array       != NULL, CPL_ERROR_NULL_INPUT);
05380     cpl_ensure_code(iindex          != NULL, CPL_ERROR_NULL_INPUT);
05381     cpl_ensure_code(pair            != NULL, CPL_ERROR_NULL_INPUT);
05382 
05383     nsets_extracted = cpl_frameset_get_size(set);
05384     selection = cpl_malloc(sizeof(int) * nsets_extracted);
05385     memset(&selection[0], 0, sizeof(int) * nsets_extracted);
05386 
05387     nsets_extracted = cpl_frameset_get_size(set);
05388     dit = dit_array[iindex[*next_element] ];
05389     /* only one element would be returned */
05390     selection[iindex[*next_element] ] = 1;
05391     (*next_element)++;
05392     /* prepare frameset */
05393     cpl_frameset_delete(*pair);
05394     *pair = cpl_frameset_extract(set, selection, 1);
05395 
05396     cpl_free(selection);
05397     return cpl_error_get_code();
05398 }
05399 
05400 
05401 /*---------------------------------------------------------------------------*/
05490 /*---------------------------------------------------------------------------*/
05491 
05492 cpl_table *
05493 irplib_detmon_gain(const cpl_imagelist  * imlist_on,
05494            const cpl_imagelist  * imlist_off,
05495            const cpl_vector     * exptimes,
05496            const cpl_vector     * ndit,
05497            double                 tolerance,
05498            int                    llx,
05499            int                    lly,
05500            int                    urx,
05501            int                    ury,
05502                    double                 kappa,
05503                    int                    nclip,
05504                    int                    xshift,
05505                    int                    yshift,
05506            cpl_propertylist     * qclist,
05507            unsigned               mode,
05508            cpl_imagelist       ** diff_imlist,
05509            cpl_imagelist       ** autocorr_imlist)
05510 {
05511     cpl_table     * gain_table   = NULL;
05512     cpl_imagelist * difflist     = NULL;
05513     cpl_imagelist * autocorrlist = NULL;
05514     cpl_imagelist * c_onlist     = NULL;
05515     cpl_imagelist * c_offlist    = NULL;
05516     cpl_vector    * diffdits     = NULL;
05517     cpl_vector    * diffndits     = NULL;
05518     int rows_in_gain = 0;
05519     int             ndiffdits, ndits;
05520     int             i, j;
05521     cpl_boolean     opt_nir      = mode & IRPLIB_GAIN_OPT ? OPT : NIR;
05522     const char    * method       = mode & IRPLIB_GAIN_PTC ? "PTC" : "MED";
05523 
05524     cpl_ensure(imlist_on  != NULL, CPL_ERROR_NULL_INPUT, NULL);
05525     cpl_ensure(imlist_off != NULL, CPL_ERROR_NULL_INPUT, NULL);
05526     cpl_ensure(exptimes   != NULL, CPL_ERROR_NULL_INPUT, NULL);
05527     cpl_ensure(qclist     != NULL, CPL_ERROR_NULL_INPUT, NULL);
05528 
05529     /* Create table with columns */
05530     gain_table = cpl_table_new(cpl_vector_get_size(exptimes) / 2);
05531     skip_if(irplib_detmon_gain_table_create(gain_table, opt_nir));
05532 
05533 
05534     /* Search for different EXPTIME values */
05535     skip_if(irplib_detmon_lg_find_dits_ndits(exptimes, ndit,tolerance,&diffdits,&diffndits));
05536     ndiffdits = cpl_vector_get_size(diffdits);
05537 
05538     ndits     = cpl_vector_get_size(exptimes);
05539 
05540     /* AUTOCORR processing requires both. They will become outputs later. */
05541     if (mode & IRPLIB_GAIN_WITH_AUTOCORR && (diff_imlist || autocorr_imlist)) {
05542     difflist     = cpl_imagelist_new();
05543     autocorrlist = cpl_imagelist_new();
05544     }
05545 
05546     if (mode & IRPLIB_GAIN_COLLAPSE) {
05547         if (mode & IRPLIB_GAIN_WITH_RESCALE) {
05548         c_offlist = cpl_imagelist_duplicate(imlist_off);
05549         skip_if(irplib_detmon_lg_rescale(c_offlist));
05550         } else {
05551             c_offlist = (cpl_imagelist *) imlist_off;
05552         }
05553     }
05554 
05555     /* Loop over the different DITs found in EXPTIMEs */
05556     for (i = 0; i < ndiffdits; i++) {
05557         int c_nons;
05558         int c_noffs = 0; /* False (uninit) warning */
05559 
05560     double c_dit = 0;
05561     int c_ndit = 1;
05562 
05563         c_dit=cpl_vector_get(diffdits, i);
05564 
05565     if(opt_nir) {
05566       c_ndit=(int)cpl_vector_get(diffndits, i);
05567     }
05568 
05569     c_onlist  = cpl_imagelist_new();
05570     c_nons = 0;
05571 
05572     if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
05573         c_offlist = cpl_imagelist_new();
05574         c_noffs = 0;
05575     }
05576 
05577     /* Extraction of images of EXPTIME i */
05578     for(j = 0; j < ndits; j++) {
05579         if (fabs(c_dit - cpl_vector_get(exptimes, j)) <= tolerance) {
05580                 /*
05581                  * First we get the corresponding image from the ON imlist.
05582                  * The option IRPLIB_GAIN_WITH_RESCALE requires to modify
05583                  * the input pixel buffer; therefore we must duplicate it.
05584                  * On the other hand, if this option is not required, there
05585                  * is no need for that duplication. We must only care that
05586                  * c_onlist must not be deleted but only unset.
05587                  */
05588                 cpl_image * im_on;
05589                 if (mode & IRPLIB_GAIN_WITH_RESCALE) {
05590                     const cpl_image * im =
05591                         cpl_imagelist_get_const(imlist_on, j);
05592                     im_on = cpl_image_duplicate(im);
05593                 } else {
05594                     im_on = (cpl_image *)cpl_imagelist_get_const(imlist_on, j);
05595                 }
05596                 skip_if(cpl_imagelist_set(c_onlist, im_on, c_nons));
05597                 c_nons++;
05598 
05599                 /*
05600                  * Same explanation as above but for OFF imlist.
05601                  * Only necessary when IRPLIB_GAIN_NO_COLLAPSE required.
05602                  */
05603         if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
05604                     cpl_image * im_off;
05605                     if (mode & IRPLIB_GAIN_WITH_RESCALE) {
05606                         const cpl_image * im =
05607                           cpl_imagelist_get_const(imlist_off, j);
05608                         im_off = cpl_image_duplicate(im);
05609                     } else {
05610                         im_off =
05611                           (cpl_image *) cpl_imagelist_get_const(imlist_off, j);
05612                     }
05613             skip_if(cpl_imagelist_set(c_offlist, im_off, c_noffs));
05614             c_noffs++;
05615         }
05616         }
05617     }
05618 
05619     /* If NO_COLLAPSE, must be the same number of images! */
05620     if (mode & IRPLIB_GAIN_NO_COLLAPSE)
05621         skip_if (c_nons != c_noffs);
05622 
05623     /* There must be pairs! */
05624     skip_if (c_nons == 0 || c_nons % 2 != 0);
05625 
05626     /* Rescaling */
05627     if(mode & IRPLIB_GAIN_WITH_RESCALE) {
05628         skip_if(irplib_detmon_lg_rescale(c_onlist));
05629         if (mode & IRPLIB_GAIN_NO_COLLAPSE)
05630         skip_if(irplib_detmon_lg_rescale(c_offlist));
05631     }
05632 
05633     /* The following loop is necessary for the case of multiple pairs
05634        of same EXPTIME values */
05635     while(c_nons > 0) {
05636         int rows_affected = 1;
05637         skip_if(irplib_detmon_gain_table_fill_row(gain_table,
05638                               c_dit,c_ndit,
05639                               autocorrlist,
05640                               difflist, c_onlist,
05641                               c_offlist, kappa, nclip,
05642                                                       llx, lly, urx, ury,
05643                                                       xshift, yshift,1E10,  i,
05644 mode, &rows_affected));
05645         if (rows_affected)
05646         {
05647             rows_in_gain++;
05648         }
05649             if (mode & IRPLIB_GAIN_WITH_RESCALE) {
05650                 cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
05651                 cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
05652                 if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
05653                   cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
05654                   cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
05655                 }
05656             } else {
05657             cpl_imagelist_unset(c_onlist, 0);
05658                 skip_if(0);
05659                 cpl_imagelist_unset(c_onlist, 0);
05660                 skip_if(0);
05661                 if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
05662                   cpl_imagelist_unset(c_offlist, 0);
05663                   skip_if(0);
05664                   cpl_imagelist_unset(c_offlist, 0);
05665                   skip_if(0);
05666                 }
05667             }
05668             skip_if(0);
05669         c_nons -= 2;
05670     }
05671 
05672     cpl_imagelist_delete(c_onlist);
05673     if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
05674           cpl_imagelist_delete(c_offlist);
05675     }
05676     }
05677 
05678     skip_if(cpl_propertylist_append_string(qclist, DETMON_QC_METHOD, method));
05679     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_METHOD,
05680                      DETMON_QC_METHOD_C));
05681 
05682     /* Computation of GAIN via polynomial fit */
05683     if (mode & IRPLIB_GAIN_PTC) {
05684       skip_if(irplib_detmon_lg_qc_ptc(gain_table, qclist, mode, rows_in_gain));
05685     } else {
05686     skip_if(irplib_detmon_lg_qc_med(gain_table, qclist, rows_in_gain));
05687     }
05688 
05689     if(mode & IRPLIB_GAIN_WITH_AUTOCORR) {
05690         double autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
05691     skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_AUTOCORR,
05692                            autocorr));
05693     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_AUTOCORR,
05694                          DETMON_QC_AUTOCORR_C));
05695     }
05696 
05697     if (diff_imlist != NULL) *diff_imlist = difflist;
05698     if (autocorr_imlist != NULL) *autocorr_imlist = autocorrlist;
05699 
05700     end_skip;
05701 
05702     cpl_vector_delete(diffdits);
05703     cpl_vector_delete(diffndits);
05704 
05705     return gain_table;
05706 }
05707 
05708 static cpl_error_code
05709 irplib_detmon_gain_table_create(cpl_table * gain_table,
05710                                 const cpl_boolean opt_nir)
05711 {
05712     if (opt_nir == NIR) {
05713     skip_if(cpl_table_new_column(gain_table, "DIT",     CPL_TYPE_DOUBLE));
05714     skip_if(cpl_table_new_column(gain_table, "NDIT",     CPL_TYPE_INT));
05715     } else { /* OPT */
05716     skip_if(cpl_table_new_column(gain_table, "EXPTIME", CPL_TYPE_DOUBLE));
05717     }
05718     skip_if(cpl_table_new_column(gain_table, "MEAN_ON1",    CPL_TYPE_DOUBLE));
05719     skip_if(cpl_table_new_column(gain_table, "MEAN_ON2",    CPL_TYPE_DOUBLE));
05720     skip_if(cpl_table_new_column(gain_table, "MEAN_OFF1",   CPL_TYPE_DOUBLE));
05721     skip_if(cpl_table_new_column(gain_table, "MEAN_OFF2",   CPL_TYPE_DOUBLE));
05722     skip_if(cpl_table_new_column(gain_table, "SIG_ON_DIF",  CPL_TYPE_DOUBLE));
05723     skip_if(cpl_table_new_column(gain_table, "SIG_OFF_DIF", CPL_TYPE_DOUBLE));
05724     skip_if(cpl_table_new_column(gain_table, "GAIN",        CPL_TYPE_DOUBLE));
05725     skip_if(cpl_table_new_column(gain_table, "AUTOCORR",    CPL_TYPE_DOUBLE));
05726     skip_if(cpl_table_new_column(gain_table, "GAIN_CORR",   CPL_TYPE_DOUBLE));
05727     skip_if(cpl_table_new_column(gain_table, "ADU",         CPL_TYPE_DOUBLE));
05728     skip_if(cpl_table_new_column(gain_table, "X_FIT",       CPL_TYPE_DOUBLE));
05729     skip_if(cpl_table_new_column(gain_table, "X_FIT_CORR",  CPL_TYPE_DOUBLE));
05730     skip_if(cpl_table_new_column(gain_table, "Y_FIT",       CPL_TYPE_DOUBLE));
05731     skip_if(cpl_table_new_column(gain_table, "Y_FIT_CORR",  CPL_TYPE_DOUBLE));
05732     skip_if(cpl_table_new_column(gain_table, "FLAG",  CPL_TYPE_INT));
05733 
05734     end_skip;
05735 
05736     return cpl_error_get_code();
05737 }
05738 
05739 static cpl_error_code
05740 irplib_detmon_lin_table_create(cpl_table * lin_table,
05741                                const cpl_boolean opt_nir)
05742 {
05743     if (opt_nir == NIR) {
05744     skip_if(cpl_table_new_column(lin_table, "DIT",     CPL_TYPE_DOUBLE));
05745     } else { /* OPT */
05746     skip_if(cpl_table_new_column(lin_table, "EXPTIME", CPL_TYPE_DOUBLE));
05747     }
05748     skip_if(cpl_table_new_column(lin_table, "MED",      CPL_TYPE_DOUBLE));
05749     skip_if(cpl_table_new_column(lin_table, "MEAN",     CPL_TYPE_DOUBLE));
05750     skip_if(cpl_table_new_column(lin_table, "MED_DIT",  CPL_TYPE_DOUBLE));
05751     skip_if(cpl_table_new_column(lin_table, "MEAN_DIT", CPL_TYPE_DOUBLE));
05752     skip_if(cpl_table_new_column(lin_table, "ADL",      CPL_TYPE_DOUBLE));
05753     end_skip;
05754 
05755     return cpl_error_get_code();
05756 }
05757 
05758 static cpl_vector *
05759 irplib_detmon_lg_find_dits(const cpl_vector * exptimes,
05760                            double             tolerance)
05761 {
05762     cpl_vector * dits  = cpl_vector_new(cpl_vector_get_size(exptimes) / 2);
05763     int          ndits = 0;
05764 
05765     int          i, j;
05766 
05767     /* First different EXPTIME */
05768     cpl_vector_set(dits, 0, cpl_vector_get(exptimes, 0));
05769     ndits = 1;
05770 
05771     /* Search for all different EXPTIMEs */
05772     for(i = 1; i < cpl_vector_get_size(exptimes); i++) {
05773       int ndiffs = 0;
05774     for (j = 0; j < ndits; j++) {
05775         if (fabs(cpl_vector_get(exptimes, i) -
05776              cpl_vector_get(dits,     j)) > tolerance)
05777               ndiffs++;
05778     }
05779         if(ndiffs == ndits) {
05780           cpl_vector_set(dits, ndits, cpl_vector_get(exptimes, i));
05781           ndits++;
05782         }
05783     }
05784 
05785     cpl_vector_set_size(dits, ndits);
05786 
05787     return dits;
05788 }
05789 
05790 
05791 
05792 
05793 static cpl_error_code
05794 irplib_detmon_lg_find_dits_ndits(const cpl_vector * exptimes,
05795                const cpl_vector * vec_ndits,
05796                            double             tolerance,
05797                            cpl_vector** diff_dits,
05798                cpl_vector** diff_ndits)
05799 {
05800     int          ndits = 0;
05801 
05802     int          i, j;
05803     int size=0;
05804 
05805 
05806     * diff_dits = cpl_vector_new(cpl_vector_get_size(exptimes) / 2);
05807     * diff_ndits = cpl_vector_new(cpl_vector_get_size(*diff_dits));
05808 
05809     /* First different EXPTIME */
05810     cpl_vector_set(*diff_dits, 0, cpl_vector_get(exptimes, 0));
05811     cpl_vector_set(*diff_ndits, 0, cpl_vector_get(vec_ndits, 0));
05812 
05813     ndits = 1;
05814     size=cpl_vector_get_size(exptimes);
05815     /* Search for all different EXPTIMEs */
05816     for(i = 1; i < size; i++) {
05817       int ndiffs = 0;
05818     for (j = 0; j < ndits; j++) {
05819         if (fabs(cpl_vector_get(exptimes, i) -
05820              cpl_vector_get(*diff_dits,j)) > tolerance)
05821               ndiffs++;
05822     }
05823         if(ndiffs == ndits) {
05824           cpl_vector_set(*diff_dits, ndits, cpl_vector_get(exptimes, i));
05825           cpl_vector_set(*diff_ndits, ndits, cpl_vector_get(vec_ndits, i));
05826           ndits++;
05827         }
05828     }
05829 
05830     cpl_vector_set_size(*diff_dits, ndits);
05831     cpl_vector_set_size(*diff_ndits, ndits);
05832 
05833 
05834     return cpl_error_get_code();
05835 }
05836 
05837 
05838 /*---------------------------------------------------------------------------*/
05919 /*---------------------------------------------------------------------------*/
05920 
05921 cpl_table *
05922 irplib_detmon_lin(const cpl_imagelist  * imlist_on,
05923           const cpl_imagelist  * imlist_off,
05924           const cpl_vector     * exptimes,
05925           double                 tolerance,
05926           int                    llx,
05927           int                    lly,
05928           int                    urx,
05929           int                    ury,
05930           int                    order,
05931                   int                    ref_level,
05932                   double kappa,
05933                   cpl_boolean bpmbin,
05934           cpl_propertylist     * qclist,
05935           unsigned               mode,
05936           cpl_imagelist       ** coeffs_cube,
05937           cpl_image           ** bpm)
05938 {
05939     cpl_table     * lin_table    = NULL;
05940     cpl_imagelist * c_onlist     = NULL;
05941     cpl_imagelist * c_offlist    = NULL;
05942     cpl_vector    * diffdits     = NULL;
05943     cpl_imagelist * lin_inputs   = NULL;
05944     cpl_polynomial * poly_linfit = NULL;
05945     cpl_image     * fiterror     = NULL;
05946     cpl_vector    * vcoeffs      = NULL;
05947     double        * pcoeffs      = NULL;
05948     int             ndiffdits, ndits;
05949     int             i, j;
05950     cpl_boolean     opt_nir      = mode & IRPLIB_LIN_OPT ? OPT : NIR;
05951     const cpl_vector *x = NULL;
05952     const cpl_vector *y = NULL;
05953 
05954     const cpl_image * first = NULL;
05955     int sizex = 0;
05956     int sizey = 0;
05957 
05958     double vsize = 0;
05959 
05960 
05961     cpl_ensure(imlist_on  != NULL, CPL_ERROR_NULL_INPUT, NULL);
05962     cpl_ensure(imlist_off != NULL, CPL_ERROR_NULL_INPUT, NULL);
05963     cpl_ensure(exptimes   != NULL, CPL_ERROR_NULL_INPUT, NULL);
05964     cpl_ensure(qclist     != NULL, CPL_ERROR_NULL_INPUT, NULL);
05965     cpl_ensure(order      >  0   , CPL_ERROR_ILLEGAL_INPUT, NULL);
05966 
05967     vcoeffs      = cpl_vector_new(order + 1);
05968     pcoeffs      = cpl_vector_get_data(vcoeffs);
05969 
05970     /* This mode requires optional outputs */
05971     if (mode & IRPLIB_LIN_PIX2PIX) {
05972     lin_inputs = cpl_imagelist_new();
05973     cpl_ensure(coeffs_cube != NULL, CPL_ERROR_NULL_INPUT, NULL);
05974     cpl_ensure(bpm         != NULL, CPL_ERROR_NULL_INPUT, NULL);
05975     }
05976 
05977     /* Create table with columns */
05978     lin_table = cpl_table_new(cpl_vector_get_size(exptimes) / 2);
05979     skip_if(irplib_detmon_lin_table_create(lin_table, opt_nir));
05980 
05981     /* Search for different EXPTIME values */
05982     /* Search for different EXPTIME values */
05983     diffdits  = irplib_detmon_lg_find_dits(exptimes, tolerance);
05984     ndiffdits = cpl_vector_get_size(diffdits);
05985 
05986     ndits     = cpl_vector_get_size(exptimes);
05987 
05988 
05989 
05990 
05991 
05992 
05993 /* TO BE IMPLEMENTED SIMILARLY TO UPPER LEVEL FUNCTION (search for nskip)
05994    if(filter > 0) {
05995     double med1 =
05996         cpl_image_get_median_window(cpl_imagelist_get(imlist_on, 0),
05997                     llx,lly,urx,ury);
05998     double med2 =
05999            cpl_image_get_median_window(cpl_imagelist_get(imlist_on, 1),
06000                     llx,lly,urx,ury);
06001     if ( med1 > (double)filter ||
06002          med2 > (double)filter) {
06003         follow = CPL_FALSE;
06004         cpl_table_select_row(lin_table, dit_nb);
06005             dit_nskip++;
06006         cpl_msg_warning(cpl_func, "Frames of EXPTIME nb %d "
06007                 "will not be taken into account for computation "
06008                 "as they are above --filter threshold", dit_nb);
06009     }
06010     }
06011 */
06012 
06013 
06014 
06015 
06016     if (mode & IRPLIB_LIN_COLLAPSE) {
06017     /*
06018      * The master bias is required only for
06019      * linearity computation in the OPT domain
06020      */
06021     cpl_image * collapse = cpl_imagelist_collapse_create(imlist_off);
06022     skip_if(collapse == NULL);
06023 
06024     c_offlist = cpl_imagelist_new();
06025     skip_if(cpl_imagelist_set(c_offlist, collapse, 0));
06026     }
06027 
06028     /* Loop over the different DITs found in EXPTIMEs */
06029     for (i = 0; i < ndiffdits; i++) {
06030         int c_nons;
06031         int c_noffs = 0; /* False (uninit) warning */
06032 
06033     double c_dit = cpl_vector_get(diffdits, i);
06034 
06035     c_onlist  = cpl_imagelist_new();
06036     c_nons = 0;
06037 
06038     if (mode & IRPLIB_LIN_NO_COLLAPSE) {
06039         c_offlist = cpl_imagelist_new();
06040         c_noffs = 0;
06041     }
06042 
06043     for(j = 0; j < ndits; j++) {
06044         if (fabs(c_dit - cpl_vector_get(exptimes, j)) <= tolerance) {
06045                 /*
06046                  * First we get the corresponding image from the ON imlist.
06047                  * The option IRPLIB_GAIN_WITH_RESCALE requires to modify
06048                  * the input pixel buffer; therefore we must duplicate it.
06049                  * On the other hand, if this option is not required, there
06050                  * is no need for that duplication. We must only care that
06051                  * c_onlist must not be deleted but only unset.
06052                  */
06053                 cpl_image * im_on;
06054                 if (mode & IRPLIB_LIN_WITH_RESCALE) {
06055                     const cpl_image * im =
06056                         cpl_imagelist_get_const(imlist_on, j);
06057                     im_on = cpl_image_duplicate(im);
06058                 } else {
06059                     im_on = (cpl_image *)cpl_imagelist_get_const(imlist_on, j);
06060                 }
06061                 skip_if(cpl_imagelist_set(c_onlist, im_on, c_nons));
06062                 c_nons++;
06063 
06064                 /*
06065                  * Same explanation as above but for OFF imlist.
06066                  * Only necessary when IRPLIB_GAIN_NO_COLLAPSE required.
06067                  */
06068         if (mode & IRPLIB_LIN_NO_COLLAPSE) {
06069                     cpl_image * im_off;
06070                     if (mode & IRPLIB_LIN_WITH_RESCALE) {
06071                         const cpl_image * im =
06072                           cpl_imagelist_get_const(imlist_off, j);
06073                         im_off = cpl_image_duplicate(im);
06074                     } else {
06075                         im_off =
06076                           (cpl_image *) cpl_imagelist_get_const(imlist_off, j);
06077                     }
06078             skip_if(cpl_imagelist_set(c_offlist, im_off, c_noffs));
06079             c_noffs++;
06080         }
06081         }
06082     }
06083 
06084     /* If NO_COLLAPSE, must be the same number of images! */
06085     if (mode & IRPLIB_LIN_NO_COLLAPSE)
06086         skip_if (c_nons != c_noffs);
06087 
06088     /* There must be pairs! */
06089     skip_if (c_nons == 0 || c_nons % 2 != 0);
06090 
06091     /* Rescaling */
06092     if(mode & IRPLIB_LIN_WITH_RESCALE) {
06093         skip_if(irplib_detmon_lg_rescale(c_onlist));
06094         if (mode & IRPLIB_LIN_NO_COLLAPSE)
06095         skip_if(irplib_detmon_lg_rescale(c_offlist));
06096     }
06097 
06098     /* The following loop is necessary for the case of multiple pairs
06099        of same EXPTIME values */
06100     while(c_nons > 0) {
06101 
06102         skip_if(irplib_detmon_lin_table_fill_row(lin_table, c_dit,
06103                              lin_inputs,
06104                              c_onlist, c_offlist,
06105                              llx, lly, urx, ury,
06106                              i, 0, mode));
06107 
06108             if (mode & IRPLIB_LIN_WITH_RESCALE) {
06109                 cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
06110                 cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
06111                 if (mode & IRPLIB_LIN_NO_COLLAPSE) {
06112                   cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
06113                   cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
06114                 }
06115             } else {
06116             cpl_imagelist_unset(c_onlist, 0);
06117                 skip_if(0);
06118                 cpl_imagelist_unset(c_onlist, 0);
06119                 skip_if(0);
06120                 if (mode & IRPLIB_LIN_NO_COLLAPSE) {
06121                   cpl_imagelist_unset(c_offlist, 0);
06122                   skip_if(0);
06123                   cpl_imagelist_unset(c_offlist, 0);
06124                   skip_if(0);
06125                 }
06126             }
06127             skip_if(0);
06128         c_nons -= 2;
06129     }
06130 
06131     cpl_imagelist_delete(c_onlist);
06132     if (mode & IRPLIB_LIN_NO_COLLAPSE) {
06133           cpl_imagelist_delete(c_offlist);
06134     }
06135     }
06136 
06137     skip_if(irplib_detmon_add_adl_column(lin_table, opt_nir));
06138 
06139     if(!(mode & IRPLIB_LIN_PIX2PIX)) {
06140     double mse = 0;
06141         /* Computation of LINEARITY via polynomial fit */
06142     y = cpl_vector_wrap(cpl_table_get_nrow(lin_table),
06143                 (double *)cpl_table_get_data_double_const(lin_table,
06144                                   "MED"));
06145         if (opt_nir == NIR) {
06146            x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
06147                              (double *)cpl_table_get_data_double_const(lin_table,                                                                                                 "DIT"));
06148         } else {
06149            x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
06150                              (double *)cpl_table_get_data_double_const(lin_table,                                                                                                 "EXPTIME"));
06151         }
06152         if(x == NULL || y == NULL) {
06153         cpl_vector_unwrap((cpl_vector *)x);
06154         cpl_vector_unwrap((cpl_vector *)y);
06155         /*
06156          * As x and y are const vectors, if they would be defined at the
06157          * beginning of the function (required for skip_if - end_skip
06158          * scheme), they couldn't be initialised to NULL (required too).
06159          * Therefore, they are considered apart from the scheme.
06160          */
06161         skip_if(1);
06162     }
06163 
06164         cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
06165         poly_linfit = irplib_polynomial_fit_1d_create_chiq(x, y, order, &mse);
06166 
06167     if(order == cpl_vector_get_size(x) - 1) {
06168         cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
06169         mse = 0;
06170     }
06171 
06172     if(poly_linfit == NULL) {
06173         cpl_vector_unwrap((cpl_vector *)x);
06174         cpl_vector_unwrap((cpl_vector *)y);
06175         /* See comment in previous error checking if() statement */
06176         skip_if(1);
06177     }
06178 
06179     cpl_vector_unwrap((cpl_vector *)x);
06180     cpl_vector_unwrap((cpl_vector *)y);
06181 
06182         for(i = 0; i <= order; i++) {
06183             const double            coeff =
06184                 cpl_polynomial_get_coeff(poly_linfit, &i);
06185             char                   *name_o =
06186                 cpl_sprintf("ESO QC LIN COEF%d", i);
06187             assert(name_o != NULL);
06188             skip_if(cpl_propertylist_append_double(qclist, name_o, coeff));
06189             skip_if(cpl_propertylist_set_comment(qclist,name_o,
06190                          DETMON_QC_LIN_COEF_C));
06191             cpl_free(name_o);
06192         pcoeffs[i] = coeff;
06193         }
06194     skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT, mse));
06195             skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
06196                          DETMON_QC_ERRFIT_MSE_C));
06197 
06198 
06199     } else {
06200        if (opt_nir == NIR) {
06201           x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
06202                 (double *)cpl_table_get_data_double_const(lin_table,
06203                                                                       "DIT"));
06204        } else {
06205           x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
06206                 (double *)cpl_table_get_data_double_const(lin_table,
06207                                                                       "EXPTIME"));
06208        }
06209 
06210 
06211        first = cpl_imagelist_get_const(lin_inputs, 0);
06212        sizex = cpl_image_get_size_x(first);
06213        sizey = cpl_image_get_size_y(first);
06214 
06215        vsize = cpl_vector_get_size(x);
06216 
06217     fiterror = cpl_image_new(sizex, sizey, CPL_TYPE_FLOAT);
06218 
06219         *coeffs_cube =
06220             cpl_fit_imagelist_polynomial(x, lin_inputs, 0,
06221                                          order, FALSE, CPL_TYPE_FLOAT,
06222                      fiterror);
06223 
06224     cpl_vector_unwrap((cpl_vector*)x);
06225     irplib_ensure(*coeffs_cube != NULL, CPL_ERROR_UNSPECIFIED,
06226               "Failed polynomial fit");
06227 
06228         for(i = 0; i <= order; i++) {
06229             cpl_image              *image = cpl_imagelist_get(*coeffs_cube, i);
06230         const double coeff = cpl_image_get_median(image);
06231             char * name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
06232             char * name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
06233         pcoeffs[i] = coeff;
06234             assert(name_o1 != NULL);
06235             assert(name_o2 != NULL);
06236             skip_if(cpl_propertylist_append_double(qclist, name_o1, coeff));
06237             skip_if(cpl_propertylist_set_comment(qclist,name_o1,
06238                          DETMON_QC_LIN_COEF_C));
06239             cpl_free(name_o1);
06240         name_o1= NULL;
06241             skip_if(cpl_propertylist_append_double(qclist, name_o2,
06242                        cpl_image_get_stdev(image)));
06243             skip_if(cpl_propertylist_set_comment(qclist,name_o2,
06244                          DETMON_QC_LIN_COEF_ERR_C));
06245             cpl_free(name_o2);
06246         name_o2= NULL;
06247         }
06248 
06249     if(order == vsize - 1) {
06250         cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
06251         skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
06252                            0.0));
06253             skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
06254                          DETMON_QC_ERRFIT_C));
06255 
06256 
06257     } else {
06258         skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
06259                            cpl_image_get_median(fiterror)));
06260             skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
06261                          DETMON_QC_ERRFIT_C));
06262 
06263     }
06264     }
06265 
06266     skip_if(irplib_detmon_lg_lineff(pcoeffs, qclist, ref_level, order));
06267 
06268     if(mode & IRPLIB_LIN_PIX2PIX) {
06269     int nbpixs;
06270         *bpm = irplib_detmon_bpixs(*coeffs_cube, bpmbin, kappa, &nbpixs);
06271     skip_if(*bpm == NULL);
06272     skip_if(cpl_propertylist_append_int(qclist, DETMON_QC_NUM_BPM,
06273                         nbpixs));
06274     skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_NUM_BPM,
06275                          DETMON_QC_NUM_BPM_C));
06276     }
06277 
06278     end_skip;
06279 
06280     cpl_vector_delete(diffdits);
06281     cpl_polynomial_delete(poly_linfit);
06282     cpl_imagelist_delete(lin_inputs);
06283     cpl_vector_delete(vcoeffs);
06284     cpl_image_delete(fiterror);
06285 
06286     return lin_table;
06287 
06288 }
06289 
06290 /*--------------------------------------------------------------------------*/
06314 /*--------------------------------------------------------------------------*/
06315 static cpl_error_code
06316 irplib_detmon_lin_table_fill_row(cpl_table * lin_table, double c_dit,
06317                  cpl_imagelist * linearity_inputs,
06318                  const cpl_imagelist * ons,
06319                  const cpl_imagelist * offs,
06320                  int llx,
06321                  int lly,
06322                  int urx,
06323                  int ury,
06324                  const int pos,
06325                                  const int nskip,
06326                  unsigned mode)
06327 {
06328     cpl_image              * dif1=NULL;
06329     cpl_image              * dif2=NULL;
06330     cpl_image              * dif_avg=NULL;
06331 
06332     double                   med_dit=0;
06333     double                   mean_dit=0;
06334     cpl_error_code           error;
06335     cpl_image * extracted=NULL;
06336     int offsize=0;
06337 
06338     cpl_ensure_code(lin_table != NULL, CPL_ERROR_NULL_INPUT);
06339     cpl_ensure_code(ons != NULL, CPL_ERROR_NULL_INPUT);
06340     cpl_ensure_code(offs != NULL, CPL_ERROR_NULL_INPUT);
06341 
06342     if (mode & IRPLIB_LIN_PIX2PIX) {
06343        cpl_msg_debug(cpl_func,"checking linearity inputs");
06344     cpl_ensure_code(linearity_inputs != NULL, CPL_ERROR_NULL_INPUT);
06345     }
06346 
06347 
06348     if (mode & IRPLIB_LIN_NIR) {
06349     cpl_table_set(lin_table, "DIT", pos, c_dit);
06350     } else if (mode & IRPLIB_LIN_OPT) { /*OPT */
06351         cpl_table_set(lin_table, "EXPTIME", pos, c_dit);
06352     } else {
06353     cpl_msg_error(cpl_func, "Mandatory mode not given");
06354     }
06355 
06356     offsize = cpl_imagelist_get_size(offs);
06357 
06358     /* Algorithm defined: substract ON - OFF and average 2 differences */
06359     dif1 = cpl_image_subtract_create(cpl_imagelist_get_const(ons, 0),
06360                                      cpl_imagelist_get_const(offs, 0));
06361 
06362     if (mode & IRPLIB_LIN_NO_COLLAPSE && offsize > 1)
06363         dif2 = cpl_image_subtract_create(cpl_imagelist_get_const(ons, 1),
06364                                          cpl_imagelist_get_const(offs, 1));
06365     else
06366         dif2 = cpl_image_subtract_create(cpl_imagelist_get_const(ons, 1),
06367                                          cpl_imagelist_get_const(offs, 0));
06368 
06369     dif_avg = cpl_image_average_create(dif1, dif2);
06370 
06371     cpl_image_abs(dif_avg);
06372     extracted = cpl_image_extract(dif_avg, llx, lly, urx, ury);
06373 
06374     cpl_ensure_code(extracted != NULL, cpl_error_get_code());
06375 
06376     cpl_table_set(lin_table, "MED", pos, cpl_image_get_median(extracted));
06377     cpl_table_set(lin_table, "MEAN", pos, cpl_image_get_mean(extracted));
06378     med_dit = cpl_image_get_median(extracted) / c_dit;
06379     mean_dit = cpl_image_get_mean(extracted)  / c_dit;
06380 
06381     cpl_table_set(lin_table, "MED_DIT", pos, med_dit);
06382     cpl_table_set(lin_table, "MEAN_DIT", pos, mean_dit);
06383 
06384     cpl_image_delete(dif1);
06385     cpl_image_delete(dif2);
06386 
06387     /* Insert to the imagelist used to fit the polynomial */
06388     if(mode & IRPLIB_LIN_PIX2PIX) {
06389         error = cpl_imagelist_set(linearity_inputs, extracted, pos-nskip);
06390         cpl_ensure_code(!error, error);
06391     } else {
06392         cpl_image_delete(extracted);
06393     }
06394 
06395 
06396     cpl_image_delete(dif_avg);
06397 
06398     return cpl_error_get_code();
06399 }
06400 
06401 static double irplib_calculate_total_noise_smooth(const cpl_image* pimage, int pattern_x, int pattern_y)
06402 {
06403     cpl_image * p_tmp_image = 0;
06404     cpl_image * psmooth_image = 0;
06405     double ret_noise = -1;
06406     cpl_mask * mask = cpl_mask_new(pattern_x, pattern_y);
06407     cpl_mask_not(mask);
06408     p_tmp_image = cpl_image_duplicate(pimage);
06409     cpl_image_filter_mask(p_tmp_image,pimage, mask,CPL_FILTER_MEDIAN ,CPL_BORDER_FILTER);
06410     cpl_image_divide_scalar(p_tmp_image, cpl_image_get_median(pimage));
06411     psmooth_image  = cpl_image_divide_create(pimage,p_tmp_image);
06412     ret_noise = irplib_calculate_total_noise(psmooth_image);
06413     cpl_mask_delete(mask);
06414     cpl_image_delete(psmooth_image);
06415     cpl_image_delete(p_tmp_image);
06416     return ret_noise;
06417 }
06418 static double irplib_calculate_total_noise(const cpl_image* pimage)
06419 {
06420     double total_noise = -1;
06421     unsigned long max_bin_size = 1E5;
06422     const double  hstart = cpl_image_get_min(pimage);
06423     const double  hrange = cpl_image_get_max(pimage) - hstart;
06424     const unsigned long nbins  = max_bin_size;
06425     cpl_error_code err = CPL_ERROR_NONE;
06426     /* apply histogram method */
06427     irplib_hist * phist = 0;
06428     phist = irplib_hist_new();
06429     /* 2 extra-bins for possible out-of-range values */
06430 
06431     irplib_hist_init(phist, nbins, hstart, hrange);
06432     err = irplib_hist_fill(phist, pimage);
06433     if (err == CPL_ERROR_NONE)
06434     {
06435         unsigned int i = 0;
06436         double x0 = 0;
06437         double area = 0;
06438         double offset = 0;
06439 
06440         /* prepare vector */
06441         unsigned long n_bins = irplib_hist_get_nbins(phist);
06442         double start = irplib_hist_get_start(phist);
06443         double bin_size = irplib_hist_get_bin_size(phist);
06444         cpl_vector* pdata_vector = cpl_vector_new(n_bins);
06445         cpl_vector* ppos_vector = cpl_vector_new(n_bins);
06446         cpl_table* ptable = cpl_table_new(n_bins);
06447         cpl_table_new_column(ptable, "bin", CPL_TYPE_DOUBLE);
06448         cpl_table_new_column(ptable, "value", CPL_TYPE_DOUBLE);
06449         for(i = 0; i < n_bins; i++)
06450         {
06451             unsigned int value = irplib_hist_get_value(phist, i);
06452             double dvalue = (double)(value);
06453             cpl_vector_set(pdata_vector, i, dvalue);
06454             cpl_vector_set(ppos_vector, i, start + i * bin_size);
06455 
06456             cpl_table_set(ptable, "bin", i, start + i * bin_size);
06457             cpl_table_set(ptable, "value", i, dvalue);
06458         }
06459         err = cpl_vector_fit_gaussian(ppos_vector, NULL, pdata_vector, NULL, CPL_FIT_ALL, &x0, &total_noise, &area, &offset, NULL, NULL, NULL );
06460         if (err == CPL_ERROR_NONE)
06461         {
06462             cpl_msg_info(cpl_func, "FPN Calculation: histogram x0[%f] total_noise[%f] area[%f] offset[%f]", x0, total_noise, area, offset);
06463         }
06464         else
06465         {
06466             cpl_msg_warning(cpl_func, "FPN could not be computed due failed Gaussian Fit,  err msg [%s]", cpl_error_get_message());
06467             cpl_error_reset();
06468         }
06469         cpl_table_delete(ptable);
06470         cpl_vector_delete(ppos_vector);
06471         cpl_vector_delete(pdata_vector);
06472     }
06473     else
06474     {
06475         cpl_msg_warning(cpl_func, "FPN could not be computed due failed histogram computation, err msg [%s]", cpl_error_get_message());
06476         cpl_error_reset();
06477     }
06478     irplib_hist_delete(phist);
06479 
06480     return total_noise;
06481 }
06482 
06483 static double irplib_compute_err(double gain, double ron, double FA)
06484 {
06485     double int_gain = (gain * gain - 1) / 12;
06486     if (int_gain < 0)
06487     {
06488         int_gain = 0;
06489     }
06490     return sqrt(ron * ron + FA / gain + int_gain);
06491 }
06492 static double irplib_fpn_lg(const cpl_image* f1, int* range, double gain ,
06493         FPN_METHOD fpn_method, int smooth_size, double* mse)
06494 {
06495     cpl_image* im_diff = 0;
06496     const cpl_image* im_f1 = f1;
06497     cpl_image* im_inrange1 = 0;
06498     double FA = 0;
06499     double s_tot = 0; /* absolute total noise */
06500     double s_fpn = 0; /* fixed pattern noise */
06501     double sr_fpn = 0; /* relative structural noise */
06502     /*che cinput*/
06503     if (gain<=0) {
06504      /* put dummy values Negative to indicate a problem occurred
06505        (FPN should be always positive) */
06506        cpl_msg_warning(cpl_func,"gain[%f]<0", gain);
06507        cpl_msg_warning(cpl_func,"We set dummy values for FPN");
06508        s_fpn=-999.;
06509        sr_fpn=-999;
06510        return sr_fpn;
06511     }
06512     if (range)
06513     {
06514         im_inrange1 = cpl_image_extract(f1, range[0], range[1], range[2], range[3]);
06515         im_f1 = im_inrange1;
06516     }
06517     FA = cpl_image_get_median(im_f1);
06518 
06519     /* apply histogram method */
06520         /* Is this irplib function giving the right result?? */
06521     switch (fpn_method)
06522     {
06523     case FPN_SMOOTH:
06524         cpl_msg_info(cpl_func,"SMOOTH method is used for FPN, pattern size[%d x %d] pixels",smooth_size,smooth_size );
06525         s_tot = irplib_calculate_total_noise_smooth(im_f1,smooth_size,smooth_size);
06526         break;
06527     case FPN_HISTOGRAM:
06528         cpl_msg_info(cpl_func,"HISTOGRAM method is used for FPN");
06529         s_tot = irplib_calculate_total_noise(im_f1);
06530         break;
06531     default:
06532         s_tot = -1;
06533         sr_fpn = -1;
06534         cpl_msg_warning(cpl_func,"fpn_method is not defined");
06535         break;
06536     }
06537     if (s_tot > 0)
06538     {
06539         if (FA<0)
06540         {
06541           /* put dummy values Negative to indicate a problem occurred
06542            (FPN should be always positive) */
06543            cpl_msg_warning(cpl_func,"Median flux on sum of flats<0");
06544            cpl_msg_warning(cpl_func,"We set dummy values for FPN");
06545            s_fpn=-999.;
06546            sr_fpn=-999;
06547         }
06548 
06549         if ((s_tot * s_tot - FA / gain) > 0)
06550         {
06551            s_fpn = sqrt(s_tot * s_tot - FA / gain);
06552            sr_fpn = s_fpn / FA;
06553            *mse = (irplib_compute_err(gain, 0, FA)) * gain / FA;
06554         } else {
06555           /* put dummy values Negative to indicate a problem occurred
06556            (FPN should be always positive) */
06557            cpl_msg_warning(cpl_func,"s_tot * s_tot < FA / gain");
06558            cpl_msg_warning(cpl_func,"We set dummy values for FPN");
06559            s_fpn=-999.;
06560            sr_fpn=-999;
06561            *mse = -1;
06562         }
06563 /*
06564         cpl_msg_debug(cpl_func, "FPN Calculation: FA[%f] s_tot[%f] photon_noise[%f] s_fpn[%f] sr_fpn[%f] mse[%f]", FA, s_tot, photon_noise, s_fpn, sr_fpn, *mse);
06565 */
06566     }
06567     cpl_image_delete(im_diff);
06568     if (range)
06569     {
06570         cpl_image_delete(im_inrange1);
06571     }
06572     return sr_fpn;
06573 }
06574 
06575 static cpl_imagelist * irplib_load_fset_wrp(const cpl_frameset * pframeset, cpl_type type , int whichext)
06576 {
06577     cpl_imagelist * ret = 0;
06578     ret =  cpl_imagelist_load_frameset(pframeset, type,
06579             1, whichext);
06580     if (ret)
06581     {
06582         /* check the images for size*/
06583         int sz = cpl_imagelist_get_size(ret);
06584         int i = 0;
06585         for(i = 0; i < sz; i ++)
06586         {
06587             cpl_image* pimage = 0;
06588             pimage = cpl_imagelist_get(ret, i);
06589             if (pimage)
06590             {
06591                 int size_x = 0;
06592                 int size_y = 0;
06593                 size_x = cpl_image_get_size_x(pimage);
06594                 size_y = cpl_image_get_size_y(pimage);
06595                 if (detmon_lg_config.nx != size_x || detmon_lg_config.ny != size_y)
06596                 {
06597                     cpl_msg_error(cpl_func, "All images in the input should have the same size,\n" \
06598                             " image #%d has size x[%d] y[%d], expected size  x[%d] y[%d]", i, size_x, size_y,
06599                             detmon_lg_config.nx, detmon_lg_config.ny);
06600                     cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
06601                     cpl_imagelist_delete(ret);
06602                     ret = 0;
06603                 }
06604             }
06605         }
06606     }
06607     return ret;
06608 }
06609 
06610 static cpl_imagelist * irplib_load_fset_wrp_ext(const cpl_frameset * pframeset, cpl_type type , int whichext)
06611 {
06612    int i = whichext; /* fake code to avoid compiler warning */
06613     cpl_imagelist* offs = cpl_imagelist_new();
06614     detmon_lg_config.load_fset(pframeset, type, offs);
06615     i++;
06616     return offs;
06617 }
06618 
06619 static cpl_error_code irplib_table_create_column(cpl_table* ptable, cpl_propertylist* plist)
06620 {
06621     if (ptable && plist)
06622     {
06623         int size = cpl_propertylist_get_size(plist);
06624         int i = 0;
06625         for (i = 0; i < size; i++)
06626         {
06627             cpl_property* pprop = cpl_propertylist_get(plist,i);
06628             if (pprop)
06629             {
06630                 const char* pname = cpl_property_get_name(pprop);
06631                 if (pname)
06632                 {
06633                     cpl_table_new_column(ptable, pname, cpl_property_get_type(pprop));
06634                     if (cpl_error_get_code() != CPL_ERROR_NONE)
06635                     {
06636                         cpl_msg_warning(cpl_func, "cannot create new column[%s], err[%s]", pname, cpl_error_get_message());
06637                         break; /* leave the cycle */
06638                     }
06639                 }
06640             }
06641         }
06642     }
06643     return cpl_error_get_code();
06644 }
06645 
06646 static cpl_error_code irplib_fill_table_DETWINUIT(cpl_table* ptable, cpl_propertylist* plist, int row)
06647 {
06648     cpl_error_code err = CPL_ERROR_NONE;
06649     if (ptable && plist)
06650     {
06651         int size = cpl_propertylist_get_size(plist);
06652         int i = 0;
06653         for (i = 0; i < size; i++)
06654         {
06655             cpl_property* pprop = cpl_propertylist_get(plist,i);
06656             if (pprop)
06657             {
06658                 const char* pname = cpl_property_get_name(pprop);
06659                 double  value = cpl_property_get_double(pprop);
06660                 if (pname)
06661                 {
06662                     cpl_table_set_double(ptable, pname, row, value);
06663                     if (cpl_error_get_code() != CPL_ERROR_NONE)
06664                     {
06665                         cpl_msg_warning(cpl_func, "cannot write value to the table, column[%s] value[%f], err[%s]", pname, value, cpl_error_get_message());
06666                         cpl_error_reset();
06667                         break; /* leave the cycle */
06668                     }
06669                 }
06670             }
06671         }
06672     }
06673     return err;
06674 }
06675 cpl_error_code irplib_detmon_check_order(const double *exptime, int sz, double tolerance, int order)
06676 {
06677     int nsets = 0;
06678     int i = 0;
06679     /* 1. Determine number of groups */
06680 /*   cpl_msg_warning(cpl_func, "irplib_detmon_check_order sz[%i]", sz);*/
06681     do
06682     {
06683 /*      cpl_msg_warning(cpl_func, "irplib_detmon_check_order i[%i] exptime[%g]", i, exptime[i]);   */
06684         nsets++;
06685         do
06686         {
06687             i++;
06688             if(i == sz - 1)
06689             {
06690                 break;
06691             }
06692         } while(fabs(exptime[i-1] - exptime[i]) < tolerance);
06693     } while(i < sz - 1);
06694     /* the very last adjustment for the last group */
06695     if (!fabs(exptime[i-1] - exptime[i]) < tolerance) nsets++;
06696     if(nsets <= order)
06697     {
06698              cpl_error_set_message(cpl_func,CPL_ERROR_INCOMPATIBLE_INPUT,
06699                                    "Not enough frames for the polynomial"
06700                                    " fitting. nsets = %d <= %d order",
06701                                    nsets,order);
06702     }
06703     return cpl_error_get_code();
06704 }
06705 
06706 static cpl_error_code irplib_detmon_lg_dfs_save_imagelist(
06707         cpl_frameset * frameset,
06708         const cpl_parameterlist * parlist,
06709         const cpl_frameset *usedframes,
06710         const cpl_imagelist *coeffs,
06711         const char *recipe_name,
06712         const cpl_propertylist *mypro_coeffscube,
06713         const char * package,
06714         const char * name_o)
06715 {
06716        return(cpl_dfs_save_imagelist
06717            (frameset, NULL, parlist, usedframes, NULL,coeffs, CPL_BPP_IEEE_FLOAT,
06718         recipe_name, mypro_coeffscube, NULL, package,
06719         name_o));
06720 }
06721 static void irplib_detmon_lg_add_empty_image(cpl_imagelist* imlist, int pos)
06722 {
06723     const cpl_image* first = cpl_imagelist_get(imlist, 0);
06724     if (first)
06725     {
06726           int x = cpl_image_get_size_x(first);
06727           int y = cpl_image_get_size_y(first);
06728           cpl_type type = cpl_image_get_type(first);
06729           cpl_image * blank = cpl_image_new(x, y, type);
06730           cpl_imagelist_set(imlist, blank, pos);
06731     }
06732 }

Generated on 8 Mar 2011 for SINFONI Pipeline Reference Manual by  doxygen 1.6.1