uves_dfs.c

00001 /*
00002  * This file is part of the UVES Pipeline
00003  * Copyright (C) 2002, 2003, 2004, 2005 European Southern Observatory
00004  *
00005  * This program 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/02/27 15:01:26 $
00023  * $Revision: 1.247 $
00024  * $Name: uves-3_9_0 $
00025  * $Log: uves_dfs.c,v $
00026  * Revision 1.247  2008/02/27 15:01:26  amodigli
00027  * cleaned output
00028  *
00029  * Revision 1.246  2008/02/15 11:46:03  amodigli
00030  * fixed bug to load pipe generated INSTR_RESPONSE curve
00031  *
00032  * Revision 1.245  2008/02/05 14:09:53  amodigli
00033  * collate 2 image estension for BLUE arm 626KHz
00034  *
00035  * Revision 1.244  2008/02/05 13:51:36  amodigli
00036  * fixed compilation warnings
00037  *
00038  * Revision 1.243  2008/02/01 12:48:16  amodigli
00039  * modified load_raw_image in order to support new BLUE arm FITS FORMAT with multi estention active since 2008-01-18
00040  *
00041  * Revision 1.242  2007/12/03 16:29:55  amodigli
00042  * commented out uves_propertylist_copy_property_regexp command to copy HIERARCH ESO keywords as was screwing up the header of the rotated-cropped frame
00043  *
00044  * Revision 1.241  2007/12/03 07:59:15  amodigli
00045  * use uves_propertylist_copy_property_regexp to copy some HIERARCH keys to 'debug' product
00046  *
00047  * Revision 1.240  2007/10/30 17:45:03  jmlarsen
00048  * Added WEIGHTS_<chip> images to support object weighted arclamp extraction
00049  *
00050  * Revision 1.239  2007/10/17 14:58:59  amodigli
00051  * added uves_check_if_format_is_midas and fixed compilation warnings
00052  *
00053  * Revision 1.238  2007/10/15 06:39:13  amodigli
00054  * keep 'Fibre' column in linetable to make work flames-uves data reduction chain
00055  *
00056  * Revision 1.237  2007/10/01 17:07:49  amodigli
00057  * cleaned output
00058  *
00059  * Revision 1.236  2007/09/19 11:09:49  amodigli
00060  * Now FLAMES_FIB_FF_DT is a macro
00061  *
00062  * Revision 1.235  2007/09/12 13:11:56  amodigli
00063  * fixed bug with UVES-ech data reduction
00064  *
00065  * Revision 1.234  2007/09/11 17:08:07  amodigli
00066  * added uves_polynomial_convert_from_plist_midas from uves_utils_polynomial.h
00067  *
00068  * Revision 1.233  2007/09/06 15:48:42  amodigli
00069  * added info on old/new format
00070  *
00071  * Revision 1.232  2007/09/06 14:15:16  amodigli
00072  * changed filenames science products
00073  *
00074  * Revision 1.231  2007/08/24 06:43:37  amodigli
00075  * fixed compilation warnings
00076  *
00077  * Revision 1.230  2007/08/21 13:08:26  jmlarsen
00078  * Removed irplib_access module, largely deprecated by CPL-4
00079  *
00080  * Revision 1.229  2007/08/20 07:59:15  amodigli
00081  * update to CPL4
00082  *
00083  * Revision 1.228  2007/08/16 13:21:15  amodigli
00084  * added uves_scired_red_2d_error_filename
00085  *
00086  * Revision 1.227  2007/08/16 06:49:47  amodigli
00087  * added uves_vector_to_image
00088  *
00089  * Revision 1.226  2007/08/10 12:10:35  amodigli
00090  * changed 2d extraction product file names as by DFS04196
00091  *
00092  * Revision 1.225  2007/07/27 14:17:07  amodigli
00093  * commented out code to remove blanks (' ') from  string descriptors. Added code to check that HISTORY keywords are in group of 3 lines, 2 not empty and the last empty
00094  *
00095  * Revision 1.224  2007/07/25 10:56:23  amodigli
00096  * fixed small leak
00097  *
00098  * Revision 1.223  2007/07/25 10:52:17  amodigli
00099  * fixed problem with images with NAXIS=1 and CPL4
00100  *
00101  * Revision 1.222  2007/07/23 06:30:50  amodigli
00102  * added FLAMES_FIB_FF_DT
00103  *
00104  * Revision 1.221  2007/07/03 12:40:03  amodigli
00105  * added FLAMES_CORVEL_MASK FLAMES_SCI_SIM_RED and support for cubes FIB_FF and SLIT_FF
00106  *
00107  * Revision 1.220  2007/06/29 10:47:50  jmlarsen
00108  * load_linetable: Assume MIDAS like format if FLAMES
00109  *
00110  * Revision 1.219  2007/06/28 09:17:16  jmlarsen
00111  * Make work order table column renaming for FLAMES
00112  *
00113  * Revision 1.218  2007/06/26 14:48:11  jmlarsen
00114  * Removed unused variable
00115  *
00116  * Revision 1.217  2007/06/26 14:46:01  jmlarsen
00117  * Do not try to read dispersion polynomial when not requested
00118  *
00119  * Revision 1.216  2007/06/26 14:04:35  jmlarsen
00120  * Save with BITPIX16 for FLAMES orderpos
00121  *
00122  * Revision 1.215  2007/06/26 13:34:52  jmlarsen
00123  * Exported function for FLAMES
00124  *
00125  * Revision 1.214  2007/06/25 15:43:45  jmlarsen
00126  * uves_frameset_insert(): propagate custom keywords before, not after, calling cpl_dfs_setup_product_header
00127  *
00128  * Revision 1.213  2007/06/25 05:55:11  amodigli
00129  * added FLAMES_SCI_RED FLAMES_SCI_COM_RED to raw frames list
00130  *
00131  * Revision 1.212  2007/06/22 14:50:46  jmlarsen
00132  * Optionally save height=1 images as NAXIS=1
00133  *
00134  * Revision 1.211  2007/06/22 11:15:05  jmlarsen
00135  * uves_save_image(): Also save float images with NAXIS=1 when height is 1
00136  *
00137  * Revision 1.210  2007/06/22 09:30:08  jmlarsen
00138  * Allow saving CPL_TYPE_INT images as 16 or 32 bit FITS
00139  *
00140  * Revision 1.209  2007/06/20 15:49:05  jmlarsen
00141  * Enabled check for NULL polynoimal
00142  *
00143  * Revision 1.208  2007/06/20 13:05:17  amodigli
00144  * commented assure not to make fail a test case
00145  *
00146  * Revision 1.207  2007/06/20 08:32:52  amodigli
00147  * updated uves_load_linetable to support FIBER mode
00148  *
00149  * Revision 1.206  2007/06/06 08:17:33  amodigli
00150  * replace tab with 4 spaces
00151  *
00152  * Revision 1.205  2007/05/23 12:50:53  jmlarsen
00153  * Replace isnan/isinf -> irplib_isnan/irplib_isinf
00154  *
00155  * Revision 1.204  2007/05/16 14:56:27  jmlarsen
00156  * Fixed error message
00157  *
00158  * Revision 1.203  2007/05/16 11:47:18  amodigli
00159  * added FLAMES_SCI_COM_RED
00160  *
00161  * Revision 1.202  2007/05/04 08:55:15  amodigli
00162  * moved up declaration of img to suppress compilation warning
00163  *
00164  * Revision 1.201  2007/05/03 15:19:10  jmlarsen
00165  * Added const version of uves_load_linetable()
00166  *
00167  * Revision 1.200  2007/05/02 13:36:14  jmlarsen
00168  * Decreased verbosity of debug message
00169  *
00170  * Revision 1.199  2007/05/02 13:16:30  jmlarsen
00171  * Fixed error message typo
00172  *
00173  * Revision 1.198  2007/04/26 13:19:11  jmlarsen
00174  * Exported function copy_if_possible
00175  *
00176  * Revision 1.197  2007/04/24 16:44:26  amodigli
00177  * changed interface uves_load_ordertable to return also extention table
00178  *
00179  * Revision 1.196  2007/04/24 12:50:29  jmlarsen
00180  * Replaced cpl_propertylist -> uves_propertylist which is much faster
00181  *
00182  * Revision 1.195  2007/04/23 06:59:29  amodigli
00183  * added uves_save_imagelist
00184  *
00185  * Revision 1.194  2007/04/12 12:15:12  jmlarsen
00186  * Propagate keyword OS-EXPOI
00187  *
00188  * Revision 1.193  2007/04/12 11:58:46  jmlarsen
00189  * Rename order table column if necessary
00190  *
00191  * Revision 1.192  2007/04/10 07:06:59  jmlarsen
00192  * Take into account 64 pixel gap in REDU CRVAL2 computation
00193  *
00194  * Revision 1.191  2007/04/04 06:27:06  jmlarsen
00195  * Fixed malloc -> cpl_malloc
00196  *
00197  * Revision 1.190  2007/04/03 11:02:25  jmlarsen
00198  * Support reading float MIDAS arrays
00199  *
00200  * Revision 1.189  2007/04/03 08:03:59  jmlarsen
00201  * uves_read_midas_array: support arrays of any length
00202  *
00203  * Revision 1.188  2007/04/03 06:28:45  amodigli
00204  * uves_load_ordertable provides now fibre_mask and fibre_pos if appropriate
00205  *
00206  * Revision 1.187  2007/03/30 07:06:59  jmlarsen
00207  * Initialize variables to suppress warnings
00208  *
00209  * Revision 1.186  2007/03/23 07:59:30  jmlarsen
00210  * Fixed minor memory leak
00211  *
00212  * Revision 1.185  2007/03/20 15:39:46  amodigli
00213  * added FLAMES tags
00214  *
00215  * Revision 1.184  2007/03/20 07:26:57  jmlarsen
00216  * Don't remove std star from flux table which has NULL type
00217  *
00218  * Revision 1.183  2007/03/15 15:04:34  jmlarsen
00219  * Allow spaces in HISTORY keyword string values
00220  *
00221  * Revision 1.182  2007/03/05 10:16:12  jmlarsen
00222  * Define 'dWave' as constant
00223  *
00224  * Revision 1.181  2007/02/27 14:04:35  jmlarsen
00225  * Added comment
00226  *
00227  * Revision 1.180  2007/02/26 13:27:53  jmlarsen
00228  * Partial workaround for slow uves_propertylist_copy_property_regexp()
00229  *
00230  * Revision 1.179  2007/02/22 15:33:24  jmlarsen
00231  * Redefine catalogue wavelength uncertainties to better match new catalogue
00232  *
00233  * Revision 1.178  2007/02/14 14:06:34  jmlarsen
00234  * Use REF_TFLAT, not MASTER_TFLAT as master
00235  *
00236  * Revision 1.177  2007/02/12 10:09:33  jmlarsen
00237  * Fixed recently introduced bug that REDL image was loaded twice, instead of REDL + REDU
00238  *
00239  * Revision 1.176  2007/02/09 13:36:04  jmlarsen
00240  * Added function to load ref_flat
00241  *
00242  * Revision 1.175  2007/02/09 08:51:06  jmlarsen
00243  * Use define's rather than hard-coded recipe names
00244  *
00245  * Revision 1.174  2007/02/09 08:03:08  jmlarsen
00246  * Changed definition of CRVAL in products
00247  *
00248  * Revision 1.173  2007/02/08 07:33:01  jmlarsen
00249  * Added uves_load_cd_align(), changed CRVAL computation
00250  *
00251  * Revision 1.172  2007/02/01 07:23:44  jmlarsen
00252  * Removed debugging code
00253  *
00254  * Revision 1.171  2007/01/31 15:18:52  jmlarsen
00255  * Write +- FLT_MAX to FITS file if double value out of range
00256  *
00257  * Revision 1.170  2007/01/31 15:10:34  jmlarsen
00258  * Avoid inf+nan when saving FITS files
00259  *
00260  * Revision 1.169  2007/01/17 13:25:39  jmlarsen
00261  * Added uves_load_image()
00262  *
00263  * Revision 1.168  2007/01/16 10:27:30  jmlarsen
00264  * Implemented self-consistent propagation of FITS geometry keywords
00265  *
00266  * Revision 1.167  2007/01/15 08:45:27  jmlarsen
00267  * Added comment
00268  *
00269  * Revision 1.166  2007/01/10 12:37:16  jmlarsen
00270  * Exported function to warn about mismatching calibration frames
00271  *
00272  * Revision 1.165  2007/01/09 17:45:42  amodigli
00273  * added uves_check_rec_status
00274  *
00275  * Revision 1.164  2006/12/12 12:09:14  jmlarsen
00276  * Added function to load corvel table
00277  *
00278  * Revision 1.163  2006/12/11 12:34:01  jmlarsen
00279  * Use date to determine new/old format
00280  *
00281  * Revision 1.162  2006/12/07 08:22:59  jmlarsen
00282  * uves_load_raw_imagelist: support FLAMES
00283  *
00284  * Revision 1.161  2006/12/01 08:26:56  jmlarsen
00285  * Load FLAMES order table oshift/yshift
00286  *
00287  * Revision 1.160  2006/11/24 16:21:07  jmlarsen
00288  * Added FIB_LINE_TABLE_x
00289  *
00290  * Revision 1.159  2006/11/24 11:10:14  jmlarsen
00291  * Support for loading FLAMES guess line table
00292  *
00293  * Revision 1.158  2006/11/24 09:35:40  jmlarsen
00294  * Workaround for slow uves_propertylist_get_size
00295  *
00296  * Revision 1.157  2006/11/23 10:04:11  jmlarsen
00297  * Minor message change
00298  *
00299  * Revision 1.156  2006/11/22 08:39:55  jmlarsen
00300  * Exported and fixed bug in uves_read_midas_array
00301  *
00302  * Revision 1.154  2006/11/22 08:22:29  jmlarsen
00303  * Set message level according to preprocessor symbol
00304  *
00305  * Revision 1.153  2006/11/16 14:08:33  jmlarsen
00306  * Implemented loading FLAMES ordertable
00307  *
00308  * Revision 1.152  2006/11/16 09:51:13  jmlarsen
00309  * Use compile time branching to support both released and development CPL versions
00310  *
00311  * Revision 1.151  2006/11/16 08:32:03  jmlarsen
00312  * Save CPL_TYPE_INT images as 16 bit unsigned, to support flames_cal_orderpos
00313  *
00314  * Revision 1.150  2006/11/15 15:02:14  jmlarsen
00315  * Implemented const safe workarounds for CPL functions
00316  *
00317  * Revision 1.148  2006/11/15 14:04:08  jmlarsen
00318  * Removed non-const version of parameterlist_get_first/last/next which is already 
00319  * in CPL, added const-safe wrapper, unwrapper and deallocator functions
00320  *
00321  * Revision 1.147  2006/11/13 14:23:55  jmlarsen
00322  * Removed workarounds for CPL const bugs
00323  *
00324  * Revision 1.146  2006/11/13 12:44:31  jmlarsen
00325  * Support FLAMES FIB_ARC_LAMP_RED frames
00326  *
00327  * Revision 1.145  2006/11/08 14:03:31  jmlarsen
00328  * Fixed doc bug when warning about deprecated background table
00329  *
00330  * Revision 1.144  2006/11/08 08:03:26  jmlarsen
00331  * Avoid initializers not computable at compile time, for portability
00332  *
00333  * Revision 1.143  2006/11/07 14:01:10  jmlarsen
00334  * Moved flames_load_ functions to separate source file
00335  *
00336  * Revision 1.142  2006/11/06 15:19:41  jmlarsen
00337  * Removed unused include directives
00338  *
00339  * Revision 1.141  2006/11/03 15:01:21  jmlarsen
00340  * Killed UVES 3d table module and use CPL 3d tables
00341  *
00342  * Revision 1.140  2006/10/26 14:02:41  jmlarsen
00343  * Removed redundant goto
00344  *
00345  * Revision 1.139  2006/10/24 14:05:23  jmlarsen
00346  * Generalized load functions to support FLAMES
00347  *
00348  * Revision 1.138  2006/10/19 13:53:25  jmlarsen
00349  * Changed guess line table tag to LINE_GUESS_TAB
00350  *
00351  * Revision 1.137  2006/10/12 11:37:28  jmlarsen
00352  * Temporarily disabled FLAMES code generation
00353  *
00354  * Revision 1.136  2006/10/10 11:29:24  jmlarsen
00355  * Added code to propagate TM-START
00356  *
00357  * Revision 1.135  2006/10/10 11:20:47  jmlarsen
00358  * Renamed line table columns to match MIDAS
00359  *
00360  * Revision 1.134  2006/10/05 11:14:59  jmlarsen
00361  * Removed debugging code
00362  *
00363  * Revision 1.133  2006/10/02 08:34:04  jmlarsen
00364  * Added REF_TFLAT
00365  *
00366  * Revision 1.132  2006/09/27 13:13:26  jmlarsen
00367  * Use dynamic memory allocation to store bad pixels
00368  *
00369  * Revision 1.131  2006/09/20 15:42:17  jmlarsen
00370  * Implemented MASTER_RESPONSE support
00371  *
00372  * Revision 1.130  2006/09/20 10:56:50  jmlarsen
00373  * Propagate DATAMEAN/DATAMED/DATARMS if present
00374  *
00375  * Revision 1.129  2006/09/19 14:25:30  jmlarsen
00376  * Propagate FITS keywords from master flat, not science, to WCALIB_FLAT_OBJ
00377  *
00378  * Revision 1.128  2006/09/19 06:55:06  jmlarsen
00379  * Changed interface of uves_frameset to optionally write image statistics kewwords
00380  *
00381  * Revision 1.127  2006/09/14 08:46:51  jmlarsen
00382  * Added support for TFLAT, SCREEN_FLAT frames
00383  *
00384  * Revision 1.126  2006/09/08 14:04:41  jmlarsen
00385  * Documentation update
00386  *
00387  * Revision 1.125  2006/08/31 07:24:57  jmlarsen
00388  * Fixed buffer overruns happening when raw frames are not available
00389  *
00390  * Revision 1.124  2006/08/24 11:36:56  jmlarsen
00391  * Write recipe start/stop time to header
00392  *
00393  * Revision 1.123  2006/08/23 09:33:03  jmlarsen
00394  * Renamed local variables shadowing POSIX reserved names
00395  *
00396  * Revision 1.122  2006/08/21 07:53:17  jmlarsen
00397  * Added debug message
00398  *
00399  * Revision 1.121  2006/08/18 13:32:13  jmlarsen
00400  * Use legal FITS keywords for TRACEID/WINDOW/FABSORD/LABSORD
00401  *
00402  * Revision 1.120  2006/08/18 07:07:43  jmlarsen
00403  * Switched order of cpl_calloc arguments
00404  *
00405  * Revision 1.119  2006/08/17 14:11:25  jmlarsen
00406  * Use assure_mem macro to check for memory allocation failure
00407  *
00408  * Revision 1.118  2006/08/17 13:56:52  jmlarsen
00409  * Reduced max line length
00410  *
00411  * Revision 1.117  2006/08/17 13:04:10  jmlarsen
00412  * Reduced max line length
00413  *
00414  * Revision 1.116  2006/08/17 09:17:15  jmlarsen
00415  * Removed CPL2 code
00416  *
00417  * Revision 1.115  2006/08/11 14:56:05  amodigli
00418  * removed Doxygen warnings
00419  *
00420  * Revision 1.114  2006/08/11 11:26:59  jmlarsen
00421  * Change text message
00422  *
00423  * Revision 1.113  2006/08/11 08:59:07  jmlarsen
00424  * Take into account the different meanings of line table 'Y' column
00425  *
00426  * Revision 1.112  2006/08/08 12:55:00  jmlarsen
00427  * Support uppercase column names when loading linetable
00428  *
00429  * Revision 1.111  2006/08/08 11:27:18  amodigli
00430  * upgrade to CPL3
00431  *
00432  * Revision 1.110  2006/08/07 14:42:02  jmlarsen
00433  * Implemented on-the-fly correction of a line table when its 
00434  * order numbering is inconsistent with the order table (DFS02694)
00435  *
00436  * Revision 1.109  2006/08/07 12:14:13  jmlarsen
00437  * Removed unused code
00438  *
00439  * Revision 1.108  2006/08/01 14:43:36  amodigli
00440  * fixed bug loading fitsheader in uves_load_masterformatcheck
00441  *
00442  * Revision 1.107  2006/07/31 06:29:05  amodigli
00443  * added flames_load_frame_index
00444  *
00445  * Revision 1.106  2006/07/14 12:19:28  jmlarsen
00446  * Support multiple QC tests per product
00447  *
00448  * Revision 1.105  2006/07/03 12:59:14  jmlarsen
00449  * Changed message to debug level
00450  *
00451  * Revision 1.104  2006/06/29 07:57:21  amodigli
00452  * fixed warning messages from make html
00453  *
00454  * Revision 1.103  2006/06/29 07:32:05  amodigli
00455  * removed warning from make html
00456  *
00457  * Revision 1.102  2006/06/28 13:27:50  amodigli
00458  * Fixed problem dumping ARCFILE key changing uves_save_paf interface
00459  *
00460  * Revision 1.101  2006/06/26 07:54:14  amodigli
00461  * flames_load_image flames_load_table
00462  *
00463  * Revision 1.100  2006/06/23 15:31:32  amodigli
00464  * added useful stuff for flames
00465  *
00466  * Revision 1.99  2006/06/22 15:25:35  amodigli
00467  * changes for flames_cal_prep_sff_ofpos
00468  *
00469  * Revision 1.98  2006/06/22 12:03:56  amodigli
00470  * clean msg warning
00471  *
00472  * Revision 1.97  2006/06/22 09:42:56  jmlarsen
00473  * Removed syntax error
00474  *
00475  * Revision 1.96  2006/06/22 08:57:38  jmlarsen
00476  * Changed a few messages
00477  *
00478  * Revision 1.95  2006/06/22 06:42:38  amodigli
00479  * fixed some compilation warnings
00480  *
00481  * Revision 1.94  2006/06/20 08:25:56  amodigli
00482  * fixed doxigen warnings
00483  *
00484  * Revision 1.93  2006/06/19 06:51:14  amodigli
00485  * added support flames-old format
00486  *
00487  * Revision 1.92  2006/06/16 08:22:01  jmlarsen
00488  * Manually propagate ESO.DET. keywords from 1st/2nd input header
00489  *
00490  * Revision 1.91  2006/06/13 11:55:06  jmlarsen
00491  * Shortened max line length
00492  *
00493  * Revision 1.90  2006/06/05 08:51:55  amodigli
00494  * cleaned some warnings from static checks
00495  *
00496  * Revision 1.89  2006/06/01 14:43:17  jmlarsen
00497  * Added missing documentation
00498  *
00499  * Revision 1.88  2006/06/01 14:21:02  amodigli
00500  * frm --> frm_tmp, dup --> frm_dup
00501  *
00502  * Revision 1.87  2006/05/31 09:51:01  amodigli
00503  * removed compilation warning
00504  *
00505  * Revision 1.86  2006/05/22 06:47:15  amodigli
00506  * fixed some bugs on msflat
00507  *
00508  * Revision 1.85  2006/05/19 13:07:52  amodigli
00509  * modified to support SFLATs
00510  *
00511  * Revision 1.84  2006/05/17 09:54:55  amodigli
00512  * added supposr SFLATs
00513  *
00514  * Revision 1.82  2006/05/15 06:09:52  amodigli
00515  * added support for some FLAMES input frames
00516  *
00517  * Revision 1.81  2006/05/12 15:01:30  jmlarsen
00518  * Changed msg level warning -> debug when there's no QC log
00519  *
00520  * Revision 1.80  2006/04/25 14:58:48  amodigli
00521  * added paf creation functionalities
00522  *
00523  * Revision 1.79  2006/04/24 09:18:06  jmlarsen
00524  * Minor message change
00525  *
00526  * Revision 1.78  2006/04/20 10:48:20  amodigli
00527  * inform that no QC log is provided
00528  *
00529  * Revision 1.77  2006/04/10 12:35:42  jmlarsen
00530  * Simplified the save-product function
00531  *
00532  * Revision 1.76  2006/04/06 13:12:54  jmlarsen
00533  * Fixed doc. bug
00534  *
00535  * Revision 1.75  2006/04/06 12:56:50  jmlarsen
00536  * Added support for PDARK, IFLAT, DLFAT frames
00537  *
00538  * Revision 1.74  2006/04/06 11:48:17  jmlarsen
00539  * Support for SCI_POINT_-, SCI_EXTND_- and SCI_SLICER-frames
00540  *
00541  * Revision 1.73  2006/04/06 09:48:15  amodigli
00542  * changed uves_frameset_insert interface to have QC log
00543  *
00544  * Revision 1.72  2006/04/06 08:31:15  jmlarsen
00545  * Added support for reading MASTER_DFLAT, MASTER_IFLAT, MASTER_PDARK
00546  *
00547  * Revision 1.71  2006/03/24 14:24:29  jmlarsen
00548  * Don't blindly stack flat-fields of different wavelenghts
00549  *
00550  * Revision 1.70  2006/03/09 10:51:58  jmlarsen
00551  * Added timing info
00552  *
00553  * Revision 1.69  2006/03/06 09:22:43  jmlarsen
00554  * Added support for reading MIDAS line tables with MIDAS tags
00555  *
00556  * Revision 1.68  2006/03/03 13:54:11  jmlarsen
00557  * Changed syntax of check macro
00558  *
00559  * Revision 1.67  2006/02/15 13:19:15  jmlarsen
00560  * Reduced source code max. line length
00561  *
00562  * Revision 1.66  2006/01/17 10:14:20  jmlarsen
00563  * Changed order of functions
00564  *
00565  * Revision 1.65  2006/01/16 07:10:53  amodigli
00566  *
00567  * Clean
00568  *
00569  * Revision 1.64  2006/01/09 15:22:53  jmlarsen
00570  * Removed some warnings
00571  *
00572  * Revision 1.63  2006/01/09 14:05:21  amodigli
00573  * Fixed doxigen warnings
00574  *
00575  * Revision 1.62  2006/01/03 16:56:53  amodigli
00576  * Added MASTER_ARC_FORM
00577  *
00578  * Revision 1.61  2005/12/19 16:17:56  jmlarsen
00579  * Replaced bool -> int
00580  *
00581  */
00582 
00583 #ifdef HAVE_CONFIG_H
00584 #include <config.h>
00585 #endif
00586 
00587 /*----------------------------------------------------------------------------*/
00594 /*----------------------------------------------------------------------------*/
00595 
00596 /*-----------------------------------------------------------------------------
00597                                    Includes
00598  -----------------------------------------------------------------------------*/
00599 
00600 #include <uves_dfs.h>
00601 
00602 #include <uves_utils.h>
00603 #include <uves_wavecal_utils.h>
00604 #include <uves_pfits.h>
00605 #include <uves_dump.h>
00606 #include <uves_qclog.h>
00607 #include <uves.h>
00608 #include <uves_utils_wrappers.h>
00609 #include <uves_error.h>
00610 #include <uves_msg.h>
00611 
00612 #include <irplib_utils.h>
00613 
00614 #include <cpl.h>
00615 
00616 #include <qfits.h> /* iso time */
00617 
00618 #include <float.h>
00619 
00620 /*-----------------------------------------------------------------------------
00621                                    Defines
00622  -----------------------------------------------------------------------------*/
00623 
00624 #define DICTIONARY "PRO-1.15"
00625 /*-----------------------------------------------------------------------------
00626                                    Prototypes
00627  -----------------------------------------------------------------------------*/
00628 
00629 static polynomial *load_polynomial(const char* filename, int extension);
00630 static char *uves_local_filename(const char *prefix, enum uves_chip chip, int trace, int window);
00631 static char *int_to_string(int i);
00632 
00633 static cpl_error_code
00634 load_raw_image(const char *filename, 
00635            cpl_type type, bool flames, bool blue,
00636            cpl_image *raw_image[2],
00637            uves_propertylist *raw_header[2], 
00638            uves_propertylist *rotated_header[2]);
00639 
00647 int uves_check_rec_status(const int val) {
00648    if(cpl_error_get_code() != CPL_ERROR_NONE) {
00649       uves_msg_error("error before %d",val);
00650       uves_msg_error((char* ) cpl_error_get_message());
00651       uves_msg_error((char* ) cpl_error_get_where());
00652       return -1;
00653     }
00654     return 0;
00655 }
00656 
00657 
00658 /*----------------------------------------------------------------------------*/
00675 /*----------------------------------------------------------------------------*/
00676 polynomial *
00677 uves_polynomial_convert_from_plist_midas(const uves_propertylist *plist, 
00678                      const char *regression_name,
00679                                          const int index)
00680 {
00681     polynomial *result = NULL;
00682     cpl_polynomial *pol = NULL;
00683     int N = strlen(regression_name);
00684     const char *coeffi_name = NULL;
00685     cpl_type type;
00686     int length;
00687     int *coeffi = NULL;
00688     int degree1 = -1;
00689     int degree2 = -1; 
00690     bool found = false;
00691     const long int plist_size = uves_propertylist_get_size(plist);
00692     int i;
00693      
00694     char cind=' ';
00695 
00696     if (index == -1) {
00697       coeffi_name = cpl_sprintf("%sI", regression_name);
00698     }
00699     else {
00700 
00701      switch(index) {
00702 
00703      case 1: cind='1'; break;
00704      case 2: cind='2'; break;
00705      case 3: cind='3'; break;
00706      case 4: cind='4'; break;
00707      case 5: cind='5'; break;
00708      case 6: cind='6'; break;
00709      case 7: cind='7'; break;
00710      case 8: cind='8'; break;
00711      case 9: cind='9'; break;
00712      default: 
00713        assure( false, CPL_ERROR_ILLEGAL_INPUT, 
00714              "Illegal index %d, 1-9 expected", index);
00715        break;
00716      }
00717 
00718 
00719       coeffi_name = cpl_sprintf("%sI%d", regression_name, index);
00720     }
00721 
00722     check_nomsg( coeffi = uves_read_midas_array(plist, coeffi_name, &length, &type, NULL));
00723 
00724 
00725     assure( type == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
00726         "Type of array %s is %s, integer expected",
00727         coeffi_name, uves_tostring_cpl_type(type));
00728     /*
00729     assure( length == 7, CPL_ERROR_ILLEGAL_INPUT,
00730         "Wrong array length = %d, 7 expected",
00731         length);
00732     */
00733     /* ignore OUTPUTI(1)- N,no.of data, */
00734     
00735     /* OUTPUTI(2)- M,no.of ind.var. */
00736     
00737     assure( coeffi[1] == 2, CPL_ERROR_UNSUPPORTED_MODE,
00738         "Regressions is %d-dimensional (2D expected)", 
00739         coeffi[1]);
00740 
00741     /* ignore OUTPUTI(3-5) (column number of variables)
00742        (3)- col.no. of dep.var.
00743        (4)- col.no. of indep.var.
00744        (5)-
00745     */
00746     
00747     /* Read degree of first and second variable 
00748        (6)- degree (ND) */
00749 
00750     degree1 = coeffi[5];
00751     degree2 = coeffi[6];
00752     
00753     uves_msg_debug("Degree of 2D regression %s is (%d, %d)",
00754                    regression_name, degree1, degree2);
00755 
00756     /* The degree of the regression is now known. Next, read the coefficients */
00757 
00758     pol = cpl_polynomial_new(2);
00759 
00760     /* Search for <regression_name>D */
00761     found = false;
00762     for (i = 0; !found && i < plist_size; i++){
00763     const cpl_property *p = uves_propertylist_get_const(plist, i);
00764     const char *name = cpl_property_get_name(p);
00765     
00766     if (strcmp(name, "HISTORY") == 0) {
00767         const char *value;
00768         check( value = cpl_property_get_string(p),
00769            "Error reading property value");
00770         
00771         /* match the string  "'<regression_name>D'"  */
00772 
00773         if (
00774          
00775         (((index < 0) &&
00776         (int)strlen(value) >= 1+N+2 &&
00777              value[0]     == '\'' &&
00778              value[1+N]   == 'D' && 
00779          value[1+N+1] == '\'') 
00780 
00781                 || 
00782 
00783         ((index > 0) &&
00784         (int)strlen(value) >= 1+N+3 &&
00785              value[0]     == '\'' &&
00786              value[1+N]   == 'D' && 
00787              value[1+N+1] == cind && 
00788          value[1+N+2] == '\'') ) 
00789 
00790                  &&
00791  
00792         strncmp(value+1, regression_name, N) == 0
00793         ) {
00794         double coeff;
00795         char *next;
00796         int power[2];
00797         int j = i; /* points to the property currently being read */
00798 
00799         power[0] = 0;  /* Current degree */
00800         power[1] = 0;
00801 
00802         found = true;
00803         value = "dummy"; /* This will make strtod fail the first time */
00804         
00805         while (power[1] <= degree2){
00806             /* Read coefficient */
00807             coeff = strtod(value, &next);
00808             
00809             if (next != value) {
00810             /* A prefix of the string was successfully converted to double */
00811             cpl_polynomial_set_coeff(pol, power, coeff);
00812             uves_msg_debug("Polynomial coefficient of order (%d, %d) is %e", 
00813                        power[0], power[1], coeff);
00814             
00815             power[0]++;
00816             if (power[0] > degree1){
00817                 power[0] = 0;
00818                 power[1]++;
00819             }
00820             value = next;
00821             }
00822             else {
00823             /* No more doubles could be read from the string,
00824                so move to the next property in the plist */
00825             j = j + 1;
00826             
00827             assure(j < plist_size, CPL_ERROR_ILLEGAL_INPUT,
00828                    "Missing header data");
00829             
00830             p = uves_propertylist_get_const(plist, j);
00831             assure(       cpl_property_get_type(p)             == CPL_TYPE_STRING &&
00832                    strcmp(cpl_property_get_name(p), "HISTORY") == 0, 
00833                       CPL_ERROR_ILLEGAL_INPUT, "Error parsing polynomial");
00834             
00835             value = cpl_property_get_string(p);
00836 
00837             
00838             uves_msg_debug("Parsing string '%s'", value);
00839             }
00840         } /* Read coefficients */
00841         } /* string was "'...D'" */
00842     } /* Keyword was HISTORY */
00843     }/* for i... */
00844     
00845     assure( found, CPL_ERROR_ILLEGAL_INPUT, "Could not find '%sD' in property list", 
00846         regression_name);
00847 
00848     /* Create a new polynomial from the cpl_polynomial */
00849     result = uves_polynomial_new(pol);
00850     
00851   cleanup:
00852     uves_free_int(&coeffi);
00853     uves_free_string_const(&coeffi_name);
00854     uves_free_polynomial(&pol);
00855     if (cpl_error_get_code() != CPL_ERROR_NONE) 
00856     {
00857         uves_polynomial_delete(&result);
00858     }
00859 
00860     return result;
00861 }
00862 
00863 
00864 /*----------------------------------------------------------------------------*/
00871 /*----------------------------------------------------------------------------*/
00872 cpl_error_code
00873 uves_frameset_merge(cpl_frameset * set1, const cpl_frameset* set2)
00874 {
00875 
00876     const cpl_frame* frm_tmp=NULL;
00877     cpl_frame* frm_dup=NULL;
00878 
00879   passure(set1 != NULL, "Wrong input set");
00880   passure(set2 != NULL, "Wrong input set");
00881   
00882   for (frm_tmp = cpl_frameset_get_first_const(set2);
00883        frm_tmp != NULL;
00884        frm_tmp = cpl_frameset_get_next_const(set2))
00885       {
00886       frm_dup = cpl_frame_duplicate(frm_tmp);
00887       cpl_frameset_insert(set1, frm_dup);
00888       }
00889   
00890   cleanup:
00891   return cpl_error_get_code();
00892 }
00893 
00894 /*----------------------------------------------------------------------------*/
00902 /*----------------------------------------------------------------------------*/
00903 
00904 cpl_error_code
00905 uves_extract_frames_group_type(const cpl_frameset * set, cpl_frameset** ext, cpl_frame_group type)
00906 {
00907     const cpl_frame* frm_tmp=NULL;
00908   cpl_frame* frm_dup=NULL;
00909   cpl_frame_group g;
00910 
00911   check_nomsg(*ext = cpl_frameset_new());
00912   check_nomsg(frm_tmp = cpl_frameset_get_first_const(set));
00913   while (frm_tmp != NULL)
00914     {
00915       g=cpl_frame_get_group(frm_tmp);
00916       if(g == type) {
00917     frm_dup=cpl_frame_duplicate(frm_tmp);
00918         cpl_frameset_insert(*ext,frm_dup);
00919         uves_msg_debug("group %d insert file %s ",type,cpl_frame_get_filename(frm_dup));
00920       }
00921       frm_tmp = cpl_frameset_get_next_const(set);
00922     }
00923 
00924   cleanup:
00925     return cpl_error_get_code();
00926 }
00927 
00928 /*----------------------------------------------------------------------------*/
00936 /*----------------------------------------------------------------------------*/
00937 cpl_error_code
00938 uves_sflats_get_encoder_steps(const cpl_frameset * set, cpl_table** enc, int* nset)
00939 {
00940   /* Input */
00941     const cpl_frame* frm=NULL;
00942   int x1enc=0;
00943   int x2enc=0;
00944   int ref_x1enc=0;
00945   int ref_x2enc=0;
00946   int i=0;
00947   int ndata=0;
00948   const int threshold=5;
00949   int status=0;
00950   uves_propertylist* plist=NULL;
00951   cpl_table* encoder_tbl=NULL;
00952   ndata = cpl_frameset_get_size(set);
00953   encoder_tbl=cpl_table_new(ndata);
00954   cpl_table_new_column(encoder_tbl,"x1enc",CPL_TYPE_INT);
00955   cpl_table_new_column(encoder_tbl,"x2enc",CPL_TYPE_INT);
00956   cpl_table_new_column(encoder_tbl,"flag",CPL_TYPE_INT);
00957  
00958   for(i=0;i<cpl_frameset_get_size(set);i++)
00959     {
00960     check_nomsg(frm=cpl_frameset_get_frame_const(set,i));
00961     check_nomsg(plist=uves_propertylist_load(cpl_frame_get_filename(frm),0));
00962     check_nomsg(x1enc=uves_pfits_get_slit3_x1encoder(plist));
00963     check_nomsg(x2enc=uves_pfits_get_slit3_x2encoder(plist));
00964     check_nomsg(cpl_table_set_int(encoder_tbl,"x1enc",i,x1enc));
00965     check_nomsg(cpl_table_set_int(encoder_tbl,"x2enc",i,x2enc));
00966     uves_free_propertylist(&plist);
00967     }
00968  
00969   check_nomsg(uves_sort_table_2(encoder_tbl,"x1enc","x2enc",false,true));
00970 
00971   check_nomsg(ref_x1enc=cpl_table_get_int(encoder_tbl,"x1enc",0,&status));
00972   check_nomsg(ref_x2enc=cpl_table_get_int(encoder_tbl,"x2enc",0,&status));
00973   *nset=1;
00974   *enc=cpl_table_new(1);
00975   cpl_table_new_column(*enc,"x1enc",CPL_TYPE_INT);
00976   cpl_table_new_column(*enc,"x2enc",CPL_TYPE_INT);
00977   check_nomsg(cpl_table_set_int(*enc,"x1enc",0,ref_x1enc));
00978   check_nomsg(cpl_table_set_int(*enc,"x2enc",0,ref_x2enc));
00979 
00980   for(i=1;i<cpl_table_get_nrow(encoder_tbl);i++) {
00981      check_nomsg(x1enc=cpl_table_get_int(encoder_tbl,"x1enc",i,&status));
00982      check_nomsg(x2enc=cpl_table_get_int(encoder_tbl,"x2enc",i,&status));
00983      if( (fabs(ref_x1enc -x1enc) > threshold) || 
00984          (fabs(ref_x2enc -x2enc) > threshold) ) {
00985   
00986        ref_x1enc = x1enc;
00987        ref_x2enc = x2enc;
00988        cpl_table_set_size(*enc,(*nset+1));
00989        check_nomsg(cpl_table_set_int(*enc,"x1enc",*nset,ref_x1enc));
00990        check_nomsg(cpl_table_set_int(*enc,"x2enc",*nset,ref_x2enc));
00991        *nset=*nset+1;
00992 
00993      }
00994   }
00995   uves_msg("Number of sets = %d",*nset);
00996 
00997   cleanup:
00998    uves_free_table(&encoder_tbl);
00999     uves_free_propertylist(&plist);
01000     return cpl_error_get_code();
01001 }
01002 
01003 
01004 /*----------------------------------------------------------------------------*/
01010 /*----------------------------------------------------------------------------*/
01011 cpl_error_code
01012 uves_dfs_set_groups(cpl_frameset * set)
01013 {
01014     cpl_frame   *   cur_frame ;
01015     int             nframes ;
01016     
01017     /* Check entries */
01018     assure(set != NULL, CPL_ERROR_NULL_INPUT, "Null input"); 
01019     
01020     /* Initialize */
01021     check( nframes = cpl_frameset_get_size(set), "Could not read frameset size");
01022     
01023     /* Loop on frames */
01024     for (cur_frame = cpl_frameset_get_first(set);
01025      cur_frame != NULL;
01026      cur_frame = cpl_frameset_get_next(set))
01027     {
01028         bool is_raw   = false;
01029         bool is_calib = false;
01030         bool is_recognized = false;
01031         bool blue;
01032         enum uves_chip chip;
01033         const char  *   tag = cpl_frame_get_tag(cur_frame);
01034         
01035         assure( tag != NULL && strcmp(tag, "") != 0, CPL_ERROR_ILLEGAL_INPUT,
01036             "Frame has no tag!");
01037         
01038         blue = false;
01039         do {
01040         bool flames = false;
01041         do {
01042             /* RAW frames */
01043             is_raw   = is_raw   || 
01044             (strcmp(tag, UVES_ORDER_FLAT  (flames,blue)) == 0 ||
01045              strcmp(tag, UVES_BIAS        (blue)) == 0 ||
01046              strcmp(tag, UVES_DARK        (blue)) == 0 ||
01047              strcmp(tag, UVES_PDARK       (blue)) == 0 ||
01048              strcmp(tag, UVES_FLAT        (blue)) == 0 ||
01049              strcmp(tag, UVES_IFLAT       (blue)) == 0 ||
01050              strcmp(tag, UVES_DFLAT       (blue)) == 0 ||
01051              strcmp(tag, UVES_SFLAT       (blue)) == 0 ||
01052              strcmp(tag, UVES_TFLAT       (blue)) == 0 ||
01053              strcmp(tag, UVES_SCREEN_FLAT (blue)) == 0 ||
01054              strcmp(tag, UVES_CD_ALIGN    (blue)) == 0 ||
01055              strcmp(tag, UVES_FORMATCHECK (flames,blue)) == 0 ||
01056              strcmp(tag, UVES_STD_STAR    (blue)) == 0 ||
01057              strcmp(tag, UVES_SCIENCE     (blue)) == 0 ||
01058              strcmp(tag, UVES_SCI_EXTND   (blue)) == 0 ||
01059              strcmp(tag, UVES_SCI_POINT   (blue)) == 0 ||
01060              strcmp(tag, UVES_SCI_SLICER  (blue)) == 0 ||
01061              strcmp(tag, UVES_ARC_LAMP    (flames,blue)) == 0 ||
01062              strcmp(tag, UVES_ECH_ARC_LAMP(blue)) == 0 ||
01063              strcmp(tag, FLAMES_SCI_RED) == 0 ||
01064              strcmp(tag, FLAMES_SCI_SIM_RED) == 0 ||
01065              strcmp(tag, FLAMES_SCI_COM_RED) == 0 ||
01066              strcmp(tag, FLAMES_FIB_FF_ODD) == 0 ||
01067              strcmp(tag, FLAMES_FIB_FF_EVEN) == 0 ||
01068              strcmp(tag, FLAMES_FIB_FF_ALL) == 0);
01069             
01070             /* CALIB frames */
01071             
01072             /* Loop through all (1 or 2) blue or red chips */
01073             for (chip = uves_chip_get_first(blue);
01074              chip != UVES_CHIP_INVALID; 
01075              chip = uves_chip_get_next(chip))
01076             {
01077                 int window;
01078                 
01079                 is_calib = is_calib || 
01080                 (strcmp(tag, UVES_DRS_SETUP(flames, chip)) == 0 ||
01081                  strcmp(tag, UVES_ORDER_TABLE(flames, chip)) == 0 ||
01082                  strcmp(tag, UVES_GUESS_ORDER_TABLE(flames,chip)) == 0 ||
01083                  strcmp(tag, UVES_MASTER_BIAS   (chip)) == 0 ||
01084                  strcmp(tag, UVES_MASTER_DARK   (chip)) == 0 ||
01085                  strcmp(tag, UVES_MASTER_PDARK  (chip)) == 0 ||
01086                  strcmp(tag, UVES_MASTER_FLAT   (chip)) == 0 ||
01087                  strcmp(tag, UVES_MASTER_DFLAT  (chip)) == 0 ||
01088                  strcmp(tag, UVES_MASTER_SFLAT  (chip)) == 0 ||
01089                  strcmp(tag, UVES_MASTER_IFLAT  (chip)) == 0 ||
01090                  strcmp(tag, UVES_MASTER_TFLAT  (chip)) == 0 ||
01091                  strcmp(tag, UVES_REF_TFLAT     (chip)) == 0 ||
01092                  strcmp(tag, UVES_MASTER_SCREEN_FLAT(chip)) == 0 ||
01093                  strcmp(tag, UVES_MASTER_ARC_FORM(chip)) == 0 ||
01094                  strcmp(tag, UVES_WEIGHTS(chip))        == 0 ||
01095                  strcmp(tag, UVES_LINE_TABLE(flames,chip)) == 0 ||
01096                  strcmp(tag, UVES_GUESS_LINE_TABLE(flames,chip)) == 0 ||
01097                  strcmp(tag, UVES_INSTR_RESPONSE(chip)) == 0 ||
01098                  strcmp(tag, UVES_MASTER_RESPONSE(chip)) == 0 ||
01099                  strcmp(tag, UVES_LINE_REFER_TABLE    ) == 0 ||
01100                  strcmp(tag, UVES_LINE_INTMON_TABLE   ) == 0 ||
01101                  strcmp(tag, UVES_FLUX_STD_TABLE      ) == 0 ||
01102                  strcmp(tag, UVES_EXTCOEFF_TABLE      ) == 0 ||
01103                  strcmp(tag, FLAMES_LINE_TABLE(chip)) == 0 ||
01104                  strcmp(tag, FLAMES_SLIT_FF_DT1(chip)) == 0 ||
01105                  strcmp(tag, FLAMES_SLIT_FF_DT2(chip)) == 0 ||
01106                  strcmp(tag, FLAMES_SLIT_FF_DT3(chip)) == 0 ||
01107                  strcmp(tag, FLAMES_SLIT_FF_DTC(chip)) == 0 ||
01108                  strcmp(tag, FLAMES_SLIT_FF_BP1(chip)) == 0 ||
01109                  strcmp(tag, FLAMES_SLIT_FF_BP2(chip)) == 0 ||
01110                  strcmp(tag, FLAMES_SLIT_FF_BP3(chip)) == 0 ||
01111                  strcmp(tag, FLAMES_SLIT_FF_BPC(chip)) == 0 ||
01112                  strcmp(tag, FLAMES_SLIT_FF_BN1(chip)) == 0 ||
01113                  strcmp(tag, FLAMES_SLIT_FF_BN2(chip)) == 0 ||
01114                  strcmp(tag, FLAMES_SLIT_FF_BN3(chip)) == 0 ||
01115                  strcmp(tag, FLAMES_SLIT_FF_BNC(chip)) == 0 ||
01116                  strcmp(tag, FLAMES_SLIT_FF_SG1(chip)) == 0 ||
01117                  strcmp(tag, FLAMES_SLIT_FF_SG2(chip)) == 0 ||
01118                  strcmp(tag, FLAMES_SLIT_FF_SG3(chip)) == 0 ||
01119                  strcmp(tag, FLAMES_SLIT_FF_SGC(chip)) == 0 ||
01120                  strcmp(tag, FLAMES_SLIT_FF_COM(chip)) == 0 ||
01121                  strcmp(tag, FLAMES_SLIT_FF_NOR(chip)) == 0 ||
01122                  strcmp(tag, FLAMES_SLIT_FF_NSG(chip)) == 0 ||
01123                  strcmp(tag, FLAMES_FIB_FF_DT1(chip)) == 0 ||
01124                  strcmp(tag, FLAMES_FIB_FF_DT2(chip)) == 0 ||
01125                  strcmp(tag, FLAMES_FIB_FF_DT3(chip)) == 0 ||
01126                  strcmp(tag, FLAMES_FIB_FF_DTC(chip)) == 0 ||
01127                  strcmp(tag, FLAMES_FIB_FF_BP1(chip)) == 0 ||
01128                  strcmp(tag, FLAMES_FIB_FF_BP2(chip)) == 0 ||
01129                  strcmp(tag, FLAMES_FIB_FF_BP3(chip)) == 0 ||
01130                  strcmp(tag, FLAMES_FIB_FF_BPC(chip)) == 0 ||
01131                  strcmp(tag, FLAMES_FIB_FF_BN1(chip)) == 0 ||
01132                  strcmp(tag, FLAMES_FIB_FF_BN2(chip)) == 0 ||
01133                  strcmp(tag, FLAMES_FIB_FF_BN3(chip)) == 0 ||
01134                  strcmp(tag, FLAMES_FIB_FF_BNC(chip)) == 0 ||
01135                  strcmp(tag, FLAMES_FIB_FF_SG1(chip)) == 0 ||
01136                  strcmp(tag, FLAMES_FIB_FF_SG2(chip)) == 0 ||
01137                  strcmp(tag, FLAMES_FIB_FF_SG3(chip)) == 0 ||
01138                  strcmp(tag, FLAMES_FIB_FF_SGC(chip)) == 0 ||
01139                  strcmp(tag, FLAMES_FIB_FF_COM(chip)) == 0 ||
01140                  strcmp(tag, FLAMES_FIB_FF_NOR(chip)) == 0 ||
01141                  strcmp(tag, FLAMES_FIB_FF_NSG(chip)) == 0 ||
01142                  strcmp(tag, FLAMES_ORDEF(flames,chip)) == 0 ||
01143                  strcmp(tag, FLAMES_CORVEL_MASK) == 0);
01144                 
01145                 for (window = 1; window <= 3; window++)
01146                 {
01147                     is_calib = is_calib || 
01148                     strcmp(tag, UVES_LINE_TABLE_MIDAS(chip, window)) == 0;
01149                 }
01150                 
01151                 if (!flames && strcmp(tag, UVES_BACKGR_TABLE(chip)) == 0)
01152                 {
01153                     uves_msg_warning("Background table %s has been deprecated. "
01154                              "Inter-order positions will be inferred "
01155                              "from the order table %s. "
01156                              "Use recipe parameters to define "
01157                              "measuring method ",
01158                              UVES_BACKGR_TABLE(chip), 
01159                              UVES_ORDER_TABLE(flames, chip));
01160                     
01161                     is_recognized = true;
01162                 }
01163                 
01164                 if (strcmp(tag, UVES_DRS_SETUP(flames, chip)) == 0)
01165                 {
01166                     uves_msg_warning("DRS setup table %s has been deprecated. "
01167                              "Use recipe parameters "
01168                              "to define data reduction parameters ",
01169                              UVES_DRS_SETUP(flames, chip));
01170                     
01171                     is_recognized = true;
01172                 }
01173             }
01174             flames = !flames;
01175         } while (flames);
01176         blue = !blue;
01177         }
01178         while (blue);
01179         
01180         is_recognized = is_recognized || is_raw || is_calib;
01181 
01182         if (is_raw)
01183         {
01184             cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW) ;
01185         }
01186         else if (is_calib)
01187         {
01188             cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB) ;
01189         }
01190         else if (!is_recognized)
01191         {
01192             uves_msg_warning("Unrecognized tag %s", tag);
01193         }
01194     }
01195     
01196   cleanup:
01197     return cpl_error_get_code();
01198 }
01199 
01200 
01201 /*----------------------------------------------------------------------------*/
01210 /*----------------------------------------------------------------------------*/
01211 static void
01212 remove_pre_over_scan(uves_propertylist *pl)
01213 {
01214     bool blue, new_format;
01215     enum uves_chip chip;
01216     
01217     new_format = false;
01218     do {
01219     blue = false;
01220     do {
01221         for (chip = uves_chip_get_first(blue); 
01222          chip != UVES_CHIP_INVALID;
01223          chip = uves_chip_get_next(chip))
01224         {
01225             int n_erase_px = 0;   /* Number of erased properties */
01226             int n_erase_py = 0;
01227             int n_erase_ox = 0;
01228             int n_erase_oy = 0;
01229             
01230             do {
01231             /* This function erases only one property at a time,
01232              *  therefore call it until it returns 0
01233              */
01234             check( n_erase_px = 
01235                    uves_propertylist_erase(pl, UVES_PRESCANX(new_format, chip)),
01236                    "Error erasing keyword '%s'", UVES_PRESCANX(new_format, chip));
01237             
01238             check( n_erase_py = 
01239                    uves_propertylist_erase(pl, UVES_PRESCANY(new_format, chip)),
01240                    "Error erasing keyword '%s'", UVES_PRESCANY(new_format, chip));
01241             
01242             check( n_erase_ox =
01243                    uves_propertylist_erase(pl, UVES_OVRSCANX(new_format, chip)),
01244                    "Error erasing keyword '%s'", UVES_OVRSCANX(new_format, chip));
01245             
01246             check( n_erase_oy =
01247                    uves_propertylist_erase(pl, UVES_OVRSCANY(new_format, chip)),
01248                    "Error erasing keyword '%s'", UVES_OVRSCANY(new_format, chip));
01249             }
01250             while (n_erase_px > 0 ||
01251                n_erase_py > 0 ||
01252                n_erase_ox > 0 ||
01253                n_erase_oy > 0);
01254         }
01255         blue = !blue;
01256     }
01257     while (blue);
01258     
01259     new_format = !new_format;
01260     }
01261     while (new_format);
01262 
01263   cleanup:
01264     return;
01265 }
01266 
01267 
01268 /*----------------------------------------------------------------------------*/
01278 /*----------------------------------------------------------------------------*/
01279 
01280 void
01281 uves_copy_if_possible(uves_propertylist *to, const uves_propertylist *from,
01282          const char *name)
01283 {
01284     if (!uves_propertylist_contains(to, name) &&
01285     uves_propertylist_contains(from, name))
01286     {
01287         uves_msg_debug("Propagating keyword %s", name);
01288 
01289         check_nomsg( uves_propertylist_copy_property(to, from, name) );
01290     }
01291     else
01292     {
01293         uves_msg_debug("Keyword %s not propagated", name);
01294     }
01295     
01296   cleanup:
01297     return;
01298 }
01299 
01300 /*----------------------------------------------------------------------------*/
01344 /*----------------------------------------------------------------------------*/
01345 cpl_error_code
01346 uves_frameset_insert(cpl_frameset *frames, 
01347                      void *object, 
01348                      cpl_frame_group group, 
01349                      cpl_frame_type type, 
01350                      cpl_frame_level level,
01351                      const char *filename, 
01352                      const char *tag, 
01353                      const uves_propertylist *raw_header,
01354                      const uves_propertylist *primary_header, 
01355                      const uves_propertylist *table_header, 
01356                      const cpl_parameterlist *parameters, 
01357                      const char *recipe, 
01358                      const char *pipeline,
01359                      cpl_table **qc,
01360                      const char *start_time,
01361                      bool dump_paf,
01362                      unsigned stats_mask)
01363 {
01364     cpl_frame *f = NULL;
01365     uves_propertylist *pl = NULL;
01366     const char *origin = "";
01367 
01368     passure( !(type == CPL_FRAME_TYPE_IMAGE && table_header != NULL), " ");
01369     passure( raw_header != NULL, " ");
01370     passure( primary_header != NULL, " ");
01371 
01372     assure( type == CPL_FRAME_TYPE_IMAGE || stats_mask == 0,
01373         CPL_ERROR_INCOMPATIBLE_INPUT,
01374         "Cannot compute image statistics on table product" );
01375 
01376     /* Insert the object (image or table) into frameset */
01377     check(( f = cpl_frame_new(),
01378             cpl_frame_set_filename(f, filename),    /* local filename */
01379             cpl_frame_set_tag     (f, tag),         /* e.g. ORDER_TABLE_BLUE */
01380             cpl_frame_set_type    (f, type),        /* e.g. table */
01381             cpl_frame_set_group   (f, group),       /* e.g. raw/product */
01382             cpl_frame_set_level   (f, level),       /* e.g. temporary/final */
01383             cpl_frameset_insert(frames, f)), "Could not insert frame into frameset");
01384     
01385     /* Pipeline id format is <PACKAGE "/" PACKAGE_VERSION>; */
01386     if (strchr(pipeline, '/') == NULL)
01387     {
01388         uves_msg_warning("Pipeline ID '%s' is not of format: "
01389                  "Pipeline-name/version", pipeline);
01390     }
01391 
01392     /* Copy provided keywords in 'primary_header' to 'pl' */
01393     pl = uves_propertylist_new();
01394     if (!uves_propertylist_is_empty(primary_header))
01395     {
01396         if (0)
01397                 /* This takes (n*m) time */
01398                 {
01399                     /* The regexp "" matches any string (because any string has
01400                        the empty string as a sub-string),
01401                        except on Mac, where it is an illegal regexp (for whatever reason).
01402                        Therefore, use ".*" to match any string */
01403                     
01404                     check( uves_propertylist_copy_property_regexp(pl, primary_header, ".*", 0),
01405                            "Could not copy keywords");
01406                 }
01407             else
01408                 check( uves_propertylist_append(pl, primary_header),
01409                        "Could not copy keywords");
01410     }
01411     
01412     /* Propagate/create DFS keywords */
01413     UVES_TIME_START("cpl_dfs_setup_product_header");
01414     check( uves_dfs_setup_product_header(pl,
01415                     f,
01416                     frames,
01417                     parameters,
01418                     recipe,
01419                     pipeline,
01420                     DICTIONARY),
01421        "Error setting up product header");
01422     UVES_TIME_END;
01423     
01424     /* Change origin to 'ESO' if it says 'ESO-MIDAS'
01425      * NOST-Definition: "The value field shall contain a character string
01426      *                   identifying the organization or institution responsible 
01427      *                   for creating the FITS file."
01428      */
01429     
01430     check( uves_get_property_value(pl, "ORIGIN", CPL_TYPE_STRING, &origin),
01431        "Error reading ORIGIN from product header");
01432 
01433     if (strcmp(origin, "ESO-MIDAS") == 0) 
01434     {
01435         uves_propertylist_set_string(pl, "ORIGIN", "ESO");
01436     }
01437     
01438     /* Set OBJECT = DO category */
01439     check( uves_pfits_set_object(pl, tag), "Error writing object keyword");
01440         
01441     /* Add statistics keywords */
01442     if (type == CPL_FRAME_TYPE_IMAGE && stats_mask != 0)
01443     {
01444         check( uves_dfs_write_statistics((cpl_image *) object, pl, stats_mask),
01445            "Error adding image statistics keywords");
01446     }
01447     
01448     /* Propagate ESO.DET keywords from 'raw_header',
01449      * This is necessary because cpl_dfs_setup_product_header() copies
01450      * only from the primary extension of the first input frames
01451      */
01452     check( uves_propertylist_copy_property_regexp(pl, raw_header, "^ESO DET ", 0),
01453        "Could not propagate 'ESO DET*' keywords");
01454 
01455     /* But remove prescan, overscan keywords. 
01456        (Since these areas are not present in any products.) */
01457     check( remove_pre_over_scan(pl), 
01458        "Error removing pre-, overscan keywords from product header");
01459 
01460     /* Propagate certain keywords from 'raw_header' 
01461        (only if available and if not already present in product header) */
01462     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_AIRMASS) );
01463     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_IMAGETYP) );
01464     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_UT) );
01465     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_ST) );
01466     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_EXPTIME) );
01467     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_EXTNAME) );
01468     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_DATE) );
01469     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_DATAMEAN) );
01470     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_DATAMED) );
01471     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_DATARMS) );
01472     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_OS_EXPOI) );
01473 
01474     /* MIDAS internal(?): check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_TMSTART) ); */
01475 
01476     if (0)
01477         /* uves_propertylist_copy_property_regexp() is slow */
01478         {
01479             check( uves_propertylist_copy_property_regexp(pl, raw_header, "^GRAT[0-9]*$", 0),
01480                    "Could not propagate 'GRATi' keywords");
01481             check( uves_propertylist_copy_property_regexp(pl, raw_header, "^FILTER[0-9]*$", 0),
01482                    "Could not propagate 'FILTERi' keywords");
01483             check( uves_propertylist_copy_property_regexp(pl, raw_header, "^WLEN[0-9]*$", 0),
01484                    "Could not propagate 'WLENi' keywords");
01485         }
01486     else
01487         {
01488             check( uves_propertylist_copy_property_regexp(
01489                        pl, raw_header, "^((GRAT|FILTER|WLEN)[0-9]*)$", 0),
01490                    "Could not propagate GRATi, FILTERi and WLENi keywords");
01491         }
01492 
01493     /* If RA,DEC do not exist, invent them and set to zero, like MIDAS */
01494     if ( !uves_propertylist_contains(pl, UVES_RA) )
01495     {
01496         uves_pfits_set_ra(pl, 0);
01497     }
01498     if ( !uves_propertylist_contains(pl, UVES_DEC) )
01499     {
01500         uves_pfits_set_dec(pl, 0);
01501     }
01502 
01503     /* 
01504      * REDLEVEL and STATUS have been deprecated, so delete them
01505      * along with inherited MIDAS specific keywords
01506      */
01507     {
01508         bool invert = false;
01509         uves_propertylist_erase_regexp(pl, "^("
01510                                        "ESO PRO (REDLEVEL|REC[0-9]+ STATUS)|"
01511                                        "TM-START|MIDASFTP|FILENAME)$", invert);
01512     }
01513 
01514     check( uves_pfits_set_starttime(pl, start_time),
01515        "Could not write recipe start time");
01516 
01517     check( uves_pfits_set_stoptime(pl, qfits_get_datetime_iso8601()),
01518        "Could not write recipe stop time");
01519 
01520     /* Create paf file from each QC table, and transfer
01521        all QC parameters to product header
01522     */
01523     if (qc != NULL)
01524     {
01525         int i;
01526         for (i = 0; qc[i] != NULL; i++)
01527         {
01528             uves_pfits_put_qc(pl, qc[i]);
01529                         
01530             if (dump_paf)
01531             {
01532                 /* Exception! This is a hack */
01533                 if (strcmp(recipe, make_str(UVES_TFLAT_ID)) == 0 && i == 1)
01534                 {
01535                     /* Don't dump the science QC again */
01536                 }
01537                 else
01538                 {
01539                     uves_save_paf(filename, i, recipe, qc[i], 
01540                           pl, raw_header, tag);
01541                 }
01542             }
01543         } 
01544     }
01545 
01546     UVES_TIME_START("save product");
01547 
01548     /* Now save with the correct header */
01549     if (type == CPL_FRAME_TYPE_IMAGE)
01550     {
01551         bool use_bitpix16_for_int = (strcmp(recipe, make_str(FLAMES_CAL_ORDERPOS)) == 0);
01552         
01553         check( uves_save_image((cpl_image *) object, filename, pl, 
01554                                use_bitpix16_for_int, true), 
01555            "Error saving image to file %s", filename);
01556     }
01557     else if (type == CPL_FRAME_TYPE_TABLE)                           /* Table */
01558     {
01559         check( uves_table_save((cpl_table *) object,
01560                   pl,                                /* Primary header */
01561                   table_header,                      /* Table header */
01562                   filename,
01563                   CPL_IO_DEFAULT),                   /* Create new file */
01564            "Error saving table to file '%s'", filename);
01565     }
01566     else
01567     {
01568         assure(false, CPL_ERROR_UNSUPPORTED_MODE, "Unsupported frame type");
01569     }
01570 
01571     UVES_TIME_END;
01572     
01573   cleanup:
01574     uves_free_propertylist(&pl);
01575     
01576     return cpl_error_get_code();
01577 }
01578 
01579 
01580 /*----------------------------------------------------------------------------*/
01589 /*----------------------------------------------------------------------------*/
01590 void
01591 uves_dfs_write_statistics(const cpl_image *image, uves_propertylist *header,
01592          unsigned stats_mask)
01593 {
01594     cpl_stats *stats = NULL;
01595 
01596     /* Only these bits are supported, all others must be zero */
01597     assure( (stats_mask & (CPL_STATS_MEAN | CPL_STATS_STDEV | CPL_STATS_MEDIAN |
01598               CPL_STATS_MIN  | CPL_STATS_MAX)) == stats_mask,
01599         CPL_ERROR_UNSUPPORTED_MODE, "Cannot compute mask %d",
01600         stats_mask );
01601 
01602     UVES_TIME_START("calculate stats");
01603 
01604     check( stats = cpl_stats_new_from_image(
01605            image, stats_mask),
01606        "Error reading image statistics");
01607     
01608     UVES_TIME_END;
01609     
01610     if (stats_mask & CPL_STATS_MEDIAN)
01611     {
01612         check( uves_pfits_set_data_median (header, cpl_stats_get_median(stats) ), 
01613            "Could not write median flux");
01614     }
01615     if (stats_mask & CPL_STATS_MEAN)
01616     {
01617         check( uves_pfits_set_data_average(header, cpl_stats_get_mean  (stats) ), 
01618            "Could not write average flux");
01619     }
01620     if (stats_mask & CPL_STATS_STDEV)
01621     {
01622         check( uves_pfits_set_data_stddev (header, cpl_stats_get_stdev (stats) ), 
01623            "Could not write flux stdev");
01624     }
01625     if (stats_mask & CPL_STATS_MIN)
01626     {
01627         check( uves_pfits_set_data_min    (header, cpl_stats_get_min   (stats) ), 
01628            "Could not write min flux");
01629     }
01630     if (stats_mask & CPL_STATS_MIN)
01631     {
01632         check( uves_pfits_set_data_max    (header, cpl_stats_get_max   (stats) ), 
01633            "Could not write max flux");
01634     }
01635 
01636   cleanup:
01637     uves_free_stats(&stats);
01638     return;
01639 }
01640 
01641 
01642 /*----------------------------------------------------------------------------*/
01677 /*----------------------------------------------------------------------------*/
01678 void *
01679 uves_read_midas_array(const uves_propertylist *plist, const char *name, 
01680                       int *length, cpl_type *type, int *ncards)
01681 {
01682     void *result = NULL;
01683     unsigned result_size;
01684     int N = strlen(name);
01685     bool found = false;
01686     const char *value;
01687     int size;
01688     int i;
01689     const long int plist_size = uves_propertylist_get_size(plist);
01690    
01691     assure_nomsg( length != NULL, CPL_ERROR_NULL_INPUT );
01692     assure_nomsg(   type != NULL, CPL_ERROR_NULL_INPUT );
01693     for (i = 0; !found && i < plist_size; i++)
01694     {
01695       const cpl_property *p = uves_propertylist_get_const(plist, i);
01696       value = cpl_property_get_name(p);
01697       
01698       if (strcmp(value, "HISTORY") == 0)
01699         {
01700           
01701           check( value = cpl_property_get_string(p),
01702          "Error reading property value");
01703           
01704           /* match the string  "'<name>','t"  */
01705           
01706           if ((int)strlen(value) >= 1+N+4 &&
01707           value[0]     == '\'' &&
01708           value[N+1]   == '\'' && 
01709           value[N+2]   == ','  && 
01710           value[N+3]   == '\'' && 
01711           strncmp(value+1, name, N) == 0
01712           )
01713         { 
01714           switch(value[N+4]) {
01715           case 'R':
01716         /* Distinguish between 
01717            "'<name>','R*4'" and
01718            "'<name>','R*8'"
01719         */
01720         *type = CPL_TYPE_DOUBLE;
01721 
01722         if ((int)strlen(value) >= 1+N+4+2 && value[N+4+1] == '*')
01723           {
01724             switch(value[N+4+2]) {
01725             case '4': *type = CPL_TYPE_FLOAT; break;
01726             case '8': *type = CPL_TYPE_DOUBLE; break; 
01727             default:
01728               assure( false, CPL_ERROR_ILLEGAL_INPUT,
01729                   "Unrecognized MIDAS type: 'R*%c'",
01730                   value[N+4+2]);
01731               break;
01732             }
01733           }
01734         break;
01735           case 'I': *type = CPL_TYPE_INT   ; size = sizeof(int);    break;
01736           case 'C': *type = CPL_TYPE_STRING; size = sizeof(char);   break;
01737           default:
01738         assure( false, CPL_ERROR_UNSUPPORTED_MODE,
01739             "Unrecognized type '%c'", value[N+4]);
01740         break;
01741           }
01742           found = true;
01743         }
01744         }
01745     }
01746     
01747     assure( found, CPL_ERROR_ILLEGAL_INPUT, "Could not find '%s' in property list", name);
01748     
01749     /* 'i' is now the row immediately after first occurence of 'HISTORY   '<name>...  */
01750     result_size = sizeof(double) * 100;  /* realloc when/if out of memory */
01751     result = cpl_malloc(result_size);
01752 
01753     *length = 0;
01754     if (ncards != NULL) *ncards = 2; /* First HISTORY entry + termination HISTORY entry */
01755     do {
01756       const cpl_property *p;
01757 
01758       if (ncards != NULL) *ncards += 1;
01759 
01760       assure(i < plist_size, 
01761          CPL_ERROR_ILLEGAL_INPUT, "Missing header data");
01762       p = uves_propertylist_get_const(plist, i);
01763       assure(       cpl_property_get_type(p)             == CPL_TYPE_STRING &&
01764             strcmp(cpl_property_get_name(p), "HISTORY") == 0, 
01765             CPL_ERROR_ILLEGAL_INPUT, "Error parsing array");
01766       value = cpl_property_get_string(uves_propertylist_get_const(plist, i));
01767     
01768       uves_msg_debug("Parsing '%s'", value);
01769 
01770       if (*type == CPL_TYPE_STRING)
01771     {
01772       assure( strlen(value) < 100, CPL_ERROR_UNSUPPORTED_MODE, 
01773           "String too long. Max size is 100");
01774 
01775       /* Remove any blanks from the string
01776          (e.g. convert "0 1 2" to "012")
01777       */
01778       {
01779         int len = strlen(value);
01780         int j = 0;
01781         int k;
01782         for (k = 0; k <= len; k++)  /* including final '\0' */
01783           {
01784         //if (value[k] != ' '){
01785         ((char*)result)[j] = value[k];
01786         j++;
01787         //      }
01788           }
01789         *length = j-1;
01790       }
01791 
01792       uves_msg_debug("Converted '%s' to '%s'",
01793              value, (char*)result);
01794                 
01795       /* done parsing */
01796       value = "";
01797     }
01798         
01799       else { /* numerical types */
01800     if (strcmp(value, "") != 0) {
01801       double numberd = -1; /* suppres warning */
01802       int numberi = -1;
01803       float numberf = -1;
01804       const int base = 10;
01805       char *next = (char *) value;
01806 
01807       do {
01808             /* ignore OUTPUTI(1)- N,no.of data, */
01809         switch(*type) {
01810         case CPL_TYPE_DOUBLE:
01811           numberd = strtod(value, &next);
01812           uves_msg_debug("Got %g, remaining: '%s'", numberd, next);
01813           break;
01814         case CPL_TYPE_FLOAT:
01815           numberf = strtod(value, &next); // C99: strtof(value, &next);
01816           uves_msg_debug("Got %g, remaining: '%s'", numberf, next);
01817           break;
01818         case CPL_TYPE_INT:
01819           numberi = strtol(value, &next, base);
01820           uves_msg_debug("Got %d, remaining: '%s'", numberi, next);
01821           break;
01822         default:
01823           passure(false, " ");
01824         }
01825                     
01826             if (next != value)
01827           {
01828                 /* A prefix of the string could be converted */
01829                 (*length)++;
01830         if (*length * sizeof(double) > result_size)
01831           {
01832             result_size *= 2;
01833             result = cpl_realloc(result, result_size);
01834           }
01835 
01836         switch(*type) {
01837         case CPL_TYPE_DOUBLE:
01838           ((double *)result)[*length-1] = numberd;
01839           break;
01840         case CPL_TYPE_FLOAT:
01841           ((float *)result)[*length-1] = numberf;
01842           break;
01843         case CPL_TYPE_INT:
01844           ((int    *)result)[*length-1] = numberi;
01845           break;
01846         default:
01847           passure(false, " ");
01848         }
01849 
01850                 value = next;
01851                             
01852         switch(*type) {
01853         case CPL_TYPE_DOUBLE:
01854           numberd = strtod(value, &next);
01855           uves_msg_debug("Got %g, remaining: '%s'", numberd, next);
01856           break;
01857         case CPL_TYPE_FLOAT:
01858           numberf = strtod(value, &next); // C99: strtof(value, &next);
01859           uves_msg_debug("Got %g, remaining: '%s'", numberf, next);
01860           break;
01861         case CPL_TYPE_INT:
01862           numberi = strtol(value, &next, base);
01863           uves_msg_debug("Got %d, remaining: '%s'", numberi, next);
01864           break;
01865         default:
01866           passure(false, " ");
01867         }
01868           }
01869       } while (next != value);
01870         }
01871       }/* if numerical type */
01872         
01873       i++;
01874 
01875       assure( strcmp(value, "") == 0, CPL_ERROR_ILLEGAL_INPUT,
01876           "Cannot parse %s descriptor %s, remaining string: '%s'", 
01877           uves_tostring_cpl_type(*type), name, value);
01878     
01879       /* Find out if we can continue parsing the next HISTORY keyword */
01880       if (i < plist_size)
01881         {
01882       p = uves_propertylist_get_const(plist, i);
01883       if (cpl_property_get_type(p) == CPL_TYPE_STRING &&
01884           strcmp(cpl_property_get_name(p), "HISTORY") == 0)
01885             {
01886           value = cpl_property_get_string(
01887                           uves_propertylist_get_const(plist, i));
01888 
01889           if (*type == CPL_TYPE_STRING)
01890         {
01891           if (strcmp(value, "") != 0) {
01892             uves_msg_debug("String array %s with length > 1 found. Ignoring remaining values", name);
01893             while (strcmp(value, "") != 0 && i+1 < plist_size) {
01894               i++;
01895               p = uves_propertylist_get_const(plist, i);
01896               value = cpl_property_get_string(
01897                               uves_propertylist_get_const(plist, i));
01898               if (ncards != NULL) *ncards += 1;
01899             }
01900           }
01901         }
01902         }
01903     }
01904       
01905     } while (strcmp(value, "") != 0);
01906     
01907  cleanup:
01908     if (cpl_error_get_code() != CPL_ERROR_NONE)
01909       {
01910     cpl_free(result); result = NULL;
01911       }
01912     return result;
01913 }
01914 
01915 
01916 /*----------------------------------------------------------------------------*/
01934 /*----------------------------------------------------------------------------*/
01935 cpl_error_code
01936 uves_save_table_local(const char *description, const char *filename_prefix,
01937               const cpl_table *table, 
01938               enum uves_chip chip, int trace, int window,
01939               const uves_propertylist *pheader, const uves_propertylist *eheader)
01940 {
01941     char *filename = NULL;
01942 
01943     check( filename = uves_local_filename(filename_prefix, chip, trace, window),
01944        "Error getting filename");
01945 
01946     check( uves_table_save(table, pheader, eheader, filename, CPL_IO_DEFAULT), 
01947        "Error saving table to file '%s'", filename);
01948     
01949     if (description != NULL) uves_msg("%s saved to '%s'", description, filename);
01950     
01951   cleanup:
01952     cpl_free(filename);
01953     return cpl_error_get_code();
01954 }
01955 
01956 /*----------------------------------------------------------------------------*/
01977 /*----------------------------------------------------------------------------*/
01978 cpl_error_code
01979 uves_save_image_local(const char *description, const char *filename_prefix, 
01980                       const cpl_image *image, 
01981                       enum uves_chip chip, int trace, int window,
01982                       const uves_propertylist *plist,
01983                       bool use_bitpix16_for_int)
01984 {
01985     char *filename = NULL;
01986     
01987     check( filename = uves_local_filename(filename_prefix, chip, trace, window),
01988        "Error getting filename");
01989     
01990     check( uves_save_image(image, filename, plist, use_bitpix16_for_int, true),
01991            "Error saving image to file '%s'", filename);
01992     if (description != NULL) uves_msg("%s saved to '%s'", description, filename);
01993     
01994   cleanup:
01995     cpl_free(filename);
01996     return cpl_error_get_code();
01997 }
01998 
01999 
02000 /*----------------------------------------------------------------------------*/
02010 /*----------------------------------------------------------------------------*/
02011 cpl_image *uves_load_image(const cpl_frame *f,
02012                int plane,
02013                int extension,
02014                uves_propertylist **header)
02015 {
02016     cpl_image *image = NULL;
02017     uves_propertylist *plist = NULL;
02018     const char *filename;
02019     int bitpix;
02020     cpl_type type;
02021     int naxis=0;
02022     cpl_vector * vector=NULL;
02023 
02024     
02025     assure_nomsg( f != NULL, CPL_ERROR_NULL_INPUT );
02026  
02027     assure( cpl_frame_get_type(f) == CPL_FRAME_TYPE_IMAGE,
02028         CPL_ERROR_TYPE_MISMATCH, "Wrong type: %s",
02029         uves_tostring_cpl_frame_type(cpl_frame_get_type(f)));
02030 
02031     filename = cpl_frame_get_filename(f);
02032 
02033     check( plist = uves_propertylist_load(filename, extension),
02034        "Could not load header from %s extension %d", 
02035        filename, extension);
02036     
02037     check( bitpix = uves_pfits_get_bitpix(plist),
02038        "Could not read BITPIX from %s extension %d",
02039        filename, extension);
02040     
02041     if      (bitpix == -32) type = CPL_TYPE_FLOAT;
02042     else if (bitpix == -64) type = CPL_TYPE_DOUBLE;
02043     else if (bitpix ==  32) type = CPL_TYPE_INT;
02044     else if (bitpix ==  16) type = CPL_TYPE_INT;
02045     else
02046     {
02047         assure( false, CPL_ERROR_UNSUPPORTED_MODE,
02048             "No CPL type to represent BITPIX = %d", bitpix);
02049     }
02050 
02051     check( naxis = uves_pfits_get_naxis(plist),
02052            "could not get NAXIS" );
02053 
02054     if( naxis == 1) {
02055 
02056       check( vector = cpl_vector_load(filename,extension),
02057              "Could not load vector from extension %d of file '%s' ",
02058              extension, filename);
02059       cknull(image=uves_vector_to_image(vector,type),
02060          "could not convert vector to image");
02061     } else {
02062 
02063 
02064       check( image = cpl_image_load(filename,
02065                     type,
02066                     plane,
02067                     extension),
02068          "Could not load image from extension %d of file '%s' ", 
02069          extension, filename);
02070 
02071     }
02072 
02073     if (header != NULL)
02074     {
02075         *header = uves_propertylist_duplicate(plist);
02076     }
02077 
02078   cleanup:
02079     uves_free_vector(&vector);
02080     uves_free_propertylist(&plist);
02081     return image;
02082 }
02083 /*----------------------------------------------------------------------------*/
02087 /*----------------------------------------------------------------------------*/
02088 
02089 cpl_image *uves_load_image_file(const char *filename,
02090                                 int plane,
02091                                 int extension,
02092                                 uves_propertylist **header)
02093 {
02094     cpl_image *i;
02095     cpl_frame *f = cpl_frame_new();
02096     cpl_frame_set_filename(f, filename);
02097     cpl_frame_set_type(f, CPL_FRAME_TYPE_IMAGE);
02098 
02099     i = uves_load_image(f, plane, extension, header);
02100     
02101     uves_free_frame(&f);
02102 
02103     return i;
02104 }
02105 
02106 /*----------------------------------------------------------------------------*/
02131 /*----------------------------------------------------------------------------*/
02132 void
02133 uves_save_image(const cpl_image *image, const char *filename, const uves_propertylist *plist,
02134                 bool use_bitpix16_for_int, bool save1d)
02135 {
02136     cpl_type_bpp bpp;
02137     cpl_type t;
02138     const cpl_vector *image_1d = NULL;
02139     uves_propertylist *header = NULL;
02140     cpl_image *thresholded = NULL;
02141     cpl_image *thresholded_double = NULL;
02142     
02143     if (image == NULL) {
02144         check( uves_image_save(image, filename, CPL_BPP_IEEE_FLOAT, plist, CPL_IO_DEFAULT), 
02145                "Error saving NULL image to file '%s'", filename);
02146     }
02147     else {
02148         check( t = cpl_image_get_type(image), "Error reading image type");
02149         if      (t == CPL_TYPE_FLOAT ) bpp = CPL_BPP_IEEE_FLOAT;
02150         else if (t == CPL_TYPE_DOUBLE) bpp = CPL_BPP_IEEE_FLOAT;
02151         /* Internal computations in double precision,
02152            save as single precision */
02153 #if CPL_VERSION_CODE >= CPL_VERSION(3, 0, 1)
02154         /* Some FLAMES images are BITPIX=16 (ORDEF), 
02155            some are 32 SLIT_FF_COM_REDL
02156         */
02157         else if (t == CPL_TYPE_INT   ) {
02158             if (use_bitpix16_for_int) bpp = CPL_BPP_16_UNSIGNED;
02159             else bpp = CPL_BPP_32_SIGNED;
02160         }
02161 #else
02162         else if (t == CPL_TYPE_INT   ) bpp = CPL_BPP_16_SIGNED;
02163 #endif
02164         else assure(false, CPL_ERROR_UNSUPPORTED_MODE,
02165                     "Unsupported image type '%s'", uves_tostring_cpl_type(t));
02166 
02167 
02168         thresholded = cpl_image_duplicate(image);
02169         assure_mem( thresholded );
02170 
02171         if (t == CPL_TYPE_DOUBLE)
02172             {
02173                 passure( bpp == CPL_BPP_IEEE_FLOAT, "%d", bpp);
02174 
02175                 /* Avoid infinities that would happen when casting
02176                    double -> float
02177                    by thresholding the image to +-FLT_MAX (or, better
02178                    a little less than FLT_MAX just to be sure).
02179         
02180                    (This is not a really nice solution because it solves the
02181                    problem (too large/small values) after it is introduced
02182                    (rather than avoiding it), but a general solution of the
02183                    problem would probably mean guarding every arithmetic
02184                    operation with range checks.)
02185                 */
02186         
02187                 check_nomsg( cpl_image_threshold(thresholded,
02188                                                  -FLT_MAX, FLT_MAX,
02189                                                  -FLT_MAX, FLT_MAX) );
02190 
02191                 /* Also get rid of NaN, set to zero (what else?) */
02192                 {
02193                     double *data = cpl_image_get_data_double(thresholded);
02194                     int nx = cpl_image_get_size_x(thresholded);
02195                     int ny = cpl_image_get_size_y(thresholded);
02196                     int x, y;
02197         
02198                     for (y = 0; y < ny; y++)
02199                         for (x = 0; x < nx; x++)
02200                             {
02201                                 if (irplib_isnan(data[x + y*nx]))
02202                                     {
02203                                         data[x + y*nx] = 0;
02204                                     }
02205                             }
02206                 }
02207             }
02208 
02209         if (save1d && 
02210             cpl_image_get_size_y(thresholded) == 1 &&
02211             (t == CPL_TYPE_DOUBLE ||
02212              t == CPL_TYPE_FLOAT)) {
02213             
02214             bool invert = false;
02215             if (plist != NULL)
02216                 {
02217                     header = uves_propertylist_duplicate(plist);
02218             
02219                     uves_propertylist_erase_regexp(header, "^CDELT2$", invert);
02220                     uves_propertylist_erase_regexp(header, "^CRPIX2$", invert);
02221                     uves_propertylist_erase_regexp(header, "^CRVAL2$", invert);
02222                     uves_propertylist_erase_regexp(header, "^CTYPE2$", invert);
02223                 }
02224             else
02225                 {
02226                     header = NULL;
02227                 }
02228         
02229             /* Image type must be double, before wrapping it
02230                in a vector */
02231             if (t == CPL_TYPE_FLOAT) {
02232                 thresholded_double = cpl_image_cast(thresholded, CPL_TYPE_DOUBLE);
02233             }
02234             else {
02235                 thresholded_double = cpl_image_duplicate(thresholded);
02236             }
02237         
02238             passure( cpl_image_get_type(thresholded_double) == CPL_TYPE_DOUBLE, "%d",
02239                      cpl_image_get_type(thresholded_double));
02240         
02241             image_1d = cpl_vector_wrap(
02242                 cpl_image_get_size_x(thresholded_double),
02243                 cpl_image_get_data_double(thresholded_double));
02244         
02245             check( uves_vector_save(image_1d, filename, bpp, header, CPL_IO_DEFAULT),
02246                    "Error saving vector to file '%s'", filename );
02247         }
02248         else
02249             {
02250                 check( uves_image_save(thresholded, filename, bpp, plist, CPL_IO_DEFAULT), 
02251                        "Error saving image to file '%s'", filename);
02252             }
02253     }
02254     
02255   cleanup:
02256     uves_unwrap_vector_const(&image_1d);
02257     uves_free_propertylist(&header);
02258     uves_free_image(&thresholded);
02259     uves_free_image(&thresholded_double);
02260     
02261     return;
02262 }
02263 
02264 
02265 /*----------------------------------------------------------------------------*/
02285 /*----------------------------------------------------------------------------*/
02286 void
02287 uves_save_imagelist(const cpl_imagelist *iml, const char *filename, const uves_propertylist *plist)
02288 {
02289     const cpl_image* img=NULL;
02290     cpl_type_bpp bpp;
02291     cpl_type t;
02292     const cpl_vector *image_1d = NULL;
02293     uves_propertylist *header = NULL;
02294     cpl_imagelist *thresholded = NULL;
02295 
02296     int nx = 0;
02297     int ny = 0;
02298     int nz = 0;
02299 
02300     
02301     cknull(iml,"Null input image");
02302     check(img=cpl_imagelist_get_const(iml,0),"error reading image");
02303 
02304     check_nomsg( nx = cpl_image_get_size_x(img));
02305     check_nomsg( ny = cpl_image_get_size_y(img));
02306     check_nomsg( nz = cpl_imagelist_get_size(iml));
02307 
02308     check( t = cpl_image_get_type(img), "Error reading image type");
02309     if      (t == CPL_TYPE_FLOAT ) bpp = CPL_BPP_IEEE_FLOAT;
02310     else if (t == CPL_TYPE_DOUBLE) bpp = CPL_BPP_IEEE_FLOAT;
02311     /* Internal computations in double precision,
02312        save as single precision */
02313 #if CPL_VERSION_CODE >= CPL_VERSION(3, 0, 1)
02314     else if (t == CPL_TYPE_INT   ) bpp = CPL_BPP_16_UNSIGNED;
02315 #else
02316     else if (t == CPL_TYPE_INT   ) bpp = CPL_BPP_16_SIGNED;
02317 #endif
02318     else assure(false, CPL_ERROR_UNSUPPORTED_MODE,
02319         "Unsupported image type '%s'", uves_tostring_cpl_type(t));
02320 
02321 
02322     thresholded = cpl_imagelist_duplicate(iml);
02323     assure_mem( thresholded );
02324 
02325     if (t == CPL_TYPE_DOUBLE)
02326     {
02327         passure( bpp == CPL_BPP_IEEE_FLOAT, "%d", bpp);
02328 
02329         /* Avoid infinities that would happen when casting
02330                double -> float
02331            by thresholding the image to +-FLT_MAX (or, better
02332            a little less than FLT_MAX just to be sure).
02333         
02334            (This is not a really nice solution because it solves the
02335            problem (too large/small values) after it is introduced
02336            (rather than avoiding it), but a general solution of the
02337            problem would probably mean guarding every arithmetic
02338            operation with range checks.)
02339         */
02340         
02341         check_nomsg( cpl_imagelist_threshold(thresholded,
02342                          -FLT_MAX, FLT_MAX,
02343                          -FLT_MAX, FLT_MAX) );
02344 
02345 
02346 
02347         /* Also get rid of NaN, set to zero (what else?) */
02348         {
02349         int x, y, z;
02350         double* data=NULL;
02351         cpl_image* ima=NULL;
02352         for (z = 0; z < nz; z++) {
02353           ima=cpl_imagelist_get(thresholded,z);
02354           data = cpl_image_get_data_double(ima);
02355 
02356           for (y = 0; y < ny; y++) {
02357             for (x = 0; x < nx; x++) {
02358               if (irplib_isnan(data[x + y*nx])) {
02359             data[x + y*nx] = 0;    
02360               }
02361             }
02362           }
02363         }
02364         }
02365     }
02366     if (nz == 1 && t == CPL_TYPE_DOUBLE)
02367     /* To support other types (float, int) we would
02368        need to convert to double first */
02369     {
02370         bool invert = false;
02371         if (plist != NULL)
02372         {
02373             header = uves_propertylist_duplicate(plist);
02374             
02375             uves_propertylist_erase_regexp(header, "^CDELT3$", invert);
02376             uves_propertylist_erase_regexp(header, "^CRPIX3$", invert);
02377             uves_propertylist_erase_regexp(header, "^CRVAL3$", invert);
02378             uves_propertylist_erase_regexp(header, "^CTYPE3$", invert);
02379         }
02380         else
02381         {
02382             header = NULL;
02383         }
02384         /*
02385         image_1d = cpl_vector_wrap(nx,
02386                         cpl_image_get_data_double_const(thresholded));
02387         
02388         check( uves_vector_save(image_1d, filename, bpp, header, CPL_IO_DEFAULT),
02389            "Error saving vector to file '%s'", filename );
02390         */
02391         
02392     }
02393     else
02394     {
02395         check( uves_imagelist_save(thresholded, filename, bpp, plist, CPL_IO_DEFAULT), 
02396            "Error saving image to file '%s'", filename);
02397     }
02398     
02399   cleanup:
02400     uves_unwrap_vector_const(&image_1d);
02401     uves_free_propertylist(&header);
02402     uves_free_imagelist(&thresholded);
02403 
02404     return;
02405 }
02406 
02407 /*----------------------------------------------------------------------------*/
02421 /*----------------------------------------------------------------------------*/
02422 cpl_error_code
02423 uves_save_polynomial(polynomial *p, const char *filename, const uves_propertylist *header)
02424 {
02425     cpl_table *t = NULL;
02426 
02427     check( t = uves_polynomial_convert_to_table(p), "Error converting polynomial to table");
02428     
02429     check( uves_table_save(t, 
02430               NULL,                       /* Primary header, ignored when 
02431                              mode = CPL_IO_EXTEND */
02432               header,                     /* Table header */
02433               filename,
02434               CPL_IO_EXTEND),             /* Append to existing file */
02435        "Error saving table to file '%s'", filename);
02436     
02437   cleanup:
02438     uves_free_table(&t);
02439     return cpl_error_get_code();
02440 }
02441 
02442 
02443 /*----------------------------------------------------------------------------*/
02451 /*----------------------------------------------------------------------------*/
02452 static polynomial *
02453 load_polynomial(const char* filename, int extension)
02454 {
02455     polynomial *p = NULL;  /* Result */
02456     cpl_table  *t = NULL;
02457     
02458     check(t = cpl_table_load(filename,
02459                  extension,
02460                  1),                   /* Mark identified 
02461                               invalid null values (1=yes) */
02462       "Error loading polynomial from extension %d of file '%s'", extension, filename);
02463 
02464     assure( uves_erase_invalid_table_rows(t, NULL) == 0, 
02465         CPL_ERROR_ILLEGAL_INPUT, "Table contains invalid rows");
02466     
02467     check(p = uves_polynomial_convert_from_table(t), "Error converting table to polynomial");
02468 
02469   cleanup:
02470     uves_free_table(&t);
02471     if (cpl_error_get_code() != CPL_ERROR_NONE)
02472     uves_polynomial_delete(&p);
02473     return p;
02474 }
02475 /*----------------------------------------------------------------------------*/
02490 /*----------------------------------------------------------------------------*/
02491 static const char *
02492 identify_arm(const cpl_frameset *frames, const char *blue_tag, const char *red_tag,
02493          bool *blue)
02494 {
02495     const char *tag = NULL; /* Result */
02496     
02497     const cpl_frame *frame = NULL;
02498     
02499     passure( frames != NULL, "");
02500     assure (!cpl_frameset_is_empty(frames), CPL_ERROR_ILLEGAL_INPUT, "No input frames");
02501     
02502     /* Identify blue/red arm */
02503     frame = cpl_frameset_find_const(frames, blue_tag);
02504     *blue = (frame != NULL);
02505     
02506     if (frame == NULL)
02507     {
02508         frame = cpl_frameset_find_const(frames, red_tag);
02509     }
02510     
02511     assure( frame != NULL, CPL_ERROR_ILLEGAL_INPUT, 
02512         "No valid input frames "
02513         "('%s' or '%s') in frame set",
02514         blue_tag, red_tag);
02515     
02516     assure( cpl_frameset_find_const(frames, blue_tag) == NULL ||
02517         cpl_frameset_find_const(frames, red_tag)  == NULL,
02518         CPL_ERROR_INCOMPATIBLE_INPUT,
02519         "Multiple types of input frames ('%s' and '%s') in frame set",
02520         blue_tag, red_tag);
02521     
02522     tag = cpl_frame_get_tag(frame);
02523     
02524     uves_msg("Input frames are '%s'", tag);
02525     
02526 
02527   cleanup:
02528     return tag;
02529 }
02530 
02531 /*----------------------------------------------------------------------------*/
02549 /*----------------------------------------------------------------------------*/
02550 cpl_image *
02551 uves_crop_and_rotate(const cpl_image *image, const uves_propertylist *header,
02552              enum uves_chip chip,
02553              const uves_propertylist *redl_header, 
02554              bool new_format, uves_propertylist **out_header)
02555 {
02556     cpl_image *result = NULL;
02557     int prescanx, ovrscanx;
02558     int nx, ny;
02559     int x_0, y_0, x_1, y_1; /* Extracted area (inclusive) in 
02560                    FITS convention (i.e. counting from 1) */
02561 
02562     const char *ctype1, *ctype2; /* Geometry */
02563     const char *bunit;
02564     double crval1, crval2;
02565     double crpix1, crpix2;
02566     double cdelt1, cdelt2;
02567 
02568 
02569     passure( image != NULL, " ");
02570     passure( header != NULL, " ");
02571     passure( out_header != NULL, " ");
02572     
02573     nx = cpl_image_get_size_x(image);
02574     ny = cpl_image_get_size_y(image);
02575 
02576 
02577     /* Determine pre- and overscan areas */
02578     check( prescanx = uves_pfits_get_prescanx(header, chip), "Could not read x-prescan info" );
02579     check( ovrscanx = uves_pfits_get_ovrscanx(header, chip), "Could not read x-overscan info");
02580   
02581     /* Don't try to read the y pre- and overscan regions, which should be zero for UVES.
02582        The keywords are not present in older UVES data. */
02583 
02584     /* Read geometry */
02585     check( ctype1 = uves_pfits_get_ctype1(header), "Error reading keyword");
02586     check( ctype2 = uves_pfits_get_ctype2(header), "Error reading keyword");
02587     check( crval1 = uves_pfits_get_crval1(header), "Error reading keyword");
02588     check( crval2 = uves_pfits_get_crval2(header), "Error reading keyword");
02589     check( crpix1 = uves_pfits_get_crpix1(header), "Error reading keyword");
02590     check( crpix2 = uves_pfits_get_crpix2(header), "Error reading keyword");
02591     check( cdelt1 = uves_pfits_get_cdelt1(header), "Error reading keyword");
02592     check( cdelt2 = uves_pfits_get_cdelt2(header), "Error reading keyword");
02593     if (uves_propertylist_contains(header, UVES_BUNIT))
02594     {
02595         bunit = uves_pfits_get_bunit(header);
02596     }
02597     else
02598     {
02599         bunit = " ";
02600     }
02601     
02602 
02603     /* Crop the image */
02604     {
02605     y_0 = 1;
02606     y_1 = ny;
02607     if (new_format || chip == UVES_CHIP_BLUE)
02608         {
02609         x_0 = prescanx + 1;
02610         x_1 = nx - ovrscanx;
02611         }
02612     else /* red, old format */
02613         {
02614         if (chip == UVES_CHIP_REDU)
02615             {
02616             x_0 = prescanx + 1;
02617             x_1 = nx/2 - ovrscanx;
02618             }
02619         else
02620             { /* lower */
02621             x_0 = nx/2 + prescanx + 1;
02622             x_1 = nx - ovrscanx;
02623             }
02624         }
02625     
02626     check( result = cpl_image_extract(image, x_0, y_0, x_1, y_1), "Could not crop image");
02627     crpix1 = crpix1 - (x_0 - 1);
02628     crpix2 = crpix2 - (y_0 - 1);
02629     nx = (x_1 - x_0) + 1;
02630     ny = (y_1 - y_0) + 1;
02631     }
02632 
02633     UVES_TIME_START("Rotation");
02634     /* ... is a bit slow, and there's probably nothing to
02635        do about as it involves moving data between remote
02636        places in memory.
02637     */
02638 
02639     /* Rotate the image into standard orientation */
02640     {
02641     int crpix1_old = crpix1;
02642     int crpix2_old = crpix2;
02643     int crval1_old = crval1;
02644     int crval2_old = crval2;
02645     int cdelt1_old = cdelt1;
02646     int cdelt2_old = cdelt2;
02647     const char *ctype1_old = ctype1;
02648     const char *ctype2_old = ctype2;
02649 
02650     if (chip == UVES_CHIP_BLUE)
02651         {
02652         /* 90 deg counterclockwise rotation */
02653         check( cpl_image_turn(result, -1), "Could not turn image");
02654         
02655         crpix1 = ny - (crpix2_old - 1); /* Note: old value of ny */
02656         crpix2 = crpix1_old;
02657         crval1 = crval2_old;
02658         crval2 = crval1_old;
02659         }
02660     else 
02661         {
02662         /* Red */
02663         /* Flip image around y=-x */
02664         check( cpl_image_flip(result, 3), "Could not flip image");
02665 
02666         crpix1 = ny - (crpix2_old - 1); /* Note: old value of nx, ny */
02667         crpix2 = nx - (crpix1_old - 1);
02668         crval1 = crval2_old;
02669         crval2 = crval1_old;
02670         }
02671 
02672 
02673     /* Always swap these ones */
02674     ctype1 = ctype2_old;
02675     ctype2 = ctype1_old;
02676     cdelt1 = cdelt2_old;
02677     cdelt2 = cdelt1_old;
02678     }
02679 
02680     UVES_TIME_END;
02681 
02682     /* Here we should use the CROTAi keywords to 
02683        properly describe the new rotation */
02684     
02685     /* Instead, redefine CRVAL as in the following, on request from DFO */
02686 
02687     crpix1 = 1;
02688     crpix2 = 1;
02689     if (chip == UVES_CHIP_BLUE || chip == UVES_CHIP_REDL)
02690     {
02691         crval1 = 1;
02692         crval2 = 1;
02693     }
02694     else 
02695     {
02696             int physical_gap_between_chips = 64; /* Pixels. Unbinned. Hardcoded. */
02697 
02698 
02699         passure( chip == UVES_CHIP_REDU , "%d", chip );
02700         
02701         crval1 = 1;
02702         
02703         /* Set CRVAL2 = REDL_height - REDL_overscan - REDL_prescan + gap. */
02704         if (new_format)
02705         {
02706 
02707             check( crval2 = 1 +
02708                (uves_pfits_get_naxis1(redl_header) -
02709                 uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL) -
02710                 uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL)) *
02711                uves_pfits_get_cdelt1(redl_header) +
02712                            physical_gap_between_chips,
02713                "Error reading REDL chip geometry");
02714 
02715             uves_msg_debug("Setting CRVAL2 = 1 + (%d - %d - %d) * %f + %d = %f",
02716                    uves_pfits_get_naxis1(redl_header),
02717                    uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL),
02718                    uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL),
02719                    uves_pfits_get_cdelt1(redl_header),
02720                                    physical_gap_between_chips, crval2);
02721         }
02722         else
02723         {
02724 
02725             /* old format */
02726             check( crval2 = 1 +
02727                (uves_pfits_get_naxis1(header)/2 -
02728                 uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL) -
02729                 uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL)) *
02730                uves_pfits_get_cdelt1(redl_header) +
02731                            physical_gap_between_chips,
02732                "Error reading REDL chip geometry");
02733 
02734             uves_msg_debug("Setting CRVAL2 = 1 + (%d - %d - %d) * %f + %d = %f",
02735                    uves_pfits_get_naxis1(header)/2, 
02736                    uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL),
02737                    uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL),
02738                    uves_pfits_get_cdelt1(redl_header),
02739                                    physical_gap_between_chips, crval2);
02740         }
02741 
02742     }
02743 
02744 
02745     /* Update header with new geometry */
02746     check( *out_header = uves_initialize_image_header(ctype1, ctype2, bunit,
02747                               crval1, crval2,
02748                               crpix1, crpix2,
02749                               cdelt1, cdelt2),
02750        "Error initializing header");
02751 
02752     //check(uves_propertylist_copy_property_regexp(*out_header, header,
02753     //                      "^ESO ", 0),
02754     //   "Error copying hieararch keys");
02755 
02756 
02757     uves_msg("Raw image cropped and rotated from %dx%d to %dx%d",
02758          nx, ny,
02759          cpl_image_get_size_x(result),
02760          cpl_image_get_size_y(result));     
02761 
02762   cleanup:
02763     if (cpl_error_get_code() != CPL_ERROR_NONE)
02764     {
02765         uves_free_image(&result);
02766         if (out_header != NULL)
02767         {
02768             uves_free_propertylist(out_header);
02769         }
02770     }
02771 
02772     return result;
02773 }
02774 
02775 /*----------------------------------------------------------------------------*/
02789 /*----------------------------------------------------------------------------*/
02790 void
02791 uves_warn_if_chip_names_dont_match(const uves_propertylist *calib_header, 
02792                   const char *raw_chip_name, enum uves_chip chip)
02793 {
02794     const char *calib_chip_name;
02795     bool mismatch = false;
02796 
02797     check( calib_chip_name = uves_pfits_get_chipid(calib_header, chip),
02798        "Could not read chip name of calibration data");
02799 
02800 
02801     /* Ignore leading/trailing blanks when comparing name strings.
02802      * (The following is O(n^2) where n is the string length, 
02803      * but that's ok because the strings stored in a FITS card are short).
02804      */
02805     {
02806     unsigned int calib_first, calib_last;  /* inclusive */
02807     unsigned int raw_first, raw_last;
02808     
02809     calib_first = 0;
02810     raw_first = 0;
02811     while (calib_chip_name[calib_first] == ' ' && calib_first < strlen(calib_chip_name) - 1)
02812         {
02813         calib_first++;
02814         }
02815     while (raw_chip_name[raw_first] == ' ' && raw_first < strlen(raw_chip_name) - 1)
02816         {
02817         raw_first++;
02818         }
02819 
02820     calib_last = strlen(calib_chip_name) - 1;
02821     raw_last = strlen(raw_chip_name) - 1;
02822     while (calib_chip_name[calib_last] == ' ' && calib_last > 0)
02823         {
02824         calib_last--;
02825         }
02826     while (raw_chip_name[raw_last] == ' ' && raw_last > 0)
02827         {
02828         raw_last--;
02829         }
02830 
02831     /* Compare substrings */
02832     if (calib_last - calib_first != raw_last - raw_first)
02833         {
02834         mismatch = true;
02835         }
02836     else
02837         {
02838         unsigned int i;
02839         
02840         for (i = 0; i <= (calib_last - calib_first); i++)
02841             {
02842             if (raw_chip_name[raw_first + i] != 
02843                 calib_chip_name[calib_first + i])
02844                 {
02845                 mismatch = true;
02846                 }
02847             }
02848         }
02849     }
02850 
02851 
02852     if (mismatch)
02853     {
02854         uves_msg_warning("Calibration frame chip ID '%s' does "
02855                  "not match raw frame chip ID '%s'",
02856                  calib_chip_name, raw_chip_name);
02857     }
02858 
02859   cleanup:
02860     return;
02861 }
02862 
02863 
02864 /*----------------------------------------------------------------------------*/
02886 /*----------------------------------------------------------------------------*/
02887 
02888 static cpl_error_code
02889 load_raw_image(const char *filename, 
02890                cpl_type type,
02891                bool flames,
02892                bool blue,
02893                cpl_image *raw_image[2],
02894                uves_propertylist *raw_header[2], 
02895                uves_propertylist *rotated_header[2])
02896 {
02897 
02898  
02899     cpl_image *image = NULL;
02900     uves_propertylist *primary_header = NULL;
02901     uves_propertylist *ext_header = NULL;
02902     int extension, nextensions;
02903     bool new_format;
02904     int plane = 0;   /* Only one plane in FLAMES/UVES raw files */
02905 
02906     cpl_image* image1=NULL;
02907     cpl_image* image2=NULL;
02908     int sx=0;
02909     int sy=0;
02910 
02911 
02912     /* Initialize parameters */
02913     raw_image[0] = NULL;
02914     raw_image[1] = NULL;
02915     raw_header[0] = NULL;
02916     raw_header[1] = NULL;
02917     rotated_header[0] = NULL;
02918     rotated_header[1] = NULL;
02919 
02920     check( nextensions = uves_get_nextensions(filename),
02921        "Error reading number of extensions of file '%s'", filename);
02922 
02923     /* Find out if new/old format */
02924     extension = 0;
02925     check( primary_header = uves_propertylist_load(filename,
02926                           extension),
02927        "Could not load header from extension %d of file '%s'", 
02928        extension, filename);
02929 
02930     check( new_format = uves_format_is_new(primary_header),
02931        "Error determining new/old format of file %s", filename);
02932  
02933     uves_msg_low("Raw frame is %s, %s format, file '%s' has %d extensions", 
02934          (blue) ? "blue" : "red", (new_format) ? "new" : "old", 
02935          filename, nextensions);
02936 
02937     /* If the raw frame is blue, or if it's an old format red frame */
02938     if (blue || !new_format)
02939     {
02940         enum uves_chip chip;
02941         
02942         uves_msg_debug("Frame is blue or old format");
02943 
02944         assure( nextensions == 0 || 
02945                 (blue   && nextensions == 2) ||
02946                 (flames && nextensions == 2),
02947                 CPL_ERROR_ILLEGAL_INPUT,
02948                 "Unrecognized format of file '%s'. %d extensions expected. %d found.",
02949                 filename,
02950                 ((flames||blue) && (nextensions ==2)) ? 2 : 0, nextensions);
02951 
02952         /* FLAMES: the 2 extensions contain OzPoz table and FLAMES FIBRE table */
02953 
02954        /* Load the header */
02955         check( raw_header[0] = uves_propertylist_load(filename,
02956                              extension),
02957            "Could not load header from extension %d of file '%s'", 
02958            extension, filename);
02959 
02960 
02961         extension = 0;
02962         if(blue && nextensions == 2) {
02963            extension = 1;
02964            check( raw_header[1] = uves_propertylist_load(filename,
02965                                                          extension),
02966                   "Could not load header from extension %d of file '%s'",
02967                   extension, filename);
02968            check( uves_propertylist_append(raw_header[0],raw_header[1]),
02969                   "Could not collate header from extension 1 to 0 of file '%s'",filename);
02970            uves_free_propertylist(&raw_header[1]);
02971  
02972            check( image1 = cpl_image_load(filename,
02973                                           type,
02974                                           plane,   
02975                                           extension
02976                      ), "Could not load image from extension %d of file '%s' ", 
02977                   extension, filename);
02978            cpl_image_save(image1, "ima1.fits", CPL_BPP_IEEE_FLOAT,
02979                           NULL,CPL_IO_DEFAULT);
02980 
02981            extension = 2;
02982            check( image2 = cpl_image_load(filename,
02983                                           type,
02984                                           plane,   
02985                                           extension
02986                      ), "Could not load image from extension %d of file '%s' ", 
02987                   extension, filename);
02988            check_nomsg(sx=cpl_image_get_size_x(image1));
02989            check_nomsg(sy=cpl_image_get_size_y(image1));
02990 
02991            check_nomsg(image=cpl_image_new(2*sx,sy,type));
02992            check_nomsg(cpl_image_copy(image,image1,1,1));
02993            check_nomsg(cpl_image_copy(image,image2,1+sx,1));
02994 
02995            
02996            uves_free_image(&image1);
02997            uves_free_image(&image2);
02998 
02999            extension = 1;
03000 
03001 
03002 
03003         } else {
03004 
03005 
03006         check( image = cpl_image_load(filename,
03007                       type,
03008                       plane,   
03009                       extension
03010                ), "Could not load image from extension %d of file '%s' ", 
03011            extension, filename);
03012         }
03013  
03014         /* Get blue (or lower red) chip */
03015         chip = (blue) ? UVES_CHIP_BLUE : UVES_CHIP_REDL;
03016         check( raw_image[0] = uves_crop_and_rotate(image, raw_header[0], 
03017                                chip, raw_header[0],
03018                                new_format, 
03019                                &rotated_header[0]),
03020            "Error splitting image");
03021         
03022         if (!blue)
03023         {
03024             const uves_propertylist *redl_header;
03025 
03026             /* Upper red chip, use again the primary header */
03027             check( raw_header[1] = uves_propertylist_duplicate(raw_header[0]),
03028                "Error duplicating FITS header");
03029             
03030             /* Get upper red chip */
03031             chip = UVES_CHIP_REDU;
03032             redl_header = raw_header[0];
03033             check( raw_image[1] = uves_crop_and_rotate(image, raw_header[1],
03034                                    chip, redl_header,
03035                                    new_format,
03036                                    &rotated_header[1]),
03037                "Error splitting red image");
03038         }
03039         else
03040         {
03041             raw_image[1] = NULL;
03042             raw_header[1] = NULL;
03043             rotated_header[1] = NULL;
03044         }
03045     }
03046     else
03047     /* New red format. UVES must have 2 extensions,
03048      * FLAMES must have 2 or more extensions
03049      */
03050     {
03051         uves_msg_debug("Frame is red, new format");
03052         
03053         assure( nextensions >= 2, CPL_ERROR_UNSUPPORTED_MODE,
03054             "File '%s' (red frame) has %d extensions. 2+ extensions expected "
03055                     "for new format",
03056             filename, nextensions);
03057         
03058         uves_msg_debug("New red format, %s frame",
03059                (nextensions > 2) ? "FLAMES" : "FLAMES/UVES");
03060         
03061 
03062         /* Images always in extension 1 and 2. First load just the headers */
03063         for (extension = 1; extension <= 2; extension++)
03064         {
03065             /* In the FITS file, REDU is stored
03066                in extension 1, and REDL is stored in
03067                extension 2 */
03068             enum uves_chip chip = (extension == 1) ? UVES_CHIP_REDU : UVES_CHIP_REDL;
03069             int indx = uves_chip_get_index(chip);
03070 
03071             /* Load the extension header */
03072             uves_free_propertylist(&ext_header);
03073             check( ext_header = uves_propertylist_load(filename,
03074                                   extension),
03075                "Could not load header from extension %d of file '%s'", 
03076                extension, filename);
03077             
03078             /* Merge with primary header */
03079             check( raw_header[indx] = uves_propertylist_duplicate(primary_header),
03080                "Error cloning primary header");
03081             
03082             if (!uves_propertylist_is_empty(ext_header))
03083             {
03084                 check( uves_propertylist_copy_property_regexp(raw_header[indx],
03085                                      ext_header, ".*", 0),
03086                    "Error merging primary header with extension %d header", 
03087                    extension);
03088             }
03089         }
03090 
03091 
03092         /* Remove pre-, overscan areas (we needed to load both image headers for this) */
03093         for (extension = 1; extension <= 2; extension++)
03094         {
03095             enum uves_chip chip = (extension == 1) ? UVES_CHIP_REDU : UVES_CHIP_REDL;
03096             int indx      = uves_chip_get_index(chip);
03097             int indx_redl = uves_chip_get_index(UVES_CHIP_REDL);
03098             
03099             const uves_propertylist *redl_header = raw_header[indx_redl];
03100             
03101             uves_free_image(&image);
03102             check( image = cpl_image_load(filename,
03103                           type,
03104                           plane,               
03105                           extension),
03106                "Could not load image from extension %d of file '%s' ", 
03107                extension, filename);
03108             
03109             check( raw_image[indx] = uves_crop_and_rotate(image, 
03110                                   raw_header[indx],
03111                                   chip, redl_header,
03112                                   new_format,
03113                                   &rotated_header[indx]),
03114                "Error splitting red image");
03115         }
03116 
03117         
03118     }/* if new format */
03119  
03120 
03121   cleanup:
03122     uves_free_image(&image);
03123     uves_free_image(&image1);
03124     uves_free_image(&image2);
03125 
03126     uves_free_propertylist(&primary_header);
03127     uves_free_propertylist(&ext_header);
03128 
03129     if (cpl_error_get_code() != CPL_ERROR_NONE)
03130     {
03131         uves_free_image       (&raw_image[0]);
03132         uves_free_image       (&raw_image[1]);
03133         uves_free_propertylist(&raw_header[0]);
03134         uves_free_propertylist(&raw_header[1]);
03135         uves_free_propertylist(&rotated_header[0]);
03136         uves_free_propertylist(&rotated_header[1]);
03137     }
03138     
03139     return cpl_error_get_code();
03140 }
03141 
03142 
03143 /*----------------------------------------------------------------------------*/
03171 /*----------------------------------------------------------------------------*/
03172 cpl_error_code
03173 uves_load_raw_imagelist(const cpl_frameset *frames,
03174             bool flames,
03175             const char *blue_tag, const char *red_tag, cpl_type type, 
03176             cpl_imagelist *images[2],
03177             uves_propertylist **raw_headers[2], uves_propertylist *rotated_header[2],
03178             bool *blue)
03179 {
03180     const char *tag           = NULL;
03181     const cpl_frame *frame    = NULL;
03182     cpl_image *temp_image[2]  = {NULL, NULL};
03183     uves_propertylist *temp_header[2] = {NULL, NULL};
03184     int number_of_frames = 0;
03185     int frameset_size = 0;   /* Keeps track of number of raw_header pointers allocated */
03186     int nchips;
03187     int chip;
03188     
03189     raw_headers[0] = NULL;
03190     raw_headers[1] = NULL;
03191 
03192     check( frameset_size = cpl_frameset_get_size(frames),
03193        "Error reading frameset size");
03194 
03195     check( tag = identify_arm(frames, blue_tag, red_tag, blue),
03196        "Could not identify chip type");
03197     
03198     nchips = (*blue) ? 1 : 2;
03199     for(chip = 0; chip < nchips; chip++)
03200     {
03201         images[chip] = NULL;
03202         rotated_header[chip] = NULL;
03203         
03204         images[chip] = cpl_imagelist_new();
03205         raw_headers[chip] = cpl_calloc(frameset_size, sizeof(uves_propertylist *));
03206     }
03207 
03208     /* Load all input images with correct tag,
03209        split,
03210        insert into image list(s) */  
03211 
03212     number_of_frames = 0;
03213     for(frame = cpl_frameset_get_first_const(frames);
03214     frame != NULL;
03215     frame = cpl_frameset_get_next_const(frames))
03216     {
03217         /* If match */
03218         if ( strcmp(cpl_frame_get_tag(frame), tag) == 0)
03219         {
03220             const char *filename = cpl_frame_get_filename(frame);
03221             
03222             /* Load image + header */
03223             uves_free_propertylist(&rotated_header[0]);
03224             uves_free_propertylist(&rotated_header[1]);
03225             
03226             check( load_raw_image(filename,
03227                       type,
03228                       flames,
03229                       *blue,
03230                       temp_image,
03231                       temp_header,
03232                       rotated_header),
03233                "Could not load image from file '%s'", filename);
03234             
03235             /* Append to image lists */
03236             for(chip = 0; chip < nchips; chip++)
03237             {
03238                 raw_headers[chip][number_of_frames] = temp_header[chip];
03239                 temp_header[chip] = NULL;
03240                 
03241                 check( cpl_imagelist_set(images[chip],
03242                              temp_image[chip],
03243                              /* Position */
03244                              cpl_imagelist_get_size(images[chip])
03245                        ),
03246                    "Could not insert image into image list");
03247                 
03248                 /* Don't deallocate image or header */
03249                 temp_image[chip] = NULL;
03250             }
03251             
03252             number_of_frames += 1;
03253         }
03254     }
03255 
03256     /* Check that image sizes are identical */
03257     
03258     for(chip = 0; chip < nchips; chip++)
03259     {
03260         /* This function returns zero iff the list is uniform */
03261         assure (cpl_imagelist_is_uniform(images[chip]) == 0,
03262             CPL_ERROR_INCOMPATIBLE_INPUT, 
03263             "Input images are not of same size and type");
03264         
03265         passure( cpl_imagelist_get_size(images[chip]) == number_of_frames, 
03266              "%d %d", cpl_imagelist_get_size(images[0]), number_of_frames);
03267 
03268     }
03269 
03270     
03271     /* Check central wavelengths (not bias/dark) */
03272     if ( strcmp(UVES_BIAS (*blue), tag) != 0 &&
03273      strcmp(UVES_DARK (*blue), tag) != 0 &&
03274      strcmp(UVES_PDARK(*blue), tag) != 0) {
03275     enum uves_chip chip_id;
03276     int i;
03277     double wlen = 0;
03278     
03279     for (chip_id = uves_chip_get_first(*blue); 
03280          chip_id != UVES_CHIP_INVALID;
03281          chip_id = uves_chip_get_next(chip_id)) {
03282         for (i = 0; i < number_of_frames; i++) {
03283         if (i == 0) {
03284             check( wlen = uves_pfits_get_gratwlen(
03285                    raw_headers[uves_chip_get_index(chip_id)][i], chip_id),
03286                "Error reading central wavelength of input frame number %d", i+1);
03287         }
03288         else {
03289             double w;
03290             
03291             check( w = uves_pfits_get_gratwlen(
03292                    raw_headers[uves_chip_get_index(chip_id)][i], chip_id),
03293                "Error reading central wavelength of input frame number %d", i+1);
03294             
03295             assure( fabs((w-wlen)/wlen) < 0.01, CPL_ERROR_INCOMPATIBLE_INPUT,
03296                 "Mis-matching input frame central wavelengths: "
03297                 "%e (frame 1) != %e (frame %d)", wlen, w, i+1);
03298         }
03299         }
03300     }
03301     }
03302     
03303   cleanup:
03304     uves_free_image(&temp_image[0]);
03305     uves_free_image(&temp_image[1]);
03306     uves_free_propertylist(&temp_header[0]);
03307     uves_free_propertylist(&temp_header[1]);
03308     
03309     if (cpl_error_get_code() != CPL_ERROR_NONE) {
03310     if (raw_headers[0] != NULL) {
03311         int i;
03312         for (i = 0; i < frameset_size; i++)    {
03313         if (raw_headers[0] != NULL) uves_free_propertylist(&raw_headers[0][i]);
03314         if (raw_headers[1] != NULL) uves_free_propertylist(&raw_headers[1][i]);
03315         }
03316     }
03317     cpl_free(raw_headers[0]); raw_headers[0] = NULL;
03318     cpl_free(raw_headers[1]); raw_headers[1] = NULL;
03319     
03320     uves_free_imagelist(&images[0]);
03321     uves_free_imagelist(&images[1]);
03322     
03323     uves_free_propertylist(&rotated_header[0]);
03324     uves_free_propertylist(&rotated_header[1]);
03325     }
03326 
03327     return cpl_error_get_code();
03328 }
03329 
03330 
03331 /*----------------------------------------------------------------------------*/
03348 /*----------------------------------------------------------------------------*/
03349 cpl_error_code
03350 uves_load_orderpos(const cpl_frameset *frames,
03351            bool flames,
03352            const char **raw_filename,
03353            cpl_image *raw_image[2],
03354            uves_propertylist *raw_header[2], 
03355            uves_propertylist *rotated_header[2], bool *blue)
03356 {
03357     const char *tags[4];
03358 
03359     int number_of_tags = sizeof(tags) / sizeof(char *);
03360     int indx;
03361 
03362     /* Warning: Duplicate logic. The number of tags must match the size of the
03363        tags array defined above */
03364     tags[0] = UVES_ORDER_FLAT(flames, false); /* red */
03365     tags[1] = UVES_ORDER_FLAT(flames, true);  /* blue */
03366     tags[2] = UVES_STD_STAR(false);
03367     tags[3] = UVES_STD_STAR(true);
03368 
03369     if (flames)
03370     {
03371         *blue = false;
03372         number_of_tags = 1;
03373 
03374         check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx,
03375                            NULL),
03376            "Could not find raw frame (%s) in SOF", 
03377            tags[0]);
03378         
03379     }
03380     else
03381     {    
03382         check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx,
03383                            NULL),
03384            "Could not find raw frame (%s, %s, %s, or %s) in SOF", 
03385            tags[0], tags[1], tags[2], tags[3]);
03386         
03387         *blue = (indx == 1) || (indx == 3);
03388     }
03389 
03390     /* Load the image */
03391     check( load_raw_image(*raw_filename,
03392               CPL_TYPE_DOUBLE,
03393               flames,
03394               *blue,
03395               raw_image,
03396               raw_header,
03397               rotated_header),
03398        "Error loading image from file '%s'", *raw_filename);
03399     
03400     passure( !flames || !(*blue), "%d %d",
03401          flames, *blue );
03402 
03403   cleanup:
03404     if (cpl_error_get_code() != CPL_ERROR_NONE)
03405     {
03406         *raw_filename = NULL;
03407     }
03408     
03409     return cpl_error_get_code();
03410 }
03411 
03412 /*----------------------------------------------------------------------------*/
03428 /*----------------------------------------------------------------------------*/
03429 cpl_error_code
03430 uves_load_formatcheck(const cpl_frameset *frames,
03431               bool flames,
03432               const char **raw_filename,
03433               cpl_image *raw_image[2],
03434               uves_propertylist *raw_header[2], 
03435               uves_propertylist *rotated_header[2], bool *blue)
03436 {
03437     const char *tags[2];
03438     int number_of_tags = sizeof(tags) / sizeof(char *);
03439     int indx;
03440 
03441     tags[0] = UVES_FORMATCHECK(flames, false);   /* red */
03442     tags[1] = UVES_FORMATCHECK(flames, true);    /* blue */
03443     if (flames)
03444     {
03445         *blue = false;
03446         number_of_tags = 1;
03447 
03448         check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
03449            "Could not find raw frame (%s) in SOF",
03450            tags[0]);
03451     }
03452     else
03453     {
03454         check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
03455            "Could not find raw frame (%s or %s) in SOF", 
03456            tags[0], tags[1]);
03457         
03458         *blue = (indx == 1);
03459     }
03460 
03461     /* Load the image */
03462     check( load_raw_image(*raw_filename,
03463               CPL_TYPE_DOUBLE,
03464               flames,
03465               *blue,
03466               raw_image,
03467               raw_header,
03468               rotated_header),
03469        "Error loading image from file '%s'", *raw_filename);
03470    
03471   cleanup:
03472     if (cpl_error_get_code() != CPL_ERROR_NONE) 
03473     {
03474         *raw_filename = NULL;
03475     }
03476     return cpl_error_get_code();
03477 }
03478 
03479 /*----------------------------------------------------------------------------*/
03498 /*----------------------------------------------------------------------------*/
03499 void uves_load_cd_align(const cpl_frameset *frames,
03500             const char **raw_filename1,
03501             const char **raw_filename2,
03502             cpl_image *raw_image1[2],
03503             cpl_image *raw_image2[2],
03504             uves_propertylist *raw_header1[2], 
03505             uves_propertylist *raw_header2[2], 
03506             uves_propertylist *rotated_header1[2], 
03507             uves_propertylist *rotated_header2[2], 
03508             bool *blue)
03509 {
03510     const char *tags[2];
03511     int number_of_tags = sizeof(tags) / sizeof(char *);
03512     int indx;
03513     bool flames = false;
03514     const cpl_frame *frame;
03515 
03516     tags[0] = UVES_CD_ALIGN(false);   /* red */
03517     tags[1] = UVES_CD_ALIGN(true);    /* blue */
03518 
03519     check( *raw_filename1 = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
03520        "Could not find raw frame (%s or %s) in SOF", 
03521        tags[0], tags[1]);
03522     
03523     *blue = (indx == 1);
03524 
03525     assure( cpl_frameset_count_tags(frames, tags[indx]) == 2,
03526         CPL_ERROR_ILLEGAL_INPUT,
03527         "%d %s frames found. Exactly 2 required",
03528         cpl_frameset_count_tags(frames, tags[indx]), tags[indx] );
03529 
03530     /* Load the two frames */
03531     {
03532     int n = 1;
03533     for (frame = cpl_frameset_get_first_const(frames);
03534          frame != NULL;
03535          frame = cpl_frameset_get_next_const(frames))
03536         {
03537         if (strcmp(cpl_frame_get_tag(frame), tags[indx]) == 0)
03538             {
03539             if (n == 1)
03540                 {
03541                 *raw_filename1 = cpl_frame_get_filename(frame);
03542                 }
03543             else
03544                 {
03545                 *raw_filename2 = cpl_frame_get_filename(frame);
03546                 }
03547             
03548             check( load_raw_image(n == 1 ? 
03549                           *raw_filename1 :
03550                           *raw_filename2,
03551                           CPL_TYPE_DOUBLE,
03552                           flames,
03553                           *blue,
03554                           n == 1 ?
03555                           raw_image1 :
03556                           raw_image2,
03557                           n == 1 ?
03558                           raw_header1 :
03559                           raw_header2,
03560                           n == 1 ?
03561                           rotated_header1 :
03562                           rotated_header2),
03563                    "Error loading image from file '%s'",
03564                    n == 1 ? *raw_filename1 : *raw_filename2);
03565 
03566             n++;
03567             }
03568         }
03569     }
03570     
03571   cleanup:
03572     if (cpl_error_get_code() != CPL_ERROR_NONE) 
03573     {
03574         *raw_filename1 = NULL;
03575         *raw_filename2 = NULL;
03576     }
03577     
03578     return;
03579 }
03580 
03581 
03582 /*----------------------------------------------------------------------------*/
03603 /*----------------------------------------------------------------------------*/
03604 void
03605 uves_load_arclamp(const cpl_frameset *frames,
03606           bool flames,
03607           const char **raw_filename, 
03608           cpl_image *raw_image[2], uves_propertylist *raw_header[2],
03609           uves_propertylist *rotated_header[2], bool *blue,
03610           bool *sim_cal)
03611 {
03612     const char *tags[4];
03613 
03614     int number_of_tags = sizeof(tags) / sizeof(char *);
03615     int indx;
03616 
03617     /* Warning: duplicate logic. Array size above must match */
03618     if (flames)
03619     {
03620         assure_nomsg( sim_cal != NULL, CPL_ERROR_NULL_INPUT );
03621 
03622         tags[0] = UVES_ARC_LAMP(flames, true);  /* blue flag not used */
03623         tags[1] = FLAMES_FIB_SCI_SIM;
03624 
03625         number_of_tags = 2;
03626         *blue = false;
03627 
03628         check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
03629            "Could not find raw frame (%s or %s) in SOF", 
03630            tags[0], tags[1]);
03631         
03632         *sim_cal = (indx == 1);
03633     }
03634     else
03635     {
03636         tags[0] = UVES_ARC_LAMP(flames, true);
03637         tags[1] = UVES_ARC_LAMP(flames, false);
03638         tags[2] = UVES_ECH_ARC_LAMP(true);
03639         tags[3] = UVES_ECH_ARC_LAMP(false);
03640 
03641         check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
03642            "Could not find raw frame (%s, %s, %s or %s) in SOF", 
03643            tags[0], tags[1], tags[2], tags[3]);
03644         
03645         *blue = (indx == 0 || indx == 2);
03646     }
03647     
03648     /* Load the image */
03649     check( load_raw_image(*raw_filename,
03650               CPL_TYPE_DOUBLE,
03651               flames,
03652               *blue,
03653               raw_image,
03654               raw_header,
03655               rotated_header),
03656        "Error loading image from file '%s'", *raw_filename);
03657 
03658   cleanup:
03659     if (cpl_error_get_code() != CPL_ERROR_NONE) {
03660     *raw_filename = NULL;
03661     uves_free_image       (raw_image);
03662     uves_free_propertylist(raw_header);
03663     }
03664     return;
03665 }
03666 
03667 /*----------------------------------------------------------------------------*/
03682 /*----------------------------------------------------------------------------*/
03683 cpl_error_code
03684 uves_load_science(const cpl_frameset *frames, const char **raw_filename, 
03685           cpl_image *raw_image[2], 
03686           uves_propertylist *raw_header[2], 
03687           uves_propertylist *rotated_header[2], 
03688           bool *blue,
03689           const char **sci_type)
03690 {
03691     /* Note: the two following arrays must match */
03692     const char *tags[] = 
03693     { 
03694         UVES_SCIENCE(true), UVES_SCIENCE(false),
03695         UVES_SCI_EXTND(true), UVES_SCI_EXTND(false),
03696         UVES_SCI_POINT(true), UVES_SCI_POINT(false),
03697         UVES_SCI_SLICER(true), UVES_SCI_SLICER(false),
03698         UVES_TFLAT(true), UVES_TFLAT(false) 
03699     };
03700 
03701     const char *type[] = 
03702     {
03703         "SCIENCE", "SCIENCE",
03704         "SCI_EXTND", "SCI_EXTND",
03705         "SCI_POINT", "SCI_POINT",
03706         "SCI_SLICER", "SCI_SLICER",
03707         "TFLAT", "TFLAT",
03708     };
03709 
03710     int number_of_tags = sizeof(tags) / sizeof(char *);
03711     int indx;
03712     bool flames = false;
03713 
03714     check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
03715        "No science frame (%s, %s, %s, %s, %s, %s, %s, %s, %s or %s) in SOF", 
03716        tags[0], tags[1], tags[2], tags[3], 
03717        tags[4], tags[5], tags[6], tags[7], tags[7], tags[8]);
03718 
03719     *blue = (indx % 2 == 0);
03720     *sci_type = type[indx];
03721     
03722     /* Load the image */
03723     check( load_raw_image(*raw_filename,
03724               CPL_TYPE_DOUBLE,
03725               flames,
03726               *blue,
03727               raw_image,
03728               raw_header,
03729               rotated_header),
03730        "Error loading image from file '%s'", *raw_filename);
03731   cleanup:
03732     if (cpl_error_get_code() != CPL_ERROR_NONE)
03733     {
03734         *raw_filename = NULL;
03735         uves_free_image       (raw_image);
03736         uves_free_propertylist(raw_header);
03737     }
03738     return cpl_error_get_code();
03739 }
03740 
03741 /*----------------------------------------------------------------------------*/
03758 /*----------------------------------------------------------------------------*/
03759 cpl_error_code
03760 uves_load_standard(const cpl_frameset *frames, const char **raw_filename, 
03761            cpl_image *raw_image[2],
03762            uves_propertylist *raw_header[2], 
03763            uves_propertylist *rotated_header[2], bool *blue)
03764 {
03765     const char *tags[] = { UVES_STD_STAR(true), UVES_STD_STAR(false) };
03766     int number_of_tags = sizeof(tags) / sizeof(char *);
03767     int indx;
03768     bool flames = false;
03769     
03770     check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
03771        "Could not identify raw frame (%s or %s) in SOF", tags[0], tags[1]);
03772 
03773     *blue = (indx == 0);
03774     
03775     /* Load the image */
03776     check( load_raw_image(*raw_filename,
03777               CPL_TYPE_DOUBLE,
03778               flames,
03779               *blue,
03780               raw_image,
03781               raw_header,
03782               rotated_header),
03783        "Error loading image from file '%s'", *raw_filename);
03784 
03785   cleanup:
03786     if (cpl_error_get_code() != CPL_ERROR_NONE)
03787     {
03788         *raw_filename = NULL;
03789         uves_free_image       (raw_image);
03790         uves_free_propertylist(raw_header);
03791     }
03792     return cpl_error_get_code();
03793 }
03794 
03795 /*----------------------------------------------------------------------------*/
03811 /*----------------------------------------------------------------------------*/
03812 
03813 cpl_error_code
03814 uves_load_drs(const cpl_frameset *frames, 
03815           bool flames,
03816           const char *chip_name,
03817           const char **drs_filename, 
03818           uves_propertylist **drs_header,
03819           enum uves_chip chip)
03820 {
03821     const char *tags[1];
03822     int number_of_tags = sizeof(tags) / sizeof(char *);
03823     int extension;
03824     int indx;
03825     
03826     *drs_header = NULL;
03827     tags[0]   = UVES_DRS_SETUP(flames, chip);
03828     extension = UVES_DRS_SETUP_EXTENSION(chip);
03829 
03830     check( *drs_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
03831        "Could not find DRS table (%s) in SOF", tags[0]);
03832     
03833     /* Load the header */
03834     check( *drs_header = uves_propertylist_load(*drs_filename,
03835                            extension),
03836        "Could not load header from extension %d of file '%s'", extension, *drs_filename);
03837 
03838     check_nomsg( uves_warn_if_chip_names_dont_match(*drs_header, chip_name, chip) );
03839 
03840   cleanup:
03841     if (cpl_error_get_code() != CPL_ERROR_NONE) {
03842     *drs_filename = NULL;
03843     uves_free_propertylist(drs_header);
03844     }
03845     return cpl_error_get_code();
03846 }
03847 
03848 /*----------------------------------------------------------------------------*/
03856 /*----------------------------------------------------------------------------*/
03857 cpl_image *
03858 uves_load_weights(const cpl_frameset *frames, const char **weights_filename,
03859                   enum uves_chip chip)
03860 {
03861     cpl_image *weights = NULL;
03862     const char *tags[1];
03863     int number_of_tags = sizeof(tags) / sizeof(char *);
03864     int extension = 0;
03865     int indx;
03866 
03867     assure( weights_filename != NULL, CPL_ERROR_NULL_INPUT, "Null filename");
03868     
03869     tags[0]   = UVES_WEIGHTS(chip);
03870 
03871     check( *weights_filename = uves_find_frame(frames, 
03872                                                tags, number_of_tags, &indx, NULL), 
03873            "Could not find '%s' in frame set", tags[0]);
03874     
03875     check( weights = cpl_image_load(*weights_filename,
03876                                     CPL_TYPE_DOUBLE,           /* Convert to this type */
03877                                     0,                         /* plane number */
03878                                     extension                  /* Extension number */
03879                ),
03880            "Could not load master bias from extension %d of file '%s'", 
03881            extension, *weights_filename);
03882 
03883   cleanup:
03884     return weights;
03885 }
03886 
03887 
03888 /*----------------------------------------------------------------------------*/
03904 /*----------------------------------------------------------------------------*/
03905 
03906 cpl_error_code
03907 uves_load_mbias(const cpl_frameset *frames, const char *chip_name,
03908         const char **mbias_filename, 
03909         cpl_image **mbias, uves_propertylist **mbias_header, enum uves_chip chip)
03910 {
03911     const char *tags[1];
03912     int number_of_tags = sizeof(tags) / sizeof(char *);
03913     int extension;
03914     int indx;
03915     
03916     *mbias        = NULL;
03917     *mbias_header = NULL;
03918 
03919     tags[0]   = UVES_MASTER_BIAS          (chip);
03920     extension = UVES_MASTER_BIAS_EXTENSION(chip);
03921     
03922     check( *mbias_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
03923        "Could not find '%s' in frame set", tags[0]);
03924     
03925     /* Load the mbias image */
03926     check( *mbias = cpl_image_load(*mbias_filename,
03927                    CPL_TYPE_DOUBLE,           /* Convert to this type */
03928                    0,                         /* plane number */
03929                    extension                  /* Extension number */
03930            ),
03931        "Could not load master bias from extension %d of file '%s'", 
03932        extension, *mbias_filename);
03933 
03934     /* Load the header */
03935     check( *mbias_header = uves_propertylist_load(*mbias_filename,
03936                          extension),
03937        "Could not load header from extension %d of file '%s'", 
03938        extension, *mbias_filename);
03939 
03940     check_nomsg( uves_warn_if_chip_names_dont_match(*mbias_header, chip_name, chip) );
03941 
03942   cleanup:
03943     if (cpl_error_get_code() != CPL_ERROR_NONE) 
03944     {
03945         *mbias_filename = NULL;
03946         uves_free_image(mbias);
03947         uves_free_propertylist(mbias_header);
03948     }
03949     return cpl_error_get_code();
03950 }
03951 
03952 
03953 /*----------------------------------------------------------------------------*/
03969 /*----------------------------------------------------------------------------*/
03970 
03971 cpl_error_code
03972 uves_load_master_formatcheck(const cpl_frameset *frames, const char *chip_name,
03973         const char **mform_filename, 
03974         cpl_image **mform, uves_propertylist **mform_header, enum uves_chip chip)
03975 {
03976     const char *tags[1];
03977     int number_of_tags = sizeof(tags) / sizeof(char *);
03978     int extension;
03979     int indx;
03980     
03981     *mform        = NULL;
03982     *mform_header = NULL;
03983 
03984     tags[0]   = UVES_MASTER_ARC_FORM          (chip);
03985     extension = UVES_MASTER_ARC_FORM_EXTENSION(chip);
03986     
03987     check( *mform_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
03988        "Could not find '%s' in frame set", tags[0]);
03989     
03990     /* Load the mbias image */
03991     check( *mform = cpl_image_load(*mform_filename,
03992                    CPL_TYPE_DOUBLE,           /* Convert to this type */
03993                    0,                         /* plane number */
03994                    extension                  /* Extension number */
03995            ),
03996        "Could not load master formatcheck from extension %d of file '%s'", 
03997        extension, *mform_filename);
03998 
03999     /* Load the header */
04000     
04001     check( *mform_header = uves_propertylist_load(*mform_filename,
04002                          extension),
04003        "Could not load header from extension %d of file '%s'", 
04004        extension, *mform_filename);
04005 
04006     check_nomsg( uves_warn_if_chip_names_dont_match(*mform_header, chip_name, chip) );
04007 
04008   cleanup:
04009     if (cpl_error_get_code() != CPL_ERROR_NONE) 
04010     {
04011         *mform_filename = NULL;
04012         uves_free_image(mform);
04013         uves_free_propertylist(mform_header);
04014     }
04015     return cpl_error_get_code();
04016 }
04017 
04018 /*----------------------------------------------------------------------------*/
04034 /*----------------------------------------------------------------------------*/
04035 
04036 cpl_error_code
04037 uves_load_mdark(const cpl_frameset *frames, const char *chip_name,
04038         const char **mdark_filename, cpl_image **mdark,
04039         uves_propertylist **mdark_header, enum uves_chip chip)
04040 {
04041     const char *tags[2];
04042     int number_of_tags = sizeof(tags) / sizeof(char *);
04043     int extension;
04044     int indx;
04045     
04046     *mdark        = NULL;
04047     *mdark_header = NULL;
04048 
04049     tags[0]   = UVES_MASTER_DARK          (chip);
04050     tags[1]   = UVES_MASTER_PDARK         (chip);
04051     extension = UVES_MASTER_DARK_EXTENSION(chip);
04052     
04053     check( *mdark_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
04054        "Could not find %s or %s in frame set", tags[0], tags[1]);
04055     
04056     /* Load the mdark image */
04057     check( *mdark = cpl_image_load(*mdark_filename,
04058                    CPL_TYPE_DOUBLE,           /* Convert to this type */
04059                    0,                         /* plane number */
04060                    extension                  /* Extension number */
04061            ),
04062        "Could not load master dark from extension %d of file '%s'", 
04063        extension, *mdark_filename);
04064 
04065     /* Load the header */
04066     check( *mdark_header = uves_propertylist_load(*mdark_filename,
04067                          extension),
04068        "Could not load header from extension %d of file '%s'", 
04069        extension, *mdark_filename);
04070 
04071     check_nomsg( uves_warn_if_chip_names_dont_match(*mdark_header, chip_name, chip) );
04072 
04073   cleanup:
04074     if (cpl_error_get_code() != CPL_ERROR_NONE) 
04075     {
04076         *mdark_filename = NULL;
04077         uves_free_image(mdark);
04078         uves_free_propertylist(mdark_header);
04079     }
04080     return cpl_error_get_code();
04081 }
04082 /*----------------------------------------------------------------------------*/
04098 /*----------------------------------------------------------------------------*/
04099 void
04100 uves_load_ref_flat(const cpl_frameset *frames, const char *chip_name,
04101            const char **filename, cpl_image **rflat,
04102            uves_propertylist **rflat_header, enum uves_chip chip)
04103 {
04104     const char *tags[1];
04105     int number_of_tags = sizeof(tags) / sizeof(char *);
04106     int extension;
04107     int indx;
04108     
04109     *rflat        = NULL;
04110     *rflat_header = NULL;
04111 
04112     tags[0]   = UVES_REF_TFLAT(chip);
04113     extension = UVES_MASTER_FLAT_EXTENSION(chip);
04114 
04115     check( *filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
04116        "Could not find %s in frame set", tags[0]);
04117     
04118     check( *rflat = cpl_image_load(*filename,
04119                    CPL_TYPE_DOUBLE,           /* Convert to this type */
04120                    0,                         /* plane number */
04121                    extension                  /* Extension number */
04122            ),
04123        "Could not load reference dark from extension %d of file '%s'", 
04124        extension, *filename);
04125 
04126     check( *rflat_header = uves_propertylist_load(*filename,
04127                          extension),
04128        "Could not load header from extension %d of file '%s'", 
04129        extension, *filename);
04130 
04131     check_nomsg( uves_warn_if_chip_names_dont_match(*rflat_header, chip_name, chip) );
04132 
04133   cleanup:
04134     if (cpl_error_get_code() != CPL_ERROR_NONE) 
04135     {
04136         *filename = NULL;
04137         uves_free_image(rflat);
04138         uves_free_propertylist(rflat_header);
04139     }
04140 
04141     return;
04142 }
04143 
04144 /*----------------------------------------------------------------------------*/
04160 /*----------------------------------------------------------------------------*/
04161 
04162 cpl_error_code
04163 uves_load_mflat_const(const cpl_frameset *frames, const char *chip_name,
04164               const char **mflat_filename, 
04165               cpl_image **mflat, uves_propertylist **mflat_header, 
04166               enum uves_chip chip,
04167               const cpl_frame **mflat_frame)
04168 {
04169     const char *tags[6];
04170     int number_of_tags = sizeof(tags) / sizeof(char *);
04171     int extension;
04172     int indx;
04173     
04174     *mflat        = NULL;
04175     *mflat_header = NULL;
04176 
04177     tags[0]   = UVES_REF_TFLAT            (chip);   /* Use REF TFLAT, rather than MASTER_TFLAT */
04178     tags[1]   = UVES_MASTER_FLAT          (chip);
04179     tags[2]   = UVES_MASTER_DFLAT         (chip);
04180     tags[3]   = UVES_MASTER_IFLAT         (chip);
04181     tags[4]   = UVES_MASTER_TFLAT         (chip);
04182     tags[5]   = UVES_MASTER_SCREEN_FLAT   (chip);
04183     extension = UVES_MASTER_FLAT_EXTENSION(chip);
04184     
04185     check( *mflat_filename = uves_find_frame(frames, tags, number_of_tags, &indx,
04186                          mflat_frame), 
04187        "Could not find '%s', '%s', '%s', '%s' or '%s' in frame set", 
04188        tags[0], tags[1], tags[2], tags[3], tags[4]);
04189     
04190     /* Load the mflat image */
04191     check( *mflat = cpl_image_load(*mflat_filename,
04192                    CPL_TYPE_DOUBLE,           /* Convert to this type */
04193                    0,                         /* plane number */
04194                    extension                  /* Extension number */
04195            ),
04196        "Could not load master flat from extension %d of file '%s'", 
04197        extension, *mflat_filename);
04198 
04199     /* Load the header */
04200     check( *mflat_header = uves_propertylist_load(*mflat_filename,
04201                          extension),
04202        "Could not load header from extension %d of file '%s'", 
04203        extension, *mflat_filename);
04204 
04205     check_nomsg( uves_warn_if_chip_names_dont_match(*mflat_header, chip_name, chip) );
04206 
04207   cleanup:
04208     if (cpl_error_get_code() != CPL_ERROR_NONE) 
04209     {
04210         *mflat_filename = NULL;
04211         uves_free_image(mflat);
04212         uves_free_propertylist(mflat_header);
04213     }
04214     return cpl_error_get_code();
04215 }
04216 
04217 /*----------------------------------------------------------------------------*/
04232 /*----------------------------------------------------------------------------*/
04233 cpl_error_code
04234 uves_load_mflat(cpl_frameset *frames, const char *chip_name,
04235         const char **mflat_filename, 
04236         cpl_image **mflat, uves_propertylist **mflat_header, enum uves_chip chip,
04237         cpl_frame **mflat_frame)
04238 {
04239     return uves_load_mflat_const((const cpl_frameset *)frames,
04240                  chip_name,
04241                  mflat_filename,
04242                  mflat, mflat_header, chip,
04243                  (const cpl_frame **) mflat_frame);
04244 }
04245 
04246 /*----------------------------------------------------------------------------*/
04278 /*----------------------------------------------------------------------------*/
04279 cpl_error_code
04280 uves_load_ordertable(const cpl_frameset *frames, 
04281                      bool flames,
04282                      const char *chip_name,
04283                      const char **ordertable_filename, 
04284                      cpl_table **ordertable, 
04285                      uves_propertylist **ordertable_header, 
04286                      uves_propertylist **ordertable_xheader, 
04287                      polynomial **order_locations, 
04288                      cpl_table **traces, 
04289                      int *tab_in_out_oshift,
04290                      double *tab_in_out_yshift,
04291                      int ** fib_msk,
04292                      double ** fib_pos,
04293                      enum uves_chip chip,
04294                      bool guess_table)
04295 {
04296     uves_propertylist *midas_header = NULL;      /* Table header if midas format */
04297     uves_propertylist *prime_header = NULL;      /* Prime header if flames  */
04298     const char *tags[1];
04299     int number_of_tags = sizeof(tags) / sizeof(char *);
04300     bool format_is_midas;
04301     int *tioo = NULL;
04302     double *tioy = NULL;
04303     int indx;
04304 
04305     double *fibre_pos = NULL;
04306     int *fibre_mask = NULL;
04307 
04308     if (guess_table)
04309     {
04310         tags[0] = UVES_GUESS_ORDER_TABLE(flames, chip);
04311     }
04312     else
04313     {
04314         tags[0] = UVES_ORDER_TABLE(flames, chip);
04315     }
04316 
04317     check( *ordertable_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
04318        "No order table (%s) found in SOF", tags[0]);
04319     
04320     check( *ordertable = cpl_table_load(*ordertable_filename,
04321                     UVES_ORDER_TABLE_EXTENSION,
04322                     1),                /* Mark identified 
04323                                   invalid values? (1=yes) */
04324        "Error loading order table from extension %d of file '%s'", 
04325        UVES_ORDER_TABLE_EXTENSION, *ordertable_filename);
04326     
04327     assure(ordertable_header != NULL,CPL_ERROR_NULL_INPUT,
04328            "NULL primary header uves_propertylist variable header");
04329     check( *ordertable_header = uves_propertylist_load(*ordertable_filename, 0),
04330        "Could not load header from extension 0 of '%s'", *ordertable_filename);
04331 
04332     if(ordertable_xheader != NULL) {
04333 
04334     check( *ordertable_xheader = uves_propertylist_load(*ordertable_filename, 1),
04335        "Could not load header from extension 1 of '%s'", *ordertable_filename);
04336 
04337 
04338 
04339     }
04340     check_nomsg( uves_warn_if_chip_names_dont_match(*ordertable_header, chip_name, chip) );
04341     
04342     check(uves_check_if_format_is_midas(*ordertable_header,&format_is_midas),
04343       "Error getting FITS format");
04344 
04345 
04346     if (!format_is_midas && !flames)
04347     {
04348             /* The format check and order position recipes create order tables
04349                with different column names. Rename if necessary. 
04350 
04351                This is a workaround for the problem that different recipes
04352                create the same products (order tables and line tables).
04353                The true solution would be to remove the format check recipe from
04354                the recution cascade, and use the theoretical physical model to
04355                bootstrap the order definition and wavelength calibration.
04356             */
04357             if (cpl_table_has_column(*ordertable, "ORDER"))
04358                 {
04359                     cpl_table_name_column(*ordertable, "ORDER", "Order");
04360                 }
04361             if (cpl_table_has_column(*ordertable, "YFIT"))
04362                 {
04363                     cpl_table_name_column(*ordertable, "YFIT", "Yfit");
04364                 }
04365 
04366         if (order_locations != NULL)
04367         {
04368             check( *order_locations = 
04369                load_polynomial(*ordertable_filename, UVES_ORDER_TABLE_EXTENSION_POLY),
04370                "Could not read polynomial from extension %d of file '%s'",
04371                UVES_ORDER_TABLE_EXTENSION_POLY, *ordertable_filename);
04372         }
04373 
04374         if (traces != NULL)
04375         {
04376             check( *traces = cpl_table_load(*ordertable_filename,
04377                             UVES_ORDER_TABLE_EXTENSION_FIBRE,
04378                             1),    /* Mark identified 
04379                                   invalid values? (1=yes) */
04380                "Error loading fibre table from extension %d of file '%s'", 
04381                UVES_ORDER_TABLE_EXTENSION_FIBRE, *ordertable_filename);
04382         }
04383     }
04384     else
04385         /* MIDAS format, or FLAMES */
04386     {
04387         /* Rename */
04388         check(( cpl_table_cast_column (*ordertable, "ORDER", "Order", CPL_TYPE_INT),
04389                 cpl_table_erase_column(*ordertable, "ORDER")),
04390               "Error casting and renaming column 'ORDER'");
04391         
04392         check( cpl_table_name_column(*ordertable, "YFIT", "Yfit"),
04393                "Error renaming column 'YFIT'");
04394                 
04395         //check( midas_header = uves_propertylist_load(*ordertable_filename, 1),
04396     //      "Could not load header from extension 1 of '%s'", 
04397     //     *ordertable_filename);
04398       check(midas_header = uves_propertylist_load(*ordertable_filename, 1),
04399          "Could not load header from extension 1 of '%s'",
04400          *ordertable_filename);
04401 
04402     if(flames) {
04403           check(prime_header = uves_propertylist_load(*ordertable_filename, 0),
04404          "Could not load header from extension 0 of '%s'",
04405          *ordertable_filename);
04406       check_nomsg(uves_propertylist_append(midas_header,prime_header));
04407         }
04408 
04409         /* Load polynomial named 'COEFF' from descriptors in extension 1 */
04410         if (order_locations != NULL)
04411         {
04412             check( *order_locations = 
04413            uves_polynomial_convert_from_plist_midas(midas_header, "COEFF",-1),
04414                    "Error reading polynomial from %s", *ordertable_filename);
04415         }
04416 
04417 
04418         if (flames && tab_in_out_oshift != NULL )
04419         {
04420             /* Get tab_in_out_oshift */
04421             int tioo_length;
04422                     cpl_type tioo_type;
04423 
04424             check( tioo = uves_read_midas_array(
04425                    midas_header, "TAB_IN_OUT_OSHIFT", &tioo_length,
04426                                &tioo_type, NULL),
04427                "Error reading TAB_IN_OUT_OSHIFT from MIDAS header");
04428 
04429                     assure( tioo_type == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
04430                             "Type of TAB_IN_OUT_OSHIFT is %s, double expected",
04431                             uves_tostring_cpl_type(tioo_type));
04432 
04433             if (tioo_length != 1)
04434             {
04435                 uves_msg_warning("Length of TAB_IN_OUT_OSHIFT array is %d; "
04436                          "%d expected", tioo_length, 1);
04437             }
04438 
04439             *tab_in_out_oshift = tioo[0];
04440             
04441             uves_msg_debug("TAB_IN_OUT_OSHIFT = %d", *tab_in_out_oshift);
04442 
04443         }
04444         
04445         if (flames && tab_in_out_yshift != NULL)
04446         {
04447             /* Get tab_in_out_yshift */
04448             int tioy_length;
04449                     cpl_type tioy_type;
04450 
04451             check( tioy = uves_read_midas_array(
04452                    midas_header, "TAB_IN_OUT_YSHIFT", &tioy_length,
04453                                &tioy_type, NULL),
04454                "Error reading TAB_IN_OUT_YSHIFT from MIDAS header");
04455 
04456                     assure( tioy_type == CPL_TYPE_DOUBLE, CPL_ERROR_TYPE_MISMATCH,
04457                             "Type of TAB_IN_OUT_YSHIFT is %s, double expected",
04458                             uves_tostring_cpl_type(tioy_type));
04459 
04460             if (tioy_length != 1)
04461             {
04462                 uves_msg_warning("Length of TAB_IN_OUT_YSHIFT array is %d; "
04463                          "%d expected", tioy_length, 1);
04464             }
04465 
04466             *tab_in_out_yshift = tioy[0];
04467 
04468             uves_msg_debug("TAB_IN_OUT_YSHIFT = %f", *tab_in_out_yshift);
04469         }
04470         
04471         if (traces != NULL)
04472         {
04473             *traces = uves_ordertable_traces_new();
04474             
04475             if (!flames)
04476             /* UVES: one trace with zero offset */
04477             {
04478                 int fibre_ID = 0;
04479                 double fibre_offset = 0.0;
04480                 int fibre_msk = 1;
04481                 uves_ordertable_traces_add(*traces, 
04482                                fibre_ID,
04483                                fibre_offset,
04484                                fibre_msk);
04485             }
04486             else
04487             /* FLAMES */
04488             {
04489 
04490                 int fibre_pos_length;
04491                 int fibre_mask_length;
04492                             cpl_type fibre_pos_type;
04493                             cpl_type fibre_mask_type;
04494                 int fibre_ID;
04495 
04496                 check( fibre_pos = uves_read_midas_array(
04497                        midas_header, "FIBREPOS", &fibre_pos_length,
04498                                        &fibre_pos_type, NULL),
04499                    "Error reading FIBREPOS from MIDAS header");
04500 
04501                             assure( fibre_pos_type == CPL_TYPE_DOUBLE, CPL_ERROR_TYPE_MISMATCH,
04502                                     "Type of FIBREPOS is %s, double expected",
04503                                     uves_tostring_cpl_type(fibre_pos_type));
04504 
04505                 check( fibre_mask = uves_read_midas_array(
04506                        midas_header, "FIBREMASK", &fibre_mask_length,
04507                                        &fibre_mask_type, NULL),
04508                    "Error reading FIBREMASK from MIDAS header");
04509 
04510                             assure( fibre_mask_type == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
04511                                     "Type of FIBREMASK is %s, double expected",
04512                                     uves_tostring_cpl_type(fibre_mask_type));
04513                             
04514                 assure( fibre_pos_length == fibre_mask_length,
04515                     CPL_ERROR_INCOMPATIBLE_INPUT,
04516                     "FIBREMASK has length %d, but "
04517                     "FIBREPOS has length %d",
04518                     fibre_mask_length, fibre_pos_length );
04519             
04520                 *fib_pos= cpl_malloc(sizeof(double) * fibre_pos_length);
04521                 *fib_msk= cpl_malloc(sizeof(int) * fibre_mask_length);
04522 
04523                 for (fibre_ID = 0; fibre_ID < fibre_mask_length; fibre_ID++)
04524                 {
04525                     uves_msg_debug("Found trace %d, position %f (%s)",
04526                            fibre_ID, fibre_pos[fibre_ID],
04527                            fibre_mask[fibre_ID] ? 
04528                            "enabled" : "disabled");
04529                     uves_ordertable_traces_add(*traces, 
04530                                    fibre_ID,
04531                                    fibre_pos[fibre_ID],
04532                                    fibre_mask[fibre_ID]);
04533                     (*fib_pos)[fibre_ID]=fibre_pos[fibre_ID];
04534                     (*fib_msk)[fibre_ID]=fibre_mask[fibre_ID];
04535                 }
04536             }
04537         }
04538     }
04539 
04540   cleanup:
04541     uves_free_propertylist(&midas_header);
04542     uves_free_double(&fibre_pos);
04543     uves_free_int(&fibre_mask);
04544     uves_free_int(&tioo);
04545     uves_free_double(&tioy);
04546     uves_free_propertylist(&prime_header);
04547 
04548     if (cpl_error_get_code() != CPL_ERROR_NONE) 
04549     {
04550         *ordertable_filename = NULL;
04551         uves_free_table       (ordertable);
04552         uves_free_propertylist(ordertable_header);
04553         if (order_locations != NULL) uves_polynomial_delete(order_locations);
04554         if (traces != NULL)          uves_free_table       (traces);
04555     }
04556     return cpl_error_get_code();
04557 }
04558 
04559 
04560 
04561 /*--------------------------------------------------------------------------*/
04570 /*--------------------------------------------------------------------------*/
04571 
04572 
04573 cpl_error_code
04574 uves_check_if_format_is_midas(uves_propertylist* header, bool* format_is_midas)
04575 {
04576  
04577   /* Determine format of order table and read the polynomial */
04578   if (uves_propertylist_contains(header, UVES_DRS_ID)) {
04579 
04580 
04581     const char* drs_id=NULL;
04582 
04583     check( drs_id = uves_pfits_get_drs_id(header), "Error reading DRS ID");
04584     if (strstr(drs_id, "CPL") != NULL || 
04585     strstr(drs_id, "cpl") != NULL) {
04586       *format_is_midas = false;
04587       uves_msg_debug("Order table was written by CPL");
04588     } else if (strstr(drs_id, "MIDAS") != NULL || 
04589                strstr(drs_id, "midas") != NULL) {
04590       *format_is_midas = true;
04591       uves_msg_low("Order table was written by MIDAS");
04592     } else {
04593       assure ( false, CPL_ERROR_ILLEGAL_INPUT, 
04594            "Unrecognized order table format, DRS_ID = '%s'", drs_id);
04595     }
04596   } else {
04597 
04598     *format_is_midas = true;
04599     uves_msg_debug("No '%s' keyword found. Assuming MIDAS format", UVES_DRS_ID);
04600   }
04601  
04602  cleanup:
04603   return cpl_error_get_code();
04604 
04605 }
04606 
04607 /*--------------------------------------------------------------------------*/
04617 /*--------------------------------------------------------------------------*/
04618 
04619 static cpl_error_code
04620 create_column_pixelsize(cpl_table *linetable)
04621 {
04622     polynomial *p = NULL;
04623     cpl_table *t = NULL;
04624     double d1, d2;
04625     int i;
04626     int degree = 3;
04627     
04628     /* Remove rows with Ident = 0 (unidentified lines) */
04629     check( t = uves_extract_table_rows(linetable, "Ident", CPL_GREATER_THAN, 0.1),
04630        "Error deleting rows with Ident=0");
04631     
04632     /* Create column Aux := Ident * Order  */
04633     check(( cpl_table_duplicate_column(t, "Aux", t, "Ident"),
04634         cpl_table_multiply_columns(t, "Aux", "Order")),
04635       "Error creating 'Aux' column");
04636     
04637     check( p = uves_polynomial_regression_1d(t, 
04638                          "X", "Aux", NULL,
04639                          degree,
04640                          NULL, NULL,
04641                          NULL,
04642                          -1),
04643        "Regression failed");
04644     
04645     check( d1 = uves_polynomial_get_coeff_1d(p, 1),
04646        "Error reading polynomial coefficient");
04647     
04648     check( d2 = uves_polynomial_get_coeff_1d(p, 2),
04649        "Error reading polynomial coefficient");
04650     
04651     cpl_table_new_column(linetable, LINETAB_PIXELSIZE, CPL_TYPE_DOUBLE);
04652     
04653     for (i = 0; i < cpl_table_get_nrow(linetable); i++)
04654     {
04655         int x;
04656         int order;
04657         double pixelsize;
04658         double ident;
04659         
04660         check(( x     = cpl_table_get_double(linetable, "X", i, NULL),
04661             order = cpl_table_get_int   (linetable, "Order", i, NULL),
04662             ident = cpl_table_get_double(linetable, "Ident", i, NULL)),
04663           "Error reading line table");
04664         
04665         assure( order != 0, CPL_ERROR_ILLEGAL_INPUT, "Illegal order number: %d", order);
04666         
04667         /* 
04668          * MIDAS approximates
04669          * d(lambda m)/dx (x,m)   =  d1 + 2*d2*x
04670          *
04671          * where the polynomial itself is ... + d1*x + d2*x^2 + ...
04672          */
04673         pixelsize = (d1 + 2*d2* x) / order;
04674 //        pixelsize = uves_polynomial_derivative_2d(dispersion_relation, x, order, 1)/order;
04675         
04676         if (ident > 0.01)
04677         {
04678             cpl_table_set_double(linetable, LINETAB_PIXELSIZE, i, pixelsize);
04679         }
04680         else
04681         {
04682             cpl_table_set_invalid(linetable, LINETAB_PIXELSIZE, i);
04683         }
04684     }
04685     
04686   cleanup:
04687     uves_free_table(&t);
04688     uves_polynomial_delete(&p);
04689     return cpl_error_get_code();
04690 }
04691 
04692 
04693 
04694 /*----------------------------------------------------------------------------*/
04721 /*----------------------------------------------------------------------------*/
04722 static void
04723 align_order_line_table(cpl_table *linetable, const polynomial *absolute_order,
04724                uves_propertylist **linetable_header,
04725                const polynomial *order_locations, int minorder, int maxorder)
04726 {
04727     polynomial *absord = NULL;
04728 
04729     assure ( order_locations  != NULL, CPL_ERROR_NULL_INPUT, 
04730              "Null order locations polynomial!");
04731 
04732     assure ( absolute_order  != NULL, CPL_ERROR_NULL_INPUT, 
04733              "Null absolute order pllynomial!");
04734     assure( cpl_table_has_column(linetable, "X"   ), CPL_ERROR_DATA_NOT_FOUND, 
04735         "Missing line table column 'X'");
04736     assure( cpl_table_has_column(linetable, "Ynew"), CPL_ERROR_DATA_NOT_FOUND, 
04737         "Missing line table column 'Ynew'");
04738     assure( cpl_table_has_column(linetable, "Order"), CPL_ERROR_DATA_NOT_FOUND, 
04739         "Missing line table column 'Order'");
04740     
04741     assure( cpl_table_get_column_type(linetable, "X") == CPL_TYPE_DOUBLE,
04742         CPL_ERROR_TYPE_MISMATCH, "Line table column 'X' has type %s (double expected))",
04743         uves_tostring_cpl_type(cpl_table_get_column_type(linetable, "X")) );
04744     
04745     assure( cpl_table_get_column_type(linetable, "Ynew") == CPL_TYPE_DOUBLE,
04746         CPL_ERROR_TYPE_MISMATCH, "Line table column 'Ynew' has type %s (double expected))",
04747         uves_tostring_cpl_type(cpl_table_get_column_type(linetable, "Ynew")) );
04748     
04749     assure( cpl_table_get_column_type(linetable, "Y") == CPL_TYPE_INT,
04750         CPL_ERROR_TYPE_MISMATCH, "Line table column 'Y' has type %s (integer expected))",
04751         uves_tostring_cpl_type(cpl_table_get_column_type(linetable, "Y")) );
04752 
04753 
04754     if (linetable_header != NULL)
04755     /* then correct first/abs order keywords */
04756     {
04757         int line_first, line_last;
04758         int ord_first, ord_last;
04759             {
04760 
04761                 int maxx;
04762                 int minx;
04763                 int x, y, order, absorder;  /* At chip center */
04764                 int coeff;
04765                 
04766 
04767                 maxx = uves_round_double(cpl_table_get_column_max(linetable, "X"));
04768 
04769                 minx = uves_round_double(cpl_table_get_column_min(linetable, "X"));
04770                 
04771                 assure( 1 <= minx && minx <= maxx, CPL_ERROR_ILLEGAL_INPUT,
04772                         "Illegal min/max line x positions: %d/%d, must be > 1", 
04773                         minx, maxx);
04774         
04775                 /* Center of chip */
04776                 x = (minx + maxx) / 2;
04777                 order = (minorder + maxorder) / 2;
04778 
04779                 y = uves_polynomial_evaluate_2d(order_locations, x, order);
04780                 if (uves_polynomial_derivative_2d(absolute_order, x, y, 2) > 0) {
04781                     coeff = +1;
04782                 }
04783                 else {
04784                     coeff = -1;
04785                 } 
04786 
04787     assure ( order_locations  != NULL, CPL_ERROR_NULL_INPUT, 
04788              "Null order locations polynomial!");
04789 
04790 
04791                 absorder = uves_round_double(uves_polynomial_evaluate_2d(absolute_order, x, y));
04792 
04793 
04794                 uves_msg_debug("Absolute order polynomial at (%d, %d) = %f, "
04795                                "rounding to %d", x, y, 
04796                                uves_polynomial_evaluate_2d(absolute_order, x, y), absorder);
04797 
04798                 ord_first = absorder + (minorder - order) * coeff;
04799                 ord_last  = absorder + (maxorder - order) * coeff;
04800             }
04801 
04802             check( line_first =
04803            uves_pfits_get_firstabsorder(*linetable_header),
04804            "Could not read order number from line table header");
04805         
04806         check( line_last  =
04807            uves_pfits_get_lastabsorder (*linetable_header),
04808            "Could not read order number from line table header");
04809         
04810         uves_msg_debug("Order table range: %d - %d. Line table range: %d - %d",
04811                ord_first, ord_last, line_first, line_last);
04812         
04813         if (line_first != ord_first ||
04814         line_last  != ord_last)
04815         {
04816             uves_msg_warning("Provided line and order tables are incompatible. "
04817                      "Line table contains orders %d - %d. "
04818                      "Order table contains orders %d - %d. "
04819                      "Correcting on the fly",
04820                      line_first, line_last, ord_first, ord_last);
04821             
04822             check( uves_pfits_set_firstabsorder(*linetable_header,
04823                             ord_first),
04824                "Could not write corrected first absolute order number");
04825             check( uves_pfits_set_lastabsorder(*linetable_header,
04826                                ord_last),
04827                "Could not write corrected first absolute order number");
04828 
04829             uves_msg_debug("Setting line table order range = %d - %d",
04830                    ord_first, ord_last);
04831         }
04832     }
04833     /* This 'Y' column is the relative order number in linetables
04834        but the absolute order number (and therefore equal to
04835        the 'order' column) in line guess tables (!!) 
04836     */
04837 
04838     {
04839     double epsilon = 0.01; /* Must be larger than machine precision but
04840                   less than the typical difference between
04841                   absolute/relative numbering (~100) 
04842                    */
04843 
04844     if (fabs(cpl_table_get_column_median(linetable, "Y") - 
04845          cpl_table_get_column_median(linetable, "Order")) > epsilon)
04846 
04847         /* If column 'Y' is different from 'Order', 
04848            then 'Y' is the relative order number and
04849            should be corrected (if there is an inconsistency).
04850 
04851            For now, simply delete the 'Y' column because it is
04852            not used later. If the 'Y' column will be used later,
04853            it must be corrected at this place.
04854         */
04855         {
04856         uves_msg_debug("Removing line table column 'Y'");
04857         cpl_table_erase_column(linetable, "Y");
04858         }
04859     }
04860     
04861   cleanup:
04862     uves_polynomial_delete(&absord);
04863 }
04864 
04865 
04866 /*----------------------------------------------------------------------------*/
04905 /*----------------------------------------------------------------------------*/
04906 void
04907 uves_load_linetable(const cpl_frameset *frames, 
04908                     bool flames,
04909                     const char *chip_name,
04910                     const polynomial *order_locations, int minorder, int maxorder,
04911                     const char **linetable_filename,
04912                     cpl_table **linetable,
04913                     uves_propertylist **linetable_header,
04914                     polynomial **dispersion_relation,
04915                     polynomial **absolute_order,
04916                     enum uves_chip chip, int trace_id, int window)
04917 {
04918     uves_propertylist *primary_header = NULL;
04919     uves_propertylist *header         = NULL;
04920     uves_propertylist *midas_header   = NULL;       /* MIDAS extension header */
04921     int *absorders                   = NULL;       /* Absolute order numbers */
04922     cpl_table *temp                  = NULL;
04923     polynomial *absolute_order_local = NULL;
04924     const char *tags[3];
04925     int number_of_tags = sizeof(tags) / sizeof(char *);
04926     const char *drs_id;
04927     bool format_is_midas;               /* Was file written by CPL or MIDAS? */
04928     int base_extension;                 /* Last extension (e.g. 0) before 
04929                        extension with line table */
04930     int indx;
04931 
04932     if (flames)
04933     {
04934         tags[0] = UVES_GUESS_LINE_TABLE(flames, chip);
04935         tags[1] = UVES_LINE_TABLE(flames, chip);
04936         tags[2] = UVES_LINE_TABLE(flames, chip);
04937         number_of_tags = 3;
04938         
04939         check( *linetable_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
04940            "No line table (%s, %s or %s) found in SOF", tags[0], tags[1], tags[2]);
04941     }
04942     else
04943     {
04944         tags[0] = UVES_LINE_TABLE(flames, chip);
04945         tags[1] = UVES_LINE_TABLE(flames, chip);
04946         tags[2] = UVES_GUESS_LINE_TABLE(flames, chip);
04947         
04948         /* For backwards compatibility with MIDAS, 
04949            also look for LINE_TABLE_chip%d */
04950         if (cpl_frameset_find_const(frames, tags[0]) == NULL &&
04951             cpl_frameset_find_const(frames, tags[1]) == NULL &&
04952             cpl_frameset_find_const(frames, tags[2]) == NULL)
04953         {
04954             uves_msg_debug("No %s", tags[0]);
04955             
04956             if (window >= 1)
04957             {
04958                 /* Look for LINE_TABLE_BLUEwindow */
04959                 
04960                 tags[0] = UVES_LINE_TABLE_MIDAS(chip, window);
04961                 tags[1] = UVES_LINE_TABLE_MIDAS(chip, window);
04962                 tags[2] = UVES_LINE_TABLE_MIDAS(chip, window);
04963                 
04964                 uves_msg_debug("Trying %s", tags[0]);
04965             }
04966             if (window <= 0)
04967             {
04968                 /* Look for any LINE_TABLE_BLUEi */
04969                 tags[0] = UVES_LINE_TABLE_MIDAS(chip, 1);
04970                 tags[1] = UVES_LINE_TABLE_MIDAS(chip, 2);
04971                 tags[2] = UVES_LINE_TABLE_MIDAS(chip, 3);
04972                 
04973                 uves_msg_debug("Trying %s, %s or %s", tags[0], tags[1], tags[2]);
04974             }
04975         }
04976         
04977         check( *linetable_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
04978            "No line table (%s, %s or %s) found in SOF", tags[0], tags[1], tags[2]);
04979     }
04980     
04981     /* Read primary header */
04982     check( primary_header = uves_propertylist_load(*linetable_filename, 0),
04983        "Could not load primary header of '%s'", *linetable_filename);  
04984 
04985     check_nomsg( uves_warn_if_chip_names_dont_match(primary_header, chip_name, chip) );
04986     
04987     /* Determine format of line table */
04988     if (uves_propertylist_contains(primary_header, UVES_DRS_ID))
04989     {
04990         check( drs_id = uves_pfits_get_drs_id(primary_header), "Error reading DRS ID");
04991         if (strstr(drs_id, "CPL") != NULL || strstr(drs_id, "cpl") != NULL)
04992         {
04993             format_is_midas = false;
04994             uves_msg_debug("Line table was written by CPL");
04995         }
04996         else if (strstr(drs_id, "MIDAS") != NULL || strstr(drs_id, "midas") != NULL)
04997         {
04998             format_is_midas = true;
04999             uves_msg_debug("Line table was written by MIDAS");
05000         }
05001         else
05002         {
05003             assure ( false,
05004                  CPL_ERROR_ILLEGAL_INPUT,
05005                  "Unrecognized line table format, DRS_ID = '%s'", drs_id);
05006         }
05007     }
05008     else
05009     {
05010         format_is_midas = true;
05011         uves_msg_debug("No '%s' keyword found. Assuming MIDAS format", UVES_DRS_ID);
05012     }
05013 
05014     if (format_is_midas || flames)
05015     {
05016         if (!flames)
05017         {
05018             assure( trace_id == 0 && (window == -1 || (1 <= window && window <= 3)), 
05019                 CPL_ERROR_UNSUPPORTED_MODE,
05020                 "Cannot read (fibre, window) = (%d, %d) from MIDAS line table", 
05021                 trace_id, window);
05022             
05023             base_extension = 0;
05024         }
05025         else
05026         {
05027 
05028       if(trace_id > 0) {
05029 
05030             assure( ((1<= trace_id && trace_id <= 9) && (window == -1)), 
05031                 CPL_ERROR_UNSUPPORTED_MODE,
05032                 "Cannot read (fibre, window) = (%d, %d) from MIDAS line table", 
05033                 trace_id, window);
05034             
05035             base_extension = 0;
05036 
05037 
05038       } else {
05039 
05040             uves_msg_warning("Assuming line table is guess table");
05041             base_extension = 0;
05042       }
05043         }
05044     }
05045     else
05046     /* Find table extension containing the line table for the specified trace and window */
05047     {
05048         int nextensions;
05049         bool found;
05050         
05051         check( nextensions = uves_get_nextensions(*linetable_filename),
05052            "Error reading number of extensions of file '%s'", *linetable_filename);
05053         header = NULL;
05054         found = false;
05055 
05056             uves_msg_debug("Number of extensions = %d", nextensions);
05057 
05058         for (base_extension = 1; base_extension < nextensions && !found; base_extension++)
05059         {
05060             int header_trace;
05061             int header_window;
05062             
05063             /* Read header trace & window info */
05064             check(( uves_free_propertylist(&header),
05065                header = uves_propertylist_load(*linetable_filename, base_extension)),
05066                "Could not header of extension %d of '%s'", 
05067               base_extension, *linetable_filename);
05068             
05069             check( header_trace  = uves_pfits_get_traceid     (header),
05070                "Error reading trace ID from header of extension %d of '%s'",
05071                base_extension, *linetable_filename);
05072             
05073             check( header_window = uves_pfits_get_windownumber(header),
05074                "Error reading window number from header of extension %d of '%s'",
05075                base_extension, *linetable_filename);
05076             
05077                     uves_msg_debug("Found (trace, window) = (%d, %d), need (%d, %d)",
05078                                    header_trace, header_window,
05079                                    trace_id, window);
05080 
05081             found = ( (trace_id == header_trace) && 
05082                   (window == -1 || window == header_window) );
05083         }
05084         
05085         assure( found,
05086             CPL_ERROR_ILLEGAL_INPUT,
05087             "Line table (trace, window) = (%d, %d) is not present in file '%s'",
05088             trace_id, window, *linetable_filename);
05089 
05090         /* Let 'base_extension' be the first extension before 
05091            the proper extension was found (0, 3, 6, ...) */
05092         base_extension -= 2;
05093         /* ...and incremented in for-loop */
05094     }
05095 
05096     check( *linetable = cpl_table_load(*linetable_filename,
05097                        base_extension + UVES_LINE_TABLE_EXTENSION,
05098                        1),              /* Mark identified 
05099                                invalid values? (1=yes) */
05100        "Error loading line table from extension %d of file '%s'", 
05101        base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
05102 
05103     /* Read header of table extension if requested */
05104     if (linetable_header != NULL)
05105     {
05106         check( *linetable_header = 
05107            uves_propertylist_load(*linetable_filename, 
05108                      base_extension + UVES_LINE_TABLE_EXTENSION),
05109            "Could not load header of extension %d of '%s'", 
05110            base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
05111 
05112         if (format_is_midas)
05113         {
05114             int size = 0;
05115                     cpl_type type;
05116             absorders = uves_read_midas_array(*linetable_header, "ORDER", &size,
05117                                                       &type, NULL);
05118                     
05119                     assure( type == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
05120                             "Type of ORDER is %s, int expected",
05121                             uves_tostring_cpl_type(type));
05122 
05123             assure( size == 2, 
05124                 CPL_ERROR_ILLEGAL_INPUT,
05125                 "'ORDER' array has size %d. Size 2 expected.", size);
05126             check(( uves_pfits_set_firstabsorder(*linetable_header, absorders[0]),
05127                 uves_pfits_set_lastabsorder(*linetable_header, absorders[1])),
05128               "Error updating table header");
05129         }        
05130     }
05131     
05132     /* Read the polynomials if requested */
05133     if (format_is_midas)
05134     {
05135         /* Rename & cast order/ident/X columns */
05136         check(( cpl_table_cast_column(*linetable, "X", "xxxx", CPL_TYPE_DOUBLE),
05137             cpl_table_erase_column(*linetable, "X"),
05138             cpl_table_name_column(*linetable, "xxxx", "X")),
05139           "Error casting and renaming column 'X'");
05140         
05141         check(( cpl_table_cast_column(*linetable, "YNEW", "xxxx", CPL_TYPE_DOUBLE),
05142             cpl_table_erase_column(*linetable, "YNEW"),
05143             cpl_table_name_column(*linetable, "xxxx", "Ynew")),
05144           "Error casting and renaming column 'YNEW'");
05145         
05146         check(( cpl_table_cast_column(*linetable, "Y", "xxxx", CPL_TYPE_INT),
05147             cpl_table_erase_column(*linetable, "Y"),
05148             cpl_table_name_column(*linetable, "xxxx", "Y")),
05149            "Error casting and renaming column 'Y'");
05150 
05151         check(( cpl_table_cast_column(*linetable, "ORDER", "Order", CPL_TYPE_INT),
05152             cpl_table_erase_column(*linetable, "ORDER")),
05153            "Error casting and renaming column 'ORDER'");
05154            
05155         check( cpl_table_name_column(*linetable, "IDENT", "Ident"),
05156            "Error renaming column 'IDENT'");
05157 
05158         check( midas_header = uves_propertylist_load(
05159                *linetable_filename, 
05160                base_extension + UVES_LINE_TABLE_EXTENSION),
05161            "Could not load header of extension %d of '%s'",
05162            base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
05163         
05164         if (dispersion_relation != NULL) {
05165             if (trace_id > 0) {
05166                 check( *dispersion_relation = 
05167                        uves_polynomial_convert_from_plist_midas(midas_header,
05168                                                                 "REGR", trace_id),
05169                        "Error reading polynomial 'REGR%d' from '%s'",
05170                        trace_id,
05171                        *linetable_filename);
05172             }
05173             else {
05174                 check( *dispersion_relation = 
05175                        uves_polynomial_convert_from_plist_midas(midas_header,
05176                                                                 "REGR", -1),
05177                        "Error reading polynomial 'REGR' from '%s'",
05178                        *linetable_filename);
05179             }
05180         }
05181         
05182     
05183       check( absolute_order_local = 
05184              uves_polynomial_convert_from_plist_midas(midas_header, "RORD",-1),
05185              "Error reading polynomial 'RORD' from '%s'", *linetable_filename);
05186       
05187       /* For FLAMES data, it seems that the polynomial is half an order shifted
05188          (for unknown reasons) */
05189         if (flames)
05190             {
05191                 check_nomsg( uves_polynomial_shift(absolute_order_local, 0, 0.5) );
05192             }
05193     }
05194     else
05195     /* CPL format */
05196     {
05197         /* physmod + wavecal recipes use different naming conventions,
05198            workaround for this:
05199         */
05200         if (cpl_table_has_column(*linetable, "YNEW"))
05201         {
05202             cpl_table_name_column(*linetable, "YNEW", "Ynew");
05203         }
05204 
05205         if (dispersion_relation != NULL)
05206         {
05207             check( *dispersion_relation = load_polynomial(
05208                    *linetable_filename,
05209                    base_extension + UVES_LINE_TABLE_EXTENSION_DISPERSION),
05210                "Could not read polynomial from extension %d of file '%s'", 
05211                base_extension + UVES_LINE_TABLE_EXTENSION_DISPERSION,
05212                *linetable_filename);
05213         }
05214 
05215         check( absolute_order_local =
05216            load_polynomial(*linetable_filename, 
05217                    base_extension + UVES_LINE_TABLE_EXTENSION_ABSORDER),
05218            "Could not read polynomial from extension %d of file '%s'",
05219            base_extension + UVES_LINE_TABLE_EXTENSION_ABSORDER, *linetable_filename);
05220     }
05221         
05222     if (absolute_order != NULL)
05223     {
05224         *absolute_order = uves_polynomial_duplicate(absolute_order_local);
05225     }
05226     
05227 
05228     check( align_order_line_table(
05229            *linetable, absolute_order_local, linetable_header, 
05230            order_locations, minorder, maxorder),
05231        "Error while aligning line/order tables");
05232 
05233 
05234     /* Remove all other columns than 'Ident', 'Order', 'X', 'Pixelsize' */
05235     {
05236     const char *colname;
05237 
05238     /* Loop through all columns */
05239 
05240     /* It is undefined behaviour (for a reason!) to loop through
05241        columns while deleting some of them. Therefore, copy the
05242        structure of the linetable to another (empty) table */
05243     
05244     uves_free_table(&temp);
05245     check(( temp = cpl_table_new(0),
05246         cpl_table_copy_structure(temp, *linetable)),
05247            "Error duplicating line table column structure");
05248     
05249     colname = cpl_table_get_column_name(temp);
05250     while (colname != NULL)
05251         {
05252         if (!(strcmp(colname, "X"        ) == 0 ||
05253               strcmp(colname, "Order"    ) == 0 ||
05254               strcmp(colname, "Ident"    ) == 0 ||
05255           strcmp(colname, "FIBRE"    ) == 0 ||
05256           strcmp(colname, "Fibre"    ) == 0 ||
05257               strcmp(colname, LINETAB_PIXELSIZE) == 0))
05258             {
05259             cpl_table_erase_column(*linetable, colname);
05260             uves_msg_debug("Removing unused column '%s'", colname);
05261             }
05262         
05263         /* Call with NULL argument to get the next column name */
05264         colname = cpl_table_get_column_name(NULL);
05265         }
05266     }
05267     
05268     /* support MIDAS
05269      * Calculate 'Pixel' column (lower case) for MIDAS tables 
05270      */
05271     if ( !cpl_table_has_column(*linetable, LINETAB_PIXELSIZE) )
05272     {
05273         check( create_column_pixelsize(*linetable),
05274            "Error adding 'Pixelsize' column");
05275     }
05276 
05277     /* Remove un-identified lines (where Ident = invalid or Ident = zero) ... */
05278     check( uves_erase_invalid_table_rows(*linetable, "Ident"),
05279        "Error deleting rows with illegal 'Ident' value");
05280 
05281     check( uves_erase_table_rows(*linetable, "Ident", CPL_LESS_THAN, 0.01),
05282        "Error deleting rows with illegal 'Ident' value");
05283     
05284     /* Check for any other invalid value */
05285     assure( uves_erase_invalid_table_rows(*linetable, NULL) == 0, CPL_ERROR_ILLEGAL_INPUT,
05286         "After deleting rows with invalid 'Ident' values, "
05287         "the table in extension %d of file '%s' still contains invalid rows",
05288         base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
05289     
05290     /* Sort line table by 'Order' (ascending), then 'X' (ascending) */
05291     check( uves_sort_table_2(*linetable, "Order", "X", false, false), "Error sorting line table");
05292     
05293   cleanup:
05294     uves_free_propertylist(&primary_header);
05295     uves_free_propertylist(&header);
05296     uves_free_propertylist(&midas_header);
05297     uves_free_table(&temp);
05298     uves_polynomial_delete(&absolute_order_local);
05299     cpl_free(absorders);
05300     if (cpl_error_get_code() != CPL_ERROR_NONE) {
05301     *linetable_filename = NULL;
05302     uves_free_table(linetable);
05303     if (dispersion_relation != NULL) uves_polynomial_delete(dispersion_relation);
05304     if (absolute_order      != NULL) uves_polynomial_delete(absolute_order);
05305     }
05306     return;
05307 }
05308 
05309 /*----------------------------------------------------------------------------*/
05313 /*----------------------------------------------------------------------------*/
05314 void
05315 uves_load_linetable_const(const cpl_frameset *frames, 
05316                           bool flames,
05317                           const char *chip_name,
05318                           const polynomial *order_locations, int minorder, int maxorder,
05319                           const char **linetable_filename,
05320                           const cpl_table **linetable,
05321                           const uves_propertylist **linetable_header,
05322                           const polynomial **dispersion_relation,
05323                           polynomial **absolute_order,
05324                           enum uves_chip chip, int trace_id, int window)
05325 {
05326     uves_load_linetable(frames, flames, chip_name, order_locations, 
05327                         minorder, maxorder, 
05328                         linetable_filename, 
05329                         (cpl_table **)linetable, 
05330                         (uves_propertylist **)linetable_header,
05331                         (polynomial **)dispersion_relation, 
05332                         absolute_order,
05333                         chip, trace_id, window);
05334 }
05335 
05336 
05337 
05338 /*----------------------------------------------------------------------------*/
05353 /*----------------------------------------------------------------------------*/
05354 
05355 cpl_error_code
05356 uves_load_response_curve(const cpl_frameset *frames, const char *chip_name,
05357              const char **response_filename, 
05358              cpl_image **response_curve,
05359              cpl_table **master_response,
05360              uves_propertylist **response_header, enum uves_chip chip)
05361 {
05362     const char *tags[2];
05363     int number_of_tags = sizeof(tags) / sizeof(char *);
05364     int extension;
05365     int indx;
05366     
05367     *response_curve  = NULL;
05368     *response_header = NULL;
05369     *master_response = NULL;
05370     
05371     tags[0]   = UVES_INSTR_RESPONSE (chip);
05372     tags[1]   = UVES_MASTER_RESPONSE(chip);
05373     
05374     check( *response_filename = uves_find_frame(frames, tags, number_of_tags, &indx, 
05375                         NULL), 
05376        "Could not find '%s' in frame set", tags[0]);
05377 
05378  
05379     if (indx == 0)
05380     {
05381         extension = UVES_INSTR_RESPONSE_EXTENSION(chip);
05382         
05383         /* Load the response image
05384            
05385         Note: Even if the response curve was saved as
05386         a FITS file with NAXIS=1, cpl_image_load() will
05387         create an image of size nx1, which is just
05388         what we want
05389         */
05390         check( *response_curve = uves_load_image_file(*response_filename,
05391                                                       /* CPL_TYPE_DOUBLE,  Convert to this type */
05392                             0,               /* plane number */
05393                                                       extension,        /* Extension number */
05394                             
05395 response_header
05396                ),
05397            "Could not load response curve from extension %d of file '%s'", 
05398            extension, *response_filename);
05399 
05400         /* Load the header */
05401 /*
05402         check( *response_header = uves_propertylist_load(*response_filename,
05403                                 extension),
05404            "Could not load header from extension %d of file '%s'", 
05405            extension, *response_filename);
05406 */
05407         check_nomsg( uves_warn_if_chip_names_dont_match(*response_header, chip_name, chip) );
05408     }
05409     else
05410     /* Master response */
05411     {
05412         extension = UVES_MASTER_RESPONSE_EXTENSION(chip);
05413         
05414         check( *master_response = cpl_table_load(*response_filename,
05415                              UVES_LINE_INTMON_TABLE_EXTENSION,
05416                              1),   /* Mark identified 
05417                                   invalid values? (1=yes) */
05418            "Error master response curve from extension %d of file '%s'", 
05419            extension, *response_filename);           
05420 
05421         /* Convert columns to double */
05422         check(( cpl_table_cast_column(*master_response, "LAMBDA", "LAMBDA_double", 
05423                       CPL_TYPE_DOUBLE),
05424             cpl_table_erase_column(*master_response, "LAMBDA"),
05425             cpl_table_name_column(*master_response, "LAMBDA_double", "LAMBDA")),
05426           "Could not cast column 'LAMBDA'");
05427 
05428         check(( cpl_table_cast_column(*master_response, "FLUX_CONV", "FLUX_CONV_double", 
05429                       CPL_TYPE_DOUBLE),
05430             cpl_table_erase_column(*master_response, "FLUX_CONV"),
05431             cpl_table_name_column(*master_response, "FLUX_CONV_double", "FLUX_CONV")),
05432           "Could not cast column 'FLUX_CONV'");
05433 
05434         /* Do not need the header, which also does not contain 
05435            keywords needed for uves_warn_if_chip_names_dont_match() */
05436     }
05437     
05438   cleanup:
05439     if (cpl_error_get_code() != CPL_ERROR_NONE) 
05440     {
05441         *response_filename = NULL;
05442         uves_free_image(response_curve);
05443         uves_free_propertylist(response_header);
05444     }
05445     return cpl_error_get_code();
05446 }
05447 
05448 
05449 /*----------------------------------------------------------------------------*/
05459 /*----------------------------------------------------------------------------*/
05460 cpl_error_code uves_load_lineintmon(const cpl_frameset *frames, 
05461                     const char **line_intmon_filename, 
05462                     cpl_table **line_intmon)
05463 {
05464     const char *tags[1] = {UVES_LINE_INTMON_TABLE};    
05465 
05466     int number_of_tags = sizeof(tags) / sizeof(char *);
05467     int indx;
05468     
05469     /* Get filename */
05470     check( *line_intmon_filename = uves_find_frame(frames, tags, number_of_tags, 
05471                            &indx, NULL),
05472        "No line intensity table (%s) found in SOF", tags[0]);
05473     
05474     /* Load table */
05475     check( *line_intmon = cpl_table_load(*line_intmon_filename,
05476                      UVES_LINE_INTMON_TABLE_EXTENSION,
05477                      1),         /* Mark identified 
05478                             invalid values? (1=yes) */
05479        "Error loading line reference table from extension %d of file '%s'", 
05480        UVES_LINE_INTMON_TABLE_EXTENSION, *line_intmon_filename);
05481 
05482     check(( cpl_table_cast_column(*line_intmon, "WAVE", "Wave", CPL_TYPE_DOUBLE),
05483         cpl_table_erase_column(*line_intmon, "WAVE")),
05484       "Could not cast and rename column");
05485     
05486     /* Sort table by 'Wave' (ascending) */
05487     check(  uves_sort_table_1(*line_intmon, "Wave", false), "Error sorting table");
05488     
05489   cleanup:
05490     if (cpl_error_get_code() != CPL_ERROR_NONE) 
05491     {
05492         *line_intmon_filename = NULL;
05493         uves_free_table(line_intmon);
05494     }
05495     return cpl_error_get_code();
05496 }
05497 
05498 
05499 /*----------------------------------------------------------------------------*/
05512 /*----------------------------------------------------------------------------*/
05513 void
05514 uves_load_corvel(const cpl_frameset *frames,
05515          enum uves_chip chip,
05516          cpl_table **corvel,
05517          uves_propertylist **corvel_header,
05518          const char **corvel_filename)
05519 {
05520     const char *tags[1];
05521     int number_of_tags = sizeof(tags) / sizeof(char *);
05522     int indx;
05523     int extension;
05524 
05525     tags[0] = FLAMES_CORVEL(chip);
05526 
05527     assure_nomsg( corvel != NULL, CPL_ERROR_NULL_INPUT );
05528     assure_nomsg( corvel_filename != NULL, CPL_ERROR_NULL_INPUT );
05529 
05530     /* Get filename */
05531     check( *corvel_filename = uves_find_frame(frames, tags, number_of_tags, 
05532                           &indx, NULL),
05533        "No velocity correction table (%s) found in SOF", tags[0]);
05534     
05535     /* Load table */
05536     extension = 1;
05537     check( *corvel = cpl_table_load(*corvel_filename,
05538                     extension,
05539                     1),         /* Mark identified 
05540                            invalid values? (1=yes) */
05541        "Error loading line reference table from extension %d of file '%s'",
05542        extension, *corvel_filename);
05543 
05544     /* Load header */
05545     if (corvel_header != NULL)
05546     {
05547         extension = 0;
05548         check( *corvel_header = uves_propertylist_load(*corvel_filename,
05549                               extension),
05550            "Could not load header from extension %d of file %s",
05551            extension, *corvel_filename);
05552 
05553     }
05554     
05555   cleanup:
05556     if (cpl_error_get_code() != CPL_ERROR_NONE) 
05557     {
05558         *corvel_filename = NULL;
05559         uves_free_table(corvel);
05560     }
05561     return;
05562 }
05563 
05564 /*----------------------------------------------------------------------------*/
05580 /*----------------------------------------------------------------------------*/
05581 cpl_error_code
05582 uves_load_linerefertable(const cpl_frameset *frames, 
05583              const char **line_refer_filename, 
05584              cpl_table **line_refer, uves_propertylist **line_refer_header)
05585 {
05586     const char *tags[1] = {UVES_LINE_REFER_TABLE};    
05587 
05588     int number_of_tags = sizeof(tags) / sizeof(char *);
05589     int indx;
05590     
05591     /* Get filename */
05592     check( *line_refer_filename = uves_find_frame(frames, tags, number_of_tags, 
05593                           &indx, NULL),
05594        "No line reference table (%s) found in SOF", tags[0]);
05595     
05596     /* Load table */
05597     check( *line_refer = cpl_table_load(*line_refer_filename,
05598                        UVES_LINE_REFER_TABLE_EXTENSION,
05599                        1),         /* Mark identified 
05600                               invalid values? (1=yes) */
05601        "Error loading line reference table from extension %d of file '%s'", 
05602        UVES_LINE_REFER_TABLE_EXTENSION, *line_refer_filename);
05603 
05604     /* Load header if requested */
05605     if (line_refer_header != NULL)
05606     {
05607         check( *line_refer_header = uves_propertylist_load(*line_refer_filename, 0),
05608            "Could not load header of line_refer table in '%s'", *line_refer_filename);
05609     }
05610 
05611     assure( uves_erase_invalid_table_rows(*line_refer, NULL) == 0, CPL_ERROR_ILLEGAL_INPUT,
05612         "Table in extension %d of file '%s' contains invalid rows", 
05613         UVES_LINE_REFER_TABLE_EXTENSION, *line_refer_filename);
05614 
05615     check(( cpl_table_cast_column(*line_refer, "WAVE", "Wave", CPL_TYPE_DOUBLE),
05616         cpl_table_erase_column(*line_refer, "WAVE")),
05617        "Could not cast and rename column");
05618     
05619     /* Write uncertainties of wavelengths.
05620        The value 0.002 is finetuned/retro-fitted to get a chi_sq ~ 1 when
05621        using the new catalogue from
05622 
05623        M. T. Murphy, P. Tzanavaris, J. K. Webb, C. Lovis
05624        "Selection of ThAr lines for wavelength calibration of echelle
05625        spectra and implications for variations in the fine-structure constant",
05626        Submitted to MNRAS
05627     */
05628 
05629 #if 0
05630      check(( cpl_table_duplicate_column(*line_refer, "dWave", *line_refer, "Wave"),
05631            cpl_table_divide_scalar   (*line_refer, "dWave", 300000*10)),
05632        "Error writing wavelength uncertainties");
05633 #else
05634      /* we should do this */
05635     check(( cpl_table_new_column(*line_refer, "dWave", CPL_TYPE_DOUBLE),
05636             cpl_table_fill_column_window(*line_refer,
05637                                          "dWave",
05638                                          0,
05639                                          cpl_table_get_nrow(*line_refer), 0.002)),
05640           "Error writing wavelength uncertainties");
05641 #endif
05642     
05643     /* Sort table by 'Wave' (ascending) */
05644     check(  uves_sort_table_1(*line_refer, "Wave", false), "Error sorting table");
05645     
05646   cleanup:
05647     if (cpl_error_get_code() != CPL_ERROR_NONE) {
05648     *line_refer_filename = NULL;
05649     uves_free_table       (line_refer);
05650     if (line_refer_header != NULL) uves_free_propertylist(line_refer_header);
05651     }
05652     return cpl_error_get_code();
05653 }
05654 
05655 /*----------------------------------------------------------------------------*/
05669 /*----------------------------------------------------------------------------*/
05670 cpl_error_code
05671 uves_load_flux_table(const cpl_frameset *frames, const char **flux_table_filename, 
05672              cpl_table **flux_table)
05673 {
05674     const char *tags[1] = {UVES_FLUX_STD_TABLE};
05675 
05676     int number_of_tags = sizeof(tags) / sizeof(char *);
05677     int indx;
05678     
05679     /* Get filename */
05680     check( *flux_table_filename = uves_find_frame(frames, tags, number_of_tags, 
05681                           &indx, NULL), 
05682        "No standard star flux table (%s) in SOF", tags[0]);
05683 
05684     /* Load table */
05685     check( *flux_table = cpl_table_load(*flux_table_filename,
05686                     UVES_FLUX_STD_TABLE_EXTENSION,
05687                     1),         /* Mark identified 
05688                                invalid values? (1=yes) */
05689        "Error loading flux table from extension %d of file '%s'",
05690        UVES_FLUX_STD_TABLE_EXTENSION, *flux_table_filename);
05691 
05692     if (false)
05693         /* Don't do this, it will remove one std (LTT2415) from the table which has TYPE = NULL.
05694            Instead, set type to "NULL" (this is only used for messages) 
05695         */
05696         {
05697             if (uves_erase_invalid_table_rows(*flux_table, NULL) != 0)
05698                 {
05699                     uves_msg_warning("Table in extension %d of file '%s' contains null values",
05700                                      UVES_FLUX_STD_TABLE_EXTENSION, *flux_table_filename);
05701                 }
05702         }
05703     else
05704         {
05705             int i;
05706             for (i = 0; i < cpl_table_get_nrow(*flux_table); i++)
05707                 {
05708                     if (cpl_table_get_string(*flux_table, "TYPE", i) == NULL)
05709                         {
05710                             cpl_table_set_string(*flux_table, "TYPE", i, "NULL");
05711                         }
05712                 }
05713         }
05714     
05715         
05716   cleanup:
05717     if (cpl_error_get_code() != CPL_ERROR_NONE) 
05718     {
05719         *flux_table_filename = NULL;
05720         uves_free_table(flux_table);
05721     }
05722     return cpl_error_get_code();
05723 }
05724 
05725 
05726 /*----------------------------------------------------------------------------*/
05740 /*----------------------------------------------------------------------------*/
05741 cpl_error_code
05742 uves_load_atmo_ext(const cpl_frameset *frames, const char **atmext_table_filename, 
05743            cpl_table **atmext_table)
05744 {
05745     const char *tags[1] = {UVES_EXTCOEFF_TABLE};
05746     
05747     int number_of_tags = sizeof(tags) / sizeof(char *);
05748     int indx;
05749     
05750     /* Get filename */
05751     check( *atmext_table_filename = uves_find_frame(frames, tags, number_of_tags, 
05752                             &indx, NULL), 
05753        "No atmospheric extinction table (%s) found in SOF", tags[0]);
05754 
05755     /* Load table */
05756     check( *atmext_table = cpl_table_load(*atmext_table_filename,
05757                       UVES_EXTCOEFF_TABLE_EXTENSION,
05758                       1),          /* Mark identified 
05759                               invalid values? (1=yes) */
05760        "Error loading atmospheric extinction table from extension %d of file '%s'",
05761        UVES_EXTCOEFF_TABLE_EXTENSION, *atmext_table_filename);
05762     
05763     assure( uves_erase_invalid_table_rows(*atmext_table, NULL) == 0, CPL_ERROR_ILLEGAL_INPUT,
05764         "Table in extension %d of file '%s' contains invalid rows",
05765         UVES_EXTCOEFF_TABLE_EXTENSION, *atmext_table_filename);
05766     
05767     check( uves_sort_table_1(*atmext_table, "LAMBDA", false),
05768        "Error sorting table");
05769     
05770     /* Convert columns to double */
05771     check(( cpl_table_cast_column(*atmext_table, "LAMBDA", "LAMBDA_double", CPL_TYPE_DOUBLE),
05772         cpl_table_erase_column(*atmext_table, "LAMBDA"),
05773         cpl_table_name_column(*atmext_table, "LAMBDA_double", "LAMBDA")),
05774       "Could not cast column 'LAMBDA'");
05775     
05776     check(( cpl_table_cast_column(*atmext_table, "LA_SILLA", "LA_SILLA_double", CPL_TYPE_DOUBLE),
05777         cpl_table_erase_column(*atmext_table, "LA_SILLA"),
05778         cpl_table_name_column(*atmext_table, "LA_SILLA_double", "LA_SILLA")),
05779       "Could not cast column 'LA_SILLA'");
05780     
05781   cleanup:
05782     if (cpl_error_get_code() != CPL_ERROR_NONE) 
05783     {
05784         *atmext_table_filename = NULL;
05785         uves_free_table(atmext_table);
05786     }
05787     return cpl_error_get_code();
05788 }
05789 /*----------------------------------------------------------------------------*/
05797 /*----------------------------------------------------------------------------*/
05798 char *
05799 uves_guess_order_table_filename(enum uves_chip chip) 
05800 {
05801     return uves_local_filename("orderguesstable", chip, -1, -1);
05802 }
05803 
05804 /*----------------------------------------------------------------------------*/
05812 /*----------------------------------------------------------------------------*/
05813 char *
05814 uves_order_table_filename(enum uves_chip chip) 
05815 {
05816     return uves_local_filename("ordertable", chip, -1, -1);
05817 }
05818 
05819 /*----------------------------------------------------------------------------*/
05826 /*----------------------------------------------------------------------------*/
05827 char *uves_ordef_filename(enum uves_chip chip)
05828 {
05829     return uves_local_filename("order_def", chip, -1, -1);
05830 }
05831 
05832 /*----------------------------------------------------------------------------*/
05840 /*----------------------------------------------------------------------------*/
05841 char *
05842 uves_masterdark_filename(enum uves_chip chip) 
05843 {
05844     return uves_local_filename("masterdark", chip, -1, -1);
05845 }
05846 
05847 
05848 /*----------------------------------------------------------------------------*/
05854 /*----------------------------------------------------------------------------*/
05855 char *
05856 uves_flat_ratio_filename(enum uves_chip chip) 
05857 {
05858     return uves_local_filename("ratio", chip, -1, -1);
05859 }
05860 
05861 /*----------------------------------------------------------------------------*/
05868 /*----------------------------------------------------------------------------*/
05869 char *uves_cd_align_filename(enum uves_chip chip)
05870 {
05871     return uves_local_filename("cd_align", chip, -1, -1);
05872 }
05873 
05874 /*----------------------------------------------------------------------------*/
05882 /*----------------------------------------------------------------------------*/
05883 char *
05884 uves_masterflat_filename(enum uves_chip chip) 
05885 {
05886     return uves_local_filename("masterflat", chip, -1, -1);
05887 }
05888 /*----------------------------------------------------------------------------*/
05896 /*----------------------------------------------------------------------------*/
05897 char *
05898 uves_masterflat_bkg_filename(enum uves_chip chip) 
05899 {
05900     return uves_local_filename("masterflat_bkg", chip, -1, -1);
05901 }
05902 
05903 /*----------------------------------------------------------------------------*/
05911 /*----------------------------------------------------------------------------*/
05912 char *
05913 uves_masterbias_filename(enum uves_chip chip) 
05914 {
05915     return uves_local_filename("masterbias", chip, -1, -1);
05916 }
05917 
05918 /*----------------------------------------------------------------------------*/
05926 /*----------------------------------------------------------------------------*/
05927 char *
05928 uves_guess_line_table_filename(enum uves_chip chip)
05929 {
05930     return uves_local_filename("lineguesstable", chip, -1, -1);
05931 }
05932 /*----------------------------------------------------------------------------*/
05940 /*----------------------------------------------------------------------------*/
05941 char *
05942 uves_line_table_filename(enum uves_chip chip)
05943 {
05944     return uves_local_filename("linetable", chip, -1, -1);
05945 }
05946 
05947 /*----------------------------------------------------------------------------*/
05955 /*----------------------------------------------------------------------------*/
05956 char *
05957 uves_line_table_filename_paf(enum uves_chip chip)
05958 {
05959     return uves_local_filename("linetable_paf", chip, -1, -1);
05960 }
05961 
05962 /*----------------------------------------------------------------------------*/
05970 /*----------------------------------------------------------------------------*/
05971 char *
05972 uves_response_curve_filename(enum uves_chip chip)
05973 {
05974     return uves_local_filename("response", chip, -1, -1);
05975 }
05976 
05977 /*----------------------------------------------------------------------------*/
05985 /*----------------------------------------------------------------------------*/
05986 char *
05987 uves_response_curve_2d_filename(enum uves_chip chip)
05988 {
05989     return uves_local_filename("response_2d", chip, -1, -1);
05990 }
05991 
05992 /*----------------------------------------------------------------------------*/
06000 /*----------------------------------------------------------------------------*/
06001 char *
06002 uves_response_red_standard_filename(enum uves_chip chip)
06003 {
06004     return uves_local_filename("red_std", chip, -1, -1);
06005 }
06006 
06007 /*----------------------------------------------------------------------------*/
06015 /*----------------------------------------------------------------------------*/
06016 char *
06017 uves_response_bkg_standard_filename(enum uves_chip chip)
06018 {
06019     return uves_local_filename("bkg_std", chip, -1, -1);
06020 }
06021 
06022 /*----------------------------------------------------------------------------*/
06030 /*----------------------------------------------------------------------------*/
06031 char *
06032 uves_response_efficiency_filename(enum uves_chip chip)
06033 {
06034     return uves_local_filename("efficiency", chip, -1, -1);
06035 }
06036 
06037 /*----------------------------------------------------------------------------*/
06045 /*----------------------------------------------------------------------------*/
06046 
06047 char *
06048 uves_scired_red_2d_science_filename(enum uves_chip chip)
06049 {
06050     return uves_local_filename("red_2d_science", chip, -1, -1);
06051 }
06052 
06060 /*----------------------------------------------------------------------------*/
06061 
06062 
06063 
06064 char *
06065 uves_scired_red_science_filename(enum uves_chip chip)
06066 {
06067     return uves_local_filename("red_science", chip, -1, -1);
06068 }
06069 /*----------------------------------------------------------------------------*/
06077 /*----------------------------------------------------------------------------*/
06078 char *
06079 uves_scired_red_error_filename(enum uves_chip chip)
06080 {
06081     return uves_local_filename("error_red_science", chip, -1, -1);
06082 }
06083 
06084 /*----------------------------------------------------------------------------*/
06092 /*----------------------------------------------------------------------------*/
06093 char *
06094 uves_scired_red_2d_error_filename(enum uves_chip chip)
06095 {
06096     return uves_local_filename("error_2d_science", chip, -1, -1);
06097 }
06098 
06099 
06100 /*----------------------------------------------------------------------------*/
06108 /*----------------------------------------------------------------------------*/
06109 char *
06110 uves_scired_fluxcal_science_filename(enum uves_chip chip)
06111 {
06112     return uves_local_filename("fluxcal_science", chip, -1, -1);
06113 }
06114 /*----------------------------------------------------------------------------*/
06122 /*----------------------------------------------------------------------------*/
06123 char *
06124 uves_scired_fluxcal_error_filename(enum uves_chip chip)
06125 {
06126     return uves_local_filename("fluxcal_error_science", chip, -1, -1);
06127 }
06128 
06129 
06130 
06138 /*----------------------------------------------------------------------------*/
06139 char *
06140 uves_scired_fluxcal_science_2d_filename(enum uves_chip chip)
06141 {
06142     return uves_local_filename("fluxcal_2d_science", chip, -1, -1);
06143 }
06144 /*----------------------------------------------------------------------------*/
06152 /*----------------------------------------------------------------------------*/
06153 char *
06154 uves_scired_fluxcal_error_2d_filename(enum uves_chip chip)
06155 {
06156     return uves_local_filename("fluxcal_error_2d_science", chip, -1, -1);
06157 }
06158 /*----------------------------------------------------------------------------*/
06166 /*----------------------------------------------------------------------------*/
06167 char *
06168 uves_scired_ff_variance_filename(enum uves_chip chip)
06169 {
06170     return uves_local_filename("variance_ff_science", chip, -1, -1);
06171 }
06172 
06173 /*----------------------------------------------------------------------------*/
06181 /*----------------------------------------------------------------------------*/
06182 char *
06183 uves_scired_ff_variance_2d_filename(enum uves_chip chip)
06184 {
06185     return uves_local_filename("variance_ff_2d_science", chip, -1, -1);
06186 }
06187 
06188 /*----------------------------------------------------------------------------*/
06195 /*----------------------------------------------------------------------------*/
06196 char *
06197 uves_scired_merged_2d_science_filename(enum uves_chip chip)
06198 {
06199     return uves_local_filename("merged_2d_science", chip, -1, -1);
06200 }
06201 
06209 /*----------------------------------------------------------------------------*/
06210 char *
06211 uves_scired_merged_science_filename(enum uves_chip chip)
06212 {
06213     return uves_local_filename("merged_science", chip, -1, -1);
06214 }
06215 /*----------------------------------------------------------------------------*/
06223 /*----------------------------------------------------------------------------*/
06224 char *
06225 uves_scired_merged_sky_filename(enum uves_chip chip)
06226 {
06227     return uves_local_filename("merged_sky", chip, -1, -1);
06228 }
06229 
06230 /*----------------------------------------------------------------------------*/
06238 /*----------------------------------------------------------------------------*/
06239 char *
06240 uves_scired_background_filename(enum uves_chip chip)
06241 {
06242     return uves_local_filename("background", chip, -1, -1);
06243 }
06244 
06245 /*----------------------------------------------------------------------------*/
06253 /*----------------------------------------------------------------------------*/
06254 char *
06255 uves_scired_resampled_filename(enum uves_chip chip)
06256 {
06257     return uves_local_filename("resampled_science", chip, -1, -1);
06258 }
06259 
06260 /*----------------------------------------------------------------------------*/
06268 /*----------------------------------------------------------------------------*/
06269 char *
06270 uves_scired_resampledmf_filename(enum uves_chip chip)
06271 {
06272     return uves_local_filename("resampled_mflat", chip, -1, -1);
06273 }
06274 
06275 /*----------------------------------------------------------------------------*/
06284 /*----------------------------------------------------------------------------*/
06285 char *
06286 uves_scired_rebinned_filename(enum uves_chip chip)
06287 {
06288     return uves_local_filename("resampled_ff_science", chip, -1, -1);
06289 }
06290 
06291 
06300 /*----------------------------------------------------------------------------*/
06301 char *
06302 uves_scired_rebinned_2d_filename(enum uves_chip chip)
06303 {
06304     return uves_local_filename("resampled_ff_2d_science", chip, -1, -1);
06305 }
06306 /*----------------------------------------------------------------------------*/
06314 /*----------------------------------------------------------------------------*/
06315 char *
06316 uves_scired_ordertrace_filename(enum uves_chip chip)
06317 {
06318     return uves_local_filename("ordertrace", chip, -1, -1);
06319 }
06320 
06321 /*----------------------------------------------------------------------------*/
06329 /*----------------------------------------------------------------------------*/
06330 char *
06331 uves_scired_crmask_filename(enum uves_chip chip)
06332 {
06333     return uves_local_filename("cr_mask", chip, -1, -1);
06334 }
06335 
06336 
06337 /*----------------------------------------------------------------------------*/
06345 /*----------------------------------------------------------------------------*/
06346 char *uves_scired_ext2d_filename(enum uves_chip chip)
06347 {
06348     return uves_local_filename("ext_2d_science", chip, -1, -1);
06349 }
06350 
06351 /*----------------------------------------------------------------------------*/
06359 /*----------------------------------------------------------------------------*/
06360 char *uves_scired_ff2d_filename(enum uves_chip chip)
06361 {
06362     return uves_local_filename("ff_2d_science", chip, -1, -1);
06363 }
06364 
06365 /*----------------------------------------------------------------------------*/
06386 /*----------------------------------------------------------------------------*/
06387 static char *
06388 uves_local_filename(const char *prefix, enum uves_chip chip, int trace, int window)
06389 {
06390     char *result = NULL;
06391     const char *chip_string;
06392     const char *suffix = ".fits";     /* Always */
06393     char *t = NULL;
06394     char *w = NULL;
06395 
06396     assure( (trace < 0 && window < 0) ||           /* Empty suffix          */
06397         (trace < 0 && window > 0) ||           /* Window only suffix    */
06398         (trace >= 0 && window > 0),            /* Trace & window suffix */
06399         CPL_ERROR_ILLEGAL_INPUT, "Illegal trace and window numbers: (%d, %d)", 
06400         trace, window);
06401 
06402     /* Chip */
06403     chip_string = uves_chip_tostring_lower(chip);
06404     
06405     /* Trace and window number (possibly empty string) */
06406     check(( t = int_to_string(trace),
06407         w = int_to_string(window)),
06408           "Error creating substrings");
06409 
06410 /* old code:
06411     result = cpl_calloc(strlen(prefix) + 1 + 
06412             strlen(chip_string) + strlen(t) + strlen(w) + strlen(suffix) + 1,
06413             sizeof(char));
06414     
06415     assure_mem( result );
06416     
06417     strcpy(result, prefix);
06418     strcat(result, "_");
06419     strcat(result, chip_string);
06420     strcat(result, t);
06421     strcat(result, w);
06422     strcat(result, suffix);
06423 */
06424     result = uves_sprintf("%s_%s%s%s%s", prefix, chip_string, t, w, suffix);
06425     assure_mem( result );
06426 
06427   cleanup:
06428     cpl_free(t);
06429     cpl_free(w);
06430     if (cpl_error_get_code() != CPL_ERROR_NONE)
06431     {
06432         cpl_free(result); result = NULL;
06433     }
06434     return result;
06435 }
06436 
06437 /*----------------------------------------------------------------------------*/
06448 /*----------------------------------------------------------------------------*/
06449 static char *
06450 int_to_string(int i)
06451 {
06452     char *result = NULL;
06453 
06454     assure( -1 <= i, CPL_ERROR_ILLEGAL_INPUT, "Illegal number (%d)", i);
06455 
06456     if (i == -1)
06457     {
06458         /* Empty string */
06459         result = cpl_calloc(1, sizeof(char));
06460         assure_mem( result );
06461     }
06462     else
06463     {
06464         result = uves_sprintf("_%d", i);
06465     }
06466     
06467   cleanup:
06468     if (cpl_error_get_code() != CPL_ERROR_NONE){
06469     cpl_free(result); result = NULL;
06470     }
06471     return result;
06472 }
06473 
06474 
06475 /*----------------------------------------------------------------------------*/
06485 /*----------------------------------------------------------------------------*/
06486 
06487 cpl_image*
06488 uves_vector_to_image(const cpl_vector* vector,cpl_type type)
06489 {
06490   int i=0;
06491   cpl_image* image=NULL;
06492   int size=0;
06493   const double* pv=NULL;
06494   int* pi=NULL;
06495   float* pf=NULL;
06496   double* pd=NULL;
06497 
06498 
06499       size=cpl_vector_get_size(vector);
06500       image=cpl_image_new(size,1,type);
06501       pv=cpl_vector_get_data_const(vector);
06502       if(type == CPL_TYPE_INT) {
06503         pi=cpl_image_get_data_int(image);
06504         for(i=0;i<size;i++) {
06505       pi[i]=pv[i];
06506     }
06507       } else if (type == CPL_TYPE_FLOAT) {
06508         pf=cpl_image_get_data_float(image);
06509         for(i=0;i<size;i++) {
06510       pf[i]=pv[i];
06511     }
06512       } else if (type == CPL_TYPE_DOUBLE) {
06513         pd=cpl_image_get_data_double(image);
06514         for(i=0;i<size;i++) {
06515       pd[i]=pv[i];
06516     }
06517       } else {
06518         assure( false, CPL_ERROR_INVALID_TYPE,
06519             "No CPL type to represent BITPIX = %d", type);
06520       }
06521 
06522  cleanup:
06523     if (cpl_error_get_code() != CPL_ERROR_NONE){
06524       uves_free_image(&image);
06525     }
06526 
06527     return image;
06528 
06529 }

Generated on Fri Apr 18 14:11:42 2008 for UVES Pipeline Reference Manual by  doxygen 1.5.1