irplib_detmon.c

00001 
00002 /* $Id: irplib_detmon.c,v 1.60 2007/06/11 11:37:39 lbilbao Exp $
00003  *
00004  * This file is part of the irplib package
00005  * Copyright (C) 2002, 2003 European Southern Observatory
00006  *
00007  * This program is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
00020  */
00021 
00022 /*
00023  * $Author: lbilbao $
00024  * $Date: 2007/06/11 11:37:39 $
00025  * $Revision: 1.60 $
00026  * $Name: uves-3_3_1 $
00027  */
00028 
00029 #ifdef HAVE_CONFIG_H
00030 #include <config.h>
00031 #endif
00032 
00033 /*---------------------------------------------------------------------------
00034                                   Includes
00035  ---------------------------------------------------------------------------*/
00036 
00037 #ifdef HAVE_FFTW
00038 #include <complex.h>
00039 #include <fftw3.h>
00040 #endif
00041 
00042 #include <math.h>
00043 #include <string.h>
00044 #include <assert.h>
00045 
00046 #include <cpl.h>
00047 
00048 #include "irplib_detmon.h"
00049 
00050 #include "irplib_utils.h"
00051 #include "irplib_dfs.h"
00052 
00053 
00054 /*--------------------------------------------------------------------------*/
00055 
00056 /*
00057  * @defgroup irplib_detmon        Detector monitoring functions
00058  */
00059 
00060 /*--------------------------------------------------------------------------*/
00061 
00062 /*---------------------------------------------------------------------------
00063                                   Defines
00064  ---------------------------------------------------------------------------*/
00065 
00066 enum pixeltypes
00067 {
00068     HOT = 0,
00069     DEAD = 1,
00070     NOISY = 2
00071 };
00072 
00073 static struct
00074 {
00075     /* Inputs */
00076     int                     order;
00077     int                     kappa;
00078     int                     niter;
00079     int                     threshold_min;
00080     int                     threshold_max;
00081     int                     llx;
00082     int                     lly;
00083     int                     urx;
00084     int                     ury;
00085     int                     ref_level;
00086     int                     threshold;
00087     int                     m;
00088     int                     n;
00089     int                     llx1;
00090     int                     lly1;
00091     int                     urx1;
00092     int                     ury1;
00093     int                     llx2;
00094     int                     lly2;
00095     int                     urx2;
00096     int                     ury2;
00097     int                     llx3;
00098     int                     lly3;
00099     int                     urx3;
00100     int                     ury3;
00101     int                     llx4;
00102     int                     lly4;
00103     int                     urx4;
00104     int                     ury4;
00105     int                     llx5;
00106     int                     lly5;
00107     int                     urx5;
00108     int                     ury5;
00109     cpl_boolean             autocorr;
00110     cpl_boolean             intermediate;
00111     cpl_boolean             collapse;
00112     /* Outputs */
00113     double                  cr;
00114 } detmon_lg_config;
00115 
00116 #define NIR TRUE
00117 #define OPT FALSE
00118 
00119 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(3, 1, 90)
00120 #define irplib_sprintf  cpl_sprintf
00121 #endif
00122 
00123 /*---------------------------------------------------------------------------
00124                                   Private function prototypes
00125  ---------------------------------------------------------------------------*/
00126 
00127 static cpl_error_code
00128 irplib_detmon_retrieve_params(const char *,
00129                               const char *,
00130                               const cpl_parameterlist *);
00131 
00132 static cpl_error_code
00133 irplib_detmon_lg_split_onoff(const cpl_frameset *,
00134                              cpl_frameset *,
00135                              cpl_frameset *,
00136                              const char *, const char *, const cpl_boolean);
00137 
00138 int
00139 irplib_detmon_compare_dits(const cpl_frame *, const cpl_frame *);
00140 
00141 static cpl_error_code
00142 irplib_detmon_lg_reduce(const cpl_frameset *,
00143                         const cpl_frameset *,
00144                         const int *,
00145                         const int *,
00146                         const int,
00147                         cpl_imagelist **,
00148                         cpl_table **,
00149                         cpl_table **,
00150                         cpl_image **, cpl_propertylist *, const cpl_boolean);
00151 
00152 double
00153 irplib_pfits_get_exptime(const cpl_propertylist *);
00154 /*
00155 static double
00156 irplib_pfits_get_exptime(const cpl_propertylist *);
00157 */
00158 static cpl_error_code
00159 irplib_detmon_linearity(const cpl_frameset *,
00160                         cpl_table **,
00161                         cpl_table **,
00162                         cpl_imagelist **,
00163                         cpl_vector **,
00164                         const cpl_imagelist *,
00165                         const cpl_imagelist *,
00166                         const int,
00167                         const int, cpl_propertylist *, const cpl_boolean);
00168 
00169 static cpl_error_code
00170 irplib_detmon_gain(cpl_table **,
00171                    cpl_table **,
00172                    const cpl_imagelist *, const cpl_imagelist *, const int);
00173 
00174 static cpl_image *
00175 irplib_detmon_bpixs(const cpl_imagelist *, int *);
00176 
00177 static double
00178 irplib_detmon_autocorr_factor(const cpl_image *, const int);
00179 
00180 #ifdef HAVE_FFTW
00181 static cpl_image *
00182 irplib_detmon_image_autocorrelate_fftw(const cpl_image *,
00183                                        const int,
00184                                        const int);
00185 #endif
00186 
00187 static cpl_image *
00188 irplib_detmon_autocorrelate(const cpl_image *,
00189                             const int, const int);
00190 
00191 static int
00192 irplib_get_clean_mean_window(cpl_image *,
00193                              const int,
00194                              const int,
00195                              const int,
00196                              const int,
00197                              const int, const int, double *, double *);
00198 
00199 static cpl_error_code
00200 irplib_detmon_lg_save(const cpl_parameterlist *,
00201                       cpl_frameset *,
00202                       const char *,
00203                       const char *,
00204                       const char *,
00205                       const char *,
00206                       const char *,
00207                       const char *,
00208                       const char *,
00209                       const cpl_imagelist *,
00210                       const cpl_table *,
00211                       const cpl_table *,
00212                       const cpl_image *,
00213                       cpl_propertylist *,
00214                       const int, const int, cpl_frameset *, cpl_boolean);
00215 
00216 static cpl_error_code
00217 irplib_detmon_opt_contamination(const cpl_image *, cpl_propertylist *);
00218 
00219 static int
00220 irplib_detmon_opt_lampcr(cpl_frameset *);
00221 
00222 int
00223 irplib_detmon_dfs_set_groups(cpl_frameset *,
00224                              const char *,
00225                              const char *);
00226 
00227 static int
00228 irplib_detmon_retrieve_par(const char *,
00229                            const char *,
00230                            const char *,
00231                            const cpl_parameterlist *);
00232 
00233 int
00234 irplib_detmon_fill_parlist(cpl_parameterlist * parlist,
00235                            const char *recipe_name, const char *pipeline_name,
00236                            int npars, ...);
00237 
00238 
00239 /*--------------------------------------------------------------------------*/
00240 
00241 /*
00242  * @brief  Reduce linearity and gain in the IR domain
00243  * @param  parlist      List of required parameters
00244  * @param  frameset     Input frameset
00245  * @param  tag_on       Tag to identify the ON frames
00246  * @param  tag_off      Tag to identify the OFF frames
00247  * @param  recipe_name      Name of the recipe calling this function
00248  * @param  pipeline_name    Name of the pipeline calling this function
00249  * @param  procatg      PRO.CATG required for the DFS keywords
00250  * @param  package      PACKAGE (incl. VERSION) required
00251  *                              for the DFS keywords
00252  * @return 0 on success, -1 on fail.
00253  */
00254 
00255 /*--------------------------------------------------------------------------*/
00256 
00257 int
00258 irplib_detmon_lg(cpl_frameset * frameset,
00259                  const cpl_parameterlist * parlist,
00260                  const char *tag_on,
00261                  const char *tag_off,
00262                  const char *recipe_name,
00263                  const char *pipeline_name,
00264                  const char *procatg_lintbl,
00265                  const char *procatg_gaintbl,
00266                  const char *procatg_lincoeff,
00267                  const char *procatg_bpm,
00268                  const char *package,
00269                  int (* compare)(const cpl_frame *,
00270                                  const cpl_frame *), const cpl_boolean opt_nir)
00271 {
00272     int                     nsets;
00273     int                    *selection = NULL;
00274     int                     i;
00275 
00276 #define clreturn_if(CONDITION, ERR_MSG)                                      \
00277     do if (cpl_error_get_code() || CONDITION) {                              \
00278         cpl_msg_error(cpl_func, ERR_MSG);                                    \
00279         if(selection) cpl_free(selection);                                   \
00280         if(selection_on) cpl_free(selection_on);                             \
00281         if(selection_off) cpl_free(selection_off);                           \
00282         if(cur_fset) cpl_frameset_delete(cur_fset);                          \
00283         if(cur_fset_on) cpl_frameset_delete(cur_fset_on);                    \
00284         if(cur_fset_off) cpl_frameset_delete(cur_fset_off);                  \
00285         if(gain_table) cpl_table_delete(gain_table);                         \
00286         if(linear_table) cpl_table_delete(linear_table);                     \
00287         if(coeffs) cpl_imagelist_delete(coeffs);                             \
00288         if(bpms) cpl_image_delete(bpms);                                     \
00289         if(qclist) cpl_propertylist_delete(qclist);                          \
00290         return -1;                                                           \
00291     } while(0)
00292 
00293     /* Test entries */
00294     cpl_ensure(parlist != NULL, CPL_ERROR_NULL_INPUT, -1);
00295     cpl_ensure(frameset != NULL, CPL_ERROR_NULL_INPUT, -1);
00296     cpl_ensure(tag_on != NULL, CPL_ERROR_NULL_INPUT, -1);
00297     cpl_ensure(tag_off != NULL, CPL_ERROR_NULL_INPUT, -1);
00298     cpl_ensure(recipe_name != NULL, CPL_ERROR_NULL_INPUT, -1);
00299     cpl_ensure(procatg_lintbl != NULL, CPL_ERROR_NULL_INPUT, -1);
00300     cpl_ensure(procatg_gaintbl != NULL, CPL_ERROR_NULL_INPUT, -1);
00301     cpl_ensure(procatg_lincoeff != NULL, CPL_ERROR_NULL_INPUT, -1);
00302     cpl_ensure(procatg_bpm != NULL, CPL_ERROR_NULL_INPUT, -1);
00303     cpl_ensure(package != NULL, CPL_ERROR_NULL_INPUT, -1);
00304 
00305 /*  This check is invalid.
00306  *
00307  *  if (cpl_frameset_get_size(frameset) % 4 != 0) {
00308  *      cpl_msg_error(cpl_func, "Illegal amount of input files:"
00309  *                              "4 frames for each DIT value are required");
00310  *  }
00311  */
00312 
00313     /* Identify the RAW and CALIB frames in the input frameset */
00314     if(irplib_detmon_dfs_set_groups(frameset, tag_on, tag_off))
00315         cpl_msg_error(cpl_func, "Cannot identify RAW and CALIB frames");
00316 
00317     if(irplib_detmon_retrieve_params(pipeline_name, recipe_name, parlist))
00318         cpl_msg_error(cpl_func, "Failed to retrieve input parameters");
00319 
00320     /* Labelise all input frames */
00321     if(compare == NULL)
00322         nsets = 1;
00323     else {
00324         cpl_msg_info(cpl_func, "Identify the different settings");
00325         selection = cpl_frameset_labelise(frameset, compare, &nsets);
00326         if(selection == NULL)
00327             cpl_msg_error(cpl_func, "Cannot labelise input frames");
00328     }
00329 
00330     /* Extract settings and reduce each of them */
00331     for(i = 0; i < nsets; i++) {
00332         int              * selection_on = NULL;
00333         int              * selection_off = NULL;
00334         cpl_frameset     * cur_fset = NULL;
00335         cpl_frameset     * cur_fset_on = NULL;
00336         cpl_frameset     * cur_fset_off = NULL;
00337         cpl_table        * gain_table = NULL;
00338         cpl_table        * linear_table = NULL;
00339         cpl_imagelist    * coeffs = NULL;
00340         cpl_image        * bpms = NULL;
00341         int                nsets_on = 0;
00342         int                nsets_off = 0;
00343         cpl_propertylist * qclist = cpl_propertylist_new();
00344 
00345         /* Reduce data set nb i */
00346         cpl_msg_info(cpl_func, "Reduce data set no %d out of %d", i + 1,
00347                      nsets);
00348         /*
00349          * If nsets = 1, no selection is available,
00350          * input frameset is duplicated.
00351          * This 2 lines are introduced to re-use the code inside the for()
00352          * for the case nsets = 1.
00353          */
00354 
00355         if(nsets == 1)
00356             cur_fset = cpl_frameset_duplicate(frameset);
00357         else
00358             cur_fset = cpl_frameset_extract(frameset, selection, i);
00359 
00360         /*
00361          * In the optical domain, the first 2 frames
00362          * are used apart from the pairs.
00363          */
00364         if(opt_nir == OPT)
00365             irplib_detmon_opt_lampcr(cur_fset);
00366 
00367         /* Split input frameset into 2 sub-framesets for ON and OFF frames */
00368         cur_fset_on = cpl_frameset_new();
00369         cur_fset_off = cpl_frameset_new();
00370         cpl_msg_info(cpl_func, "Splitting into ON and OFF sub-framesets");
00371         irplib_detmon_lg_split_onoff(cur_fset, cur_fset_on, cur_fset_off,
00372                                      tag_on, tag_off, opt_nir);
00373         clreturn_if(0, "Failed to split into ON and OFF subframesets");
00374 
00375         /* Labelise each sub-frameset according to DIT values */
00376         clreturn_if((selection_on =
00377                      cpl_frameset_labelise(cur_fset_on,
00378                                            irplib_detmon_compare_dits,
00379                                            &nsets_on)) == NULL,
00380                     "Cannot labelise ON frames");
00381 
00382         if(!detmon_lg_config.collapse)
00383             clreturn_if((selection_off =
00384                          cpl_frameset_labelise(cur_fset_off,
00385                                                irplib_detmon_compare_dits,
00386                                                &nsets_off)) == NULL,
00387                         "Cannot labelise OFF frames");
00388 
00389         /* Test if they have equal nb of labels */
00390         if(!detmon_lg_config.collapse)
00391             clreturn_if(nsets_on != nsets_off,
00392                         "Illegal input: different nb of ON and OFF frames");
00393 
00394         /* Reduction done here */
00395         cpl_msg_info(cpl_func, "Starting data reduction");
00396 
00397         irplib_detmon_lg_reduce(cur_fset_on, cur_fset_off,
00398                                 selection_on, selection_off,
00399                                 nsets_on, &coeffs, &gain_table,
00400                                 &linear_table, &bpms, qclist, opt_nir);
00401         clreturn_if(0, "Cannot perform linearity/gain reduction");
00402 
00403         /* Save the products for each setting */
00404         cpl_msg_info(cpl_func, "Saving the products");
00405         if(nsets == 1) {
00406             irplib_detmon_lg_save(parlist, frameset, recipe_name,
00407                                   pipeline_name, procatg_lintbl,
00408                                   procatg_gaintbl, procatg_lincoeff,
00409                                   procatg_bpm, package, coeffs,
00410                                   gain_table, linear_table, bpms,
00411                                   qclist, 0, 0, cur_fset, opt_nir);
00412         } else {
00413             irplib_detmon_lg_save(parlist, frameset, recipe_name,
00414                                   pipeline_name, procatg_lintbl,
00415                                   procatg_gaintbl, procatg_lincoeff,
00416                                   procatg_bpm, package, coeffs,
00417                                   gain_table, linear_table, bpms,
00418                                   qclist, 1, i + 1, cur_fset, opt_nir);
00419         }
00420         clreturn_if(0, "Cannot save the products");
00421 
00422         /* Free for each setting */
00423         cpl_free(selection_on);
00424         cpl_free(selection_off);
00425 
00426         cpl_frameset_delete(cur_fset);
00427         cpl_frameset_delete(cur_fset_on);
00428         cpl_frameset_delete(cur_fset_off);
00429 
00430         cpl_imagelist_delete(coeffs);
00431         cpl_table_delete(gain_table);
00432         cpl_table_delete(linear_table);
00433         cpl_image_delete(bpms);
00434         cpl_propertylist_delete(qclist);
00435     }
00436 
00437     /* Free and return */
00438     if(compare != NULL)
00439         cpl_free(selection);
00440 
00441 #undef clreturn_if
00442 
00443     return 0;
00444 }
00445 
00446 /*--------------------------------------------------------------------------*/
00447 
00448 /*
00449  * @brief  Correlate two images with a given range of shifts
00450  * @param  image1   Input image
00451  * @param  image2   Input image
00452  * @param  m        Shift to apply on the x-axis
00453  * @param  n        Shift to apply on the y-axis
00454  * @return      An image of size 2m+1 by 2n+1. Each pixel value
00455  *          corresponds to the correlation of shift the position
00456  *          of the pixel. Pixel in the centre (m+1, n+1),
00457  *                      corresponds to shift (0,0). Pixels to the left and
00458  *                      down correspond to negative shifts.
00459  *
00460  * @note        At this moment, this function only accepts images to
00461  *          have both the same size.
00462  */
00463 
00464 /*--------------------------------------------------------------------------*/
00465 #ifdef HAVE_FFTW
00466 
00467 cpl_image              *
00468 irplib_detmon_image_correlate(const cpl_image * image1,
00469                               const cpl_image * image2,
00470                               const int m, const int n)
00471 {
00472     cpl_image              *image1_padded;
00473     cpl_image              *image2_padded;
00474     float                  *data1;
00475     float                  *data2;
00476     int                     nx, ny;
00477     int                     nx2, ny2;
00478     int                     i;
00479 
00480     fftwf_plan              p1;
00481     fftwf_complex          *in1;
00482     fftwf_complex          *ri1;
00483 
00484     fftwf_plan              p2;
00485     fftwf_complex          *in2;
00486     fftwf_complex          *ri2;
00487 
00488     fftwf_plan              p_inv;
00489     fftwf_complex          *in_inv;
00490     fftwf_complex          *ri_inv;
00491 
00492     fftwf_complex          *corr;
00493     float                  *corr_r;
00494 
00495     cpl_image              *corr_image;
00496     cpl_image              *corr_image_window;
00497     cpl_image              *reorganised;
00498     cpl_image              *image;
00499 
00500     /* Test the entries */
00501     cpl_ensure(image1 != NULL, CPL_ERROR_NULL_INPUT, NULL);
00502     cpl_ensure(image2 != NULL, CPL_ERROR_NULL_INPUT, NULL);
00503 
00504     cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
00505     cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
00506 
00507     nx = cpl_image_get_size_x(image1);
00508     ny = cpl_image_get_size_y(image1);
00509 
00510     nx2 = cpl_image_get_size_x(image2);
00511     ny2 = cpl_image_get_size_y(image2);
00512 
00513     /* At this moment, the images must be of the same size */
00514     cpl_ensure(nx == nx2 && ny == ny2, CPL_ERROR_ILLEGAL_INPUT, NULL);
00515 
00516     /* Pad the images with zeroes to avoid periodical effects of DFT */
00517     image1_padded = cpl_image_new(nx + 2 * m, ny + 2 * n, CPL_TYPE_FLOAT);
00518     cpl_image_copy(image1_padded, image1, m + 1, n + 1);
00519 
00520     image2_padded = cpl_image_new(nx + 2 * m, ny + 2 * n, CPL_TYPE_FLOAT);
00521     cpl_image_copy(image2_padded, image2, m + 1, n + 1);
00522 
00523     /* Get pointers to the pixel data */
00524     data1 = cpl_image_get_data_float(image1_padded);
00525     data2 = cpl_image_get_data_float(image2_padded);
00526 
00527     /*New dimensions of the padded images */
00528     nx = nx + 2 * m;
00529     ny = ny + 2 * n;
00530 
00531     /* Establish the input/output data arrays and the FFT plan */
00532     in1 = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * nx * ny);
00533     ri1 = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * nx * ny);
00534     p1 = fftwf_plan_dft_2d(ny, nx, in1, ri1, FFTW_FORWARD, FFTW_ESTIMATE);
00535 
00536     /* Pack the CPL image data into the FFTW input array */
00537     for(i = 0; i < nx * ny; i++) {
00538         *(in1 + i) = (*(data1 + i) + 0.0 * I);
00539     }
00540 
00541     /* Actually perform the FFT */
00542     fftwf_execute(p1);
00543 
00544     /* Cleanup resources */
00545     fftwf_destroy_plan(p1);
00546     cpl_image_delete(image1_padded);
00547 
00548     /* Establish the input/output data arrays and the FFT plan */
00549     in2 = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * nx * ny);
00550     ri2 = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * nx * ny);
00551     p2 = fftwf_plan_dft_2d(ny, nx, in2, ri2, FFTW_FORWARD, FFTW_ESTIMATE);
00552 
00553     /* Pack the CPL image data into the FFTW input array */
00554     for(i = 0; i < nx * ny; i++) {
00555         *(in2 + i) = (*(data2 + i) + 0.0 * I);
00556     }
00557 
00558     /* Actually perform the FFT */
00559     fftwf_execute(p2);
00560 
00561     /* Cleanup resources */
00562     fftwf_destroy_plan(p2);
00563     cpl_image_delete(image2_padded);
00564 
00565     /* Establish the input/output data arrays and the FFT plan */
00566     in_inv = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * nx * ny);
00567     ri_inv = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * nx * ny);
00568     p_inv = fftwf_plan_dft_2d(ny, nx, in_inv, ri_inv,
00569                               FFTW_BACKWARD, FFTW_ESTIMATE);
00570 
00571     /* Correlation in the Fourier domain: G*[n]·H[n] */
00572     for(i = 0; i < nx * ny; i++) {
00573         in_inv[i] = conjf(ri1[i]) * ri2[i];
00574     }
00575 
00576     /* Cleanup resources */
00577     fftwf_free(in1);
00578     fftwf_free(ri1);
00579 
00580     fftwf_free(in2);
00581     fftwf_free(ri2);
00582 
00583     /* Actually perform the FFT */
00584     fftwf_execute(p_inv);
00585 
00586     /* Cleanup FFTW resources */
00587     fftwf_destroy_plan(p_inv);
00588 
00589     /* Get the module of the inversed signal */
00590     corr = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * nx * ny);
00591     corr_r = (float *) cpl_malloc(sizeof(float) * nx * ny);
00592 
00593     for(i = 0; i < nx * ny; i++) {
00594         *(corr + i) = conjf(*(ri_inv + i));
00595         *(corr + i) *= *(ri_inv + i);
00596         corr_r[i] = crealf(*(corr + i));
00597     }
00598     fftwf_free(in_inv);
00599     fftwf_free(ri_inv);
00600 
00601     /* Wrap the data onto an image */
00602     corr_image = cpl_image_wrap_float(nx, ny, corr_r);
00603 
00604     /* Cleanup resources */
00605     fftwf_free(corr);
00606 
00607     /* Reorganise the pixels to the output */
00608     reorganised = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00609 
00610     image = cpl_image_extract(corr_image, nx / 2 + 1, 1, nx, ny);
00611     cpl_image_copy(reorganised, image, 1, 1);
00612     cpl_image_delete(image);
00613 
00614     image = cpl_image_extract(corr_image, 1, 1, nx / 2, ny);
00615     cpl_image_copy(reorganised, image, nx / 2 + 1, 1);
00616     cpl_image_delete(image);
00617 
00618     cpl_image_unwrap(corr_image);
00619     cpl_free(corr_r);
00620 
00621     corr_image = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00622 
00623     image = cpl_image_extract(reorganised, 1, ny / 2 + 1, nx, ny);
00624     cpl_image_copy(corr_image, image, 1, 1);
00625     cpl_image_delete(image);
00626 
00627     image = cpl_image_extract(reorganised, 1, 1, nx, ny / 2);
00628     cpl_image_copy(corr_image, image, 1, ny / 2 + 1);
00629     cpl_image_delete(image);
00630 
00631     /* Extract a window with the desired shifts */
00632     corr_image_window = cpl_image_extract(corr_image,
00633                                           nx / 2 + 1 - m,
00634                                           ny / 2 + 1 - n,
00635                                           nx / 2 + 1 + m, ny / 2 + 1 + n);
00636 
00637     /* Free and return */
00638     cpl_image_delete(reorganised);
00639     cpl_image_delete(corr_image);
00640 
00641     if(cpl_image_divide_scalar(corr_image_window,
00642                                cpl_image_get_max(corr_image_window))) {
00643         cpl_image_delete(corr_image_window);
00644         return NULL;
00645     }
00646 
00647     return corr_image_window;
00648 }
00649 
00650 
00651 static cpl_image       *
00652 irplib_detmon_image_autocorrelate_fftw(const cpl_image * image,
00653                                        const int m, const int n)
00654 {
00655     cpl_image              *input;
00656     cpl_image              *image_padded;
00657 
00658     int                     nx, ny;
00659     int                     i;
00660 
00661     fftwf_plan              p1;
00662     fftwf_complex          *fourier;
00663     fftwf_plan              p_inv;
00664 
00665     cpl_image              *corr_image;
00666     cpl_image              *corr_image_window;
00667     cpl_image              *reorganised;
00668     cpl_image              *image1;
00669     int                     npix;
00670     size_t                  bigsize;
00671     float                  *in;
00672 
00673     /* Test the entries */
00674     cpl_ensure(image != NULL, CPL_ERROR_NULL_INPUT, NULL);
00675 
00676     cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
00677     cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
00678 
00679     nx = cpl_image_get_size_x(image);
00680     ny = cpl_image_get_size_y(image);
00681 
00682     npix = (nx + 2 * m) * (ny + 2 * n);
00683 
00684     /* Storage needed for one transformed image */
00685     bigsize = 2 * (npix / 2 + 1);
00686 
00687     /* Allocate space for two transforms */
00688     in = (float *) fftw_malloc(sizeof(float) * bigsize);
00689 
00690     /* Pad the image with zeroes to avoid periodical effects of DFT */
00691     input = cpl_image_cast(image, CPL_TYPE_FLOAT);
00692 
00693     image_padded = cpl_image_wrap_float(nx, ny, in);
00694     cpl_image_copy(image_padded, input, m + 1, n + 1);
00695     cpl_image_delete(input);
00696 
00697     /*New dimensions of the padded images */
00698     nx = nx + 2 * m;
00699     ny = ny + 2 * n;
00700 
00701     /* Establish the input/output data arrays and the FFT plan */
00702     fourier = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * nx * ny);
00703     p1 = fftwf_plan_dft_r2c_2d(ny, nx, in, fourier, FFTW_FORWARD);
00704 
00705     /* Actually perform the FFT */
00706     fftwf_execute(p1);
00707 
00708     /* Cleanup resources */
00709     fftwf_destroy_plan(p1);
00710     cpl_image_unwrap(image_padded);
00711 
00712     /* Establish the input/output data arrays and the FFT plan */
00713     p_inv = fftwf_plan_dft_c2r_2d(ny, nx, fourier, in, FFTW_BACKWARD);
00714 
00715     /* Correlation in the Fourier domain: G*[n]·H[n] */
00716     for(i = 0; i < nx * ny; i++) {
00717         fourier[i] = conj(fourier[i]) * fourier[i];
00718     }
00719 
00720     /* Actually perform the FFT */
00721     fftwf_execute(p_inv);
00722 
00723     /* Cleanup FFTW resources */
00724     fftwf_destroy_plan(p_inv);
00725 
00726     fftwf_free(fourier);
00727 
00728     /* Wrap the data onto an image */
00729     corr_image = cpl_image_wrap_float(nx, ny, in);
00730 
00731     /* Reorganise the pixels to the output */
00732     reorganised = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00733 
00734     image1 = cpl_image_extract(corr_image, nx / 2 + 1, 1, nx, ny);
00735     cpl_image_copy(reorganised, image1, 1, 1);
00736     cpl_image_delete(image1);
00737 
00738     image1 = cpl_image_extract(corr_image, 1, 1, nx / 2, ny);
00739     cpl_image_copy(reorganised, image1, nx / 2 + 1, 1);
00740     cpl_image_delete(image1);
00741 
00742     cpl_image_unwrap(corr_image);
00743     fftwf_free(in);
00744 
00745     corr_image = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00746     image1 = cpl_image_extract(reorganised, 1, ny / 2 + 1, nx, ny);
00747     cpl_image_copy(corr_image, image1, 1, 1);
00748     cpl_image_delete(image1);
00749 
00750     image1 = cpl_image_extract(reorganised, 1, 1, nx, ny / 2);
00751     cpl_image_copy(corr_image, image1, 1, ny / 2 + 1);
00752     cpl_image_delete(image1);
00753 
00754     /* Extract a window with the desired shifts */
00755     corr_image_window = cpl_image_extract(corr_image,
00756                                           nx / 2 + 1 - m,
00757                                           ny / 2 + 1 - n,
00758                                           nx / 2 + 1 + m, ny / 2 + 1 + n);
00759 
00760     /* Free and return */
00761     cpl_image_delete(reorganised);
00762     cpl_image_delete(corr_image);
00763 
00764     if(cpl_image_divide_scalar(corr_image_window,
00765                                cpl_image_get_max(corr_image_window))) {
00766         cpl_image_delete(corr_image_window);
00767         return NULL;
00768     }
00769 
00770     return corr_image_window;
00771 }
00772 #endif
00773 
00774 /*--------------------------------------------------------------------------*/
00775 
00776 /*
00777  * @brief  Autocorrelate an image with a given range of shifts, using
00778  *     cpl_image_fft()
00779  * @param  input    Input image
00780  * @param  m        Shift to apply on the x-axis
00781  * @param  n        Shift to apply on the y-axis
00782  * @return      An image of size 2m+1 by 2n+1. Each pixel value
00783  *          corresponds to the correlation of shift the position
00784  *          of the pixel. Pixel in the centre (m+1, n+1),
00785  *                      corresponds to shift (0,0). Pixels to the left and
00786  *                      down correspond to negative shifts.
00787  */
00788 
00789 /*--------------------------------------------------------------------------*/
00790 
00791 static cpl_image       *
00792 irplib_detmon_autocorrelate(const cpl_image * input, const int m, const int n)
00793 {
00794     cpl_image              *im_re;
00795     cpl_image              *im_im;
00796     int                     nx, ny;
00797     cpl_image              *ifft_re;
00798     cpl_image              *ifft_im;
00799     cpl_image              *autocorr;
00800     cpl_image              *autocorr_norm;
00801     double                  max;
00802     cpl_image              *reorganised;
00803     cpl_image              *image;
00804     int                     p;
00805 
00806     cpl_ensure(input != NULL, CPL_ERROR_NULL_INPUT, NULL);
00807 
00808     cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
00809     cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
00810 
00811     nx = cpl_image_get_size_x(input) + 2 * m;
00812     ny = cpl_image_get_size_y(input) + 2 * n;
00813 
00814     p = 128;
00815     while(nx > p || ny > p) {
00816         p *= 2;
00817     }
00818 
00819     im_re = cpl_image_new(p, p, CPL_TYPE_FLOAT);
00820     cpl_image_copy(im_re, input, 1, 1);
00821 
00822     im_im = cpl_image_new(p, p, CPL_TYPE_FLOAT);
00823 
00824     cpl_image_fft(im_re, im_im, CPL_FFT_DEFAULT);
00825 
00826     ifft_re = cpl_image_new(p, p, CPL_TYPE_FLOAT);
00827     //ifft_im = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00828 
00829     cpl_image_power(im_re, 2);
00830     cpl_image_add(ifft_re, im_re);
00831     cpl_image_delete(im_re);
00832 
00833     cpl_image_power(im_im, 2);
00834     cpl_image_add(ifft_re, im_im);
00835     cpl_image_delete(im_im);
00836 
00837     ifft_im = cpl_image_new(p, p, CPL_TYPE_FLOAT);
00838 
00839     cpl_image_fft(ifft_re, ifft_im, CPL_FFT_INVERSE);
00840 
00841     autocorr = cpl_image_new(p, p, CPL_TYPE_FLOAT);
00842 
00843     cpl_image_power(ifft_re, 2);
00844     cpl_image_add(autocorr, ifft_re);
00845     cpl_image_delete(ifft_re);
00846 
00847     cpl_image_power(ifft_im, 2);
00848     cpl_image_add(autocorr, ifft_im);
00849     cpl_image_delete(ifft_im);
00850 
00851     max = cpl_image_get_max(autocorr);
00852 
00853     cpl_image_divide_scalar(autocorr, max);
00854 
00855     /* Reorganise the pixels to the output */
00856     reorganised = cpl_image_new(p, p, CPL_TYPE_FLOAT);
00857 
00858     image = cpl_image_extract(autocorr, p / 2 + 1, 1, p, p);
00859     cpl_image_copy(reorganised, image, 1, 1);
00860     cpl_image_delete(image);
00861 
00862     image = cpl_image_extract(autocorr, 1, 1, p / 2, p);
00863     cpl_image_copy(reorganised, image, p / 2 + 1, 1);
00864     cpl_image_delete(image);
00865 
00866     cpl_image_delete(autocorr);
00867 
00868     autocorr = cpl_image_new(p, p, CPL_TYPE_FLOAT);
00869 
00870     image = cpl_image_extract(reorganised, 1, p / 2 + 1, p, p);
00871     cpl_image_copy(autocorr, image, 1, 1);
00872     cpl_image_delete(image);
00873 
00874     image = cpl_image_extract(reorganised, 1, 1, p, p / 2);
00875     cpl_image_copy(autocorr, image, 1, p / 2 + 1);
00876     cpl_image_delete(image);
00877 
00878     cpl_image_delete(reorganised);
00879 
00880     autocorr_norm =
00881         cpl_image_extract(autocorr, p / 2 + 1 - m, p / 2 + 1 - n,
00882                           p / 2 + 1 + m, p / 2 + 1 + n);
00883 
00884     cpl_image_delete(autocorr);
00885 
00886     if(cpl_image_divide_scalar(autocorr_norm,
00887                                cpl_image_get_max(autocorr_norm))) {
00888         cpl_image_delete(autocorr_norm);
00889         cpl_ensure(0, cpl_error_get_code(), NULL);
00890     }
00891     return autocorr_norm;
00892 }
00893 
00894 /*--------------------------------------------------------------------------*/
00895 
00896 /*
00897  * @brief  Fill the necessary parameters for linearity/gain
00898 
00899  * used called from rrrecipe_create()
00900  * @param parlist       Parameterlist
00901  */
00902 
00903 /*--------------------------------------------------------------------------*/
00904 int
00905 irplib_detmon_fill_params(cpl_parameterlist * parlist,
00906                           const char *recipe_name, const char *pipeline_name)
00907 {
00908     irplib_detmon_fill_parlist(parlist, recipe_name, pipeline_name, 36,
00909                                "order",
00910                                "Polynomial order for the fit",
00911                                "CPL_TYPE_INT", 3,
00912 
00913                                "kappa",
00914                                "Kappa value for the kappa-sigma clipping",
00915                                "CPL_TYPE_INT", 3,
00916 
00917                                "niter",
00918                                "Number of iterations to compute rms",
00919                                "CPL_TYPE_INT", 25,
00920 
00921                                "threshold_min",
00922                                "Minimum threshold for non-linear pixels rejection",
00923                                "CPL_TYPE_INT", 0,
00924 
00925                                "threshold_max",
00926                                "Maximum threshold for non-linear pixels rejection",
00927                                "CPL_TYPE_INT", 10000,
00928 
00929                                "llx",
00930                                "x coordinate of the lower-left "
00931                                "point of the region of interest",
00932                                "CPL_TYPE_INT", 1,
00933 
00934                                "lly",
00935                                "y coordinate of the lower-left "
00936                                "point of the region of interest",
00937                                "CPL_TYPE_INT", 1,
00938 
00939                                "urx",
00940                                "x coordinate of the upper-right "
00941                                "point of the region of interest",
00942                                "CPL_TYPE_INT", 1024,
00943 
00944                                "ury",
00945                                "y coordinate of the upper-right "
00946                                "point of the region of interest",
00947                                "CPL_TYPE_INT", 1024,
00948     
00949                                "ref_level",
00950                                "User reference level",
00951                                "CPL_TYPE_INT", 10000,
00952   
00953                                "threshold",
00954                                "Intensity of threshold pixels",
00955                                "CPL_TYPE_INT", 10000,
00956 
00957                                "intermediate",
00958                                "De-/Activate intermediate products",
00959                                "CPL_TYPE_BOOL", "CPL_FALSE",
00960 
00961                                "autocorr", 
00962                                "De-/Activate the autocorr option",
00963                                "CPL_TYPE_BOOL", "CPL_FALSE",
00964 
00965                                "collapse", 
00966                                "De-/Activate the collapse option",
00967                                "CPL_TYPE_BOOL", "CPL_FALSE",
00968 
00969                                "m",
00970                                "Maximum x-shift for the autocorr",
00971                                "CPL_TYPE_INT", 26,
00972 
00973                                "n",
00974                                "Maximum y-shift for the autocorr",
00975                                "CPL_TYPE_INT", 26,
00976 
00977                                "llx1",
00978                                "x coord of the lower-left point of the first "
00979                                "field used for contamination measurement", 
00980                                "CPL_TYPE_INT", 1,
00981  
00982                                "lly1",
00983                                "y coord of the lower-left point of the first "
00984                                "field used for contamination measurement", 
00985                                "CPL_TYPE_INT", 1,
00986 
00987                                "urx1",
00988                                "x coord of the upper-right point of the first "
00989                                "field used for contamination measurement", 
00990                                "CPL_TYPE_INT", 1024,
00991 
00992                                "ury1",
00993                                "y coord of the upper-right point of the first "
00994                                "field used for contamination measurement",
00995                                "CPL_TYPE_INT", 1024, 
00996 
00997                                "llx2",
00998                                "x coord of the lower-left point of the second "
00999                                "field used for contamination measurement", 
01000                                "CPL_TYPE_INT", 1,
01001 
01002                                "lly2",
01003                                "y coord of the lower-left point of the second "
01004                                "field used for contamination measurement", 
01005                                "CPL_TYPE_INT", 1,
01006         
01007                                "urx2",
01008                                "x coord of the upper-right point of the second "
01009                                "field used for contamination measurement", 
01010                                "CPL_TYPE_INT", 512,
01011 
01012                                "ury2",
01013                                "y coord of the upper-right point of the second "
01014                                "field used for contamination measurement", 
01015                                "CPL_TYPE_INT", 512,
01016 
01017                                "llx3",
01018                                "x coord of the lower-left point of the third "
01019                                "field used for contamination measurement", 
01020                                "CPL_TYPE_INT", 512, 
01021 
01022                                "lly3",
01023                                "y coord of the lower-left point of the third "
01024                                "field used for contamination measurement", 
01025                                "CPL_TYPE_INT", 1,
01026  
01027                                "urx3",
01028                                "x coord of the upper-right point of the third "
01029                                "field used for contamination measurement", 
01030                                "CPL_TYPE_INT", 1024,
01031 
01032                                "ury3",
01033                                "y coord of the upper-right point of the third "
01034                                "field used for contamination measurement", 
01035                                "CPL_TYPE_INT", 512,
01036 
01037                                "llx4",
01038                                "x coord of the lower-left point of the fourth "
01039                                "field used for contamination measurement", 
01040                                "CPL_TYPE_INT", 512,
01041 
01042                                "lly4",
01043                                "y coord of the lower-left point of the fourth "
01044                                "field used for contamination measurement", 
01045                                "CPL_TYPE_INT", 512,
01046 
01047                                "urx4",
01048                                "x coord of the upper-right point of the fourth "
01049                                "field used for contamination measurement", 
01050                                "CPL_TYPE_INT", 1024,
01051 
01052                                "ury4",
01053                                "y coord of the upper-right point of the fourth "
01054                                "field used for contamination measurement", 
01055                                "CPL_TYPE_INT", 1024,
01056 
01057                                "llx5",
01058                                "x coord of the lower-left point of the fifth "
01059                                "field used for contamination measurement", 
01060                                "CPL_TYPE_INT", 1,
01061 
01062                                "lly5",
01063                                "y coord of the lower-left point of the fifth "
01064                                "field used for contamination measurement", 
01065                                "CPL_TYPE_INT", 512,
01066  
01067                                "urx5",
01068                                "x coord of the upper-right point of the fifth "
01069                                "field used for contamination measurement", 
01070                                "CPL_TYPE_INT", 512,
01071  
01072                                "ury5",
01073                                "y coord of the upper-right point of the fifth "
01074                                "field used for contamination measurement", 
01075                                "CPL_TYPE_INT", 1024);
01076 
01077     return 0;
01078 }
01079 
01080 int
01081 irplib_detmon_fill_parlist(cpl_parameterlist * parlist,
01082                            const char *recipe_name, const char *pipeline_name,
01083                            int npars, ...)
01084 {
01085 
01086     va_list ap;
01087 
01088     char                   * par_name;
01089     char                   * group_name;
01090     cpl_parameter          * p;
01091 
01092     int    v1;
01093     char * v2;
01094 
01095     int pars_counter = 0;    
01096 
01097     group_name = irplib_sprintf("%s.%s", pipeline_name, recipe_name);
01098     assert(group_name != NULL);
01099 
01100 #define insert_par(PARNAME, PARDESC, PARVALUE, PARTYPE)                      \
01101     do {                                                                     \
01102     par_name = irplib_sprintf("%s.%s", group_name, PARNAME);                 \
01103     assert(par_name != NULL);                                                \
01104     p = cpl_parameter_new_value(par_name, PARTYPE,                           \
01105                                 PARDESC, group_name, PARVALUE);              \
01106     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, PARNAME);             \
01107     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);                        \
01108     cpl_parameterlist_append(parlist, p);                                    \
01109     cpl_free(par_name);                                                      \
01110     } while(0);
01111 
01112  
01113     va_start(ap, npars);
01114 
01115     while(pars_counter < npars) {
01116         char * name = va_arg(ap, char *);
01117         char * desc = va_arg(ap, char *);
01118         char * type = va_arg(ap, char *);
01119 
01120         if(!strcmp(type, "CPL_TYPE_INT")) {
01121             v1 = va_arg(ap, int);
01122             insert_par(name, desc, v1, CPL_TYPE_INT);
01123         }
01124         else if(!strcmp(type, "CPL_TYPE_BOOL")) {
01125             v2 = va_arg(ap, char *);
01126             insert_par(name, desc, CPL_FALSE, CPL_TYPE_BOOL);
01127         }
01128 
01129     pars_counter++;
01130     }
01131 
01132     va_end(ap);
01133 
01134     cpl_free(group_name);
01135 
01136 #undef insert_par
01137     return 0;
01138 }
01139 
01140 /*---------------------------------------------------------------------------*/
01141 
01142 /*
01143  * @brief  Retrieve input parameters
01144  * @param  pipeline_name    Input image
01145  * @param  recipe_name      Input image
01146  * @param  parlist      Shift to apply on the x-axis
01147  * @return CPL_ERROR_NONE on success.
01148  */
01149 
01150 /*---------------------------------------------------------------------------*/
01151 static int
01152 irplib_detmon_retrieve_par(const char *parn,
01153                            const char *pipeline_name,
01154                            const char *recipe_name,
01155                            const cpl_parameterlist * parlist)
01156 {
01157     char                   *par_name;
01158     cpl_parameter          *par;
01159     int                     value;
01160 
01161     par_name = irplib_sprintf("%s.%s.%s", pipeline_name, recipe_name, parn);
01162     assert(par_name != NULL);
01163     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01164     value = cpl_parameter_get_int(par);
01165     cpl_free(par_name);
01166 
01167     return value;
01168 }
01169 
01170 static                  cpl_error_code
01171 irplib_detmon_retrieve_params(const char *pipeline_name,
01172                               const char *recipe_name,
01173                               const cpl_parameterlist * parlist)
01174 {
01175 
01176     char                   *par_name;
01177     cpl_parameter          *par;
01178 
01179     /* --order */
01180     detmon_lg_config.order =
01181         irplib_detmon_retrieve_par("order", pipeline_name, recipe_name,
01182                                    parlist);
01183 
01184     /* --kappa */
01185     detmon_lg_config.kappa =
01186         irplib_detmon_retrieve_par("kappa", pipeline_name, recipe_name,
01187                                    parlist);
01188 
01189     /* --niter */
01190     detmon_lg_config.niter =
01191         irplib_detmon_retrieve_par("niter", pipeline_name, recipe_name,
01192                                    parlist);
01193 
01194     /* --threshold_min */
01195     detmon_lg_config.threshold_min =
01196         irplib_detmon_retrieve_par("threshold_min", pipeline_name,
01197                                    recipe_name, parlist);
01198 
01199     /* --threshold_max */
01200     detmon_lg_config.threshold_max =
01201         irplib_detmon_retrieve_par("threshold_max", pipeline_name,
01202                                    recipe_name, parlist);
01203 
01204     /* --llx */
01205     detmon_lg_config.llx =
01206         irplib_detmon_retrieve_par("llx", pipeline_name, recipe_name,
01207                                    parlist);
01208 
01209     /* --lly */
01210     detmon_lg_config.lly =
01211         irplib_detmon_retrieve_par("lly", pipeline_name, recipe_name,
01212                                    parlist);
01213 
01214     /* --urx */
01215     detmon_lg_config.urx =
01216         irplib_detmon_retrieve_par("urx", pipeline_name, recipe_name,
01217                                    parlist);
01218 
01219     /* --ury */
01220     detmon_lg_config.ury =
01221         irplib_detmon_retrieve_par("ury", pipeline_name, recipe_name,
01222                                    parlist);
01223 
01224     /* --ref_level */
01225     detmon_lg_config.ref_level =
01226         irplib_detmon_retrieve_par("ref_level", pipeline_name, recipe_name,
01227                                    parlist);
01228 
01229     /* --threshold */
01230     detmon_lg_config.threshold =
01231         irplib_detmon_retrieve_par("threshold", pipeline_name, recipe_name,
01232                                    parlist);
01233 
01234     /* --intermediate */
01235     par_name =
01236         irplib_sprintf("%s.%s.intermediate", pipeline_name, recipe_name);
01237     assert(par_name != NULL);
01238     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01239     detmon_lg_config.intermediate = cpl_parameter_get_bool(par);
01240     cpl_free(par_name);
01241 
01242     /* --autocorr */
01243     par_name = irplib_sprintf("%s.%s.autocorr", pipeline_name, recipe_name);
01244     assert(par_name != NULL);
01245     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01246     detmon_lg_config.autocorr = cpl_parameter_get_bool(par);
01247     cpl_free(par_name);
01248 
01249     /* --collapse */
01250     par_name = irplib_sprintf("%s.%s.collapse", pipeline_name, recipe_name);
01251     assert(par_name != NULL);
01252     par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
01253     detmon_lg_config.collapse = cpl_parameter_get_bool(par);
01254     cpl_free(par_name);
01255 
01256     /* --m */
01257     detmon_lg_config.m =
01258         irplib_detmon_retrieve_par("m", pipeline_name, recipe_name, parlist);
01259 
01260     /* --n */
01261     detmon_lg_config.n =
01262         irplib_detmon_retrieve_par("n", pipeline_name, recipe_name, parlist);
01263 
01264     /* --llx1 */
01265     detmon_lg_config.llx1 =
01266         irplib_detmon_retrieve_par("llx1", pipeline_name, recipe_name,
01267                                    parlist);
01268 
01269     /* --lly1 */
01270     detmon_lg_config.lly1 =
01271         irplib_detmon_retrieve_par("lly1", pipeline_name, recipe_name,
01272                                    parlist);
01273 
01274     /* --urx1 */
01275     detmon_lg_config.urx1 =
01276         irplib_detmon_retrieve_par("urx1", pipeline_name, recipe_name,
01277                                    parlist);
01278 
01279     /* --ury1 */
01280     detmon_lg_config.ury1 =
01281         irplib_detmon_retrieve_par("ury1", pipeline_name, recipe_name,
01282                                    parlist);
01283 
01284     /* --llx2 */
01285     detmon_lg_config.llx2 =
01286         irplib_detmon_retrieve_par("llx2", pipeline_name, recipe_name,
01287                                    parlist);
01288 
01289     /* --lly2 */
01290     detmon_lg_config.lly2 =
01291         irplib_detmon_retrieve_par("lly2", pipeline_name, recipe_name,
01292                                    parlist);
01293 
01294     /* --urx2 */
01295     detmon_lg_config.urx2 =
01296         irplib_detmon_retrieve_par("urx2", pipeline_name, recipe_name,
01297                                    parlist);
01298 
01299     /* --ury2 */
01300     detmon_lg_config.ury2 =
01301         irplib_detmon_retrieve_par("ury2", pipeline_name, recipe_name,
01302                                    parlist);
01303 
01304     /* --llx3 */
01305     detmon_lg_config.llx3 =
01306         irplib_detmon_retrieve_par("llx3", pipeline_name, recipe_name,
01307                                    parlist);
01308 
01309     /* --lly3 */
01310     detmon_lg_config.lly3 =
01311         irplib_detmon_retrieve_par("lly3", pipeline_name, recipe_name,
01312                                    parlist);
01313 
01314     /* --urx3 */
01315     detmon_lg_config.urx3 =
01316         irplib_detmon_retrieve_par("urx3", pipeline_name, recipe_name,
01317                                    parlist);
01318 
01319     /* --ury3 */
01320     detmon_lg_config.ury3 =
01321         irplib_detmon_retrieve_par("ury3", pipeline_name, recipe_name,
01322                                    parlist);
01323 
01324     /* --llx4 */
01325     detmon_lg_config.llx4 =
01326         irplib_detmon_retrieve_par("llx4", pipeline_name, recipe_name,
01327                                    parlist);
01328 
01329     /* --lly4 */
01330     detmon_lg_config.lly4 =
01331         irplib_detmon_retrieve_par("lly4", pipeline_name, recipe_name,
01332                                    parlist);
01333 
01334     /* --urx4 */
01335     detmon_lg_config.urx4 =
01336         irplib_detmon_retrieve_par("urx4", pipeline_name, recipe_name,
01337                                    parlist);
01338 
01339     /* --ury4 */
01340     detmon_lg_config.ury4 =
01341         irplib_detmon_retrieve_par("ury4", pipeline_name, recipe_name,
01342                                    parlist);
01343 
01344     /* --llx5 */
01345     detmon_lg_config.llx5 =
01346         irplib_detmon_retrieve_par("llx5", pipeline_name, recipe_name,
01347                                    parlist);
01348 
01349     /* --lly5 */
01350     detmon_lg_config.lly5 =
01351         irplib_detmon_retrieve_par("lly5", pipeline_name, recipe_name,
01352                                    parlist);
01353 
01354     /* --urx5 */
01355     detmon_lg_config.urx5 =
01356         irplib_detmon_retrieve_par("urx5", pipeline_name, recipe_name,
01357                                    parlist);
01358 
01359     /* --ury5 */
01360     detmon_lg_config.ury5 =
01361         irplib_detmon_retrieve_par("ury5", pipeline_name, recipe_name,
01362                                    parlist);
01363 
01364     if(cpl_error_get_code()) {
01365         cpl_msg_error(cpl_func, "Failed to retrieve the input parameters");
01366         cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
01367     }
01368 
01369 
01370     return CPL_ERROR_NONE;
01371 }
01372 
01373 /*--------------------------------------------------------------------------*/
01374 
01375 /*
01376  * @brief  Split the input frameset into two sub-framesets (ON and OFF)
01377  * @param  cur_fset     Pointer to input frameset
01378  * @param  cur_fset_on      Pointer to output ON sub-frameset
01379  * @param  cur_fset_off     Pointer to output OFF sub-frameset
01380  * @param  tag_on       Tag to identify ON frames
01381  * @param  tag_off      Tag to identify OFF frames
01382  * @return cpl_error_code.
01383  */
01384 
01385 /*--------------------------------------------------------------------------*/
01386 
01387 static                  cpl_error_code
01388 irplib_detmon_lg_split_onoff(const cpl_frameset * cur_fset,
01389                              cpl_frameset * cur_fset_on,
01390                              cpl_frameset * cur_fset_off,
01391                              const char *tag_on,
01392                              const char *tag_off, const cpl_boolean opt_nir)
01393 {
01394     int                     nframes;
01395     int                     i;
01396     cpl_frame              *cur_frame;
01397     cpl_frame              *cur_frame_dup;
01398     char                   *tag;
01399 
01400     nframes = cpl_frameset_get_size(cur_fset);
01401     for(i = 0; i < nframes; i++) {
01402         if(opt_nir == OPT && i == 0)
01403             i = 2;
01404         cur_frame = cpl_frameset_get_frame(cur_fset, i);
01405 
01406         /* Duplication is required for insertion to a different frameset */
01407         cur_frame_dup = cpl_frame_duplicate(cur_frame);
01408 
01409         tag = (char *) cpl_frame_get_tag(cur_frame_dup);
01410 
01411         /* Insertion in the corresponding sub-frameset */
01412         if(!strcmp(tag, tag_on)) {
01413             cpl_error_reset();
01414             cpl_frameset_insert(cur_fset_on, cur_frame_dup);
01415             if(cpl_error_get_code() != CPL_ERROR_NONE) {
01416                 cpl_msg_error(cpl_func,
01417                               "Cannot insert ON frame nb %d into "
01418                               "corresponding sub-frameset", i + 1);
01419                 cpl_frame_delete(cur_frame_dup);
01420                 cpl_ensure_code(0, cpl_error_get_code());
01421             }
01422         } else if(!strcmp(tag, tag_off)) {
01423             cpl_error_reset();
01424             cpl_frameset_insert(cur_fset_off, cur_frame_dup);
01425             if(cpl_error_get_code() != CPL_ERROR_NONE) {
01426                 cpl_msg_error(cpl_func, "Cannot insert OFF frame nb %d into "
01427                               "corresponding sub-frameset", i + 1);
01428                 cpl_frame_delete(cur_frame_dup);
01429                 cpl_ensure_code(0, cpl_error_get_code());
01430             }
01431         } else {
01432             cpl_frame_delete(cur_frame_dup);
01433         }
01434     }
01435 
01436     return CPL_ERROR_NONE;
01437 }
01438 
01439 /*--------------------------------------------------------------------------*/
01440 
01441 /*
01442  * @brief    Comparison function to identify different settings
01443  * @param    frame1  First frame 
01444  * @param    frame2  Second frame 
01445  * @return   0 if different, 1 if equal, -1 in error case
01446  */
01447 
01448 /*--------------------------------------------------------------------------*/
01449 
01450 int
01451 irplib_detmon_compare_dits(const cpl_frame * frame1, const cpl_frame * frame2)
01452 {
01453     int                     comparison;
01454     cpl_propertylist       *plist1;
01455     cpl_propertylist       *plist2;
01456     double                  dval1, dval2;
01457 
01458     /* Test entries */
01459     if(frame1 == NULL || frame2 == NULL)
01460         return -1;
01461 
01462     /* Get property lists */
01463     if((plist1 = cpl_propertylist_load(cpl_frame_get_filename(frame1),
01464                                        0)) == NULL) {
01465         cpl_msg_error(cpl_func, "getting header from reference frame");
01466         return -1;
01467     }
01468     if((plist2 = cpl_propertylist_load(cpl_frame_get_filename(frame2),
01469                                        0)) == NULL) {
01470         cpl_msg_error(cpl_func, "getting header from reference frame");
01471         cpl_propertylist_delete(plist1);
01472         return -1;
01473     }
01474 
01475     /* Test status */
01476     if(cpl_error_get_code()) {
01477         cpl_propertylist_delete(plist1);
01478         cpl_propertylist_delete(plist2);
01479         return -1;
01480     }
01481 
01482     /* Compare exposure time */
01483     comparison = 1;
01484     dval1 = irplib_pfits_get_exptime(plist1);
01485     dval2 = irplib_pfits_get_exptime(plist2);
01486     if(cpl_error_get_code()) {
01487         cpl_msg_error(cpl_func, "cannot get exposure time");
01488         cpl_propertylist_delete(plist1);
01489         cpl_propertylist_delete(plist2);
01490         return -1;
01491     }
01492     if(fabs(dval1 - dval2) > 1e-3)
01493         comparison = 0;
01494 
01495     /* Free and return */
01496     cpl_propertylist_delete(plist1);
01497     cpl_propertylist_delete(plist2);
01498     return comparison;
01499 }
01500 
01501 /*--------------------------------------------------------------------------*/
01502 
01503 /*
01504  * @brief  Apply linearity and gain reduction algorithms
01505  * @param  set_on       ON sub-frameset
01506  * @param  set_off      OFF sub-frameset
01507  * @param  selection_on     Array of labels to identify pairs in set_on
01508  * @param  selection_off    Array of labels to identify pairs in set_off
01509  * @param  nsets        Number of pairs in each sub-frameset
01510  * @param  coeffs_ptr       Pointer to output coeffs imagelist
01511  * @param  gain_table_ptr   Pointer to output gain table
01512  * @return cpl_error_code.
01513  */
01514 
01515 /*--------------------------------------------------------------------------*/
01516 
01517 static cpl_error_code
01518 irplib_detmon_lg_reduce(const cpl_frameset * set_on,
01519                         const cpl_frameset * set_off,
01520                         const int *selection_on,
01521                         const int *selection_off,
01522                         const int nsets,
01523                         cpl_imagelist ** coeffs_ptr,
01524                         cpl_table ** gain_table_ptr,
01525                         cpl_table ** linear_table_ptr,
01526                         cpl_image ** bpms_ptr,
01527                         cpl_propertylist * qclist, const cpl_boolean opt_nir)
01528 {
01529     int                     i;
01530     cpl_frameset           *pair_on = NULL;
01531     cpl_frameset           *pair_off = NULL;
01532     cpl_imagelist          *ons = NULL;
01533     cpl_imagelist          *offs = NULL;
01534     cpl_propertylist       *reflist = NULL;
01535     cpl_imagelist          *linearity_inputs = NULL;
01536     cpl_table              *fit_table = NULL;
01537     cpl_vector             *x_pos = NULL;
01538     cpl_image              *fiterror = NULL;
01539     cpl_polynomial         *poly_fit = NULL;
01540     cpl_vector             *x = NULL;
01541     cpl_vector             *y = NULL;
01542     double                  mse;
01543     char                   *name_o = NULL;
01544     cpl_image              *image = NULL;
01545     int                     nbpixs = 0;
01546 
01547 #define clreturn_if(CONDITION, ERR_MSG, ERRCODE)                             \
01548     do if (cpl_error_get_code() || CONDITION) {                              \
01549         cpl_msg_error(cpl_func, ERR_MSG);                                    \
01550         if(x) cpl_vector_unwrap(x);                                          \
01551         if(y) cpl_vector_unwrap(y);                                          \
01552         if(pair_on) cpl_frameset_delete(pair_on);                            \
01553         if(pair_off) cpl_frameset_delete(pair_off);                          \
01554         if(ons) cpl_imagelist_delete(ons);                                   \
01555         if(offs) cpl_imagelist_delete(offs);                                 \
01556         if(reflist) cpl_propertylist_delete(reflist);                        \
01557         if(linearity_inputs) cpl_imagelist_delete(linearity_inputs);         \
01558         if(fit_table) cpl_table_delete(fit_table);                           \
01559         if(x_pos) cpl_vector_delete(x_pos);                                  \
01560         if(fiterror) cpl_image_delete(fiterror);                             \
01561         if(poly_fit) cpl_polynomial_delete(poly_fit);                        \
01562         if(name_o) cpl_free(name_o);                                         \
01563         if(image) cpl_image_delete(image);                                   \
01564         return ERRCODE;                                                      \
01565     } while(0)
01566 
01567 
01568     /* Test entries */
01569     cpl_ensure(set_on != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
01570     cpl_ensure(set_off != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
01571 
01572     /* Initialise */
01573     *gain_table_ptr = cpl_table_new(nsets);
01574     cpl_table_new_column(*gain_table_ptr, "DIT", CPL_TYPE_DOUBLE);
01575     cpl_table_new_column(*gain_table_ptr, "EXPTIME", CPL_TYPE_DOUBLE);
01576     cpl_table_new_column(*gain_table_ptr, "MEAN_ON1", CPL_TYPE_DOUBLE);
01577     cpl_table_new_column(*gain_table_ptr, "MEAN_ON2", CPL_TYPE_DOUBLE);
01578     cpl_table_new_column(*gain_table_ptr, "MEAN_OFF1", CPL_TYPE_DOUBLE);
01579     cpl_table_new_column(*gain_table_ptr, "MEAN_OFF2", CPL_TYPE_DOUBLE);
01580     cpl_table_new_column(*gain_table_ptr, "SIG_ON_DIF", CPL_TYPE_DOUBLE);
01581     cpl_table_new_column(*gain_table_ptr, "SIG_OFF_DIF", CPL_TYPE_DOUBLE);
01582     cpl_table_new_column(*gain_table_ptr, "GAIN", CPL_TYPE_DOUBLE);
01583     cpl_table_new_column(*gain_table_ptr, "ADU", CPL_TYPE_DOUBLE);
01584 
01585 
01586     *linear_table_ptr = cpl_table_new(nsets);
01587     cpl_table_new_column(*linear_table_ptr, "DIT", CPL_TYPE_DOUBLE);
01588     cpl_table_new_column(*linear_table_ptr, "EXPTIME", CPL_TYPE_DOUBLE);
01589     cpl_table_new_column(*linear_table_ptr, "MED", CPL_TYPE_DOUBLE);
01590     cpl_table_new_column(*linear_table_ptr, "MEAN", CPL_TYPE_DOUBLE);
01591     cpl_table_new_column(*linear_table_ptr, "MED_DIT", CPL_TYPE_DOUBLE);
01592     cpl_table_new_column(*linear_table_ptr, "MEAN_DIT", CPL_TYPE_DOUBLE);
01593     cpl_table_new_column(*linear_table_ptr, "ADL", CPL_TYPE_DOUBLE);
01594 
01595     fit_table = cpl_table_new(nsets);
01596     cpl_table_new_column(fit_table, "Y", CPL_TYPE_DOUBLE);
01597     cpl_table_new_column(fit_table, "X", CPL_TYPE_DOUBLE);
01598 
01599     if(opt_nir == NIR) {
01600         linearity_inputs = cpl_imagelist_new();
01601         x_pos = cpl_vector_new(nsets);
01602     }
01603 
01604     /* Loop on every DIT value */
01605     for(i = 0; i < nsets; i++) {
01606 
01607         /* Pair extraction */
01608         clreturn_if((pair_on = cpl_frameset_extract(set_on,
01609                                                     selection_on, i)) == NULL,
01610                     "Cannot extract ON pair", cpl_error_get_code());
01611 
01612         /* Load the ON images */
01613         clreturn_if((ons =
01614                      cpl_imagelist_load_frameset(pair_on, CPL_TYPE_FLOAT, 1,
01615                                                  0)) == NULL,
01616                     "Cannot load the ON images", cpl_error_get_code());
01617 
01618         /* Test if they are really pairs */
01619         clreturn_if(cpl_frameset_get_size(pair_on) != 2,
01620                     "Some frames are not a pair", CPL_ERROR_ILLEGAL_INPUT);
01621 
01622         if(!detmon_lg_config.collapse) {
01623             clreturn_if((pair_off = cpl_frameset_extract(set_off,
01624                                                          selection_off,
01625                                                          i)) == NULL,
01626                         "Cannot extract OFF pair", cpl_error_get_code());
01627             clreturn_if(cpl_frameset_get_size(pair_off) != 2,
01628                         "Some frames are not a pair", CPL_ERROR_ILLEGAL_INPUT);
01629             clreturn_if((offs =
01630                          cpl_imagelist_load_frameset(pair_off, CPL_TYPE_FLOAT, 1,
01631                                                      0)) == NULL,
01632                         "Cannot load the OFF images", cpl_error_get_code());
01633         }
01634 
01635         /* Linearity part */
01636         cpl_msg_info(cpl_func,
01637                      "Producing image nb %d required for polynomial fit",
01638                      i + 1);
01639 
01640         if(!detmon_lg_config.collapse)
01641             irplib_detmon_linearity(pair_on, linear_table_ptr, gain_table_ptr,
01642                                     &linearity_inputs, &x_pos, ons, offs, i,
01643                                     nsets, qclist, opt_nir);
01644         else {
01645             /*
01646              * The master bias is required only for 
01647              * linearity computation in the OPT domain
01648              */
01649             cpl_imagelist * masterl = 
01650                 cpl_imagelist_load_frameset(set_off, CPL_TYPE_FLOAT, 1, 0);
01651             cpl_image * collapse = cpl_imagelist_collapse_create(masterl);
01652 
01653             /* Error checking missing here */
01654             cpl_imagelist_set(masterl, collapse, 0);
01655 
01656             irplib_detmon_linearity(pair_on, linear_table_ptr, gain_table_ptr,
01657                                     &linearity_inputs, &x_pos, ons, masterl, i,
01658                                     nsets, qclist, opt_nir);
01659 
01660             cpl_imagelist_delete(masterl);
01661         }
01662 
01663             clreturn_if(0, "Cannot reduce linearity part", cpl_error_get_code());
01664 
01665         /* Gain part */
01666         cpl_msg_info(cpl_func, "Computing GAIN for DIT value nb %d", i + 1);
01667         if(!detmon_lg_config.collapse)
01668             irplib_detmon_gain(gain_table_ptr, &fit_table, ons, offs, i);
01669         else {
01670             cpl_frame * first = cpl_frameset_get_first(set_off);
01671             cpl_frame * dup_first = cpl_frame_duplicate(first);
01672 
01673             cpl_frame * second = cpl_frameset_get_next(set_off);
01674             cpl_frame * dup_second = cpl_frame_duplicate(second);
01675 
01676             cpl_frameset * raw_offs = cpl_frameset_new();
01677 
01678             cpl_imagelist * opt_offs;
01679 
01680             cpl_frameset_insert(raw_offs, dup_first);
01681             cpl_frameset_insert(raw_offs, dup_second);
01682 
01683             opt_offs =
01684                 cpl_imagelist_load_frameset(raw_offs, CPL_TYPE_FLOAT, 1, 0);
01685             irplib_detmon_gain(gain_table_ptr, &fit_table, ons, opt_offs, i);
01686             cpl_frameset_delete(raw_offs);
01687             cpl_imagelist_delete(opt_offs);
01688 
01689         }
01690         clreturn_if(0, "Cannot reduce gain part", cpl_error_get_code());
01691 
01692         cpl_frameset_delete(pair_on);
01693         cpl_imagelist_delete(ons);
01694 
01695         if(!detmon_lg_config.collapse) {
01696             cpl_frameset_delete(pair_off);
01697             cpl_imagelist_delete(offs);
01698         }
01699     }
01700     /* Remove this ifdef once CPL 3.1 is no longer supported */
01701 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(3, 1, 90)
01702     /* The following line requires cpl_fit.h */
01703     cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix");
01704 
01705     if(opt_nir == OPT) {
01706         /* Computation of GAIN via polynomial fit */
01707         cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
01708 
01709         x = cpl_vector_wrap(nsets,
01710                             cpl_table_get_data_double(*linear_table_ptr,
01711                                                       "MED"));
01712         y = cpl_vector_wrap(nsets,
01713                             cpl_table_get_data_double(*linear_table_ptr,
01714                                                       "DIT"));
01715         clreturn_if(x == NULL
01716                     || y == NULL, "Cannot read LINEAR table",
01717                     cpl_error_get_code());
01718         clreturn_if((poly_fit =
01719                      cpl_polynomial_fit_1d_create(x, y,
01720                                                   detmon_lg_config.order,
01721                                                   &mse)) == NULL,
01722                     "Cannot fit to a linear", cpl_error_get_code());
01723 
01724         for(i = 1; i <= detmon_lg_config.order; i++) {
01725             const double coeff = cpl_polynomial_get_coeff(poly_fit, &i);
01726             name_o = irplib_sprintf("ESO QC LIN COEF%d", i);
01727             assert(name_o != NULL);
01728             cpl_propertylist_append_double(qclist, name_o, coeff);
01729             cpl_free(name_o);
01730         }
01731 
01732         cpl_vector_unwrap(x);
01733         cpl_vector_unwrap(y);
01734         cpl_polynomial_delete(poly_fit);
01735 
01736     } else {
01737         clreturn_if((*coeffs_ptr =
01738                      cpl_fit_imagelist_polynomial(x_pos, linearity_inputs, 0,
01739                                                   detmon_lg_config.order,
01740                                                   FALSE, CPL_TYPE_FLOAT,
01741                                                   fiterror)) == NULL,
01742                     "Cannot compute the polynomial image fit",
01743                     cpl_error_get_code());
01744 
01745         for(i = 0; i < detmon_lg_config.order; i++) {
01746             image = cpl_imagelist_get(*coeffs_ptr, i);
01747             name_o = irplib_sprintf("ESO QC LIN COEF%d", i);
01748             assert(name_o != NULL);
01749             cpl_propertylist_append_double(qclist, name_o,
01750                                            cpl_image_get_median(image));
01751             cpl_free(name_o);
01752             name_o = irplib_sprintf("ESO QC LIN COEF%d ERR", i);
01753             assert(name_o != NULL);
01754             cpl_propertylist_append_double(qclist, name_o,
01755                                            cpl_image_get_stdev(image));
01756             cpl_free(name_o);
01757         }
01758     }
01759 #else
01760     cpl_ensure_code(0, CPL_ERROR_UNSUPPORTED_MODE);
01761 #endif
01762     /* Detection of bad pixels */
01763     cpl_msg_info(cpl_func, "Bad pixel detection");
01764     if(opt_nir == NIR)
01765         clreturn_if((*bpms_ptr =
01766                      irplib_detmon_bpixs(*coeffs_ptr, &nbpixs)) == NULL,
01767                     "Cannot detect bad pixels", CPL_ERROR_DATA_NOT_FOUND);
01768 
01769     /* Computation of GAIN via polynomial fit */
01770     cpl_msg_info(cpl_func,
01771                  "Polynomial fitting for the GAIN (constant term method)");
01772 
01773     x = cpl_vector_wrap(nsets, cpl_table_get_data_double(fit_table, "X"));
01774     y = cpl_vector_wrap(nsets, cpl_table_get_data_double(fit_table, "Y"));
01775     clreturn_if(x == NULL || y == NULL, "Cannot read FIT table",
01776                 cpl_error_get_code());
01777 
01778     clreturn_if((poly_fit =
01779                  cpl_polynomial_fit_1d_create(x, y, 1, &mse)) == NULL,
01780                 "Cannot fit to a linear", cpl_error_get_code());
01781 
01782     cpl_propertylist_append_double(qclist, "ESO QC LAMP FLUX",
01783                                    detmon_lg_config.cr);
01784 
01785     cpl_propertylist_append_double(qclist, "ESO QC GAIN MED",
01786                                    cpl_table_get_column_median
01787                                    (*gain_table_ptr, "GAIN"));
01788     cpl_propertylist_append_double(qclist, "ESO QC GAIN STD",
01789                                    cpl_table_get_column_stdev(*gain_table_ptr,
01790                                                               "GAIN"));
01791     i = 1;
01792     cpl_propertylist_append_double(qclist, "ESO QC CONAD FIT",
01793                                    cpl_polynomial_get_coeff(poly_fit, &i));
01794 
01795     i = 1;
01796     cpl_propertylist_append_double(qclist, "ESO QC GAIN FIT",
01797                                    1 / cpl_polynomial_get_coeff(poly_fit,
01798                                                                 &i));
01799 
01800     i = 0;
01801     cpl_propertylist_append_double(qclist, "ESO QC READNOISE",
01802                                    cpl_polynomial_get_coeff(poly_fit, &i));
01803 
01804     cpl_propertylist_append_double(qclist, "ESO QC NUM BPM", nbpixs);
01805 
01806     if(linearity_inputs)
01807         cpl_imagelist_delete(linearity_inputs);
01808     if(x_pos)
01809         cpl_vector_delete(x_pos);
01810     if(fiterror)
01811         cpl_image_delete(fiterror);
01812     if(x)
01813         cpl_vector_unwrap(x);
01814     if(y)
01815         cpl_vector_unwrap(y);
01816     if(fit_table)
01817         cpl_table_delete(fit_table);
01818     cpl_polynomial_delete(poly_fit);
01819 
01820     reflist = cpl_propertylist_new();
01821     cpl_propertylist_append_bool(reflist, "ADU", FALSE);
01822 
01823     cpl_table_sort(*gain_table_ptr, reflist);
01824 
01825     clreturn_if(0, "Cannot sort the GAIN table", cpl_error_get_code());
01826 
01827     cpl_propertylist_delete(reflist);
01828 
01829 #undef clreturn_if
01830 
01831     return CPL_ERROR_NONE;
01832 }
01833 
01834 /*--------------------------------------------------------------------------*/
01835 
01836 /*
01837  * @brief    Find out the character string associated to the DIT keyword
01838  *           in a propertylist
01839  * @param    plist  Propertylist 
01840  * @return   DIT value
01841  */
01842 
01843 /*--------------------------------------------------------------------------*/
01844 /*
01845 double
01846 irplib_pfits_get_exptime(const cpl_propertylist * plist)
01847 {
01848     double                  dit;
01849 
01850     dit = cpl_propertylist_get_double(plist, "ESO DET DIT");
01851 
01852     if(cpl_error_get_code() != CPL_ERROR_NONE) {
01853         cpl_msg_error(cpl_func, cpl_error_get_where());
01854     }
01855     return dit;
01856 }*/
01857 
01858 /*--------------------------------------------------------------------------*/
01859 
01860 /*
01861  * @brief    Find out the character string associated to the DIT keyword
01862  *           in a propertylist
01863  * @param    plist  Propertylist 
01864  * @return   DIT value
01865  */
01866 
01867 /*--------------------------------------------------------------------------*/
01868 
01869 double
01870 irplib_pfits_get_exptime(const cpl_propertylist * plist)
01871 {
01872     double                  exptime;
01873 
01874     exptime = cpl_propertylist_get_double(plist, "EXPTIME");
01875 
01876     return exptime;
01877 }
01878 
01879 /*--------------------------------------------------------------------------*/
01880 
01881 /*
01882  * @brief    Operate on input ON and OFF images related to linearity
01883  * @param    pair           Frameset to retrieve DIT value 
01884  * @param    linearity_inputs_ptr   Pointer to the imagelist where image
01885  *                                      is to be stored 
01886  * @param    x_pos_ptr          Pointer to the vector where DIT values
01887  *                                      are to be stored
01888  * @param    ons            Images of the ON pair
01889  * @param    offs           Images of the OFF pair
01890  * @param    pos            Position to store image in both
01891  *                                      imagelist and vector
01892  * @return   cpl_error_code.
01893  */
01894 
01895 /*--------------------------------------------------------------------------*/
01896 
01897 static                  cpl_error_code
01898 irplib_detmon_linearity(const cpl_frameset * pair,
01899                         cpl_table ** linear_table_ptr,
01900                         cpl_table ** gain_table_ptr,
01901                         cpl_imagelist ** linearity_inputs_ptr,
01902                         cpl_vector ** x_pos_ptr,
01903                         const cpl_imagelist * ons,
01904                         const cpl_imagelist * offs,
01905                         const int pos,
01906                         const int nsets,
01907                         cpl_propertylist * qclist, const cpl_boolean opt_nir)
01908 {
01909     const char             *filename;
01910     cpl_propertylist       *plist;
01911     cpl_image              *dif1;
01912     cpl_image              *dif2;
01913     cpl_image              *dif_avg;
01914     double                  med_dit;
01915     double                  mean_dit;
01916     double                  exptime, dit;
01917 
01918     /* DIT needed for linearity */
01919     filename = cpl_frame_get_filename(cpl_frameset_get_first(pair));
01920     if((plist = cpl_propertylist_load(filename, 0)) == NULL) {
01921         cpl_msg_error(cpl_func, "getting header from reference frame");
01922         cpl_ensure_code(0, cpl_error_get_code());
01923     }
01924 
01925     dit = irplib_pfits_get_exptime(plist);
01926     exptime = irplib_pfits_get_exptime(plist);
01927 
01928     cpl_table_set(*linear_table_ptr, "DIT", pos, dit);
01929     cpl_table_set(*gain_table_ptr, "DIT", pos, dit);
01930 
01931     cpl_table_set(*linear_table_ptr, "EXPTIME", pos, exptime);
01932     cpl_table_set(*gain_table_ptr, "EXPTIME", pos, exptime);
01933 
01934     /* Algorithm defined: substract ON - OFF and average 2 differences */
01935     dif1 = cpl_image_subtract_create(cpl_imagelist_get(ons, 0),
01936                                      cpl_imagelist_get(offs, 0));
01937     if(!detmon_lg_config.collapse)
01938         dif2 = cpl_image_subtract_create(cpl_imagelist_get(ons, 1),
01939                                          cpl_imagelist_get(offs, 1));
01940     else
01941         dif2 = cpl_image_subtract_create(cpl_imagelist_get(ons, 1),
01942                                          cpl_imagelist_get(offs, 0));
01943 
01944     dif_avg = cpl_image_average_create(dif1, dif2);
01945 
01946     if(opt_nir == OPT && pos == nsets / 2) {
01947         irplib_detmon_opt_contamination(dif_avg, qclist);
01948     }
01949 
01950     cpl_table_set(*linear_table_ptr, "MED", pos,
01951                   cpl_image_get_median(dif_avg));
01952     cpl_table_set(*linear_table_ptr, "MEAN", pos,
01953                   cpl_image_get_mean(dif_avg));
01954 
01955     med_dit = cpl_image_get_median(dif_avg) / irplib_pfits_get_exptime(plist);
01956     mean_dit = cpl_image_get_mean(dif_avg) / irplib_pfits_get_exptime(plist);
01957 
01958     cpl_table_set(*linear_table_ptr, "MED_DIT", pos, med_dit);
01959     cpl_table_set(*linear_table_ptr, "MEAN_DIT", pos, mean_dit);
01960 
01961     /* Compute lamp count rate */
01962     if(pos == 0)
01963         detmon_lg_config.cr = cpl_image_get_mean(dif_avg) / dit;
01964 
01965     cpl_image_delete(dif1);
01966     cpl_image_delete(dif2);
01967     cpl_propertylist_delete(plist);
01968 
01969     /* Insert to the imagelist used to fit the polynomial */
01970     if(opt_nir == NIR) {
01971         cpl_imagelist_set(*linearity_inputs_ptr, dif_avg, pos);
01972         cpl_vector_set(*x_pos_ptr, pos, dit);
01973     } else {
01974         cpl_image_delete(dif_avg);
01975     }
01976 
01977     return CPL_ERROR_NONE;
01978 }
01979 
01980 /*---------------------------------------------------------------------------*/
01981 
01982 /*
01983  * @brief    Operate on input ON and OFF images related to gain
01984  * @param    gain_table_ptr     Pointer to the table to store values
01985  * @param    ons            Images of the ON pair
01986  * @param    offs           Images of the OFF pair
01987  * @param    pos            Position to store image in both
01988  *                                      imagelist and vector
01989  * @return   cpl_error_code.
01990  */
01991 
01992 /*---------------------------------------------------------------------------*/
01993 
01994 static cpl_error_code
01995 irplib_detmon_gain(cpl_table ** gain_table_ptr,
01996                    cpl_table ** fit_table_ptr,
01997                    const cpl_imagelist * ons,
01998                    const cpl_imagelist * offs, const int pos)
01999 {
02000     cpl_image              *image;
02001     double                  std;
02002     cpl_image              *on_dif;
02003     cpl_image              *off_dif;
02004     double                  avg_on1, avg_on2;
02005     double                  avg_off1, avg_off2;
02006     double                  avg_on_dif, sig_on_dif;
02007     double                  avg_off_dif, sig_off_dif;
02008     double                  double_adu, autocorr, gain;
02009     double                  sigma_corr;
02010     cpl_propertylist       *plist;
02011 
02012     std = 0;
02013 
02014     if((image = cpl_imagelist_get(ons, 0)) == NULL) {
02015         cpl_ensure_code(0, cpl_error_get_code());
02016     }
02017     irplib_get_clean_mean_window(image,
02018                                  detmon_lg_config.llx,
02019                                  detmon_lg_config.lly,
02020                                  detmon_lg_config.urx,
02021                                  detmon_lg_config.ury,
02022                                  detmon_lg_config.kappa,
02023                                  detmon_lg_config.niter, &avg_on1, &std);
02024     cpl_ensure_code(cpl_error_get_code() == CPL_ERROR_NONE,
02025                     cpl_error_get_code());
02026     cpl_table_set_double(*gain_table_ptr, "MEAN_ON1", pos, avg_on1);
02027 
02028     if((image = cpl_imagelist_get(ons, 1)) == NULL) {
02029         cpl_ensure_code(0, cpl_error_get_code());
02030     }
02031     irplib_get_clean_mean_window(image,
02032                                  detmon_lg_config.llx,
02033                                  detmon_lg_config.lly,
02034                                  detmon_lg_config.urx,
02035                                  detmon_lg_config.ury,
02036                                  detmon_lg_config.kappa,
02037                                  detmon_lg_config.niter, &avg_on2, &std);
02038     cpl_ensure_code(cpl_error_get_code() == CPL_ERROR_NONE,
02039                     cpl_error_get_code());
02040     cpl_table_set_double(*gain_table_ptr, "MEAN_ON2", pos, avg_on2);
02041 
02042     on_dif =
02043         cpl_image_subtract_create(cpl_imagelist_get(ons, 0),
02044                                   cpl_imagelist_get(ons, 1));
02045     irplib_get_clean_mean_window(on_dif, detmon_lg_config.llx,
02046                                  detmon_lg_config.lly,
02047                                  detmon_lg_config.urx,
02048                                  detmon_lg_config.ury,
02049                                  detmon_lg_config.kappa,
02050                                  detmon_lg_config.niter, &avg_on_dif,
02051                                  &sig_on_dif);
02052     cpl_ensure_code(cpl_error_get_code() == CPL_ERROR_NONE,
02053                     cpl_error_get_code());
02054     cpl_table_set_double(*gain_table_ptr, "SIG_ON_DIF", pos, sig_on_dif);
02055     cpl_msg_info(cpl_func, "Computing autocorr factor for DIT value nb  %d ",
02056                  pos);
02057     autocorr = irplib_detmon_autocorr_factor(on_dif, pos);
02058 
02059     if(detmon_lg_config.intermediate) {
02060         char * frame_name = irplib_sprintf("dif%d.fits", pos);
02061         plist = cpl_propertylist_new();
02062         cpl_propertylist_append_double(plist, "ESO DET DIT", 3);
02063         cpl_propertylist_append_double(plist, "EXPTIME", 3);
02064         cpl_image_save(on_dif, frame_name, CPL_BPP_IEEE_FLOAT, plist,
02065                        CPL_IO_DEFAULT);
02066         cpl_propertylist_delete(plist);
02067         cpl_free(frame_name);
02068     }
02069 
02070     cpl_image_delete(on_dif);
02071 
02072     cpl_ensure_code(cpl_error_get_code() == CPL_ERROR_NONE,
02073                     cpl_error_get_code());
02074 
02075     irplib_get_clean_mean_window(cpl_imagelist_get(offs, 0),
02076                                  detmon_lg_config.llx,
02077                                  detmon_lg_config.lly,
02078                                  detmon_lg_config.urx,
02079                                  detmon_lg_config.ury,
02080                                  detmon_lg_config.kappa,
02081                                  detmon_lg_config.niter, &avg_off1, &std);
02082     cpl_ensure_code(cpl_error_get_code() == CPL_ERROR_NONE,
02083                     cpl_error_get_code());
02084     cpl_table_set_double(*gain_table_ptr, "MEAN_OFF1", pos, avg_off1);
02085     irplib_get_clean_mean_window(cpl_imagelist_get(offs, 1),
02086                                  detmon_lg_config.llx,
02087                                  detmon_lg_config.lly,
02088                                  detmon_lg_config.urx,
02089                                  detmon_lg_config.ury,
02090                                  detmon_lg_config.kappa,
02091                                  detmon_lg_config.niter, &avg_off2, &std);
02092     cpl_ensure_code(cpl_error_get_code() == CPL_ERROR_NONE,
02093                     cpl_error_get_code());
02094     cpl_table_set_double(*gain_table_ptr, "MEAN_OFF2", pos, avg_off2);
02095 
02096     off_dif =
02097         cpl_image_subtract_create(cpl_imagelist_get(offs, 0),
02098                                   cpl_imagelist_get(offs, 1));
02099     irplib_get_clean_mean_window(off_dif, detmon_lg_config.llx,
02100                                  detmon_lg_config.lly,
02101                                  detmon_lg_config.urx,
02102                                  detmon_lg_config.ury,
02103                                  detmon_lg_config.kappa,
02104                                  detmon_lg_config.niter, &avg_off_dif,
02105                                  &sig_off_dif);
02106     cpl_ensure_code(cpl_error_get_code() == CPL_ERROR_NONE,
02107                     cpl_error_get_code());
02108     cpl_table_set_double(*gain_table_ptr, "SIG_OFF_DIF", pos, sig_off_dif);
02109 
02110     cpl_image_delete(off_dif);
02111 
02112     double_adu = (avg_on1 + avg_on2) - (avg_off1 + avg_off2);
02113 
02114     sigma_corr = autocorr *
02115         ((sig_on_dif * sig_on_dif) - (sig_off_dif * sig_off_dif));
02116 
02117     gain = double_adu / sigma_corr;
02118 
02119     if(cpl_table_set_double(*gain_table_ptr, "GAIN", pos, gain)) {
02120         cpl_ensure_code(0, cpl_error_get_code());
02121     }
02122     if(cpl_table_set_double(*gain_table_ptr, "ADU", pos, double_adu / 2)) {
02123         cpl_ensure_code(0, cpl_error_get_code());
02124     }
02125 //  cpl_table_set_double(*fit_table_ptr, "Y", pos, double_adu);
02126 //  cpl_table_set_double(*fit_table_ptr, "X", pos, sigma_corr);
02127 
02128     /* Changed for the new fitting formula */
02129     if(cpl_table_set_double
02130        (*fit_table_ptr, "Y", pos, sig_on_dif * sig_on_dif)) {
02131         cpl_ensure_code(0, cpl_error_get_code());
02132     }
02133     if(cpl_table_set_double(*fit_table_ptr, "X", pos, double_adu / autocorr)) {
02134         cpl_ensure_code(0, cpl_error_get_code());
02135     }
02136     return CPL_ERROR_NONE;
02137 }
02138 
02139 /*--------------------------------------------------------------------------*/
02140 
02141 /*
02142  * @brief  Detect bad pixels based on polynomial coefficients obtained
02143  *     for each pixel
02144  * @param  imagelist    Input cube; each plane correspond to a coefficient
02145  * @return      Cube with bad pixels on each plane
02146  */
02147 
02148 /*--------------------------------------------------------------------------*/
02149 
02150 static cpl_image       *
02151 irplib_detmon_bpixs(const cpl_imagelist * coeffs, int *nbpixs)
02152 {
02153     int                     size;
02154     int                     i;
02155     cpl_image              *cur_coeff;
02156     cpl_stats              *stats;
02157     double                  cur_mean;
02158     double                  cur_stdev;
02159     double                  lo_cut;
02160     double                  hi_cut;
02161     cpl_mask               *cur_mask;
02162     cpl_image              *cur_image;
02163     cpl_image              *bpm = NULL;
02164     double                  p;
02165 
02166     size = cpl_imagelist_get_size(coeffs);
02167 
02168     for(i = 0; i < size; i++) {
02169         cur_coeff = cpl_imagelist_get(coeffs, i);
02170         if(!i) {
02171             bpm = cpl_image_new(cpl_image_get_size_x(cur_coeff),
02172                                 cpl_image_get_size_y(cur_coeff),
02173                                 CPL_TYPE_INT);
02174         }
02175         stats = cpl_stats_new_from_image(cur_coeff,
02176                                          CPL_STATS_MEAN | CPL_STATS_STDEV);
02177         cur_mean = cpl_stats_get_mean(stats);
02178         cur_stdev = cpl_stats_get_stdev(stats);
02179 
02180         lo_cut = cur_mean - detmon_lg_config.kappa * cur_stdev;
02181         hi_cut = cur_mean + detmon_lg_config.kappa * cur_stdev;
02182 
02183         cur_mask = cpl_mask_threshold_image_create(cur_coeff, lo_cut, hi_cut);
02184         cpl_mask_not(cur_mask);
02185 
02186         *nbpixs += cpl_mask_count(cur_mask);
02187 
02188         cur_image = cpl_image_new_from_mask(cur_mask);
02189         p = pow(2, i);
02190         cpl_image_power(cur_image, p);
02191         cpl_image_add(bpm, cur_image);
02192 
02193         cpl_mask_delete(cur_mask);
02194         cpl_image_delete(cur_image);
02195         cpl_stats_delete(stats);
02196     }
02197 
02198     return bpm;
02199 }
02200 
02201 
02202 /*---------------------------------------------------------------------------*/
02203 
02204 /*
02205  * @brief  Compute autocorr factor
02206  * @param  image    Input image
02207  * @return      Autocorrelation factor used as correction for gain
02208  *          formula
02209  */
02210 
02211 /*---------------------------------------------------------------------------*/
02212 
02213 static double
02214 irplib_detmon_autocorr_factor(const cpl_image * image, const int pos)
02215 {
02216 
02217     cpl_image              *autocorr_image;
02218     double                  autocorr;
02219     cpl_propertylist       *plist;
02220 
02221 #ifdef HAVE_FFTW
02222     if(detmon_lg_config.autocorr) {
02223         cpl_msg_info(cpl_func, "Autocorr via FFTW");
02224 //        autocorr_image = irplib_detmon_image_autocorrelate_fftw(image, detmon_lg_config.m, detmon_lg_config.m);
02225         autocorr_image =
02226             irplib_detmon_image_correlate(image, image, detmon_lg_config.m,
02227                                           detmon_lg_config.m);
02228         if(autocorr_image == NULL) {
02229             return -1;
02230         }
02231     } else {
02232         cpl_msg_info(cpl_func, "Autocorr deactivated by user");
02233         autocorr = 1.0;
02234         return autocorr;
02235     }
02236 #else
02237     if(detmon_lg_config.autocorr) {
02238         cpl_msg_info(cpl_func, "Autocorr via cpl_image_fft()");
02239         autocorr_image =
02240             irplib_detmon_autocorrelate(image, detmon_lg_config.m,
02241                                         detmon_lg_config.m);
02242         if(autocorr_image == NULL) {
02243             return -1;
02244         }
02245     } else {
02246         cpl_msg_info(cpl_func, "Autocorr deactivated by user");
02247         autocorr = 1.0;
02248         return autocorr;
02249     }
02250 #endif
02251 
02252     autocorr = cpl_image_get_flux(autocorr_image);
02253 
02254     if(detmon_lg_config.intermediate) {
02255         char * frame_name = irplib_sprintf("corr%d.fits", pos);
02256         plist = cpl_propertylist_new();
02257         cpl_propertylist_append_double(plist, "ESO DET DIT", 3);
02258         cpl_propertylist_append_double(plist, "EXPTIME", 3);
02259         cpl_image_save(autocorr_image, frame_name, CPL_BPP_IEEE_FLOAT, plist,
02260                        CPL_IO_DEFAULT);
02261         cpl_propertylist_delete(plist);
02262         cpl_free(frame_name);
02263     }
02264 
02265     cpl_image_delete(autocorr_image);
02266 
02267     return autocorr;
02268 }
02269 
02284 static int
02285 irplib_get_clean_mean_window(cpl_image * img,
02286                              const int llx,
02287                              const int lly,
02288                              const int urx, int ury,
02289                              const int kappa,
02290                              const int nclip,
02291                              double *clean_mean, double *clean_stdev)
02292 {
02293 
02294 
02295     double                  mean = 0;
02296     double                  stdev = 0;
02297     double                  threshold = 0;
02298     double                  lo_cut = 0;
02299     double                  hi_cut = 0;
02300     double                  lo_cut_p = 0;
02301     double                  hi_cut_p = 0;
02302 
02303     cpl_mask               *mask = NULL;
02304     cpl_image              *tmp = NULL;
02305     cpl_stats              *stats = NULL;
02306     int                     i = 0;
02307 
02308     if((tmp = cpl_image_extract(img, llx, lly, urx, ury)) == NULL) {
02309         cpl_msg_error(cpl_func, "Error extracting window");
02310         return -1;
02311     }
02312     cpl_image_accept_all(tmp);
02313     for(i = 0; i < nclip; i++) {
02314 
02315 
02316         cpl_stats_delete(stats);
02317         stats =
02318             cpl_stats_new_from_image(tmp, CPL_STATS_MEAN | CPL_STATS_STDEV);
02319         mean = cpl_stats_get_mean(stats);
02320         stdev = cpl_stats_get_stdev(stats);
02321 
02322         threshold = kappa * stdev;
02323         lo_cut = mean - threshold;
02324         hi_cut = mean + threshold;
02325 
02326         cpl_image_accept_all(tmp);
02327         mask = cpl_mask_threshold_image_create(tmp, lo_cut, hi_cut);
02328 
02329         cpl_mask_not(mask);
02330         cpl_image_reject_from_mask(tmp, mask);
02331         cpl_mask_delete(mask);
02332         if(lo_cut_p == lo_cut && hi_cut_p == hi_cut)
02333             break;
02334         else {
02335             lo_cut_p = lo_cut;
02336             hi_cut_p = hi_cut;
02337         }
02338 
02339     }
02340     *clean_mean = mean;
02341     *clean_stdev = stdev;
02342     cpl_image_delete(tmp);
02343     cpl_stats_delete(stats);
02344 
02345     return 0;
02346 
02347 
02348 }
02349 
02350 /*--------------------------------------------------------------------------*/
02351 
02352 /*
02353  * @brief  Function to save the products
02354  */
02355 
02356 /*--------------------------------------------------------------------------*/
02357 
02358 static cpl_error_code
02359 irplib_detmon_lg_save(const cpl_parameterlist * parlist,
02360                       cpl_frameset * frameset,
02361                       const char *recipe_name,
02362                       const char *pipeline_name,
02363                       const char *procatg_lintbl,
02364                       const char *procatg_gaintbl,
02365                       const char *procatg_lincoeff,
02366                       const char *procatg_bpm,
02367                       const char *package,
02368                       const cpl_imagelist * coeffs,
02369                       const cpl_table * gain_table,
02370                       const cpl_table * linear_table,
02371                       const cpl_image * bpms,
02372                       cpl_propertylist * qclist,
02373                       const int flag_sets,
02374                       const int which_set,
02375                       cpl_frameset * usedframes, cpl_boolean opt_nir)
02376 {
02377 
02378     cpl_frame              *ref_frame;
02379     cpl_propertylist       *plist;
02380     char                   *name_o;
02381     char                   *name_coeff;
02382 
02383 //    cpl_frame         * product_frame;
02384     int                     nb_images;
02385     int                     i;
02386     cpl_propertylist       *paflist;
02387 
02388     /**************************/
02389     /*  Write the GAIN TABLE  */
02390     /**************************/
02391 
02392     /* Set the file name for the table */
02393     if(!flag_sets) {
02394         name_o = irplib_sprintf("%s_gain_table.fits", recipe_name);
02395         assert(name_o != NULL);
02396     } else {
02397         name_o =
02398             irplib_sprintf("%s_gain_table_set%02d.fits", recipe_name,
02399                            which_set);
02400         assert(name_o != NULL);
02401     }
02402 
02403     /* Save the table */
02404     if(irplib_table_save(frameset, parlist, usedframes, gain_table,
02405                          NULL, recipe_name, procatg_gaintbl, qclist, NULL,
02406                          package, name_o)) {
02407         cpl_msg_error(cpl_func, "Cannot save the product: %s", name_o);
02408         cpl_free(name_o);
02409         cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
02410     }
02411 
02412     /* Free */
02413     cpl_free(name_o);
02414 
02415     /*******************************/
02416     /*  Write the LINEARITY TABLE  */
02417     /*******************************/
02418 
02419     /* Set the file name for the table */
02420     if(!flag_sets) {
02421         name_o = irplib_sprintf("%s_linearity_table.fits", recipe_name);
02422         assert(name_o != NULL);
02423     } else {
02424         name_o =
02425             irplib_sprintf("%s_linearity_table_set%02d.fits", recipe_name,
02426                            which_set);
02427         assert(name_o != NULL);
02428     }
02429 
02430     /* Save the table */
02431     if(irplib_table_save(frameset, parlist, usedframes, linear_table,
02432                          NULL, recipe_name, procatg_lintbl, qclist, NULL,
02433                          package, name_o)) {
02434         cpl_msg_error(cpl_func, "Cannot save the product: %s", name_o);
02435         cpl_free(name_o);
02436         cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
02437     }
02438 
02439     /* Free */
02440     cpl_free(name_o);
02441 
02442     if(opt_nir == NIR) {
02443 
02444     /***************************/
02445     /*  Write the COEFFS FITS  */
02446     /***************************/
02447 
02448         nb_images = cpl_imagelist_get_size(coeffs);
02449 
02450         for(i = 0; i < nb_images; i++) {
02451             /* Set the file name for each image */
02452             if(!flag_sets) {
02453                 name_o =
02454                     irplib_sprintf("%s_lin_coeff_%d.fits", recipe_name, i);
02455                 assert(name_o != NULL);
02456             } else {
02457                 name_o =
02458                     irplib_sprintf("%s_lin_coeff_%d_set%02d.fits",
02459                                    recipe_name, i, which_set);
02460                 assert(name_o != NULL);
02461             }
02462 
02463             name_coeff = irplib_sprintf("%s_%d", procatg_lincoeff, i);
02464             assert(name_coeff != NULL);
02465 
02466             /* Save the coefficient images */
02467             if(irplib_image_save(frameset, parlist, usedframes,
02468                                  cpl_imagelist_get(coeffs, i),
02469                                  CPL_BPP_IEEE_FLOAT, recipe_name, name_coeff,
02470                                  qclist, NULL, package, name_o)) {
02471                 cpl_msg_error(cpl_func, "Could not save product");
02472                 cpl_free(name_o);
02473                 cpl_free(name_coeff);
02474                 cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
02475             }
02476 
02477             /* Free */
02478             cpl_free(name_o);
02479             cpl_free(name_coeff);
02480         }
02481 
02482     /*******************************/
02483     /*  Write the BAD PIXEL MAP    */
02484     /*******************************/
02485 
02486         /* Set the file name for the bpm */
02487         if(!flag_sets) {
02488             name_o = irplib_sprintf("%s_bpm.fits", recipe_name);
02489             assert(name_o != NULL);
02490         } else {
02491             name_o =
02492                 irplib_sprintf("%s_bpm_set%02d.fits", recipe_name, which_set);
02493             assert(name_o != NULL);
02494         }
02495 
02496         /* Save the bpm */
02497         if(irplib_image_save(frameset, parlist, usedframes, bpms,
02498                              CPL_BPP_IEEE_FLOAT, recipe_name, procatg_bpm,
02499                              qclist, NULL, package, name_o)) {
02500             cpl_msg_error(cpl_func, "Cannot save the product: %s", name_o);
02501             cpl_free(name_o);
02502             cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
02503         }
02504 
02505         /* Free */
02506         cpl_free(name_o);
02507 
02508     }
02509 
02510     /*******************************/
02511     /*  Write the PAF file         */
02512     /*******************************/
02513 
02514     /* Get FITS header from reference file */
02515     ref_frame = cpl_frameset_get_first(frameset);
02516     if((plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
02517                                       0)) == NULL) {
02518         cpl_msg_error(cpl_func, "getting header from reference frame");
02519         cpl_ensure_code(0, cpl_error_get_code());
02520     }
02521 
02522     /* Get the keywords for the paf file */
02523     paflist = cpl_propertylist_new();
02524     cpl_propertylist_copy_property_regexp(paflist, plist,
02525                                           "^(ARCFILE|MJD-OBS|ESO TPL ID|"
02526                                           "DATE-OBS|ESO DET DIT|ESO DET NDIT|"
02527                                           "ESO DET NCORRS|"
02528                                           "ESO DET MODE NAME)$", 0);
02529 
02530     cpl_propertylist_append(paflist, qclist);
02531 
02532     /* Set the file name for the bpm */
02533     if(!flag_sets) {
02534         name_o = irplib_sprintf("%s.paf", recipe_name);
02535         assert(name_o != NULL);
02536     } else {
02537         name_o = irplib_sprintf("%s_set%02d.paf", recipe_name, which_set);
02538         assert(name_o != NULL);
02539     }
02540 
02541     /* Save the PAF */
02542     if(irplib_paf_save(pipeline_name, recipe_name, paflist, name_o)) {
02543         cpl_msg_error(cpl_func, "Cannot save the product: %s", name_o);
02544         cpl_free(name_o);
02545         cpl_propertylist_delete(paflist);
02546         cpl_propertylist_delete(plist);
02547         cpl_free(name_o);
02548         cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
02549     }
02550 
02551     cpl_propertylist_delete(plist);
02552     cpl_propertylist_delete(paflist);
02553     cpl_free(name_o);
02554 
02555     return CPL_ERROR_NONE;
02556 }
02557 
02558 /*---------------------------------------------------------------------------*/
02559 
02560 /*
02561  * @brief  Function to save the products
02562 
02563  */
02564 
02565 /*---------------------------------------------------------------------------*/
02566 
02567 static                  cpl_error_code
02568 irplib_detmon_opt_contamination(const cpl_image * reduced,
02569                                 cpl_propertylist * qclist)
02570 {
02571     double                  flux[5];
02572 
02573     flux[0] = cpl_image_get_flux_window(reduced,
02574                                         detmon_lg_config.llx1,
02575                                         detmon_lg_config.lly1,
02576                                         detmon_lg_config.urx1,
02577                                         detmon_lg_config.ury1);
02578 
02579     flux[1] = cpl_image_get_flux_window(reduced,
02580                                         detmon_lg_config.llx2,
02581                                         detmon_lg_config.lly2,
02582                                         detmon_lg_config.urx2,
02583                                         detmon_lg_config.ury2);
02584     cpl_propertylist_append_double(qclist, "ESO QC CONTAM2",
02585                                    flux[1] / flux[0]);
02586 
02587     flux[2] = cpl_image_get_flux_window(reduced,
02588                                         detmon_lg_config.llx3,
02589                                         detmon_lg_config.lly3,
02590                                         detmon_lg_config.urx3,
02591                                         detmon_lg_config.ury3);
02592     cpl_propertylist_append_double(qclist, "ESO QC CONTAM3",
02593                                    flux[2] / flux[0]);
02594 
02595     flux[3] = cpl_image_get_flux_window(reduced,
02596                                         detmon_lg_config.llx4,
02597                                         detmon_lg_config.lly4,
02598                                         detmon_lg_config.urx4,
02599                                         detmon_lg_config.ury4);
02600     cpl_propertylist_append_double(qclist, "ESO QC CONTAM4",
02601                                    flux[3] / flux[0]);
02602 
02603     flux[4] = cpl_image_get_flux_window(reduced,
02604                                         detmon_lg_config.llx5,
02605                                         detmon_lg_config.lly5,
02606                                         detmon_lg_config.urx5,
02607                                         detmon_lg_config.ury5);
02608     cpl_propertylist_append_double(qclist, "ESO QC CONTAM5",
02609                                    flux[4] / flux[0]);
02610 
02611     return CPL_ERROR_NONE;
02612 }
02613 
02614 static int
02615 irplib_detmon_opt_lampcr(cpl_frameset * cur_fset)
02616 {
02617     cpl_image              *on;
02618     cpl_image              *off;
02619     cpl_frame              *first_off;
02620     cpl_frame              *first_on;
02621     cpl_propertylist       *plist;
02622     double                  dit;
02623 
02624     if((first_off = cpl_frameset_get_first(cur_fset)) == NULL) {
02625         cpl_ensure_code(0, cpl_error_get_code());
02626     }
02627     if((first_on = cpl_frameset_get_next(cur_fset)) == NULL) {
02628         cpl_ensure_code(0, cpl_error_get_code());
02629     }
02630 
02631     on = cpl_image_load(cpl_frame_get_filename(first_on),
02632                         CPL_TYPE_FLOAT, 0, 0);
02633     off = cpl_image_load(cpl_frame_get_filename(first_off),
02634                          CPL_TYPE_FLOAT, 0, 0);
02635     cpl_image_subtract(on, off);
02636 
02637     plist = cpl_propertylist_load(cpl_frame_get_filename(first_on), 0);
02638     if(plist == NULL) {
02639         cpl_msg_error(cpl_func, "getting header from reference frame");
02640         cpl_image_delete(on);
02641         cpl_image_delete(off);
02642         cpl_ensure_code(0, cpl_error_get_code());
02643     }
02644 
02645     dit = irplib_pfits_get_exptime(plist);
02646 
02647     detmon_lg_config.cr = cpl_image_get_mean(on) / dit;
02648 
02649     cpl_image_delete(on);
02650     cpl_image_delete(off);
02651     cpl_propertylist_delete(plist);
02652 
02653     return 0;
02654 }
02655 
02656 int
02657 irplib_detmon_dfs_set_groups(cpl_frameset * set,
02658                              const char *tag_on, const char *tag_off)
02659 {
02660     cpl_frame              *cur_frame;
02661     const char             *tag;
02662     int                     nframes;
02663     int                     i;
02664 
02665     /* Check entries */
02666     if(set == NULL)
02667         return -1;
02668 
02669     /* Initialize */
02670     nframes = cpl_frameset_get_size(set);
02671 
02672     /* Loop on frames */
02673     for(i = 0; i < nframes; i++) {
02674         cur_frame = cpl_frameset_get_frame(set, i);
02675         tag = cpl_frame_get_tag(cur_frame);
02676 
02677         /* RAW frames */
02678         if(!strcmp(tag, tag_on) || !strcmp(tag, tag_off))
02679             cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW);
02680         /* CALIB frames */
02681 
02682 /*        else if (!strcmp(tag, IIINSTRUMENT_CALIB_FLAT))
02683             cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB) ;
02684 */
02685     }
02686     return 0;
02687 }

Generated on Tue Jun 19 14:39:14 2007 for UVES Pipeline Reference Manual by  doxygen 1.4.6