GIRAFFE Pipeline Reference Manual

irplib_detmon_lg.c

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

This file is part of the GIRAFFE Pipeline Reference Manual 2.8.7.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Fri Aug 6 13:56:43 2010 by doxygen 1.5.1 written by Dimitri van Heesch, © 1997-2004