uves_wavecal_body.c

00001 /*                                                                              *
00002  *   This file is part of the ESO UVES Pipeline                                 *
00003  *   Copyright (C) 2004,2005 European Southern Observatory                      *
00004  *                                                                              *
00005  *   This library is free software; you can redistribute it and/or modify       *
00006  *   it under the terms of the GNU General Public License as published by       *
00007  *   the Free Software Foundation; either version 2 of the License, or          *
00008  *   (at your option) any later version.                                        *
00009  *                                                                              *
00010  *   This program is distributed in the hope that it will be useful,            *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of             *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
00013  *   GNU General Public License for more details.                               *
00014  *                                                                              *
00015  *   You should have received a copy of the GNU General Public License          *
00016  *   along with this program; if not, write to the Free Software                *
00017  *   Foundation, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA       *
00018  *                                                                              */
00019  
00020 /*
00021  * $Author: jmlarsen $
00022  * $Date: 2007/10/30 17:45:44 $
00023  * $Revision: 1.57 $
00024  * $Name: uves-3_4_5 $
00025  * $Log: uves_wavecal_body.c,v $
00026  * Revision 1.57  2007/10/30 17:45:44  jmlarsen
00027  * Support weighted extraction
00028  *
00029  * Revision 1.56  2007/10/18 08:39:00  amodigli
00030  * add #define N_FIBRES_MAX 9 and remove include of flames_uves to make it work without flames recipes
00031  *
00032  * Revision 1.55  2007/10/05 16:01:45  amodigli
00033  * using proces_chip parameter to process or not a given RED chip
00034  *
00035  * Revision 1.54  2007/10/05 06:08:55  amodigli
00036  * added LINETAB_PIXELSIZE and FIBREMASK to linetable header
00037  *
00038  * Revision 1.53  2007/08/21 13:08:26  jmlarsen
00039  * Removed irplib_access module, largely deprecated by CPL-4
00040  *
00041  * Revision 1.52  2007/07/04 06:41:11  jmlarsen
00042  * Changed message (FLAMES)
00043  *
00044  * Revision 1.51  2007/06/29 10:48:26  jmlarsen
00045  * Made gaussian fitting robust against bad dispersion solution
00046  *
00047  * Revision 1.50  2007/06/28 12:04:04  jmlarsen
00048  * Fixed QC.TEST2.ID name if FLAMES
00049  *
00050  * Revision 1.49  2007/06/22 09:30:53  jmlarsen
00051  * Changed interface of uves_save_image
00052  *
00053  * Revision 1.48  2007/06/11 06:42:06  jmlarsen
00054  * Set tolerance to 0.6. The value 0.07 was inappropriate for some wavelength settings
00055  *
00056  * Revision 1.47  2007/06/06 13:17:41  amodigli
00057  * fixed mem leak
00058  *
00059  * Revision 1.46  2007/06/06 08:17:33  amodigli
00060  * replace tab with 4 spaces
00061  *
00062  * Revision 1.45  2007/06/01 06:28:24  amodigli
00063  * defined DRS_CVEL_MIN/MAX
00064  *
00065  * Revision 1.44  2007/05/30 14:46:11  amodigli
00066  * fixed small leak
00067  *
00068  * Revision 1.43  2007/05/30 13:39:06  amodigli
00069  * fixed seg fault in case of FLAMES data reduction
00070  *
00071  * Revision 1.42  2007/05/25 11:50:32  jmlarsen
00072  * Re-added ORDER_TRACE_TABLE
00073  *
00074  * Revision 1.41  2007/05/25 07:05:37  jmlarsen
00075  * Added documentation
00076  *
00077  * Revision 1.40  2007/05/22 14:34:32  jmlarsen
00078  * Removed unnecessary includes
00079  *
00080  * Revision 1.39  2007/05/22 11:45:47  jmlarsen
00081  * Removed 1d wavecal mode which was not supported
00082  *
00083  * Revision 1.38  2007/05/21 11:53:36  jmlarsen
00084  * Removed commented out code
00085  *
00086  * Revision 1.37  2007/05/16 16:33:22  amodigli
00087  * fixed small leak
00088  *
00089  * Revision 1.36  2007/05/09 14:46:18  jmlarsen
00090  * Read slitlength from header
00091  *
00092  * Revision 1.35  2007/05/09 08:13:31  jmlarsen
00093  * Changed comment
00094  *
00095  * Revision 1.34  2007/05/08 11:30:15  jmlarsen
00096  * Change extraction method to optimal/constant necessary to support flat-fielding
00097  *
00098  * Revision 1.33  2007/05/07 14:26:44  jmlarsen
00099  * Added QC.NLINSOL parameter
00100  *
00101  * Revision 1.32  2007/05/07 10:20:04  jmlarsen
00102  * Make sure resampled error spectrum is always positive
00103  *
00104  * Revision 1.31  2007/05/07 07:13:59  jmlarsen
00105  * Made resolution computation robust against negative dl/dx
00106  *
00107  * Revision 1.30  2007/05/03 15:23:54  jmlarsen
00108  * Decreased verbosity
00109  *
00110  * Revision 1.29  2007/05/02 13:19:29  jmlarsen
00111  * Implemented bias + flat correction
00112  *
00113  * Revision 1.28  2007/04/27 07:22:37  jmlarsen
00114  * Implemented possibility to use automatic polynomial degree
00115  *
00116  * Revision 1.27  2007/04/24 16:45:17  amodigli
00117  * changed interface of calls to uves_load_ordertable to match new interface
00118  *
00119  * Revision 1.26  2007/04/24 14:09:29  jmlarsen
00120  * Removed obsolete log_slitwidth option to uves_qclog_add_common_wave()
00121  *
00122  * Revision 1.25  2007/04/24 12:50:29  jmlarsen
00123  * Replaced cpl_propertylist -> uves_propertylist which is much faster
00124  *
00125  * Revision 1.24  2007/04/03 06:29:39  amodigli
00126  * changed interface to uves_load_ordertable
00127  *
00128  * Revision 1.23  2007/03/28 11:42:58  jmlarsen
00129  * Removed MIDAS flag from uves_define_noise
00130  *
00131  * Revision 1.22  2007/03/05 10:21:50  jmlarsen
00132  * Do not correct TOLERANCE for binning, detect fewer lines
00133  *
00134  * Revision 1.21  2007/02/26 10:17:50  jmlarsen
00135  * Update to new interface of uves_qclog_add_common_wave()
00136  *
00137  * Revision 1.20  2007/02/23 13:33:43  jmlarsen
00138  * Added code to test unweighted fitting
00139  *
00140  * Revision 1.19  2007/02/23 07:37:15  jmlarsen
00141  * Adjust tolerance parameter for binning
00142  *
00143  * Revision 1.18  2007/02/22 15:37:02  jmlarsen
00144  * Changed default tolerance to 0.07
00145  *
00146  * Revision 1.17  2007/02/14 14:09:58  jmlarsen
00147  * Added commented out code
00148  *
00149  * Revision 1.16  2007/02/09 09:01:04  jmlarsen
00150  * Added context as parameter of uves_set_parameter_default
00151  *
00152  * Revision 1.15  2007/01/15 08:49:58  jmlarsen
00153  * Set degree to 4 used in MIDAS/UVES
00154  *
00155  * Revision 1.14  2007/01/04 13:54:01  jmlarsen
00156  * Compute line table Select column
00157  *
00158  * Revision 1.13  2006/12/12 12:09:58  jmlarsen
00159  * Load corvel table
00160  *
00161  * Revision 1.12  2006/12/07 08:28:46  jmlarsen
00162  * Factored some common QC parameters
00163  *
00164  * Revision 1.11  2006/12/01 12:32:06  jmlarsen
00165  * Implemented FLAMES QC
00166  *
00167  * Revision 1.10  2006/11/24 16:23:25  jmlarsen
00168  * Added FIB_LINE_TABLE_x
00169  *
00170  * Revision 1.9  2006/11/23 10:05:23  jmlarsen
00171  * Fixed 20 bytes memory leak
00172  *
00173  * Revision 1.8  2006/11/22 12:43:16  jmlarsen
00174  * Changed message
00175  *
00176  * Revision 1.7  2006/11/22 12:40:06  jmlarsen
00177  * Set traceid = 1, not 0 for UVES
00178  *
00179  * Revision 1.6  2006/11/16 14:11:26  jmlarsen
00180  * Added comment
00181  *
00182  * Revision 1.5  2006/11/16 09:49:25  jmlarsen
00183  * Fixed doxygen bug
00184  *
00185  * Revision 1.4  2006/11/15 15:02:15  jmlarsen
00186  * Implemented const safe workarounds for CPL functions
00187  *
00188  * Revision 1.2  2006/11/15 14:04:08  jmlarsen
00189  * Removed non-const version of parameterlist_get_first/last/next which is 
00190  * already in CPL, added const-safe wrapper, unwrapper and deallocator functions
00191  *
00192  * Revision 1.1  2006/11/13 12:42:55  jmlarsen
00193  * Factored out common UVES/FLAMES wavecal code
00194  *
00195  * Revision 1.46  2006/11/06 15:19:42  jmlarsen
00196  * Removed unused include directives
00197  *
00198  */
00199 
00200 /*-----------------------------------------------------------------------------
00201                                 Includes
00202  -----------------------------------------------------------------------------*/
00203 
00204 #ifdef HAVE_CONFIG_H
00205 #  include <config.h>
00206 #endif
00207 /*----------------------------------------------------------------------------*/
00211 /*----------------------------------------------------------------------------*/
00212 
00213 #include <uves_wavecal_body.h>
00214 
00215 /* Definitions */
00216 #include <uves.h>
00217 
00218 /* Macro steps */
00219 #include <uves_extract.h>
00220 #include <uves_flatfield.h>
00221 #include <uves_wavecal_search.h>
00222 #include <uves_wavecal_firstsolution.h>
00223 #include <uves_wavecal_identify.h>
00224 #include <uves_rebin.h>
00225 #include <uves_merge.h>
00226 
00227 /* Utility functions */
00228 #include <uves_wavecal_utils.h>
00229 #include <uves_utils.h>
00230 #include <uves_utils_wrappers.h>
00231 #include <uves_plot.h>
00232 #include <uves_parameters.h>
00233 #include <uves_dfs.h>
00234 #include <uves_pfits.h>
00235 #include <uves_qclog.h>
00236 #include <uves_recipe.h>
00237 #include <uves_error.h>
00238 
00239 #include <cpl.h>
00240 
00241 #include <stdbool.h>
00242 #include <float.h>
00243 
00244 /*-----------------------------------------------------------------------------
00245                                 Defines
00246  -----------------------------------------------------------------------------*/
00247 /* threshold values for maximum pixel saturation */
00248 #define DRS_PTHRES_MAX 55000
00249 #define DRS_PTHRES_MIN -20
00250 #define DRS_CVEL_MIN -6.
00251 #define DRS_CVEL_MAX +6.
00252 #define N_FIBRES_MAX 9
00253 /*-----------------------------------------------------------------------------
00254                             Functions prototypes
00255  -----------------------------------------------------------------------------*/
00256 static void uves_wavecal_qclog(const cpl_table* table,
00257                                int firstabs,
00258                                int lastabs,
00259                    const cpl_image *arclamp,
00260                    const uves_propertylist* raw_header,
00261                    bool flames,
00262                    int trace_number,
00263                    int fibre_mask,
00264                    double offset,
00265                    enum uves_chip chip,
00266                    cpl_table* qclog);
00267 
00268 static void uves_wavecal_qclog_intmon(cpl_table* table,
00269                       const cpl_table *line_intmon,
00270                       const uves_propertylist* raw_header,
00271                       bool flames,
00272                       int fibre,
00273                       enum uves_chip chip,
00274                       cpl_table* qclog);
00275 
00276 /*-----------------------------------------------------------------------------
00277                             Recipe standard code
00278  -----------------------------------------------------------------------------*/
00279 
00280 const char * const uves_wavecal_desc_short = "Performs the wavelength calibration";
00281 
00282 const char * const uves_wavecal_desc =
00283 "The recipe performs a wavelength calibration for each extraction window.\n"
00284 "Conceptually, each chip contains a number of order lines, each of which\n"
00285 "contains a number of fibre traces, each of which contains a number of\n"
00286 "extraction windows. For UVES data, there is only one trace per order and\n"
00287 "three extraction windows (sky, object, sky). For FLAMES/UVES data there\n"
00288 "are multiple traces per order but only one extraction window per trace.\n"
00289 "The number of traces is defined in the order table while the geometry of\n"
00290 "the extraction windows is specified by recipe parameters (see below).\n"
00291 "\n"
00292 "Expected input for this recipe is an arc lamp frame, ARC_LAMP_xxx or\n"
00293 "ECH_ARC_LAMP_xxx (where xxx=BLUE, RED), order table(s) for each chip,\n"
00294 "ORDER_TABLE_xxxx (where xxxx=BLUE, REDL, REDU), 'guess' line table(s)\n"
00295 "for each chip, LINE_TABLE_xxxx, a wavelength catalogue table, \n"
00296 "LINE_REFER_TABLE, and optionally a wavelength table of bright lines,\n"
00297 "LINE_INTMON_TABLE, used only for computing Quality Control parameters.\n"
00298 "\n"
00299 "The output line table(s), LINE_TABLE_xxxx, contains the columns\n"
00300 "X            : Horizontal position (from Gaussian fit) of detected line\n"
00301 "dX           : Uncertainty (one sigma) of X\n"
00302 "Ynew         : Vertical position of detected line\n"
00303 "XWidth       : Width (in pixels) of detected line from Gaussian fit\n"
00304 "Peak         : Intensity of detected line\n"
00305 "Background   : Fitted background (ADU) of detected line\n"
00306 "Slope        : Linear background slope (ADU/pixel) of detected line\n"
00307 "               from Gaussian fit\n"
00308 "Intensity    : Intensity of detected line scaled to unit exposure\n"
00309 "               time. (This column only present if a LINE_INTMON_TABLE\n"
00310 "               is provided.)\n"
00311 "Order        : Absolute order number of detected line\n"
00312 "Y            : Relative order number of detected line\n"
00313 "               (it's not a very descriptive column name)\n"
00314 "WaveC        : Wavelength of this line (computed using the resulting\n"
00315 "               dispersion relation)\n"
00316 "dLambdaC     : Uncertainty (one sigma) of 'WaveC'.\n"
00317 "Pixel        : The width in w.l.u. of a pixel (computed locally).\n"
00318 "Residual     : Residual (in w.l.u.) of this line\n"
00319 "Residual_pix : Residual (in pixels) of this line\n"
00320 "Lambda_candidate : Nearest line in catalogue\n"
00321 "dLambda_cat_sq   : Squared distance to nearest catalogue line\n"
00322 "dLambda_nn_sq    : Squared distance to nearest neighbour multiplied by ALPHA\n"
00323 "Ident        : The wavelength associated with this emission line,\n"
00324 "               or invalid if this line was not identified\n"
00325 "dIdent       : Uncertainty of catalogue wavelength\n"
00326 "Select       : 1 if the line was identified, 0 otherwise\n"
00327 "NLinSol      : 1 if the line was identified and accepted for the\n"
00328 "               polynomial fit, 0 otherwise\n"
00329 "Intensity    : Intensity of detected line scaled to unit exposure\n"
00330 "               time. (This column is present only if a LINE_INTMON_TABLE\n"
00331 "               is provided.)\n"
00332 "\n"
00333 "The 2nd table extension contains the dispersion relation (a 2d polynomial).\n"
00334 "The 3rd table extension contains the map from (pixel, pixel)-space to\n"
00335 " physical order numbers (used internally by the calibration recipe; \n"
00336 "another 2d polynomial).\n"
00337 "\n"
00338 "If there is more than one extraction window, the results of each calibration\n"
00339 "is stored in subsequent table extensions of the same FITS file. For \n"
00340 "example, extensions 4, 5 and 6 would contain the resulting line table \n"
00341 "(and its two associated polynomials) for the second extraction window. \n"
00342 "The results for the calibration of the n'th extraction window is stored \n"
00343 "in extensions (3*n - 2) to 3*n.\n";
00346 /*-----------------------------------------------------------------------------
00347                             Functions code
00348  -----------------------------------------------------------------------------*/
00349 
00350 /*----------------------------------------------------------------------------*/
00358 /*----------------------------------------------------------------------------*/
00359 int
00360 uves_wavecal_define_parameters_body(cpl_parameterlist *parameters, 
00361                     const char *recipe_id, double slit)
00362 {
00363     const char *subcontext;
00364 
00365     /*****************
00366      *    General    *
00367      *****************/
00368     
00369     if (uves_define_global_parameters(parameters) != CPL_ERROR_NONE)
00370     {
00371         return -1;
00372     }
00373     
00374     /*****************
00375      *  Extraction   *
00376      *****************/
00377 
00378     subcontext = NULL;
00379 
00380     /* nwindows */
00381     uves_par_new_range("nwindows",
00382                CPL_TYPE_INT,
00383                "Number of extraction windows per trace. "
00384                "The windows will be aligned (i.e. no overlap "
00385                "and no spacing between adjacent windows). "
00386                "Unless an offset is specified, the middle "
00387                "window(s) is centered on the trace",
00388                strcmp(recipe_id, "flames_cal_wavecal") == 0 ?
00389             1 : 3,      /* FLAMES: 1; UVES: 3 */
00390             1, INT_MAX);
00391 
00392     /* length */
00393     uves_par_new_range("length",
00394                CPL_TYPE_DOUBLE,
00395                "Length (in pixels) of each extraction window. "
00396                "This parameter is also equal to the seperation of "
00397                "adjacent window centers, causing the extraction "
00398                "windows to always be aligned. The parameter is "
00399                "automatically adjusted according to the binning "
00400                "of the input raw frame. If negative, the extraction "
00401                        "window length is determined automatically "
00402                        "to cover the full slit",
00403                slit, -2.0, DBL_MAX);
00404 
00405     /* offset */
00406     uves_par_new_range("offset",
00407                CPL_TYPE_DOUBLE,
00408                "A global offset (in pixels) of all extraction windows",
00409                0.0, 0.0, DBL_MAX);
00410     
00411     /* method */
00412     if (uves_propagate_parameters_step(UVES_EXTRACT_ID, parameters, 
00413                        recipe_id, NULL) != 0)
00414     {
00415         return -1;
00416     }
00417     
00418     /* Override default optimal extraction profile. Assume constant profile */
00419 #if 0
00420     /* this should perhaps be enabled but doesn't work properly in the moment.
00421 
00422         ChangeLog:
00423     uves_cal_wavecal: The arc lamp spectrum is now extracted using
00424     average extraction and weighting each pixel with its inverse
00425     variance. This is equivalent to doing an optimal extraction under
00426     the assumption of a constant spatial profile, and is implemented
00427     as such. This was a necessary change in order to be robust against
00428     interorder noisy pixels caused by dividing by the flat-field.
00429 
00430        */
00431     {
00432     const char *profile = "constant";
00433         double kappa = -1;
00434     
00435     if (uves_set_parameter_default(parameters, 
00436                        recipe_id, UVES_EXTRACT_ID ".profile",
00437                        CPL_TYPE_STRING, &profile)
00438         != CPL_ERROR_NONE)
00439         {
00440         return -1;
00441         }
00442 
00443         /* Disable cosmic ray rejection, it does not work well for
00444            this particular profile and very high S/N */
00445     if (uves_set_parameter_default(parameters,
00446                        recipe_id, UVES_EXTRACT_ID ".kappa",
00447                        CPL_TYPE_DOUBLE, &kappa)
00448         != CPL_ERROR_NONE)
00449         {
00450         return -1;
00451         }
00452     }
00453 #else
00454     {
00455     const char *method = "average";
00456     
00457     if (uves_set_parameter_default(parameters, 
00458                        recipe_id, UVES_EXTRACT_ID ".method",
00459                        CPL_TYPE_STRING, &method)
00460         != CPL_ERROR_NONE)
00461         {
00462         return -1;
00463         }
00464         
00465     }
00466 #endif
00467     
00468     /*****************
00469      *    Search     *
00470      *****************/
00471 
00472     subcontext = "search";
00473 
00474     /* range */
00475     uves_par_new_range("range",
00476                CPL_TYPE_INT,
00477                "Width (in pixels) of search window is 2*range + 1. "
00478                "This parameter is automatically adjusted "
00479                "according to binning.",
00480                8, 1, INT_MAX);
00481 
00482     /* minlines */
00483     uves_par_new_range("minlines",
00484                CPL_TYPE_INT,
00485                "Minimum number of lines to detect. If zero, "
00486                "the default value (2000 for BLUE/REDL chips; "
00487                "1000 for REDU chip) is used.",
00488                0, 0, INT_MAX);
00489 
00490     /* maxlines */
00491     uves_par_new_range("maxlines",
00492                CPL_TYPE_INT,
00493                "Maximum number of lines to detect. If zero, "
00494                "the default value (2400 for BLUE/REDL chip; "
00495                "1400 for REDU chip) is used.",
00496                0, 0, INT_MAX);
00497     
00498     /* centeringmethod */
00499     uves_par_new_enum("centeringmethod",
00500               CPL_TYPE_STRING,
00501               "Line centering method",
00502               "gaussian",             /* Default */
00503               2,                      /* Number of options */
00504               "gaussian", "gravity"); /* List of options */
00505     
00506 
00507     /*******************
00508      *  First solution *
00509      *******************/
00510 
00511     subcontext = "first";
00512 
00513     /* shiftmax */
00514     uves_par_new_range("shiftmax",
00515                CPL_TYPE_DOUBLE,
00516                "The maximum shift (in pixels) compared to "
00517                "guess solution. This parameter is automatically "
00518                "corrected for binning",
00519                10.0, 0.0, DBL_MAX);
00520 
00521     /* shiftstep */
00522     uves_par_new_range("shiftstep",
00523                CPL_TYPE_DOUBLE,
00524                "The step size (in pixels) used when searching "
00525                "for the optimum shift. This parameter is "
00526                "automatically corrected for binning",
00527                0.1, 0.0, DBL_MAX);
00528 
00529     /* shifttoler */
00530     uves_par_new_range("shifttoler",
00531                CPL_TYPE_DOUBLE,
00532                "Tolerance (in pixels) when matching shifted lines. "
00533                "This parameter is not adjusted according to binning",
00534                0.05, 0.0, DBL_MAX);
00535 
00536 
00537     /*****************
00538      *  Identify     *
00539      *****************/
00540 
00541     subcontext = "identify";
00542     
00543     /* alpha */
00544     uves_par_new_range("alpha",
00545                CPL_TYPE_DOUBLE,
00546                "The parameter that controls the distance to the "
00547                "nearest neighbours",
00548                0.1, 0.0, 1.0);
00549 
00550     /* maxerror */
00551     uves_par_new_range("maxerror",
00552                CPL_TYPE_DOUBLE,
00553                "This parameter controls the graceful exit of "
00554                "the identification loop. If the RMS of the "
00555                "global fit exceeds this value (in pixels) the "
00556                "iteration stops",
00557                20.0, 0.0, DBL_MAX);
00558     
00559     /* degree */
00560     uves_par_new_range("degree",
00561                CPL_TYPE_INT,
00562                "Degrees of the global 2d dispersion polynomial. If "
00563                        "a negative number is specified, the polynomial "
00564                        "degrees are automatically selected by starting from "
00565                        "(1, 1) and inreasing the degrees as long as the RMS "
00566                        "residual decreases significantly",
00567                5, -2, INT_MAX);
00568 
00569 
00570     /*****************
00571      * Calibration   *
00572      *****************/
00573 
00574     subcontext = "calibrate";
00575 
00576     /* tolerance */
00577     uves_par_new_value("tolerance",
00578                        CPL_TYPE_DOUBLE,
00579                        "Tolerance of fit. If positive, the tolerance "
00580                        "is in pixel units. If negative, abs(tolerance) "
00581                        "is in wavelength units. Lines with residuals "
00582                        "worse than the tolerance are excluded from the "
00583                        "final fit. Unlike in previous versions, this "
00584                        "parameter is not corrected for CCD binning. "
00585                        "This rejection based on the absolute residual in "
00586                        "pixel can be effectively disabled by setting the "
00587                        "tolerance to a very large number (e.g. 9999). In "
00588                        "that case outliers will be rejected using only "
00589                        "kappa sigma clipping.",
00590                        0.6); 
00591 /*               0.07); */
00592 /*                       9999.0);*/
00593 
00594     
00595     /* kappa */
00596     uves_par_new_value("kappa",
00597                CPL_TYPE_DOUBLE,
00598                "Lines with residuals more then kappa stdev "
00599                        "are rejected from the final fit",
00600                4.0);
00601 
00602     /***************
00603      * Rebinning   *
00604      ***************/
00605     if (uves_propagate_parameters_step(UVES_REBIN_ID, parameters, 
00606                        recipe_id, NULL) != 0)
00607     {
00608         return -1;
00609     }
00610     
00611     return (cpl_error_get_code() != CPL_ERROR_NONE);
00612 }
00613 
00614 /*----------------------------------------------------------------------------*/
00684 /*----------------------------------------------------------------------------*/
00685 static cpl_table *
00686 uves_wavecal_process_window(const cpl_image *arclamp, 
00687                             const cpl_image *arclamp_noise,
00688                             const uves_propertylist *rotated_header,
00689                             const cpl_table *ordertable, 
00690                             const polynomial *order_locations,
00691                             bool flat_fielded,
00692                             cpl_image *weights,
00693                             /* const cpl_table *drs_table,  Not used */
00694                             const cpl_table *guess,
00695                             const cpl_table *line_refer,
00696                             bool flames,
00697                             int tab_in_out_oshift,
00698                             double tab_in_out_yshift,
00699                             enum uves_chip chip, int bin_disp,
00700                             int trace, int window,
00701                             /* General */
00702                             bool DEBUG,
00703                             /* Extraction */
00704                             double offset,
00705                             double slitlength,
00706                             const cpl_parameterlist *parameters,
00707                             const char *recipe_id,
00708                             /* Search */
00709                             int RANGE,
00710                             int MINLINES,
00711                             int MAXLINES,
00712                             centering_method CENTERING_METHOD,
00713                             /* First solution */
00714                             double SHIFT_MAX,
00715                             double SHIFT_STEP,
00716                             double SHIFT_TOLERANCE,
00717                             /* Identify */
00718                             double ALPHA,
00719                             double MAXERROR,
00720                             int DEGREE,
00721                             /* Calibrate */
00722                             double TOLERANCE,
00723                             double kappa,
00724                             /* Result */
00725                             polynomial **dispersion_relation,
00726                             polynomial **absolute_order,
00727                             int *first_absolute_order,
00728                             int *last_absolute_order)
00729 {
00730     cpl_table        *linetable          = NULL;  /* Result */
00731     cpl_table        *temp               = NULL;
00732     cpl_image        *spectrum           = NULL;
00733     cpl_image        *spectrum_noise     = NULL;
00734     cpl_image        *debug_image        = NULL;
00735     polynomial       *initial_dispersion = NULL;
00736     int              *relative_order     = NULL;  /* Map from physical 
00737                              order to relative order */
00738     uves_propertylist *spectrum_header    = NULL;
00739 
00740     cpl_image        *rebinned           = NULL;  /* Used for calculating 
00741                              the instrument resolution */
00742     cpl_image        *rebinned_noise     = NULL;  /* Used for calculating 
00743                              the instrument resolution */
00744     uves_propertylist *rebinned_header    = NULL;
00745     cpl_image        *merged             = NULL;
00746     cpl_image        *merged_noise       = NULL;
00747     uves_propertylist *merged_header      = NULL;
00748     cpl_table        *info_tbl           = NULL;
00749 
00750     /* Needed for optimal extraction */
00751     cpl_image *weights_opt = NULL;
00752     cpl_table *cr_table = NULL;
00753     cpl_image *cr_image = NULL;
00754     cpl_table *order_trace = NULL;
00755 
00756     merge_method m_method = flat_fielded ? MERGE_OPTIMAL : MERGE_SUM;
00757 
00758     /* Extract the spectrum */
00759     uves_free_table(&info_tbl);
00760 
00761     check( spectrum = uves_extract((cpl_image *)arclamp,/* Const-casts are okay,
00762                                                            the image (bpm) + error bars
00763                                                            is changed
00764                                                            only in optimal extraction */
00765                                    (cpl_image *)arclamp_noise,
00766                                    NULL,            /* Header (optimal only)    */
00767                                    ordertable, 
00768                                    order_locations,
00769                                    slitlength,      /* Slit length (pixels)     */
00770                                    offset,          /* Slit center offset       */
00771                                    parameters,      /* Extraction method        */
00772                                    recipe_id,      
00773                                    true,            /* Extraction partial bins? */
00774                                    DEBUG,
00775                                    chip,
00776                                    &spectrum_header,
00777                                    &spectrum_noise,
00778                                    NULL, 
00779                                    NULL,            /* Optimal:  sky+noise      */
00780                                    &cr_table, 
00781                                    &cr_image, 
00782                                    NULL, 
00783                                    (weights != NULL) ? &weights : &weights_opt,
00784                                    &info_tbl,
00785                                    &order_trace),
00786            "Error extracting spectrum");
00787     uves_free_table(&info_tbl);
00788 
00789     /* Set bad pixels to 0, so that the search algorithm doesn't
00790        fail because of bad pixels (but simply does not detect anything)
00791     */
00792     cpl_image_fill_rejected(spectrum, 0);
00793     cpl_image_accept_all(spectrum);
00794     cpl_image_fill_rejected(spectrum_noise, 1);
00795     cpl_image_accept_all(spectrum_noise);
00796 
00797     /* Save spectrum + noise */
00798     if (DEBUG)
00799     {
00800         check( uves_save_image_local("Extracted spectrum", "spectrum", 
00801                      spectrum, chip, trace, window, spectrum_header, true),
00802            "Error saving spectrum");
00803 
00804         check( uves_save_image_local("Extracted spectrum noise", "spectrum_noise",
00805                      spectrum_noise, chip, trace, window, spectrum_header, true),
00806            "Error saving spectrum");
00807     }
00808 
00809     /* Locate lines */
00810     debug_image = cpl_image_duplicate(arclamp);
00811     check( linetable = uves_wavecal_search(spectrum, 
00812                                            spectrum_noise,
00813                                            spectrum_header,
00814                                            flat_fielded,
00815                        order_locations, 
00816                                            debug_image,
00817                        RANGE, 
00818                                            MINLINES, 
00819                                            MAXLINES, 
00820                                            CENTERING_METHOD,
00821                                            bin_disp),
00822        "Line search failed");
00823 
00824     if (flames)
00825     {
00826 //The following (flames_reduce.VCORREL) calculates a cross correlation and does some QC
00827 /*
00828 
00829 > !To support simcal Mode
00830 > if i1 .eq. 1 then
00831 >    w/o "DRS_CVEL_SWITCH={DRS_CVEL_SWITCH}"
00832 >    if "{DRS_CVEL_SWITCH}" .eq. "Y" then
00833 >       w/o "To support simcal Mode"
00834 >       define/local ord_min/i/1/1 0
00835 >       define/local ord_max/i/1/1 0
00836 >       define/local rsample/d/1/1 0
00837 >       statistic/table {ORDTAB} :ORDER >Null
00838 >       ord_min = outputr(1)
00839 >       ord_max = outputr(2)
00840 >       rsample = {{LINTAB},PIXEL(1)}
00841 >       rsample = 2./3. * rsample
00842 >       rebin/echelle  {ofrm} w{ofrm} {rsample} NONL {LINTAB} {SESSOUTV}
00843 >       mercut/echelle w{ofrm} mw{ofrm} {ord_min},{ord_max} NOAPPEND
00844 >       !corvel stuff
00845 >       define/local OLD_CVEL_MAX/d/1/1 {DRS_CVEL_MAX}
00846 >       define/local OLD_CVEL_MIN/d/1/1 {DRS_CVEL_MIN}
00847 >       @p flames_reduce,VCORREL x1_rbf_ cvel1 0 {ord_max} {parCorVelTab} _0 _{chip({PATHID})} 0
00848 >       DRS_CVEL_MAX = DRS_CVEL_MAX + {q1}
00849 >       DRS_CVEL_MIN = DRS_CVEL_MIN + {q1}
00850 >
00851 >       @p flames_reduce,VCORREL x1_rbf_ cvel2 0 {ord_max} {parCorVelTab} _0 _{chip({PATHID})} 0
00852 >       cvel_0 = {q1}
00853 >       DRS_CVEL_MAX = OLD_CVEL_MAX
00854 >       DRS_CVEL_MIN = OLD_CVEL_MIN
00855 >    endif
00856 >    write/keyword DRS_CVEL_SWITCH Y
00857 > endif
00858 
00859 
00860 
00861 
00862         */
00863 
00864     }
00865 
00866     /* Read first solution from guess line table */
00867     {
00868         int degree = 5; /* for the initial solution only. For the
00869                            final solution the degree given as recipe
00870                            parameter is used */
00871         uves_polynomial_delete(&initial_dispersion);
00872         cpl_free(relative_order);
00873         check( initial_dispersion = uves_wavecal_firstsolution(linetable,
00874                                                                guess, 
00875                                                                absolute_order,
00876                                                                ordertable,
00877                                                                order_locations,
00878                                                                flames,
00879                                                                offset,
00880                                                                &relative_order,
00881                                                                degree,
00882                                                                SHIFT_MAX, 
00883                                                                SHIFT_STEP, 
00884                                                                SHIFT_TOLERANCE, 
00885                                                                MAXERROR,
00886                                                                first_absolute_order,
00887                                                                last_absolute_order),
00888                "Could not get first solution");
00889     }
00890 
00891 
00892     if (flames)
00893     {
00894         /* !AM: To correct eventual residual shifts between Guess and Final order
00895            ! (and line) table
00896            compute/table {LINTAB} :YNEW =
00897            :YNEW - {{ORDTAB},TAB_IN_OUT_YSHIFT} - {{OLDORDTAB},FIBREPOS({i1})}
00898            compute/table {LINTAB} :Y = :Y +{{ORDTAB},TAB_IN_OUT_OSHIFT}
00899         */
00900 
00901         cpl_table_add_scalar(linetable, "Y", tab_in_out_oshift);
00902         cpl_table_add_scalar(linetable, "Ynew", - tab_in_out_yshift - offset);
00903     }
00904 
00905     /* Calibrate */
00906     check( *dispersion_relation = uves_wavecal_identify(linetable, /* Guess solution */
00907                             line_refer,
00908                             initial_dispersion, 
00909                                                         DEGREE,
00910                             TOLERANCE, ALPHA, MAXERROR,
00911                                                         kappa),
00912        "Could not calibrate orders");
00913 
00914     if (flames)
00915     {
00916         /* AM: To have correct split of fibres in line table:
00917            > compute/table {LINTAB} :YNEW = :YNEW + {{ORDTAB},TAB_IN_OUT_YSHIFT}
00918                      + {{OLDORDTAB},FIBREPOS({i1})}
00919         */
00920 
00921         cpl_table_add_scalar(linetable, "Ynew", + tab_in_out_yshift + offset);
00922     }
00923 
00924     /* UVES: make plots (resolution + etc.) for the central window,
00925      * FLAMES: all fibres
00926      */
00927     if (flames || (trace == 0 && window == 2))
00928     {
00929         /* Create x-FWHM column:   FWHM = 2.3548 sigma */
00930         check(( cpl_table_duplicate_column(linetable, "deltaX", linetable, "Xwidth"),
00931             cpl_table_multiply_scalar (linetable, "deltaX", TWOSQRT2LN2)),
00932           "Error creating FWHM column");
00933         
00934 
00935         check_nomsg( temp = uves_extract_table_rows(
00936                              linetable, "NLinSol", CPL_NOT_EQUAL_TO, 0) );
00937 
00938         check( uves_plot_table(temp, "Order", LINETAB_RESIDUAL, "Residual of fit"), 
00939            "Plotting failed");
00940         
00941         check( uves_plot_table(temp, "X", "deltaX", "line FWHM (mean = %.2f pixels)",
00942                    cpl_table_get_column_mean(linetable, "deltaX")),
00943            "Plotting failed");
00944         /*
00945           check( uves_plot_table(linetable, "Y", "deltaX", 
00946           "line FWHM (mean FWHM = %.2f pixels)",
00947           cpl_table_get_column_mean(linetable, "deltaX")), "Plotting failed");
00948         */
00949         
00950         
00951         /* Compute resolution as as lambda / deltalambda   where deltalambda
00952                is the peak FWHM in wavelength space (after resampling using 
00953            WAVESTEP = average pixelsize) 
00954         */
00955         
00956         {
00957         /* Rebin using steps of median pixelsize */
00958         double wavestep;
00959         double lambda_start = 0;
00960         int n_traces = 1;      /* We didn't do a 2d extraction; 
00961                       there's only 1 trace
00962                       per order */
00963         int i, nbins;
00964                 bool threshold_to_positive = true;
00965 
00966         cpl_table_new_column(linetable, "deltaLambda", CPL_TYPE_DOUBLE);
00967         
00968         check( rebinned_noise = uves_rebin(spectrum_noise,
00969                                            parameters, 
00970                                            recipe_id,
00971                                            linetable, 
00972                                            *dispersion_relation, 
00973                                            *first_absolute_order, 
00974                                            *last_absolute_order,
00975                                            n_traces,
00976                                            threshold_to_positive,
00977                                            &rebinned_header),
00978                "Could not rebin noise of arc lamp spectrum");
00979 
00980         threshold_to_positive = false;
00981         uves_free_propertylist(&rebinned_header);
00982         check( rebinned = uves_rebin(spectrum,
00983                                      parameters, 
00984                                      recipe_id,
00985                                      linetable, 
00986                                      *dispersion_relation, 
00987                                      *first_absolute_order, 
00988                                      *last_absolute_order,
00989                                      n_traces,
00990                                      threshold_to_positive,
00991                                      &rebinned_header),
00992                "Could not rebin arc lamp spectrum");
00993 
00994         /* Save order-by-order rebinned spectrum+noise */
00995         if (DEBUG)
00996             {
00997             check( uves_save_image_local("Rebinned spectrum",
00998                              "wxb", rebinned, chip, 
00999                              trace, window, rebinned_header, true),
01000                    "Error saving rebinned spectrum");
01001 
01002             check( uves_save_image_local("Noise of rebinned spectrum",
01003                              "errwxb", rebinned_noise, chip, 
01004                              trace, window, rebinned_header, true),
01005                    "Error saving noise of rebinned spectrum");
01006             }
01007         
01008         check( merged = uves_merge_orders(rebinned, 
01009                                                   rebinned_noise,
01010                           rebinned_header,
01011                           m_method,
01012                           n_traces,
01013                           &merged_header,
01014                           &merged_noise),
01015                "Could not merge arc lamp spectrum");
01016 
01017         check( uves_plot_image_rows(merged, 1, 1, 1, 
01018                         "Wavelength (arbitrary units)", 
01019                         "Flux", "Resampled arc lamp spectrum"),
01020                "Plotting failed");
01021 
01022         /* Save merged arc lamp spectrum */
01023         if (DEBUG)
01024             {
01025             check( uves_save_image_local("Rebinned, merged spectrum",
01026                              "merged", merged, chip, 
01027                              trace, window, merged_header, true),
01028                    "Error saving merged spectrum");
01029             }
01030         
01031         nbins = cpl_image_get_size_x(merged);
01032 
01033         check( wavestep = uves_pfits_get_cdelt1(merged_header),
01034                "Error reading resampling step size");
01035         
01036         check( lambda_start = uves_pfits_get_crval1(merged_header), 
01037                "Could not read start wavelength of merged spectrum");
01038 
01039         /* For all identified lines fit the line width in the
01040            merged spectrum to get the resolution  */
01041         for (i = 0; i < cpl_table_get_nrow(linetable); i++)
01042             {
01043             double lambda = cpl_table_get_double(
01044                 linetable, LINETAB_LAMBDAC, i, NULL);
01045             double width  = 
01046                 cpl_table_get_double(linetable, "Xwidth"   , i, NULL) *
01047                 fabs(cpl_table_get_double(linetable, LINETAB_PIXELSIZE, i, NULL)); 
01048             /* in wlu */
01049             
01050             /* Convert line wavelength and width to 'bin' units */
01051             int bin       = 1 + 
01052                 uves_round_double((lambda - lambda_start) / wavestep);
01053             double width_bin = width / wavestep;
01054 
01055             /* Set fitting window to +-5 sigma */
01056             int first_bin = uves_max_int(    1, uves_round_double(bin - 5*width_bin));
01057             int last_bin  = uves_min_int(nbins, uves_round_double(bin + 5*width_bin));
01058 
01059             double my, sigma, norm, background;    /* Results of fit */
01060             double lambda_fwhm;
01061             
01062             if (cpl_table_is_valid(linetable, "Ident", i) && first_bin < last_bin)
01063                 {
01064                 /* Fit a gaussian to the merged arc spectrum */
01065                 uves_fit_1d_image(merged, 
01066 #if 1
01067                                                   merged_noise, 
01068 #else /* Unweighted fit like MIDAS which gives larger sigma */
01069                                                   NULL,
01070 #endif
01071                                                   NULL,
01072                           true,     /* Horizontal?    */
01073                           false,    /* Fix background?*/
01074                           false,    /* Fit background?*/
01075                           first_bin, 
01076                                                   last_bin, 
01077                                                   1,  /* xlo, xhi, y    */
01078                           &my, 
01079                                                   &sigma, 
01080                                                   &norm, 
01081                                                   &background, NULL, /* slope */
01082                           NULL, 
01083                                                   NULL, 
01084                                                   NULL,    /* mse, red_chisq,
01085                                   covariance     */
01086                           uves_gauss, 
01087                                                   uves_gauss_derivative, 
01088                                                   4);
01089                                         
01090                 if (cpl_error_get_code() == CPL_ERROR_CONTINUE)
01091                     {
01092                     uves_error_reset();
01093                     uves_msg_debug("Gaussian fitting failed "
01094                                "at lambda = %f wlu, bins = "
01095                                "%d - %d, ignoring line",
01096                                lambda, first_bin, last_bin);
01097                     
01098                     cpl_table_set_invalid(linetable, "deltaLambda", i);
01099                     
01100                     }
01101                 else
01102                     {
01103                         assure(cpl_error_get_code() == CPL_ERROR_NONE,
01104                                cpl_error_get_code(), "Gaussian fitting failed");
01105                     
01106                     /* Convert from bins to wavelength */
01107                     lambda_fwhm = TWOSQRT2LN2 * sigma * wavestep;
01108                     
01109                     cpl_table_set_double(linetable, "deltaLambda",
01110                                  i, lambda_fwhm);
01111 
01112                     }
01113                 }
01114             else
01115                 {
01116                 cpl_table_set_invalid(linetable, "deltaLambda", i);
01117                 }
01118             }
01119         
01120         
01121         /* Create column 'Resol'(ution) = lambda / deltalambda */
01122         check(( cpl_table_duplicate_column(linetable, "Resol", 
01123                            linetable, LINETAB_LAMBDAC),
01124             cpl_table_divide_columns  (linetable, "Resol",
01125                            "deltaLambda")),
01126               "Error creating 'Resol' column");
01127         
01128         /* Filter out extreme outliers (due to bad gaussian fit) */
01129         {
01130             double resol_avg   = cpl_table_get_column_median(linetable, "Resol");
01131             double resol_stdev = cpl_table_get_column_stdev (linetable, "Resol");
01132             double kappar = 10.0;
01133 
01134             for (i = 0; i < cpl_table_get_nrow(linetable); i++)
01135             {
01136                 double r = cpl_table_get_double(linetable, "Resol", i, NULL);
01137                 if (r < resol_avg - kappar*resol_stdev ||
01138                 r > resol_avg + kappar*resol_stdev)
01139                 {
01140                     cpl_table_set_invalid(linetable, "Resol", i);
01141                     cpl_table_set_invalid(linetable, "deltaLambda", i);
01142                 }
01143             }
01144         }
01145 
01146 
01147         /* check( uves_plot_table(linetable, "X", "Resol", 
01148            "(x, l / dl)"), "Plotting failed"); 
01149            check( uves_plot_table(linetable, "Y", "Resol", 
01150            "(y, l / dl)"), "Plotting failed"); 
01151         */
01152         check( uves_plot_table(linetable, LINETAB_LAMBDAC, "Resol",
01153                        "(l, l / dl)"), "Plotting failed");
01154         }
01155         
01156         /* Plot identifications */
01157             uves_free_table(&temp);
01158         check( temp = cpl_table_duplicate(linetable), 
01159            "Error copying line table");
01160         check( uves_erase_invalid_table_rows(temp, "Ident"), 
01161            "Error removing un-identified lines");
01162         check( uves_plot_table(temp, "X", "Ynew", 
01163                    "Line identifications"), 
01164            "Plotting failed");
01165         uves_free_table(&temp);
01166 
01167     } /* Plots for middle (object) window */
01168     
01169     if (DEBUG) 
01170     {
01171         /* Results of uves_wavecal_search are already 
01172            drawn on debug_image */
01173         
01174         /* Draw guess table lines using the initial solution */
01175         if (0) check( uves_draw_lines(debug_image, initial_dispersion,
01176                       order_locations, guess,
01177                       "Ident", "Order", relative_order,
01178                       -1, -1,
01179                       false,     /* true = vertical */
01180                       12), "Error drawing guess solution");
01181         
01182         /* Draw catalogue lines using the initial solution */
01183         check( uves_draw_lines(debug_image, initial_dispersion, order_locations,
01184                    line_refer, "Wave", NULL, relative_order,
01185                    uves_min_int(*first_absolute_order, *last_absolute_order),
01186                    uves_max_int(*first_absolute_order, *last_absolute_order),
01187                    true,                   /* true = vertical */
01188                    8), "Error drawing catalogue lines");
01189         
01190         /* Draw catalogue lines using the final solution */
01191         check( uves_draw_lines(debug_image, *dispersion_relation, order_locations, 
01192                    line_refer, "Wave", NULL, relative_order,
01193                    uves_min_int(*first_absolute_order, *last_absolute_order),
01194                    uves_max_int(*first_absolute_order, *last_absolute_order),
01195                    true,                     /* true = vertical */
01196                    16), "Error drawing catalogue lines");
01197         
01198         /* Draw detected lines using initial solution */
01199         if (0) check( uves_draw_lines(debug_image, initial_dispersion, 
01200                       order_locations, linetable, 
01201                       LINETAB_LAMBDAC, "Order", relative_order,
01202                       -1, -1,
01203                       false,            /* true = vertical */
01204                       -16), "Error drawing detected lines");
01205         
01206         /* Draw IDed lines */
01207             uves_free_table(&temp);
01208         check(( temp = cpl_table_duplicate(linetable),
01209             /* Delete rows with invalid 'Ident' */
01210             uves_erase_invalid_table_rows(temp, "Ident")),
01211           "Error duplicating table");
01212         
01213         check( uves_draw_lines(debug_image, *dispersion_relation, order_locations,
01214                    temp, LINETAB_LAMBDAC, "Order", relative_order,
01215                    -1, -1,
01216                    true,                  /* true = vertical */
01217                    0), "Error drawing detected lines");
01218         
01219 
01220         /* Explanation of drawing produced by code above:
01221            The output frame emission lines will look like this
01222 
01223 
01224                      #### |1
01225                          ####   |2  
01226                          #|3#
01227                          -+--
01228                          #|##
01229                          ####
01230                          ####
01231         
01232 
01233                 Legend:
01234 
01235                   ##: The emmission line
01236                   --: (horizontal line) The line was detected
01237                   |1: (vertical line)   Predicted position (final solution)
01238                   |2: (vertical line)   Predicted position (initial solution)
01239                   |3: (vertical line)   Is drawn iff the line was identified
01240 
01241 
01242           
01243         */
01244 
01245         /* Save the raw arc frame with detected emission lines marked */
01246         check( uves_save_image_local("Debug image", "rawdebug", 
01247                      debug_image, chip, trace, window,
01248                      rotated_header, true),
01249            "Error saving spectrum");
01250     }
01251 
01252     if (flames)
01253     {
01254         int start = 0;
01255         int count = cpl_table_get_nrow(linetable);
01256 
01257         check_nomsg( cpl_table_new_column(linetable, "Fibre", CPL_TYPE_INT) );
01258 
01259         cpl_table_fill_column_window(linetable, "Fibre",
01260                      start, count,
01261                      trace + 1);   /* Write value in range 1-9 */
01262     }
01263         
01264   cleanup:
01265     uves_free_table(&info_tbl);
01266     uves_free_table(&temp);
01267     uves_free_image(&weights_opt);
01268     uves_free_table(&cr_table);
01269     uves_free_image(&cr_image);
01270     uves_free_image(&spectrum);
01271     uves_free_image(&spectrum_noise);
01272     uves_free_image(&debug_image);
01273     uves_free_image(&rebinned);
01274     uves_free_image(&rebinned_noise);
01275     uves_free_image(&merged);
01276     uves_free_image(&merged_noise);
01277     uves_free_propertylist(&spectrum_header);
01278     uves_free_propertylist(&rebinned_header);
01279     uves_free_propertylist(&merged_header);
01280     cpl_free(relative_order);
01281     uves_polynomial_delete(&initial_dispersion);
01282     uves_free_table(&order_trace);
01283 
01284     return linetable;
01285 }
01286 
01287 
01288 
01289 /*----------------------------------------------------------------------------*/
01314 /*----------------------------------------------------------------------------*/
01315 void
01316 uves_wavecal_exe_body(cpl_frameset *frames,
01317               bool flames,
01318               const char *recipe_id,
01319               const cpl_parameterlist *parameters,
01320               const char *starttime)
01321 {
01322     /*
01323      * Variables containg the values of recipe parameters 
01324      */
01325 
01326     /* General */
01327     bool DEBUG;
01328 
01329     /* Extraction */
01330     int NWINDOWS;
01331     double OFFSET;
01332     double SLITLENGTH_par;  /* slitlength given by user */
01333 
01334     /* Search */
01335     int    RANGE;
01336     int    MAXLINES;
01337     int    MINLINES;
01338     centering_method CENTERING_METHOD;
01339 
01340     /* First solution */
01341     double SHIFT_MAX;
01342     double SHIFT_STEP;
01343     double SHIFT_TOLERANCE;
01344 
01345     /* Identify */
01346     double  ALPHA;
01347     double  MAXERROR;
01348     int     DEGREE;
01349     /* Calibrate */
01350     double  TOLERANCE;
01351     double  KAPPA;
01352 
01353     /* Input */
01354     cpl_image        *arclamp[2]          = {NULL, NULL};
01355     cpl_image        *arclamp_noise       = NULL;
01356     uves_propertylist *arclamp_header[2]   = {NULL, NULL};
01357     uves_propertylist *rotated_header[2]   = {NULL, NULL};
01358     
01359     /* Order table */
01360     cpl_table        *ordertable            = NULL;
01361     uves_propertylist *ordertable_header     = NULL;
01362     polynomial       *order_locations       = NULL;
01363     cpl_table        *traces                = NULL;
01364     
01365     /* Bias */
01366     cpl_image        *master_bias        = NULL;
01367     uves_propertylist *master_bias_header = NULL;
01368 
01369     /* Flat field */
01370     cpl_image        *master_flat        = NULL;
01371     cpl_image        *mflat_noise        = NULL;
01372     uves_propertylist *master_flat_header = NULL;
01373 
01374     /* Weight map */
01375     cpl_image        *weights            = NULL;
01376 
01377     /* DRS guess table is not used */
01378     /* 
01379        cpl_table        *drs_table             = NULL;
01380        uves_propertylist *drs_header            = NULL;
01381     */
01382 
01383     //FLAMES-DRS specific descriptors
01384     int* fibres_mask=NULL;
01385     double* fibres_pos=NULL;
01386 
01387     /* Guess line table */
01388     cpl_table        *guess              = NULL;
01389     polynomial       *absolute_order     = NULL;
01390     
01391     /* Velocity correction table */
01392     cpl_table        *corvel             = NULL;
01393     uves_propertylist *corvel_header      = NULL;
01394 
01395     /* Reference catalogue */
01396     cpl_table        *line_refer            = NULL;
01397     cpl_table        *line_intmon           = NULL;
01398    
01399     /* Output */
01400     lt_type          *linetable             = NULL;
01401 
01402     uves_propertylist *primary_header        = NULL;
01403     uves_propertylist *table_header          = NULL;
01404     /* QC for resolution + intmon + NULL */
01405     cpl_table        *qclog[3]              = {NULL, NULL, NULL};
01406 
01407     /* Local variables */
01408     cpl_image        *absorder_image     = NULL;
01409     const char *arclamp_filename = "";
01410     const char *line_refer_filename = "";
01411     const char *line_intmon_filename = "";
01412     char *product_filename = NULL;
01413     char *temp = NULL;
01414     bool blue  = false;
01415     bool sim_cal = false;
01416     enum uves_chip chip;
01417     int binx = 0;
01418     int biny = 0;
01419     bool drs_cvel_sw=false;
01420     const char* PROCESS_CHIP=NULL;
01421     extract_method em;
01422 
01423     /* Read recipe parameters */
01424     {
01425     const char *centering_m = "";
01426         const char *profile = "";
01427 
01428  
01429 
01430     /* General */
01431     check( uves_get_parameter(parameters, NULL, "uves", "debug", 
01432                   CPL_TYPE_BOOL, &DEBUG), "Could not read parameter");
01433     
01434     check( uves_get_parameter(parameters, NULL, "uves", "process_chip", CPL_TYPE_STRING, &PROCESS_CHIP),
01435                "Could not read parameter");
01436 
01437         /* Extraction */
01438     check( uves_get_parameter(parameters, NULL, recipe_id, "nwindows",
01439                   CPL_TYPE_INT   , &NWINDOWS    ), "Could not read parameter");
01440     check( uves_get_parameter(parameters, NULL, recipe_id, "length",
01441                   CPL_TYPE_DOUBLE, &SLITLENGTH_par), "Could not read parameter");
01442     check( uves_get_parameter(parameters, NULL, recipe_id, "offset",
01443                   CPL_TYPE_DOUBLE, &OFFSET      ), "Could not read parameter");
01444     
01445     /* Don't allow optimal extraction. This requires that
01446        additional arguments (weight image, ..) are passed to uves_extract */
01447     temp = uves_sprintf("%s.%s", recipe_id, UVES_EXTRACT_ID);
01448     check( em = uves_get_extract_method(parameters, NULL, temp),
01449            "Could not read extraction method");
01450     
01451     check( uves_get_parameter(parameters, NULL, recipe_id, UVES_EXTRACT_ID ".profile",
01452                   CPL_TYPE_STRING, &profile), "Could not read parameter");
01453 
01454     assure( em == EXTRACT_LINEAR || em == EXTRACT_AVERAGE || em == EXTRACT_WEIGHTED ||
01455             (em == EXTRACT_OPTIMAL && strcmp(profile, "constant") == 0),
01456             CPL_ERROR_UNSUPPORTED_MODE, 
01457             "Only linear/average/weighted/optimal(constant profile) extraction "
01458             "methods are supported by this recipe");
01459     
01460     /* Search */
01461     check( uves_get_parameter(parameters, NULL, recipe_id, "search.range",
01462                   CPL_TYPE_INT   , &RANGE       ), "Could not read parameter");
01463     check( uves_get_parameter(parameters, NULL, recipe_id, "search.minlines",
01464                   CPL_TYPE_INT   , &MINLINES    ), "Could not read parameter");
01465     check( uves_get_parameter(parameters, NULL, recipe_id, "search.maxlines",
01466                   CPL_TYPE_INT   , &MAXLINES    ), "Could not read parameter");
01467     check( uves_get_parameter(parameters, NULL, recipe_id, "search.centeringmethod",
01468                   CPL_TYPE_STRING, &centering_m ), "Could not read parameter");
01469     if      (strcmp(centering_m, "gravity" ) == 0) CENTERING_METHOD = CENTERING_GRAVITY;
01470     else if (strcmp(centering_m, "gaussian") == 0) CENTERING_METHOD = CENTERING_GAUSSIAN;
01471     else
01472         { 
01473         /* Impossible */ assure(false, CPL_ERROR_ILLEGAL_INPUT,
01474                     "Unrecognized parameter value '%s'", centering_m);
01475         }
01476     
01477     /* First solution */
01478     check( uves_get_parameter(parameters, NULL, recipe_id, "first.shiftmax",
01479                   CPL_TYPE_DOUBLE , &SHIFT_MAX      ),
01480            "Could not read parameter");
01481     check( uves_get_parameter(parameters, NULL, recipe_id, "first.shiftstep", 
01482                   CPL_TYPE_DOUBLE , &SHIFT_STEP     ), 
01483            "Could not read parameter");
01484     check( uves_get_parameter(parameters, NULL, recipe_id, "first.shifttoler",
01485                   CPL_TYPE_DOUBLE , &SHIFT_TOLERANCE), 
01486            "Could not read parameter");
01487     
01488     /* Identify */
01489     check( uves_get_parameter(parameters, NULL, recipe_id, "identify.alpha",
01490                   CPL_TYPE_DOUBLE , &ALPHA      ), "Could not read parameter");
01491     check( uves_get_parameter(parameters, NULL, recipe_id, "identify.maxerror",
01492                   CPL_TYPE_DOUBLE , &MAXERROR   ), "Could not read parameter");
01493     check( uves_get_parameter(parameters, NULL, recipe_id, "identify.degree",
01494                   CPL_TYPE_INT    , &DEGREE     ), "Could not read parameter");
01495     
01496     /* Calibrate */
01497     check( uves_get_parameter(parameters, NULL, recipe_id, "calibrate.tolerance",
01498                   CPL_TYPE_DOUBLE, &TOLERANCE   ), "Could not read parameter");
01499     check( uves_get_parameter(parameters, NULL, recipe_id, "calibrate.kappa",
01500                   CPL_TYPE_DOUBLE, &KAPPA   ), "Could not read parameter");
01501     
01502     /* Additional checks */
01503     if (CENTERING_METHOD == CENTERING_GRAVITY)
01504         {
01505         uves_msg_warning("Centering method 'gravity' might lead to inaccurate "
01506                  "results. Recommended is 'gaussian'");
01507         }
01508     }
01509 
01510     /* Load raw image and header, and identify input frame as red or blue */
01511     check( uves_load_arclamp(frames, flames, &arclamp_filename, arclamp, arclamp_header, 
01512                  rotated_header, &blue, &sim_cal), "Error loading raw frame");
01513 
01514     /* Load reference line table */
01515     check( uves_load_linerefertable(frames, &line_refer_filename, &line_refer, NULL),
01516        "Could not load line reference table");
01517     uves_msg("Using line reference table '%s'", line_refer_filename);
01518     
01519     /* Load INTensity MONitoring table if present */
01520     if (cpl_frameset_find(frames, UVES_LINE_INTMON_TABLE) != NULL)
01521     {
01522         uves_free_table(&line_intmon);
01523         check( uves_load_lineintmon(frames, &line_intmon_filename,
01524                     &line_intmon),
01525            "Error loading line reference table");
01526         
01527         uves_msg("Using bright line table '%s'", line_intmon_filename);
01528     }
01529   
01530     /*
01531      * Adjust parameters according to binning 
01532      */
01533     check (binx = uves_pfits_get_binx(arclamp_header[0]),
01534        "Could not read x binning factor from input header");
01535     check (biny = uves_pfits_get_biny(arclamp_header[0]),
01536        "Could not read y binning factor from input header");
01537     SLITLENGTH_par /= (1.0*binx);  /* Extraction slit length */
01538     RANGE /= (1.0*biny);           /* Search window */
01539     SHIFT_MAX /= (1.0*binx);       /* Max shift compared to guess solution */
01540     SHIFT_STEP /= (1.0*binx);
01541 
01542     /* After the default tolerance was lowered to 0.07, do not adjust it according to binning,
01543        which would cause too many lines to be rejected
01544        
01545        TOLERANCE /= (1.0*biny); 
01546     */
01547 
01548 
01549     /* Loop over one or two chips, over traces and
01550        over extraction windows */
01551     for (chip = uves_chip_get_first(blue); 
01552          chip != UVES_CHIP_INVALID; 
01553          chip = uves_chip_get_next(chip)) {
01554 
01555 
01556         if(strcmp(PROCESS_CHIP,"redu") == 0) {
01557             chip = uves_chip_get_next(chip);
01558         }
01559       
01560         const char *ordertable_filename = "";
01561         const char *corvel_filename = "";
01562         const char *master_flat_filename = "";
01563         const char *master_bias_filename = "";
01564         const char *weights_filename = "";
01565         /* const char *drs_filename        = "";    not used */
01566         const char *guess_filename      = "";
01567         const char *chip_name = "";
01568         int ntraces;
01569         int tracerow;                       /* Index of table row */
01570         int raw_index = uves_chip_get_index(chip);
01571         int current_linetable_extension;
01572         int tab_in_out_oshift = -1;
01573         double tab_in_out_yshift = -1;
01574         double slitlength;
01575       
01576       uves_msg("Processing %s chip in '%s'",
01577                uves_chip_tostring_upper(chip), arclamp_filename);
01578       
01579       check_nomsg( chip_name = uves_pfits_get_chipid(arclamp_header[raw_index], chip));
01580       
01581       
01582       uves_msg_debug("binning = %dx%d", binx, biny);
01583       
01584       
01585       /* Load the order table for this chip */
01586       uves_free_table       (&ordertable);
01587       uves_free_propertylist(&ordertable_header);
01588       uves_polynomial_delete(&order_locations);
01589       uves_free_table       (&traces);
01590       
01591       
01592       check( uves_load_ordertable(frames, 
01593                                   flames,
01594                                   chip_name, 
01595                                   &ordertable_filename,
01596                                   &ordertable, 
01597                                   &ordertable_header,
01598                                   NULL,
01599                                   &order_locations, 
01600                                   &traces, 
01601                                   (flames) ? &tab_in_out_oshift : NULL,
01602                                   (flames) ? &tab_in_out_yshift : NULL,
01603                                   &fibres_mask, 
01604                                   &fibres_pos, /* fibre_pos,fibre_mask */
01605                                   chip, 
01606                                   false  /* load guess table? */),
01607              "Could not load order table");
01608       uves_msg("Using order table in '%s'", ordertable_filename);
01609       ntraces = cpl_table_get_nrow(traces);
01610       uves_free_double(&fibres_pos);
01611       uves_free_int(&fibres_mask);
01612       
01613       /* Load master bias if present */
01614       uves_free_image(&master_bias);
01615       uves_free_propertylist(&master_bias_header);
01616       if (cpl_frameset_find(frames, UVES_MASTER_BIAS(chip)) != NULL)
01617           {
01618               check( uves_load_mbias(frames, chip_name, &master_bias_filename, &master_bias, 
01619                                      &master_bias_header, chip),
01620                      "Error loading master bias");
01621               
01622               uves_msg_low("Using master bias in '%s'", master_bias_filename);
01623           }
01624       else
01625           {
01626               uves_msg_warning("Master bias not provided. Bias subtraction not done");
01627           }
01628       
01629       
01630       /* Load master flat if present */
01631       uves_free_image(&master_flat);
01632       uves_free_propertylist(&master_flat_header);
01633       if ((cpl_frameset_find(frames, UVES_MASTER_FLAT(chip)) != NULL ||
01634            cpl_frameset_find(frames, UVES_MASTER_DFLAT(chip)) != NULL ||
01635            cpl_frameset_find(frames, UVES_MASTER_IFLAT(chip)) != NULL ||
01636            cpl_frameset_find(frames, UVES_MASTER_TFLAT(chip)) != NULL))
01637           {
01638               check( uves_load_mflat(frames, chip_name, &master_flat_filename, &master_flat, 
01639                                      &master_flat_header, chip, NULL),
01640                      "Error loading master flat");
01641               
01642               uves_msg_low("Using master flat in '%s'", master_flat_filename);
01643           }
01644       else
01645           {
01646               uves_msg_warning("Master flat not provided. Flat-fielding not done");
01647           }
01648 
01649       /* Load weight map if present */
01650       if (em == EXTRACT_WEIGHTED) {
01651           uves_free_image(&weights);
01652           check( weights = uves_load_weights(frames, &weights_filename, chip),
01653                  "Error loading weight map");
01654 
01655           uves_msg_low("Using weight map %s", weights_filename);
01656       }
01657 
01658       if (flames)
01659           /* Load CORVEL table */
01660           {
01661               if (cpl_frameset_find(frames, FLAMES_CORVEL(chip)))
01662                   {
01663                       check( uves_load_corvel(frames, chip,
01664                                               &corvel, &corvel_header,
01665                                               &corvel_filename),
01666                              "Could not load velocity correction table");
01667                       
01668                       uves_msg("Using velocity correction table %s", corvel_filename);
01669                       
01670                       drs_cvel_sw=true;
01671                       
01672                       
01673                   }
01674               else
01675                   {
01676                       uves_msg("No corvel table found. Switch off corvel");
01677                       corvel = NULL;
01678                   }
01679           }
01680 
01681       /* Allocate all line tables for this chip */
01682       uves_lt_delete(&linetable);
01683       linetable = uves_lt_new(NWINDOWS, ntraces);
01684 
01685 
01686       /* Init QC tables for this chip */
01687       uves_qclog_delete(&qclog[0]); qclog[0] = uves_qclog_init(arclamp_header[raw_index], chip);
01688       uves_qclog_delete(&qclog[1]); qclog[1] = uves_qclog_init(arclamp_header[raw_index], chip);
01689 
01690       /* Saving the rotated raw arc frame */
01691       if (DEBUG) check( uves_save_image_local("Arc lamp frame", "raw", 
01692                                               arclamp[raw_index], 
01693                                               chip, -1, -1, rotated_header[raw_index], true),
01694                         "Error saving arc lamp frame");
01695 
01696       if (master_bias != NULL)
01697           {
01698               uves_msg("Subtracting master bias");
01699                 
01700               check( uves_subtract_bias(arclamp[raw_index], master_bias),
01701                      "Error during bias subtraction");
01702           }
01703       else {
01704           /* In lack of a real master bias frame, one might subtract the bias by estimating it
01705              as the median value across the chip (which should be okay for arc lamp frames)
01706           */
01707             
01708           /* Disabled. Would need to be tested. probably doesn't make any big difference anyway
01709              double bias = cpl_image_get_median(ff);
01710              uves_msg_debug("Estimated bias level is %f ADU", bias);
01711              cpl_image_subtract_scalar(ff, bias);
01712           */
01713       }
01714 
01715 
01716       /* Define arc lamp noise */
01717       uves_free_image(&arclamp_noise);
01718       check( arclamp_noise = uves_define_noise(arclamp[raw_index], 
01719                                                arclamp_header[raw_index], 1, chip),
01720              "Could not set arc lamp noise");
01721 
01722       if (master_flat != NULL)
01723           {
01724               uves_msg("Dividing by master flat");
01725                 
01726               uves_free_image(&mflat_noise);
01727               check( mflat_noise = 
01728                      uves_define_noise(master_flat, master_flat_header, 
01729                                        uves_pfits_get_datancom(master_flat_header),
01730                                        chip),
01731                      "Could not set master flat error bars");
01732                 
01733               check( uves_flatfielding(arclamp[raw_index], arclamp_noise,
01734                                        master_flat, mflat_noise),
01735                      "Error while dividing by flat field");
01736           }
01737 
01738       if (DEBUG) check( uves_save_image_local("Pre-processed arc lamp frame",
01739                                               "preproc", 
01740                                               arclamp[raw_index], chip, -1, -1,
01741                                               rotated_header[raw_index], true),
01742                         "Error saving arc lamp frame");
01743 
01744       /* Set appropriate slitlength if user did not */
01745       if (SLITLENGTH_par < 0) {
01746             
01747           double header_full_slit;
01748             
01749           check( header_full_slit = 
01750                  uves_pfits_get_slitlength_pixels(arclamp_header[raw_index], chip),
01751                  "Could not read slit length");
01752             
01753           /* Avoid pixels at the edge of the slit
01754            *  which are likely to be noisy 
01755            */
01756           slitlength = uves_max_double(1.0, (header_full_slit - 2)/NWINDOWS);
01757 
01758           uves_msg("Full slit = %.2f pixels", header_full_slit);
01759       }
01760       else {
01761           slitlength = SLITLENGTH_par;
01762       }
01763                 
01764    
01765       /* Loop over traces */
01766       for(tracerow = 0; tracerow < ntraces; tracerow++) {
01767         double trace_offset;
01768         int trace_number;
01769         int trace_enabled;
01770         
01771         trace_offset  = cpl_table_get_double(traces, "Offset"   , tracerow, NULL);
01772         trace_number  = cpl_table_get_int   (traces, "TraceID"  , tracerow, NULL);
01773         trace_enabled = cpl_table_get_int   (traces, "Tracemask", tracerow, NULL);
01774 
01775             if (ntraces > 1) {
01776                 uves_msg("Processing trace %d", trace_number);
01777             }
01778 
01779         if (flames && sim_cal) 
01780         {
01781             /* Only calibrate SIMCAL fibre in SIMCAL mode */
01782             trace_enabled = (trace_number == 1) ? 1 : 0;
01783         }
01784 
01785         uves_msg_low("Trace offset = %.2f pixels ; enabled = %d",
01786              trace_offset, trace_enabled);
01787         
01788         assure( flames || trace_number == 0, CPL_ERROR_ILLEGAL_INPUT,
01789             "%s: UVES trace number must be 0, it is %d", 
01790             ordertable_filename, trace_number );
01791         
01792         
01793         if (trace_enabled != 0) {
01794         int window;          /* window number */
01795 
01796         /* Load guess line table for this trace, any window */
01797         uves_free_table       (&guess);
01798         uves_polynomial_delete(&absolute_order);
01799 
01800         check( uves_load_linetable(
01801                frames, flames, chip_name, order_locations,
01802                cpl_table_get_column_min(ordertable, "Order"),
01803                cpl_table_get_column_max(ordertable, "Order"),
01804                &guess_filename, &guess, 
01805                NULL, NULL,
01806                &absolute_order, chip, trace_number, -1),
01807                "Could not load guess line table for trace number %d", 
01808                trace_number);
01809         uves_msg("Using guess line table '%s'", guess_filename);
01810  
01811         if (DEBUG)
01812             {
01813             /* Create an image showing the polynomial   m = f(x,y)
01814                where m is the absolute order number
01815             */
01816             int x, y;
01817 
01818             absorder_image = cpl_image_new(cpl_image_get_size_x(arclamp[raw_index]),
01819                                cpl_image_get_size_y(arclamp[raw_index]),
01820                                CPL_TYPE_FLOAT);
01821             assure_mem(absorder_image);
01822             
01823             for (y = 1; y <= cpl_image_get_size_y(arclamp[raw_index]); y++)
01824                 {
01825                 for (x = 1; x <= cpl_image_get_size_x(arclamp[raw_index]); x++)
01826                     {
01827                     double absorder = 
01828                         uves_polynomial_evaluate_2d(absolute_order, x, y);
01829                     
01830                     cpl_image_set(absorder_image, x, y, absorder);
01831                     }
01832                 }
01833             
01834             check( uves_save_image_local("Absolute order image", "absord",
01835                              absorder_image, chip, trace_number,
01836                              1, rotated_header[raw_index], true),
01837                    "Error saving absolute order image");
01838             
01839             uves_free_image(&absorder_image);
01840             }
01841 
01842         /* Loop over sky windows */
01843         for (window = 1; window <= NWINDOWS; window ++) {
01844             /*      
01845                 | -trace_offs- | 
01846                 |              |  -win_offs-  |
01847                 |              |              |
01848                 |              | | -glb_offs- | 
01849                         order_loc.=0       |
01850                 |
01851                 window_loc.
01852             */
01853                 
01854             /* Adjacent windows are separated by slitlength,
01855                and offset is zero when window_number = (NWINDOWS+1)/2,
01856                so the formula is */
01857             double window_offset =
01858             slitlength * (window - (NWINDOWS+1) / 2.0);
01859 
01860             /* Total offset (see sketch) */
01861             double offset = trace_offset + window_offset + OFFSET;
01862 
01863             /* Number of lines to detect. Use defaults if 
01864                parameter values are negative */
01865 #if 0
01866             int lines_min = (MINLINES >= 1) ? MINLINES : 
01867             (chip == UVES_CHIP_REDU) ? 1000 : 2000;
01868             int lines_max = (MAXLINES >= 1) ? MAXLINES : 
01869             (chip == UVES_CHIP_REDU) ? 1400 : 2400;
01870 #else
01871 /* like MIDAS (fewer lines): */
01872             int lines_min = (MINLINES >= 1) ? MINLINES : 
01873             (chip == UVES_CHIP_REDU) ? 1000 : 1200;
01874             int lines_max = (MAXLINES >= 1) ? MAXLINES : 
01875             (chip == UVES_CHIP_REDU) ? 1400 : 1600;
01876 #endif
01877 
01878             assure( lines_min <= lines_max , CPL_ERROR_ILLEGAL_INPUT, 
01879                 "Minimum and maximum number of requested line "
01880                 "detections don't make sense (min = %d; max = %d)",
01881                 lines_min, lines_max);
01882 
01883             if (NWINDOWS > 1) {
01884                 uves_msg("Processing window %d of %d", window, NWINDOWS);
01885             }
01886                     
01887             passure( *(uves_lt_get_disprel(linetable, window, trace_number))
01888                  == NULL, "%d %d", window, trace_number);
01889             passure( *(uves_lt_get_absord (linetable, window, trace_number))
01890                  == NULL, "%d %d", window, trace_number);
01891 
01892 
01893             if (weights != NULL) {
01894                 /* Object weighted extraction, use offset = 0 three times */
01895                 offset = 0;
01896             }
01897                     
01898             /* Set absord guess solution */
01899             *uves_lt_get_absord(linetable, window, trace_number) = 
01900             uves_polynomial_duplicate(absolute_order);
01901 
01902             /* Execute macrosteps */
01903             check( *uves_lt_get_table(linetable, window, trace_number) =
01904                    uves_wavecal_process_window(
01905                        /* Raw */
01906                        arclamp[raw_index], 
01907                        arclamp_noise,
01908                        rotated_header[raw_index],
01909                        /* Calibration */
01910                        ordertable, order_locations,
01911                        master_flat != NULL,
01912                        weights,
01913                        /* drs_table,  not used */
01914                        guess,
01915                        line_refer,
01916                        flames,
01917                        tab_in_out_oshift,
01918                        tab_in_out_yshift,
01919                    /* Which window? */
01920                    chip, biny, trace_number, window,
01921                    /* Parameters    */
01922                    DEBUG,
01923                    /* Extract       */
01924                    offset, slitlength, parameters, recipe_id,
01925                    /* Search        */
01926                    RANGE, lines_min, lines_max, CENTERING_METHOD,
01927                    /* First solution */
01928                    SHIFT_MAX, SHIFT_STEP, SHIFT_TOLERANCE,
01929                    /* Identify      */
01930                    ALPHA, MAXERROR, DEGREE,
01931                    /* Calibrate     */
01932                    TOLERANCE, KAPPA,
01933                    /* Returned */
01934                    uves_lt_get_disprel(linetable, window, trace_number),
01935                    uves_lt_get_absord (linetable, window, trace_number),
01936                    uves_lt_get_firstabs(linetable, window, trace_number),
01937                    uves_lt_get_lastabs(linetable, window, trace_number)),
01938                "Wavelength calibration failed");
01939 
01940 
01941             //If CORVEL map is provided we perform the 
01942                     //corresponding analysis
01943             if(drs_cvel_sw) {
01944               /*
01945       define/local ord_min/i/1/1 0
01946       define/local ord_max/i/1/1 0
01947       define/local rsample/d/1/1 0
01948       statistic/table {ORDTAB} :ORDER >Null
01949       ord_min = outputr(1)
01950       ord_max = outputr(2)
01951       rsample = {{LINTAB},PIXEL(1)}
01952       rsample = 2./3. * rsample
01953       rebin/echelle  {ofrm} w{ofrm} {rsample} NONL {LINTAB} {SESSOUTV}
01954       mercut/echelle w{ofrm} mw{ofrm} {ord_min},{ord_max} NOAPPEND 
01955       !corvel stuff
01956       define/local OLD_CVEL_MAX/d/1/1 {DRS_CVEL_MAX}
01957       define/local OLD_CVEL_MIN/d/1/1 {DRS_CVEL_MIN}
01958       @p flames_reduce,VCORREL x1_rbf_ cvel1 0 {ord_max} {parCorVelTab} _0 _{chip({PATHID})} 0
01959       DRS_CVEL_MAX = DRS_CVEL_MAX + {q1}
01960       DRS_CVEL_MIN = DRS_CVEL_MIN + {q1}
01961 
01962       @p flames_reduce,VCORREL x1_rbf_ cvel2 0 {ord_max} {parCorVelTab} _0 _{chip({PATHID})} 0
01963       cvel_0 = {q1}
01964       DRS_CVEL_MAX = OLD_CVEL_MAX
01965       DRS_CVEL_MIN = OLD_CVEL_MIN
01966               */
01967 
01968               int ord_min=0;
01969               int ord_max=0;
01970                       double rsample=0;
01971                       double old_cvel_min=DRS_CVEL_MIN;
01972                       double old_cvel_max=DRS_CVEL_MAX;
01973                       double drs_cvel_min=old_cvel_min;
01974                       double drs_cvel_max=old_cvel_max;
01975 
01976                       //rebin
01977                       //merge
01978                       //computes vcorr
01979 
01980                       
01981                       ord_min = ord_min;
01982                       ord_max = ord_max;
01983                       rsample = rsample;
01984                       drs_cvel_min=old_cvel_min;
01985                       drs_cvel_max=old_cvel_max;
01986 
01987             }
01988 
01989 
01990 
01991             if (flames ||                             /* FLAMES: all fibres */
01992             (window == 2 && trace_number == 0)) { /* UVES: central window */
01993 
01994 
01995             check( uves_wavecal_qclog(
01996                    *uves_lt_get_table(
01997                        linetable,
01998                        window,
01999                        trace_number),
02000                                    *uves_lt_get_firstabs(linetable, window, trace_number),
02001                                    *uves_lt_get_lastabs(linetable, window, trace_number),
02002                    arclamp[raw_index], 
02003                    arclamp_header[raw_index],
02004                    flames, 
02005                    trace_number, trace_enabled, trace_offset,
02006                    chip,
02007                                    qclog[0]),
02008                    "Could not calculate resolution QC parameters");
02009 
02010             if (line_intmon != NULL) {
02011                 check( uves_wavecal_qclog_intmon(
02012                        *uves_lt_get_table(
02013                        linetable,
02014                        window,
02015                        trace_number), 
02016                        line_intmon,
02017                        arclamp_header[raw_index],
02018                        flames, trace_number,
02019                        chip,
02020                        qclog[1]),
02021                    "Could not calculate int.mon. QC parameters");
02022             }
02023             else
02024                 {
02025                 /* Kill initialization and set pointer to NULL */
02026                 uves_qclog_delete(&qclog[1]);
02027                 }
02028             }
02029                     
02030             /* Finished processing. Save later (because
02031                all QC parameters must be available
02032                when the product file is first created). */
02033 
02034         }/* for each window... */
02035             
02036         }/* if trace enabled? */
02037         else
02038         {
02039             uves_msg("Skipping trace number %d", trace_number);
02040         }
02041     }/* for each trace... */
02042 
02043     /* Finished calculating all line tables for current chip. Now save. */
02044 
02045     /* Prepare product filename 
02046        (which need not be calculated for each trace and window) */
02047     cpl_free(product_filename);
02048     check( product_filename = uves_line_table_filename(chip), "Error getting filename");
02049     current_linetable_extension = 1;
02050         
02051     /* Loop over traces */
02052     for(tracerow = 0; tracerow < cpl_table_get_nrow(traces); tracerow++)
02053         {
02054         int trace_number;
02055         double trace_offset;
02056         int trace_enabled;
02057             
02058         trace_offset  = cpl_table_get_double(traces, "Offset"    , tracerow, NULL);
02059         trace_number  = cpl_table_get_int   (traces, "TraceID"   , tracerow, NULL);
02060         trace_enabled = cpl_table_get_int   (traces, "Tracemask" , tracerow, NULL);
02061             
02062         if (trace_enabled != 0)
02063                     {
02064             int window;
02065                 
02066             /* Loop over sky windows */
02067             for (window = 1; window <= NWINDOWS; window ++)
02068                 {
02069                 double window_offset =
02070                     slitlength * (window - (NWINDOWS+1) / 2.0);
02071             
02072                 double offset = trace_offset + window_offset + OFFSET;
02073         
02074                 /* Table header */
02075                 uves_free_propertylist(&table_header);
02076                 table_header   = uves_propertylist_new();
02077                 check( uves_pfits_set_traceid     ( table_header, trace_number),
02078                        "Error writing trace ID to product header");
02079                 check( uves_pfits_set_offset      ( table_header, offset),
02080                        "Error writing trace offset to product header");
02081                 check( uves_pfits_set_windownumber( table_header, window),
02082                        "Error writing window number to product header");
02083                 check( uves_pfits_set_firstabsorder( table_header, 
02084                                      *uves_lt_get_firstabs(
02085                                      linetable, 
02086                                      window,
02087                                      trace_number)),
02088                        "Error writing order number to product header");
02089                 check( uves_pfits_set_lastabsorder( table_header,
02090                                     *uves_lt_get_lastabs(
02091                                     linetable, 
02092                                     window,
02093                                     trace_number)),
02094                        "Error writing order number to product header");
02095 
02096                 /* Save line table + 2 polynomials (in 3 extensions) */
02097 
02098                 if (current_linetable_extension == 1) {
02099                     uves_free_propertylist(&primary_header);
02100                     primary_header = uves_propertylist_new();
02101                     
02102                     if (flames)
02103               {
02104             char values[80];
02105             /* The MIDAS pipeline writes this QC to the
02106                header (always zero), but not as part of
02107                the QC logging */
02108             check_nomsg( uves_flames_pfits_set_ccfposmax(
02109                                      primary_header, 0.0) );
02110             //Add descriptors needed for science reduction
02111             /* FIBREMASK */
02112 
02113             uves_propertylist_append_string(primary_header, 
02114                             "HISTORY", 
02115                             "'FIBREMASK','I*4'");
02116 
02117             {
02118               int i;
02119               for (i = 0; i < N_FIBRES_MAX; i++) {
02120                 snprintf(values, 80, "%1.1d ",
02121                      cpl_table_get_int(traces,"Tracemask",
02122                                i,NULL));
02123                 uves_propertylist_append_string(primary_header,
02124                                 "HISTORY", values);
02125                 uves_msg_warning("value=%d",
02126                          cpl_table_get_int(traces,
02127                                    "Tracemask",
02128                                    i,NULL));
02129               }
02130             }
02131             uves_propertylist_append_string(primary_header,
02132                             "HISTORY", " ");
02133 
02134 
02135             /* PIXEL */        
02136                         double pixelsize;
02137                         double wavestep;
02138 
02139             check( pixelsize = 
02140                    cpl_table_get_column_mean(
02141                              *uves_lt_get_table(
02142                                         linetable,
02143                                         window,
02144                                         trace_number),
02145                              LINETAB_PIXELSIZE),
02146                    "Error reading mean pixelsize");
02147             uves_msg_warning("Average pixelsize = %f w.l.u.", 
02148                        pixelsize);
02149 
02150             wavestep = pixelsize*2.0/3;
02151 
02152             uves_propertylist_append_string(primary_header, 
02153                             "HISTORY", 
02154                             "'PIXEL','R*4'");
02155             snprintf(values,80,"%14.7g %14.7g",pixelsize,pixelsize);
02156             uves_propertylist_append_string(primary_header,
02157                             "HISTORY", values);
02158             uves_propertylist_append_string(primary_header,
02159                             "HISTORY", " ");
02160                       
02161 
02162 
02163               }
02164                     
02165                     uves_msg("Creating line table '%s'", product_filename);
02166                     check( uves_frameset_insert(
02167                            frames,
02168                            *uves_lt_get_table(
02169                                linetable,
02170                                window,
02171                                trace_number),
02172                            CPL_FRAME_GROUP_PRODUCT,
02173                            CPL_FRAME_TYPE_TABLE,
02174                            CPL_FRAME_LEVEL_INTERMEDIATE,
02175                            product_filename,
02176                            UVES_LINE_TABLE(flames, chip),
02177                            arclamp_header[raw_index],     
02178                            primary_header,
02179                            table_header,
02180                            parameters,
02181                            recipe_id,
02182                            PACKAGE "/" PACKAGE_VERSION,
02183                            qclog, starttime, true, 0),
02184                            "Could not add line table '%s' (%s) to frameset",
02185                            product_filename, UVES_LINE_TABLE(flames, chip));
02186                         
02187                     uves_msg("Line table '%s' (%s) added to frameset",
02188                          product_filename, UVES_LINE_TABLE(flames, chip));
02189                     }
02190                 else   /* If this is not the first line table, 
02191                       append to the existing file */
02192                     {
02193                     check( uves_table_save(
02194                            *uves_lt_get_table(linetable,
02195                                       window,
02196                                       trace_number),
02197                            NULL,            /* Primary header,
02198                                        ignored when mode
02199                                        is IO_EXTEND */
02200                            table_header,    /* Extension header */
02201                            product_filename,/* This file 
02202                                        already exists */
02203                            CPL_IO_EXTEND),   /* Append to
02204                                     existing file */
02205                            "Error appending table to file '%s'", 
02206                            product_filename);
02207                     }
02208                 current_linetable_extension += 1;
02209                 
02210                 /* Save in next extension */
02211                 check( uves_save_polynomial(*uves_lt_get_disprel(
02212                                 linetable, 
02213                                 window,
02214                                 trace_number),
02215                                 product_filename,
02216                                 table_header), 
02217                        "Could not write polynomial to file '%s'", 
02218                        product_filename);
02219                 current_linetable_extension += 1;
02220 
02221                 /* Save in next extension */
02222                 check( uves_save_polynomial(*uves_lt_get_absord(
02223                                 linetable, 
02224                                 window,
02225                                 trace_number), 
02226                                 product_filename,
02227                                 table_header), 
02228                        "Could not write polynomial to file '%s'", 
02229                        product_filename);
02230                 current_linetable_extension += 1;
02231 
02232                 uves_msg("Line table for trace %d, window #%d "
02233                      "saved to extensions %d-%d of '%s'",
02234                      trace_number, window, 
02235                      current_linetable_extension - 3,
02236                      current_linetable_extension - 1, 
02237                      product_filename);
02238 
02239                 } /* for each window */
02240             } /* if trace enabled */
02241         } /* for each trace */
02242 
02243       if(strcmp(PROCESS_CHIP,"redl") == 0) {
02244     chip = uves_chip_get_next(chip);
02245       }
02246 
02247 
02248     }/* For each chip */
02249 
02250   cleanup:
02251     /* Input */
02252     uves_free_image(&arclamp[0]);
02253     uves_free_image(&arclamp[1]);
02254     uves_free_image(&arclamp_noise);
02255     uves_free_image(&absorder_image);
02256     uves_free_propertylist(&arclamp_header[0]);
02257     uves_free_propertylist(&arclamp_header[1]);
02258     uves_free_propertylist(&rotated_header[0]);
02259     uves_free_propertylist(&rotated_header[1]);
02260 
02261     uves_free_table(&ordertable);
02262     uves_free_propertylist(&ordertable_header);
02263     uves_free_table(&corvel);
02264     uves_free_propertylist(&corvel_header);
02265     uves_polynomial_delete(&order_locations);
02266     uves_polynomial_delete(&absolute_order);
02267     uves_free_table(&traces);
02268     
02269     uves_free_image(&master_bias);
02270     uves_free_propertylist(&master_bias_header);
02271     uves_free_image(&master_flat);
02272     uves_free_image(&mflat_noise);
02273     uves_free_propertylist(&master_flat_header);
02274     uves_free_image(&weights);
02275     
02276     /* DRS not used
02277        uves_free_table(&drs_table);
02278        uves_free_propertylist(&drs_header);
02279     */
02280     
02281     uves_free_table(&guess);
02282 
02283     uves_free_table(&line_refer);
02284     uves_free_table(&line_intmon);
02285 
02286     /* Output */
02287     uves_lt_delete(&linetable);
02288     uves_free_propertylist(&primary_header);
02289     uves_free_propertylist(&table_header);
02290     uves_qclog_delete(&qclog[0]);
02291     uves_qclog_delete(&qclog[1]);
02292 
02293     cpl_free(product_filename);
02294     cpl_free(temp);
02295     
02296     return;
02297 }
02298 
02299 
02312 static void uves_wavecal_qclog(const cpl_table* linetable,
02313                                int firstabs,
02314                                int lastabs,
02315                    const cpl_image *arclamp,
02316                    const uves_propertylist* raw_header,
02317                    bool flames,
02318                    int trace_number,
02319                    int fibre_mask,
02320                    double offset,
02321                    enum uves_chip chip,
02322                    cpl_table* qclog)
02323 {
02324 
02325     const char *qc_fib_drsno_name= uves_qclog_get_qc_name("DRSNO", flames, trace_number);
02326     const char *qc_fib_seq_name  = uves_qclog_get_qc_name("SEQ", flames, trace_number);
02327     const char *qc_fib_pos_name  = uves_qclog_get_qc_name("POS", flames, trace_number);
02328     const char *qc_fib_msk_name  = uves_qclog_get_qc_name("MSK", flames, trace_number);
02329     const char *qc_fwhmavg_name  = uves_qclog_get_qc_name("FWHMAVG", flames, trace_number);
02330     const char *qc_fwhmrms_name  = uves_qclog_get_qc_name("FWHMRMS", flames, trace_number);
02331     const char *qc_fwhmmed_name  = uves_qclog_get_qc_name("FWHMMED", flames, trace_number);
02332     const char *qc_resolavg_name = uves_qclog_get_qc_name("RESOLAVG", flames, trace_number);
02333     const char *qc_resolrms_name = uves_qclog_get_qc_name("RESOLRMS", flames, trace_number);
02334     const char *qc_resolmed_name = uves_qclog_get_qc_name("RESOLMED", flames, trace_number);
02335     const char *qc_wlenmin_name  = uves_qclog_get_qc_name("WLENMIN", flames, trace_number);
02336     const char *qc_wlenmax_name  = uves_qclog_get_qc_name("WLENMAX", flames, trace_number);
02337     const char *qc_ordmin_name   = uves_qclog_get_qc_name("ORDMIN", flames, trace_number);
02338     const char *qc_ordmax_name   = uves_qclog_get_qc_name("ORDMAX", flames, trace_number);
02339     const char *qc_nlintot_name  = uves_qclog_get_qc_name("NLINTOT", flames, trace_number);
02340     const char *qc_nlinsel_name  = uves_qclog_get_qc_name("NLINSEL", flames, trace_number);
02341     const char *qc_nlinsol_name  = uves_qclog_get_qc_name("NLINSOL", flames, trace_number);
02342     const char *qc_nlinres1_name = uves_qclog_get_qc_name("NLINRES1", flames, trace_number);
02343     const char *qc_lineresidavg_name = 
02344     uves_qclog_get_qc_name("LINE RESIDAVG", flames, trace_number);
02345     const char *qc_lineresidrms_name = 
02346     uves_qclog_get_qc_name("LINE RESIDRMS", flames, trace_number);
02347 
02348     cpl_table *selected = NULL;
02349     polynomial *pol = NULL;
02350     const char *test_id = uves_sprintf("%sResolution-Test-Results", 
02351                        flames ? "Fibre-" : "");
02352 
02353     check_nomsg(uves_qclog_add_string(qclog,
02354                       "QC TEST1 ID",
02355                       test_id,
02356                       "Name of QC test",
02357                       "%s"));
02358 
02359     check_nomsg( uves_qclog_add_common_wave(raw_header, chip, qclog) );
02360 
02361     if (flames)
02362     {
02363         /* Fibre ID */
02364 //         qc1log/out 1 {LINTAB} "QC.FIB{fi}.DRSNO" {win_id} "DRS det. fibre seq. pos." 
02365         check_nomsg(uves_qclog_add_int(qclog,
02366                        qc_fib_drsno_name,
02367                        trace_number + 1,
02368                        "DRS det. fibre seq. pos.",
02369                        "%d"));
02370         
02371         /* Index */
02372 //         qc1log/out 1 {LINTAB} "QC.FIB{fi}.SEQ"  {ord_fib_seq} "det. fibre seq. no." 
02373         check_nomsg(uves_qclog_add_int(qclog,
02374                        qc_fib_seq_name,
02375                        trace_number + 1,
02376                        "det. fibre seq. no.",
02377                        "%d"));
02378 
02379 //         qc1log/out 1 {LINTAB} "QC.FIB{fi}.POS"  {ord_fib_pos} "det. fibre seq. rel. pos." 
02380         check_nomsg(uves_qclog_add_double(qclog,
02381                           qc_fib_pos_name,
02382                           offset,
02383                           "det. fibre seq. rel. pos.",
02384                           "%.4f"));
02385 
02386 
02387         //qc1log/out 1 {LINTAB} "QC.FIB{fi}.MSK"  {fib_msk({win_id})} "DRS det. fibre mask value" 
02388         check_nomsg(uves_qclog_add_int(qclog,
02389                        qc_fib_msk_name,
02390                        fibre_mask,
02391                        "DRS det. fibre mask value",
02392                        "%d"));
02393 
02394         {
02395 
02396 /*
02397   tot_int = outputr(7)
02398   exp_time = {{wlc},{h_dit1}}
02399   rel_int = tot_int / exp_time
02400   qc1log/out 1 {LINTAB} "QC.FIB.ABSTRANS"     {rel_int}   "abs. trans. countrate"    
02401 */
02402         double exptime;
02403       
02404         check( exptime = uves_flames_pfits_get_dit(raw_header),
02405                "Error reading exposure time");
02406       
02407         check_nomsg(uves_qclog_add_double(qclog,
02408                           "QC FIB ABSTRANS",
02409                           cpl_image_get_flux(arclamp) / exptime,
02410                           "abs. trans. countrate",
02411                           "%.4f"));
02412         }
02413 //        qc1log/out 1 {LINTAB} "QC.NHOTPIX"          {n_hpix}   "no. of hot pixels"   
02414         {
02415         int n_hpix;
02416         int x, y;
02417       
02418         n_hpix = 0;
02419         for (y = 1; y <= cpl_image_get_size_y(arclamp); y++)
02420             for (x = 1; x <= cpl_image_get_size_x(arclamp); x++)
02421             {
02422                 int pis_rejected;
02423                 int value = cpl_image_get(arclamp, x, y, &pis_rejected);
02424           
02425                 if (!pis_rejected &&
02426                 (value < DRS_PTHRES_MIN || value > DRS_PTHRES_MAX))
02427                 {
02428                     n_hpix += 1;
02429                 }
02430             }
02431 
02432         check_nomsg(uves_qclog_add_int(qclog,
02433                            "QC NHOTPIX",
02434                            n_hpix,
02435                            "no. of hot pixels",
02436                            "%d"));
02437       
02438         }
02439   
02440         {
02441         int plate_id;
02442       
02443         //qc1log/out 1 {LINTAB} "QC.PLATENO"          {plate_no} "Plate Id."
02444         check( plate_id = uves_flames_pfits_get_plateid(raw_header),
02445                "Error reading plate ID");
02446         check_nomsg(uves_qclog_add_int(qclog,
02447                            "QC PLATENO",
02448                            plate_id,
02449                            "Plate Id.",
02450                            "%d"));
02451         }
02452 
02453     } /* if flames */
02454 
02455     /* FLAMES + UVES common QC params */
02456 
02457     selected = uves_extract_table_rows(linetable, "NLinSol", CPL_NOT_EQUAL_TO, 0);
02458    
02459     /* FWHM in pixels */
02460     check_nomsg(uves_qclog_add_double(qclog,
02461                       qc_fwhmavg_name,
02462                       cpl_table_get_column_mean(selected,"Xwidth")*TWOSQRT2LN2,
02463                       "average FWHM in X of lines selected",
02464                       "%.2f"));
02465 
02466     check_nomsg(uves_qclog_add_double(qclog,
02467                       qc_fwhmrms_name,
02468                       cpl_table_get_column_stdev(selected,"Xwidth")*TWOSQRT2LN2,
02469                       "stdev FWHM in X of lines selected",
02470                       "%.4f"));
02471 
02472     check_nomsg(uves_qclog_add_double(qclog,
02473                       qc_fwhmmed_name,
02474                       cpl_table_get_column_median(selected,"Xwidth")*TWOSQRT2LN2,
02475                       "median FWHM in X of lines selected",
02476                       "%.4f"));
02477 
02478     check_nomsg(uves_qclog_add_double(qclog,
02479                       qc_resolavg_name,
02480                       cpl_table_get_column_mean(selected,"Resol"),
02481                       "average resolving power of lines selected",
02482                       "%.4f"));
02483 
02484     check_nomsg(uves_qclog_add_double(qclog,
02485                       qc_resolrms_name,
02486                       cpl_table_get_column_stdev(selected,"Resol"),
02487                       "stdev resolving power of lines selected",
02488                       "%.4f"));
02489 
02490     check_nomsg(uves_qclog_add_double(qclog,
02491                       qc_resolmed_name,
02492                       cpl_table_get_column_median(selected,"Resol"),
02493                       "median resolving power of lines selected",
02494                       "%.4f"));
02495 
02496     /* Convert A -> picometers */
02497     check_nomsg(uves_qclog_add_double(qclog,
02498                       qc_lineresidavg_name,
02499                       cpl_table_get_column_mean(selected, LINETAB_RESIDUAL)*100,
02500                       "mean resid of line pos to fit",
02501                       "%.4f"));
02502 
02503     check_nomsg(uves_qclog_add_double(qclog,
02504                       qc_lineresidrms_name,
02505                       cpl_table_get_column_stdev(selected, LINETAB_RESIDUAL)*100,
02506                       "sigma resid of line pos to fit",
02507                       "%.4f"));
02508 
02509     /* Convert A -> nm */
02510     check_nomsg(uves_qclog_add_double(qclog,
02511                       qc_wlenmin_name,
02512                       cpl_table_get_column_min(linetable,LINETAB_LAMBDAC)/10.0,
02513                       "minimum wavelength",
02514                       "%.4f"));
02515 
02516     check_nomsg(uves_qclog_add_double(qclog,
02517                       qc_wlenmax_name,
02518                       cpl_table_get_column_max(linetable,LINETAB_LAMBDAC)/10.0,
02519                       "maximum wavelength",
02520                       "%.4f"));
02521 
02522     check_nomsg(uves_qclog_add_int(qclog,
02523                    qc_ordmin_name,
02524                    uves_min_int(firstabs, lastabs),
02525                    "minimum order number detected",
02526                    "%d"));
02527 
02528     check_nomsg(uves_qclog_add_int(qclog,
02529                    qc_ordmax_name,
02530                    uves_max_int(firstabs, lastabs),
02531                    "maximum order number detected",
02532                    "%d"));
02533 
02534     check_nomsg(uves_qclog_add_int(qclog,
02535                    qc_nlintot_name,
02536                    cpl_table_get_nrow(linetable),
02537                    "No of lines found",
02538                    "%d"));
02539 
02540     check_nomsg(uves_qclog_add_int(qclog,
02541                    qc_nlinsel_name,
02542                    cpl_table_get_nrow(linetable) -
02543                                    cpl_table_count_invalid(linetable, "Ident"),
02544                    "No of lines selected",
02545                    "%d"));
02546 
02547     check_nomsg(uves_qclog_add_int(qclog,
02548                    qc_nlinsol_name,
02549                    cpl_table_get_nrow(selected),
02550                    "No of lines used",
02551                    "%d"));
02552 
02553     uves_free_table(&selected);
02554     selected = cpl_table_duplicate(linetable);
02555     assure_mem( selected );
02556 
02557     /* Remove unidentified lines and
02558        lines with residual > 1 A      */
02559     check_nomsg( uves_erase_invalid_table_rows(selected, "Ident") );
02560     check_nomsg( uves_erase_table_rows(selected, LINETAB_RESIDUAL, 
02561                        CPL_NOT_LESS_THAN,
02562                        1.0) );
02563   
02564     check_nomsg(uves_qclog_add_int(qclog,
02565                    qc_nlinres1_name,
02566                    cpl_table_get_nrow(selected),
02567                    "No of lines with residuals < 0.1 nm",
02568                    "%d"));
02569 
02570 
02571   cleanup:
02572     uves_free_string_const(&qc_fib_drsno_name);
02573     uves_free_string_const(&qc_fib_seq_name);
02574     uves_free_string_const(&qc_fib_pos_name);
02575     uves_free_string_const(&qc_fib_msk_name);
02576 
02577     uves_free_string_const(&test_id);
02578     uves_free_string_const(&qc_fwhmavg_name);
02579     uves_free_string_const(&qc_fwhmrms_name);
02580     uves_free_string_const(&qc_fwhmmed_name);
02581 
02582     uves_free_string_const(&qc_resolavg_name);
02583     uves_free_string_const(&qc_resolrms_name);
02584     uves_free_string_const(&qc_resolmed_name);
02585     uves_free_string_const(&qc_wlenmin_name);
02586     uves_free_string_const(&qc_wlenmax_name);
02587     uves_free_string_const(&qc_ordmin_name);
02588     uves_free_string_const(&qc_ordmax_name);
02589     uves_free_string_const(&qc_nlintot_name);
02590     uves_free_string_const(&qc_nlinsel_name);
02591     uves_free_string_const(&qc_nlinsol_name);
02592     uves_free_string_const(&qc_nlinres1_name);
02593     uves_free_string_const(&qc_lineresidavg_name);
02594     uves_free_string_const(&qc_lineresidrms_name);
02595 
02596     uves_free_table(&selected);
02597     uves_polynomial_delete(&pol);
02598     return;
02599  
02600 }
02601 
02610 static void uves_wavecal_qclog_intmon(cpl_table* table,
02611                       const cpl_table *line_intmon,
02612                       const uves_propertylist* raw_header,
02613                       bool flames,
02614                       int fibre,
02615                       enum uves_chip chip,
02616                       cpl_table* qclog)
02617 {
02618     const char *qc_intavg_name = NULL;
02619     const char *qc_nlinint_name = NULL;
02620 
02621     cpl_table *temp = NULL;
02622         
02623     check_nomsg(uves_qclog_add_string(qclog,
02624                                       "QC TEST2 ID",
02625                                       flames ? "Fibre-Line-Intensity-Test-Results"
02626                                       : "Line-Intensity-Test-Results",
02627                                       "Name of QC test",
02628                                       "%s"));
02629 
02630     check_nomsg( uves_qclog_add_common_wave(raw_header,
02631                                             chip, qclog) );
02632 
02633     {
02634     double tolerance = 0.001; /* (A) 
02635                      The lines in the line table
02636                      and intmon table are considered
02637                      identical if the difference
02638                      is less than this number.
02639                   */
02640                       
02641     double exptime;
02642 
02643     int N_bright = cpl_table_get_nrow(line_intmon);
02644     int i;
02645 
02646     check( exptime = uves_pfits_get_exptime(raw_header),
02647            "Could not get exposure time");
02648     
02649     cpl_table_new_column(table, "Intensity", CPL_TYPE_DOUBLE); 
02650     for (i = 0; i < cpl_table_get_nrow(table); i++)
02651     {
02652         int is_null;
02653         double ident = cpl_table_get_double(table, "Ident", i, &is_null);
02654 
02655         if (!is_null)
02656         {
02657             int bright_index = uves_wavecal_find_nearest(
02658             line_intmon, ident, 0, N_bright-1);
02659 
02660             double bright = cpl_table_get_double(
02661             line_intmon, "Wave", bright_index, NULL);
02662 
02663             if (fabs(bright - ident) < tolerance)
02664             {
02665                 double peak = cpl_table_get_double(table, "Peak", i, NULL);
02666                 double pixelsize = 
02667                 fabs(cpl_table_get_double(table, LINETAB_PIXELSIZE, i, NULL));
02668 
02669                 double lambda_fwhm = cpl_table_get_double(table, "Xwidth", i, NULL)
02670                 * TWOSQRT2LN2 * pixelsize;
02671                 /* Line FWHM in wlu */
02672 
02673                 double intensity = peak * lambda_fwhm / exptime;
02674                 /* Same formula as in MIDAS */
02675 
02676                 cpl_table_set_double(table, "Intensity", i, intensity);
02677             }
02678             else
02679             {
02680                 cpl_table_set_invalid(table, "Intensity", i);
02681             }
02682         }
02683         else
02684         {
02685             cpl_table_set_invalid(table, "Intensity", i);
02686         }
02687     }
02688     }
02689 
02690     uves_free_table(&temp);
02691     temp = cpl_table_duplicate(table);
02692     uves_erase_invalid_table_rows(temp, "Intensity");
02693 
02694     {
02695     double mean;
02696     if (cpl_table_get_nrow(temp) == 0)
02697         {
02698         uves_msg_warning("No bright lines found!");
02699         mean = 0;
02700         }
02701     else
02702         {
02703         mean = cpl_table_get_column_mean(temp, "Intensity");
02704         }
02705 
02706     if (flames)
02707         {
02708         qc_intavg_name  = uves_sprintf("QC FIB%d INTAVG", fibre+1); /* Count 1-9 */
02709         qc_nlinint_name = uves_sprintf("QC FIB%d NLININT", fibre+1);
02710         }
02711     else
02712         {
02713         qc_intavg_name  = uves_sprintf("QC INTAVG");
02714         qc_nlinint_name = uves_sprintf("QC NLININT");
02715         }
02716         
02717     check_nomsg(uves_qclog_add_double(qclog,
02718                       qc_intavg_name,
02719                       mean,
02720                       "average intensity of line list",
02721                       "%.4f"));
02722     
02723     check_nomsg(uves_qclog_add_int(qclog,
02724                        qc_nlinint_name,
02725                        cpl_table_get_nrow(temp),
02726                        "No of lines to measure INTAVG",
02727                        "%d"));
02728     }
02729 
02730  cleanup:
02731     uves_free_string_const(&qc_intavg_name);
02732     uves_free_string_const(&qc_nlinint_name);
02733   uves_free_table(&temp);
02734   return;
02735 }
02736 
02737 

Generated on Thu Nov 15 14:32:35 2007 for UVES Pipeline Reference Manual by  doxygen 1.5.1