uves_response_efficiency.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  02111-1307  USA       *
00018  *                                                                              */
00019  
00020 /*
00021  * $Author: amodigli $
00022  * $Date: 2012/03/02 17:01:39 $
00023  * $Revision: 1.37 $
00024  * $Name: uves-5_0_0 $
00025  *
00026  */
00027 
00028 /*----------------------------------------------------------------------------*/
00032 /*----------------------------------------------------------------------------*/
00033 
00034 #ifdef HAVE_CONFIG_H
00035 #  include <config.h>
00036 #endif
00037 
00038 /*-----------------------------------------------------------------------------
00039                                 Includes
00040  -----------------------------------------------------------------------------*/
00041 
00042 #include <uves_response_efficiency.h>
00043 #include <uves_response_utils.h>
00044 #include <uves_reduce.h>
00045 #include <uves_reduce_utils.h>
00046 #include <uves_dfs.h>
00047 #include <uves_pfits.h>
00048 #include <uves_wavecal_utils.h>
00049 #include <uves_utils_polynomial.h>
00050 #include <uves_utils.h>
00051 #include <uves_utils_wrappers.h>
00052 #include <uves_utils_cpl.h>
00053 #include <uves.h>
00054 #include <uves_error.h>
00055 #include <uves_msg.h>
00056 
00057 #include <cpl.h>
00058 
00059 #include <stdbool.h>
00060 
00061 /*-----------------------------------------------------------------------------
00062                                 Defines
00063  -----------------------------------------------------------------------------*/
00064 #define H_BAR 6.626068e-34           /* SI-units */
00065 #define PRIMARY_DIA 818              /* Primary diameter (cm) */
00066 #define OBSTR_DIA   140              /* Central obstruction diameter (cm) */
00067 #define TELESCOPE_EFFECTIVE_AREA   \
00068   (M_PI * (PRIMARY_DIA * PRIMARY_DIA - OBSTR_DIA * OBSTR_DIA) / 4.0)  /* (cm^2) */
00069 
00098 /*----------------------------------------------------------------------------*/
00099 cpl_error_code
00100 uves_response_efficiency(const cpl_image *raw_image, 
00101                          const uves_propertylist *raw_header, 
00102                          const uves_propertylist *rotated_header,
00103                          const cpl_image *master_bias,
00104                          const cpl_image *master_dark, 
00105                          const uves_propertylist *mdark_header, 
00106                          const cpl_table *ordertable, 
00107                          const polynomial *order_locations,
00108                          const cpl_table *linetable[3], 
00109                          const uves_propertylist *linetable_header[3], 
00110                          const polynomial *dispersion_relation[3],
00111                          const cpl_table *flux_table,
00112                          const cpl_table *atm_extinction,
00113                          enum uves_chip chip,
00114                          bool DEBUG,
00115                          const cpl_parameterlist *parameters,
00116                          /* Identification */
00117                          double PACCURACY,
00118                          /* Output */
00119                          cpl_table **efficiency,
00120                          cpl_table **blaze_efficiency)
00121 {
00122     cpl_image *background             = NULL;
00123     cpl_image *rebinned_spectrum      = NULL;
00124     cpl_image *rebinned_noise         = NULL;
00125     cpl_image *merged_sky             = NULL;
00126     cpl_image *merged_spectrum        = NULL;
00127     cpl_image *merged_noise           = NULL;
00128     cpl_image *reduced_spectrum       = NULL;
00129     cpl_image *reduced_noise          = NULL;
00130     cpl_image *reduced_rebinned       = NULL;
00131     cpl_image *reduced_rebinned_noise = NULL;
00132     uves_propertylist *rebinned_header = NULL;
00133     uves_propertylist *reduced_header  = NULL;
00134     polynomial *disprel_1d            = NULL;
00135 
00136     cpl_image *response_orders     = NULL;
00137     cpl_image *efficiency_spectrum = NULL;
00138     cpl_table *central_efficiency  = NULL;
00139 
00140     cpl_table *info_tbl            = NULL;  /* Local. The info tbl
00141                            should not be calculated twice
00142                            in the response recipe. It is
00143                            calculated in the first extraction */
00144 
00145     char *ref_obj_id = NULL;
00146     
00147     double wavestep;
00148     double extraction_slit;
00149     cpl_image* wave_map=NULL;
00150     cpl_image* reduced_rebinned_no_bpm=NULL;
00151     cpl_mask* bpm=NULL;
00152 
00153     /* Set parameters
00154        wavestep       = 10 * 2/3 * mean(pixelsize)
00155 
00156        After execution, revert to current value
00157     */
00158     {
00159     double smooth_step;
00160     
00161     /* wavestep */
00162     check( uves_get_parameter(parameters, NULL, 
00163                   make_str(UVES_RESPONSE_ID) "", "reduce.rebin.wavestep", 
00164                   CPL_TYPE_DOUBLE, &wavestep),
00165            "Error getting resampling step size");
00166     
00167     check( smooth_step = cpl_table_get_column_mean(linetable[1], LINETAB_PIXELSIZE),
00168            "Error reading mean pixelsize");
00169     
00170     smooth_step = 10*2*smooth_step/3;
00171         
00172     /* Cast to non-const is okay. The parameter is reset to its previous value
00173        (see below), so there is not net change (unless the reduction fails, 
00174        in which case parameter list will change).
00175     */
00176     check( uves_set_parameter((cpl_parameterlist *) parameters,
00177                   make_str(UVES_RESPONSE_ID) "", "reduce.rebin.wavestep",
00178                   CPL_TYPE_DOUBLE, &smooth_step),
00179            "Error setting resampling step size");
00180     }
00181     
00182     check( uves_reduce(raw_image, 
00183                        raw_header, 
00184                        rotated_header,
00185                master_bias,
00186                master_dark, 
00187                        mdark_header,
00188                NULL, 
00189                        NULL,                              /* No master flat */
00190                ordertable, 
00191                        order_locations,
00192                linetable, 
00193                        linetable_header, 
00194                        dispersion_relation,
00195                chip,
00196                DEBUG, 
00197                parameters, 
00198                        make_str(UVES_RESPONSE_ID),
00199                        ".efficiency",
00200                /* Output */
00201                NULL, 
00202                        NULL, 
00203                        NULL,                        /* 2d products */
00204                NULL,                        /* Cosmic ray table */
00205                &wave_map,
00206                &background,
00207                NULL, 
00208                        NULL,                        /* Variance of flat-fielded spectrum */
00209                NULL, 
00210                        NULL,                        /* Don't need these 
00211                                intermediate products */
00212                &merged_sky,
00213                &rebinned_spectrum, 
00214                        &rebinned_noise, 
00215                        &rebinned_header,
00216                &merged_spectrum, 
00217                        &merged_noise, 
00218                        &reduced_header,
00219                &reduced_rebinned, 
00220                        &reduced_rebinned_noise,
00221                &reduced_spectrum, 
00222                        &reduced_noise,
00223                        &info_tbl,
00224                &extraction_slit,   /* not passed on to the caller */
00225                        NULL),
00226        "Could not reduce frame");
00227     
00228     /* Reset parameter to previous value */
00229     {
00230     uves_msg_debug("Resetting parameter wavestep = %e", wavestep);
00231 
00232     /* Cast to non-const is okay. There is no net change in the parameter list (see above). */
00233     check( uves_set_parameter((cpl_parameterlist *) parameters, 
00234                   make_str(UVES_RESPONSE_ID) "", "reduce.rebin.wavestep", 
00235                   CPL_TYPE_DOUBLE, &wavestep),
00236            "Error resetting resampling step size");
00237     }
00238     
00239     
00240     /* Save reduced spectrum */
00241     if (DEBUG) 
00242     {
00243         /* Window number doesn't apply. This is middle window minus two other (sky) windows */
00244         check( uves_save_image_local("Reduced spectrum (2d)", "reduced", 
00245                      reduced_rebinned, chip, -1, -1, rebinned_header, true), 
00246            "Error saving reduced spectrum (2d)");
00247         
00248         check( uves_save_image_local("Reduced spectrum (2d) noise", "errreduced", 
00249                      reduced_rebinned_noise, chip, -1, -1, rebinned_header, true),
00250            "Error saving reduced spectrum (2d) noise");
00251 
00252         check( uves_save_image_local("Reduced spectrum", "merged", 
00253                      reduced_spectrum, chip, -1, -1, reduced_header, true), 
00254            "Error saving reduced spectrum");
00255         
00256         check( uves_save_image_local("Reduced spectrum noise", "errmerged", 
00257                      reduced_noise, chip, -1, -1, reduced_header, true), 
00258            "Error saving reduced spectrum noise");
00259     }
00260     
00261     uves_msg("Dividing by catalogue flux");
00262     /*
00263      * Calculate 2d response curve  (don't scale to unit exposure time, binning, gain, ... ) 
00264      */
00265     /* in some cases are flagged too many bad pixels on sky frames used 
00266        to compute reduced object in linear extraction method, this 
00267        affecting the number of bad pixels of the reduced_rebinned obj spectrum
00268        to fix this we erase the associated bad pixel map
00269     */
00270     reduced_rebinned_no_bpm=cpl_image_duplicate(reduced_rebinned);
00271     bpm=cpl_image_unset_bpm(reduced_rebinned_no_bpm);
00272     check( response_orders = uves_calculate_response(reduced_rebinned_no_bpm, 
00273                                                      rebinned_header,
00274                                                      flux_table,
00275                                                      raw_header, PACCURACY,
00276                                                      false,
00277                                                      &ref_obj_id),/*  flux/std_flux  */
00278        "Could not calculate response curve");
00279 
00280     uves_free_image(&reduced_rebinned_no_bpm);
00281     uves_free_mask(&bpm);
00282 
00283     if (DEBUG)
00284     {
00285         check( uves_save_image_local("2d response curve", "resp",
00286                      response_orders, chip, -1, -1, rebinned_header, true),
00287            "Error saving 2d response curve");
00288     }
00289 
00290     /*
00291      *   Extinction correction, exposure time + gain
00292      */
00293     {
00294     int n_traces = cpl_image_get_size_y(merged_spectrum);    /* Number of spatial traces */
00295     
00296     assure( n_traces == 1, CPL_ERROR_ILLEGAL_INPUT,
00297         "2d extraction/reduction not supported");
00298     
00299     check( efficiency_spectrum = uves_normalize_spectrum(response_orders, NULL,
00300                                  /* Spectrum, noise */
00301                                  rebinned_header,
00302                                  raw_header,
00303                                  n_traces,
00304                                  chip,
00305                                  atm_extinction,
00306                                  false,  /* Don't divide by binning */
00307                                  NULL),  /* Don't need output noise */
00308            "Could not normalize spectrum");
00309     }
00310 
00311     /*
00312      *   7 x 1 median filter
00313      */
00314     uves_msg("Applying 7x1 median filter");
00315     check( uves_filter_image_median(&efficiency_spectrum, 3, 0, false),
00316        "Error applying median filter");
00317 
00318     
00319     uves_msg("Calculating quantum detection efficiency");
00320 
00321     {
00322     int nx, nbins, norders, order;
00323     int first_abs_order, last_abs_order, abs_order;  /* Absolute order numbers */
00324     double dlambda;
00325     double average_noise;               /* Median of noise of rebinned spectrum */
00326     int row = 0;                                       /* Next unused table row */
00327 
00328     double *efficiency_data;               /* For efficiency. cpl_image_get()   */
00329     double *reduced_noise_data;            /* is slow when there are bad pixels */
00330 
00331     efficiency_data    = cpl_image_get_data_double(efficiency_spectrum);
00332     reduced_noise_data = cpl_image_get_data_double(reduced_rebinned_noise);
00333 
00334     nx      = cpl_image_get_size_x(raw_image);
00335     nbins   = cpl_image_get_size_x(efficiency_spectrum);
00336     norders = cpl_image_get_size_y(efficiency_spectrum);
00337     
00338     *efficiency = cpl_table_new(nbins * norders);
00339     cpl_table_new_column(*efficiency, "Wave", CPL_TYPE_DOUBLE);
00340     cpl_table_new_column(*efficiency, "Eff", CPL_TYPE_DOUBLE);
00341     cpl_table_new_column(*efficiency, "Binsize", CPL_TYPE_DOUBLE);
00342     cpl_table_new_column(*efficiency, "Order", CPL_TYPE_INT);
00343     row = 0;
00344     
00345     check( first_abs_order = uves_pfits_get_firstabsorder(linetable_header[1]), 
00346            "Could not read order numbers from line table header");
00347     check( last_abs_order  = uves_pfits_get_lastabsorder (linetable_header[1]), 
00348            "Could not read order numbers from line table header");
00349     
00350     check( dlambda = uves_pfits_get_cdelt1(rebinned_header),
00351            "Error reading bin width from header");
00352     
00353     check( average_noise = cpl_image_get_median(reduced_rebinned_noise),
00354            "Error reading median noise level");
00355 
00356     for (order = 1; order <= norders; order++)
00357         {
00358         double lambda_start, lambda, lambda_end;
00359         double x;
00360         int bin;
00361 
00362         abs_order = uves_absolute_order(first_abs_order, last_abs_order, order);
00363 
00364         check( lambda_start = uves_pfits_get_wstart(rebinned_header, order),
00365                "Error reading start wavelength from header");
00366         
00367         check( lambda_end   = uves_pfits_get_wend(rebinned_header, order),
00368                "Error reading end wavelength from header");
00369 
00370         /* Get 1d dispersion relation for this order
00371            f_1d = f(x, m=abs_order) 
00372 
00373            Collapsing a polynomial is slow, so do it
00374            only once per order
00375         */
00376         uves_polynomial_delete(&disprel_1d);
00377         check( disprel_1d = uves_polynomial_collapse(dispersion_relation[1],
00378                                  2,  /* Independent variable number */
00379                                  abs_order),
00380                "Error getting 1d dispersion relation for absolute order #%d", abs_order);
00381 
00382         x = 1;
00383         for (lambda = lambda_start, bin = 1;
00384              lambda < lambda_end + 0.5 * dlambda && bin <= nbins; 
00385              bin++, lambda += dlambda)
00386             {
00387             double flux;
00388             double dldx;
00389             double noise;            /* Only use positions with low noise 
00390                             (middle of blaze function) */
00391             
00392             /* flux  = cpl_image_get(efficiency_spectrum, 
00393                                      bin, order, &pis_rejected);
00394                noise = cpl_image_get(reduced_rebinned_noise, 
00395                bin, order, &pis_rejected); */
00396             flux  = efficiency_data   [(bin-1) + (order-1) * nbins];
00397             noise = reduced_noise_data[(bin-1) + (order-1) * nbins];
00398 
00399 
00400             /*
00401              *   Energy per (time * area * wavelength) =
00402              *    ((electron counts)/gain) * (hc/lambda) / 
00403              *    (time * area * |dlambda/dx|)
00404              *
00405              *   We already divided by exposure time, gain
00406              *   We did not multiply by dlambda/dx during rebinning,
00407              *    so now is the time to do it
00408              */
00409 
00410             /* Solve  f(x,m) = m*lambda  for x.
00411              *
00412              * This is equivalent to solving f_1d(x) = m*lambda
00413             */
00414             
00415             check( x = uves_polynomial_solve_1d(
00416                    disprel_1d, 
00417                    abs_order * lambda, /* right hand side    */
00418                    x,                  /* guess              */
00419                    1),                 /* multiplicity       */
00420                    "Could not solve dispersion relation for x "
00421                    "at (m, lambda) = (%d, %f)", abs_order, lambda);
00422             
00423 
00424 
00425             /*  For constant absolute order number, m:
00426                 dl/dx  =  d (l.m)/dx / m  */
00427             
00428             check( dldx = fabs(uves_polynomial_derivative_2d(
00429                            dispersion_relation[1], 
00430                            x, 
00431                            abs_order, 1) / abs_order),
00432                    "Could not evaluate dispersion relation");
00433             
00434                         /* Don't make a linear interpolation
00435             weight = (lambda - lambda_start) / (lambda_end - lambda_start);
00436             
00437             check( dldx =
00438                    fabs(uves_polynomial_derivative_2d(
00439                     dispersion_relation[1],
00440                     1 , abs_order,
00441                     1) / abs_order) * (1 - weight) +
00442                    fabs(uves_polynomial_derivative_2d(
00443                     dispersion_relation[1],
00444                     nx, abs_order, 1) / abs_order) * weight,
00445                    "Could not evaluate dispersion relation");
00446             */
00447 
00448             flux = flux * 1e16 * 1e17 * H_BAR * SPEED_OF_LIGHT /
00449                 (dldx * lambda * TELESCOPE_EFFECTIVE_AREA);
00450             /* The factor 1e17 accounts for the conversion Joule<-erg
00451              * (10^7) and Angstrom->meters (10^10)
00452              * The factor 1e16 is to correct for the fact that the
00453              * catalogue flux is in units of (10^-16 <standard units>)
00454              */
00455 
00456             if (noise < 3*average_noise)
00457                 {
00458                 check(( cpl_table_set_double(*efficiency, "Wave", row, lambda),
00459                     cpl_table_set_double(*efficiency, "Eff",  row, flux),
00460                     cpl_table_set_double(*efficiency, "Binsize",  row, dldx),
00461                     cpl_table_set_int   (*efficiency, "Order",  row, order),
00462                     row++),
00463                        "Error updating efficiency table row %d", row);
00464                 }
00465             }
00466         }
00467     
00468     /* Remove unused rows of efficiency table */
00469     check( cpl_table_set_size(*efficiency, row), 
00470            "Error setting size of efficiency table to %d rows", row);
00471     /* remove negative efficiency points */
00472     cpl_table* tmp=cpl_table_duplicate(*efficiency);
00473     row=cpl_table_and_selected_double(tmp,"Eff",CPL_GREATER_THAN,0.);
00474     uves_free_table(efficiency);
00475     *efficiency=cpl_table_extract_selected(tmp);
00476     uves_free_table(&tmp);
00477 
00478 
00479     /* Get the "top efficiency" (90% percentile efficiency of middle 20% of each order) */
00480 
00481     *blaze_efficiency = cpl_table_new(norders);
00482     cpl_table_new_column(*blaze_efficiency, "Order", CPL_TYPE_INT);
00483     cpl_table_new_column(*blaze_efficiency, "Wave" , CPL_TYPE_DOUBLE);
00484     cpl_table_new_column(*blaze_efficiency, "Eff"  , CPL_TYPE_DOUBLE);
00485     row = 0;
00486     
00487     for (order = 1; order <= norders; order++)
00488         {
00489         double lambda_min;
00490         double lambda_central_min;
00491         double lambda_central;
00492         double lambda_central_max;
00493         double lambda_max;
00494         double top_efficiency;
00495 
00496         abs_order = uves_absolute_order(first_abs_order, last_abs_order, order);
00497 
00498 
00499         check( lambda_min = uves_pfits_get_wstart(rebinned_header, order),
00500                "Error reading bin width from header");
00501 
00502         check( lambda_max = uves_pfits_get_wend(rebinned_header, order),
00503                "Error reading bin width from header");
00504         
00505         lambda_central_min = lambda_min + 0.4 * (lambda_max - lambda_min);
00506         lambda_central     = lambda_min + 0.5 * (lambda_max - lambda_min);
00507         lambda_central_max = lambda_min + 0.6 * (lambda_max - lambda_min);
00508         
00509         /* Select rows in this order in range 
00510            ]lambda_central_min ; lambda_central_max[ */
00511         cpl_table_select_all(*efficiency);
00512         cpl_table_and_selected_int   (*efficiency, "Order", 
00513                           CPL_EQUAL_TO    , order);
00514         cpl_table_and_selected_double(*efficiency, "Wave" , 
00515                           CPL_GREATER_THAN, lambda_central_min);
00516         cpl_table_and_selected_double(*efficiency, "Wave" , 
00517                           CPL_LESS_THAN   , lambda_central_max);
00518         
00519         uves_msg_debug("%" CPL_SIZE_FORMAT " bins in central 20 %% range of order #%d",
00520                    cpl_table_count_selected(*efficiency), order);
00521         
00522         if ( cpl_table_count_selected(*efficiency) > 0)
00523             {
00524             uves_free_table(&central_efficiency);
00525             central_efficiency = cpl_table_extract_selected(*efficiency);
00526             
00527             /* Get 90% percentile efficiency */
00528             uves_sort_table_1(central_efficiency, "Eff", false);     /* Ascending */
00529             
00530             top_efficiency = cpl_table_get_double(
00531                 central_efficiency, "Eff", 
00532                 (int) (0.9 * cpl_table_get_nrow(central_efficiency)), NULL);
00533             }
00534         else
00535             {
00536             uves_msg_debug("No wavelength bins in central 20%% range of order #%d",
00537                        order);
00538             top_efficiency = 0;
00539             }
00540         
00541         uves_msg("Efficiency(lambda = %.2f A) = %.2f%%", 
00542              lambda_central, top_efficiency*100);
00543 
00544         check(( cpl_table_set_int   (*blaze_efficiency, "Order", row, order),
00545             cpl_table_set_double(*blaze_efficiency, "Wave" , row, lambda_central),
00546             cpl_table_set_double(*blaze_efficiency, "Eff"  , row, top_efficiency),
00547             row++),
00548                "Error updating blaze efficiency table");
00549         } /* for order */
00550     }
00551 
00552   cleanup:
00553     uves_free_image(&background);
00554     uves_free_image(&rebinned_spectrum);
00555     uves_free_image(&rebinned_noise);
00556     uves_free_image(&merged_sky);
00557     uves_free_image(&merged_spectrum);
00558     uves_free_image(&merged_noise);
00559     uves_free_image(&reduced_spectrum);
00560     uves_free_image(&reduced_noise);
00561     uves_free_image(&reduced_rebinned);
00562     uves_free_image(&reduced_rebinned_noise);
00563     uves_free_propertylist(&reduced_header);
00564     uves_free_propertylist(&rebinned_header);
00565     uves_polynomial_delete(&disprel_1d);
00566 
00567     uves_free_image(&response_orders);
00568     uves_free_image(&efficiency_spectrum);
00569     uves_free_table(&central_efficiency);
00570     uves_free_table(&info_tbl);
00571     
00572     cpl_free(ref_obj_id);
00573 
00574     if (cpl_error_get_code() != CPL_ERROR_NONE)
00575     {
00576         uves_free_table(efficiency);
00577         uves_free_table(blaze_efficiency);
00578     }
00579     
00580     return cpl_error_get_code();
00581 }

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