irplib_detmon_lg.c

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

Generated on Thu Mar 24 11:59:39 2011 for VISIR Pipeline Reference Manual by  doxygen 1.5.8