GIRAFFE Pipeline Reference Manual

irplib_detmon_lg.c

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

This file is part of the GIRAFFE Pipeline Reference Manual 2.9.0.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Thu Jan 26 14:20:29 2012 by doxygen 1.6.3 written by Dimitri van Heesch, © 1997-2004