naco_spc_wavecal.c

00001 /* $Id: naco_spc_wavecal.c,v 1.67 2009/02/23 08:11:29 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: 2009/02/23 08:11:29 $
00024  * $Revision: 1.67 $
00025  * $Name: naco-4_1_2 $
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             /* modelframe and argonframe will not be modified */
00300             /* Cannot skip with frames shared among two framelists */
00301             (void)irplib_framelist_set(f_one, (cpl_frame*)modelframe, n_one);
00302             (void)irplib_framelist_set(f_one, (cpl_frame*)argonframe, n_one+1);
00303             (void)naco_spc_wavecal_save(framelist, parlist, qclist, paflist,
00304                                         lamp_wave, disp2d, i+1, f_one);
00305             (void)irplib_framelist_unset(f_one, n_one+1, NULL);
00306             (void)irplib_framelist_unset(f_one, n_one, NULL);
00307             skip_if(!cpl_errorstate_is_equal(prestate));
00308 
00309             do {
00310                 cpl_image_delete(cpl_imagelist_unset(lamp_wave, 0));
00311             } while (cpl_imagelist_get_size(lamp_wave) > 0);
00312 
00313             nb_good++;
00314         }
00315         cpl_propertylist_empty(qclist);
00316         cpl_propertylist_empty(paflist);
00317         irplib_framelist_delete(f_one);
00318         f_one = NULL;
00319     }
00320 
00321     irplib_ensure(nb_good > 0, CPL_ERROR_DATA_NOT_FOUND,
00322                   "None of the %d sets could be reduced", nsets);
00323     
00324     end_skip;
00325 
00326     cpl_free(taglist);
00327     cpl_imagelist_delete(lamp_wave);
00328     cpl_table_delete(modeltab);
00329     cpl_bivector_unwrap_vectors(argonlines);
00330     (void)cpl_vector_unwrap(argonlinex);
00331     (void)cpl_vector_unwrap(argonliney);
00332     cpl_table_delete(argontab);
00333     irplib_framelist_delete(f_one);
00334     irplib_framelist_delete(allframes);
00335     irplib_framelist_delete(rawframes);
00336     cpl_propertylist_delete(qclist);
00337     cpl_propertylist_delete(paflist);
00338     cpl_polynomial_delete(disp2d);
00339 
00340     return cpl_error_get_code();
00341 }
00342 
00343 /*----------------------------------------------------------------------------*/
00356 /*----------------------------------------------------------------------------*/
00357 static cpl_error_code naco_spc_wavecal_reduce(cpl_imagelist * imglist,
00358                                               cpl_polynomial * disp2d,
00359                                               cpl_propertylist * qclist,
00360                                               const char * tag,
00361                                               const irplib_framelist * framelist,
00362                                               const cpl_table * modeltab,
00363                                               const cpl_bivector * argonlines,
00364                                               const cpl_parameterlist * parlist)
00365 {
00366     cpl_image      * self = NULL;
00367     cpl_image      * corrected = NULL;
00368     cpl_imagelist  * difflist = cpl_imagelist_new();
00369     cpl_polynomial * disp1d = NULL;
00370     cpl_polynomial * collapse = cpl_polynomial_new(1);
00371     const int        nplot = naco_parameterlist_get_int(parlist, RECIPE_STRING,
00372                                                        NACO_PARAM_PLOT);
00373     const int        deg0 = 0;
00374     cpl_polynomial * phdisp = cpl_polynomial_new(1);
00375     const cpl_propertylist * plist
00376         = irplib_framelist_get_propertylist_const(framelist, 0);
00377     const char     * specmode
00378         = irplib_pfits_get_string(plist, NACO_PFITS_STRING_SPECMODE);
00379     const double     wlen
00380         = irplib_pfits_get_double(plist, NACO_PFITS_DOUBLE_CWLEN);
00381     cpl_propertylist * lampkeys = cpl_propertylist_new();
00382     cpl_stats      * stats = NULL;
00383     double           adumin, adumax;
00384     double           mse = 0.0;
00385     cpl_vector     * center = cpl_vector_new(2);
00386     int              ny; /* Wavelength resolution */
00387 
00388     bug_if (0);
00389     bug_if (imglist    == NULL);
00390     bug_if (qclist     == NULL);
00391     bug_if (framelist  == NULL);
00392     bug_if (modeltab   == NULL);
00393     bug_if (argonlines == NULL);
00394     bug_if (parlist    == NULL);
00395     bug_if (cpl_imagelist_get_size(imglist));
00396 
00397     /* On-frames have lamp1 on and lamp2 off */
00398     bug_if(cpl_propertylist_append_int(lampkeys, NACO_PFITS_BOOL_LAMP1, 1));
00399     bug_if(cpl_propertylist_append_int(lampkeys, NACO_PFITS_INT_LAMP2,  0));
00400   
00401     skip_if(naco_imagelist_load_diff(difflist, framelist, lampkeys));
00402 
00403     bug_if(0);
00404 
00405     if (cpl_imagelist_get_size(difflist) > 1) {
00406         cpl_msg_warning(cpl_func, "Averaging %d difference images into one image "
00407                         "for setting %s", cpl_imagelist_get_size(difflist),
00408                         tag);
00409         self = cpl_imagelist_collapse_create(difflist);
00410     } else {
00411         self = cpl_imagelist_unset(difflist, 0);
00412     }
00413 
00414     stats = cpl_stats_new_from_image(self, CPL_STATS_MIN | CPL_STATS_MAX);
00415     adumin = cpl_stats_get_min(stats);
00416     adumax = cpl_stats_get_max(stats);
00417 
00418     cpl_msg_info(cpl_func, "Difference image for '%s' has ADUs in range: "
00419                  "%g -> %g", tag, adumin, adumax);
00420     if (adumin < 0.0) {
00421         cpl_msg_info(cpl_func, "Setting negative ADUs to zero");
00422         bug_if(cpl_image_threshold(self, 0.0, FLT_MAX, 0.0, FLT_MAX));
00423     }
00424 
00425     if (nplot > 2) {
00426       cpl_errorstate prestate = cpl_errorstate_get();
00427       irplib_image_plot("", "t 'Difference image'", "", self);
00428       if (!cpl_errorstate_is_equal(prestate)) {
00429         cpl_errorstate_set(prestate);
00430       }
00431     }
00432 
00433     corrected = cpl_image_duplicate(self);
00434     skip_if(naco_spc_wavecal_distortion(corrected, qclist, parlist));
00435 
00436     ny = cpl_image_get_size_y(self);
00437     bug_if (0);
00438 
00439 
00440     skip_if(naco_spc_physdisp_fill(phdisp, specmode, modeltab));
00441 
00442     cpl_msg_info(cpl_func, "Wavelength range using physical model [micron]: "
00443                  "%g -> %g",
00444                  cpl_polynomial_eval_1d(phdisp, 0.5,    NULL),
00445                  cpl_polynomial_eval_1d(phdisp, 0.5 + ny, NULL));
00446 
00447     if (naco_parameterlist_get_bool(parlist, RECIPE_STRING, NACO_PARAM_FORCE)) {
00448         /* FIXME: cpl_wlcalib_xc_best_poly() also fails with this */
00449         const int idegree = 0;
00450         const double dwlen
00451             = cpl_polynomial_eval_1d(phdisp, 0.5*(1+ny), NULL) - wlen;
00452         const double newval
00453             = cpl_polynomial_get_coeff(phdisp, &idegree) - dwlen;
00454 
00455         bug_if(cpl_polynomial_set_coeff(phdisp, &idegree, newval));
00456     }
00457 
00458     cpl_msg_info(cpl_func, "Central Wavelength (model <=> CWLEN) [micron]: "
00459                  "%g <=> %g", cpl_polynomial_eval_1d(phdisp, 0.5*(1+ny), NULL),
00460                  wlen);
00461 
00462 
00463     skip_if(naco_spc_wavecal_1d(imglist, qclist, self, plist, tag, phdisp,
00464                                 argonlines, parlist));
00465 
00466     skip_if(irplib_polynomial_fit_2d_dispersion(disp2d,
00467                                                 cpl_imagelist_get(imglist, 0),
00468                                                 4, &mse));
00469 
00470     cpl_msg_info(cpl_func, "2D-dispersion with MSE=%g for setting %s", mse, tag);
00471     skip_if(cpl_polynomial_dump(disp2d, stdout));
00472 
00473     skip_if(naco_spc_wavecal_interpolate_rejected(cpl_imagelist_get(imglist, 0),
00474                                                   disp2d));
00475 
00476     bug_if(cpl_vector_set(center, 0, 0.5*(1+cpl_image_get_size_x(self))));
00477     bug_if(cpl_vector_set(center, 1, 0.5*(1+cpl_image_get_size_y(self))));
00478 
00479     bug_if(cpl_propertylist_append_double(qclist, "ESO QC WLEN",
00480                                           cpl_polynomial_eval(disp2d, center)));
00481 
00482     /* Central 1D polynomial */
00483     bug_if(cpl_polynomial_set_coeff(collapse, &deg0,
00484                                     0.5 * (1+cpl_image_get_size_x(self))));
00485 
00486     disp1d = cpl_polynomial_extract(disp2d, 0, collapse);
00487     cpl_msg_info(cpl_func, "Central 1D-dispersion (at x=%g)",
00488                  0.5*(1+cpl_image_get_size_x(self)));
00489     skip_if(cpl_polynomial_dump(disp1d, stdout));
00490 
00491     end_skip;
00492 
00493     if (cpl_error_get_code()) {
00494         cpl_image_delete(self);
00495         cpl_image_delete(corrected);
00496     } else {
00497         cpl_imagelist_set(imglist, self, 1);
00498         cpl_imagelist_set(imglist, corrected, 2);
00499     }
00500 
00501     cpl_vector_delete(center);
00502     cpl_propertylist_delete(lampkeys);
00503     cpl_imagelist_delete(difflist);
00504     cpl_stats_delete(stats);
00505     cpl_polynomial_delete(phdisp);
00506     cpl_polynomial_delete(disp1d);
00507     cpl_polynomial_delete(collapse);
00508 
00509     return cpl_error_get_code();
00510 }
00511 
00512 
00513 /*----------------------------------------------------------------------------*/
00526 /*----------------------------------------------------------------------------*/
00527 static cpl_error_code naco_spc_wavecal_1d(cpl_imagelist          * self,
00528                                           cpl_propertylist       * qclist,
00529                                           const cpl_image        * spec2d,
00530                                           const cpl_propertylist * plist,
00531                                           const char             * tag,
00532                                           const cpl_polynomial   * phdisp,
00533                                           const cpl_bivector     * argonlines,
00534                                           const cpl_parameterlist* parlist)
00535 {
00536 
00537     cpl_errorstate prestate = cpl_errorstate_get();
00538     const int        nx = cpl_image_get_size_x(spec2d); /* Spatial resolution */
00539     const int        ny = cpl_image_get_size_y(spec2d); /* Wavelength resolution */
00540     cpl_vector     * vspec1d  = NULL;
00541     cpl_polynomial * disp     = NULL;
00542     cpl_polynomial * dispcen  = NULL;
00543     cpl_polynomial * phshift  = cpl_polynomial_duplicate(phdisp);
00544     cpl_polynomial * dispdif  = cpl_polynomial_new(1);
00545     /* Initialize to zero */
00546     cpl_vector     * linepix
00547         = cpl_vector_wrap(cpl_bivector_get_size(argonlines),
00548                           cpl_calloc(cpl_bivector_get_size(argonlines),
00549                                      sizeof(double)));
00550     double           slitw = 0.0; /* Fix (false) uninit warning */
00551     const double     wfwhm = 4.0;
00552     double           xtrunc;
00553     double           xc, xcmean, xcstdev;
00554     const int        nplot = naco_parameterlist_get_int(parlist, RECIPE_STRING,
00555                                                         NACO_PARAM_PLOT);
00556     const int        plotstep = nplot > 0 ? nx / (1<<nplot) : nx + 1;
00557     const int        degree = cpl_polynomial_get_degree(phdisp);
00558     const int        fitdeg = degree > 4 ? degree : 4; /* Fit at least 4th degree */
00559     cpl_image      * imgdisp = cpl_image_new(nx, ny, cpl_image_get_type(spec2d));
00560     cpl_vector     * vxcall = cpl_vector_new(nx);
00561     /* One practical limitation on hshiftmax is that it may not be so big, as
00562        to cause phdisp to be evaluated outside its range of monotony. */
00563     const int        hshiftmax = ny/4;
00564     irplib_line_spectrum_model model;
00565     const double     pixstep = 0.25;
00566     const double     pixtol = 1e-5; /* 1e-6 leads to more accuracy, is slower */
00567     const int        istart = nx/2; /* Start on central column */
00568     const int        maxite = fitdeg * 100;
00569     int              ispec = istart;
00570     double           wl2dmin = FLT_MAX;
00571     double           wl2dmax = 0.0;
00572     cpl_boolean      isfirst = CPL_TRUE;
00573 
00574     bug_if(0);
00575     bug_if(qclist     == NULL);
00576     bug_if(spec2d     == NULL);
00577     bug_if(plist      == NULL);
00578     bug_if(phdisp     == NULL);
00579     bug_if(argonlines == NULL);
00580 
00581 
00582     skip_if(naco_spc_wavecal_get_slitw(plist, &slitw));
00583 
00584     cpl_msg_info(cpl_func, "Slitwidth [pixel]: %g", slitw);
00585 
00586     xtrunc = 0.5 * slitw + 5.0 * wfwhm * CPL_MATH_SIG_FWHM;
00587 
00588     model.wslit = slitw;
00589     model.wfwhm = wfwhm;
00590     model.xtrunc = xtrunc;
00591     model.lines = argonlines;
00592     model.linepix = linepix;
00593     model.cost = 0;
00594 
00595     vspec1d = cpl_vector_new_from_image_column(spec2d, ispec);
00596 #ifdef NACO_SPC_WAVECAL_LOG
00597     bug_if(cpl_vector_add_scalar(vspec1d, 1.0));
00598     skip_if(cpl_vector_logarithm(vspec1d, exp(1.0)));
00599 #endif
00600 
00601     if (nplot > 0) {
00602         char         * title = cpl_sprintf("t 'Uncalibrated 1D-spectrum "
00603                                            "using %s' w linespoints", tag);
00604         cpl_vector   * vphys = cpl_vector_new(ny);
00605         cpl_bivector * bspec1d = cpl_bivector_wrap_vectors(vphys, vspec1d);
00606 
00607         (void)cpl_vector_fill_polynomial(vphys, phdisp, 1.0, 1.0);
00608 
00609 
00610         irplib_bivector_plot("set grid;set xlabel 'Wavelength [micron]';"
00611                              "set ylabel 'Intensity [ADU]';", title, "",
00612                              bspec1d);
00613         cpl_free(title);
00614         cpl_vector_delete(vphys);
00615         cpl_bivector_unwrap_vectors(bspec1d);
00616         if (!cpl_errorstate_is_equal(prestate)) {
00617             cpl_errorstate_set(prestate);
00618         }
00619     }
00620 
00621     skip_if(irplib_polynomial_shift_1d_from_correlation(phshift, vspec1d,
00622                                                         (void*)&model,
00623                                                      irplib_vector_fill_line_spectrum,
00624                                                         hshiftmax, nplot > 0));
00625 
00626     if (nplot > 0) {
00627         bug_if(irplib_plot_spectrum_and_model(vspec1d, phshift, (void*)&model,
00628                                             irplib_vector_fill_line_spectrum));
00629     }
00630 
00631     bug_if(irplib_polynomial_subtract(dispdif, phshift, phdisp));
00632 
00633     cpl_msg_info(cpl_func, "Changes to model polynomial by XC is of degree %d",
00634                  cpl_polynomial_get_degree(dispdif));
00635     skip_if(cpl_polynomial_dump(dispdif, stdout));
00636 
00637     disp = cpl_polynomial_duplicate(phshift);
00638     /* In the unlikely event that the calibration fails on the central column */
00639     dispcen = cpl_polynomial_duplicate(disp); 
00640 
00641     /* Right half starting from central column */
00642     for (; ispec <= nx; ispec++) {
00643         const unsigned prevcost = model.cost;
00644 
00645         if (!isfirst) {
00646             cpl_vector_delete(vspec1d);
00647             vspec1d = cpl_vector_new_from_image_column(spec2d, ispec);
00648 #ifdef NACO_SPC_WAVECAL_LOG
00649             bug_if(cpl_vector_add_scalar(vspec1d, 1.0));
00650             skip_if(cpl_vector_logarithm(vspec1d, exp(1.0)));
00651 #endif
00652         }
00653 
00654         xc = 0.0;
00655         if (irplib_polynomial_find_1d_from_correlation
00656             (disp, fitdeg, vspec1d, (void *)&model,
00657              irplib_vector_fill_line_spectrum, pixtol, pixstep, 2, maxite,
00658              &xc)) {
00659             irplib_error_recover(prestate, "Could not calibrate column %d of "
00660                                  "%d", ispec, nx);
00661             cpl_polynomial_copy(disp, dispcen);
00662             xc = 0.0;
00663         } else {
00664             double wl2d = cpl_polynomial_eval_1d(disp, 0.5, NULL);
00665 
00666             if (wl2d < wl2dmin) wl2dmin = wl2d;
00667 
00668             wl2d = cpl_polynomial_eval_1d(disp, ny + 0.5, NULL);
00669             if (wl2d > wl2dmax) wl2dmax = wl2d;
00670 
00671             if (ispec % plotstep == 0) {
00672                 bug_if(irplib_plot_spectrum_and_model
00673                        (vspec1d, disp,
00674                         (void*)&model,
00675                         irplib_vector_fill_line_spectrum));
00676             }
00677 #ifdef IRPLIB_SPC_DUMP
00678             /* Need irplib_wavecal.c rev. 1.12 through 1.15 */
00679             if (ispec == istart) {
00680                 irplib_polynomial_tabulate(disp, vspec1d, (void *)&model,
00681                                            irplib_vector_fill_line_spectrum,
00682                                            50, 0.1);
00683             }
00684 #endif
00685         }
00686 
00687         bug_if(cpl_vector_set(vxcall, ispec-1, xc));
00688 
00689         cpl_msg_info(cpl_func, "XC(%d): %g (cost=%u of %u)", ispec, xc,
00690                      model.cost-prevcost, model.cost);
00691 
00692         bug_if(naco_image_fill_column_from_dispersion(imgdisp, ispec, xc <= 0.0,
00693                                                       disp));
00694 
00695         if (isfirst) {
00696             double cdisp;
00697             const double cwl = cpl_polynomial_eval_1d(disp, 0.5*ny + 0.5,
00698                                                       &cdisp);
00699 
00700             isfirst = CPL_FALSE;
00701             cpl_msg_info(cpl_func, "Center of setting %s has range %g -> %g "
00702                          "-> %g [um], center dispersion %g [nm/pixel] and "
00703                          "dispersion (of degree %d):", tag,
00704                          cpl_polynomial_eval_1d(disp, 0.5, NULL),
00705                          cwl,
00706                          cpl_polynomial_eval_1d(disp, ny + 0.5, NULL),
00707                          1e3*cdisp,
00708                          cpl_polynomial_get_degree(disp));
00709             skip_if(cpl_polynomial_dump(disp, stdout));
00710 
00711             cpl_polynomial_copy(dispcen, disp);
00712 
00713             bug_if(irplib_polynomial_subtract(dispdif, disp, phshift));
00714 
00715             cpl_msg_info(cpl_func, "Changes to model polynomial by search is "
00716                          "of degree %d", cpl_polynomial_get_degree(dispdif));
00717             skip_if(cpl_polynomial_dump(dispdif, stdout));
00718 
00719             bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISP XCORR",
00720                                                   xc));
00721         }
00722     }
00723 
00724     /* Left half, restarting from central column */
00725     cpl_polynomial_copy(disp, dispcen);
00726 
00727     for (ispec = istart-1; ispec > 0; ispec--) {
00728         const unsigned prevcost = model.cost;
00729 
00730         cpl_vector_delete(vspec1d);
00731         vspec1d = cpl_vector_new_from_image_column(spec2d, ispec);
00732 #ifdef NACO_SPC_WAVECAL_LOG
00733         bug_if(cpl_vector_add_scalar(vspec1d, 1.0));
00734         skip_if(cpl_vector_logarithm(vspec1d, exp(1.0)));
00735 #endif
00736 
00737         xc = 0.0;
00738         if (irplib_polynomial_find_1d_from_correlation
00739             (disp, fitdeg, vspec1d, (void *)&model,
00740              irplib_vector_fill_line_spectrum, pixtol, pixstep, 2, maxite, &xc)) {
00741             if (ispec == 1 && wl2dmin >= wl2dmax) {
00742                 error_if (0, cpl_error_get_code(),
00743                           "None of the columns could be calibrated");
00744             }
00745 
00746             irplib_error_recover(prestate, "Could not calibrate column %d of "
00747                                  "%d", ispec, nx);
00748             cpl_polynomial_copy(disp, dispcen);
00749         } else {
00750             double wl2d = cpl_polynomial_eval_1d(disp, 0.5, NULL);
00751 
00752             if (wl2d < wl2dmin) wl2dmin = wl2d;
00753 
00754             wl2d = cpl_polynomial_eval_1d(disp, ny + 0.5, NULL);
00755             if (wl2d > wl2dmax) wl2dmax = wl2d;
00756 
00757             if (ispec % plotstep == 0) {
00758                 bug_if(irplib_plot_spectrum_and_model
00759                        (vspec1d, disp,
00760                         (void*)&model,
00761                         irplib_vector_fill_line_spectrum));
00762             }
00763         }
00764 
00765         bug_if(cpl_vector_set(vxcall, ispec-1, xc));
00766 
00767         cpl_msg_info(cpl_func, "XC(%d): %g (cost=%u of %u)", ispec, xc,
00768                      model.cost-prevcost, model.cost);
00769 
00770         bug_if(naco_image_fill_column_from_dispersion(imgdisp, ispec, xc <= 0.0,
00771                                                       disp));
00772     }
00773 
00774     if (nplot > 0) {
00775         irplib_vector_plot("set grid;", "t 'XC over spatial range' w linespoints",
00776                            "", vxcall);
00777     }
00778 
00779     xcmean  = cpl_vector_get_mean(vxcall);
00780     xcstdev = cpl_vector_get_stdev(vxcall);
00781 
00782     bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISP XCORR MEAN",
00783                                           xcmean));
00784     bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISP XCORR STDEV",
00785                                           xcstdev));
00786 
00787     cpl_msg_info(cpl_func,"Cross-correlation mean and stdev for setting %s: %g "
00788                  "%g", tag, xcmean, xcstdev);
00789     cpl_msg_info(cpl_func, "Total fitting cost: %u", model.cost);
00790 
00791     skip_if(naco_spc_wavecal_count_lines(qclist, argonlines, wl2dmin, wl2dmax));
00792 
00793     end_skip;
00794 
00795     if (cpl_error_get_code()) {
00796         cpl_image_delete(imgdisp);
00797     } else {
00798         cpl_imagelist_set(self, imgdisp, 0);
00799     }
00800 
00801     cpl_vector_delete(linepix);
00802     cpl_vector_delete(vxcall);
00803     cpl_polynomial_delete(dispdif);
00804     cpl_polynomial_delete(disp);
00805     cpl_polynomial_delete(dispcen);
00806     cpl_polynomial_delete(phshift);
00807     cpl_vector_delete(vspec1d);
00808 
00809     return cpl_error_get_code();
00810 }
00811 
00812 
00813 /*----------------------------------------------------------------------------*/
00822 /*----------------------------------------------------------------------------*/
00823 static cpl_error_code naco_spc_physdisp_fill(cpl_polynomial * self,
00824                                              const char * mode,
00825                                              const cpl_table * modeltab)
00826 {
00827 
00828     int imode;
00829     const int nrows = cpl_table_get_nrow(modeltab);
00830     const char ** smode = cpl_table_get_data_string_const(modeltab,
00831                                                           NACO_SPC_LAB_MODE);
00832 
00833     bug_if(self     == NULL);
00834     bug_if(mode     == NULL);
00835     bug_if(modeltab == NULL);
00836     bug_if(cpl_polynomial_get_dimension(self) != 1);
00837 
00838     skip_if (smode == NULL);
00839 
00840     for (imode = 0; imode < nrows; imode++) {
00841 
00842         skip_if(smode[imode] == NULL);
00843 
00844         if (!strcmp(mode, smode[imode])) break;
00845     }
00846 
00847     error_if (imode == nrows, CPL_ERROR_UNSUPPORTED_MODE, "Unsupported value "
00848               "'%s' for " NACO_PFITS_STRING_SPECMODE, mode);
00849 
00850     cpl_msg_info(cpl_func, "Finding dispersion relation for spectrum mode "
00851                  "%d/%d: %s ", imode, nrows, mode);
00852 
00853     skip_if(naco_spc_physdisp_transform
00854             (self,
00855              cpl_table_get_double(modeltab, NACO_SPC_LAB_XMIN,  imode, NULL),
00856              cpl_table_get_double(modeltab, NACO_SPC_LAB_XMAX,  imode, NULL),
00857              cpl_table_get_int   (modeltab, NACO_SPC_LAB_ORDER, imode, NULL),
00858              cpl_table_get_double(modeltab, NACO_SPC_LAB_C1,    imode, NULL),
00859              cpl_table_get_double(modeltab, NACO_SPC_LAB_C2,    imode, NULL),
00860              cpl_table_get_double(modeltab, NACO_SPC_LAB_C3,    imode, NULL),
00861              cpl_table_get_double(modeltab, NACO_SPC_LAB_C4,    imode, NULL)));
00862 
00863 #ifdef NACO_SPC_WAVECAL_S54_3_SH
00864     if (!strcmp("S54_3_SH", mode)) {
00865         double p0 = 1.36983;
00866         double p1 = 0.000165591;
00867         double p2 = 2.86676e-07;
00868         int degree = 0;
00869 
00870         bug_if(cpl_polynomial_set_coeff(self, &degree, p0));
00871         degree++;
00872         bug_if(cpl_polynomial_set_coeff(self, &degree, p1));
00873         degree++;
00874         bug_if(cpl_polynomial_set_coeff(self, &degree, p2));
00875         degree++;
00876         bug_if(cpl_polynomial_set_coeff(self, &degree, 0.0));
00877         degree++;
00878         bug_if(cpl_polynomial_set_coeff(self, &degree, 0.0));
00879 
00880         cpl_msg_warning(cpl_func, "Changing phdisp to simple fit:");
00881         skip_if(cpl_polynomial_dump(self, stdout));
00882     }
00883 #endif
00884 
00885     end_skip;
00886 
00887     return cpl_error_get_code();
00888 }
00889 
00890 
00891 /*----------------------------------------------------------------------------*/
00906 /*----------------------------------------------------------------------------*/
00907 static cpl_error_code naco_spc_physdisp_transform(cpl_polynomial * self,
00908                                                   double xmin, double xmax,
00909                                                   int fit_order,
00910                                                   double c1, double c2,
00911                                                   double c3, double c4)
00912 {
00913 
00914     const double alpha = 2.0/(xmax - xmin);
00915     const double beta  = -(xmax + xmin) / (xmax - xmin);
00916     double value;
00917     double lambdamin1, lambdamax1;
00918     double lambdamin2, lambdamax2;
00919     int degree;
00920 
00921     bug_if(self == NULL);
00922     bug_if(cpl_polynomial_get_dimension(self) != 1);
00923 
00924     /* The specifics of the model may later become user definable */
00925     skip_if(xmin >= xmax);
00926 
00927     value = 1e-4 * (c1 - 0.5 * c3);
00928     degree = 0;
00929     bug_if(cpl_polynomial_set_coeff(self, &degree, value));
00930 
00931     value = 1e-4 * (c2 - 1.5 * c4);
00932     degree = 1;
00933     bug_if(cpl_polynomial_set_coeff(self, &degree, value));
00934 
00935     if (fit_order > 2) {
00936         value = 1e-4 * 1.5 * c3;
00937         degree = 2;
00938         bug_if(cpl_polynomial_set_coeff(self, &degree, value));
00939 
00940         if (fit_order > 3) {
00941             value = 1e-4 * 2.5 * c4;
00942             degree = 3;
00943             bug_if(cpl_polynomial_set_coeff(self, &degree, value));
00944 
00945             skip_if(fit_order > 4);
00946         }
00947     } else {
00948         skip_if(fit_order < 2);
00949     }
00950 
00951 
00952     lambdamin1 = cpl_polynomial_eval_1d(self, -1.0, NULL);
00953     lambdamax1 = cpl_polynomial_eval_1d(self,  1.0, NULL);
00954 
00955 
00956     /* Now transform the polynomial from the domain [-1;1] to [xmin;xmax],
00957        n = (2 * x - (xmax + xmin) / (xmax - xmin),
00958        n = x * alpha + beta */
00959 
00960 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE > CPL_VERSION(4, 5, 0)
00961     bug_if(cpl_polynomial_shift_1d(self, 0, beta));
00962 #else
00963     bug_if(cpl_polynomial_shift_1d(self, beta));
00964 #endif
00965 
00966     degree = 1;
00967     value = cpl_polynomial_get_coeff(self, &degree) * alpha;
00968     bug_if(cpl_polynomial_set_coeff(self, &degree, value));
00969 
00970     if (fit_order > 2) {
00971         degree = 2;
00972         value = cpl_polynomial_get_coeff(self, &degree) * alpha * alpha;
00973         bug_if(cpl_polynomial_set_coeff(self, &degree, value));
00974 
00975         if (fit_order > 3) {
00976             degree = 3;
00977             value = cpl_polynomial_get_coeff(self, &degree) * alpha * alpha
00978                 * alpha;
00979             bug_if(cpl_polynomial_set_coeff(self, &degree, value));
00980         }
00981     }
00982 
00983     lambdamin2 = cpl_polynomial_eval_1d(self, xmin, NULL);
00984     lambdamax2 = cpl_polynomial_eval_1d(self, xmax, NULL);
00985 
00986     skip_if(cpl_polynomial_get_degree(self) != fit_order - 1);
00987 
00988     skip_if(cpl_polynomial_dump(self, stdout));
00989 
00990     cpl_msg_debug(cpl_func, "Interpolation minimum=%g: %g (%g)", xmin,
00991                  lambdamin1, lambdamin2-lambdamin1);
00992     cpl_msg_debug(cpl_func, "Interpolation maximum=%g: %g (%g)", xmax,
00993                  lambdamax1, lambdamax2-lambdamax1);
00994 
00995     end_skip;
00996 
00997     return cpl_error_get_code();
00998 }
00999 
01000 
01001 /*----------------------------------------------------------------------------*/
01011 /*----------------------------------------------------------------------------*/
01012 static cpl_error_code naco_spc_wavecal_get_slitw(const cpl_propertylist * self,
01013                                                  double * pslitw)
01014 {
01015     const char * sslitw;
01016     int nvals;
01017     unsigned uslitw;
01018     double pixscale;
01019 
01020 
01021     bug_if(self   == NULL);
01022     bug_if(pslitw == NULL);
01023 
01024     sslitw = irplib_pfits_get_string(self, NACO_PFITS_STRING_SLITNAME);
01025     skip_if(sslitw == NULL);
01026 
01027     nvals = sscanf(sslitw, "Slit_%u", &uslitw);
01028 
01029     error_if(nvals != 1, CPL_ERROR_UNSUPPORTED_MODE, "Unsupported value of '"
01030              NACO_PFITS_STRING_SLITNAME ": %s", sslitw);
01031 
01032     pixscale = irplib_pfits_get_double(self, NACO_PFITS_DOUBLE_PIXSCALE);
01033     skip_if(0);
01034     error_if(pixscale <= 0.0, CPL_ERROR_ILLEGAL_INPUT, "Non-positive value of '"
01035              NACO_PFITS_DOUBLE_PIXSCALE ": %g", pixscale);
01036 
01037     *pslitw = (double)uslitw/(1000.0*pixscale); /* Convert from mas to pixel */
01038 
01039     end_skip;
01040 
01041     return cpl_error_get_code();
01042 }
01043 
01044 
01045 /*----------------------------------------------------------------------------*/
01055 /*----------------------------------------------------------------------------*/
01056 static cpl_error_code
01057 naco_image_fill_column_from_dispersion(cpl_image * self,
01058                                        int ispec, cpl_boolean is_bad,
01059                                        const cpl_polynomial * disp)
01060 {
01061 
01062     const int ny = cpl_image_get_size_y(self);
01063     int i;
01064 
01065     bug_if(self == NULL);
01066     bug_if(disp == NULL);
01067     bug_if(cpl_polynomial_get_dimension(disp) != 1);
01068     bug_if(cpl_polynomial_get_degree(disp) < 1);
01069 
01070     for (i = 1; i <= ny; i++) {
01071         const double value = cpl_polynomial_eval_1d(disp, (double)i, NULL);
01072         cpl_image_set(self, ispec, i, value);
01073         if (is_bad) cpl_image_reject(self, ispec, i);
01074     }
01075 
01076     end_skip;
01077 
01078     return cpl_error_get_code();
01079 }
01080 
01081 
01082 /*----------------------------------------------------------------------------*/
01091 /*----------------------------------------------------------------------------*/
01092 static
01093 cpl_error_code naco_spc_wavecal_distortion(cpl_image * self,
01094                                            cpl_propertylist * qclist,
01095                                            const cpl_parameterlist * parlist)
01096 {
01097 
01098     const int       fitdeg = 2;
01099     cpl_image     * copy = NULL;
01100     const int       nx = cpl_image_get_size_x(self);
01101     const int       ny = cpl_image_get_size_y(self);
01102     cpl_apertures * lines = NULL;
01103     cpl_polynomial* distortion = NULL;
01104     cpl_polynomial* yid2d = cpl_polynomial_new(2);
01105     cpl_vector    * profile = cpl_vector_new(CPL_KERNEL_DEF_SAMPLES);
01106     int             power[] = {0, 1};
01107     const int       nplot = naco_parameterlist_get_int(parlist, RECIPE_STRING,
01108                                                        NACO_PARAM_PLOT);
01109     cpl_polynomial* center = cpl_polynomial_new(1);
01110     cpl_polynomial* dist1d = NULL;
01111     cpl_vector    * dist1dfix = NULL;
01112     const int       i0 = 0;
01113     const int       i1 = 1;
01114     const double    xcent = 0.5*(nx + 1);
01115     const double    ycent = 0.5*(ny + 1);
01116 
01117     bug_if(0);
01118     bug_if(self    == NULL);
01119     bug_if(qclist  == NULL);
01120     bug_if(parlist == NULL);
01121 
01122 
01123     /* Distortion correction supports only vertical lines */
01124     bug_if(cpl_image_turn(self, 1));
01125 
01126     distortion = irplib_distortion_estimate(self, 1, 1, nx, ny,
01127                                             CPL_FALSE, 1e8,
01128                                             33,
01129                                             0.33, fitdeg, &lines);
01130 
01131     error_if(distortion == NULL, cpl_error_get_code(), "Curvature estimation "
01132              "failed");
01133 
01134     if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
01135         skip_if(cpl_polynomial_dump(distortion, stdout));
01136         cpl_apertures_dump(lines, stdout);
01137     }
01138 
01139     skip_if(naco_spc_wavecal_qc_lines(qclist, self, lines));
01140 
01141     /* Create the y-identity 2D-polynomial */
01142     bug_if(cpl_polynomial_set_coeff(yid2d, power, 1.0));
01143     
01144     /* Fill the kernel */
01145     bug_if(cpl_vector_fill_kernel_profile(profile, CPL_KERNEL_DEFAULT,
01146                                           CPL_KERNEL_DEF_WIDTH));
01147 
01148     /* Apply the distortion correction */
01149     copy = cpl_image_duplicate(self); /* Needed, so self can keep result */
01150     error_if (cpl_image_warp_polynomial(self, copy, distortion, yid2d, profile,
01151                                         CPL_KERNEL_DEF_WIDTH, profile,
01152                                         CPL_KERNEL_DEF_WIDTH),
01153               cpl_error_get_code(), "Distortion correction failed");
01154 
01155     /* Rotate distortion corrected image back */
01156     bug_if(cpl_image_turn(self, -1));
01157 
01158     if (nplot > 1) {
01159       cpl_errorstate prestate = cpl_errorstate_get();
01160       irplib_image_plot("", "t 'Distortion corrected image'", "", self);
01161       if (!cpl_errorstate_is_equal(prestate)) {
01162         cpl_errorstate_set(prestate);
01163       }
01164 
01165       /* Rotate distortion corrected image back */
01166       (void)cpl_image_turn(copy, -1);
01167 
01168       (void)cpl_image_subtract(copy, self);
01169 
01170       irplib_image_plot("", "t 'Distortion correction'", "", copy);
01171       if (!cpl_errorstate_is_equal(prestate)) {
01172         cpl_errorstate_set(prestate);
01173       }
01174 
01175     }
01176 
01177     skip_if(cpl_polynomial_dump(distortion, stdout));
01178 
01179     /* center is a zero-degree polynomial, p(x) = (nx+1)/2 */
01180     bug_if(cpl_polynomial_set_coeff(center, &i0, xcent));
01181 
01182     dist1d = cpl_polynomial_extract(distortion, 1, center);
01183 
01184     /* Reuse center-polynimial: P(y) = y */
01185     bug_if(cpl_polynomial_set_coeff(center, &i1, 1.0));
01186     bug_if(cpl_polynomial_set_coeff(center, &i0, 0.0));
01187 
01188     /* The deviation from the perfect center polynomial */
01189     bug_if(irplib_polynomial_subtract(center, dist1d, center));
01190 
01191     if (cpl_polynomial_get_degree(center) > 0) {
01192         const int ndist1d = cpl_polynomial_get_degree(dist1d);
01193         int       dist1dnreal;
01194 
01195         cpl_msg_info(cpl_func, "On the center column (x=%g) the distortion "
01196                      "polynomial should be P(y)=y, its deviation from that has "
01197                      "degree %d:", xcent, cpl_polynomial_get_degree(center));
01198         skip_if(cpl_polynomial_dump(center, stdout));
01199 
01200         if (ndist1d > 0) {
01201             cpl_errorstate prestate = cpl_errorstate_get();
01202             dist1dfix = cpl_vector_new(ndist1d);
01203             if (irplib_polynomial_solve_1d_all(dist1d, dist1dfix,
01204                                                &dist1dnreal)) {
01205             dist1dnreal = 0;
01206             irplib_error_recover(prestate, "Could not compute fix-points for "
01207                                  "%d-degree polynomial", ndist1d);
01208             }
01209         } else {
01210             dist1dnreal = 0;
01211         }
01212 
01213         if (dist1dnreal > 0) {
01214             cpl_vector * dist1dfixreal = dist1dnreal == ndist1d ? dist1dfix
01215                 : cpl_vector_wrap(dist1dnreal, cpl_vector_get_data(dist1dfix));
01216             cpl_msg_info(cpl_func, "The distortion correction has "
01217                          "%d fix-point(s) on the center column:", dist1dnreal);
01218             cpl_vector_dump(dist1dfixreal, stdout);
01219             if (dist1dfixreal != dist1dfix)
01220                 (void)cpl_vector_unwrap(dist1dfixreal);
01221         } else if (cpl_polynomial_get_coeff(dist1d, &i0) != 0.0) {
01222             /* Should not reach this point */
01223             cpl_msg_info(cpl_func, "The distortion correction has "
01224                          "no fix-points on the center column");
01225         } else {
01226             /* Should not reach this point */
01227             cpl_msg_info(cpl_func, "The distortion correction has "
01228                          "no fix-points on the center column");
01229         }
01230 
01231         cpl_msg_info(cpl_func, "The distortion correction moves the detector "
01232                      "center at (%g,%g) by (%g,%g)", xcent, ycent, 0.0,
01233                      cpl_polynomial_eval_1d(dist1d, ycent, NULL)-ycent);
01234     } else if (cpl_polynomial_get_coeff(center, &i0) != 0.0) {
01235         cpl_msg_info(cpl_func, "The distortion correction has no fix-points "
01236                      "on the center column, their Y-offset are [pixel]: %g",
01237                      cpl_polynomial_get_coeff(center, &i0));
01238     } else {
01239         cpl_msg_info(cpl_func, "The distortion correction has all points "
01240                      "on the center column (at x=%g) as fix-points", xcent);
01241     }
01242 
01243 
01244     power[0] = power[1] = 0;
01245     bug_if(cpl_propertylist_append_double(qclist, "ESO QC DIST1",
01246                                           cpl_polynomial_get_coeff(distortion,
01247                                                                    power)));
01248     power[0] = 1;
01249     bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTY",
01250                                           cpl_polynomial_get_coeff(distortion,
01251                                                                    power)));
01252     power[0] = 2;
01253     bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTYY",
01254                                           cpl_polynomial_get_coeff(distortion,
01255                                                                    power)));
01256 
01257     power[0] = power[1] = 1;
01258     bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTXY",
01259                                           cpl_polynomial_get_coeff(distortion,
01260                                                                    power)));
01261     power[0] = 0;
01262     bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTX",
01263                                           cpl_polynomial_get_coeff(distortion,
01264                                                                    power)));
01265     power[1] = 2;
01266     bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISTXX",
01267                                           cpl_polynomial_get_coeff(distortion,
01268                                                                    power)));
01269 
01270     end_skip;
01271 
01272     /* lines and distortion are rotated :-( */
01273 
01274     cpl_image_delete(copy);
01275     cpl_apertures_delete(lines);
01276     cpl_vector_delete(profile);
01277     cpl_vector_delete(dist1dfix);
01278     cpl_polynomial_delete(distortion);
01279     cpl_polynomial_delete(yid2d);
01280     cpl_polynomial_delete(center);
01281     cpl_polynomial_delete(dist1d);
01282 
01283     return cpl_error_get_code();
01284 }
01285 
01286 /*----------------------------------------------------------------------------*/
01294 /*----------------------------------------------------------------------------*/
01295 static cpl_error_code naco_spc_wavecal_qc(cpl_propertylist       * qclist,
01296                                           cpl_propertylist       * paflist,
01297                                           const irplib_framelist * rawframes)
01298 {
01299 
01300     const cpl_propertylist * reflist
01301         = irplib_framelist_get_propertylist_const(rawframes, 0);
01302     const char pafcopy[] = "^(" NACO_PFITS_REGEXP_SPCWAVE_PAF ")$";
01303 
01304 
01305     bug_if (0);
01306 
01307 
01308     /* THE PAF FILE FOR QC PARAMETERS */
01309     skip_if (cpl_propertylist_copy_property_regexp(paflist, reflist, pafcopy,
01310                                                    0));
01311     skip_if (cpl_propertylist_append(paflist, qclist));
01312 
01313     bug_if (cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
01314                                                  IRPLIB_PFITS_REGEXP_RECAL_LAMP
01315                                                   ")$", 0));
01316     end_skip;
01317 
01318     return cpl_error_get_code();
01319 }
01320 
01321 /*----------------------------------------------------------------------------*/
01333 /*----------------------------------------------------------------------------*/
01334 static cpl_error_code naco_spc_wavecal_fill_table(cpl_table * self,
01335                                                   const cpl_polynomial * disp2d)
01336 {
01337 
01338     const int degree = cpl_polynomial_get_degree(disp2d);
01339     const char * lunit = "micron";
01340     int i, j;
01341 
01342     bug_if (self   == NULL);
01343     bug_if (cpl_polynomial_get_dimension(disp2d) != 2);
01344     bug_if (degree < 1);
01345 
01346     bug_if(cpl_table_set_size(self, 1));
01347 
01348     for (i=0; i <= degree; i++) {
01349         for (j = 0; j <= i; j++) {
01350             const int powers[2] = {i-j, j};
01351             const double value = cpl_polynomial_get_coeff(disp2d, powers);
01352             char * label = cpl_sprintf("DISP2D_%d_%d", i-j, j);
01353             char * unit  = i > 1 ? cpl_sprintf("%s/pixel^%d", lunit, i)
01354                 : cpl_sprintf(i ? "%s/pixel" : "%s", lunit);
01355 
01356             cpl_table_new_column(self, label, CPL_TYPE_DOUBLE);
01357             cpl_table_set_column_unit(self, label, unit);
01358             cpl_table_set_double(self, label, 0, value);
01359 
01360             cpl_free(label);
01361             cpl_free(unit);
01362             bug_if(0);
01363         }
01364     }
01365 
01366     end_skip;
01367 
01368     return cpl_error_get_code();
01369 }
01370 
01371 /*----------------------------------------------------------------------------*/
01384 /*----------------------------------------------------------------------------*/
01385 static cpl_error_code naco_spc_wavecal_save(cpl_frameset            * set_tot,
01386                                             const cpl_parameterlist * parlist,
01387                                             const cpl_propertylist  * qclist,
01388                                             const cpl_propertylist  * paflist,
01389                                             const cpl_imagelist     * lamp_wave,
01390                                             const cpl_polynomial    * disp2d,
01391                                             int                       set_nb,
01392                                             const irplib_framelist  * rawframes)
01393 {
01394     cpl_frameset * proframes = irplib_frameset_cast(rawframes);
01395     cpl_table    * table2d = cpl_table_new(1);
01396     char         * filename  = NULL;
01397 
01398 
01399     /* This will catch rawframes == NULL */
01400     bug_if (0);
01401 
01402     /* The wavelength map */
01403     filename = cpl_sprintf(RECIPE_STRING "_set%02d" CPL_DFS_FITS, set_nb);
01404     skip_if (irplib_dfs_save_image(set_tot, parlist, proframes,
01405                                 cpl_imagelist_get_const(lamp_wave, 0),
01406                                 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
01407                                 NACO_CALIB_ARC_MAP, qclist, NULL,
01408                                 naco_pipe_id, filename));
01409 
01410     bug_if(naco_spc_wavecal_fill_table(table2d, disp2d));
01411 
01412     skip_if(cpl_table_save(table2d, NULL, NULL, filename, CPL_IO_EXTEND));
01413 
01414     /* The difference image with the arc exposure */
01415     cpl_free(filename);
01416     filename = cpl_sprintf(RECIPE_STRING "_set%02d_diff" CPL_DFS_FITS, set_nb);
01417     skip_if (irplib_dfs_save_image(set_tot, parlist, proframes,
01418                                 cpl_imagelist_get_const(lamp_wave, 1),
01419                                 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
01420                                 NACO_CALIB_ARC_DIFF, qclist, NULL,
01421                                 naco_pipe_id, filename));
01422 
01423     skip_if (cpl_image_save(cpl_imagelist_get_const(lamp_wave, 2), filename,
01424                             CPL_BPP_IEEE_FLOAT, NULL, CPL_IO_EXTEND));
01425 
01426     cpl_free(filename);
01427     filename = cpl_sprintf(RECIPE_STRING "_set%02d" CPL_DFS_PAF, set_nb);
01428     skip_if (cpl_dfs_save_paf("NACO", RECIPE_STRING, paflist, filename));
01429 
01430     end_skip;
01431 
01432     cpl_table_delete(table2d);
01433     cpl_free(filename);
01434     cpl_frameset_delete(proframes);
01435 
01436     return cpl_error_get_code();
01437 
01438 }
01439 
01440 
01441 /*----------------------------------------------------------------------------*/
01450 /*----------------------------------------------------------------------------*/
01451 static cpl_error_code naco_spc_wavecal_count_lines(cpl_propertylist   * self,
01452                                                    const cpl_bivector * lines,
01453                                                    double wlmin,
01454                                                    double wlmax)
01455 {
01456 
01457     const cpl_vector * xlines  = cpl_bivector_get_x_const(lines);
01458     const double     * dxlines = cpl_vector_get_data_const(xlines);
01459     int minline, maxline;
01460     int clines;
01461 
01462 
01463     bug_if (self  == NULL);
01464     bug_if (lines == NULL);
01465 
01466     bug_if (wlmin < 0.0);
01467     bug_if (wlmax < wlmin);
01468 
01469     /* Find the 1st line */
01470     minline = cpl_vector_find(xlines, wlmin);
01471 
01472     /* The first line must be at least at wlmin */
01473     if (dxlines[minline] < wlmin) minline++;
01474 
01475     /* Find the last line */
01476     maxline = cpl_vector_find(xlines, wlmax);
01477 
01478     /* The last line must be at most at wlmax */
01479     if (dxlines[maxline] > wlmax) maxline--;
01480 
01481     clines = maxline >= minline ? maxline - minline : 0;
01482 
01483     bug_if(cpl_propertylist_append_int(self, "ESO QC DISP NUMCAT", clines));
01484 
01485     end_skip;
01486 
01487     return cpl_error_get_code();
01488 }
01489 
01490 /*----------------------------------------------------------------------------*/
01498 /*----------------------------------------------------------------------------*/
01499 static cpl_error_code
01500 naco_spc_wavecal_interpolate_rejected(cpl_image * self,
01501                                       const cpl_polynomial * disp2d)
01502 {
01503 
01504     const int nz = cpl_image_count_rejected(self);
01505     const int nx = cpl_image_get_size_x(self);
01506     const int ny = cpl_image_get_size_y(self);
01507     double power[2];
01508     cpl_vector * vpower = cpl_vector_wrap(2, power);
01509     int i, j;
01510     int k = nz;
01511 
01512     bug_if(self   == NULL);
01513     bug_if(disp2d == NULL);
01514 
01515     if (nz > 0) cpl_msg_info(cpl_func, "Interpolating %d poorly calibrated "
01516                              "pixels in the wavelength map", nz);
01517 
01518     for (i = 1; i <= nx && k > 0; i++) {
01519         for (j = 1; j <= ny && k > 0; j++) {
01520             if (cpl_image_is_rejected(self, i, j)) {
01521                 power[0] = (double)i;
01522                 power[1] = (double)j;
01523                 cpl_image_set(self, i, j, cpl_polynomial_eval(disp2d, vpower));
01524                 cpl_image_reject(self, i, j); /* Flagged as interpolated */
01525                 k--;
01526             }
01527         }
01528     }
01529 
01530     end_skip;
01531 
01532     cpl_vector_unwrap(vpower);
01533 
01534     return cpl_error_get_code();
01535 }
01536 
01537 
01538 /*----------------------------------------------------------------------------*/
01547 /*----------------------------------------------------------------------------*/
01548 static cpl_error_code naco_spc_wavecal_qc_lines(cpl_propertylist    * self,
01549                                                 const cpl_image     * spec2d,
01550                                                 const cpl_apertures * lines)
01551 {
01552 
01553     const int    nlines = cpl_apertures_get_size(lines);
01554     const int    ny     = cpl_image_get_size_y(spec2d);
01555     const double ycen   = 0.5 * (ny + 1);
01556     int          i, igood;
01557     char       * label  = NULL;
01558     cpl_vector * vmedian = cpl_vector_new(nlines);
01559     double       median;
01560 
01561     bug_if(self   == NULL);
01562     bug_if(spec2d == NULL);
01563     bug_if(lines  == NULL);
01564 
01565     bug_if(cpl_propertylist_append_int(self, "ESO QC ARCS NUM", nlines));
01566 
01567     igood = 0;
01568     for(i = 1; i <= nlines; i++) {
01569         cpl_errorstate prestate = cpl_errorstate_get();
01570         const double flux = cpl_apertures_get_flux(lines, i);
01571         const double xcen = cpl_apertures_get_centroid_x(lines, i);
01572         double fwhm_x, fwhm_y;
01573 
01574         if (cpl_image_get_fwhm(spec2d, xcen, ycen, &fwhm_x, &fwhm_y)) {
01575             irplib_error_recover(prestate, "Could not compute the FWHM for "
01576                                  "aperture %d of %d (with xcentroid=%g, flux=%g",
01577                                  i, nlines, xcen, flux);
01578             fwhm_x = -1.0;
01579         }
01580 
01581         if (fwhm_x > 0.0) {
01582             cpl_vector_set(vmedian, igood++, fwhm_x);
01583         }
01584 
01585         cpl_free(label);
01586         label = cpl_sprintf("ESO QC ARCS%d XPOS", i);
01587         cpl_propertylist_append_double(self, label, xcen);
01588 
01589         cpl_free(label);
01590         label = cpl_sprintf("ESO QC ARCS%d FWHM", i);
01591 
01592         cpl_propertylist_append_double(self, label, fwhm_x);
01593 
01594         cpl_free(label);
01595         label = cpl_sprintf("ESO QC ARCS%d FLUX", i);
01596 
01597         cpl_propertylist_append_double(self, label, flux);
01598     }
01599     bug_if(0);
01600 
01601     bug_if(cpl_propertylist_append_int(self, "ESO QC ARCS NUMGOOD", igood));
01602 
01603     if (igood > 0) {
01604         bug_if(cpl_vector_set_size(vmedian, igood));
01605         median = cpl_vector_get_median(vmedian);
01606     } else {
01607         median = -1.0;
01608     }
01609 
01610     bug_if(cpl_propertylist_append_double(self, "ESO QC FWHM MED", median));
01611 
01612     end_skip;
01613 
01614     cpl_vector_delete(vmedian);
01615     cpl_free(label);
01616 
01617     return cpl_error_get_code();
01618 }

Generated on Fri Jul 3 11:23:59 2009 for NACO Pipeline Reference Manual by  doxygen 1.5.8