irplib_detmon_lg.c

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

Generated on 13 Jun 2011 for DETMON Pipeline Reference Manual by  doxygen 1.6.1