naco_spc_wavecal.c

00001 /* $Id: naco_spc_wavecal.c,v 1.76 2012/09/06 08:29:10 llundin Exp $
00002  *
00003  * This file is part of the NACO Pipeline
00004  * Copyright (C) 2002,2003 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: llundin $
00023  * $Date: 2012/09/06 08:29:10 $
00024  * $Revision: 1.76 $
00025  * $Name: naco-4_3_3 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*-----------------------------------------------------------------------------
00033                                 Includes
00034  -----------------------------------------------------------------------------*/
00035 
00036 #include "naco_recipe.h"
00037 #if 0
00038 #include "irplib_distortion.h"
00039 #endif
00040 
00041 #include "irplib_wlxcorr.h"
00042 
00043 #include "naco_spc.h"
00044 
00045 #include "irplib_polynomial.h"
00046 #include "irplib_wavecal.h"
00047 #include "irplib_distortion.h"
00048 
00049 
00050 #include <string.h>
00051 
00052 /*-----------------------------------------------------------------------------
00053                             Recipe defines
00054  -----------------------------------------------------------------------------*/
00055 
00056 #define RECIPE_STRING   "naco_spc_wavecal"
00057 
00058 /*-----------------------------------------------------------------------------
00059                             Private Functions prototypes
00060  -----------------------------------------------------------------------------*/
00061 
00062 static cpl_error_code naco_spc_wavecal_reduce(cpl_imagelist *,
00063                                               cpl_polynomial *,
00064                                               cpl_propertylist *,
00065                                               const char *,
00066                                               const irplib_framelist *,
00067                                               const cpl_table *,
00068                                               const cpl_bivector *,
00069                                               const cpl_parameterlist *);
00070 
00071 static cpl_error_code naco_spc_wavecal_get_slitw(const cpl_propertylist *,
00072                                                  double *);
00073 
00074 
00075 static cpl_error_code naco_spc_wavecal_1d(cpl_imagelist          * self,
00076                                           cpl_propertylist       * qclist,
00077                                           const cpl_image        * spec2d,
00078                                           const cpl_propertylist * plist,
00079                                           const char             * tag,
00080                                           const cpl_polynomial   * phdisp,
00081                                           const cpl_bivector     * argonlines,
00082                                           const cpl_parameterlist* parlist);
00083 
00084 static
00085 cpl_error_code naco_image_fill_column_from_dispersion(cpl_image *, int, cpl_boolean,
00086                                                       const cpl_polynomial *);
00087 
00088 static cpl_error_code naco_spc_wavecal_distortion(cpl_image *,
00089                                                   cpl_propertylist *,
00090                                                   const cpl_parameterlist *);
00091 
00092 static cpl_error_code naco_spc_physdisp_fill(cpl_polynomial *, const char *,
00093                                              const cpl_table *);
00094 
00095 static cpl_error_code naco_spc_physdisp_transform(cpl_polynomial *, double,
00096                                                   double, int, double, double,
00097                                                   double, double);
00098 
00099 static cpl_error_code naco_spc_wavecal_qc(cpl_propertylist *,
00100                                            cpl_propertylist *,
00101                                            const irplib_framelist *);
00102 
00103 static cpl_error_code naco_spc_wavecal_save(cpl_frameset *,
00104                                              const cpl_parameterlist *,
00105                                              const cpl_propertylist *,
00106                                              const cpl_propertylist *,
00107                                              const cpl_imagelist *,
00108                                              const cpl_polynomial *,
00109                                              int, const irplib_framelist *);
00110 
00111 static cpl_error_code naco_spc_wavecal_fill_table(cpl_table *,
00112                                                   const cpl_polynomial *);
00113 
00114 static cpl_error_code naco_spc_wavecal_count_lines(cpl_propertylist     *,
00115                                                    const cpl_bivector   *,
00116                                                    double, double);
00117 static
00118 cpl_error_code naco_spc_wavecal_interpolate_rejected(cpl_image *,
00119                                                      const cpl_polynomial *);
00120 
00121 static cpl_error_code naco_spc_wavecal_qc_lines(cpl_propertylist     *,
00122                                                 const cpl_image *,
00123                                                 const cpl_apertures *);
00124 
00125 NACO_RECIPE_DEFINE(naco_spc_wavecal,
00126                    NACO_PARAM_PLOT | NACO_PARAM_FORCE,
00127                    "Wavelength calibration using arc lamps",
00128                    RECIPE_STRING
00129                    " -- NACO spectrocopy wavelength calibration from "
00130                    "lamp images.\n" 
00131                    "The files listed in the Set Of Frames (sof-file) "
00132                    "must be tagged:\n" 
00133                    "NACO-raw-file.fits " NACO_SPC_LAMPWAVE_RAW "\n"
00134                    "NACO-spectrum-model.fits " NACO_SPC_MODEL " .\n"
00135                    "\n"
00136                    NACO_SPC_MAN_MODESPLIT "\n\n"
00137                    "Furthermore, each input frame must have a value of "
00138                    NACO_PFITS_BOOL_LAMP1 " that is false for off-frames and "
00139                    "true for on-frames.\n"
00140                    "\n"
00141                    "Products:\n"
00142                    NACO_CALIB_ARC_MAP ": Primary HDU with the wavelength map, "
00143                    "i.e. the pixel values are wavelengths. The first extension "
00144                    "is a single-row table with the polynomial coefficients of "
00145                    "the 2D dispersion relation, lambda = P(x, y).\n"
00146                    NACO_CALIB_ARC_DIFF ": Primary HDU with the difference image "
00147                    "of the lamp-on and -off image. The first extension is the "
00148                    "distortion corrected image, were all the arc-lines are "
00149                    "straight. The dispersion in the distortion corrected image "
00150                    "is given by the central dispersion, lambda = P(512.5, y).");
00151 
00152 
00153 /*----------------------------------------------------------------------------*/
00157 /*----------------------------------------------------------------------------*/
00158 
00159 /*-----------------------------------------------------------------------------
00160                                 Functions code
00161  -----------------------------------------------------------------------------*/
00162 
00163 /*----------------------------------------------------------------------------*/
00170 /*----------------------------------------------------------------------------*/
00171 static int naco_spc_wavecal(cpl_frameset            * framelist,
00172                              const cpl_parameterlist * parlist)
00173 {
00174     cpl_errorstate       cleanstate = cpl_errorstate_get();
00175     irplib_framelist   * allframes = NULL;
00176     irplib_framelist   * rawframes = NULL;
00177     irplib_framelist   * f_one     = NULL;
00178     const char        ** taglist   = NULL;
00179     cpl_imagelist      * lamp_wave = cpl_imagelist_new();
00180     cpl_polynomial     * disp2d    = cpl_polynomial_new(2);
00181     cpl_propertylist   * qclist    = cpl_propertylist_new();
00182     cpl_propertylist   * paflist   = cpl_propertylist_new();
00183     const cpl_frame    * modelframe;
00184     const char         * modelfile;
00185     cpl_table          * modeltab  = NULL;
00186     const cpl_frame    * argonframe;
00187     const char         * argonfile;
00188     cpl_table          * argontab  = NULL;
00189     cpl_bivector       * argonlines= NULL;
00190     cpl_vector         * argonlinex= NULL;
00191     cpl_vector         * argonliney= NULL;
00192     int                  nargonlines;
00193     int                  nb_good   = 0;
00194     int                  nsets;
00195     int                  i;
00196     
00197 
00198     /* Identify the RAW and CALIB frames in the input frameset */
00199     skip_if (naco_dfs_set_groups(framelist));
00200 
00201     allframes = irplib_framelist_cast(framelist);
00202     skip_if(allframes == NULL);
00203 
00204     rawframes = irplib_framelist_extract(allframes, NACO_SPC_LAMPWAVE_RAW);
00205     skip_if(rawframes == NULL);
00206 
00207     irplib_framelist_empty(allframes);
00208 
00209     /* The parameters of the 1st guess of the dispersion relation */
00210     modelframe = cpl_frameset_find_const(framelist, NACO_SPC_MODEL);
00211     error_if (modelframe == NULL, CPL_ERROR_DATA_NOT_FOUND, "No input frame "
00212               "is tagged %s", NACO_SPC_MODEL);
00213 
00214     modelfile = cpl_frame_get_filename(modelframe);
00215     skip_if (modelfile == NULL);
00216 
00217     modeltab = cpl_table_load(modelfile, 1, 0);
00218     error_if (modeltab == NULL, cpl_error_get_code(), "Could not "
00219               "load the table with the model parameters");
00220 
00221     /* The argon lines */
00222     argonframe = cpl_frameset_find_const(framelist, NACO_SPC_ARGON);
00223     error_if (argonframe == NULL, CPL_ERROR_DATA_NOT_FOUND, "No input frame "
00224               "is tagged %s", NACO_SPC_ARGON);
00225 
00226     argonfile = cpl_frame_get_filename(argonframe);
00227     skip_if (argonfile == NULL);
00228 
00229     argontab = cpl_table_load(argonfile, 1, 0);
00230     error_if (argontab == NULL, cpl_error_get_code(), "Could not "
00231               "load the table with the argon lines");
00232 
00233     /* Wrap a bivector around the argontable */
00234     nargonlines = cpl_table_get_nrow(argontab);
00235 
00236     argonlinex = cpl_vector_wrap(nargonlines,
00237                                  cpl_table_get_data_double(argontab,
00238                                                            NACO_SPC_LAB_WAVE));
00239     skip_if(argonlinex == NULL);
00240 
00241     argonliney = cpl_vector_wrap(nargonlines,
00242                                  cpl_table_get_data_double(argontab,
00243                                                           NACO_SPC_LAB_INTENS));
00244     skip_if(argonliney == NULL);
00245 
00246 #ifdef NACO_SPC_WAVECAL_LOG
00247     bug_if(cpl_vector_add_scalar(argonliney, 1.0));
00248     skip_if(cpl_vector_logarithm(argonliney, exp(1.0)));
00249 #endif
00250 
00251     argonlines = cpl_bivector_wrap_vectors(argonlinex, argonliney);
00252     bug_if(argonlines == NULL);
00253 
00254     skip_if(irplib_framelist_load_propertylist_all(rawframes, 0, "^("
00255                                                    NACO_PFITS_REGEXP_SPCWAVE "|"
00256                                                    NACO_PFITS_REGEXP_SPCWAVE_PAF
00257                                                    ")$", CPL_FALSE));
00258 
00259     taglist = naco_framelist_set_tag(rawframes, naco_spc_make_tag, &nsets);
00260     skip_if(taglist == NULL);
00261 
00262     cpl_msg_info(cpl_func, "Identified %d setting(s) in %d frames",
00263                  nsets, irplib_framelist_get_size(rawframes));
00264 
00265     /* Extract settings and reduce each of them */
00266     for (i=0 ; i < nsets ; i++) {
00267         int n_one;
00268         cpl_error_code error;
00269 
00270         /* Reduce data set nb i */
00271         cpl_msg_info(cpl_func, "Reducing data set %d of %d", i+1, nsets);
00272 
00273         /* Reduce data set nb i */
00274         f_one = irplib_framelist_extract(rawframes, taglist[i]);
00275 
00276         bug_if (f_one == NULL);
00277 
00278         n_one = irplib_framelist_get_size(f_one);
00279         
00280         /* Reset the tag */
00281         bug_if(irplib_framelist_set_tag_all(f_one, NACO_SPC_LAMPWAVE_RAW));
00282 
00283         cpl_msg_info(cpl_func, "Reducing frame set %d of %d (size=%d) with "
00284                      "setting: %s", i+1, nsets, n_one, taglist[i]);
00285 
00286         error = naco_spc_wavecal_reduce(lamp_wave, disp2d, qclist, taglist[i],
00287                                         f_one, modeltab, argonlines, parlist);
00288         
00289         /* Save the products */
00290         if (error) {
00291             if (nsets > 1)
00292                 irplib_error_recover(cleanstate, "Could not do the wavelength "
00293                                  "calibration for this setting");
00294         } else {
00295             cpl_errorstate prestate = cpl_errorstate_get();
00296 
00297             skip_if(naco_spc_wavecal_qc(qclist, paflist, f_one));
00298 
00299             /* PRO.CATG */
00300             bug_if (cpl_propertylist_append_string(paflist, CPL_DFS_PRO_CATG,
00301                                                    NACO_CALIB_ARC_MAP));
00302 
00303             /* modelframe and argonframe will not be modified */
00304             /* Cannot skip with frames shared among two framelists */
00305             (void)irplib_framelist_set(f_one, (cpl_frame*)modelframe, n_one);
00306             (void)irplib_framelist_set(f_one, (cpl_frame*)argonframe, n_one+1);
00307             (void)naco_spc_wavecal_save(framelist, parlist, qclist, paflist,
00308                                         lamp_wave, disp2d, i+1, f_one);
00309             (void)irplib_framelist_unset(f_one, n_one+1, NULL);
00310             (void)irplib_framelist_unset(f_one, n_one, NULL);
00311             skip_if(!cpl_errorstate_is_equal(prestate));
00312 
00313             do {
00314                 cpl_image_delete(cpl_imagelist_unset(lamp_wave, 0));
00315             } while (cpl_imagelist_get_size(lamp_wave) > 0);
00316 
00317             nb_good++;
00318         }
00319         cpl_propertylist_empty(qclist);
00320         cpl_propertylist_empty(paflist);
00321         irplib_framelist_delete(f_one);
00322         f_one = NULL;
00323     }
00324 
00325     irplib_ensure(nb_good > 0, CPL_ERROR_DATA_NOT_FOUND,
00326                   "None of the %d sets could be reduced", nsets);
00327     
00328     end_skip;
00329 
00330     cpl_free(taglist);
00331     cpl_imagelist_delete(lamp_wave);
00332     cpl_table_delete(modeltab);
00333     cpl_bivector_unwrap_vectors(argonlines);
00334     (void)cpl_vector_unwrap(argonlinex);
00335     (void)cpl_vector_unwrap(argonliney);
00336     cpl_table_delete(argontab);
00337     irplib_framelist_delete(f_one);
00338     irplib_framelist_delete(allframes);
00339     irplib_framelist_delete(rawframes);
00340     cpl_propertylist_delete(qclist);
00341     cpl_propertylist_delete(paflist);
00342     cpl_polynomial_delete(disp2d);
00343 
00344     return cpl_error_get_code();
00345 }
00346 
00347 /*----------------------------------------------------------------------------*/
00360 /*----------------------------------------------------------------------------*/
00361 static cpl_error_code naco_spc_wavecal_reduce(cpl_imagelist * imglist,
00362                                               cpl_polynomial * disp2d,
00363                                               cpl_propertylist * qclist,
00364                                               const char * tag,
00365                                               const irplib_framelist * framelist,
00366                                               const cpl_table * modeltab,
00367                                               const cpl_bivector * argonlines,
00368                                               const cpl_parameterlist * parlist)
00369 {
00370     cpl_image      * self = NULL;
00371     cpl_image      * corrected = NULL;
00372     cpl_imagelist  * difflist = cpl_imagelist_new();
00373     cpl_polynomial * disp1d = NULL;
00374     cpl_polynomial * collapse = cpl_polynomial_new(1);
00375     const int        nplot = naco_parameterlist_get_int(parlist, RECIPE_STRING,
00376                                                        NACO_PARAM_PLOT);
00377     const cpl_size   deg0 = 0;
00378     cpl_polynomial * phdisp = cpl_polynomial_new(1);
00379     const cpl_propertylist * plist
00380         = irplib_framelist_get_propertylist_const(framelist, 0);
00381     const char     * specmode
00382         = irplib_pfits_get_string(plist, NACO_PFITS_STRING_SPECMODE);
00383     const double     wlen
00384         = irplib_pfits_get_double(plist, NACO_PFITS_DOUBLE_CWLEN);
00385     cpl_propertylist * lampkeys = cpl_propertylist_new();
00386     cpl_stats      * stats = NULL;
00387     double           adumin, adumax;
00388     double           mse = 0.0;
00389     cpl_vector     * center = cpl_vector_new(2);
00390     int              ny; /* Wavelength resolution */
00391 
00392     bug_if (0);
00393     bug_if (imglist    == NULL);
00394     bug_if (qclist     == NULL);
00395     bug_if (framelist  == NULL);
00396     bug_if (modeltab   == NULL);
00397     bug_if (argonlines == NULL);
00398     bug_if (parlist    == NULL);
00399     bug_if (cpl_imagelist_get_size(imglist));
00400 
00401     /* On-frames have lamp1 on and lamp2 off */
00402     bug_if(cpl_propertylist_append_int(lampkeys, NACO_PFITS_BOOL_LAMP1, 1));
00403     bug_if(cpl_propertylist_append_int(lampkeys, NACO_PFITS_INT_LAMP2,  0));
00404   
00405     skip_if(naco_imagelist_load_diff(difflist, framelist, lampkeys));
00406 
00407     bug_if(0);
00408 
00409     if (cpl_imagelist_get_size(difflist) > 1) {
00410         cpl_msg_warning(cpl_func, "Averaging %d difference images "
00411                         "into one image for setting %s",
00412                         (int)cpl_imagelist_get_size(difflist), tag);
00413         self = cpl_imagelist_collapse_create(difflist);
00414     } else {
00415         self = cpl_imagelist_unset(difflist, 0);
00416     }
00417 
00418     stats = cpl_stats_new_from_image(self, CPL_STATS_MIN | CPL_STATS_MAX);
00419     adumin = cpl_stats_get_min(stats);
00420     adumax = cpl_stats_get_max(stats);
00421 
00422     cpl_msg_info(cpl_func, "Difference image for '%s' has ADUs in range: "
00423                  "%g -> %g", tag, adumin, adumax);
00424     if (adumin < 0.0) {
00425         cpl_msg_info(cpl_func, "Setting negative ADUs to zero");
00426         bug_if(cpl_image_threshold(self, 0.0, FLT_MAX, 0.0, FLT_MAX));
00427     }
00428 
00429     if (nplot > 2) {
00430       cpl_errorstate prestate = cpl_errorstate_get();
00431       cpl_plot_image("", "t 'Difference image'", "", self);
00432       if (!cpl_errorstate_is_equal(prestate)) {
00433         cpl_errorstate_set(prestate);
00434       }
00435     }
00436 
00437     corrected = cpl_image_duplicate(self);
00438     skip_if(naco_spc_wavecal_distortion(corrected, qclist, parlist));
00439 
00440     ny = cpl_image_get_size_y(self);
00441     bug_if (0);
00442 
00443 
00444     skip_if(naco_spc_physdisp_fill(phdisp, specmode, modeltab));
00445 
00446     cpl_msg_info(cpl_func, "Wavelength range using physical model [micron]: "
00447                  "%g -> %g",
00448                  cpl_polynomial_eval_1d(phdisp, 0.5,    NULL),
00449                  cpl_polynomial_eval_1d(phdisp, 0.5 + ny, NULL));
00450 
00451     if (naco_parameterlist_get_bool(parlist, RECIPE_STRING, NACO_PARAM_FORCE)) {
00452         /* FIXME: cpl_wlcalib_xc_best_poly() also fails with this */
00453         const cpl_size idegree = 0;
00454         const double dwlen
00455             = cpl_polynomial_eval_1d(phdisp, 0.5*(1+ny), NULL) - wlen;
00456         const double newval
00457             = cpl_polynomial_get_coeff(phdisp, &idegree) - dwlen;
00458 
00459         bug_if(cpl_polynomial_set_coeff(phdisp, &idegree, newval));
00460     }
00461 
00462     cpl_msg_info(cpl_func, "Central Wavelength (model <=> CWLEN) [micron]: "
00463                  "%g <=> %g", cpl_polynomial_eval_1d(phdisp, 0.5*(1+ny), NULL),
00464                  wlen);
00465 
00466 
00467     skip_if(naco_spc_wavecal_1d(imglist, qclist, self, plist, tag, phdisp,
00468                                 argonlines, parlist));
00469 
00470     skip_if(irplib_polynomial_fit_2d_dispersion(disp2d,
00471                                                 cpl_imagelist_get(imglist, 0),
00472                                                 4, &mse));
00473 
00474     cpl_msg_info(cpl_func, "2D-dispersion with MSE=%g for setting %s", mse, tag);
00475     skip_if(cpl_polynomial_dump(disp2d, stdout));
00476 
00477     skip_if(naco_spc_wavecal_interpolate_rejected(cpl_imagelist_get(imglist, 0),
00478                                                   disp2d));
00479 
00480     bug_if(cpl_vector_set(center, 0, 0.5*(1+cpl_image_get_size_x(self))));
00481     bug_if(cpl_vector_set(center, 1, 0.5*(1+cpl_image_get_size_y(self))));
00482 
00483     bug_if(cpl_propertylist_append_double(qclist, "ESO QC WLEN",
00484                                           cpl_polynomial_eval(disp2d, center)));
00485 
00486     /* Central 1D polynomial */
00487     bug_if(cpl_polynomial_set_coeff(collapse, &deg0,
00488                                     0.5 * (1+cpl_image_get_size_x(self))));
00489 
00490     disp1d = cpl_polynomial_extract(disp2d, 0, collapse);
00491     cpl_msg_info(cpl_func, "Central 1D-dispersion (at x=%g)",
00492                  0.5*(1+cpl_image_get_size_x(self)));
00493     skip_if(cpl_polynomial_dump(disp1d, stdout));
00494 
00495     end_skip;
00496 
00497     if (cpl_error_get_code()) {
00498         cpl_image_delete(self);
00499         cpl_image_delete(corrected);
00500     } else {
00501         cpl_imagelist_set(imglist, self, 1);
00502         cpl_imagelist_set(imglist, corrected, 2);
00503     }
00504 
00505     cpl_vector_delete(center);
00506     cpl_propertylist_delete(lampkeys);
00507     cpl_imagelist_delete(difflist);
00508     cpl_stats_delete(stats);
00509     cpl_polynomial_delete(phdisp);
00510     cpl_polynomial_delete(disp1d);
00511     cpl_polynomial_delete(collapse);
00512 
00513     return cpl_error_get_code();
00514 }
00515 
00516 
00517 /*----------------------------------------------------------------------------*/
00530 /*----------------------------------------------------------------------------*/
00531 static cpl_error_code naco_spc_wavecal_1d(cpl_imagelist          * self,
00532                                           cpl_propertylist       * qclist,
00533                                           const cpl_image        * spec2d,
00534                                           const cpl_propertylist * plist,
00535                                           const char             * tag,
00536                                           const cpl_polynomial   * phdisp,
00537                                           const cpl_bivector     * argonlines,
00538                                           const cpl_parameterlist* parlist)
00539 {
00540 
00541     cpl_errorstate prestate = cpl_errorstate_get();
00542     const int        nx = cpl_image_get_size_x(spec2d); /* Spatial resolution */
00543     const int        ny = cpl_image_get_size_y(spec2d); /* Wavelength resolution */
00544     cpl_vector     * vspec1d  = NULL;
00545     cpl_polynomial * disp     = NULL;
00546     cpl_polynomial * dispcen  = NULL;
00547     cpl_polynomial * phshift  = cpl_polynomial_duplicate(phdisp);
00548     cpl_polynomial * dispdif  = cpl_polynomial_new(1);
00549     /* Initialize to zero */
00550     cpl_vector     * linepix
00551         = cpl_vector_wrap(cpl_bivector_get_size(argonlines),
00552                           cpl_calloc(cpl_bivector_get_size(argonlines),
00553                                      sizeof(double)));
00554     double           slitw = 0.0; /* Fix (false) uninit warning */
00555     const double     wfwhm = 4.0;
00556     double           xtrunc;
00557     double           xc, xcmean, xcstdev;
00558     const int        nplot = naco_parameterlist_get_int(parlist, RECIPE_STRING,
00559                                                         NACO_PARAM_PLOT);
00560     const int        plotstep = nplot > 0 ? nx / (1<<nplot) : nx + 1;
00561     const int        degree = cpl_polynomial_get_degree(phdisp);
00562     const int        fitdeg = degree > 4 ? degree : 4; /* Fit at least 4th degree */
00563     cpl_image      * imgdisp = cpl_image_new(nx, ny, cpl_image_get_type(spec2d));
00564     cpl_vector     * vxcall = cpl_vector_new(nx);
00565     /* One practical limitation on hshiftmax is that it may not be so big, as
00566        to cause phdisp to be evaluated outside its range of monotony. */
00567     const int        hshiftmax = ny/4;
00568     irplib_line_spectrum_model model;
00569     const double     pixstep = 0.25;
00570     const double     pixtol = 1e-5; /* 1e-6 leads to more accuracy, is slower */
00571     const int        istart = nx/2; /* Start on central column */
00572     const int        maxite = fitdeg * 100;
00573     int              ispec = istart;
00574     double           wl2dmin = FLT_MAX;
00575     double           wl2dmax = 0.0;
00576     cpl_boolean      isfirst = CPL_TRUE;
00577 
00578     bug_if(0);
00579     bug_if(qclist     == NULL);
00580     bug_if(spec2d     == NULL);
00581     bug_if(plist      == NULL);
00582     bug_if(phdisp     == NULL);
00583     bug_if(argonlines == NULL);
00584 
00585 
00586     skip_if(naco_spc_wavecal_get_slitw(plist, &slitw));
00587 
00588     cpl_msg_info(cpl_func, "Slitwidth [pixel]: %g", slitw);
00589 
00590     xtrunc = 0.5 * slitw + 5.0 * wfwhm * CPL_MATH_SIG_FWHM;
00591 
00592     memset(&model, 0, sizeof(model));
00593     model.wslit = slitw;
00594     model.wfwhm = wfwhm;
00595     model.xtrunc = xtrunc;
00596     model.lines = argonlines;
00597     model.linepix = linepix;
00598     model.cost = 0;
00599 
00600     vspec1d = cpl_vector_new_from_image_column(spec2d, ispec);
00601 #ifdef NACO_SPC_WAVECAL_LOG
00602     bug_if(cpl_vector_add_scalar(vspec1d, 1.0));
00603     skip_if(cpl_vector_logarithm(vspec1d, exp(1.0)));
00604 #endif
00605 
00606     if (nplot > 0) {
00607         char         * title = cpl_sprintf("t 'Uncalibrated 1D-spectrum "
00608                                            "using %s' w linespoints", tag);
00609         cpl_vector   * vphys = cpl_vector_new(ny);
00610         cpl_bivector * bspec1d = cpl_bivector_wrap_vectors(vphys, vspec1d);
00611 
00612         (void)cpl_vector_fill_polynomial(vphys, phdisp, 1.0, 1.0);
00613 
00614 
00615         cpl_plot_bivector("set grid;set xlabel 'Wavelength [micron]';"
00616                           "set ylabel 'Intensity [ADU]';", title, "",
00617                           bspec1d);
00618         cpl_free(title);
00619         cpl_vector_delete(vphys);
00620         cpl_bivector_unwrap_vectors(bspec1d);
00621         if (!cpl_errorstate_is_equal(prestate)) {
00622             cpl_errorstate_set(prestate);
00623         }
00624     }
00625 
00626     skip_if(irplib_polynomial_shift_1d_from_correlation(phshift, vspec1d,
00627                                                         (void*)&model,
00628                                                      irplib_vector_fill_line_spectrum,
00629                                                         hshiftmax, nplot > 0,
00630                                                         NULL));
00631 
00632     if (nplot > 0) {
00633         bug_if(irplib_plot_spectrum_and_model(vspec1d, phshift, (void*)&model,
00634                                             irplib_vector_fill_line_spectrum));
00635     }
00636 
00637     bug_if(irplib_polynomial_subtract(dispdif, phshift, phdisp));
00638 
00639     cpl_msg_info(cpl_func, "Changes to model polynomial by XC is of degree %d",
00640                  (int)cpl_polynomial_get_degree(dispdif));
00641     skip_if(cpl_polynomial_dump(dispdif, stdout));
00642 
00643     disp = cpl_polynomial_duplicate(phshift);
00644     /* In the unlikely event that the calibration fails on the central column */
00645     dispcen = cpl_polynomial_duplicate(disp); 
00646 
00647     /* Right half starting from central column */
00648     for (; ispec <= nx; ispec++) {
00649         const cpl_size prevcost = model.cost;
00650 
00651         if (!isfirst) {
00652             cpl_vector_delete(vspec1d);
00653             vspec1d = cpl_vector_new_from_image_column(spec2d, ispec);
00654 #ifdef NACO_SPC_WAVECAL_LOG
00655             bug_if(cpl_vector_add_scalar(vspec1d, 1.0));
00656             skip_if(cpl_vector_logarithm(vspec1d, exp(1.0)));
00657 #endif
00658         }
00659 
00660         xc = 0.0;
00661         if (irplib_polynomial_find_1d_from_correlation
00662             (disp, fitdeg, vspec1d, (void *)&model,
00663              irplib_vector_fill_line_spectrum, pixtol, pixstep, 2, maxite,
00664              &xc)) {
00665             irplib_error_recover(prestate, "Could not calibrate column %d of "
00666                                  "%d", ispec, nx);
00667             cpl_polynomial_copy(disp, dispcen);
00668             xc = 0.0;
00669         } else {
00670             double wl2d = cpl_polynomial_eval_1d(disp, 0.5, NULL);
00671 
00672             if (wl2d < wl2dmin) wl2dmin = wl2d;
00673 
00674             wl2d = cpl_polynomial_eval_1d(disp, ny + 0.5, NULL);
00675             if (wl2d > wl2dmax) wl2dmax = wl2d;
00676 
00677             if (ispec % plotstep == 0) {
00678                 bug_if(irplib_plot_spectrum_and_model
00679                        (vspec1d, disp,
00680                         (void*)&model,
00681                         irplib_vector_fill_line_spectrum));
00682             }
00683 #ifdef IRPLIB_SPC_DUMP
00684             /* Need irplib_wavecal.c rev. 1.12 through 1.15 */
00685             if (ispec == istart) {
00686                 irplib_polynomial_tabulate(disp, vspec1d, (void *)&model,
00687                                            irplib_vector_fill_line_spectrum,
00688                                            50, 0.1);
00689             }
00690 #endif
00691         }
00692 
00693         bug_if(cpl_vector_set(vxcall, ispec-1, xc));
00694 
00695         cpl_msg_info(cpl_func, "XC(%d): %g (cost=%u of %u)", ispec, xc,
00696                      (unsigned)(model.cost-prevcost), (unsigned)model.cost);
00697 
00698         bug_if(naco_image_fill_column_from_dispersion(imgdisp, ispec, xc <= 0.0,
00699                                                       disp));
00700 
00701         if (isfirst) {
00702             double cdisp;
00703             const double cwl = cpl_polynomial_eval_1d(disp, 0.5*ny + 0.5,
00704                                                       &cdisp);
00705 
00706             isfirst = CPL_FALSE;
00707             cpl_msg_info(cpl_func, "Center of setting %s has range %g -> %g "
00708                          "-> %g [um], center dispersion %g [nm/pixel] and "
00709                          "dispersion (of degree %d):", tag,
00710                          cpl_polynomial_eval_1d(disp, 0.5, NULL),
00711                          cwl,
00712                          cpl_polynomial_eval_1d(disp, ny + 0.5, NULL),
00713                          1e3*cdisp,
00714                          (int)cpl_polynomial_get_degree(disp));
00715             skip_if(cpl_polynomial_dump(disp, stdout));
00716 
00717             cpl_polynomial_copy(dispcen, disp);
00718 
00719             bug_if(irplib_polynomial_subtract(dispdif, disp, phshift));
00720 
00721             cpl_msg_info(cpl_func, "Changes to model polynomial by search is of"
00722                          " degree %d", (int)cpl_polynomial_get_degree(dispdif));
00723             skip_if(cpl_polynomial_dump(dispdif, stdout));
00724 
00725             bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISP XCORR",
00726                                                   xc));
00727         }
00728     }
00729 
00730     /* Left half, restarting from central column */
00731     cpl_polynomial_copy(disp, dispcen);
00732 
00733     for (ispec = istart-1; ispec > 0; ispec--) {
00734         const cpl_size prevcost = model.cost;
00735 
00736         cpl_vector_delete(vspec1d);
00737         vspec1d = cpl_vector_new_from_image_column(spec2d, ispec);
00738 #ifdef NACO_SPC_WAVECAL_LOG
00739         bug_if(cpl_vector_add_scalar(vspec1d, 1.0));
00740         skip_if(cpl_vector_logarithm(vspec1d, exp(1.0)));
00741 #endif
00742 
00743         xc = 0.0;
00744         if (irplib_polynomial_find_1d_from_correlation
00745             (disp, fitdeg, vspec1d, (void *)&model,
00746              irplib_vector_fill_line_spectrum, pixtol, pixstep, 2, maxite, &xc)) {
00747             if (ispec == 1 && wl2dmin >= wl2dmax) {
00748                 error_if (0, cpl_error_get_code(),
00749                           "None of the columns could be calibrated");
00750             }
00751 
00752             irplib_error_recover(prestate, "Could not calibrate column %d of "
00753                                  "%d", ispec, nx);
00754             cpl_polynomial_copy(disp, dispcen);
00755         } else {
00756             double wl2d = cpl_polynomial_eval_1d(disp, 0.5, NULL);
00757 
00758             if (wl2d < wl2dmin) wl2dmin = wl2d;
00759 
00760             wl2d = cpl_polynomial_eval_1d(disp, ny + 0.5, NULL);
00761             if (wl2d > wl2dmax) wl2dmax = wl2d;
00762 
00763             if (ispec % plotstep == 0) {
00764                 bug_if(irplib_plot_spectrum_and_model
00765                        (vspec1d, disp,
00766                         (void*)&model,
00767                         irplib_vector_fill_line_spectrum));
00768             }
00769         }
00770 
00771         bug_if(cpl_vector_set(vxcall, ispec-1, xc));
00772 
00773         cpl_msg_info(cpl_func, "XC(%d): %g (cost=%u of %u)", ispec, xc,
00774                      (unsigned)(model.cost-prevcost), (unsigned)model.cost);
00775 
00776         bug_if(naco_image_fill_column_from_dispersion(imgdisp, ispec, xc <= 0.0,
00777                                                       disp));
00778     }
00779 
00780     if (nplot > 0) {
00781         cpl_plot_vector("set grid;", "t 'XC over spatial range' w linespoints",
00782                         "", vxcall);
00783     }
00784 
00785     xcmean  = cpl_vector_get_mean(vxcall);
00786     xcstdev = cpl_vector_get_stdev(vxcall);
00787 
00788     bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISP XCORR MEAN",
00789                                           xcmean));
00790     bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISP XCORR STDEV",
00791                                           xcstdev));
00792 
00793     cpl_msg_info(cpl_func,"Cross-correlation mean and stdev for setting %s: %g "
00794                  "%g", tag, xcmean, xcstdev);
00795     cpl_msg_info(cpl_func, "Total fitting cost: %u", (unsigned)model.cost);
00796 
00797     skip_if(naco_spc_wavecal_count_lines(qclist, argonlines, wl2dmin, wl2dmax));
00798 
00799     end_skip;
00800 
00801     if (cpl_error_get_code()) {
00802         cpl_image_delete(imgdisp);
00803     } else {
00804         cpl_imagelist_set(self, imgdisp, 0);
00805     }
00806 
00807     cpl_vector_delete(linepix);
00808     cpl_vector_delete(vxcall);
00809     cpl_polynomial_delete(dispdif);
00810     cpl_polynomial_delete(disp);
00811     cpl_polynomial_delete(dispcen);
00812     cpl_polynomial_delete(phshift);
00813     cpl_vector_delete(vspec1d);
00814 
00815     return cpl_error_get_code();
00816 }
00817 
00818 
00819 /*----------------------------------------------------------------------------*/
00828 /*----------------------------------------------------------------------------*/
00829 static cpl_error_code naco_spc_physdisp_fill(cpl_polynomial * self,
00830                                              const char * mode,
00831                                              const cpl_table * modeltab)
00832 {
00833 
00834     int imode;
00835     const int nrows = cpl_table_get_nrow(modeltab);
00836     const char ** smode = cpl_table_get_data_string_const(modeltab,
00837                                                           NACO_SPC_LAB_MODE);
00838 
00839     bug_if(self     == NULL);
00840     bug_if(mode     == NULL);
00841     bug_if(modeltab == NULL);
00842     bug_if(cpl_polynomial_get_dimension(self) != 1);
00843 
00844     skip_if (smode == NULL);
00845 
00846     for (imode = 0; imode < nrows; imode++) {
00847 
00848         skip_if(smode[imode] == NULL);
00849 
00850         if (!strcmp(mode, smode[imode])) break;
00851     }
00852 
00853     error_if (imode == nrows, CPL_ERROR_UNSUPPORTED_MODE, "Unsupported value "
00854               "'%s' for " NACO_PFITS_STRING_SPECMODE, mode);
00855 
00856     cpl_msg_info(cpl_func, "Finding dispersion relation for spectrum mode "
00857                  "%d/%d: %s ", imode, nrows, mode);
00858 
00859     skip_if(naco_spc_physdisp_transform
00860             (self,
00861              cpl_table_get_double(modeltab, NACO_SPC_LAB_XMIN,  imode, NULL),
00862              cpl_table_get_double(modeltab, NACO_SPC_LAB_XMAX,  imode, NULL),
00863              cpl_table_get_int   (modeltab, NACO_SPC_LAB_ORDER, imode, NULL),
00864              cpl_table_get_double(modeltab, NACO_SPC_LAB_C1,    imode, NULL),
00865              cpl_table_get_double(modeltab, NACO_SPC_LAB_C2,    imode, NULL),
00866              cpl_table_get_double(modeltab, NACO_SPC_LAB_C3,    imode, NULL),
00867              cpl_table_get_double(modeltab, NACO_SPC_LAB_C4,    imode, NULL)));
00868 
00869 #ifdef NACO_SPC_WAVECAL_S54_3_SH
00870     if (!strcmp("S54_3_SH", mode)) {
00871         double p0 = 1.36983;
00872         double p1 = 0.000165591;
00873         double p2 = 2.86676e-07;
00874         cpl_size degree = 0;
00875 
00876         bug_if(cpl_polynomial_set_coeff(self, &degree, p0));
00877         degree++;
00878         bug_if(cpl_polynomial_set_coeff(self, &degree, p1));
00879         degree++;
00880         bug_if(cpl_polynomial_set_coeff(self, &degree, p2));
00881         degree++;
00882         bug_if(cpl_polynomial_set_coeff(self, &degree, 0.0));
00883         degree++;
00884         bug_if(cpl_polynomial_set_coeff(self, &degree, 0.0));
00885 
00886         cpl_msg_warning(cpl_func, "Changing phdisp to simple fit:");
00887         skip_if(cpl_polynomial_dump(self, stdout));
00888     }
00889 #endif
00890 
00891     end_skip;
00892 
00893     return cpl_error_get_code();
00894 }
00895 
00896 
00897 /*----------------------------------------------------------------------------*/
00912 /*----------------------------------------------------------------------------*/
00913 static cpl_error_code naco_spc_physdisp_transform(cpl_polynomial * self,
00914                                                   double xmin, double xmax,
00915                                                   int fit_order,
00916                                                   double c1, double c2,
00917                                                   double c3, double c4)
00918 {
00919 
00920     const double alpha = 2.0/(xmax - xmin);
00921     const double beta  = -(xmax + xmin) / (xmax - xmin);
00922     double   value;
00923     double   lambdamin1, lambdamax1;
00924     double   lambdamin2, lambdamax2;
00925     cpl_size degree;
00926 
00927     bug_if(self == NULL);
00928     bug_if(cpl_polynomial_get_dimension(self) != 1);
00929 
00930     /* The specifics of the model may later become user definable */
00931     skip_if(xmin >= xmax);
00932 
00933     value = 1e-4 * (c1 - 0.5 * c3);
00934     degree = 0;
00935     bug_if(cpl_polynomial_set_coeff(self, &degree, value));
00936 
00937     value = 1e-4 * (c2 - 1.5 * c4);
00938     degree = 1;
00939     bug_if(cpl_polynomial_set_coeff(self, &degree, value));
00940 
00941     if (fit_order > 2) {
00942         value = 1e-4 * 1.5 * c3;
00943         degree = 2;
00944         bug_if(cpl_polynomial_set_coeff(self, &degree, value));
00945 
00946         if (fit_order > 3) {
00947             value = 1e-4 * 2.5 * c4;
00948             degree = 3;
00949             bug_if(cpl_polynomial_set_coeff(self, &degree, value));
00950 
00951             skip_if(fit_order > 4);
00952         }
00953     } else {
00954         skip_if(fit_order < 2);
00955     }
00956 
00957 
00958     lambdamin1 = cpl_polynomial_eval_1d(self, -1.0, NULL);
00959     lambdamax1 = cpl_polynomial_eval_1d(self,  1.0, NULL);
00960 
00961 
00962     /* Now transform the polynomial from the domain [-1;1] to [xmin;xmax],
00963        n = (2 * x - (xmax + xmin) / (xmax - xmin),
00964        n = x * alpha + beta */
00965 
00966     bug_if(cpl_polynomial_shift_1d(self, 0, beta));
00967 
00968     degree = 1;
00969     value = cpl_polynomial_get_coeff(self, &degree) * alpha;
00970     bug_if(cpl_polynomial_set_coeff(self, &degree, value));
00971 
00972     if (fit_order > 2) {
00973         degree = 2;
00974         value = cpl_polynomial_get_coeff(self, &degree) * alpha * alpha;
00975         bug_if(cpl_polynomial_set_coeff(self, &degree, value));
00976 
00977         if (fit_order > 3) {
00978             degree = 3;
00979             value = cpl_polynomial_get_coeff(self, &degree) * alpha * alpha
00980                 * alpha;
00981             bug_if(cpl_polynomial_set_coeff(self, &degree, value));
00982         }
00983     }
00984 
00985     lambdamin2 = cpl_polynomial_eval_1d(self, xmin, NULL);
00986     lambdamax2 = cpl_polynomial_eval_1d(self, xmax, NULL);
00987 
00988     skip_if(cpl_polynomial_get_degree(self) != fit_order - 1);
00989 
00990     skip_if(cpl_polynomial_dump(self, stdout));
00991 
00992     cpl_msg_debug(cpl_func, "Interpolation minimum=%g: %g (%g)", xmin,
00993                  lambdamin1, lambdamin2-lambdamin1);
00994     cpl_msg_debug(cpl_func, "Interpolation maximum=%g: %g (%g)", xmax,
00995                  lambdamax1, lambdamax2-lambdamax1);
00996 
00997     end_skip;
00998 
00999     return cpl_error_get_code();
01000 }
01001 
01002 
01003 /*----------------------------------------------------------------------------*/
01013 /*----------------------------------------------------------------------------*/
01014 static cpl_error_code naco_spc_wavecal_get_slitw(const cpl_propertylist * self,
01015                                                  double * pslitw)
01016 {
01017     const char * sslitw;
01018     int nvals;
01019     unsigned uslitw;
01020     double pixscale;
01021 
01022 
01023     bug_if(self   == NULL);
01024     bug_if(pslitw == NULL);
01025 
01026     sslitw = irplib_pfits_get_string(self, NACO_PFITS_STRING_SLITNAME);
01027     skip_if(sslitw == NULL);
01028 
01029     nvals = sscanf(sslitw, "Slit_%u", &uslitw);
01030 
01031     error_if(nvals != 1, CPL_ERROR_UNSUPPORTED_MODE, "Unsupported value of '"
01032              NACO_PFITS_STRING_SLITNAME ": %s", sslitw);
01033 
01034     pixscale = irplib_pfits_get_double(self, NACO_PFITS_DOUBLE_PIXSCALE);
01035     skip_if(0);
01036     error_if(pixscale <= 0.0, CPL_ERROR_ILLEGAL_INPUT, "Non-positive value of '"
01037              NACO_PFITS_DOUBLE_PIXSCALE ": %g", pixscale);
01038 
01039     *pslitw = (double)uslitw/(1000.0*pixscale); /* Convert from mas to pixel */
01040 
01041     end_skip;
01042 
01043     return cpl_error_get_code();
01044 }
01045 
01046 
01047 /*----------------------------------------------------------------------------*/
01057 /*----------------------------------------------------------------------------*/
01058 static cpl_error_code
01059 naco_image_fill_column_from_dispersion(cpl_image * self,
01060                                        int ispec, cpl_boolean is_bad,
01061                                        const cpl_polynomial * disp)
01062 {
01063 
01064     const int ny = cpl_image_get_size_y(self);
01065     int i;
01066 
01067     bug_if(self == NULL);
01068     bug_if(disp == NULL);
01069     bug_if(cpl_polynomial_get_dimension(disp) != 1);
01070     bug_if(cpl_polynomial_get_degree(disp) < 1);
01071 
01072     for (i = 1; i <= ny; i++) {
01073         const double value = cpl_polynomial_eval_1d(disp, (double)i, NULL);
01074         cpl_image_set(self, ispec, i, value);
01075         if (is_bad) cpl_image_reject(self, ispec, i);
01076     }
01077 
01078     end_skip;
01079 
01080     return cpl_error_get_code();
01081 }
01082 
01083 
01084 /*----------------------------------------------------------------------------*/
01093 /*----------------------------------------------------------------------------*/
01094 static
01095 cpl_error_code naco_spc_wavecal_distortion(cpl_image * self,
01096                                            cpl_propertylist * qclist,
01097                                            const cpl_parameterlist * parlist)
01098 {
01099 
01100     const int       fitdeg = 2;
01101     cpl_image     * copy = NULL;
01102     const int       nx = cpl_image_get_size_x(self);
01103     const int       ny = cpl_image_get_size_y(self);
01104     cpl_apertures * lines = NULL;
01105     cpl_polynomial* distortion = NULL;
01106     cpl_polynomial* yid2d = cpl_polynomial_new(2);
01107     cpl_vector    * profile = cpl_vector_new(CPL_KERNEL_DEF_SAMPLES);
01108     cpl_size        power[] = {0, 1};
01109     const int       nplot = naco_parameterlist_get_int(parlist, RECIPE_STRING,
01110                                                        NACO_PARAM_PLOT);
01111     cpl_polynomial* center = cpl_polynomial_new(1);
01112     cpl_polynomial* dist1d = NULL;
01113     cpl_vector    * dist1dfix = NULL;
01114     const cpl_size  i0 = 0;
01115     const cpl_size  i1 = 1;
01116     const double    xcent = 0.5*(nx + 1);
01117     const double    ycent = 0.5*(ny + 1);
01118 
01119     bug_if(0);
01120     bug_if(self    == NULL);
01121     bug_if(qclist  == NULL);
01122     bug_if(parlist == NULL);
01123 
01124 
01125     /* Distortion correction supports only vertical lines */
01126     bug_if(cpl_image_turn(self, 1));
01127 
01128     distortion = irplib_distortion_estimate(self, 1, 1, nx, ny,
01129                                             CPL_FALSE, 1e8,
01130                                             33,
01131                                             0.33, fitdeg, &lines);
01132 
01133     error_if(distortion == NULL, cpl_error_get_code(), "Curvature estimation "
01134              "failed");
01135 
01136     if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
01137         skip_if(cpl_polynomial_dump(distortion, stdout));
01138         cpl_apertures_dump(lines, stdout);
01139     }
01140 
01141     skip_if(naco_spc_wavecal_qc_lines(qclist, self, lines));
01142 
01143     /* Create the y-identity 2D-polynomial */
01144     bug_if(cpl_polynomial_set_coeff(yid2d, power, 1.0));
01145     
01146     /* Fill the kernel */
01147     bug_if(cpl_vector_fill_kernel_profile(profile, CPL_KERNEL_DEFAULT,
01148                                           CPL_KERNEL_DEF_WIDTH));
01149 
01150     /* Apply the distortion correction */
01151     copy = cpl_image_duplicate(self); /* Needed, so self can keep result */
01152     error_if (cpl_image_warp_polynomial(self, copy, distortion, yid2d, profile,
01153                                         CPL_KERNEL_DEF_WIDTH, profile,
01154                                         CPL_KERNEL_DEF_WIDTH),
01155               cpl_error_get_code(), "Distortion correction failed");
01156 
01157     /* Rotate distortion corrected image back */
01158     bug_if(cpl_image_turn(self, -1));
01159 
01160     if (nplot > 1) {
01161       cpl_errorstate prestate = cpl_errorstate_get();
01162       cpl_plot_image("", "t 'Distortion corrected image'", "", self);
01163       if (!cpl_errorstate_is_equal(prestate)) {
01164         cpl_errorstate_set(prestate);
01165       }
01166 
01167       /* Rotate distortion corrected image back */
01168       (void)cpl_image_turn(copy, -1);
01169 
01170       (void)cpl_image_subtract(copy, self);
01171 
01172       cpl_plot_image("", "t 'Distortion correction'", "", copy);
01173       if (!cpl_errorstate_is_equal(prestate)) {
01174         cpl_errorstate_set(prestate);
01175       }
01176 
01177     }
01178 
01179     skip_if(cpl_polynomial_dump(distortion, stdout));
01180 
01181     /* center is a zero-degree polynomial, p(x) = (nx+1)/2 */
01182     bug_if(cpl_polynomial_set_coeff(center, &i0, xcent));
01183 
01184     dist1d = cpl_polynomial_extract(distortion, 1, center);
01185 
01186     /* Reuse center-polynimial: P(y) = y */
01187     bug_if(cpl_polynomial_set_coeff(center, &i1, 1.0));
01188     bug_if(cpl_polynomial_set_coeff(center, &i0, 0.0));
01189 
01190     /* The deviation from the perfect center polynomial */
01191     bug_if(irplib_polynomial_subtract(center, dist1d, center));
01192 
01193     if (cpl_polynomial_get_degree(center) > 0) {
01194         const cpl_size ndist1d = cpl_polynomial_get_degree(dist1d);
01195         cpl_size       dist1dnreal;
01196 
01197         cpl_msg_info(cpl_func, "On the center column (x=%g) the distortion poly"
01198                      "nomial should be P(y)=y, its deviation from that has deg"
01199                      "ree %d:", xcent, (int)cpl_polynomial_get_degree(center));
01200         skip_if(cpl_polynomial_dump(center, stdout));
01201 
01202         if (ndist1d > 0) {
01203             cpl_errorstate prestate = cpl_errorstate_get();
01204             dist1dfix = cpl_vector_new(ndist1d);
01205             if (irplib_polynomial_solve_1d_all(dist1d, dist1dfix,
01206                                                &dist1dnreal)) {
01207             dist1dnreal = 0;
01208             irplib_error_recover(prestate, "Could not compute fix-points for "
01209                                  "%d-degree polynomial", (int)ndist1d);
01210             }
01211         } else {
01212             dist1dnreal = 0;
01213         }
01214 
01215         if (dist1dnreal > 0) {
01216             cpl_vector * dist1dfixreal = dist1dnreal == ndist1d ? dist1dfix
01217                 : cpl_vector_wrap(dist1dnreal, cpl_vector_get_data(dist1dfix));
01218             cpl_msg_info(cpl_func, "The distortion correction has %d fix-"
01219                          "point(s) on the center column:", (int)dist1dnreal);
01220             cpl_vector_dump(dist1dfixreal, stdout);
01221             if (dist1dfixreal != dist1dfix)
01222                 (void)cpl_vector_unwrap(dist1dfixreal);
01223         } else if (cpl_polynomial_get_coeff(dist1d, &i0) != 0.0) {
01224             /* Should not reach this point */
01225             cpl_msg_info(cpl_func, "The distortion correction has "
01226                          "no fix-points on the center column");
01227         } else {
01228             /* Should not reach this point */
01229             cpl_msg_info(cpl_func, "The distortion correction has "
01230                          "no fix-points on the center column");
01231         }
01232 
01233         cpl_msg_info(cpl_func, "The distortion correction moves the detector "
01234                      "center at (%g,%g) by (%g,%g)", xcent, ycent, 0.0,
01235                      cpl_polynomial_eval_1d(dist1d, ycent, NULL)-ycent);
01236     } else if (cpl_polynomial_get_coeff(center, &i0) != 0.0) {
01237         cpl_msg_info(cpl_func, "The distortion correction has no fix-points "
01238                      "on the center column, their Y-offset are [pixel]: %g",
01239                      cpl_polynomial_get_coeff(center, &i0));
01240     } else {
01241         cpl_msg_info(cpl_func, "The distortion correction has all points "
01242                      "on the center column (at x=%g) as fix-points", xcent);
01243     }
01244 
01245 
01246     power[0] = power[1] = 0;
01247     bug_if(cpl_propertylist_append_double(qclist, "ESO QC DIST1",
01248                                           cpl_polynomial_get_coeff(distortion,
01249                                                                    power)));
01250     power[0] = 1;
01251     bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTY",
01252                                           cpl_polynomial_get_coeff(distortion,
01253                                                                    power)));
01254     power[0] = 2;
01255     bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTYY",
01256                                           cpl_polynomial_get_coeff(distortion,
01257                                                                    power)));
01258 
01259     power[0] = power[1] = 1;
01260     bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTXY",
01261                                           cpl_polynomial_get_coeff(distortion,
01262                                                                    power)));
01263     power[0] = 0;
01264     bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTX",
01265                                           cpl_polynomial_get_coeff(distortion,
01266                                                                    power)));
01267     power[1] = 2;
01268     bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTXX",
01269                                           cpl_polynomial_get_coeff(distortion,
01270                                                                    power)));
01271 
01272     end_skip;
01273 
01274     /* lines and distortion are rotated :-( */
01275 
01276     cpl_image_delete(copy);
01277     cpl_apertures_delete(lines);
01278     cpl_vector_delete(profile);
01279     cpl_vector_delete(dist1dfix);
01280     cpl_polynomial_delete(distortion);
01281     cpl_polynomial_delete(yid2d);
01282     cpl_polynomial_delete(center);
01283     cpl_polynomial_delete(dist1d);
01284 
01285     return cpl_error_get_code();
01286 }
01287 
01288 /*----------------------------------------------------------------------------*/
01296 /*----------------------------------------------------------------------------*/
01297 static cpl_error_code naco_spc_wavecal_qc(cpl_propertylist       * qclist,
01298                                           cpl_propertylist       * paflist,
01299                                           const irplib_framelist * rawframes)
01300 {
01301 
01302     const cpl_propertylist * reflist
01303         = irplib_framelist_get_propertylist_const(rawframes, 0);
01304     const char pafcopy[] = "^(" NACO_PFITS_REGEXP_SPCWAVE_PAF ")$";
01305 
01306 
01307     bug_if (0);
01308 
01309 
01310     /* THE PAF FILE FOR QC PARAMETERS */
01311     skip_if (cpl_propertylist_copy_property_regexp(paflist, reflist, pafcopy,
01312                                                    0));
01313     skip_if (cpl_propertylist_append(paflist, qclist));
01314 
01315     bug_if (cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
01316                                                  IRPLIB_PFITS_REGEXP_RECAL_LAMP
01317                                                   ")$", 0));
01318     end_skip;
01319 
01320     return cpl_error_get_code();
01321 }
01322 
01323 /*----------------------------------------------------------------------------*/
01335 /*----------------------------------------------------------------------------*/
01336 static cpl_error_code naco_spc_wavecal_fill_table(cpl_table * self,
01337                                                   const cpl_polynomial * disp2d)
01338 {
01339 
01340     const int degree = cpl_polynomial_get_degree(disp2d);
01341     const char * lunit = "micron";
01342     int i, j;
01343 
01344     bug_if (self   == NULL);
01345     bug_if (cpl_polynomial_get_dimension(disp2d) != 2);
01346     bug_if (degree < 1);
01347 
01348     bug_if(cpl_table_set_size(self, 1));
01349 
01350     for (i=0; i <= degree; i++) {
01351         for (j = 0; j <= i; j++) {
01352             const cpl_size powers[2] = {i-j, j};
01353             const double value = cpl_polynomial_get_coeff(disp2d, powers);
01354             char * label = cpl_sprintf("DISP2D_%d_%d", i-j, j);
01355             char * unit  = i > 1 ? cpl_sprintf("%s/pixel^%d", lunit, i)
01356                 : cpl_sprintf(i ? "%s/pixel" : "%s", lunit);
01357 
01358             cpl_table_new_column(self, label, CPL_TYPE_DOUBLE);
01359             cpl_table_set_column_unit(self, label, unit);
01360             cpl_table_set_double(self, label, 0, value);
01361 
01362             cpl_free(label);
01363             cpl_free(unit);
01364             bug_if(0);
01365         }
01366     }
01367 
01368     end_skip;
01369 
01370     return cpl_error_get_code();
01371 }
01372 
01373 /*----------------------------------------------------------------------------*/
01386 /*----------------------------------------------------------------------------*/
01387 static cpl_error_code naco_spc_wavecal_save(cpl_frameset            * set_tot,
01388                                             const cpl_parameterlist * parlist,
01389                                             const cpl_propertylist  * qclist,
01390                                             const cpl_propertylist  * paflist,
01391                                             const cpl_imagelist     * lamp_wave,
01392                                             const cpl_polynomial    * disp2d,
01393                                             int                       set_nb,
01394                                             const irplib_framelist  * rawframes)
01395 {
01396     cpl_frameset * proframes = irplib_frameset_cast(rawframes);
01397     cpl_table    * table2d = cpl_table_new(1);
01398     char         * filename  = NULL;
01399 
01400 
01401     /* This will catch rawframes == NULL */
01402     bug_if (0);
01403 
01404     /* The wavelength map */
01405     filename = cpl_sprintf(RECIPE_STRING "_set%02d" CPL_DFS_FITS, set_nb);
01406     skip_if (irplib_dfs_save_image(set_tot, parlist, proframes,
01407                                 cpl_imagelist_get_const(lamp_wave, 0),
01408                                 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
01409                                 NACO_CALIB_ARC_MAP, qclist, NULL,
01410                                 naco_pipe_id, filename));
01411 
01412     bug_if(naco_spc_wavecal_fill_table(table2d, disp2d));
01413 
01414     skip_if(cpl_table_save(table2d, NULL, NULL, filename, CPL_IO_EXTEND));
01415 
01416     /* The difference image with the arc exposure */
01417     cpl_free(filename);
01418     filename = cpl_sprintf(RECIPE_STRING "_set%02d_diff" CPL_DFS_FITS, set_nb);
01419     skip_if (irplib_dfs_save_image(set_tot, parlist, proframes,
01420                                 cpl_imagelist_get_const(lamp_wave, 1),
01421                                 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
01422                                 NACO_CALIB_ARC_DIFF, qclist, NULL,
01423                                 naco_pipe_id, filename));
01424 
01425     skip_if (cpl_image_save(cpl_imagelist_get_const(lamp_wave, 2), filename,
01426                             CPL_BPP_IEEE_FLOAT, NULL, CPL_IO_EXTEND));
01427 
01428 #ifdef NACO_SAVE_PAF
01429     cpl_free(filename);
01430     filename = cpl_sprintf(RECIPE_STRING "_set%02d" CPL_DFS_PAF, set_nb);
01431     skip_if (cpl_dfs_save_paf("NACO", RECIPE_STRING, paflist, filename));
01432 #else
01433     bug_if(paflist == NULL);
01434 #endif
01435 
01436     end_skip;
01437 
01438     cpl_table_delete(table2d);
01439     cpl_free(filename);
01440     cpl_frameset_delete(proframes);
01441 
01442     return cpl_error_get_code();
01443 
01444 }
01445 
01446 
01447 /*----------------------------------------------------------------------------*/
01456 /*----------------------------------------------------------------------------*/
01457 static cpl_error_code naco_spc_wavecal_count_lines(cpl_propertylist   * self,
01458                                                    const cpl_bivector * lines,
01459                                                    double wlmin,
01460                                                    double wlmax)
01461 {
01462 
01463     const cpl_vector * xlines  = cpl_bivector_get_x_const(lines);
01464     const double     * dxlines = cpl_vector_get_data_const(xlines);
01465     int minline, maxline;
01466     int clines;
01467 
01468 
01469     bug_if (self  == NULL);
01470     bug_if (lines == NULL);
01471 
01472     bug_if (wlmin < 0.0);
01473     bug_if (wlmax < wlmin);
01474 
01475     /* Find the 1st line */
01476     minline = cpl_vector_find(xlines, wlmin);
01477 
01478     /* The first line must be at least at wlmin */
01479     if (dxlines[minline] < wlmin) minline++;
01480 
01481     /* Find the last line */
01482     maxline = cpl_vector_find(xlines, wlmax);
01483 
01484     /* The last line must be at most at wlmax */
01485     if (dxlines[maxline] > wlmax) maxline--;
01486 
01487     clines = maxline >= minline ? maxline - minline : 0;
01488 
01489     bug_if(cpl_propertylist_append_int(self, "ESO QC DISP NUMCAT", clines));
01490 
01491     end_skip;
01492 
01493     return cpl_error_get_code();
01494 }
01495 
01496 /*----------------------------------------------------------------------------*/
01504 /*----------------------------------------------------------------------------*/
01505 static cpl_error_code
01506 naco_spc_wavecal_interpolate_rejected(cpl_image * self,
01507                                       const cpl_polynomial * disp2d)
01508 {
01509 
01510     const int nz = cpl_image_count_rejected(self);
01511     const int nx = cpl_image_get_size_x(self);
01512     const int ny = cpl_image_get_size_y(self);
01513     double power[2];
01514     cpl_vector * vpower = cpl_vector_wrap(2, power);
01515     int i, j;
01516     int k = nz;
01517 
01518     bug_if(self   == NULL);
01519     bug_if(disp2d == NULL);
01520 
01521     if (nz > 0) cpl_msg_info(cpl_func, "Interpolating %d poorly calibrated "
01522                              "pixels in the wavelength map", nz);
01523 
01524     for (i = 1; i <= nx && k > 0; i++) {
01525         for (j = 1; j <= ny && k > 0; j++) {
01526             if (cpl_image_is_rejected(self, i, j)) {
01527                 power[0] = (double)i;
01528                 power[1] = (double)j;
01529                 cpl_image_set(self, i, j, cpl_polynomial_eval(disp2d, vpower));
01530                 cpl_image_reject(self, i, j); /* Flagged as interpolated */
01531                 k--;
01532             }
01533         }
01534     }
01535 
01536     end_skip;
01537 
01538     cpl_vector_unwrap(vpower);
01539 
01540     return cpl_error_get_code();
01541 }
01542 
01543 
01544 /*----------------------------------------------------------------------------*/
01553 /*----------------------------------------------------------------------------*/
01554 static cpl_error_code naco_spc_wavecal_qc_lines(cpl_propertylist    * self,
01555                                                 const cpl_image     * spec2d,
01556                                                 const cpl_apertures * lines)
01557 {
01558 
01559     const int    nlines = cpl_apertures_get_size(lines);
01560     const int    ny     = cpl_image_get_size_y(spec2d);
01561     const double ycen   = 0.5 * (ny + 1);
01562     int          i, igood;
01563     char       * label  = NULL;
01564     cpl_vector * vmedian = cpl_vector_new(nlines);
01565     double       median;
01566 
01567     bug_if(self   == NULL);
01568     bug_if(spec2d == NULL);
01569     bug_if(lines  == NULL);
01570 
01571     bug_if(cpl_propertylist_append_int(self, "ESO QC ARCS NUM", nlines));
01572 
01573     igood = 0;
01574     for(i = 1; i <= nlines; i++) {
01575         cpl_errorstate prestate = cpl_errorstate_get();
01576         const double flux = cpl_apertures_get_flux(lines, i);
01577         const double xcen = cpl_apertures_get_centroid_x(lines, i);
01578         double fwhm_x, fwhm_y;
01579 
01580         if (cpl_image_get_fwhm(spec2d, xcen, ycen, &fwhm_x, &fwhm_y)) {
01581             irplib_error_recover(prestate, "Could not compute the FWHM for "
01582                                  "aperture %d of %d (with xcentroid=%g, flux=%g",
01583                                  i, nlines, xcen, flux);
01584             fwhm_x = -1.0;
01585         }
01586 
01587         if (fwhm_x > 0.0) {
01588             cpl_vector_set(vmedian, igood++, fwhm_x);
01589         }
01590 
01591         cpl_free(label);
01592         label = cpl_sprintf("ESO QC ARCS%d XPOS", i);
01593         cpl_propertylist_append_double(self, label, xcen);
01594 
01595         cpl_free(label);
01596         label = cpl_sprintf("ESO QC ARCS%d FWHM", i);
01597 
01598         cpl_propertylist_append_double(self, label, fwhm_x);
01599 
01600         cpl_free(label);
01601         label = cpl_sprintf("ESO QC ARCS%d FLUX", i);
01602 
01603         cpl_propertylist_append_double(self, label, flux);
01604     }
01605     bug_if(0);
01606 
01607     bug_if(cpl_propertylist_append_int(self, "ESO QC ARCS NUMGOOD", igood));
01608 
01609     if (igood > 0) {
01610         bug_if(cpl_vector_set_size(vmedian, igood));
01611         median = cpl_vector_get_median(vmedian);
01612     } else {
01613         median = -1.0;
01614     }
01615 
01616     bug_if(cpl_propertylist_append_double(self, "ESO QC FWHM MED", median));
01617 
01618     end_skip;
01619 
01620     cpl_vector_delete(vmedian);
01621     cpl_free(label);
01622 
01623     return cpl_error_get_code();
01624 }

Generated on Tue Mar 12 15:19:53 2013 for NACO Pipeline Reference Manual by  doxygen 1.4.7