detmon_lg.c

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

Generated on 9 Jan 2012 for DETMON Pipeline Reference Manual by  doxygen 1.6.1