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: 2007/06/06 08:17:33 $
00023  * $Revision: 1.206 $
00024  * $Name: uves-3_3_1 $
00025  * $Log: uves_dfs.c,v $
00026  * Revision 1.206  2007/06/06 08:17:33  amodigli
00027  * replace tab with 4 spaces
00028  *
00029  * Revision 1.205  2007/05/23 12:50:53  jmlarsen
00030  * Replace isnan/isinf -> irplib_isnan/irplib_isinf
00031  *
00032  * Revision 1.204  2007/05/16 14:56:27  jmlarsen
00033  * Fixed error message
00034  *
00035  * Revision 1.203  2007/05/16 11:47:18  amodigli
00036  * added FLAMES_SCI_COM_RED
00037  *
00038  * Revision 1.202  2007/05/04 08:55:15  amodigli
00039  * moved up declaration of img to suppress compilation warning
00040  *
00041  * Revision 1.201  2007/05/03 15:19:10  jmlarsen
00042  * Added const version of uves_load_linetable()
00043  *
00044  * Revision 1.200  2007/05/02 13:36:14  jmlarsen
00045  * Decreased verbosity of debug message
00046  *
00047  * Revision 1.199  2007/05/02 13:16:30  jmlarsen
00048  * Fixed error message typo
00049  *
00050  * Revision 1.198  2007/04/26 13:19:11  jmlarsen
00051  * Exported function copy_if_possible
00052  *
00053  * Revision 1.197  2007/04/24 16:44:26  amodigli
00054  * changed interface uves_load_ordertable to return also extention table
00055  *
00056  * Revision 1.196  2007/04/24 12:50:29  jmlarsen
00057  * Replaced cpl_propertylist -> uves_propertylist which is much faster
00058  *
00059  * Revision 1.195  2007/04/23 06:59:29  amodigli
00060  * added uves_save_imagelist
00061  *
00062  * Revision 1.194  2007/04/12 12:15:12  jmlarsen
00063  * Propagate keyword OS-EXPOI
00064  *
00065  * Revision 1.193  2007/04/12 11:58:46  jmlarsen
00066  * Rename order table column if necessary
00067  *
00068  * Revision 1.192  2007/04/10 07:06:59  jmlarsen
00069  * Take into account 64 pixel gap in REDU CRVAL2 computation
00070  *
00071  * Revision 1.191  2007/04/04 06:27:06  jmlarsen
00072  * Fixed malloc -> cpl_malloc
00073  *
00074  * Revision 1.190  2007/04/03 11:02:25  jmlarsen
00075  * Support reading float MIDAS arrays
00076  *
00077  * Revision 1.189  2007/04/03 08:03:59  jmlarsen
00078  * uves_read_midas_array: support arrays of any length
00079  *
00080  * Revision 1.188  2007/04/03 06:28:45  amodigli
00081  * uves_load_ordertable provides now fibre_mask and fibre_pos if appropriate
00082  *
00083  * Revision 1.187  2007/03/30 07:06:59  jmlarsen
00084  * Initialize variables to suppress warnings
00085  *
00086  * Revision 1.186  2007/03/23 07:59:30  jmlarsen
00087  * Fixed minor memory leak
00088  *
00089  * Revision 1.185  2007/03/20 15:39:46  amodigli
00090  * added FLAMES tags
00091  *
00092  * Revision 1.184  2007/03/20 07:26:57  jmlarsen
00093  * Don't remove std star from flux table which has NULL type
00094  *
00095  * Revision 1.183  2007/03/15 15:04:34  jmlarsen
00096  * Allow spaces in HISTORY keyword string values
00097  *
00098  * Revision 1.182  2007/03/05 10:16:12  jmlarsen
00099  * Define 'dWave' as constant
00100  *
00101  * Revision 1.181  2007/02/27 14:04:35  jmlarsen
00102  * Added comment
00103  *
00104  * Revision 1.180  2007/02/26 13:27:53  jmlarsen
00105  * Partial workaround for slow uves_propertylist_copy_property_regexp()
00106  *
00107  * Revision 1.179  2007/02/22 15:33:24  jmlarsen
00108  * Redefine catalogue wavelength uncertainties to better match new catalogue
00109  *
00110  * Revision 1.178  2007/02/14 14:06:34  jmlarsen
00111  * Use REF_TFLAT, not MASTER_TFLAT as master
00112  *
00113  * Revision 1.177  2007/02/12 10:09:33  jmlarsen
00114  * Fixed recently introduced bug that REDL image was loaded twice, instead of REDL + REDU
00115  *
00116  * Revision 1.176  2007/02/09 13:36:04  jmlarsen
00117  * Added function to load ref_flat
00118  *
00119  * Revision 1.175  2007/02/09 08:51:06  jmlarsen
00120  * Use define's rather than hard-coded recipe names
00121  *
00122  * Revision 1.174  2007/02/09 08:03:08  jmlarsen
00123  * Changed definition of CRVAL in products
00124  *
00125  * Revision 1.173  2007/02/08 07:33:01  jmlarsen
00126  * Added uves_load_cd_align(), changed CRVAL computation
00127  *
00128  * Revision 1.172  2007/02/01 07:23:44  jmlarsen
00129  * Removed debugging code
00130  *
00131  * Revision 1.171  2007/01/31 15:18:52  jmlarsen
00132  * Write +- FLT_MAX to FITS file if double value out of range
00133  *
00134  * Revision 1.170  2007/01/31 15:10:34  jmlarsen
00135  * Avoid inf+nan when saving FITS files
00136  *
00137  * Revision 1.169  2007/01/17 13:25:39  jmlarsen
00138  * Added uves_load_image()
00139  *
00140  * Revision 1.168  2007/01/16 10:27:30  jmlarsen
00141  * Implemented self-consistent propagation of FITS geometry keywords
00142  *
00143  * Revision 1.167  2007/01/15 08:45:27  jmlarsen
00144  * Added comment
00145  *
00146  * Revision 1.166  2007/01/10 12:37:16  jmlarsen
00147  * Exported function to warn about mismatching calibration frames
00148  *
00149  * Revision 1.165  2007/01/09 17:45:42  amodigli
00150  * added uves_check_rec_status
00151  *
00152  * Revision 1.164  2006/12/12 12:09:14  jmlarsen
00153  * Added function to load corvel table
00154  *
00155  * Revision 1.163  2006/12/11 12:34:01  jmlarsen
00156  * Use date to determine new/old format
00157  *
00158  * Revision 1.162  2006/12/07 08:22:59  jmlarsen
00159  * uves_load_raw_imagelist: support FLAMES
00160  *
00161  * Revision 1.161  2006/12/01 08:26:56  jmlarsen
00162  * Load FLAMES order table oshift/yshift
00163  *
00164  * Revision 1.160  2006/11/24 16:21:07  jmlarsen
00165  * Added FIB_LINE_TABLE_x
00166  *
00167  * Revision 1.159  2006/11/24 11:10:14  jmlarsen
00168  * Support for loading FLAMES guess line table
00169  *
00170  * Revision 1.158  2006/11/24 09:35:40  jmlarsen
00171  * Workaround for slow uves_propertylist_get_size
00172  *
00173  * Revision 1.157  2006/11/23 10:04:11  jmlarsen
00174  * Minor message change
00175  *
00176  * Revision 1.156  2006/11/22 08:39:55  jmlarsen
00177  * Exported and fixed bug in uves_read_midas_array
00178  *
00179  * Revision 1.154  2006/11/22 08:22:29  jmlarsen
00180  * Set message level according to preprocessor symbol
00181  *
00182  * Revision 1.153  2006/11/16 14:08:33  jmlarsen
00183  * Implemented loading FLAMES ordertable
00184  *
00185  * Revision 1.152  2006/11/16 09:51:13  jmlarsen
00186  * Use compile time branching to support both released and development CPL versions
00187  *
00188  * Revision 1.151  2006/11/16 08:32:03  jmlarsen
00189  * Save CPL_TYPE_INT images as 16 bit unsigned, to support flames_cal_orderpos
00190  *
00191  * Revision 1.150  2006/11/15 15:02:14  jmlarsen
00192  * Implemented const safe workarounds for CPL functions
00193  *
00194  * Revision 1.148  2006/11/15 14:04:08  jmlarsen
00195  * Removed non-const version of parameterlist_get_first/last/next which is already 
00196  * in CPL, added const-safe wrapper, unwrapper and deallocator functions
00197  *
00198  * Revision 1.147  2006/11/13 14:23:55  jmlarsen
00199  * Removed workarounds for CPL const bugs
00200  *
00201  * Revision 1.146  2006/11/13 12:44:31  jmlarsen
00202  * Support FLAMES FIB_ARC_LAMP_RED frames
00203  *
00204  * Revision 1.145  2006/11/08 14:03:31  jmlarsen
00205  * Fixed doc bug when warning about deprecated background table
00206  *
00207  * Revision 1.144  2006/11/08 08:03:26  jmlarsen
00208  * Avoid initializers not computable at compile time, for portability
00209  *
00210  * Revision 1.143  2006/11/07 14:01:10  jmlarsen
00211  * Moved flames_load_ functions to separate source file
00212  *
00213  * Revision 1.142  2006/11/06 15:19:41  jmlarsen
00214  * Removed unused include directives
00215  *
00216  * Revision 1.141  2006/11/03 15:01:21  jmlarsen
00217  * Killed UVES 3d table module and use CPL 3d tables
00218  *
00219  * Revision 1.140  2006/10/26 14:02:41  jmlarsen
00220  * Removed redundant goto
00221  *
00222  * Revision 1.139  2006/10/24 14:05:23  jmlarsen
00223  * Generalized load functions to support FLAMES
00224  *
00225  * Revision 1.138  2006/10/19 13:53:25  jmlarsen
00226  * Changed guess line table tag to LINE_GUESS_TAB
00227  *
00228  * Revision 1.137  2006/10/12 11:37:28  jmlarsen
00229  * Temporarily disabled FLAMES code generation
00230  *
00231  * Revision 1.136  2006/10/10 11:29:24  jmlarsen
00232  * Added code to propagate TM-START
00233  *
00234  * Revision 1.135  2006/10/10 11:20:47  jmlarsen
00235  * Renamed line table columns to match MIDAS
00236  *
00237  * Revision 1.134  2006/10/05 11:14:59  jmlarsen
00238  * Removed debugging code
00239  *
00240  * Revision 1.133  2006/10/02 08:34:04  jmlarsen
00241  * Added REF_TFLAT
00242  *
00243  * Revision 1.132  2006/09/27 13:13:26  jmlarsen
00244  * Use dynamic memory allocation to store bad pixels
00245  *
00246  * Revision 1.131  2006/09/20 15:42:17  jmlarsen
00247  * Implemented MASTER_RESPONSE support
00248  *
00249  * Revision 1.130  2006/09/20 10:56:50  jmlarsen
00250  * Propagate DATAMEAN/DATAMED/DATARMS if present
00251  *
00252  * Revision 1.129  2006/09/19 14:25:30  jmlarsen
00253  * Propagate FITS keywords from master flat, not science, to WCALIB_FLAT_OBJ
00254  *
00255  * Revision 1.128  2006/09/19 06:55:06  jmlarsen
00256  * Changed interface of uves_frameset to optionally write image statistics kewwords
00257  *
00258  * Revision 1.127  2006/09/14 08:46:51  jmlarsen
00259  * Added support for TFLAT, SCREEN_FLAT frames
00260  *
00261  * Revision 1.126  2006/09/08 14:04:41  jmlarsen
00262  * Documentation update
00263  *
00264  * Revision 1.125  2006/08/31 07:24:57  jmlarsen
00265  * Fixed buffer overruns happening when raw frames are not available
00266  *
00267  * Revision 1.124  2006/08/24 11:36:56  jmlarsen
00268  * Write recipe start/stop time to header
00269  *
00270  * Revision 1.123  2006/08/23 09:33:03  jmlarsen
00271  * Renamed local variables shadowing POSIX reserved names
00272  *
00273  * Revision 1.122  2006/08/21 07:53:17  jmlarsen
00274  * Added debug message
00275  *
00276  * Revision 1.121  2006/08/18 13:32:13  jmlarsen
00277  * Use legal FITS keywords for TRACEID/WINDOW/FABSORD/LABSORD
00278  *
00279  * Revision 1.120  2006/08/18 07:07:43  jmlarsen
00280  * Switched order of cpl_calloc arguments
00281  *
00282  * Revision 1.119  2006/08/17 14:11:25  jmlarsen
00283  * Use assure_mem macro to check for memory allocation failure
00284  *
00285  * Revision 1.118  2006/08/17 13:56:52  jmlarsen
00286  * Reduced max line length
00287  *
00288  * Revision 1.117  2006/08/17 13:04:10  jmlarsen
00289  * Reduced max line length
00290  *
00291  * Revision 1.116  2006/08/17 09:17:15  jmlarsen
00292  * Removed CPL2 code
00293  *
00294  * Revision 1.115  2006/08/11 14:56:05  amodigli
00295  * removed Doxygen warnings
00296  *
00297  * Revision 1.114  2006/08/11 11:26:59  jmlarsen
00298  * Change text message
00299  *
00300  * Revision 1.113  2006/08/11 08:59:07  jmlarsen
00301  * Take into account the different meanings of line table 'Y' column
00302  *
00303  * Revision 1.112  2006/08/08 12:55:00  jmlarsen
00304  * Support uppercase column names when loading linetable
00305  *
00306  * Revision 1.111  2006/08/08 11:27:18  amodigli
00307  * upgrade to CPL3
00308  *
00309  * Revision 1.110  2006/08/07 14:42:02  jmlarsen
00310  * Implemented on-the-fly correction of a line table when its 
00311  * order numbering is inconsistent with the order table (DFS02694)
00312  *
00313  * Revision 1.109  2006/08/07 12:14:13  jmlarsen
00314  * Removed unused code
00315  *
00316  * Revision 1.108  2006/08/01 14:43:36  amodigli
00317  * fixed bug loading fitsheader in uves_load_masterformatcheck
00318  *
00319  * Revision 1.107  2006/07/31 06:29:05  amodigli
00320  * added flames_load_frame_index
00321  *
00322  * Revision 1.106  2006/07/14 12:19:28  jmlarsen
00323  * Support multiple QC tests per product
00324  *
00325  * Revision 1.105  2006/07/03 12:59:14  jmlarsen
00326  * Changed message to debug level
00327  *
00328  * Revision 1.104  2006/06/29 07:57:21  amodigli
00329  * fixed warning messages from make html
00330  *
00331  * Revision 1.103  2006/06/29 07:32:05  amodigli
00332  * removed warning from make html
00333  *
00334  * Revision 1.102  2006/06/28 13:27:50  amodigli
00335  * Fixed problem dumping ARCFILE key changing uves_save_paf interface
00336  *
00337  * Revision 1.101  2006/06/26 07:54:14  amodigli
00338  * flames_load_image flames_load_table
00339  *
00340  * Revision 1.100  2006/06/23 15:31:32  amodigli
00341  * added useful stuff for flames
00342  *
00343  * Revision 1.99  2006/06/22 15:25:35  amodigli
00344  * changes for flames_cal_prep_sff_ofpos
00345  *
00346  * Revision 1.98  2006/06/22 12:03:56  amodigli
00347  * clean msg warning
00348  *
00349  * Revision 1.97  2006/06/22 09:42:56  jmlarsen
00350  * Removed syntax error
00351  *
00352  * Revision 1.96  2006/06/22 08:57:38  jmlarsen
00353  * Changed a few messages
00354  *
00355  * Revision 1.95  2006/06/22 06:42:38  amodigli
00356  * fixed some compilation warnings
00357  *
00358  * Revision 1.94  2006/06/20 08:25:56  amodigli
00359  * fixed doxigen warnings
00360  *
00361  * Revision 1.93  2006/06/19 06:51:14  amodigli
00362  * added support flames-old format
00363  *
00364  * Revision 1.92  2006/06/16 08:22:01  jmlarsen
00365  * Manually propagate ESO.DET. keywords from 1st/2nd input header
00366  *
00367  * Revision 1.91  2006/06/13 11:55:06  jmlarsen
00368  * Shortened max line length
00369  *
00370  * Revision 1.90  2006/06/05 08:51:55  amodigli
00371  * cleaned some warnings from static checks
00372  *
00373  * Revision 1.89  2006/06/01 14:43:17  jmlarsen
00374  * Added missing documentation
00375  *
00376  * Revision 1.88  2006/06/01 14:21:02  amodigli
00377  * frm --> frm_tmp, dup --> frm_dup
00378  *
00379  * Revision 1.87  2006/05/31 09:51:01  amodigli
00380  * removed compilation warning
00381  *
00382  * Revision 1.86  2006/05/22 06:47:15  amodigli
00383  * fixed some bugs on msflat
00384  *
00385  * Revision 1.85  2006/05/19 13:07:52  amodigli
00386  * modified to support SFLATs
00387  *
00388  * Revision 1.84  2006/05/17 09:54:55  amodigli
00389  * added supposr SFLATs
00390  *
00391  * Revision 1.82  2006/05/15 06:09:52  amodigli
00392  * added support for some FLAMES input frames
00393  *
00394  * Revision 1.81  2006/05/12 15:01:30  jmlarsen
00395  * Changed msg level warning -> debug when there's no QC log
00396  *
00397  * Revision 1.80  2006/04/25 14:58:48  amodigli
00398  * added paf creation functionalities
00399  *
00400  * Revision 1.79  2006/04/24 09:18:06  jmlarsen
00401  * Minor message change
00402  *
00403  * Revision 1.78  2006/04/20 10:48:20  amodigli
00404  * inform that no QC log is provided
00405  *
00406  * Revision 1.77  2006/04/10 12:35:42  jmlarsen
00407  * Simplified the save-product function
00408  *
00409  * Revision 1.76  2006/04/06 13:12:54  jmlarsen
00410  * Fixed doc. bug
00411  *
00412  * Revision 1.75  2006/04/06 12:56:50  jmlarsen
00413  * Added support for PDARK, IFLAT, DLFAT frames
00414  *
00415  * Revision 1.74  2006/04/06 11:48:17  jmlarsen
00416  * Support for SCI_POINT_-, SCI_EXTND_- and SCI_SLICER-frames
00417  *
00418  * Revision 1.73  2006/04/06 09:48:15  amodigli
00419  * changed uves_frameset_insert interface to have QC log
00420  *
00421  * Revision 1.72  2006/04/06 08:31:15  jmlarsen
00422  * Added support for reading MASTER_DFLAT, MASTER_IFLAT, MASTER_PDARK
00423  *
00424  * Revision 1.71  2006/03/24 14:24:29  jmlarsen
00425  * Don't blindly stack flat-fields of different wavelenghts
00426  *
00427  * Revision 1.70  2006/03/09 10:51:58  jmlarsen
00428  * Added timing info
00429  *
00430  * Revision 1.69  2006/03/06 09:22:43  jmlarsen
00431  * Added support for reading MIDAS line tables with MIDAS tags
00432  *
00433  * Revision 1.68  2006/03/03 13:54:11  jmlarsen
00434  * Changed syntax of check macro
00435  *
00436  * Revision 1.67  2006/02/15 13:19:15  jmlarsen
00437  * Reduced source code max. line length
00438  *
00439  * Revision 1.66  2006/01/17 10:14:20  jmlarsen
00440  * Changed order of functions
00441  *
00442  * Revision 1.65  2006/01/16 07:10:53  amodigli
00443  *
00444  * Clean
00445  *
00446  * Revision 1.64  2006/01/09 15:22:53  jmlarsen
00447  * Removed some warnings
00448  *
00449  * Revision 1.63  2006/01/09 14:05:21  amodigli
00450  * Fixed doxigen warnings
00451  *
00452  * Revision 1.62  2006/01/03 16:56:53  amodigli
00453  * Added MASTER_ARC_FORM
00454  *
00455  * Revision 1.61  2005/12/19 16:17:56  jmlarsen
00456  * Replaced bool -> int
00457  *
00458  */
00459 
00460 #ifdef HAVE_CONFIG_H
00461 #include <config.h>
00462 #endif
00463 
00464 /*----------------------------------------------------------------------------*/
00471 /*----------------------------------------------------------------------------*/
00472 
00473 /*-----------------------------------------------------------------------------
00474                                    Includes
00475  -----------------------------------------------------------------------------*/
00476 
00477 #include <uves_dfs.h>
00478 
00479 #include <uves_utils.h>
00480 #include <uves_wavecal_utils.h>
00481 #include <uves_pfits.h>
00482 #include <uves_dump.h>
00483 #include <uves_qclog.h>
00484 #include <uves.h>
00485 #include <uves_utils_wrappers.h>
00486 #include <uves_error.h>
00487 #include <uves_msg.h>
00488 
00489 #include <irplib_utils.h>
00490 #include <irplib_access.h>
00491 
00492 #include <cpl.h>
00493 
00494 #include <qfits.h> /* iso time */
00495 
00496 #include <float.h>
00497 
00498 /*-----------------------------------------------------------------------------
00499                                    Defines
00500  -----------------------------------------------------------------------------*/
00501 
00502 #define DICTIONARY "PRO-1.15"
00503 /*-----------------------------------------------------------------------------
00504                                    Prototypes
00505  -----------------------------------------------------------------------------*/
00506 
00507 static cpl_error_code write_statistics(const cpl_image *image, uves_propertylist *header,
00508                        unsigned stats_mask);
00509 static polynomial *load_polynomial(const char* filename, int extension);
00510 static char *uves_local_filename(const char *prefix, enum uves_chip chip, int trace, int window);
00511 static char *int_to_string(int i);
00512 
00513 static cpl_error_code
00514 load_raw_image(const char *filename, 
00515            cpl_type type, bool flames, bool blue,
00516            cpl_image *raw_image[2],
00517            uves_propertylist *raw_header[2], 
00518            uves_propertylist *rotated_header[2]);
00519 
00527 int uves_check_rec_status(const int val) {
00528    if(cpl_error_get_code() != CPL_ERROR_NONE) {
00529       uves_msg_error("error before %d",val);
00530       uves_msg_error((char* ) cpl_error_get_message());
00531       uves_msg_error((char* ) cpl_error_get_where());
00532       return -1;
00533     }
00534     return 0;
00535 }
00536 
00537 
00538 /*----------------------------------------------------------------------------*/
00545 /*----------------------------------------------------------------------------*/
00546 cpl_error_code
00547 uves_frameset_merge(cpl_frameset * set1, const cpl_frameset* set2)
00548 {
00549 
00550     const cpl_frame* frm_tmp=NULL;
00551     cpl_frame* frm_dup=NULL;
00552 
00553   passure(set1 != NULL, "Wrong input set");
00554   passure(set2 != NULL, "Wrong input set");
00555   
00556   for (frm_tmp = irplib_frameset_get_first_const(set2);
00557        frm_tmp != NULL;
00558        frm_tmp = irplib_frameset_get_next_const(set2))
00559       {
00560       frm_dup = cpl_frame_duplicate(frm_tmp);
00561       cpl_frameset_insert(set1, frm_dup);
00562       }
00563   
00564   cleanup:
00565   return cpl_error_get_code();
00566 }
00567 
00568 /*----------------------------------------------------------------------------*/
00576 /*----------------------------------------------------------------------------*/
00577 
00578 cpl_error_code
00579 uves_extract_frames_group_type(const cpl_frameset * set, cpl_frameset** ext, cpl_frame_group type)
00580 {
00581     const cpl_frame* frm_tmp=NULL;
00582   cpl_frame* frm_dup=NULL;
00583   cpl_frame_group g;
00584 
00585   check_nomsg(*ext = cpl_frameset_new());
00586   check_nomsg(frm_tmp = irplib_frameset_get_first_const(set));
00587   while (frm_tmp != NULL)
00588     {
00589       g=cpl_frame_get_group(frm_tmp);
00590       if(g == type) {
00591     frm_dup=cpl_frame_duplicate(frm_tmp);
00592         cpl_frameset_insert(*ext,frm_dup);
00593         uves_msg_debug("group %d insert file %s ",type,cpl_frame_get_filename(frm_dup));
00594       }
00595       frm_tmp = irplib_frameset_get_next_const(set);
00596     }
00597 
00598   cleanup:
00599     return cpl_error_get_code();
00600 }
00601 
00602 /*----------------------------------------------------------------------------*/
00610 /*----------------------------------------------------------------------------*/
00611 cpl_error_code
00612 uves_sflats_get_encoder_steps(const cpl_frameset * set, cpl_table** enc, int* nset)
00613 {
00614   /* Input */
00615     const cpl_frame* frm=NULL;
00616   int x1enc=0;
00617   int x2enc=0;
00618   int ref_x1enc=0;
00619   int ref_x2enc=0;
00620   int i=0;
00621   int ndata=0;
00622   const int threshold=5;
00623   int status=0;
00624   uves_propertylist* plist=NULL;
00625   cpl_table* encoder_tbl=NULL;
00626   ndata = cpl_frameset_get_size(set);
00627   encoder_tbl=cpl_table_new(ndata);
00628   cpl_table_new_column(encoder_tbl,"x1enc",CPL_TYPE_INT);
00629   cpl_table_new_column(encoder_tbl,"x2enc",CPL_TYPE_INT);
00630   cpl_table_new_column(encoder_tbl,"flag",CPL_TYPE_INT);
00631  
00632   for(i=0;i<cpl_frameset_get_size(set);i++)
00633     {
00634     check_nomsg(frm=irplib_frameset_get_frame_const(set,i));
00635     check_nomsg(plist=uves_propertylist_load(cpl_frame_get_filename(frm),0));
00636     check_nomsg(x1enc=uves_pfits_get_slit3_x1encoder(plist));
00637     check_nomsg(x2enc=uves_pfits_get_slit3_x2encoder(plist));
00638     check_nomsg(cpl_table_set_int(encoder_tbl,"x1enc",i,x1enc));
00639     check_nomsg(cpl_table_set_int(encoder_tbl,"x2enc",i,x2enc));
00640     uves_free_propertylist(&plist);
00641     }
00642  
00643   check_nomsg(uves_sort_table_2(encoder_tbl,"x1enc","x2enc",false,true));
00644 
00645   check_nomsg(ref_x1enc=cpl_table_get_int(encoder_tbl,"x1enc",0,&status));
00646   check_nomsg(ref_x2enc=cpl_table_get_int(encoder_tbl,"x2enc",0,&status));
00647   *nset=1;
00648   *enc=cpl_table_new(1);
00649   cpl_table_new_column(*enc,"x1enc",CPL_TYPE_INT);
00650   cpl_table_new_column(*enc,"x2enc",CPL_TYPE_INT);
00651   check_nomsg(cpl_table_set_int(*enc,"x1enc",0,ref_x1enc));
00652   check_nomsg(cpl_table_set_int(*enc,"x2enc",0,ref_x2enc));
00653 
00654   for(i=1;i<cpl_table_get_nrow(encoder_tbl);i++) {
00655      check_nomsg(x1enc=cpl_table_get_int(encoder_tbl,"x1enc",i,&status));
00656      check_nomsg(x2enc=cpl_table_get_int(encoder_tbl,"x2enc",i,&status));
00657      if( (fabs(ref_x1enc -x1enc) > threshold) || 
00658          (fabs(ref_x2enc -x2enc) > threshold) ) {
00659   
00660        ref_x1enc = x1enc;
00661        ref_x2enc = x2enc;
00662        cpl_table_set_size(*enc,(*nset+1));
00663        check_nomsg(cpl_table_set_int(*enc,"x1enc",*nset,ref_x1enc));
00664        check_nomsg(cpl_table_set_int(*enc,"x2enc",*nset,ref_x2enc));
00665        *nset=*nset+1;
00666 
00667      }
00668   }
00669   uves_msg("Number of sets = %d",*nset);
00670 
00671   cleanup:
00672    uves_free_table(&encoder_tbl);
00673     uves_free_propertylist(&plist);
00674     return cpl_error_get_code();
00675 }
00676 
00677 
00678 /*----------------------------------------------------------------------------*/
00684 /*----------------------------------------------------------------------------*/
00685 cpl_error_code
00686 uves_dfs_set_groups(cpl_frameset * set)
00687 {
00688     cpl_frame   *   cur_frame ;
00689     int             nframes ;
00690     
00691     /* Check entries */
00692     assure(set != NULL, CPL_ERROR_NULL_INPUT, "Null input"); 
00693     
00694     /* Initialize */
00695     check( nframes = cpl_frameset_get_size(set), "Could not read frameset size");
00696     
00697     /* Loop on frames */
00698     for (cur_frame = irplib_frameset_get_first(set);
00699      cur_frame != NULL;
00700      cur_frame = irplib_frameset_get_next(set))
00701     {
00702         bool is_raw   = false;
00703         bool is_calib = false;
00704         bool is_recognized = false;
00705         bool blue;
00706         enum uves_chip chip;
00707         const char  *   tag = cpl_frame_get_tag(cur_frame);
00708         
00709         assure( tag != NULL && strcmp(tag, "") != 0, CPL_ERROR_ILLEGAL_INPUT,
00710             "Frame has no tag!");
00711         
00712         blue = false;
00713         do {
00714         bool flames = false;
00715         do {
00716             /* RAW frames */
00717             is_raw   = is_raw   || 
00718             (strcmp(tag, UVES_ORDER_FLAT  (flames,blue)) == 0 ||
00719              strcmp(tag, UVES_BIAS        (blue)) == 0 ||
00720              strcmp(tag, UVES_DARK        (blue)) == 0 ||
00721              strcmp(tag, UVES_PDARK       (blue)) == 0 ||
00722              strcmp(tag, UVES_FLAT        (blue)) == 0 ||
00723              strcmp(tag, UVES_IFLAT       (blue)) == 0 ||
00724              strcmp(tag, UVES_DFLAT       (blue)) == 0 ||
00725              strcmp(tag, UVES_SFLAT       (blue)) == 0 ||
00726              strcmp(tag, UVES_TFLAT       (blue)) == 0 ||
00727              strcmp(tag, UVES_SCREEN_FLAT (blue)) == 0 ||
00728              strcmp(tag, UVES_CD_ALIGN    (blue)) == 0 ||
00729              strcmp(tag, UVES_FORMATCHECK (flames,blue)) == 0 ||
00730              strcmp(tag, UVES_STD_STAR    (blue)) == 0 ||
00731              strcmp(tag, UVES_SCIENCE     (blue)) == 0 ||
00732              strcmp(tag, UVES_SCI_EXTND   (blue)) == 0 ||
00733              strcmp(tag, UVES_SCI_POINT   (blue)) == 0 ||
00734              strcmp(tag, UVES_SCI_SLICER  (blue)) == 0 ||
00735              strcmp(tag, UVES_ARC_LAMP    (flames,blue)) == 0 ||
00736              strcmp(tag, UVES_ECH_ARC_LAMP(blue)) == 0 ||
00737              strcmp(tag, FLAMES_FIB_FF_ODD) == 0 ||
00738              strcmp(tag, FLAMES_FIB_FF_EVEN) == 0 ||
00739              strcmp(tag, FLAMES_FIB_FF_ALL) == 0);
00740             
00741             /* CALIB frames */
00742             
00743             /* Loop through all (1 or 2) blue or red chips */
00744             for (chip = uves_chip_get_first(blue);
00745              chip != UVES_CHIP_INVALID; 
00746              chip = uves_chip_get_next(chip))
00747             {
00748                 int window;
00749                 
00750                 is_calib = is_calib || 
00751                 (strcmp(tag, UVES_DRS_SETUP(flames, chip)) == 0 ||
00752                  strcmp(tag, UVES_ORDER_TABLE(flames, chip)) == 0 ||
00753                  strcmp(tag, UVES_GUESS_ORDER_TABLE(flames,chip)) == 0 ||
00754                  strcmp(tag, UVES_MASTER_BIAS   (chip)) == 0 ||
00755                  strcmp(tag, UVES_MASTER_DARK   (chip)) == 0 ||
00756                  strcmp(tag, UVES_MASTER_PDARK  (chip)) == 0 ||
00757                  strcmp(tag, UVES_MASTER_FLAT   (chip)) == 0 ||
00758                  strcmp(tag, UVES_MASTER_DFLAT  (chip)) == 0 ||
00759                  strcmp(tag, UVES_MASTER_SFLAT  (chip)) == 0 ||
00760                  strcmp(tag, UVES_MASTER_IFLAT  (chip)) == 0 ||
00761                  strcmp(tag, UVES_MASTER_TFLAT  (chip)) == 0 ||
00762                  strcmp(tag, UVES_REF_TFLAT     (chip)) == 0 ||
00763                  strcmp(tag, UVES_MASTER_SCREEN_FLAT(chip)) == 0 ||
00764                  strcmp(tag, UVES_MASTER_ARC_FORM(chip)) == 0 ||
00765                  strcmp(tag, UVES_LINE_TABLE(flames,chip)) == 0 ||
00766                  strcmp(tag, UVES_GUESS_LINE_TABLE(flames,chip)) == 0 ||
00767                  strcmp(tag, UVES_INSTR_RESPONSE(chip)) == 0 ||
00768                  strcmp(tag, UVES_MASTER_RESPONSE(chip)) == 0 ||
00769                  strcmp(tag, UVES_LINE_REFER_TABLE    ) == 0 ||
00770                  strcmp(tag, UVES_LINE_INTMON_TABLE   ) == 0 ||
00771                  strcmp(tag, UVES_FLUX_STD_TABLE      ) == 0 ||
00772                  strcmp(tag, UVES_EXTCOEFF_TABLE      ) == 0 ||
00773                  strcmp(tag, FLAMES_SCI_RED           ) == 0 ||
00774                  strcmp(tag, FLAMES_SCI_COM_RED       ) == 0 ||
00775                  strcmp(tag, FLAMES_LINE_TABLE(chip)) == 0 ||
00776                  strcmp(tag, FLAMES_SLIT_FF_DT1(chip)) == 0 ||
00777                  strcmp(tag, FLAMES_SLIT_FF_DT2(chip)) == 0 ||
00778                  strcmp(tag, FLAMES_SLIT_FF_DT3(chip)) == 0 ||
00779                  strcmp(tag, FLAMES_SLIT_FF_BP1(chip)) == 0 ||
00780                  strcmp(tag, FLAMES_SLIT_FF_BP2(chip)) == 0 ||
00781                  strcmp(tag, FLAMES_SLIT_FF_BP3(chip)) == 0 ||
00782                  strcmp(tag, FLAMES_SLIT_FF_BN1(chip)) == 0 ||
00783                  strcmp(tag, FLAMES_SLIT_FF_BN2(chip)) == 0 ||
00784                  strcmp(tag, FLAMES_SLIT_FF_BN3(chip)) == 0 ||
00785                  strcmp(tag, FLAMES_SLIT_FF_SG1(chip)) == 0 ||
00786                  strcmp(tag, FLAMES_SLIT_FF_SG2(chip)) == 0 ||
00787                  strcmp(tag, FLAMES_SLIT_FF_SG3(chip)) == 0 ||
00788                  strcmp(tag, FLAMES_SLIT_FF_COM(chip)) == 0 ||
00789                  strcmp(tag, FLAMES_SLIT_FF_NOR(chip)) == 0 ||
00790                  strcmp(tag, FLAMES_SLIT_FF_NSG(chip)) == 0 ||
00791                  strcmp(tag, FLAMES_FIB_FF_DT1(chip)) == 0 ||
00792                  strcmp(tag, FLAMES_FIB_FF_DT2(chip)) == 0 ||
00793                  strcmp(tag, FLAMES_FIB_FF_DT3(chip)) == 0 ||
00794                  strcmp(tag, FLAMES_FIB_FF_BP1(chip)) == 0 ||
00795                  strcmp(tag, FLAMES_FIB_FF_BP2(chip)) == 0 ||
00796                  strcmp(tag, FLAMES_FIB_FF_BP3(chip)) == 0 ||
00797                  strcmp(tag, FLAMES_FIB_FF_BN1(chip)) == 0 ||
00798                  strcmp(tag, FLAMES_FIB_FF_BN2(chip)) == 0 ||
00799                  strcmp(tag, FLAMES_FIB_FF_BN3(chip)) == 0 ||
00800                  strcmp(tag, FLAMES_FIB_FF_SG1(chip)) == 0 ||
00801                  strcmp(tag, FLAMES_FIB_FF_SG2(chip)) == 0 ||
00802                  strcmp(tag, FLAMES_FIB_FF_SG3(chip)) == 0 ||
00803                  strcmp(tag, FLAMES_FIB_FF_COM(chip)) == 0 ||
00804                  strcmp(tag, FLAMES_FIB_FF_NOR(chip)) == 0 ||
00805                  strcmp(tag, FLAMES_FIB_FF_NSG(chip)) == 0 ||
00806                  strcmp(tag, FLAMES_ORDEF(flames,chip)) == 0);
00807                 
00808                 for (window = 1; window <= 3; window++)
00809                 {
00810                     is_calib = is_calib || 
00811                     strcmp(tag, UVES_LINE_TABLE_MIDAS(chip, window)) == 0;
00812                 }
00813                 
00814                 if (!flames && strcmp(tag, UVES_BACKGR_TABLE(chip)) == 0)
00815                 {
00816                     uves_msg_warning("Background table %s has been deprecated. "
00817                              "Inter-order positions will be inferred "
00818                              "from the order table %s. "
00819                              "Use recipe parameters to define "
00820                              "measuring method ",
00821                              UVES_BACKGR_TABLE(chip), 
00822                              UVES_ORDER_TABLE(flames, chip));
00823                     
00824                     is_recognized = true;
00825                 }
00826                 
00827                 if (strcmp(tag, UVES_DRS_SETUP(flames, chip)) == 0)
00828                 {
00829                     uves_msg_warning("DRS setup table %s has been deprecated. "
00830                              "Use recipe parameters "
00831                              "to define data reduction parameters ",
00832                              UVES_DRS_SETUP(flames, chip));
00833                     
00834                     is_recognized = true;
00835                 }
00836             }
00837             flames = !flames;
00838         } while (flames);
00839         blue = !blue;
00840         }
00841         while (blue);
00842         
00843         is_recognized = is_recognized || is_raw || is_calib;
00844 
00845         if (is_raw)
00846         {
00847             cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW) ;
00848         }
00849         else if (is_calib)
00850         {
00851             cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB) ;
00852         }
00853         else if (!is_recognized)
00854         {
00855             uves_msg_warning("Unrecognized tag %s", tag);
00856         }
00857     }
00858     
00859   cleanup:
00860     return cpl_error_get_code();
00861 }
00862 
00863 
00864 /*----------------------------------------------------------------------------*/
00873 /*----------------------------------------------------------------------------*/
00874 static void
00875 remove_pre_over_scan(uves_propertylist *pl)
00876 {
00877     bool blue, new_format;
00878     enum uves_chip chip;
00879     
00880     new_format = false;
00881     do {
00882     blue = false;
00883     do {
00884         for (chip = uves_chip_get_first(blue); 
00885          chip != UVES_CHIP_INVALID;
00886          chip = uves_chip_get_next(chip))
00887         {
00888             int n_erase_px = 0;   /* Number of erased properties */
00889             int n_erase_py = 0;
00890             int n_erase_ox = 0;
00891             int n_erase_oy = 0;
00892             
00893             do {
00894             /* This function erases only one property at a time,
00895              *  therefore call it until it returns 0
00896              */
00897             check( n_erase_px = 
00898                    uves_propertylist_erase(pl, UVES_PRESCANX(new_format, chip)),
00899                    "Error erasing keyword '%s'", UVES_PRESCANX(new_format, chip));
00900             
00901             check( n_erase_py = 
00902                    uves_propertylist_erase(pl, UVES_PRESCANY(new_format, chip)),
00903                    "Error erasing keyword '%s'", UVES_PRESCANY(new_format, chip));
00904             
00905             check( n_erase_ox =
00906                    uves_propertylist_erase(pl, UVES_OVRSCANX(new_format, chip)),
00907                    "Error erasing keyword '%s'", UVES_OVRSCANX(new_format, chip));
00908             
00909             check( n_erase_oy =
00910                    uves_propertylist_erase(pl, UVES_OVRSCANY(new_format, chip)),
00911                    "Error erasing keyword '%s'", UVES_OVRSCANY(new_format, chip));
00912             }
00913             while (n_erase_px > 0 ||
00914                n_erase_py > 0 ||
00915                n_erase_ox > 0 ||
00916                n_erase_oy > 0);
00917         }
00918         blue = !blue;
00919     }
00920     while (blue);
00921     
00922     new_format = !new_format;
00923     }
00924     while (new_format);
00925 
00926   cleanup:
00927     return;
00928 }
00929 
00930 
00931 /*----------------------------------------------------------------------------*/
00941 /*----------------------------------------------------------------------------*/
00942 
00943 void
00944 uves_copy_if_possible(uves_propertylist *to, const uves_propertylist *from,
00945          const char *name)
00946 {
00947     if (!uves_propertylist_contains(to, name) &&
00948     uves_propertylist_contains(from, name))
00949     {
00950         uves_msg_debug("Propagating keyword %s", name);
00951 
00952         check_nomsg( uves_propertylist_copy_property(to, from, name) );
00953     }
00954     else
00955     {
00956         uves_msg_debug("Keyword %s not propagated", name);
00957     }
00958     
00959   cleanup:
00960     return;
00961 }
00962 
00963 /*----------------------------------------------------------------------------*/
01007 /*----------------------------------------------------------------------------*/
01008 cpl_error_code
01009 uves_frameset_insert(cpl_frameset *frames, 
01010                      void *object, 
01011              cpl_frame_group group, 
01012                      cpl_frame_type type, 
01013                      cpl_frame_level level,
01014              const char *filename, 
01015                      const char *tag, 
01016              const uves_propertylist *raw_header,
01017                      const uves_propertylist *primary_header, 
01018              const uves_propertylist *table_header, 
01019                      const cpl_parameterlist *parameters, 
01020              const char *recipe, 
01021                      const char *pipeline,
01022                      cpl_table **qc,
01023              const char *start_time,
01024              bool dump_paf,
01025              unsigned stats_mask)
01026 {
01027     cpl_frame *f = NULL;
01028     uves_propertylist *pl = NULL;
01029     const char *origin = "";
01030 
01031     passure( !(type == CPL_FRAME_TYPE_IMAGE && table_header != NULL), " ");
01032     passure( raw_header != NULL, " ");
01033     passure( primary_header != NULL, " ");
01034 
01035     assure( type == CPL_FRAME_TYPE_IMAGE || stats_mask == 0,
01036         CPL_ERROR_INCOMPATIBLE_INPUT,
01037         "Cannot compute image statistics on table product" );
01038 
01039     /* Insert the object (image or table) into frameset */
01040     check(( f = cpl_frame_new(),
01041         cpl_frame_set_filename(f, filename),    /* local filename */
01042         cpl_frame_set_tag     (f, tag),         /* e.g. ORDER_TABLE_BLUE */
01043         cpl_frame_set_type    (f, type),        /* e.g. table */
01044         cpl_frame_set_group   (f, group),       /* e.g. raw/product */
01045         cpl_frame_set_level   (f, level),       /* e.g. temporary/final */
01046         cpl_frameset_insert(frames, f)), "Could not insert frame into frameset");
01047     
01048     /* Pipeline id format is <PACKAGE "/" PACKAGE_VERSION>; */
01049     if (strchr(pipeline, '/') == NULL)
01050     {
01051         uves_msg_warning("Pipeline ID '%s' is not of format: "
01052                  "Pipeline-name/version", pipeline);
01053     }
01054 
01055     /* Propagate/create DFS keywords */
01056     pl = uves_propertylist_new();
01057     UVES_TIME_START("cpl_dfs_setup_product_header");
01058     check( uves_dfs_setup_product_header(pl,
01059                     f,
01060                     frames,
01061                     parameters,
01062                     recipe,
01063                     pipeline,
01064                     DICTIONARY),
01065        "Error setting up product header");
01066     UVES_TIME_END;
01067     
01068     /* Change origin to 'ESO' if it says 'ESO-MIDAS'
01069      * NOST-Definition: "The value field shall contain a character string
01070      *                   identifying the organization or institution responsible 
01071      *                   for creating the FITS file."
01072      */
01073     
01074     check( uves_get_property_value(pl, "ORIGIN", CPL_TYPE_STRING, &origin),
01075        "Error reading ORIGIN from product header");
01076 
01077     if (strcmp(origin, "ESO-MIDAS") == 0) 
01078     {
01079         uves_propertylist_set_string(pl, "ORIGIN", "ESO");
01080     }
01081     
01082     /* Set OBJECT = DO category */
01083     check( uves_pfits_set_object(pl, tag), "Error writing object keyword");
01084     
01085     /* REDLEVEL has been deprecated, so do not: uves_pfits_set_redlevel(pl, red_level); */
01086     
01087     /* Add statistics keywords */
01088     if (type == CPL_FRAME_TYPE_IMAGE && stats_mask != 0)
01089     {
01090         check( write_statistics((cpl_image *) object, pl, stats_mask),
01091            "Error adding image statistics keywords");
01092     }
01093     
01094     /* Copy provided keywords in 'primary_header' to 'pl' */
01095     if (!uves_propertylist_is_empty(primary_header))
01096     {
01097         if (0)
01098                 /* This takes (n*m) time */
01099                 {
01100                     /* The regexp "" matches any string (because any string has
01101                        the empty string as a sub-string),
01102                        except on Mac, where it is an illegal regexp (for whatever reason).
01103                        Therefore, use ".*" to match any string */
01104                     
01105                     check( uves_propertylist_copy_property_regexp(pl, primary_header, ".*", 0),
01106                            "Could not copy keywords");
01107                 }
01108             else
01109                 check( uves_propertylist_append(pl, primary_header),
01110                        "Could not copy keywords");
01111         }
01112     
01113     /* Propagate ESO.DET keywords from 'raw_header',
01114      * This is necessary because cpl_dfs_setup_product_header() copies
01115      * only from the primary extension of the first input frames
01116      */
01117     check( uves_propertylist_copy_property_regexp(pl, raw_header, "^ESO DET ", 0),
01118        "Could not propagate 'ESO DET*' keywords");
01119 
01120     /* But remove prescan, overscan keywords. 
01121        (Since these areas are not present in any products.) */
01122     check( remove_pre_over_scan(pl), 
01123        "Error removing pre-, overscan keywords from product header");
01124 
01125     /* Propagate certain keywords from 'raw_header' 
01126        (only if available and if not already present in product header) */
01127     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_AIRMASS) );
01128     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_IMAGETYP) );
01129     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_UT) );
01130     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_ST) );
01131     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_EXPTIME) );
01132     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_EXTNAME) );
01133     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_DATE) );
01134     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_DATAMEAN) );
01135     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_DATAMED) );
01136     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_DATARMS) );
01137     check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_OS_EXPOI) );
01138 
01139     /* MIDAS internal(?): check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_TMSTART) ); */
01140 
01141     if (0)
01142         /* uves_propertylist_copy_property_regexp() is slow */
01143         {
01144             check( uves_propertylist_copy_property_regexp(pl, raw_header, "^GRAT[0-9]*$", 0),
01145                    "Could not propagate 'GRATi' keywords");
01146             check( uves_propertylist_copy_property_regexp(pl, raw_header, "^FILTER[0-9]*$", 0),
01147                    "Could not propagate 'FILTERi' keywords");
01148             check( uves_propertylist_copy_property_regexp(pl, raw_header, "^WLEN[0-9]*$", 0),
01149                    "Could not propagate 'WLENi' keywords");
01150         }
01151     else
01152         {
01153             check( uves_propertylist_copy_property_regexp(
01154                        pl, raw_header, "^((GRAT|FILTER|WLEN)[0-9]*)$", 0),
01155                    "Could not propagate GRATi, FILTERi and WLENi keywords");
01156         }
01157 
01158     /* If RA,DEC do not exist, invent them and set to zero, like MIDAS */
01159     if ( !uves_propertylist_contains(pl, UVES_RA) )
01160     {
01161         uves_pfits_set_ra(pl, 0);
01162     }
01163     if ( !uves_propertylist_contains(pl, UVES_DEC) )
01164     {
01165         uves_pfits_set_dec(pl, 0);
01166     }
01167 
01168     /* 
01169      * This will be deprecated, so do not:
01170      *
01171      * As the last thing before saving, write status = SERIOUS if there were any warnings
01172      if (uves_msg_get_warnings() > 0)
01173      {
01174          check( uves_pfits_set_status(pl, "SERIOUS"), "Error writing status");
01175      }
01176     */
01177 
01178     check( uves_pfits_set_starttime(pl, start_time),
01179        "Could not write recipe start time");
01180 
01181     check( uves_pfits_set_stoptime(pl, qfits_get_datetime_iso8601()),
01182        "Could not write recipe stop time");
01183 
01184     /* Create paf file from each QC table, and transfer
01185        all QC parameters to product header
01186     */
01187     if (qc != NULL)
01188     {
01189         int i;
01190         for (i = 0; qc[i] != NULL; i++)
01191         {
01192             uves_pfits_put_qc(pl, qc[i]);
01193                         
01194             if (dump_paf)
01195             {
01196                 /* Exception! This is a hack */
01197                 if (strcmp(recipe, make_str(UVES_TFLAT_ID)) == 0 && i == 1)
01198                 {
01199                     /* Don't dump the science QC again */
01200                 }
01201                 else
01202                 {
01203                     uves_save_paf(filename, i, recipe, qc[i], 
01204                           pl, raw_header, tag);
01205                 }
01206             }
01207         } 
01208     }
01209 
01210     UVES_TIME_START("save product");
01211 
01212     /* Now save with the correct header */
01213     if (type == CPL_FRAME_TYPE_IMAGE)
01214     {
01215         check( uves_save_image((cpl_image *) object, filename, pl), 
01216            "Error saving image to file %s", filename);
01217     }
01218     else if (type == CPL_FRAME_TYPE_TABLE)                           /* Table */
01219     {
01220         check( uves_table_save((cpl_table *) object,
01221                   pl,                                /* Primary header */
01222                   table_header,                      /* Table header */
01223                   filename,
01224                   CPL_IO_DEFAULT),                   /* Create new file */
01225            "Error saving table to file '%s'", filename);
01226     }
01227     else
01228     {
01229         assure(false, CPL_ERROR_UNSUPPORTED_MODE, "Unsupported frame type");
01230     }
01231 
01232     UVES_TIME_END;
01233     
01234   cleanup:
01235     uves_free_propertylist(&pl);
01236     
01237     return cpl_error_get_code();
01238 }
01239 
01240 
01241 /*----------------------------------------------------------------------------*/
01250 /*----------------------------------------------------------------------------*/
01251 static cpl_error_code
01252 write_statistics(const cpl_image *image, uves_propertylist *header,
01253          unsigned stats_mask)
01254 {
01255     cpl_stats *stats = NULL;
01256 
01257     /* Only these bits are supported, all others must be zero */
01258     assure( (stats_mask & (CPL_STATS_MEAN | CPL_STATS_STDEV | CPL_STATS_MEDIAN |
01259               CPL_STATS_MIN  | CPL_STATS_MAX)) == stats_mask,
01260         CPL_ERROR_UNSUPPORTED_MODE, "Cannot compute mask %d",
01261         stats_mask );
01262 
01263     UVES_TIME_START("calculate stats");
01264 
01265     check( stats = cpl_stats_new_from_image(
01266            image, stats_mask),
01267        "Error reading image statistics");
01268     
01269     UVES_TIME_END;
01270     
01271     if (stats_mask & CPL_STATS_MEDIAN)
01272     {
01273         check( uves_pfits_set_data_median (header, cpl_stats_get_median(stats) ), 
01274            "Could not write median flux");
01275     }
01276     if (stats_mask & CPL_STATS_MEAN)
01277     {
01278         check( uves_pfits_set_data_average(header, cpl_stats_get_mean  (stats) ), 
01279            "Could not write average flux");
01280     }
01281     if (stats_mask & CPL_STATS_STDEV)
01282     {
01283         check( uves_pfits_set_data_stddev (header, cpl_stats_get_stdev (stats) ), 
01284            "Could not write flux stdev");
01285     }
01286     if (stats_mask & CPL_STATS_MIN)
01287     {
01288         check( uves_pfits_set_data_min    (header, cpl_stats_get_min   (stats) ), 
01289            "Could not write min flux");
01290     }
01291     if (stats_mask & CPL_STATS_MIN)
01292     {
01293         check( uves_pfits_set_data_max    (header, cpl_stats_get_max   (stats) ), 
01294            "Could not write max flux");
01295     }
01296 
01297   cleanup:
01298     uves_free_stats(&stats);
01299     return cpl_error_get_code();
01300 }
01301 
01302 
01303 /*----------------------------------------------------------------------------*/
01338 /*----------------------------------------------------------------------------*/
01339 void *
01340 uves_read_midas_array(const uves_propertylist *plist, const char *name, 
01341                       int *length, cpl_type *type, int *ncards)
01342 {
01343     void *result = NULL;
01344     unsigned result_size;
01345     int N = strlen(name);
01346     bool found = false;
01347     const char *value;
01348     int size;
01349     int i;
01350     const long int plist_size = uves_propertylist_get_size(plist);
01351    
01352     assure_nomsg( length != NULL, CPL_ERROR_NULL_INPUT );
01353     assure_nomsg(   type != NULL, CPL_ERROR_NULL_INPUT );
01354     for (i = 0; !found && i < plist_size; i++)
01355     {
01356       const cpl_property *p = uves_propertylist_get_const(plist, i);
01357       value = cpl_property_get_name(p);
01358       
01359       if (strcmp(value, "HISTORY") == 0)
01360         {
01361           
01362           check( value = cpl_property_get_string(p),
01363              "Error reading property value");
01364           
01365           /* match the string  "'<name>','t"  */
01366           
01367           if ((int)strlen(value) >= 1+N+4 &&
01368           value[0]     == '\'' &&
01369           value[N+1]   == '\'' && 
01370           value[N+2]   == ','  && 
01371           value[N+3]   == '\'' && 
01372           strncmp(value+1, name, N) == 0
01373           )
01374                   { 
01375                       switch(value[N+4]) {
01376                       case 'R':
01377                           /* Distinguish between 
01378                              "'<name>','R*4'" and
01379                              "'<name>','R*8'"
01380                           */
01381                           *type = CPL_TYPE_DOUBLE;
01382 
01383                           if ((int)strlen(value) >= 1+N+4+2 && value[N+4+1] == '*')
01384                               {
01385                                   switch(value[N+4+2]) {
01386                                   case '4': *type = CPL_TYPE_FLOAT; break;
01387                                   case '8': *type = CPL_TYPE_DOUBLE; break; 
01388                                   default:
01389                                       assure( false, CPL_ERROR_ILLEGAL_INPUT,
01390                                               "Unrecognized MIDAS type: 'R*%c'",
01391                                               value[N+4+2]);
01392                                       break;
01393                                   }
01394                               }
01395                           break;
01396                       case 'I': *type = CPL_TYPE_INT   ; size = sizeof(int);    break;
01397                       case 'C': *type = CPL_TYPE_STRING; size = sizeof(char);   break;
01398                       default:
01399                           assure( false, CPL_ERROR_UNSUPPORTED_MODE,
01400                                   "Unrecognized type '%c'", value[N+4]);
01401                           break;
01402                       }
01403                       found = true;
01404                   }
01405         }
01406     }
01407     
01408     assure( found, CPL_ERROR_ILLEGAL_INPUT, "Could not find '%s' in property list", name);
01409     
01410     /* 'i' is now the row immediately after first occurence of 'HISTORY   '<name>...  */
01411     result_size = sizeof(double) * 100;  /* realloc when/if out of memory */
01412     result = cpl_malloc(result_size);
01413 
01414     *length = 0;
01415     if (ncards != NULL) *ncards = 2; /* First HISTORY entry + termination HISTORY entry */
01416     do {
01417     const cpl_property *p;
01418 
01419         if (ncards != NULL) *ncards += 1;
01420 
01421     assure(i < plist_size, 
01422            CPL_ERROR_ILLEGAL_INPUT, "Missing header data");
01423     p = uves_propertylist_get_const(plist, i);
01424     assure(       cpl_property_get_type(p)             == CPL_TYPE_STRING &&
01425               strcmp(cpl_property_get_name(p), "HISTORY") == 0, 
01426               CPL_ERROR_ILLEGAL_INPUT, "Error parsing array");
01427     value = cpl_property_get_string(uves_propertylist_get_const(plist, i));
01428     
01429     uves_msg_debug("Parsing '%s'", value);
01430 
01431         if (*type == CPL_TYPE_STRING)
01432             {
01433                 assure( strlen(value) < 100, CPL_ERROR_UNSUPPORTED_MODE, 
01434                         "String too long. Max size is 100");
01435 
01436                 /* Remove any blanks from the string
01437                   (e.g. convert "0 1 2" to "012")
01438                 */
01439                 {
01440                     int len = strlen(value);
01441                     int j = 0;
01442                     int k;
01443                     for (k = 0; k <= len; k++)  /* including final '\0' */
01444                         {
01445                             if (value[k] != ' ')
01446                                 {
01447                                     ((char*)result)[j] = value[k];
01448                                     j++;
01449                                 }
01450                         }
01451                     *length = j-1;
01452                 }
01453 
01454                 uves_msg_debug("Converted '%s' to '%s'",
01455                                value, (char*)result);
01456                 
01457                 /* done parsing */
01458                 value = "";
01459             }
01460         
01461         else { /* numerical types */
01462             if (strcmp(value, "") != 0) {
01463         double numberd = -1; /* suppres warning */
01464                 int numberi = -1;
01465                 float numberf = -1;
01466                 const int base = 10;
01467         char *next = (char *) value;
01468 
01469         do {
01470             /* ignore OUTPUTI(1)- N,no.of data, */
01471                     switch(*type) {
01472                     case CPL_TYPE_DOUBLE:
01473                         numberd = strtod(value, &next);
01474                         uves_msg_debug("Got %g, remaining: '%s'", numberd, next);
01475                         break;
01476                     case CPL_TYPE_FLOAT:
01477                         numberf = strtod(value, &next); // C99: strtof(value, &next);
01478                         uves_msg_debug("Got %g, remaining: '%s'", numberf, next);
01479                         break;
01480                     case CPL_TYPE_INT:
01481                         numberi = strtol(value, &next, base);
01482                         uves_msg_debug("Got %d, remaining: '%s'", numberi, next);
01483                         break;
01484                     default:
01485                         passure(false, " ");
01486                     }
01487                     
01488             if (next != value)
01489             {
01490                 /* A prefix of the string could be converted */
01491                 (*length)++;
01492                             if (*length * sizeof(double) > result_size)
01493                                 {
01494                                     result_size *= 2;
01495                                     result = cpl_realloc(result, result_size);
01496                                 }
01497 
01498                             switch(*type) {
01499                             case CPL_TYPE_DOUBLE:
01500                                 ((double *)result)[*length-1] = numberd;
01501                                 break;
01502                             case CPL_TYPE_FLOAT:
01503                                 ((float *)result)[*length-1] = numberf;
01504                                 break;
01505                             case CPL_TYPE_INT:
01506                                 ((int    *)result)[*length-1] = numberi;
01507                                 break;
01508                             default:
01509                                 passure(false, " ");
01510                             }
01511 
01512                 value = next;
01513                             
01514                             switch(*type) {
01515                             case CPL_TYPE_DOUBLE:
01516                                 numberd = strtod(value, &next);
01517                                 uves_msg_debug("Got %g, remaining: '%s'", numberd, next);
01518                                 break;
01519                             case CPL_TYPE_FLOAT:
01520                                 numberf = strtod(value, &next); // C99: strtof(value, &next);
01521                                 uves_msg_debug("Got %g, remaining: '%s'", numberf, next);
01522                                 break;
01523                             case CPL_TYPE_INT:
01524                                 numberi = strtol(value, &next, base);
01525                                 uves_msg_debug("Got %d, remaining: '%s'", numberi, next);
01526                                 break;
01527                             default:
01528                                 passure(false, " ");
01529                             }
01530             }
01531         } while (next != value);
01532         }
01533         }/* if numerical type */
01534         
01535         i++;
01536 
01537     assure( strcmp(value, "") == 0, CPL_ERROR_ILLEGAL_INPUT,
01538                 "Cannot parse %s descriptor %s, remaining string: '%s'", 
01539                 uves_tostring_cpl_type(*type), name, value);
01540     
01541     /* Find out if we can continue parsing the next HISTORY keyword */
01542     if (i < plist_size)
01543         {
01544         p = uves_propertylist_get_const(plist, i);
01545         if (cpl_property_get_type(p) == CPL_TYPE_STRING &&
01546             strcmp(cpl_property_get_name(p), "HISTORY") == 0)
01547             {
01548             value = cpl_property_get_string(
01549                 uves_propertylist_get_const(plist, i));
01550 
01551                         if (*type == CPL_TYPE_STRING)
01552                             {
01553                                 assure( strcmp(value, "") == 0, CPL_ERROR_UNSUPPORTED_MODE,
01554                                         "Cannot parse string array, next HISTORY keyword contains '%s'",
01555                                         value);
01556                             }
01557             }
01558         }
01559         
01560     } while (strcmp(value, "") != 0);
01561    
01562   cleanup:
01563     if (cpl_error_get_code() != CPL_ERROR_NONE)
01564         {
01565             cpl_free(result); result = NULL;
01566         }
01567     return result;
01568 }
01569 
01570 
01571 /*----------------------------------------------------------------------------*/
01589 /*----------------------------------------------------------------------------*/
01590 cpl_error_code
01591 uves_save_table_local(const char *description, const char *filename_prefix,
01592               const cpl_table *table, 
01593               enum uves_chip chip, int trace, int window,
01594               const uves_propertylist *pheader, const uves_propertylist *eheader)
01595 {
01596     char *filename = NULL;
01597 
01598     check( filename = uves_local_filename(filename_prefix, chip, trace, window),
01599        "Error getting filename");
01600 
01601     check( uves_table_save(table, pheader, eheader, filename, CPL_IO_DEFAULT), 
01602        "Error saving table to file '%s'", filename);
01603     
01604     if (description != NULL) uves_msg("%s saved to '%s'", description, filename);
01605     
01606   cleanup:
01607     cpl_free(filename);
01608     return cpl_error_get_code();
01609 }
01610 
01611 /*----------------------------------------------------------------------------*/
01631 /*----------------------------------------------------------------------------*/
01632 cpl_error_code
01633 uves_save_image_local(const char *description, const char *filename_prefix, 
01634               const cpl_image *image, 
01635               enum uves_chip chip, int trace, int window,
01636               const uves_propertylist *plist)
01637 {
01638     char *filename = NULL;
01639     
01640     check( filename = uves_local_filename(filename_prefix, chip, trace, window),
01641        "Error getting filename");
01642     
01643     check( uves_save_image(image, filename, plist), "Error saving image to file '%s'", filename);
01644     if (description != NULL) uves_msg("%s saved to '%s'", description, filename);
01645     
01646   cleanup:
01647     cpl_free(filename);
01648     return cpl_error_get_code();
01649 }
01650 
01651 
01652 /*----------------------------------------------------------------------------*/
01662 /*----------------------------------------------------------------------------*/
01663 cpl_image *uves_load_image(const cpl_frame *f,
01664                int plane,
01665                int extension,
01666                uves_propertylist **header)
01667 {
01668     cpl_image *image = NULL;
01669     uves_propertylist *plist = NULL;
01670     const char *filename;
01671     int bitpix;
01672     cpl_type type;
01673     
01674     assure_nomsg( f != NULL, CPL_ERROR_NULL_INPUT );
01675     assure( cpl_frame_get_type(f) == CPL_FRAME_TYPE_IMAGE,
01676         CPL_ERROR_TYPE_MISMATCH, "Wrong type: %s",
01677         uves_tostring_cpl_frame_type(cpl_frame_get_type(f)));
01678 
01679     filename = cpl_frame_get_filename(f);
01680 
01681     check( plist = uves_propertylist_load(filename, extension),
01682        "Could not load header from %s extension %d", 
01683        filename, extension);
01684     
01685     check( bitpix = uves_pfits_get_bitpix(plist),
01686        "Could not read BITPIX from %s extension %d",
01687        filename, extension);
01688     
01689     if      (bitpix == -32) type = CPL_TYPE_FLOAT;
01690     else if (bitpix == -64) type = CPL_TYPE_DOUBLE;
01691     else if (bitpix ==  32) type = CPL_TYPE_INT;
01692     else
01693     {
01694         assure( false, CPL_ERROR_UNSUPPORTED_MODE,
01695             "No CPL type to represent BITPIX = %d", bitpix);
01696     }
01697 
01698     check( image = cpl_image_load(filename,
01699                   type,
01700                   plane,   
01701                   extension),
01702        "Could not load image from extension %d of file '%s' ", 
01703        extension, filename);
01704 
01705     if (header != NULL)
01706     {
01707         *header = uves_propertylist_duplicate(plist);
01708     }
01709 
01710   cleanup:
01711     uves_free_propertylist(&plist);
01712     return image;
01713 }
01714 
01715 
01716 /*----------------------------------------------------------------------------*/
01736 /*----------------------------------------------------------------------------*/
01737 void
01738 uves_save_image(const cpl_image *image, const char *filename, const uves_propertylist *plist)
01739 {
01740     cpl_type_bpp bpp;
01741     cpl_type t;
01742     const cpl_vector *image_1d = NULL;
01743     uves_propertylist *header = NULL;
01744     cpl_image *thresholded = NULL;
01745     
01746     check( t = cpl_image_get_type(image), "Error reading image type");
01747     if      (t == CPL_TYPE_FLOAT ) bpp = CPL_BPP_IEEE_FLOAT;
01748     else if (t == CPL_TYPE_DOUBLE) bpp = CPL_BPP_IEEE_FLOAT;
01749     /* Internal computations in double precision,
01750        save as single precision */
01751 #if CPL_VERSION_CODE >= CPL_VERSION(3, 0, 1)
01752     else if (t == CPL_TYPE_INT   ) bpp = CPL_BPP_16_UNSIGNED;
01753 #else
01754     else if (t == CPL_TYPE_INT   ) bpp = CPL_BPP_16_SIGNED;
01755 #endif
01756     else assure(false, CPL_ERROR_UNSUPPORTED_MODE,
01757         "Unsupported image type '%s'", uves_tostring_cpl_type(t));
01758 
01759 
01760     thresholded = cpl_image_duplicate(image);
01761     assure_mem( thresholded );
01762 
01763     if (t == CPL_TYPE_DOUBLE)
01764     {
01765         passure( bpp == CPL_BPP_IEEE_FLOAT, "%d", bpp);
01766 
01767         /* Avoid infinities that would happen when casting
01768                double -> float
01769            by thresholding the image to +-FLT_MAX (or, better
01770            a little less than FLT_MAX just to be sure).
01771         
01772            (This is not a really nice solution because it solves the
01773            problem (too large/small values) after it is introduced
01774            (rather than avoiding it), but a general solution of the
01775            problem would probably mean guarding every arithmetic
01776            operation with range checks.)
01777         */
01778         
01779         check_nomsg( cpl_image_threshold(thresholded,
01780                          -FLT_MAX, FLT_MAX,
01781                          -FLT_MAX, FLT_MAX) );
01782 
01783         /* Also get rid of NaN, set to zero (what else?) */
01784         {
01785         double *data = irplib_image_get_data_double(thresholded);
01786                 int nx = cpl_image_get_size_x(thresholded);
01787                 int ny = cpl_image_get_size_y(thresholded);
01788         int x, y;
01789         
01790         for (y = 0; y < ny; y++)
01791                 for (x = 0; x < nx; x++)
01792             {
01793             if (irplib_isnan(data[x + y*nx]))
01794                 {
01795                 data[x + y*nx] = 0;
01796                 }
01797             }
01798         }
01799     }
01800 
01801     if (cpl_image_get_size_y(thresholded) == 1 && t == CPL_TYPE_DOUBLE)
01802     /* To support other types (float, int) we would
01803        need to convert to double first */
01804     {
01805         bool invert = false;
01806         if (plist != NULL)
01807         {
01808             header = uves_propertylist_duplicate(plist);
01809             
01810             uves_propertylist_erase_regexp(header, "^CDELT2$", invert);
01811             uves_propertylist_erase_regexp(header, "^CRPIX2$", invert);
01812             uves_propertylist_erase_regexp(header, "^CRVAL2$", invert);
01813             uves_propertylist_erase_regexp(header, "^CTYPE2$", invert);
01814         }
01815         else
01816         {
01817             header = NULL;
01818         }
01819 
01820         image_1d = irplib_vector_wrap_const(cpl_image_get_size_x(thresholded),
01821                         irplib_image_get_data_double_const(thresholded));
01822         
01823         check( uves_vector_save(image_1d, filename, bpp, header, CPL_IO_DEFAULT),
01824            "Error saving vector to file '%s'", filename );
01825     }
01826     else
01827     {
01828         check( uves_image_save(thresholded, filename, bpp, plist, CPL_IO_DEFAULT), 
01829            "Error saving image to file '%s'", filename);
01830     }
01831     
01832   cleanup:
01833     uves_unwrap_vector_const(&image_1d);
01834     uves_free_propertylist(&header);
01835     uves_free_image(&thresholded);
01836 
01837     return;
01838 }
01839 
01840 
01841 
01842 
01843 
01844 
01845 
01846 
01847 
01848 
01849 
01850 
01851 
01852 
01853 
01854 
01855 
01856 
01857 
01858 /*----------------------------------------------------------------------------*/
01878 /*----------------------------------------------------------------------------*/
01879 void
01880 uves_save_imagelist(const cpl_imagelist *iml, const char *filename, const uves_propertylist *plist)
01881 {
01882     cpl_image* img=NULL;
01883     cpl_type_bpp bpp;
01884     cpl_type t;
01885     const cpl_vector *image_1d = NULL;
01886     uves_propertylist *header = NULL;
01887     cpl_imagelist *thresholded = NULL;
01888 
01889     int nx = 0;
01890     int ny = 0;
01891     int nz = 0;
01892 
01893     
01894     cknull(iml,"Null input image");
01895     check(img=cpl_imagelist_get(iml,0),"error reading image");
01896 
01897     check_nomsg( nx = cpl_image_get_size_x(img));
01898     check_nomsg( ny = cpl_image_get_size_y(img));
01899     check_nomsg( nz = cpl_imagelist_get_size(iml));
01900 
01901     check( t = cpl_image_get_type(img), "Error reading image type");
01902     if      (t == CPL_TYPE_FLOAT ) bpp = CPL_BPP_IEEE_FLOAT;
01903     else if (t == CPL_TYPE_DOUBLE) bpp = CPL_BPP_IEEE_FLOAT;
01904     /* Internal computations in double precision,
01905        save as single precision */
01906 #if CPL_VERSION_CODE >= CPL_VERSION(3, 0, 1)
01907     else if (t == CPL_TYPE_INT   ) bpp = CPL_BPP_16_UNSIGNED;
01908 #else
01909     else if (t == CPL_TYPE_INT   ) bpp = CPL_BPP_16_SIGNED;
01910 #endif
01911     else assure(false, CPL_ERROR_UNSUPPORTED_MODE,
01912         "Unsupported image type '%s'", uves_tostring_cpl_type(t));
01913 
01914 
01915     thresholded = cpl_imagelist_duplicate(iml);
01916     assure_mem( thresholded );
01917 
01918     if (t == CPL_TYPE_DOUBLE)
01919     {
01920         passure( bpp == CPL_BPP_IEEE_FLOAT, "%d", bpp);
01921 
01922         /* Avoid infinities that would happen when casting
01923                double -> float
01924            by thresholding the image to +-FLT_MAX (or, better
01925            a little less than FLT_MAX just to be sure).
01926         
01927            (This is not a really nice solution because it solves the
01928            problem (too large/small values) after it is introduced
01929            (rather than avoiding it), but a general solution of the
01930            problem would probably mean guarding every arithmetic
01931            operation with range checks.)
01932         */
01933         
01934         check_nomsg( cpl_imagelist_threshold(thresholded,
01935                          -FLT_MAX, FLT_MAX,
01936                          -FLT_MAX, FLT_MAX) );
01937 
01938 
01939 
01940         /* Also get rid of NaN, set to zero (what else?) */
01941         {
01942         int x, y, z;
01943         double* data=NULL;
01944         for (z = 0; z < nz; z++) {
01945           img=cpl_imagelist_get(thresholded,z);
01946           data = irplib_image_get_data_double(img);
01947 
01948           for (y = 0; y < ny; y++) {
01949             for (x = 0; x < nx; x++) {
01950               if (irplib_isnan(data[x + y*nx])) {
01951             data[x + y*nx] = 0;    
01952               }
01953             }
01954           }
01955         }
01956         }
01957     }
01958     if (nz == 1 && t == CPL_TYPE_DOUBLE)
01959     /* To support other types (float, int) we would
01960        need to convert to double first */
01961     {
01962         bool invert = false;
01963         if (plist != NULL)
01964         {
01965             header = uves_propertylist_duplicate(plist);
01966             
01967             uves_propertylist_erase_regexp(header, "^CDELT3$", invert);
01968             uves_propertylist_erase_regexp(header, "^CRPIX3$", invert);
01969             uves_propertylist_erase_regexp(header, "^CRVAL3$", invert);
01970             uves_propertylist_erase_regexp(header, "^CTYPE3$", invert);
01971         }
01972         else
01973         {
01974             header = NULL;
01975         }
01976         /*
01977         image_1d = irplib_vector_wrap_const(nx,
01978                         irplib_image_get_data_double_const(thresholded));
01979         
01980         check( uves_vector_save(image_1d, filename, bpp, header, CPL_IO_DEFAULT),
01981            "Error saving vector to file '%s'", filename );
01982         */
01983         
01984     }
01985     else
01986     {
01987         check( uves_imagelist_save(thresholded, filename, bpp, plist, CPL_IO_DEFAULT), 
01988            "Error saving image to file '%s'", filename);
01989     }
01990     
01991   cleanup:
01992     uves_unwrap_vector_const(&image_1d);
01993     uves_free_propertylist(&header);
01994     uves_free_imagelist(&thresholded);
01995 
01996     return;
01997 }
01998 
01999 /*----------------------------------------------------------------------------*/
02013 /*----------------------------------------------------------------------------*/
02014 cpl_error_code
02015 uves_save_polynomial(polynomial *p, const char *filename, const uves_propertylist *header)
02016 {
02017     cpl_table *t = NULL;
02018 
02019     check( t = uves_polynomial_convert_to_table(p), "Error converting polynomial to table");
02020     
02021     check( uves_table_save(t, 
02022               NULL,                       /* Primary header, ignored when 
02023                              mode = CPL_IO_EXTEND */
02024               header,                     /* Table header */
02025               filename,
02026               CPL_IO_EXTEND),             /* Append to existing file */
02027        "Error saving table to file '%s'", filename);
02028     
02029   cleanup:
02030     uves_free_table(&t);
02031     return cpl_error_get_code();
02032 }
02033 
02034 
02035 /*----------------------------------------------------------------------------*/
02043 /*----------------------------------------------------------------------------*/
02044 static polynomial *
02045 load_polynomial(const char* filename, int extension)
02046 {
02047     polynomial *p = NULL;  /* Result */
02048     cpl_table  *t = NULL;
02049     
02050     check(t = cpl_table_load(filename,
02051                  extension,
02052                  1),                   /* Mark identified 
02053                               invalid null values (1=yes) */
02054       "Error loading polynomial from extension %d of file '%s'", extension, filename);
02055 
02056     assure( uves_erase_invalid_table_rows(t, NULL) == 0, 
02057         CPL_ERROR_ILLEGAL_INPUT, "Table contains invalid rows");
02058     
02059     check(p = uves_polynomial_convert_from_table(t), "Error converting table to polynomial");
02060 
02061   cleanup:
02062     uves_free_table(&t);
02063     if (cpl_error_get_code() != CPL_ERROR_NONE)
02064     uves_polynomial_delete(&p);
02065     return p;
02066 }
02067 /*----------------------------------------------------------------------------*/
02082 /*----------------------------------------------------------------------------*/
02083 static const char *
02084 identify_arm(const cpl_frameset *frames, const char *blue_tag, const char *red_tag,
02085          bool *blue)
02086 {
02087     const char *tag = NULL; /* Result */
02088     
02089     const cpl_frame *frame = NULL;
02090     
02091     passure( frames != NULL, "");
02092     assure (!cpl_frameset_is_empty(frames), CPL_ERROR_ILLEGAL_INPUT, "No input frames");
02093     
02094     /* Identify blue/red arm */
02095     frame = irplib_frameset_find_const(frames, blue_tag);
02096     *blue = (frame != NULL);
02097     
02098     if (frame == NULL)
02099     {
02100         frame = irplib_frameset_find_const(frames, red_tag);
02101     }
02102     
02103     assure( frame != NULL, CPL_ERROR_ILLEGAL_INPUT, 
02104         "No valid input frames "
02105         "('%s' or '%s') in frame set",
02106         blue_tag, red_tag);
02107     
02108     assure( irplib_frameset_find_const(frames, blue_tag) == NULL ||
02109         irplib_frameset_find_const(frames, red_tag)  == NULL,
02110         CPL_ERROR_INCOMPATIBLE_INPUT,
02111         "Multiple types of input frames ('%s' and '%s') in frame set",
02112         blue_tag, red_tag);
02113     
02114     tag = cpl_frame_get_tag(frame);
02115     
02116     uves_msg("Input frames are '%s'", tag);
02117     
02118 
02119   cleanup:
02120     return tag;
02121 }
02122 
02123 /*----------------------------------------------------------------------------*/
02141 /*----------------------------------------------------------------------------*/
02142 cpl_image *
02143 uves_crop_and_rotate(const cpl_image *image, const uves_propertylist *header,
02144              enum uves_chip chip,
02145              const uves_propertylist *redl_header, 
02146              bool new_format, uves_propertylist **out_header)
02147 {
02148     cpl_image *result = NULL;
02149     int prescanx, ovrscanx;
02150     int nx, ny;
02151     int x_0, y_0, x_1, y_1; /* Extracted area (inclusive) in 
02152                    FITS convention (i.e. counting from 1) */
02153 
02154     const char *ctype1, *ctype2; /* Geometry */
02155     const char *bunit;
02156     double crval1, crval2;
02157     double crpix1, crpix2;
02158     double cdelt1, cdelt2;
02159 
02160     passure( image != NULL, " ");
02161     passure( header != NULL, " ");
02162     passure( out_header != NULL, " ");
02163     
02164     nx = cpl_image_get_size_x(image);
02165     ny = cpl_image_get_size_y(image);
02166 
02167 
02168     /* Determine pre- and overscan areas */
02169     check( prescanx = uves_pfits_get_prescanx(header, chip), "Could not read x-prescan info" );
02170     check( ovrscanx = uves_pfits_get_ovrscanx(header, chip), "Could not read x-overscan info");
02171   
02172     /* Don't try to read the y pre- and overscan regions, which should be zero for UVES.
02173        The keywords are not present in older UVES data. */
02174 
02175     /* Read geometry */
02176     check( ctype1 = uves_pfits_get_ctype1(header), "Error reading keyword");
02177     check( ctype2 = uves_pfits_get_ctype2(header), "Error reading keyword");
02178     check( crval1 = uves_pfits_get_crval1(header), "Error reading keyword");
02179     check( crval2 = uves_pfits_get_crval2(header), "Error reading keyword");
02180     check( crpix1 = uves_pfits_get_crpix1(header), "Error reading keyword");
02181     check( crpix2 = uves_pfits_get_crpix2(header), "Error reading keyword");
02182     check( cdelt1 = uves_pfits_get_cdelt1(header), "Error reading keyword");
02183     check( cdelt2 = uves_pfits_get_cdelt2(header), "Error reading keyword");
02184     if (uves_propertylist_contains(header, UVES_BUNIT))
02185     {
02186         bunit = uves_pfits_get_bunit(header);
02187     }
02188     else
02189     {
02190         bunit = " ";
02191     }
02192     
02193 
02194     /* Crop the image */
02195     {
02196     y_0 = 1;
02197     y_1 = ny;
02198     if (new_format || chip == UVES_CHIP_BLUE)
02199         {
02200         x_0 = prescanx + 1;
02201         x_1 = nx - ovrscanx;
02202         }
02203     else /* red, old format */
02204         {
02205         if (chip == UVES_CHIP_REDU)
02206             {
02207             x_0 = prescanx + 1;
02208             x_1 = nx/2 - ovrscanx;
02209             }
02210         else
02211             { /* lower */
02212             x_0 = nx/2 + prescanx + 1;
02213             x_1 = nx - ovrscanx;
02214             }
02215         }
02216     
02217     check( result = cpl_image_extract(image, x_0, y_0, x_1, y_1), "Could not crop image");
02218     crpix1 = crpix1 - (x_0 - 1);
02219     crpix2 = crpix2 - (y_0 - 1);
02220     nx = (x_1 - x_0) + 1;
02221     ny = (y_1 - y_0) + 1;
02222     }
02223 
02224     UVES_TIME_START("Rotation");
02225     /* ... is a bit slow, and there's probably nothing to
02226        do about as it involves moving data between remote
02227        places in memory.
02228     */
02229 
02230     /* Rotate the image into standard orientation */
02231     {
02232     int crpix1_old = crpix1;
02233     int crpix2_old = crpix2;
02234     int crval1_old = crval1;
02235     int crval2_old = crval2;
02236     int cdelt1_old = cdelt1;
02237     int cdelt2_old = cdelt2;
02238     const char *ctype1_old = ctype1;
02239     const char *ctype2_old = ctype2;
02240 
02241     if (chip == UVES_CHIP_BLUE)
02242         {
02243         /* 90 deg counterclockwise rotation */
02244         check( cpl_image_turn(result, -1), "Could not turn image");
02245         
02246         crpix1 = ny - (crpix2_old - 1); /* Note: old value of ny */
02247         crpix2 = crpix1_old;
02248         crval1 = crval2_old;
02249         crval2 = crval1_old;
02250         }
02251     else 
02252         {
02253         /* Red */
02254         /* Flip image around y=-x */
02255         check( cpl_image_flip(result, 3), "Could not flip image");
02256 
02257         crpix1 = ny - (crpix2_old - 1); /* Note: old value of nx, ny */
02258         crpix2 = nx - (crpix1_old - 1);
02259         crval1 = crval2_old;
02260         crval2 = crval1_old;
02261         }
02262 
02263     /* Always swap these ones */
02264     ctype1 = ctype2_old;
02265     ctype2 = ctype1_old;
02266     cdelt1 = cdelt2_old;
02267     cdelt2 = cdelt1_old;
02268     }
02269 
02270     UVES_TIME_END;
02271 
02272     /* Here we should use the CROTAi keywords to 
02273        properly describe the new rotation */
02274     
02275     /* Instead, redefine CRVAL as in the following, on request from DFO */
02276 
02277     crpix1 = 1;
02278     crpix2 = 1;
02279     if (chip == UVES_CHIP_BLUE || chip == UVES_CHIP_REDL)
02280     {
02281         crval1 = 1;
02282         crval2 = 1;
02283     }
02284     else 
02285     {
02286             int physical_gap_between_chips = 64; /* Pixels. Unbinned. Hardcoded. */
02287 
02288         passure( chip == UVES_CHIP_REDU , "%d", chip );
02289         
02290         crval1 = 1;
02291         
02292         /* Set CRVAL2 = REDL_height - REDL_overscan - REDL_prescan + gap. */
02293         if (new_format)
02294         {
02295             check( crval2 = 1 +
02296                (uves_pfits_get_naxis1(redl_header) -
02297                 uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL) -
02298                 uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL)) *
02299                uves_pfits_get_cdelt1(redl_header) +
02300                            physical_gap_between_chips,
02301                "Error reading REDL chip geometry");
02302 
02303             uves_msg_debug("Setting CRVAL2 = 1 + (%d - %d - %d) * %f + %d = %f",
02304                    uves_pfits_get_naxis1(redl_header),
02305                    uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL),
02306                    uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL),
02307                    uves_pfits_get_cdelt1(redl_header),
02308                                    physical_gap_between_chips, crval2);
02309         }
02310         else
02311         {
02312             /* old format */
02313             check( crval2 = 1 +
02314                (uves_pfits_get_naxis1(header)/2 -
02315                 uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL) -
02316                 uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL)) *
02317                uves_pfits_get_cdelt1(redl_header) +
02318                            physical_gap_between_chips,
02319                "Error reading REDL chip geometry");
02320 
02321             uves_msg_debug("Setting CRVAL2 = 1 + (%d - %d - %d) * %f + %d = %f",
02322                    uves_pfits_get_naxis1(header)/2, 
02323                    uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL),
02324                    uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL),
02325                    uves_pfits_get_cdelt1(redl_header),
02326                                    physical_gap_between_chips, crval2);
02327         }
02328     }
02329 
02330     /* Update header with new geometry */
02331     check( *out_header = uves_initialize_image_header(ctype1, ctype2, bunit,
02332                               crval1, crval2,
02333                               crpix1, crpix2,
02334                               cdelt1, cdelt2),
02335        "Error initializing header");
02336     
02337     uves_msg("Raw image cropped and rotated from %dx%d to %dx%d",
02338          nx, ny,
02339          cpl_image_get_size_x(result),
02340          cpl_image_get_size_y(result));     
02341     
02342   cleanup:
02343     if (cpl_error_get_code() != CPL_ERROR_NONE)
02344     {
02345         uves_free_image(&result);
02346         if (out_header != NULL)
02347         {
02348             uves_free_propertylist(out_header);
02349         }
02350     }
02351 
02352     return result;
02353 }
02354 
02355 /*----------------------------------------------------------------------------*/
02369 /*----------------------------------------------------------------------------*/
02370 void
02371 uves_warn_if_chip_names_dont_match(const uves_propertylist *calib_header, 
02372                   const char *raw_chip_name, enum uves_chip chip)
02373 {
02374     const char *calib_chip_name;
02375     bool mismatch = false;
02376 
02377     check( calib_chip_name = uves_pfits_get_chipid(calib_header, chip),
02378        "Could not read chip name of calibration data");
02379 
02380 
02381     /* Ignore leading/trailing blanks when comparing name strings.
02382      * (The following is O(n^2) where n is the string length, 
02383      * but that's ok because the strings stored in a FITS card are short).
02384      */
02385     {
02386     unsigned int calib_first, calib_last;  /* inclusive */
02387     unsigned int raw_first, raw_last;
02388     
02389     calib_first = 0;
02390     raw_first = 0;
02391     while (calib_chip_name[calib_first] == ' ' && calib_first < strlen(calib_chip_name) - 1)
02392         {
02393         calib_first++;
02394         }
02395     while (raw_chip_name[raw_first] == ' ' && raw_first < strlen(raw_chip_name) - 1)
02396         {
02397         raw_first++;
02398         }
02399 
02400     calib_last = strlen(calib_chip_name) - 1;
02401     raw_last = strlen(raw_chip_name) - 1;
02402     while (calib_chip_name[calib_last] == ' ' && calib_last > 0)
02403         {
02404         calib_last--;
02405         }
02406     while (raw_chip_name[raw_last] == ' ' && raw_last > 0)
02407         {
02408         raw_last--;
02409         }
02410 
02411     /* Compare substrings */
02412     if (calib_last - calib_first != raw_last - raw_first)
02413         {
02414         mismatch = true;
02415         }
02416     else
02417         {
02418         unsigned int i;
02419         
02420         for (i = 0; i <= (calib_last - calib_first); i++)
02421             {
02422             if (raw_chip_name[raw_first + i] != 
02423                 calib_chip_name[calib_first + i])
02424                 {
02425                 mismatch = true;
02426                 }
02427             }
02428         }
02429     }
02430 
02431 
02432     if (mismatch)
02433     {
02434         uves_msg_warning("Calibration frame chip ID '%s' does "
02435                  "not match raw frame chip ID '%s'",
02436                  calib_chip_name, raw_chip_name);
02437     }
02438 
02439   cleanup:
02440     return;
02441 }
02442 
02443 
02444 /*----------------------------------------------------------------------------*/
02466 /*----------------------------------------------------------------------------*/
02467 
02468 static cpl_error_code
02469 load_raw_image(const char *filename, 
02470            cpl_type type,
02471            bool flames,
02472            bool blue,
02473            cpl_image *raw_image[2],
02474            uves_propertylist *raw_header[2], 
02475                uves_propertylist *rotated_header[2])
02476 {
02477 
02478  
02479     cpl_image *image = NULL;
02480     uves_propertylist *primary_header = NULL;
02481     uves_propertylist *ext_header = NULL;
02482     int extension, nextensions;
02483     bool new_format;
02484     int plane = 0;   /* Only one plane in FLAMES/UVES raw files */
02485 
02486     /* Initialize parameters */
02487     raw_image[0] = NULL;
02488     raw_image[1] = NULL;
02489     raw_header[0] = NULL;
02490     raw_header[1] = NULL;
02491     rotated_header[0] = NULL;
02492     rotated_header[1] = NULL;
02493 
02494     check( nextensions = uves_get_nextensions(filename),
02495        "Error reading number of extensions of file '%s'", filename);
02496 
02497     /* Find out if new/old format */
02498     extension = 0;
02499     check( primary_header = uves_propertylist_load(filename,
02500                           extension),
02501        "Could not load header from extension %d of file '%s'", 
02502        extension, filename);
02503 
02504     check( new_format = uves_format_is_new(primary_header),
02505        "Error determining new/old format of file %s", filename);
02506  
02507     uves_msg_low("Raw frame is %s, file '%s' has %d extensions", 
02508          (blue) ? "blue" : "red", filename, nextensions);
02509     
02510     /* If the raw frame is blue, or if it's an old format red frame */
02511     if (blue || !new_format)
02512     {
02513         enum uves_chip chip;
02514         
02515         uves_msg_debug("Frame is blue or old format");
02516 
02517         assure( nextensions == 0 || (flames && nextensions == 2),
02518             CPL_ERROR_ILLEGAL_INPUT, 
02519             "Unrecognized format of file '%s'. %d extensions expected. %d found.",
02520             filename, 
02521             flames ? 2 : 0, nextensions);
02522         /* FLAMES: the 2 extensions contain OzPoz table and FLAMES FIBRE table */
02523 
02524         extension = 0;
02525 
02526         check( image = cpl_image_load(filename,
02527                       type,
02528                       plane,   
02529                       extension
02530                ), "Could not load image from extension %d of file '%s' ", 
02531            extension, filename);
02532 
02533         /* Load the header */
02534         check( raw_header[0] = uves_propertylist_load(filename,
02535                              extension),
02536            "Could not load header from extension %d of file '%s'", 
02537            extension, filename);
02538 
02539         /* Get blue (or lower red) chip */
02540         chip = (blue) ? UVES_CHIP_BLUE : UVES_CHIP_REDL;
02541         check( raw_image[0] = uves_crop_and_rotate(image, raw_header[0], 
02542                                chip, raw_header[0],
02543                                new_format, 
02544                                &rotated_header[0]),
02545            "Error splitting image");
02546         
02547         if (!blue)
02548         {
02549             const uves_propertylist *redl_header;
02550 
02551             /* Upper red chip, use again the primary header */
02552             check( raw_header[1] = uves_propertylist_duplicate(raw_header[0]),
02553                "Error duplicating FITS header");
02554             
02555             /* Get upper red chip */
02556             chip = UVES_CHIP_REDU;
02557             redl_header = raw_header[0];
02558             check( raw_image[1] = uves_crop_and_rotate(image, raw_header[1],
02559                                    chip, redl_header,
02560                                    new_format,
02561                                    &rotated_header[1]),
02562                "Error splitting red image");
02563         }
02564         else
02565         {
02566             raw_image[1] = NULL;
02567             raw_header[1] = NULL;
02568             rotated_header[1] = NULL;
02569         }
02570     }
02571     else
02572     /* New red format. UVES must have 2 extensions,
02573      * FLAMES must have 2 or more extensions
02574      */
02575     {
02576         uves_msg_debug("Frame is red, new format");
02577         
02578         assure( nextensions >= 2, CPL_ERROR_UNSUPPORTED_MODE,
02579             "File '%s' (red frame) has %d extensions. 2+ extensions expected "
02580                     "for new format",
02581             filename, nextensions);
02582         
02583         uves_msg_debug("New red format, %s frame",
02584                (nextensions > 2) ? "FLAMES" : "FLAMES/UVES");
02585         
02586         /* Images always in extension 1 and 2. First load just the headers */
02587         for (extension = 1; extension <= 2; extension++)
02588         {
02589             /* In the FITS file, REDU is stored
02590                in extension 1, and REDL is stored in
02591                extension 2 */
02592             enum uves_chip chip = (extension == 1) ? UVES_CHIP_REDU : UVES_CHIP_REDL;
02593             int indx = uves_chip_get_index(chip);
02594 
02595             /* Load the extension header */
02596             uves_free_propertylist(&ext_header);
02597             check( ext_header = uves_propertylist_load(filename,
02598                                   extension),
02599                "Could not load header from extension %d of file '%s'", 
02600                extension, filename);
02601             
02602             /* Merge with primary header */
02603             check( raw_header[indx] = uves_propertylist_duplicate(primary_header),
02604                "Error cloning primary header");
02605             
02606             if (!uves_propertylist_is_empty(ext_header))
02607             {
02608                 check( uves_propertylist_copy_property_regexp(raw_header[indx],
02609                                      ext_header, ".*", 0),
02610                    "Error merging primary header with extension %d header", 
02611                    extension);
02612             }
02613         }
02614 
02615         /* Remove pre-, overscan areas (we needed to load both image headers for this) */
02616         for (extension = 1; extension <= 2; extension++)
02617         {
02618             enum uves_chip chip = (extension == 1) ? UVES_CHIP_REDU : UVES_CHIP_REDL;
02619             int indx      = uves_chip_get_index(chip);
02620             int indx_redl = uves_chip_get_index(UVES_CHIP_REDL);
02621             
02622             const uves_propertylist *redl_header = raw_header[indx_redl];
02623             
02624             uves_free_image(&image);
02625             check( image = cpl_image_load(filename,
02626                           type,
02627                           plane,               
02628                           extension),
02629                "Could not load image from extension %d of file '%s' ", 
02630                extension, filename);
02631             
02632             check( raw_image[indx] = uves_crop_and_rotate(image, 
02633                                   raw_header[indx],
02634                                   chip, redl_header,
02635                                   new_format,
02636                                   &rotated_header[indx]),
02637                "Error splitting red image");
02638         }
02639         
02640     }/* if new format */
02641  
02642   cleanup:
02643     uves_free_image(&image);
02644     uves_free_propertylist(&primary_header);
02645     uves_free_propertylist(&ext_header);
02646 
02647     if (cpl_error_get_code() != CPL_ERROR_NONE)
02648     {
02649         uves_free_image       (&raw_image[0]);
02650         uves_free_image       (&raw_image[1]);
02651         uves_free_propertylist(&raw_header[0]);
02652         uves_free_propertylist(&raw_header[1]);
02653         uves_free_propertylist(&rotated_header[0]);
02654         uves_free_propertylist(&rotated_header[1]);
02655     }
02656     
02657     return cpl_error_get_code();
02658 }
02659 
02660 
02661 /*----------------------------------------------------------------------------*/
02689 /*----------------------------------------------------------------------------*/
02690 cpl_error_code
02691 uves_load_raw_imagelist(const cpl_frameset *frames,
02692             bool flames,
02693             const char *blue_tag, const char *red_tag, cpl_type type, 
02694             cpl_imagelist *images[2],
02695             uves_propertylist **raw_headers[2], uves_propertylist *rotated_header[2],
02696             bool *blue)
02697 {
02698     const char *tag           = NULL;
02699     const cpl_frame *frame    = NULL;
02700     cpl_image *temp_image[2]  = {NULL, NULL};
02701     uves_propertylist *temp_header[2] = {NULL, NULL};
02702     int number_of_frames = 0;
02703     int frameset_size = 0;   /* Keeps track of number of raw_header pointers allocated */
02704     int nchips;
02705     int chip;
02706     
02707     raw_headers[0] = NULL;
02708     raw_headers[1] = NULL;
02709 
02710     check( frameset_size = cpl_frameset_get_size(frames),
02711        "Error reading frameset size");
02712 
02713     check( tag = identify_arm(frames, blue_tag, red_tag, blue),
02714        "Could not identify chip type");
02715     
02716     nchips = (*blue) ? 1 : 2;
02717     for(chip = 0; chip < nchips; chip++)
02718     {
02719         images[chip] = NULL;
02720         rotated_header[chip] = NULL;
02721         
02722         images[chip] = cpl_imagelist_new();
02723         raw_headers[chip] = cpl_calloc(frameset_size, sizeof(uves_propertylist *));
02724     }
02725 
02726     /* Load all input images with correct tag,
02727        split,
02728        insert into image list(s) */  
02729 
02730     number_of_frames = 0;
02731     for(frame = irplib_frameset_get_first_const(frames);
02732     frame != NULL;
02733     frame = irplib_frameset_get_next_const(frames))
02734     {
02735         /* If match */
02736         if ( strcmp(cpl_frame_get_tag(frame), tag) == 0)
02737         {
02738             const char *filename = cpl_frame_get_filename(frame);
02739             
02740             /* Load image + header */
02741             uves_free_propertylist(&rotated_header[0]);
02742             uves_free_propertylist(&rotated_header[1]);
02743             
02744             check( load_raw_image(filename,
02745                       type,
02746                       flames,
02747                       *blue,
02748                       temp_image,
02749                       temp_header,
02750                       rotated_header),
02751                "Could not load image from file '%s'", filename);
02752             
02753             /* Append to image lists */
02754             for(chip = 0; chip < nchips; chip++)
02755             {
02756                 raw_headers[chip][number_of_frames] = temp_header[chip];
02757                 temp_header[chip] = NULL;
02758                 
02759                 check( cpl_imagelist_set(images[chip],
02760                              temp_image[chip],
02761                              /* Position */
02762                              cpl_imagelist_get_size(images[chip])
02763                        ),
02764                    "Could not insert image into image list");
02765                 
02766                 /* Don't deallocate image or header */
02767                 temp_image[chip] = NULL;
02768             }
02769             
02770             number_of_frames += 1;
02771         }
02772     }
02773 
02774     /* Check that image sizes are identical */
02775     
02776     for(chip = 0; chip < nchips; chip++)
02777     {
02778         /* This function returns zero iff the list is uniform */
02779         assure (cpl_imagelist_is_uniform(images[chip]) == 0,
02780             CPL_ERROR_INCOMPATIBLE_INPUT, 
02781             "Input images are not of same size and type");
02782         
02783         passure( cpl_imagelist_get_size(images[chip]) == number_of_frames, 
02784              "%d %d", cpl_imagelist_get_size(images[0]), number_of_frames);
02785 
02786     }
02787 
02788     
02789     /* Check central wavelengths (not bias/dark) */
02790     if ( strcmp(UVES_BIAS (*blue), tag) != 0 &&
02791      strcmp(UVES_DARK (*blue), tag) != 0 &&
02792      strcmp(UVES_PDARK(*blue), tag) != 0) {
02793     enum uves_chip chip_id;
02794     int i;
02795     double wlen = 0;
02796     
02797     for (chip_id = uves_chip_get_first(*blue); 
02798          chip_id != UVES_CHIP_INVALID;
02799          chip_id = uves_chip_get_next(chip_id)) {
02800         for (i = 0; i < number_of_frames; i++) {
02801         if (i == 0) {
02802             check( wlen = uves_pfits_get_gratwlen(
02803                    raw_headers[uves_chip_get_index(chip_id)][i], chip_id),
02804                "Error reading central wavelength of input frame number %d", i+1);
02805         }
02806         else {
02807             double w;
02808             
02809             check( w = uves_pfits_get_gratwlen(
02810                    raw_headers[uves_chip_get_index(chip_id)][i], chip_id),
02811                "Error reading central wavelength of input frame number %d", i+1);
02812             
02813             assure( fabs((w-wlen)/wlen) < 0.01, CPL_ERROR_INCOMPATIBLE_INPUT,
02814                 "Mis-matching input frame central wavelengths: "
02815                 "%e (frame 1) != %e (frame %d)", wlen, w, i+1);
02816         }
02817         }
02818     }
02819     }
02820     
02821   cleanup:
02822     uves_free_image(&temp_image[0]);
02823     uves_free_image(&temp_image[1]);
02824     uves_free_propertylist(&temp_header[0]);
02825     uves_free_propertylist(&temp_header[1]);
02826     
02827     if (cpl_error_get_code() != CPL_ERROR_NONE) {
02828     if (raw_headers[0] != NULL) {
02829         int i;
02830         for (i = 0; i < frameset_size; i++)    {
02831         if (raw_headers[0] != NULL) uves_free_propertylist(&raw_headers[0][i]);
02832         if (raw_headers[1] != NULL) uves_free_propertylist(&raw_headers[1][i]);
02833         }
02834     }
02835     cpl_free(raw_headers[0]); raw_headers[0] = NULL;
02836     cpl_free(raw_headers[1]); raw_headers[1] = NULL;
02837     
02838     uves_free_imagelist(&images[0]);
02839     uves_free_imagelist(&images[1]);
02840     
02841     uves_free_propertylist(&rotated_header[0]);
02842     uves_free_propertylist(&rotated_header[1]);
02843     }
02844 
02845     return cpl_error_get_code();
02846 }
02847 
02848 
02849 /*----------------------------------------------------------------------------*/
02866 /*----------------------------------------------------------------------------*/
02867 cpl_error_code
02868 uves_load_orderpos(const cpl_frameset *frames,
02869            bool flames,
02870            const char **raw_filename,
02871            cpl_image *raw_image[2],
02872            uves_propertylist *raw_header[2], 
02873            uves_propertylist *rotated_header[2], bool *blue)
02874 {
02875     const char *tags[4];
02876 
02877     int number_of_tags = sizeof(tags) / sizeof(char *);
02878     int indx;
02879 
02880     /* Warning: Duplicate logic. The number of tags must match the size of the
02881        tags array defined above */
02882     tags[0] = UVES_ORDER_FLAT(flames, false); /* red */
02883     tags[1] = UVES_ORDER_FLAT(flames, true);  /* blue */
02884     tags[2] = UVES_STD_STAR(false);
02885     tags[3] = UVES_STD_STAR(true);
02886 
02887     if (flames)
02888     {
02889         *blue = false;
02890         number_of_tags = 1;
02891 
02892         check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx,
02893                            NULL),
02894            "Could not find raw frame (%s) in SOF", 
02895            tags[0]);
02896         
02897     }
02898     else
02899     {    
02900         check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx,
02901                            NULL),
02902            "Could not find raw frame (%s, %s, %s, or %s) in SOF", 
02903            tags[0], tags[1], tags[2], tags[3]);
02904         
02905         *blue = (indx == 1) || (indx == 3);
02906     }
02907 
02908     /* Load the image */
02909     check( load_raw_image(*raw_filename,
02910               CPL_TYPE_DOUBLE,
02911               flames,
02912               *blue,
02913               raw_image,
02914               raw_header,
02915               rotated_header),
02916        "Error loading image from file '%s'", *raw_filename);
02917     
02918     passure( !flames || !(*blue), "%d %d",
02919          flames, *blue );
02920 
02921   cleanup:
02922     if (cpl_error_get_code() != CPL_ERROR_NONE)
02923     {
02924         *raw_filename = NULL;
02925     }
02926     
02927     return cpl_error_get_code();
02928 }
02929 
02930 /*----------------------------------------------------------------------------*/
02946 /*----------------------------------------------------------------------------*/
02947 cpl_error_code
02948 uves_load_formatcheck(const cpl_frameset *frames,
02949               bool flames,
02950               const char **raw_filename,
02951               cpl_image *raw_image[2],
02952               uves_propertylist *raw_header[2], 
02953               uves_propertylist *rotated_header[2], bool *blue)
02954 {
02955     const char *tags[2];
02956     int number_of_tags = sizeof(tags) / sizeof(char *);
02957     int indx;
02958 
02959     tags[0] = UVES_FORMATCHECK(flames, false);   /* red */
02960     tags[1] = UVES_FORMATCHECK(flames, true);    /* blue */
02961     if (flames)
02962     {
02963         *blue = false;
02964         number_of_tags = 1;
02965 
02966         check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
02967            "Could not find raw frame (%s) in SOF",
02968            tags[0]);
02969     }
02970     else
02971     {
02972         check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
02973            "Could not find raw frame (%s or %s) in SOF", 
02974            tags[0], tags[1]);
02975         
02976         *blue = (indx == 1);
02977     }
02978 
02979     /* Load the image */
02980     check( load_raw_image(*raw_filename,
02981               CPL_TYPE_DOUBLE,
02982               flames,
02983               *blue,
02984               raw_image,
02985               raw_header,
02986               rotated_header),
02987        "Error loading image from file '%s'", *raw_filename);
02988    
02989   cleanup:
02990     if (cpl_error_get_code() != CPL_ERROR_NONE) 
02991     {
02992         *raw_filename = NULL;
02993     }
02994     return cpl_error_get_code();
02995 }
02996 
02997 /*----------------------------------------------------------------------------*/
03016 /*----------------------------------------------------------------------------*/
03017 void uves_load_cd_align(const cpl_frameset *frames,
03018             const char **raw_filename1,
03019             const char **raw_filename2,
03020             cpl_image *raw_image1[2],
03021             cpl_image *raw_image2[2],
03022             uves_propertylist *raw_header1[2], 
03023             uves_propertylist *raw_header2[2], 
03024             uves_propertylist *rotated_header1[2], 
03025             uves_propertylist *rotated_header2[2], 
03026             bool *blue)
03027 {
03028     const char *tags[2];
03029     int number_of_tags = sizeof(tags) / sizeof(char *);
03030     int indx;
03031     bool flames = false;
03032     cpl_frame *frame;
03033 
03034     tags[0] = UVES_CD_ALIGN(false);   /* red */
03035     tags[1] = UVES_CD_ALIGN(true);    /* blue */
03036 
03037     check( *raw_filename1 = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
03038        "Could not find raw frame (%s or %s) in SOF", 
03039        tags[0], tags[1]);
03040     
03041     *blue = (indx == 1);
03042 
03043     assure( cpl_frameset_count_tags(frames, tags[indx]) == 2,
03044         CPL_ERROR_ILLEGAL_INPUT,
03045         "%d %s frames found. Exactly 2 required",
03046         cpl_frameset_count_tags(frames, tags[indx]), tags[indx] );
03047 
03048     /* Load the two frames */
03049     {
03050     int n = 1;
03051     for (frame = cpl_frameset_get_first(frames);
03052          frame != NULL;
03053          frame = cpl_frameset_get_next(frames))
03054         {
03055         if (strcmp(cpl_frame_get_tag(frame), tags[indx]) == 0)
03056             {
03057             if (n == 1)
03058                 {
03059                 *raw_filename1 = cpl_frame_get_filename(frame);
03060                 }
03061             else
03062                 {
03063                 *raw_filename2 = cpl_frame_get_filename(frame);
03064                 }
03065             
03066             check( load_raw_image(n == 1 ? 
03067                           *raw_filename1 :
03068                           *raw_filename2,
03069                           CPL_TYPE_DOUBLE,
03070                           flames,
03071                           *blue,
03072                           n == 1 ?
03073                           raw_image1 :
03074                           raw_image2,
03075                           n == 1 ?
03076                           raw_header1 :
03077                           raw_header2,
03078                           n == 1 ?
03079                           rotated_header1 :
03080                           rotated_header2),
03081                    "Error loading image from file '%s'",
03082                    n == 1 ? *raw_filename1 : *raw_filename2);
03083 
03084             n++;
03085             }
03086         }
03087     }
03088     
03089   cleanup:
03090     if (cpl_error_get_code() != CPL_ERROR_NONE) 
03091     {
03092         *raw_filename1 = NULL;
03093         *raw_filename2 = NULL;
03094     }
03095     
03096     return;
03097 }
03098 
03099 /*----------------------------------------------------------------------------*/
03120 /*----------------------------------------------------------------------------*/
03121 void
03122 uves_load_arclamp(const cpl_frameset *frames,
03123           bool flames,
03124           const char **raw_filename, 
03125           cpl_image *raw_image[2], uves_propertylist *raw_header[2],
03126           uves_propertylist *rotated_header[2], bool *blue,
03127           bool *sim_cal)
03128 {
03129     const char *tags[4];
03130 
03131     int number_of_tags = sizeof(tags) / sizeof(char *);
03132     int indx;
03133 
03134     /* Warning: duplicate logic. Array size above must match */
03135     if (flames)
03136     {
03137         assure_nomsg( sim_cal != NULL, CPL_ERROR_NULL_INPUT );
03138 
03139         tags[0] = UVES_ARC_LAMP(flames, true);  /* blue flag not used */
03140         tags[1] = FLAMES_FIB_SCI_SIM;
03141 
03142         number_of_tags = 2;
03143         *blue = false;
03144 
03145         check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
03146            "Could not find raw frame (%s or %s) in SOF", 
03147            tags[0], tags[1]);
03148         
03149         *sim_cal = (indx == 1);
03150     }
03151     else
03152     {
03153         tags[0] = UVES_ARC_LAMP(flames, true);
03154         tags[1] = UVES_ARC_LAMP(flames, false);
03155         tags[2] = UVES_ECH_ARC_LAMP(true);
03156         tags[3] = UVES_ECH_ARC_LAMP(false);
03157 
03158         check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
03159            "Could not find raw frame (%s, %s, %s or %s) in SOF", 
03160            tags[0], tags[1], tags[2], tags[3]);
03161         
03162         *blue = (indx == 0 || indx == 2);
03163     }
03164     
03165     /* Load the image */
03166     check( load_raw_image(*raw_filename,
03167               CPL_TYPE_DOUBLE,
03168               flames,
03169               *blue,
03170               raw_image,
03171               raw_header,
03172               rotated_header),
03173        "Error loading image from file '%s'", *raw_filename);
03174 
03175   cleanup:
03176     if (cpl_error_get_code() != CPL_ERROR_NONE) {
03177     *raw_filename = NULL;
03178     uves_free_image       (raw_image);
03179     uves_free_propertylist(raw_header);
03180     }
03181     return;
03182 }
03183 
03184 /*----------------------------------------------------------------------------*/
03199 /*----------------------------------------------------------------------------*/
03200 cpl_error_code
03201 uves_load_science(const cpl_frameset *frames, const char **raw_filename, 
03202           cpl_image *raw_image[2], 
03203           uves_propertylist *raw_header[2], 
03204           uves_propertylist *rotated_header[2], 
03205           bool *blue,
03206           const char **sci_type)
03207 {
03208     /* Note: the two following arrays must match */
03209     const char *tags[] = 
03210     { 
03211         UVES_SCIENCE(true), UVES_SCIENCE(false),
03212         UVES_SCI_EXTND(true), UVES_SCI_EXTND(false),
03213         UVES_SCI_POINT(true), UVES_SCI_POINT(false),
03214         UVES_SCI_SLICER(true), UVES_SCI_SLICER(false),
03215         UVES_TFLAT(true), UVES_TFLAT(false) 
03216     };
03217 
03218     const char *type[] = 
03219     {
03220         "SCIENCE", "SCIENCE",
03221         "SCI_EXTND", "SCI_EXTND",
03222         "SCI_POINT", "SCI_POINT",
03223         "SCI_SLICER", "SCI_SLICER",
03224         "TFLAT", "TFLAT",
03225     };
03226 
03227     int number_of_tags = sizeof(tags) / sizeof(char *);
03228     int indx;
03229     bool flames = false;
03230 
03231     check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
03232        "No science frame (%s, %s, %s, %s, %s, %s, %s, %s, %s or %s) in SOF", 
03233        tags[0], tags[1], tags[2], tags[3], 
03234        tags[4], tags[5], tags[6], tags[7], tags[7], tags[8]);
03235 
03236     *blue = (indx % 2 == 0);
03237     *sci_type = type[indx];
03238     
03239     /* Load the image */
03240     check( load_raw_image(*raw_filename,
03241               CPL_TYPE_DOUBLE,
03242               flames,
03243               *blue,
03244               raw_image,
03245               raw_header,
03246               rotated_header),
03247        "Error loading image from file '%s'", *raw_filename);
03248   cleanup:
03249     if (cpl_error_get_code() != CPL_ERROR_NONE)
03250     {
03251         *raw_filename = NULL;
03252         uves_free_image       (raw_image);
03253         uves_free_propertylist(raw_header);
03254     }
03255     return cpl_error_get_code();
03256 }
03257 
03258 /*----------------------------------------------------------------------------*/
03275 /*----------------------------------------------------------------------------*/
03276 cpl_error_code
03277 uves_load_standard(const cpl_frameset *frames, const char **raw_filename, 
03278            cpl_image *raw_image[2],
03279            uves_propertylist *raw_header[2], 
03280            uves_propertylist *rotated_header[2], bool *blue)
03281 {
03282     const char *tags[] = { UVES_STD_STAR(true), UVES_STD_STAR(false) };
03283     int number_of_tags = sizeof(tags) / sizeof(char *);
03284     int indx;
03285     bool flames = false;
03286     
03287     check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
03288        "Could not identify raw frame (%s or %s) in SOF", tags[0], tags[1]);
03289 
03290     *blue = (indx == 0);
03291     
03292     /* Load the image */
03293     check( load_raw_image(*raw_filename,
03294               CPL_TYPE_DOUBLE,
03295               flames,
03296               *blue,
03297               raw_image,
03298               raw_header,
03299               rotated_header),
03300        "Error loading image from file '%s'", *raw_filename);
03301 
03302   cleanup:
03303     if (cpl_error_get_code() != CPL_ERROR_NONE)
03304     {
03305         *raw_filename = NULL;
03306         uves_free_image       (raw_image);
03307         uves_free_propertylist(raw_header);
03308     }
03309     return cpl_error_get_code();
03310 }
03311 
03312 /*----------------------------------------------------------------------------*/
03328 /*----------------------------------------------------------------------------*/
03329 
03330 cpl_error_code
03331 uves_load_drs(const cpl_frameset *frames, 
03332           bool flames,
03333           const char *chip_name,
03334           const char **drs_filename, 
03335           uves_propertylist **drs_header,
03336           enum uves_chip chip)
03337 {
03338     const char *tags[1];
03339     int number_of_tags = sizeof(tags) / sizeof(char *);
03340     int extension;
03341     int indx;
03342     
03343     *drs_header = NULL;
03344     tags[0]   = UVES_DRS_SETUP(flames, chip);
03345     extension = UVES_DRS_SETUP_EXTENSION(chip);
03346 
03347     check( *drs_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
03348        "Could not find DRS table (%s) in SOF", tags[0]);
03349     
03350     /* Load the header */
03351     check( *drs_header = uves_propertylist_load(*drs_filename,
03352                            extension),
03353        "Could not load header from extension %d of file '%s'", extension, *drs_filename);
03354 
03355     check_nomsg( uves_warn_if_chip_names_dont_match(*drs_header, chip_name, chip) );
03356 
03357   cleanup:
03358     if (cpl_error_get_code() != CPL_ERROR_NONE) {
03359     *drs_filename = NULL;
03360     uves_free_propertylist(drs_header);
03361     }
03362     return cpl_error_get_code();
03363 }
03364 
03365 
03366 /*----------------------------------------------------------------------------*/
03382 /*----------------------------------------------------------------------------*/
03383 
03384 cpl_error_code
03385 uves_load_mbias(const cpl_frameset *frames, const char *chip_name,
03386         const char **mbias_filename, 
03387         cpl_image **mbias, uves_propertylist **mbias_header, enum uves_chip chip)
03388 {
03389     const char *tags[1];
03390     int number_of_tags = sizeof(tags) / sizeof(char *);
03391     int extension;
03392     int indx;
03393     
03394     *mbias        = NULL;
03395     *mbias_header = NULL;
03396 
03397     tags[0]   = UVES_MASTER_BIAS          (chip);
03398     extension = UVES_MASTER_BIAS_EXTENSION(chip);
03399     
03400     check( *mbias_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
03401        "Could not find '%s' in frame set", tags[0]);
03402     
03403     /* Load the mbias image */
03404     check( *mbias = cpl_image_load(*mbias_filename,
03405                    CPL_TYPE_DOUBLE,           /* Convert to this type */
03406                    0,                         /* plane number */
03407                    extension                  /* Extension number */
03408            ),
03409        "Could not load master bias from extension %d of file '%s'", 
03410        extension, *mbias_filename);
03411 
03412     /* Load the header */
03413     check( *mbias_header = uves_propertylist_load(*mbias_filename,
03414                          extension),
03415        "Could not load header from extension %d of file '%s'", 
03416        extension, *mbias_filename);
03417 
03418     check_nomsg( uves_warn_if_chip_names_dont_match(*mbias_header, chip_name, chip) );
03419 
03420   cleanup:
03421     if (cpl_error_get_code() != CPL_ERROR_NONE) 
03422     {
03423         *mbias_filename = NULL;
03424         uves_free_image(mbias);
03425         uves_free_propertylist(mbias_header);
03426     }
03427     return cpl_error_get_code();
03428 }
03429 
03430 
03431 /*----------------------------------------------------------------------------*/
03447 /*----------------------------------------------------------------------------*/
03448 
03449 cpl_error_code
03450 uves_load_master_formatcheck(const cpl_frameset *frames, const char *chip_name,
03451         const char **mform_filename, 
03452         cpl_image **mform, uves_propertylist **mform_header, enum uves_chip chip)
03453 {
03454     const char *tags[1];
03455     int number_of_tags = sizeof(tags) / sizeof(char *);
03456     int extension;
03457     int indx;
03458     
03459     *mform        = NULL;
03460     *mform_header = NULL;
03461 
03462     tags[0]   = UVES_MASTER_ARC_FORM          (chip);
03463     extension = UVES_MASTER_ARC_FORM_EXTENSION(chip);
03464     
03465     check( *mform_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
03466        "Could not find '%s' in frame set", tags[0]);
03467     
03468     /* Load the mbias image */
03469     check( *mform = cpl_image_load(*mform_filename,
03470                    CPL_TYPE_DOUBLE,           /* Convert to this type */
03471                    0,                         /* plane number */
03472                    extension                  /* Extension number */
03473            ),
03474        "Could not load master formatcheck from extension %d of file '%s'", 
03475        extension, *mform_filename);
03476 
03477     /* Load the header */
03478     
03479     check( *mform_header = uves_propertylist_load(*mform_filename,
03480                          extension),
03481        "Could not load header from extension %d of file '%s'", 
03482        extension, *mform_filename);
03483 
03484     check_nomsg( uves_warn_if_chip_names_dont_match(*mform_header, chip_name, chip) );
03485 
03486   cleanup:
03487     if (cpl_error_get_code() != CPL_ERROR_NONE) 
03488     {
03489         *mform_filename = NULL;
03490         uves_free_image(mform);
03491         uves_free_propertylist(mform_header);
03492     }
03493     return cpl_error_get_code();
03494 }
03495 
03496 /*----------------------------------------------------------------------------*/
03512 /*----------------------------------------------------------------------------*/
03513 
03514 cpl_error_code
03515 uves_load_mdark(const cpl_frameset *frames, const char *chip_name,
03516         const char **mdark_filename, cpl_image **mdark,
03517         uves_propertylist **mdark_header, enum uves_chip chip)
03518 {
03519     const char *tags[2];
03520     int number_of_tags = sizeof(tags) / sizeof(char *);
03521     int extension;
03522     int indx;
03523     
03524     *mdark        = NULL;
03525     *mdark_header = NULL;
03526 
03527     tags[0]   = UVES_MASTER_DARK          (chip);
03528     tags[1]   = UVES_MASTER_PDARK         (chip);
03529     extension = UVES_MASTER_DARK_EXTENSION(chip);
03530     
03531     check( *mdark_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
03532        "Could not find %s or %s in frame set", tags[0], tags[1]);
03533     
03534     /* Load the mdark image */
03535     check( *mdark = cpl_image_load(*mdark_filename,
03536                    CPL_TYPE_DOUBLE,           /* Convert to this type */
03537                    0,                         /* plane number */
03538                    extension                  /* Extension number */
03539            ),
03540        "Could not load master dark from extension %d of file '%s'", 
03541        extension, *mdark_filename);
03542 
03543     /* Load the header */
03544     check( *mdark_header = uves_propertylist_load(*mdark_filename,
03545                          extension),
03546        "Could not load header from extension %d of file '%s'", 
03547        extension, *mdark_filename);
03548 
03549     check_nomsg( uves_warn_if_chip_names_dont_match(*mdark_header, chip_name, chip) );
03550 
03551   cleanup:
03552     if (cpl_error_get_code() != CPL_ERROR_NONE) 
03553     {
03554         *mdark_filename = NULL;
03555         uves_free_image(mdark);
03556         uves_free_propertylist(mdark_header);
03557     }
03558     return cpl_error_get_code();
03559 }
03560 /*----------------------------------------------------------------------------*/
03576 /*----------------------------------------------------------------------------*/
03577 void
03578 uves_load_ref_flat(const cpl_frameset *frames, const char *chip_name,
03579            const char **filename, cpl_image **rflat,
03580            uves_propertylist **rflat_header, enum uves_chip chip)
03581 {
03582     const char *tags[1];
03583     int number_of_tags = sizeof(tags) / sizeof(char *);
03584     int extension;
03585     int indx;
03586     
03587     *rflat        = NULL;
03588     *rflat_header = NULL;
03589 
03590     tags[0]   = UVES_REF_TFLAT(chip);
03591     extension = UVES_MASTER_FLAT_EXTENSION(chip);
03592 
03593     check( *filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
03594        "Could not find %s in frame set", tags[0]);
03595     
03596     check( *rflat = cpl_image_load(*filename,
03597                    CPL_TYPE_DOUBLE,           /* Convert to this type */
03598                    0,                         /* plane number */
03599                    extension                  /* Extension number */
03600            ),
03601        "Could not load reference dark from extension %d of file '%s'", 
03602        extension, *filename);
03603 
03604     check( *rflat_header = uves_propertylist_load(*filename,
03605                          extension),
03606        "Could not load header from extension %d of file '%s'", 
03607        extension, *filename);
03608 
03609     check_nomsg( uves_warn_if_chip_names_dont_match(*rflat_header, chip_name, chip) );
03610 
03611   cleanup:
03612     if (cpl_error_get_code() != CPL_ERROR_NONE) 
03613     {
03614         *filename = NULL;
03615         uves_free_image(rflat);
03616         uves_free_propertylist(rflat_header);
03617     }
03618 
03619     return;
03620 }
03621 
03622 /*----------------------------------------------------------------------------*/
03638 /*----------------------------------------------------------------------------*/
03639 
03640 cpl_error_code
03641 uves_load_mflat_const(const cpl_frameset *frames, const char *chip_name,
03642               const char **mflat_filename, 
03643               cpl_image **mflat, uves_propertylist **mflat_header, 
03644               enum uves_chip chip,
03645               const cpl_frame **mflat_frame)
03646 {
03647     const char *tags[6];
03648     int number_of_tags = sizeof(tags) / sizeof(char *);
03649     int extension;
03650     int indx;
03651     
03652     *mflat        = NULL;
03653     *mflat_header = NULL;
03654 
03655     tags[0]   = UVES_REF_TFLAT            (chip);   /* Use REF TFLAT, rather than MASTER_TFLAT */
03656     tags[1]   = UVES_MASTER_FLAT          (chip);
03657     tags[2]   = UVES_MASTER_DFLAT         (chip);
03658     tags[3]   = UVES_MASTER_IFLAT         (chip);
03659     tags[4]   = UVES_MASTER_TFLAT         (chip);
03660     tags[5]   = UVES_MASTER_SCREEN_FLAT   (chip);
03661     extension = UVES_MASTER_FLAT_EXTENSION(chip);
03662     
03663     check( *mflat_filename = uves_find_frame(frames, tags, number_of_tags, &indx,
03664                          mflat_frame), 
03665        "Could not find '%s', '%s', '%s', '%s' or '%s' in frame set", 
03666        tags[0], tags[1], tags[2], tags[3], tags[4]);
03667     
03668     /* Load the mflat image */
03669     check( *mflat = cpl_image_load(*mflat_filename,
03670                    CPL_TYPE_DOUBLE,           /* Convert to this type */
03671                    0,                         /* plane number */
03672                    extension                  /* Extension number */
03673            ),
03674        "Could not load master flat from extension %d of file '%s'", 
03675        extension, *mflat_filename);
03676 
03677     /* Load the header */
03678     check( *mflat_header = uves_propertylist_load(*mflat_filename,
03679                          extension),
03680        "Could not load header from extension %d of file '%s'", 
03681        extension, *mflat_filename);
03682 
03683     check_nomsg( uves_warn_if_chip_names_dont_match(*mflat_header, chip_name, chip) );
03684 
03685   cleanup:
03686     if (cpl_error_get_code() != CPL_ERROR_NONE) 
03687     {
03688         *mflat_filename = NULL;
03689         uves_free_image(mflat);
03690         uves_free_propertylist(mflat_header);
03691     }
03692     return cpl_error_get_code();
03693 }
03694 
03695 /*----------------------------------------------------------------------------*/
03710 /*----------------------------------------------------------------------------*/
03711 cpl_error_code
03712 uves_load_mflat(cpl_frameset *frames, const char *chip_name,
03713         const char **mflat_filename, 
03714         cpl_image **mflat, uves_propertylist **mflat_header, enum uves_chip chip,
03715         cpl_frame **mflat_frame)
03716 {
03717     return uves_load_mflat_const((const cpl_frameset *)frames,
03718                  chip_name,
03719                  mflat_filename,
03720                  mflat, mflat_header, chip,
03721                  (const cpl_frame **) mflat_frame);
03722 }
03723 
03724 /*----------------------------------------------------------------------------*/
03756 /*----------------------------------------------------------------------------*/
03757 cpl_error_code
03758 uves_load_ordertable(const cpl_frameset *frames, 
03759              bool flames,
03760              const char *chip_name,
03761              const char **ordertable_filename, 
03762              cpl_table **ordertable, 
03763                      uves_propertylist **ordertable_header, 
03764                      uves_propertylist **ordertable_xheader, 
03765              polynomial **order_locations, 
03766                      cpl_table **traces, 
03767              int *tab_in_out_oshift,
03768              double *tab_in_out_yshift,
03769                      int ** fib_msk,
03770                      double ** fib_pos,
03771              enum uves_chip chip,
03772              bool guess_table)
03773 {
03774     uves_propertylist *midas_header = NULL;      /* Table header if midas format */
03775     const char *tags[1];
03776     int number_of_tags = sizeof(tags) / sizeof(char *);
03777     bool format_is_midas;
03778     int *tioo = NULL;
03779     double *tioy = NULL;
03780     int indx;
03781 
03782     double *fibre_pos = NULL;
03783     int *fibre_mask = NULL;
03784 
03785     if (guess_table)
03786     {
03787         tags[0] = UVES_GUESS_ORDER_TABLE(flames, chip);
03788     }
03789     else
03790     {
03791         tags[0] = UVES_ORDER_TABLE(flames, chip);
03792     }
03793 
03794     check( *ordertable_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL), 
03795        "No order table (%s) found in SOF", tags[0]);
03796     
03797     check( *ordertable = cpl_table_load(*ordertable_filename,
03798                     UVES_ORDER_TABLE_EXTENSION,
03799                     1),                /* Mark identified 
03800                                   invalid values? (1=yes) */
03801        "Error loading order table from extension %d of file '%s'", 
03802        UVES_ORDER_TABLE_EXTENSION, *ordertable_filename);
03803     
03804     assure(ordertable_header != NULL,CPL_ERROR_NULL_INPUT,
03805            "NULL primary header uves_propertylist variable header");
03806     check( *ordertable_header = uves_propertylist_load(*ordertable_filename, 0),
03807        "Could not load header from extension 0 of '%s'", *ordertable_filename);
03808 
03809     if(ordertable_xheader != NULL) {
03810 
03811     check( *ordertable_xheader = uves_propertylist_load(*ordertable_filename, 1),
03812        "Could not load header from extension 1 of '%s'", *ordertable_filename);
03813 
03814 
03815 
03816     }
03817     check_nomsg( uves_warn_if_chip_names_dont_match(*ordertable_header, chip_name, chip) );
03818     
03819 
03820     /* Determine format of order table and read the polynomial */
03821     if (uves_propertylist_contains(*ordertable_header, UVES_DRS_ID))
03822     {
03823 
03824 
03825         const char *drs_id;
03826 
03827         check( drs_id = uves_pfits_get_drs_id(*ordertable_header), "Error reading DRS ID");
03828         if      (strstr(drs_id, "CPL") != NULL || strstr(drs_id, "cpl") != NULL)
03829         {
03830             format_is_midas = false;
03831             uves_msg_debug("Order table was written by CPL");
03832         }
03833         else if (strstr(drs_id, "MIDAS") != NULL || strstr(drs_id, "midas") != NULL)
03834         {
03835             format_is_midas = true;
03836             uves_msg_low("Order table was written by MIDAS");
03837         }
03838         else
03839         {
03840             assure ( false, CPL_ERROR_ILLEGAL_INPUT, 
03841                  "Unrecognized order table format, DRS_ID = '%s'", drs_id);
03842         }
03843     }
03844     else
03845     {
03846 
03847         format_is_midas = true;
03848         uves_msg_debug("No '%s' keyword found. Assuming MIDAS format", UVES_DRS_ID);
03849     }
03850 
03851 
03852     if (!format_is_midas)
03853     {
03854             /* The format check and order position recipes create order tables
03855                with different column names. Rename if necessary. 
03856 
03857                This is a workaround for the problem that different recipes
03858                create the same products (order tables and line tables).
03859                The true solution would be to remove the format check recipe from
03860                the recution cascade, and use the theoretical physical model to
03861                bootstrap the order definition and wavelength calibration.
03862             */
03863             if (cpl_table_has_column(*ordertable, "ORDER"))
03864                 {
03865                     cpl_table_name_column(*ordertable, "ORDER", "Order");
03866                 }
03867             if (cpl_table_has_column(*ordertable, "YFIT"))
03868                 {
03869                     cpl_table_name_column(*ordertable, "YFIT", "Yfit");
03870                 }
03871 
03872         assure( !flames, CPL_ERROR_UNSUPPORTED_MODE, "Implement me");
03873 
03874         if (order_locations != NULL)
03875         {
03876             check( *order_locations = 
03877                load_polynomial(*ordertable_filename, UVES_ORDER_TABLE_EXTENSION_POLY),
03878                "Could not read polynomial from extension %d of file '%s'",
03879                UVES_ORDER_TABLE_EXTENSION_POLY, *ordertable_filename);
03880         }
03881 
03882         if (flames && tab_in_out_oshift != NULL)
03883         {
03884             assure( false, CPL_ERROR_UNSUPPORTED_MODE,
03885                 "Implement me");
03886         }
03887 
03888         if (flames && tab_in_out_yshift != NULL)
03889         {
03890             assure( false, CPL_ERROR_UNSUPPORTED_MODE,
03891                 "Implement me");
03892         }
03893 
03894         if (traces != NULL)
03895         {
03896             check( *traces = cpl_table_load(*ordertable_filename,
03897                             UVES_ORDER_TABLE_EXTENSION_FIBRE,
03898                             1),    /* Mark identified 
03899                                   invalid values? (1=yes) */
03900                "Error loading fibre table from extension %d of file '%s'", 
03901                UVES_ORDER_TABLE_EXTENSION_FIBRE, *ordertable_filename);
03902         }
03903     }
03904     else
03905         /* MIDAS format */
03906     {
03907         /* Rename */
03908         check(( cpl_table_cast_column (*ordertable, "ORDER", "Order", CPL_TYPE_INT),
03909             cpl_table_erase_column(*ordertable, "ORDER")),
03910           "Error casting and renaming column 'ORDER'");
03911 
03912         check( cpl_table_name_column(*ordertable, "YFIT", "Yfit"),
03913            "Error renaming column 'YFIT'");
03914 
03915         check( midas_header = uves_propertylist_load(*ordertable_filename, 1),
03916            "Could not load header from extension 1 of '%s'", 
03917            *ordertable_filename);
03918 
03919         /* Load polynomial named 'COEFF' from descriptors in extension 1 */
03920         if (order_locations != NULL)
03921         {
03922             check( *order_locations = 
03923                uves_polynomial_convert_from_plist_midas(midas_header, "COEFF"),
03924                "Error reading polynomial");
03925         }
03926 
03927 
03928         if (flames && tab_in_out_oshift != NULL )
03929         {
03930             /* Get tab_in_out_oshift */
03931             int tioo_length;
03932                     cpl_type tioo_type;
03933 
03934             check( tioo = uves_read_midas_array(
03935                    midas_header, "TAB_IN_OUT_OSHIFT", &tioo_length,
03936                                &tioo_type, NULL),
03937                "Error reading TAB_IN_OUT_OSHIFT from MIDAS header");
03938 
03939                     assure( tioo_type == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
03940                             "Type of TAB_IN_OUT_OSHIFT is %s, double expected",
03941                             uves_tostring_cpl_type(tioo_type));
03942 
03943             if (tioo_length != 1)
03944             {
03945                 uves_msg_warning("Length of TAB_IN_OUT_OSHIFT array is %d; "
03946                          "%d expected", tioo_length, 1);
03947             }
03948 
03949             *tab_in_out_oshift = tioo[0];
03950             
03951             uves_msg_debug("TAB_IN_OUT_OSHIFT = %d", *tab_in_out_oshift);
03952 
03953         }
03954         
03955         if (flames && tab_in_out_yshift != NULL)
03956         {
03957             /* Get tab_in_out_yshift */
03958             int tioy_length;
03959                     cpl_type tioy_type;
03960 
03961             check( tioy = uves_read_midas_array(
03962                    midas_header, "TAB_IN_OUT_YSHIFT", &tioy_length,
03963                                &tioy_type, NULL),
03964                "Error reading TAB_IN_OUT_YSHIFT from MIDAS header");
03965 
03966                     assure( tioy_type == CPL_TYPE_DOUBLE, CPL_ERROR_TYPE_MISMATCH,
03967                             "Type of TAB_IN_OUT_YSHIFT is %s, double expected",
03968                             uves_tostring_cpl_type(tioy_type));
03969 
03970             if (tioy_length != 1)
03971             {
03972                 uves_msg_warning("Length of TAB_IN_OUT_YSHIFT array is %d; "
03973                          "%d expected", tioy_length, 1);
03974             }
03975 
03976             *tab_in_out_yshift = tioy[0];
03977 
03978             uves_msg_debug("TAB_IN_OUT_YSHIFT = %f", *tab_in_out_yshift);
03979         }
03980         
03981         if (traces != NULL)
03982         {
03983             *traces = uves_ordertable_traces_new();
03984             
03985             if (!flames)
03986             /* UVES: one trace with zero offset */
03987             {
03988                 int fibre_ID = 0;
03989                 double fibre_offset = 0.0;
03990                 int fibre_msk = 1;
03991                 uves_ordertable_traces_add(*traces, 
03992                                fibre_ID,
03993                                fibre_offset,
03994                                fibre_msk);
03995             }
03996             else
03997             /* FLAMES */
03998             {
03999 
04000                 int fibre_pos_length;
04001                 int fibre_mask_length;
04002                             cpl_type fibre_pos_type;
04003                             cpl_type fibre_mask_type;
04004                 int fibre_ID;
04005 
04006                 check( fibre_pos = uves_read_midas_array(
04007                        midas_header, "FIBREPOS", &fibre_pos_length,
04008                                        &fibre_pos_type, NULL),
04009                    "Error reading FIBREPOS from MIDAS header");
04010 
04011                             assure( fibre_pos_type == CPL_TYPE_DOUBLE, CPL_ERROR_TYPE_MISMATCH,
04012                                     "Type of FIBREPOS is %s, double expected",
04013                                     uves_tostring_cpl_type(fibre_pos_type));
04014 
04015                 check( fibre_mask = uves_read_midas_array(
04016                        midas_header, "FIBREMASK", &fibre_mask_length,
04017                                        &fibre_mask_type, NULL),
04018                    "Error reading FIBREMASK from MIDAS header");
04019 
04020                             assure( fibre_mask_type == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
04021                                     "Type of FIBREMASK is %s, double expected",
04022                                     uves_tostring_cpl_type(fibre_mask_type));
04023                             
04024                 assure( fibre_pos_length == fibre_mask_length,
04025                     CPL_ERROR_INCOMPATIBLE_INPUT,
04026                     "FIBREMASK has length %d, but "
04027                     "FIBREPOS has length %d",
04028                     fibre_mask_length, fibre_pos_length );
04029             
04030                 *fib_pos= cpl_malloc(sizeof(double) * fibre_pos_length);
04031                 *fib_msk= cpl_malloc(sizeof(int) * fibre_mask_length);
04032 
04033                 for (fibre_ID = 0; fibre_ID < fibre_mask_length; fibre_ID++)
04034                 {
04035                     uves_msg_debug("Found trace %d, position %f (%s)",
04036                            fibre_ID, fibre_pos[fibre_ID],
04037                            fibre_mask[fibre_ID] ? 
04038                            "enabled" : "disabled");
04039                     uves_ordertable_traces_add(*traces, 
04040                                    fibre_ID,
04041                                    fibre_pos[fibre_ID],
04042                                    fibre_mask[fibre_ID]);
04043                     (*fib_pos)[fibre_ID]=fibre_pos[fibre_ID];
04044                     (*fib_msk)[fibre_ID]=fibre_mask[fibre_ID];
04045                 }
04046             }
04047         }
04048     }
04049 
04050   cleanup:
04051     uves_free_propertylist(&midas_header);
04052     uves_free_double(&fibre_pos);
04053     uves_free_int(&fibre_mask);
04054     uves_free_int(&tioo);
04055     uves_free_double(&tioy);
04056     if (cpl_error_get_code() != CPL_ERROR_NONE) 
04057     {
04058         *ordertable_filename = NULL;
04059         uves_free_table       (ordertable);
04060         uves_free_propertylist(ordertable_header);
04061         if (order_locations != NULL) uves_polynomial_delete(order_locations);
04062         if (traces != NULL)          uves_free_table       (traces);
04063     }
04064     return cpl_error_get_code();
04065 }
04066 
04067 
04068 /*----------------------------------------------------------------------------*/
04078 /*----------------------------------------------------------------------------*/
04079 
04080 static cpl_error_code
04081 create_column_pixelsize(cpl_table *linetable)
04082 {
04083     polynomial *p = NULL;
04084     cpl_table *t = NULL;
04085     double d1, d2;
04086     int i;
04087     int degree = 3;
04088     
04089     /* Remove rows with Ident = 0 (unidentified lines) */
04090     check( t = uves_extract_table_rows(linetable, "Ident", CPL_GREATER_THAN, 0.1),
04091        "Error deleting rows with Ident=0");
04092     
04093     /* Create column Aux := Ident * Order  */
04094     check(( cpl_table_duplicate_column(t, "Aux", t, "Ident"),
04095         cpl_table_multiply_columns(t, "Aux", "Order")),
04096       "Error creating 'Aux' column");
04097     
04098     check( p = uves_polynomial_regression_1d(t, 
04099                          "X", "Aux", NULL,
04100                          degree,
04101                          NULL, NULL,
04102                          NULL,
04103                          -1),
04104        "Regression failed");
04105     
04106     check( d1 = uves_polynomial_get_coeff_1d(p, 1),
04107        "Error reading polynomial coefficient");
04108     
04109     check( d2 = uves_polynomial_get_coeff_1d(p, 2),
04110        "Error reading polynomial coefficient");
04111     
04112     cpl_table_new_column(linetable, LINETAB_PIXELSIZE, CPL_TYPE_DOUBLE);
04113     
04114     for (i = 0; i < cpl_table_get_nrow(linetable); i++)
04115     {
04116         int x;
04117         int order;
04118         double pixelsize;
04119         double ident;
04120         
04121         check(( x     = cpl_table_get_double(linetable, "X", i, NULL),
04122             order = cpl_table_get_int   (linetable, "Order", i, NULL),
04123             ident = cpl_table_get_double(linetable, "Ident", i, NULL)),
04124           "Error reading line table");
04125         
04126         assure( order != 0, CPL_ERROR_ILLEGAL_INPUT, "Illegal order number: %d", order);
04127         
04128         /* 
04129          * MIDAS approximates
04130          * d(lambda m)/dx (x,m)   =  d1 + 2*d2*x
04131          *
04132          * where the polynomial itself is ... + d1*x + d2*x^2 + ...
04133          */
04134         pixelsize = (d1 + 2*d2* x) / order;
04135 //        pixelsize = uves_polynomial_derivative_2d(dispersion_relation, x, order, 1)/order;
04136         
04137         if (ident > 0.01)
04138         {
04139             cpl_table_set_double(linetable, LINETAB_PIXELSIZE, i, pixelsize);
04140         }
04141         else
04142         {
04143             cpl_table_set_invalid(linetable, LINETAB_PIXELSIZE, i);
04144         }
04145     }
04146     
04147   cleanup:
04148     uves_free_table(&t);
04149     uves_polynomial_delete(&p);
04150     return cpl_error_get_code();
04151 }
04152 
04153 
04154 
04155 /*----------------------------------------------------------------------------*/
04182 /*----------------------------------------------------------------------------*/
04183 static void
04184 align_order_line_table(cpl_table *linetable, const polynomial *absolute_order,
04185                uves_propertylist **linetable_header,
04186                const polynomial *order_locations, int minorder, int maxorder)
04187 {
04188     polynomial *absord = NULL;
04189 
04190     assure( cpl_table_has_column(linetable, "X"   ), CPL_ERROR_DATA_NOT_FOUND, 
04191         "Missing line table column 'X'");
04192     assure( cpl_table_has_column(linetable, "Ynew"), CPL_ERROR_DATA_NOT_FOUND, 
04193         "Missing line table column 'Ynew'");
04194     assure( cpl_table_has_column(linetable, "Order"), CPL_ERROR_DATA_NOT_FOUND, 
04195         "Missing line table column 'Order'");
04196     
04197     assure( cpl_table_get_column_type(linetable, "X") == CPL_TYPE_DOUBLE,
04198         CPL_ERROR_TYPE_MISMATCH, "Line table column 'X' has type %s (double expected))",
04199         uves_tostring_cpl_type(cpl_table_get_column_type(linetable, "X")) );
04200     
04201     assure( cpl_table_get_column_type(linetable, "Ynew") == CPL_TYPE_DOUBLE,
04202         CPL_ERROR_TYPE_MISMATCH, "Line table column 'Ynew' has type %s (double expected))",
04203         uves_tostring_cpl_type(cpl_table_get_column_type(linetable, "Ynew")) );
04204     
04205     assure( cpl_table_get_column_type(linetable, "Y") == CPL_TYPE_INT,
04206         CPL_ERROR_TYPE_MISMATCH, "Line table column 'Y' has type %s (integer expected))",
04207         uves_tostring_cpl_type(cpl_table_get_column_type(linetable, "Y")) );
04208 
04209     if (linetable_header != NULL)
04210     /* then correct first/abs order keywords */
04211     {
04212         int line_first, line_last;
04213         int ord_first, ord_last;
04214             {
04215                 int maxx;
04216                 int minx;
04217                 int x, y, order, absorder;  /* At chip center */
04218                 int coeff;
04219                 
04220                 maxx = uves_round_double(cpl_table_get_column_max(linetable, "X"));
04221                 minx = uves_round_double(cpl_table_get_column_min(linetable, "X"));
04222                 
04223                 assure( 1 <= minx && minx <= maxx, CPL_ERROR_ILLEGAL_INPUT,
04224                         "Illegal min/max line x positions: %d/%d, must be > 1", 
04225                         minx, maxx);
04226         
04227                 /* Center of chip */
04228                 x = (minx + maxx) / 2;
04229                 order = (minorder + maxorder) / 2;
04230                 y = uves_polynomial_evaluate_2d(order_locations, x, order);
04231 
04232                 if (uves_polynomial_derivative_2d(absolute_order, x, y, 2) > 0) {
04233                     coeff = +1;
04234                 }
04235                 else {
04236                     coeff = -1;
04237                 } 
04238 
04239                 absorder = uves_round_double(uves_polynomial_evaluate_2d(absolute_order, x, y));
04240                 uves_msg_debug("Absolute order polynomial at (%d, %d) = %f, "
04241                                "rounding to %d", x, y, 
04242                                uves_polynomial_evaluate_2d(absolute_order, x, y), absorder);
04243 
04244                 ord_first = absorder + (minorder - order) * coeff;
04245                 ord_last  = absorder + (maxorder - order) * coeff;
04246             }
04247 
04248             check( line_first =
04249            uves_pfits_get_firstabsorder(*linetable_header),
04250            "Could not read order number from line table header");
04251         
04252         check( line_last  =
04253            uves_pfits_get_lastabsorder (*linetable_header),
04254            "Could not read order number from line table header");
04255         
04256         uves_msg_debug("Order table range: %d - %d. Line table range: %d - %d",
04257                ord_first, ord_last, line_first, line_last);
04258         
04259         if (line_first != ord_first ||
04260         line_last  != ord_last)
04261         {
04262             uves_msg_warning("Provided line and order tables are incompatible. "
04263                      "Line table contains orders %d - %d. "
04264                      "Order table contains orders %d - %d. "
04265                      "Correcting on the fly",
04266                      line_first, line_last, ord_first, ord_last);
04267             
04268             check( uves_pfits_set_firstabsorder(*linetable_header,
04269                             ord_first),
04270                "Could not write corrected first absolute order number");
04271             check( uves_pfits_set_lastabsorder(*linetable_header,
04272                                ord_last),
04273                "Could not write corrected first absolute order number");
04274 
04275             uves_msg_debug("Setting line table order range = %d - %d",
04276                    ord_first, ord_last);
04277         }
04278     }
04279     /* This 'Y' column is the relative order number in linetables
04280        but the absolute order number (and therefore equal to
04281        the 'order' column) in line guess tables (!!) 
04282     */
04283 
04284     {
04285     double epsilon = 0.01; /* Must be larger than machine precision but
04286                   less than the typical difference between
04287                   absolute/relative numbering (~100) 
04288                    */
04289 
04290     if (fabs(cpl_table_get_column_median(linetable, "Y") - 
04291          cpl_table_get_column_median(linetable, "Order")) > epsilon)
04292 
04293         /* If column 'Y' is different from 'Order', 
04294            then 'Y' is the relative order number and
04295            should be corrected (if there is an inconsistency).
04296 
04297            For now, simply delete the 'Y' column because it is
04298            not used later. If the 'Y' column will be used later,
04299            it must be corrected at this place.
04300         */
04301         {
04302         uves_msg_debug("Removing line table column 'Y'");
04303         cpl_table_erase_column(linetable, "Y");
04304         }
04305     }
04306     
04307   cleanup:
04308     uves_polynomial_delete(&absord);
04309 }
04310 
04311 
04312 /*----------------------------------------------------------------------------*/
04351 /*----------------------------------------------------------------------------*/
04352 void
04353 uves_load_linetable(const cpl_frameset *frames, 
04354                     bool flames,
04355                     const char *chip_name,
04356                     const polynomial *order_locations, int minorder, int maxorder,
04357                     const char **linetable_filename,
04358                     cpl_table **linetable,
04359                     uves_propertylist **linetable_header,
04360                     polynomial **dispersion_relation,
04361                     polynomial **absolute_order,
04362                     enum uves_chip chip, int trace_id, int window)
04363 {
04364     uves_propertylist *primary_header = NULL;
04365     uves_propertylist *header         = NULL;
04366     uves_propertylist *midas_header   = NULL;       /* MIDAS extension header */
04367     int *absorders                   = NULL;       /* Absolute order numbers */
04368     cpl_table *temp                  = NULL;
04369     polynomial *absolute_order_local = NULL;
04370     const char *tags[3];
04371     int number_of_tags = sizeof(tags) / sizeof(char *);
04372     const char *drs_id;
04373     bool format_is_midas;               /* Was file written by CPL or MIDAS? */
04374     int base_extension;                 /* Last extension (e.g. 0) before 
04375                        extension with line table */
04376     int indx;
04377 
04378     if (flames)
04379     {
04380         tags[0] = UVES_GUESS_LINE_TABLE(flames, chip);
04381         number_of_tags = 1;
04382         
04383         check( *linetable_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
04384            "No line table (%s) found in SOF", tags[0]);
04385     }
04386     else
04387     {
04388         tags[0] = UVES_LINE_TABLE(flames, chip);
04389         tags[1] = UVES_LINE_TABLE(flames, chip);
04390         tags[2] = UVES_GUESS_LINE_TABLE(flames, chip);
04391         
04392         /* For backwards compatibility with MIDAS, 
04393            also look for LINE_TABLE_chip%d */
04394         if (irplib_frameset_find_const(frames, tags[0]) == NULL &&
04395         irplib_frameset_find_const(frames, tags[1]) == NULL &&
04396         irplib_frameset_find_const(frames, tags[2]) == NULL)
04397         {
04398             uves_msg_debug("No %s", tags[0]);
04399             
04400             if (window >= 1)
04401             {
04402                 /* Look for LINE_TABLE_BLUEwindow */
04403                 
04404                 tags[0] = UVES_LINE_TABLE_MIDAS(chip, window);
04405                 tags[1] = UVES_LINE_TABLE_MIDAS(chip, window);
04406                 tags[2] = UVES_LINE_TABLE_MIDAS(chip, window);
04407                 
04408                 uves_msg_debug("Trying %s", tags[0]);
04409             }
04410             if (window <= 0)
04411             {
04412                 /* Look for any LINE_TABLE_BLUEi */
04413                 tags[0] = UVES_LINE_TABLE_MIDAS(chip, 1);
04414                 tags[1] = UVES_LINE_TABLE_MIDAS(chip, 2);
04415                 tags[2] = UVES_LINE_TABLE_MIDAS(chip, 3);
04416                 
04417                 uves_msg_debug("Trying %s, %s or %s", tags[0], tags[1], tags[2]);
04418             }
04419         }
04420         
04421         check( *linetable_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
04422            "No line table (%s, %s or %s) found in SOF", tags[0], tags[1], tags[2]);
04423     }
04424     
04425     /* Read primary header */
04426     check( primary_header = uves_propertylist_load(*linetable_filename, 0),
04427        "Could not load primary header of '%s'", *linetable_filename);  
04428 
04429     check_nomsg( uves_warn_if_chip_names_dont_match(primary_header, chip_name, chip) );
04430     
04431     /* Determine format of line table */
04432     if (uves_propertylist_contains(primary_header, UVES_DRS_ID))
04433     {
04434         check( drs_id = uves_pfits_get_drs_id(primary_header), "Error reading DRS ID");
04435         if (strstr(drs_id, "CPL") != NULL || strstr(drs_id, "cpl") != NULL)
04436         {
04437             format_is_midas = false;
04438             uves_msg_debug("Line table was written by CPL");
04439         }
04440         else if (strstr(drs_id, "MIDAS") != NULL || strstr(drs_id, "midas") != NULL)
04441         {
04442             format_is_midas = true;
04443             uves_msg_debug("Line table was written by MIDAS");
04444         }
04445         else
04446         {
04447             assure ( false,
04448                  CPL_ERROR_ILLEGAL_INPUT,
04449                  "Unrecognized line table format, DRS_ID = '%s'", drs_id);
04450         }
04451     }
04452     else
04453     {
04454         format_is_midas = true;
04455         uves_msg_debug("No '%s' keyword found. Assuming MIDAS format", UVES_DRS_ID);
04456     }
04457 
04458     if (format_is_midas)
04459     {
04460         if (!flames)
04461         {
04462             assure( trace_id == 0 && (window == -1 || (1 <= window && window <= 3)), 
04463                 CPL_ERROR_UNSUPPORTED_MODE,
04464                 "Cannot read (fibre, window) = (%d, %d) from MIDAS line table", 
04465                 trace_id, window);
04466             
04467             base_extension = 0;
04468         }
04469         else
04470         {
04471             uves_msg_warning("Assuming line table is guess table");
04472             base_extension = 0;
04473         }
04474     }
04475     else
04476     /* Find table extension containing the line table for the specified trace and window */
04477     {
04478         int nextensions;
04479         bool found;
04480         
04481         check( nextensions = uves_get_nextensions(*linetable_filename),
04482            "Error reading number of extensions of file '%s'", *linetable_filename);
04483         header = NULL;
04484         found = false;
04485 
04486             uves_msg_debug("Number of extensions = %d", nextensions);
04487 
04488         for (base_extension = 1; base_extension < nextensions && !found; base_extension++)
04489         {
04490             int header_trace;
04491             int header_window;
04492             
04493             /* Read header trace & window info */
04494             check(( uves_free_propertylist(&header),
04495                header = uves_propertylist_load(*linetable_filename, base_extension)),
04496                "Could not header of extension %d of '%s'", 
04497               base_extension, *linetable_filename);
04498             
04499             check( header_trace  = uves_pfits_get_traceid     (header),
04500                "Error reading trace ID from header of extension %d of '%s'",
04501                base_extension, *linetable_filename);
04502             
04503             check( header_window = uves_pfits_get_windownumber(header),
04504                "Error reading window number from header of extension %d of '%s'",
04505                base_extension, *linetable_filename);
04506             
04507                     uves_msg_debug("Found (trace, window) = (%d, %d), need (%d, %d)",
04508                                    header_trace, header_window,
04509                                    trace_id, window);
04510 
04511             found = ( (trace_id == header_trace) && 
04512                   (window == -1 || window == header_window) );
04513         }
04514         
04515         assure( found,
04516             CPL_ERROR_ILLEGAL_INPUT,
04517             "Line table (trace, window) = (%d, %d) is not present in file '%s'",
04518             trace_id, window, *linetable_filename);
04519 
04520         /* Let 'base_extension' be the first extension before 
04521            the proper extension was found (0, 3, 6, ...) */
04522         base_extension -= 2;
04523         /* ...and incremented in for-loop */
04524     }
04525 
04526     check( *linetable = cpl_table_load(*linetable_filename,
04527                        base_extension + UVES_LINE_TABLE_EXTENSION,
04528                        1),              /* Mark identified 
04529                                invalid values? (1=yes) */
04530        "Error loading line table from extension %d of file '%s'", 
04531        base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
04532 
04533     /* Read header of table extension if requested */
04534     if (linetable_header != NULL)
04535     {
04536         check( *linetable_header = 
04537            uves_propertylist_load(*linetable_filename, 
04538                      base_extension + UVES_LINE_TABLE_EXTENSION),
04539            "Could not load header of extension %d of '%s'", 
04540            base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
04541 
04542         if (format_is_midas)
04543         {
04544             int size = 0;
04545                     cpl_type type;
04546             absorders = uves_read_midas_array(*linetable_header, "ORDER", &size,
04547                                                       &type, NULL);
04548                     
04549                     assure( type == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
04550                             "Type of ORDER is %s, int expected",
04551                             uves_tostring_cpl_type(type));
04552 
04553             assure( size == 2, 
04554                 CPL_ERROR_ILLEGAL_INPUT,
04555                 "'ORDER' array has size %d. Size 2 expected.", size);
04556             check(( uves_pfits_set_firstabsorder(*linetable_header, absorders[0]),
04557                 uves_pfits_set_lastabsorder(*linetable_header, absorders[1])),
04558               "Error updating table header");
04559         }        
04560     }
04561     
04562     /* Read the polynomials if requested */
04563     if (format_is_midas)
04564     {
04565         /* Rename & cast order/ident/X columns */
04566         check(( cpl_table_cast_column(*linetable, "X", "xxxx", CPL_TYPE_DOUBLE),
04567             cpl_table_erase_column(*linetable, "X"),
04568             cpl_table_name_column(*linetable, "xxxx", "X")),
04569           "Error casting and renaming column 'X'");
04570         
04571         check(( cpl_table_cast_column(*linetable, "YNEW", "xxxx", CPL_TYPE_DOUBLE),
04572             cpl_table_erase_column(*linetable, "YNEW"),
04573             cpl_table_name_column(*linetable, "xxxx", "Ynew")),
04574           "Error casting and renaming column 'YNEW'");
04575         
04576         check(( cpl_table_cast_column(*linetable, "Y", "xxxx", CPL_TYPE_INT),
04577             cpl_table_erase_column(*linetable, "Y"),
04578             cpl_table_name_column(*linetable, "xxxx", "Y")),
04579            "Error casting and renaming column 'Y'");
04580 
04581         check(( cpl_table_cast_column(*linetable, "ORDER", "Order", CPL_TYPE_INT),
04582             cpl_table_erase_column(*linetable, "ORDER")),
04583            "Error casting and renaming column 'ORDER'");
04584            
04585         check( cpl_table_name_column(*linetable, "IDENT", "Ident"),
04586            "Error renaming column 'IDENT'");
04587 
04588         check( midas_header = uves_propertylist_load(
04589                *linetable_filename, 
04590                base_extension + UVES_LINE_TABLE_EXTENSION),
04591            "Could not load header of extension %d of '%s'",
04592            base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
04593         
04594         if (dispersion_relation != NULL)
04595         {
04596             check( *dispersion_relation = 
04597                uves_polynomial_convert_from_plist_midas(midas_header, "REGR"),
04598                "Error reading polynomial 'REGR' from '%s'", *linetable_filename);
04599         }
04600     
04601         check( absolute_order_local = 
04602            uves_polynomial_convert_from_plist_midas(midas_header, "RORD"),
04603            "Error reading polynomial 'RORD' from '%s'", *linetable_filename);
04604 
04605         /* For FLAMES data, it seems that the polynomial is half an order shifted
04606            (for unknown reasons) */
04607         if (flames)
04608         {
04609             check_nomsg( uves_polynomial_shift(absolute_order_local, 0, 0.5) );
04610         }
04611     }
04612     else
04613     /* CPL format */
04614     {
04615         /* physmod + wavecal recipes use different naming conventions,
04616            workaround for this:
04617         */
04618         if (cpl_table_has_column(*linetable, "YNEW"))
04619         {
04620             cpl_table_name_column(*linetable, "YNEW", "Ynew");
04621         }
04622 
04623         if (dispersion_relation != NULL)
04624         {
04625             check( *dispersion_relation = load_polynomial(
04626                    *linetable_filename,
04627                    base_extension + UVES_LINE_TABLE_EXTENSION_DISPERSION),
04628                "Could not read polynomial from extension %d of file '%s'", 
04629                base_extension + UVES_LINE_TABLE_EXTENSION_DISPERSION,
04630                *linetable_filename);
04631         }
04632 
04633         check( absolute_order_local =
04634            load_polynomial(*linetable_filename, 
04635                    base_extension + UVES_LINE_TABLE_EXTENSION_ABSORDER),
04636            "Could not read polynomial from extension %d of file '%s'",
04637            base_extension + UVES_LINE_TABLE_EXTENSION_ABSORDER, *linetable_filename);
04638     }
04639         
04640     if (absolute_order != NULL)
04641     {
04642         *absolute_order = uves_polynomial_duplicate(absolute_order_local);
04643     }
04644     
04645     check( align_order_line_table(
04646            *linetable, absolute_order_local, linetable_header, 
04647            order_locations, minorder, maxorder),
04648        "Error while aligning line/order tables");
04649 
04650     /* Remove all other columns than 'Ident', 'Order', 'X', 'Pixelsize' */
04651     {
04652     const char *colname;
04653 
04654     /* Loop through all columns */
04655 
04656     /* It is undefined behaviour (for a reason!) to loop through
04657        columns while deleting some of them. Therefore, copy the
04658        structure of the linetable to another (empty) table */
04659     
04660     uves_free_table(&temp);
04661     check(( temp = cpl_table_new(0),
04662         cpl_table_copy_structure(temp, *linetable)),
04663            "Error duplicating line table column structure");
04664     
04665     colname = cpl_table_get_column_name(temp);
04666     while (colname != NULL)
04667         {
04668         if (!(strcmp(colname, "X"        ) == 0 ||
04669               strcmp(colname, "Order"    ) == 0 ||
04670               strcmp(colname, "Ident"    ) == 0 ||
04671               strcmp(colname, LINETAB_PIXELSIZE) == 0))
04672             {
04673             cpl_table_erase_column(*linetable, colname);
04674             uves_msg_debug("Removing unused column '%s'", colname);
04675             }
04676         
04677         /* Call with NULL argument to get the next column name */
04678         colname = cpl_table_get_column_name(NULL);
04679         }
04680     }
04681     
04682     /* support MIDAS
04683      * Calculate 'Pixel' column (lower case) for MIDAS tables 
04684      */
04685     if ( !cpl_table_has_column(*linetable, LINETAB_PIXELSIZE) )
04686     {
04687         check( create_column_pixelsize(*linetable),
04688            "Error adding 'Pixelsize' column");
04689     }
04690 
04691     /* Remove un-identified lines (where Ident = invalid or Ident = zero) ... */
04692     check( uves_erase_invalid_table_rows(*linetable, "Ident"),
04693        "Error deleting rows with illegal 'Ident' value");
04694 
04695     check( uves_erase_table_rows(*linetable, "Ident", CPL_LESS_THAN, 0.01),
04696        "Error deleting rows with illegal 'Ident' value");
04697     
04698     /* Check for any other invalid value */
04699     assure( uves_erase_invalid_table_rows(*linetable, NULL) == 0, CPL_ERROR_ILLEGAL_INPUT,
04700         "After deleting rows with invalid 'Ident' values, "
04701         "the table in extension %d of file '%s' still contains invalid rows",
04702         base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
04703     
04704     /* Sort line table by 'Order' (ascending), then 'X' (ascending) */
04705     check( uves_sort_table_2(*linetable, "Order", "X", false, false), "Error sorting line table");
04706     
04707   cleanup:
04708     uves_free_propertylist(&primary_header);
04709     uves_free_propertylist(&header);
04710     uves_free_propertylist(&midas_header);
04711     uves_free_table(&temp);
04712     uves_polynomial_delete(&absolute_order_local);
04713     cpl_free(absorders);
04714     if (cpl_error_get_code() != CPL_ERROR_NONE) {
04715     *linetable_filename = NULL;
04716     uves_free_table(linetable);
04717     if (dispersion_relation != NULL) uves_polynomial_delete(dispersion_relation);
04718     if (absolute_order      != NULL) uves_polynomial_delete(absolute_order);
04719     }
04720     return;
04721 }
04722 
04723 /*----------------------------------------------------------------------------*/
04727 /*----------------------------------------------------------------------------*/
04728 void
04729 uves_load_linetable_const(const cpl_frameset *frames, 
04730                           bool flames,
04731                           const char *chip_name,
04732                           const polynomial *order_locations, int minorder, int maxorder,
04733                           const char **linetable_filename,
04734                           const cpl_table **linetable,
04735                           const uves_propertylist **linetable_header,
04736                           const polynomial **dispersion_relation,
04737                           polynomial **absolute_order,
04738                           enum uves_chip chip, int trace_id, int window)
04739 {
04740     uves_load_linetable(frames, flames, chip_name, order_locations, 
04741                         minorder, maxorder, 
04742                         linetable_filename, 
04743                         (cpl_table **)linetable, 
04744                         (uves_propertylist **)linetable_header,
04745                         (polynomial **)dispersion_relation, 
04746                         absolute_order,
04747                         chip, trace_id, window);
04748 }
04749 
04750 
04751 /*----------------------------------------------------------------------------*/
04766 /*----------------------------------------------------------------------------*/
04767 
04768 cpl_error_code
04769 uves_load_response_curve(const cpl_frameset *frames, const char *chip_name,
04770              const char **response_filename, 
04771              cpl_image **response_curve,
04772              cpl_table **master_response,
04773              uves_propertylist **response_header, enum uves_chip chip)
04774 {
04775     const char *tags[2];
04776     int number_of_tags = sizeof(tags) / sizeof(char *);
04777     int extension;
04778     int indx;
04779     
04780     *response_curve  = NULL;
04781     *response_header = NULL;
04782     *master_response = NULL;
04783     
04784     tags[0]   = UVES_INSTR_RESPONSE (chip);
04785     tags[1]   = UVES_MASTER_RESPONSE(chip);
04786     
04787     check( *response_filename = uves_find_frame(frames, tags, number_of_tags, &indx, 
04788                         NULL), 
04789        "Could not find '%s' in frame set", tags[0]);
04790     
04791     if (indx == 0)
04792     {
04793         extension = UVES_INSTR_RESPONSE_EXTENSION(chip);
04794         
04795         /* Load the response image
04796            
04797         Note: Even if the response curve was saved as
04798         a FITS file with NAXIS=1, cpl_image_load() will
04799         create an image of size nx1, which is just
04800         what we want
04801         */
04802         check( *response_curve = cpl_image_load(*response_filename,
04803                             CPL_TYPE_DOUBLE, /* Convert to this type */
04804                             0,               /* plane number */
04805                             extension        /* Extension number */
04806                ),
04807            "Could not load response curve from extension %d of file '%s'", 
04808            extension, *response_filename);
04809 
04810         /* Load the header */
04811         check( *response_header = uves_propertylist_load(*response_filename,
04812                                 extension),
04813            "Could not load header from extension %d of file '%s'", 
04814            extension, *response_filename);
04815 
04816         check_nomsg( uves_warn_if_chip_names_dont_match(*response_header, chip_name, chip) );
04817     }
04818     else
04819     /* Master response */
04820     {
04821         extension = UVES_MASTER_RESPONSE_EXTENSION(chip);
04822         
04823         check( *master_response = cpl_table_load(*response_filename,
04824                              UVES_LINE_INTMON_TABLE_EXTENSION,
04825                              1),   /* Mark identified 
04826                                   invalid values? (1=yes) */
04827            "Error master response curve from extension %d of file '%s'", 
04828            extension, *response_filename);           
04829 
04830         /* Convert columns to double */
04831         check(( cpl_table_cast_column(*master_response, "LAMBDA", "LAMBDA_double", 
04832                       CPL_TYPE_DOUBLE),
04833             cpl_table_erase_column(*master_response, "LAMBDA"),
04834             cpl_table_name_column(*master_response, "LAMBDA_double", "LAMBDA")),
04835           "Could not cast column 'LAMBDA'");
04836 
04837         check(( cpl_table_cast_column(*master_response, "FLUX_CONV", "FLUX_CONV_double", 
04838                       CPL_TYPE_DOUBLE),
04839             cpl_table_erase_column(*master_response, "FLUX_CONV"),
04840             cpl_table_name_column(*master_response, "FLUX_CONV_double", "FLUX_CONV")),
04841           "Could not cast column 'FLUX_CONV'");
04842 
04843         /* Do not need the header, which also does not contain 
04844            keywords needed for uves_warn_if_chip_names_dont_match() */
04845     }
04846     
04847   cleanup:
04848     if (cpl_error_get_code() != CPL_ERROR_NONE) 
04849     {
04850         *response_filename = NULL;
04851         uves_free_image(response_curve);
04852         uves_free_propertylist(response_header);
04853     }
04854     return cpl_error_get_code();
04855 }
04856 
04857 
04858 /*----------------------------------------------------------------------------*/
04868 /*----------------------------------------------------------------------------*/
04869 cpl_error_code uves_load_lineintmon(const cpl_frameset *frames, 
04870                     const char **line_intmon_filename, 
04871                     cpl_table **line_intmon)
04872 {
04873     const char *tags[1] = {UVES_LINE_INTMON_TABLE};    
04874 
04875     int number_of_tags = sizeof(tags) / sizeof(char *);
04876     int indx;
04877     
04878     /* Get filename */
04879     check( *line_intmon_filename = uves_find_frame(frames, tags, number_of_tags, 
04880                            &indx, NULL),
04881        "No line intensity table (%s) found in SOF", tags[0]);
04882     
04883     /* Load table */
04884     check( *line_intmon = cpl_table_load(*line_intmon_filename,
04885                      UVES_LINE_INTMON_TABLE_EXTENSION,
04886                      1),         /* Mark identified 
04887                             invalid values? (1=yes) */
04888        "Error loading line reference table from extension %d of file '%s'", 
04889        UVES_LINE_INTMON_TABLE_EXTENSION, *line_intmon_filename);
04890 
04891     check(( cpl_table_cast_column(*line_intmon, "WAVE", "Wave", CPL_TYPE_DOUBLE),
04892         cpl_table_erase_column(*line_intmon, "WAVE")),
04893       "Could not cast and rename column");
04894     
04895     /* Sort table by 'Wave' (ascending) */
04896     check(  uves_sort_table_1(*line_intmon, "Wave", false), "Error sorting table");
04897     
04898   cleanup:
04899     if (cpl_error_get_code() != CPL_ERROR_NONE) 
04900     {
04901         *line_intmon_filename = NULL;
04902         uves_free_table(line_intmon);
04903     }
04904     return cpl_error_get_code();
04905 }
04906 
04907 
04908 /*----------------------------------------------------------------------------*/
04921 /*----------------------------------------------------------------------------*/
04922 void
04923 uves_load_corvel(const cpl_frameset *frames,
04924          enum uves_chip chip,
04925          cpl_table **corvel,
04926          uves_propertylist **corvel_header,
04927          const char **corvel_filename)
04928 {
04929     const char *tags[1];
04930     int number_of_tags = sizeof(tags) / sizeof(char *);
04931     int indx;
04932     int extension;
04933 
04934     tags[0] = FLAMES_CORVEL(chip);
04935 
04936     assure_nomsg( corvel != NULL, CPL_ERROR_NULL_INPUT );
04937     assure_nomsg( corvel_filename != NULL, CPL_ERROR_NULL_INPUT );
04938 
04939     /* Get filename */
04940     check( *corvel_filename = uves_find_frame(frames, tags, number_of_tags, 
04941                           &indx, NULL),
04942        "No velocity correction table (%s) found in SOF", tags[0]);
04943     
04944     /* Load table */
04945     extension = 1;
04946     check( *corvel = cpl_table_load(*corvel_filename,
04947                     extension,
04948                     1),         /* Mark identified 
04949                            invalid values? (1=yes) */
04950        "Error loading line reference table from extension %d of file '%s'",
04951        extension, *corvel_filename);
04952 
04953     /* Load header */
04954     if (corvel_header != NULL)
04955     {
04956         extension = 0;
04957         check( *corvel_header = uves_propertylist_load(*corvel_filename,
04958                               extension),
04959            "Could not load header from extension %d of file %s",
04960            extension, *corvel_filename);
04961 
04962     }
04963     
04964   cleanup:
04965     if (cpl_error_get_code() != CPL_ERROR_NONE) 
04966     {
04967         *corvel_filename = NULL;
04968         uves_free_table(corvel);
04969     }
04970     return;
04971 }
04972 
04973 /*----------------------------------------------------------------------------*/
04989 /*----------------------------------------------------------------------------*/
04990 cpl_error_code
04991 uves_load_linerefertable(const cpl_frameset *frames, 
04992              const char **line_refer_filename, 
04993              cpl_table **line_refer, uves_propertylist **line_refer_header)
04994 {
04995     const char *tags[1] = {UVES_LINE_REFER_TABLE};    
04996 
04997     int number_of_tags = sizeof(tags) / sizeof(char *);
04998     int indx;
04999     
05000     /* Get filename */
05001     check( *line_refer_filename = uves_find_frame(frames, tags, number_of_tags, 
05002                           &indx, NULL),
05003        "No line reference table (%s) found in SOF", tags[0]);
05004     
05005     /* Load table */
05006     check( *line_refer = cpl_table_load(*line_refer_filename,
05007                        UVES_LINE_REFER_TABLE_EXTENSION,
05008                        1),         /* Mark identified 
05009                               invalid values? (1=yes) */
05010        "Error loading line reference table from extension %d of file '%s'", 
05011        UVES_LINE_REFER_TABLE_EXTENSION, *line_refer_filename);
05012 
05013     /* Load header if requested */
05014     if (line_refer_header != NULL)
05015     {
05016         check( *line_refer_header = uves_propertylist_load(*line_refer_filename, 0),
05017            "Could not load header of line_refer table in '%s'", *line_refer_filename);
05018     }
05019 
05020     assure( uves_erase_invalid_table_rows(*line_refer, NULL) == 0, CPL_ERROR_ILLEGAL_INPUT,
05021         "Table in extension %d of file '%s' contains invalid rows", 
05022         UVES_LINE_REFER_TABLE_EXTENSION, *line_refer_filename);
05023 
05024     check(( cpl_table_cast_column(*line_refer, "WAVE", "Wave", CPL_TYPE_DOUBLE),
05025         cpl_table_erase_column(*line_refer, "WAVE")),
05026        "Could not cast and rename column");
05027     
05028     /* Write uncertainties of wavelengths.
05029        The value 0.002 is finetuned/retro-fitted to get a chi_sq ~ 1 when
05030        using the new catalogue from
05031 
05032        M. T. Murphy, P. Tzanavaris, J. K. Webb, C. Lovis
05033        "Selection of ThAr lines for wavelength calibration of echelle
05034        spectra and implications for variations in the fine-structure constant",
05035        Submitted to MNRAS
05036     */
05037 
05038 #if 0
05039      check(( cpl_table_duplicate_column(*line_refer, "dWave", *line_refer, "Wave"),
05040            cpl_table_divide_scalar   (*line_refer, "dWave", 300000*10)),
05041        "Error writing wavelength uncertainties");
05042 #else
05043      /* we should do this */
05044     check(( cpl_table_new_column(*line_refer, "dWave", CPL_TYPE_DOUBLE),
05045             cpl_table_fill_column_window(*line_refer,
05046                                          "dWave",
05047                                          0,
05048                                          cpl_table_get_nrow(*line_refer), 0.002)),
05049           "Error writing wavelength uncertainties");
05050 #endif
05051     
05052     /* Sort table by 'Wave' (ascending) */
05053     check(  uves_sort_table_1(*line_refer, "Wave", false), "Error sorting table");
05054     
05055   cleanup:
05056     if (cpl_error_get_code() != CPL_ERROR_NONE) {
05057     *line_refer_filename = NULL;
05058     uves_free_table       (line_refer);
05059     if (line_refer_header != NULL) uves_free_propertylist(line_refer_header);
05060     }
05061     return cpl_error_get_code();
05062 }
05063 
05064 /*----------------------------------------------------------------------------*/
05078 /*----------------------------------------------------------------------------*/
05079 cpl_error_code
05080 uves_load_flux_table(const cpl_frameset *frames, const char **flux_table_filename, 
05081              cpl_table **flux_table)
05082 {
05083     const char *tags[1] = {UVES_FLUX_STD_TABLE};
05084 
05085     int number_of_tags = sizeof(tags) / sizeof(char *);
05086     int indx;
05087     
05088     /* Get filename */
05089     check( *flux_table_filename = uves_find_frame(frames, tags, number_of_tags, 
05090                           &indx, NULL), 
05091        "No standard star flux table (%s) in SOF", tags[0]);
05092 
05093     /* Load table */
05094     check( *flux_table = cpl_table_load(*flux_table_filename,
05095                     UVES_FLUX_STD_TABLE_EXTENSION,
05096                     1),         /* Mark identified 
05097                                invalid values? (1=yes) */
05098        "Error loading flux table from extension %d of file '%s'",
05099        UVES_FLUX_STD_TABLE_EXTENSION, *flux_table_filename);
05100 
05101     if (false)
05102         /* Don't do this, it will remove one std (LTT2415) from the table which has TYPE = NULL.
05103            Instead, set type to "NULL" (this is only used for messages) 
05104         */
05105         {
05106             if (uves_erase_invalid_table_rows(*flux_table, NULL) != 0)
05107                 {
05108                     uves_msg_warning("Table in extension %d of file '%s' contains null values",
05109                                      UVES_FLUX_STD_TABLE_EXTENSION, *flux_table_filename);
05110                 }
05111         }
05112     else
05113         {
05114             int i;
05115             for (i = 0; i < cpl_table_get_nrow(*flux_table); i++)
05116                 {
05117                     if (cpl_table_get_string(*flux_table, "TYPE", i) == NULL)
05118                         {
05119                             cpl_table_set_string(*flux_table, "TYPE", i, "NULL");
05120                         }
05121                 }
05122         }
05123     
05124         
05125   cleanup:
05126     if (cpl_error_get_code() != CPL_ERROR_NONE) 
05127     {
05128         *flux_table_filename = NULL;
05129         uves_free_table(flux_table);
05130     }
05131     return cpl_error_get_code();
05132 }
05133 
05134 
05135 /*----------------------------------------------------------------------------*/
05149 /*----------------------------------------------------------------------------*/
05150 cpl_error_code
05151 uves_load_atmo_ext(const cpl_frameset *frames, const char **atmext_table_filename, 
05152            cpl_table **atmext_table)
05153 {
05154     const char *tags[1] = {UVES_EXTCOEFF_TABLE};
05155     
05156     int number_of_tags = sizeof(tags) / sizeof(char *);
05157     int indx;
05158     
05159     /* Get filename */
05160     check( *atmext_table_filename = uves_find_frame(frames, tags, number_of_tags, 
05161                             &indx, NULL), 
05162        "No atmospheric extinction table (%s) found in SOF", tags[0]);
05163 
05164     /* Load table */
05165     check( *atmext_table = cpl_table_load(*atmext_table_filename,
05166                       UVES_EXTCOEFF_TABLE_EXTENSION,
05167                       1),          /* Mark identified 
05168                               invalid values? (1=yes) */
05169        "Error loading atmospheric extinction table from extension %d of file '%s'",
05170        UVES_EXTCOEFF_TABLE_EXTENSION, *atmext_table_filename);
05171     
05172     assure( uves_erase_invalid_table_rows(*atmext_table, NULL) == 0, CPL_ERROR_ILLEGAL_INPUT,
05173         "Table in extension %d of file '%s' contains invalid rows",
05174         UVES_EXTCOEFF_TABLE_EXTENSION, *atmext_table_filename);
05175     
05176     check( uves_sort_table_1(*atmext_table, "LAMBDA", false),
05177        "Error sorting table");
05178     
05179     /* Convert columns to double */
05180     check(( cpl_table_cast_column(*atmext_table, "LAMBDA", "LAMBDA_double", CPL_TYPE_DOUBLE),
05181         cpl_table_erase_column(*atmext_table, "LAMBDA"),
05182         cpl_table_name_column(*atmext_table, "LAMBDA_double", "LAMBDA")),
05183       "Could not cast column 'LAMBDA'");
05184     
05185     check(( cpl_table_cast_column(*atmext_table, "LA_SILLA", "LA_SILLA_double", CPL_TYPE_DOUBLE),
05186         cpl_table_erase_column(*atmext_table, "LA_SILLA"),
05187         cpl_table_name_column(*atmext_table, "LA_SILLA_double", "LA_SILLA")),
05188       "Could not cast column 'LA_SILLA'");
05189     
05190   cleanup:
05191     if (cpl_error_get_code() != CPL_ERROR_NONE) 
05192     {
05193         *atmext_table_filename = NULL;
05194         uves_free_table(atmext_table);
05195     }
05196     return cpl_error_get_code();
05197 }
05198 /*----------------------------------------------------------------------------*/
05206 /*----------------------------------------------------------------------------*/
05207 char *
05208 uves_guess_order_table_filename(enum uves_chip chip) 
05209 {
05210     return uves_local_filename("orderguesstable", chip, -1, -1);
05211 }
05212 
05213 /*----------------------------------------------------------------------------*/
05221 /*----------------------------------------------------------------------------*/
05222 char *
05223 uves_order_table_filename(enum uves_chip chip) 
05224 {
05225     return uves_local_filename("ordertable", chip, -1, -1);
05226 }
05227 
05228 /*----------------------------------------------------------------------------*/
05235 /*----------------------------------------------------------------------------*/
05236 char *uves_ordef_filename(enum uves_chip chip)
05237 {
05238     return uves_local_filename("order_def", chip, -1, -1);
05239 }
05240 
05241 /*----------------------------------------------------------------------------*/
05249 /*----------------------------------------------------------------------------*/
05250 char *
05251 uves_masterdark_filename(enum uves_chip chip) 
05252 {
05253     return uves_local_filename("masterdark", chip, -1, -1);
05254 }
05255 
05256 
05257 /*----------------------------------------------------------------------------*/
05263 /*----------------------------------------------------------------------------*/
05264 char *
05265 uves_flat_ratio_filename(enum uves_chip chip) 
05266 {
05267     return uves_local_filename("ratio", chip, -1, -1);
05268 }
05269 
05270 /*----------------------------------------------------------------------------*/
05277 /*----------------------------------------------------------------------------*/
05278 char *uves_cd_align_filename(enum uves_chip chip)
05279 {
05280     return uves_local_filename("cd_align", chip, -1, -1);
05281 }
05282 
05283 /*----------------------------------------------------------------------------*/
05291 /*----------------------------------------------------------------------------*/
05292 char *
05293 uves_masterflat_filename(enum uves_chip chip) 
05294 {
05295     return uves_local_filename("masterflat", chip, -1, -1);
05296 }
05297 /*----------------------------------------------------------------------------*/
05305 /*----------------------------------------------------------------------------*/
05306 char *
05307 uves_masterflat_bkg_filename(enum uves_chip chip) 
05308 {
05309     return uves_local_filename("masterflat_bkg", chip, -1, -1);
05310 }
05311 
05312 /*----------------------------------------------------------------------------*/
05320 /*----------------------------------------------------------------------------*/
05321 char *
05322 uves_masterbias_filename(enum uves_chip chip) 
05323 {
05324     return uves_local_filename("masterbias", chip, -1, -1);
05325 }
05326 
05327 /*----------------------------------------------------------------------------*/
05335 /*----------------------------------------------------------------------------*/
05336 char *
05337 uves_guess_line_table_filename(enum uves_chip chip)
05338 {
05339     return uves_local_filename("lineguesstable", chip, -1, -1);
05340 }
05341 /*----------------------------------------------------------------------------*/
05349 /*----------------------------------------------------------------------------*/
05350 char *
05351 uves_line_table_filename(enum uves_chip chip)
05352 {
05353     return uves_local_filename("linetable", chip, -1, -1);
05354 }
05355 
05356 /*----------------------------------------------------------------------------*/
05364 /*----------------------------------------------------------------------------*/
05365 char *
05366 uves_line_table_filename_paf(enum uves_chip chip)
05367 {
05368     return uves_local_filename("linetable_paf", chip, -1, -1);
05369 }
05370 
05371 /*----------------------------------------------------------------------------*/
05379 /*----------------------------------------------------------------------------*/
05380 char *
05381 uves_response_curve_filename(enum uves_chip chip)
05382 {
05383     return uves_local_filename("response", chip, -1, -1);
05384 }
05385 
05386 /*----------------------------------------------------------------------------*/
05394 /*----------------------------------------------------------------------------*/
05395 char *
05396 uves_response_curve_2d_filename(enum uves_chip chip)
05397 {
05398     return uves_local_filename("response_2d", chip, -1, -1);
05399 }
05400 
05401 /*----------------------------------------------------------------------------*/
05409 /*----------------------------------------------------------------------------*/
05410 char *
05411 uves_response_red_standard_filename(enum uves_chip chip)
05412 {
05413     return uves_local_filename("red_std", chip, -1, -1);
05414 }
05415 
05416 /*----------------------------------------------------------------------------*/
05424 /*----------------------------------------------------------------------------*/
05425 char *
05426 uves_response_bkg_standard_filename(enum uves_chip chip)
05427 {
05428     return uves_local_filename("bkg_std", chip, -1, -1);
05429 }
05430 
05431 /*----------------------------------------------------------------------------*/
05439 /*----------------------------------------------------------------------------*/
05440 char *
05441 uves_response_efficiency_filename(enum uves_chip chip)
05442 {
05443     return uves_local_filename("efficiency", chip, -1, -1);
05444 }
05445 
05446 /*----------------------------------------------------------------------------*/
05454 /*----------------------------------------------------------------------------*/
05455 char *
05456 uves_scired_red_science_filename(enum uves_chip chip)
05457 {
05458     return uves_local_filename("red_science", chip, -1, -1);
05459 }
05460 /*----------------------------------------------------------------------------*/
05468 /*----------------------------------------------------------------------------*/
05469 char *
05470 uves_scired_red_error_filename(enum uves_chip chip)
05471 {
05472     return uves_local_filename("red_science_error", chip, -1, -1);
05473 }
05474 /*----------------------------------------------------------------------------*/
05482 /*----------------------------------------------------------------------------*/
05483 char *
05484 uves_scired_fluxcal_science_filename(enum uves_chip chip)
05485 {
05486     return uves_local_filename("fluxcal_science", chip, -1, -1);
05487 }
05488 /*----------------------------------------------------------------------------*/
05496 /*----------------------------------------------------------------------------*/
05497 char *
05498 uves_scired_fluxcal_error_filename(enum uves_chip chip)
05499 {
05500     return uves_local_filename("fluxcal_error", chip, -1, -1);
05501 }
05502 /*----------------------------------------------------------------------------*/
05510 /*----------------------------------------------------------------------------*/
05511 char *
05512 uves_scired_ff_variance_filename(enum uves_chip chip)
05513 {
05514     return uves_local_filename("ff_science_variance", chip, -1, -1);
05515 }
05516 /*----------------------------------------------------------------------------*/
05524 /*----------------------------------------------------------------------------*/
05525 char *
05526 uves_scired_merged_science_filename(enum uves_chip chip)
05527 {
05528     return uves_local_filename("merged_science", chip, -1, -1);
05529 }
05530 /*----------------------------------------------------------------------------*/
05538 /*----------------------------------------------------------------------------*/
05539 char *
05540 uves_scired_merged_sky_filename(enum uves_chip chip)
05541 {
05542     return uves_local_filename("merged_sky", chip, -1, -1);
05543 }
05544 
05545 /*----------------------------------------------------------------------------*/
05553 /*----------------------------------------------------------------------------*/
05554 char *
05555 uves_scired_background_filename(enum uves_chip chip)
05556 {
05557     return uves_local_filename("background", chip, -1, -1);
05558 }
05559 
05560 /*----------------------------------------------------------------------------*/
05568 /*----------------------------------------------------------------------------*/
05569 char *
05570 uves_scired_resampled_filename(enum uves_chip chip)
05571 {
05572     return uves_local_filename("resampled", chip, -1, -1);
05573 }
05574 
05575 /*----------------------------------------------------------------------------*/
05583 /*----------------------------------------------------------------------------*/
05584 char *
05585 uves_scired_resampledmf_filename(enum uves_chip chip)
05586 {
05587     return uves_local_filename("resampled_mflat", chip, -1, -1);
05588 }
05589 
05590 /*----------------------------------------------------------------------------*/
05599 /*----------------------------------------------------------------------------*/
05600 char *
05601 uves_scired_rebinned_filename(enum uves_chip chip)
05602 {
05603     return uves_local_filename("resampled_ff", chip, -1, -1);
05604 }
05605 
05606 /*----------------------------------------------------------------------------*/
05614 /*----------------------------------------------------------------------------*/
05615 char *
05616 uves_scired_ordertrace_filename(enum uves_chip chip)
05617 {
05618     return uves_local_filename("ordertrace", chip, -1, -1);
05619 }
05620 
05621 /*----------------------------------------------------------------------------*/
05629 /*----------------------------------------------------------------------------*/
05630 char *
05631 uves_scired_crmask_filename(enum uves_chip chip)
05632 {
05633     return uves_local_filename("cr_mask", chip, -1, -1);
05634 }
05635 
05636 
05637 /*----------------------------------------------------------------------------*/
05645 /*----------------------------------------------------------------------------*/
05646 char *uves_scired_ext2d_filename(enum uves_chip chip)
05647 {
05648     return uves_local_filename("ext2d", chip, -1, -1);
05649 }
05650 
05651 /*----------------------------------------------------------------------------*/
05659 /*----------------------------------------------------------------------------*/
05660 char *uves_scired_ff2d_filename(enum uves_chip chip)
05661 {
05662     return uves_local_filename("ff2d", chip, -1, -1);
05663 }
05664 
05665 /*----------------------------------------------------------------------------*/
05686 /*----------------------------------------------------------------------------*/
05687 static char *
05688 uves_local_filename(const char *prefix, enum uves_chip chip, int trace, int window)
05689 {
05690     char *result = NULL;
05691     const char *chip_string;
05692     const char *suffix = ".fits";     /* Always */
05693     char *t = NULL;
05694     char *w = NULL;
05695 
05696     assure( (trace < 0 && window < 0) ||           /* Empty suffix          */
05697         (trace < 0 && window > 0) ||           /* Window only suffix    */
05698         (trace >= 0 && window > 0),            /* Trace & window suffix */
05699         CPL_ERROR_ILLEGAL_INPUT, "Illegal trace and window numbers: (%d, %d)", 
05700         trace, window);
05701 
05702     /* Chip */
05703     chip_string = uves_chip_tostring_lower(chip);
05704     
05705     /* Trace and window number (possibly empty string) */
05706     check(( t = int_to_string(trace),
05707         w = int_to_string(window)),
05708           "Error creating substrings");
05709 
05710 /* old code:
05711     result = cpl_calloc(strlen(prefix) + 1 + 
05712             strlen(chip_string) + strlen(t) + strlen(w) + strlen(suffix) + 1,
05713             sizeof(char));
05714     
05715     assure_mem( result );
05716     
05717     strcpy(result, prefix);
05718     strcat(result, "_");
05719     strcat(result, chip_string);
05720     strcat(result, t);
05721     strcat(result, w);
05722     strcat(result, suffix);
05723 */
05724     result = uves_sprintf("%s_%s%s%s%s", prefix, chip_string, t, w, suffix);
05725     assure_mem( result );
05726 
05727   cleanup:
05728     cpl_free(t);
05729     cpl_free(w);
05730     if (cpl_error_get_code() != CPL_ERROR_NONE)
05731     {
05732         cpl_free(result); result = NULL;
05733     }
05734     return result;
05735 }
05736 
05737 /*----------------------------------------------------------------------------*/
05748 /*----------------------------------------------------------------------------*/
05749 static char *
05750 int_to_string(int i)
05751 {
05752     char *result = NULL;
05753 
05754     assure( -1 <= i, CPL_ERROR_ILLEGAL_INPUT, "Illegal number (%d)", i);
05755 
05756     if (i == -1)
05757     {
05758         /* Empty string */
05759         result = cpl_calloc(1, sizeof(char));
05760         assure_mem( result );
05761     }
05762     else
05763     {
05764         result = uves_sprintf("_%d", i);
05765     }
05766     
05767   cleanup:
05768     if (cpl_error_get_code() != CPL_ERROR_NONE){
05769     cpl_free(result); result = NULL;
05770     }
05771     return result;
05772 }

Generated on Tue Jun 19 14:39:15 2007 for UVES Pipeline Reference Manual by  doxygen 1.4.6