irplib_detmon_lg.c

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

Generated on Tue Jun 29 12:20:51 2010 for VISIR Pipeline Reference Manual by  doxygen 1.4.7