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

Generated on 9 Mar 2012 for UVES Pipeline Reference Manual by  doxygen 1.6.1