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

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