uves_cd_align_impl.c

00001 /*                                                                              *
00002  *   This file is part of the ESO UVES Pipeline                                 *
00003  *   Copyright (C) 2004,2005 European Southern Observatory                      *
00004  *                                                                              *
00005  *   This library is free software; you can redistribute it and/or modify       *
00006  *   it under the terms of the GNU General Public License as published by       *
00007  *   the Free Software Foundation; either version 2 of the License, or          *
00008  *   (at your option) any later version.                                        *
00009  *                                                                              *
00010  *   This program is distributed in the hope that it will be useful,            *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of             *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
00013  *   GNU General Public License for more details.                               *
00014  *                                                                              *
00015  *   You should have received a copy of the GNU General Public License          *
00016  *   along with this program; if not, write to the Free Software                *
00017  *   Foundation, 51 Franklin St, Fifth Floor, Boston MA 02110-1301 USA          *
00018  */
00019  
00020 /*
00021  * $Author: amodigli $
00022  * $Date: 2008/02/15 12:43:49 $
00023  * $Revision: 1.13 $
00024  * $Name: uves-4_2_2 $
00025  * $Log: uves_cd_align_impl.c,v $
00026  * Revision 1.13  2008/02/15 12:43:49  amodigli
00027  * allow lower/upper chip for parameter process_chip
00028  *
00029  * Revision 1.12  2007/10/05 16:01:44  amodigli
00030  * using proces_chip parameter to process or not a given RED chip
00031  *
00032  * Revision 1.11  2007/06/22 09:28:24  jmlarsen
00033  * Changed interface of uves_save_image
00034  *
00035  * Revision 1.10  2007/06/11 13:28:26  jmlarsen
00036  * Changed recipe contact address to cpl at eso.org
00037  *
00038  * Revision 1.9  2007/06/08 13:06:16  jmlarsen
00039  * Send bug reports to Andrea
00040  *
00041  * Revision 1.8  2007/06/06 08:17:33  amodigli
00042  * replace tab with 4 spaces
00043  *
00044  * Revision 1.7  2007/05/22 11:29:53  jmlarsen
00045  * Changed text
00046  *
00047  * Revision 1.6  2007/05/14 08:09:48  amodigli
00048  * updated input frames and tag description in recipe man page
00049  *
00050  * Revision 1.5  2007/04/24 12:50:29  jmlarsen
00051  * Replaced cpl_propertylist -> uves_propertylist which is much faster
00052  *
00053  * Revision 1.4  2007/03/05 10:14:56  jmlarsen
00054  * Support slope parameter in 1d fitting
00055  *
00056  * Revision 1.3  2007/02/16 10:36:15  jmlarsen
00057  * Renamed variable y0->y_0
00058  *
00059  * Revision 1.2  2007/02/09 13:36:32  jmlarsen
00060  * Use defines for recipe id
00061  *
00062  * Revision 1.1  2007/02/08 11:38:37  jmlarsen
00063  * Added cd_align recipe
00064  *
00065  * Revision 1.31  2007/01/10 12:37:39  jmlarsen
00066  * Removed obsolete comments
00067  *
00068  */
00069 
00070 #ifdef HAVE_CONFIG_H
00071 #  include <config.h>
00072 #endif
00073 
00074 /*----------------------------------------------------------------------------*/
00081 /*----------------------------------------------------------------------------*/
00082 
00083 /*-----------------------------------------------------------------------------
00084                                 Includes
00085  -----------------------------------------------------------------------------*/
00086 #include <uves_cd_align_impl.h>
00087 
00088 #include <uves.h>
00089 #include <uves_plot.h>
00090 #include <uves_parameters.h>
00091 #include <uves_dfs.h>
00092 #include <uves_pfits.h>
00093 #include <uves_qclog.h>
00094 #include <uves_recipe.h>
00095 #include <uves_utils_cpl.h>
00096 #include <uves_utils_wrappers.h>
00097 #include <uves_error.h>
00098 #include <uves_msg.h>
00099 
00100 #include <cpl.h>
00101 
00102 /*-----------------------------------------------------------------------------
00103                             Functions prototypes
00104  -----------------------------------------------------------------------------*/
00105 
00106 static int
00107 uves_cal_cd_align_define_parameters(cpl_parameterlist *parameters);
00108 
00109 /*-----------------------------------------------------------------------------
00110                             Recipe standard code
00111  -----------------------------------------------------------------------------*/
00112 #define cpl_plugin_get_info uves_cal_cd_align_get_info
00113 UVES_RECIPE_DEFINE(
00114     UVES_CD_ALIGN_ID, UVES_CD_ALIGN_DOM, uves_cal_cd_align_define_parameters,
00115     "Jonas M. Larsen", "cpl@eso.org",
00116     "Measures the reproducability of the cross disperser positioning",
00117     "Given two input frames (CD_ALIGN_xxx where xxx = BLUE or RED) which contain only\n"
00118     "one echelle order, this recipe measures the shift in the cross-dispersion \n"
00119     "direction of that order. For RED input frames, only the lower chip is processed.\n"
00120     "\n"
00121     "The recipe produces a CD_ALIGN_TABLE_xxxx (with xxxx = BLUE or REDL) with columns\n"
00122     "X:         Column number\n"
00123     "YCENi:     Centroid from Gaussian fit (for i = 1,2)\n"
00124     "SIGMAi:    Stdev from Gaussian fit\n"
00125     "BACKi:     Constant background from Gaussian fit\n"
00126     "NORMi:     Normalization constant from Gaussian fit\n"
00127     "YDIFF:     Difference YCEN2 - YCEN1 of centroid positions\n"
00128     "\n"
00129     "and the QC-parameters ESO.QC.YDIFF(AVG|MED|RMS), which are the average,\n"
00130     "median and root-mean-square of the y-shift, respectively.\n");
00131 
00132 /*-----------------------------------------------------------------------------
00133                             Functions code
00134  -----------------------------------------------------------------------------*/
00136 static int
00137 uves_cal_cd_align_define_parameters(cpl_parameterlist *parameters)
00138 {
00139     const char *subcontext = NULL;
00140     const char *recipe_id = make_str(UVES_CD_ALIGN_ID);
00141 
00142     /*****************
00143      *    General    *
00144      *****************/
00145     if (uves_define_global_parameters(parameters) != CPL_ERROR_NONE)
00146         {
00147             return -1;
00148         }
00149     
00150     /* stepsize */
00151     uves_par_new_range("steps",
00152                CPL_TYPE_INT,
00153                "Step size in pixels",
00154                100, 1, INT_MAX);
00155     
00156     /* xborder */
00157     uves_par_new_range("xborder",
00158                CPL_TYPE_INT,
00159                "Exclude a border region of this size (pixels)",
00160                200, 0, INT_MAX);
00161     
00162     /* window */
00163     uves_par_new_range("window",
00164                CPL_TYPE_INT,
00165                "The half window height used for Gaussian fitting",
00166                50, 1, INT_MAX);
00167     
00168     return (cpl_error_get_code() != CPL_ERROR_NONE);
00169 }
00170 
00171 /*----------------------------------------------------------------------------*/
00188 /*----------------------------------------------------------------------------*/
00189 cpl_table *
00190 uves_cd_align_process(const cpl_image *im1,
00191     const cpl_image *im2,
00192     const uves_propertylist *rotated_header1,
00193     const uves_propertylist *rotated_header2,
00194     int steps,
00195     int xborder,
00196     int window,
00197     bool DEBUG,
00198     enum uves_chip chip)
00199 {
00200     cpl_table *result = NULL;
00201     int row = 0;             /* number of table rows used */
00202     const cpl_image *images[2];
00203     cpl_image *rows = NULL;
00204     int max_row[2];          /* image row with max flux */
00205     int nx, ny, x;
00206     int num_fits, fit_succeeded;
00207 
00208     images[0] = im1;
00209     images[1] = im2;    
00210     nx = cpl_image_get_size_x(images[0]);
00211     ny = cpl_image_get_size_y(images[0]);
00212     
00213     if (DEBUG) check( uves_save_image_local("CD alignment frame", "cd_align1", 
00214                         images[0], chip, -1, -1, 
00215                         rotated_header1, true),
00216               "Error saving 1st CD aligment frame");
00217     
00218     if (DEBUG) check( uves_save_image_local("CD alignment frame", "cd_align2", 
00219                         images[1], chip, -1, -1, 
00220                         rotated_header2, true),
00221               "Error saving 2nd CD aligment frame");
00222     
00223     assure( cpl_image_get_size_x(images[0]) == cpl_image_get_size_x(images[1]) &&
00224         cpl_image_get_size_y(images[0]) == cpl_image_get_size_y(images[1]),
00225         CPL_ERROR_INCOMPATIBLE_INPUT,
00226         "Images sizes: %dx%d and %dx%d",
00227         cpl_image_get_size_x(images[0]),
00228         cpl_image_get_size_y(images[0]),
00229         cpl_image_get_size_x(images[1]),
00230         cpl_image_get_size_y(images[1]) );
00231 
00232 
00233     result = cpl_table_new(nx); row = 0;
00234     cpl_table_new_column(result, "X"    , CPL_TYPE_INT);
00235     cpl_table_new_column(result, "YCEN1", CPL_TYPE_DOUBLE);
00236     cpl_table_new_column(result, "YCEN2", CPL_TYPE_DOUBLE);
00237     cpl_table_new_column(result, "SIGMA1", CPL_TYPE_DOUBLE);
00238     cpl_table_new_column(result, "SIGMA2", CPL_TYPE_DOUBLE);
00239     cpl_table_new_column(result, "BACK1", CPL_TYPE_DOUBLE);
00240     cpl_table_new_column(result, "BACK2", CPL_TYPE_DOUBLE);
00241     cpl_table_new_column(result, "NORM1", CPL_TYPE_DOUBLE);
00242     cpl_table_new_column(result, "NORM2", CPL_TYPE_DOUBLE);
00243     assure_mem( result );
00244     
00245     /* Find row of max accumulated flux (i.e. position of the order) */
00246     {
00247     int im;
00248     for (im = 0; im < 2; im++)
00249         {
00250         int direction = 1; /* To get image of single column */
00251         int max_col;
00252         
00253         uves_free_image(&rows);
00254         rows = cpl_image_collapse_create(images[im], direction);
00255 
00256         cpl_image_get_maxpos(rows, &max_col, &(max_row[im]));
00257         uves_msg("Row of max flux (%d. image) = %d", im+1, max_row[im]);
00258 
00259         assure( max_col == 1, CPL_ERROR_ILLEGAL_OUTPUT,
00260             "Something went wrong, max_col in collapsed image is = %d", max_col);
00261         }
00262     }
00263 
00264     num_fits = 0;         /* Number of measure points */
00265     fit_succeeded = 0;   /* Number of successful Gauss fits */
00266     for (x = 1 + xborder; x <= nx - xborder; x += steps)
00267     {
00268         int im;
00269         for (im = 0; im < 2; im++)
00270         {
00271             bool horizontal = false;
00272             bool fix_background = false;
00273             bool fit_background = false;
00274             int number_of_parameters = 4;
00275             double y_0, sigma, norm, background;
00276             int ylow  = uves_max_int(1, uves_min_int(ny, max_row[im] - window));
00277             int yhigh = uves_max_int(1, uves_min_int(ny, max_row[im] + window));
00278         
00279             uves_fit_1d_image(images[im], 
00280                       NULL, NULL, /* errors, bpm */
00281                       horizontal, fix_background, fit_background,
00282                       ylow, yhigh, x,
00283                       &y_0, &sigma, &norm, &background, NULL, /* slope */
00284                       NULL, NULL, /* mse, red_chisq */
00285                       NULL,       /* Covariance */
00286                       uves_gauss, uves_gauss_derivative, 
00287                       number_of_parameters);
00288 
00289             num_fits += 1;
00290             if (cpl_error_get_code() == CPL_ERROR_CONTINUE)
00291             {
00292                 uves_error_reset();
00293                 
00294                 uves_msg_warning("Fitting window (%d, %d) - (%d, %d) failed",
00295                          x, ylow, x, yhigh);
00296             }
00297             else
00298             {
00299                 fit_succeeded += 1;
00300 
00301                 assure( cpl_error_get_code() == CPL_ERROR_NONE,
00302                     cpl_error_get_code(),
00303                     "Gaussian fitting failed");
00304                 
00305                 cpl_table_set_int   (result, "X"    , row, x);
00306                 cpl_table_set_double(result, (im == 0) ? "YCEN1" : "YCEN2", row, y_0);
00307                 cpl_table_set_double(result, (im == 0) ? "SIGMA1": "SIGMA2", row, sigma);
00308                 cpl_table_set_double(result, (im == 0) ? "BACK1" : "BACK2", row, norm);
00309                 cpl_table_set_double(result, (im == 0) ? "NORM1" : "NORM2", row, background);
00310             }
00311         }
00312         row++;
00313     }
00314 
00315     cpl_table_set_size(result, row);
00316 
00317     uves_msg_low("Was able to fit %d of %d columns", fit_succeeded, num_fits);
00318 
00319     check(( cpl_table_duplicate_column(result, "YDIFF", result, "YCEN2"),
00320         cpl_table_subtract_columns(result, "YDIFF", "YCEN1")),
00321       "Error calculating residuals of fit");
00322 
00323     {
00324     int num_valid = cpl_table_get_nrow(result) - cpl_table_count_invalid(result, "YDIFF");
00325     
00326     assure( num_valid >= 1, CPL_ERROR_ILLEGAL_OUTPUT,
00327         "Only %d valid YDIFF value(s), 1 or more needed",
00328         num_valid);
00329     }
00330     
00331 
00332   cleanup:
00333     uves_free_image(&rows);
00334     return result;
00335 }
00336 
00337 /*----------------------------------------------------------------------------*/
00346 /*----------------------------------------------------------------------------*/
00347 
00348 static cpl_table*
00349 cd_align_qclog(const cpl_table *cdalign,
00350            const uves_propertylist *raw_header,
00351            enum uves_chip chip)
00352 {
00353     cpl_table *qclog = NULL;
00354     double mean, sigma, median;
00355 
00356     check( qclog = uves_qclog_init(raw_header, chip),
00357        "Error during QC initialization");
00358     
00359     mean   = cpl_table_get_column_mean  (cdalign, "YDIFF");
00360     sigma  = cpl_table_get_column_stdev (cdalign, "YDIFF");
00361     median = cpl_table_get_column_median(cdalign, "YDIFF");
00362 
00363     uves_qclog_add_string(qclog,
00364               "QC TEST1 ID",
00365               "Test-of-CD-Alignment",
00366               "Name of QC test",
00367               "%s");
00368     
00369     uves_qclog_add_double(qclog,
00370               "QC YDIFFAVG",
00371               mean,
00372               "Average Y difference",
00373               "%8.4f");
00374   
00375     uves_qclog_add_double(qclog,
00376               "QC YDIFFMED",
00377               median,
00378               "Median Y difference",
00379               "%8.4f");
00380 
00381     uves_qclog_add_double(qclog,
00382               "QC YDIFFRMS",
00383               sigma,
00384               "RMS Y difference",
00385               "%8.4f");
00386   
00387 
00388     uves_msg("Average shift = %.4f +- %.4f pixels",
00389          mean, sigma);
00390          
00391 
00392   cleanup:
00393     return qclog;
00394 }
00395 
00396 /*----------------------------------------------------------------------------*/
00404 /*----------------------------------------------------------------------------*/
00405 static double
00406 avg_flux(const cpl_image *im)
00407 {
00408     double result = 0;
00409     cpl_image *median_filt = NULL;
00410     bool extrapolate_border = true;
00411     
00412     /* Report total flux after bias subtraction.
00413        Bias is estimated as the median value
00414        
00415        Note that: total flux  -  nx*ny*median =
00416        nx*ny(mean - median)
00417        
00418        so just report (mean - median)
00419     */
00420 
00421     /* First apply a small window (3x3) median filter to
00422        get a bit robust avg, but without destroying the echelle order signal
00423     */
00424     
00425     median_filt = cpl_image_duplicate(im);
00426     assure_mem( median_filt );
00427 
00428     uves_filter_image_median(&median_filt, 1, 1,
00429                  extrapolate_border);
00430 
00431     result =
00432     cpl_image_get_mean  (median_filt) -
00433     cpl_image_get_median(median_filt);
00434     
00435   cleanup:
00436     uves_free_image(&median_filt);
00437     return result;
00438 }
00439 
00440 /*----------------------------------------------------------------------------*/
00448 /*----------------------------------------------------------------------------*/
00449 static void
00450 uves_cal_cd_align_exe(cpl_frameset *frames, const cpl_parameterlist *parameters,
00451          const char *starttime)
00452 {
00453     /* Input */
00454     cpl_image *raw_images[2][2] = {{NULL, NULL}, {NULL, NULL}};
00455     
00456     /* This 2x2 array of images contain:
00457        
00458        raw_images[0][0]:  First frame, REDL or BLUE chip 
00459        raw_images[0][1]:  First frame, REDU or NULL
00460        raw_images[1][0]:  Second frame, REDL or BLUE chip 
00461        raw_images[1][1]:  Second frame, REDU or NULL
00462 
00463        etc. for the following arrays
00464     */
00465 
00466     uves_propertylist *raw_headers[2][2]     = {{NULL, NULL}, {NULL, NULL}};
00467     uves_propertylist *rotated_headers[2][2] = {{NULL, NULL}, {NULL, NULL}};
00468 
00469     cpl_table* qclog[2] = {NULL, NULL};
00470 
00471     /* Output */
00472     uves_propertylist *product_header = NULL;
00473     cpl_table *cd_align = NULL;
00474     
00475     /* Parameters */
00476     int steps, xborder, window;
00477     bool DEBUG;
00478 
00479     /* Local variables */
00480     const char *product_filename = NULL;
00481     bool blue;
00482     enum uves_chip chip;
00483     const char *raw_filename[2];
00484     int raw_index;
00485 
00486     const char* PROCESS_CHIP=NULL;
00487 
00488     check( uves_get_parameter(parameters, NULL, "uves", "debug", 
00489                   CPL_TYPE_BOOL, &DEBUG), "Could not read parameter");
00490 
00491     check( uves_get_parameter(parameters, NULL, "uves", "process_chip", CPL_TYPE_STRING, &PROCESS_CHIP),
00492                "Could not read parameter");
00493     uves_string_toupper((char*)PROCESS_CHIP);
00494 
00495     check( uves_get_parameter(parameters, NULL, make_str(UVES_CD_ALIGN_ID), "steps",
00496                   CPL_TYPE_INT   , &steps), "Could not read parameter");
00497     check( uves_get_parameter(parameters, NULL, make_str(UVES_CD_ALIGN_ID), "xborder",
00498                   CPL_TYPE_INT   , &xborder), "Could not read parameter");
00499     check( uves_get_parameter(parameters, NULL, make_str(UVES_CD_ALIGN_ID), "window",
00500                   CPL_TYPE_INT   , &window), "Could not read parameter");
00501     
00502 
00503     check( uves_load_cd_align(frames,
00504                   &raw_filename[0], 
00505                   &raw_filename[1], 
00506                   raw_images[0],
00507                   raw_images[1],
00508                   raw_headers[0],
00509                   raw_headers[1],
00510                   rotated_headers[0],
00511                   rotated_headers[1],
00512                   &blue), 
00513        "Error loading raw frame");
00514 
00515     uves_msg("Using %s", raw_filename[0]);
00516     uves_msg("Using %s", raw_filename[1]);
00517 
00518     
00519     if (blue)
00520     {
00521         chip = UVES_CHIP_BLUE;
00522     }
00523     else
00524     {
00525         if (DEBUG)
00526         {
00527             int raw_index_l = uves_chip_get_index(UVES_CHIP_REDL);
00528             int raw_index_u = uves_chip_get_index(UVES_CHIP_REDU);
00529             
00530             uves_msg("1. REDL average flux per pixel = %f ADU", avg_flux(raw_images[0][raw_index_l]));
00531             uves_msg("2. REDL average flux per pixel = %f ADU", avg_flux(raw_images[1][raw_index_l]));
00532             
00533             uves_msg("1. REDU average flux per pixel = %f ADU", avg_flux(raw_images[0][raw_index_u]));
00534             uves_msg("2. REDU average flux per pixel = %f ADU", avg_flux(raw_images[1][raw_index_u]));
00535         }
00536         
00537         chip = UVES_CHIP_REDL; /* Process only lower red chip */
00538     }
00539     
00540     raw_index = uves_chip_get_index(chip);
00541     
00542     uves_msg("Processing %s chip",
00543          uves_chip_tostring_upper(chip));
00544     
00545     check( cd_align = uves_cd_align_process(raw_images[0][raw_index],
00546                   raw_images[1][raw_index],
00547                   rotated_headers[0][raw_index],
00548                   rotated_headers[1][raw_index],
00549                   steps,
00550                   xborder,
00551                   window,
00552                   DEBUG,
00553                   chip),
00554        "Error during processing");
00555 
00556     check( qclog[0] = cd_align_qclog(cd_align,
00557                      raw_headers[0][raw_index], /* of first frame */
00558                      chip),
00559        "Could not compute QC");
00560 
00561     product_header = uves_propertylist_new();
00562     product_filename = uves_cd_align_filename(chip);
00563     check( uves_frameset_insert(frames,
00564                 cd_align,
00565                 CPL_FRAME_GROUP_PRODUCT,
00566                 CPL_FRAME_TYPE_TABLE,
00567                 CPL_FRAME_LEVEL_FINAL,
00568                 product_filename,
00569                 UVES_CD_ALIGN_TABLE(blue),
00570                 raw_headers[0][raw_index],
00571                 product_header,
00572                 NULL,       /* table header */
00573                 parameters,
00574                 make_str(UVES_CD_ALIGN_ID),
00575                 PACKAGE "/" PACKAGE_VERSION,
00576                 qclog, /* No QC */
00577                 starttime, true,
00578                 0),
00579        "Could not add CD align table %s to frameset", product_filename);
00580 
00581     uves_msg("CD align table %s (%s) added to frameset",
00582          product_filename, UVES_CD_ALIGN_TABLE(blue));
00583 
00584   cleanup:
00585     uves_free_image(&raw_images[0][0]);
00586     uves_free_image(&raw_images[0][1]);
00587     uves_free_image(&raw_images[1][0]);
00588     uves_free_image(&raw_images[1][1]);
00589     uves_free_propertylist(&raw_headers[0][0]);
00590     uves_free_propertylist(&raw_headers[0][1]);
00591     uves_free_propertylist(&raw_headers[1][0]);
00592     uves_free_propertylist(&raw_headers[1][1]);
00593     uves_free_propertylist(&rotated_headers[0][0]);
00594     uves_free_propertylist(&rotated_headers[0][1]);
00595     uves_free_propertylist(&rotated_headers[1][0]);
00596     uves_free_propertylist(&rotated_headers[1][1]);
00597 
00598     uves_free_table(&qclog[0]);
00599     uves_free_string_const(&product_filename);
00600     uves_free_table(&cd_align);
00601     uves_free_propertylist(&product_header);
00602 
00603     return;
00604 }
00605 
00606 

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