irplib_detmon_lg.c

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

Generated on Tue Jun 29 12:16:39 2010 for NACO Pipeline Reference Manual by  doxygen 1.4.7