detmon_lg.c

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

Generated on 3 Mar 2013 for DETMON Pipeline Reference Manual by  doxygen 1.6.1