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

Generated on Mon Apr 21 10:56:57 2008 for UVES Pipeline Reference Manual by  doxygen 1.5.1