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: 2010/11/26 11:07:14 $
00023  * $Revision: 1.34 $
00024  * $Name: uves-4_9_1 $
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 
00151     /* Set parameters
00152        wavestep       = 10 * 2/3 * mean(pixelsize)
00153 
00154        After execution, revert to current value
00155     */
00156     {
00157     double smooth_step;
00158     
00159     /* wavestep */
00160     check( uves_get_parameter(parameters, NULL, 
00161                   make_str(UVES_RESPONSE_ID) "", "reduce.rebin.wavestep", 
00162                   CPL_TYPE_DOUBLE, &wavestep),
00163            "Error getting resampling step size");
00164     
00165     check( smooth_step = cpl_table_get_column_mean(linetable[1], LINETAB_PIXELSIZE),
00166            "Error reading mean pixelsize");
00167     
00168     smooth_step = 10*2*smooth_step/3;
00169         
00170     /* Cast to non-const is okay. The parameter is reset to its previous value
00171        (see below), so there is not net change (unless the reduction fails, 
00172        in which case parameter list will change).
00173     */
00174     check( uves_set_parameter((cpl_parameterlist *) parameters,
00175                   make_str(UVES_RESPONSE_ID) "", "reduce.rebin.wavestep",
00176                   CPL_TYPE_DOUBLE, &smooth_step),
00177            "Error setting resampling step size");
00178     }
00179     
00180     check( uves_reduce(raw_image, 
00181                        raw_header, 
00182                        rotated_header,
00183                master_bias,
00184                master_dark, 
00185                        mdark_header,
00186                NULL, 
00187                        NULL,                              /* No master flat */
00188                ordertable, 
00189                        order_locations,
00190                linetable, 
00191                        linetable_header, 
00192                        dispersion_relation,
00193                chip,
00194                DEBUG, 
00195                parameters, 
00196                        make_str(UVES_RESPONSE_ID),
00197                        ".efficiency",
00198                /* Output */
00199                NULL, 
00200                        NULL, 
00201                        NULL,                        /* 2d products */
00202                NULL,                        /* Cosmic ray table */
00203                &wave_map,
00204                &background,
00205                NULL, 
00206                        NULL,                        /* Variance of flat-fielded spectrum */
00207                NULL, 
00208                        NULL,                        /* Don't need these 
00209                                intermediate products */
00210                &merged_sky,
00211                &rebinned_spectrum, 
00212                        &rebinned_noise, 
00213                        &rebinned_header,
00214                &merged_spectrum, 
00215                        &merged_noise, 
00216                        &reduced_header,
00217                &reduced_rebinned, 
00218                        &reduced_rebinned_noise,
00219                &reduced_spectrum, 
00220                        &reduced_noise,
00221                        &info_tbl,
00222                &extraction_slit,   /* not passed on to the caller */
00223                        NULL),
00224        "Could not reduce frame");
00225     
00226     /* Reset parameter to previous value */
00227     {
00228     uves_msg_debug("Resetting parameter wavestep = %e", wavestep);
00229 
00230     /* Cast to non-const is okay. There is no net change in the parameter list (see above). */
00231     check( uves_set_parameter((cpl_parameterlist *) parameters, 
00232                   make_str(UVES_RESPONSE_ID) "", "reduce.rebin.wavestep", 
00233                   CPL_TYPE_DOUBLE, &wavestep),
00234            "Error resetting resampling step size");
00235     }
00236     
00237     
00238     /* Save reduced spectrum */
00239     if (DEBUG) 
00240     {
00241         /* Window number doesn't apply. This is middle window minus two other (sky) windows */
00242         check( uves_save_image_local("Reduced spectrum (2d)", "reduced", 
00243                      reduced_rebinned, chip, -1, -1, rebinned_header, true), 
00244            "Error saving reduced spectrum (2d)");
00245         
00246         check( uves_save_image_local("Reduced spectrum (2d) noise", "errreduced", 
00247                      reduced_rebinned_noise, chip, -1, -1, rebinned_header, true),
00248            "Error saving reduced spectrum (2d) noise");
00249 
00250         check( uves_save_image_local("Reduced spectrum", "merged", 
00251                      reduced_spectrum, chip, -1, -1, reduced_header, true), 
00252            "Error saving reduced spectrum");
00253         
00254         check( uves_save_image_local("Reduced spectrum noise", "errmerged", 
00255                      reduced_noise, chip, -1, -1, reduced_header, true), 
00256            "Error saving reduced spectrum noise");
00257     }
00258     
00259     uves_msg("Dividing by catalogue flux");
00260     /*
00261      * Calculate 2d response curve  (don't scale to unit exposure time, binning, gain, ... ) 
00262      */
00263     check( response_orders = uves_calculate_response(reduced_rebinned, rebinned_header,
00264                              flux_table,
00265                              raw_header, PACCURACY,
00266                              false,
00267                              &ref_obj_id),       /*  flux/std_flux  */
00268        "Could not calculate response curve");
00269 
00270     if (DEBUG)
00271     {
00272         check( uves_save_image_local("2d response curve", "resp",
00273                      response_orders, chip, -1, -1, rebinned_header, true),
00274            "Error saving 2d response curve");
00275     }
00276 
00277     /*
00278      *   Extinction correction, exposure time + gain
00279      */
00280     {
00281     int n_traces = cpl_image_get_size_y(merged_spectrum);    /* Number of spatial traces */
00282     
00283     assure( n_traces == 1, CPL_ERROR_ILLEGAL_INPUT,
00284         "2d extraction/reduction not supported");
00285     
00286     check( efficiency_spectrum = uves_normalize_spectrum(response_orders, NULL,
00287                                  /* Spectrum, noise */
00288                                  rebinned_header,
00289                                  raw_header,
00290                                  n_traces,
00291                                  chip,
00292                                  atm_extinction,
00293                                  false,  /* Don't divide by binning */
00294                                  NULL),  /* Don't need output noise */
00295            "Could not normalize spectrum");
00296     }
00297 
00298     /*
00299      *   7 x 1 median filter
00300      */
00301     uves_msg("Applying 7x1 median filter");
00302     check( uves_filter_image_median(&efficiency_spectrum, 3, 0, false),
00303        "Error applying median filter");
00304 
00305     
00306     uves_msg("Calculating quantum detection efficiency");
00307 
00308     {
00309     int nx, nbins, norders, order;
00310     int first_abs_order, last_abs_order, abs_order;  /* Absolute order numbers */
00311     double dlambda;
00312     double average_noise;               /* Median of noise of rebinned spectrum */
00313     int row = 0;                                       /* Next unused table row */
00314 
00315     double *efficiency_data;               /* For efficiency. cpl_image_get()   */
00316     double *reduced_noise_data;            /* is slow when there are bad pixels */
00317 
00318     efficiency_data    = cpl_image_get_data_double(efficiency_spectrum);
00319     reduced_noise_data = cpl_image_get_data_double(reduced_rebinned_noise);
00320 
00321     nx      = cpl_image_get_size_x(raw_image);
00322     nbins   = cpl_image_get_size_x(efficiency_spectrum);
00323     norders = cpl_image_get_size_y(efficiency_spectrum);
00324     
00325     *efficiency = cpl_table_new(nbins * norders);
00326     cpl_table_new_column(*efficiency, "Wave", CPL_TYPE_DOUBLE);
00327     cpl_table_new_column(*efficiency, "Eff", CPL_TYPE_DOUBLE);
00328     cpl_table_new_column(*efficiency, "Binsize", CPL_TYPE_DOUBLE);
00329     cpl_table_new_column(*efficiency, "Order", CPL_TYPE_INT);
00330     row = 0;
00331     
00332     check( first_abs_order = uves_pfits_get_firstabsorder(linetable_header[1]), 
00333            "Could not read order numbers from line table header");
00334     check( last_abs_order  = uves_pfits_get_lastabsorder (linetable_header[1]), 
00335            "Could not read order numbers from line table header");
00336     
00337     check( dlambda = uves_pfits_get_cdelt1(rebinned_header),
00338            "Error reading bin width from header");
00339     
00340     check( average_noise = cpl_image_get_median(reduced_rebinned_noise),
00341            "Error reading median noise level");
00342 
00343     for (order = 1; order <= norders; order++)
00344         {
00345         double lambda_start, lambda, lambda_end;
00346         double x;
00347         int bin;
00348 
00349         abs_order = uves_absolute_order(first_abs_order, last_abs_order, order);
00350 
00351         check( lambda_start = uves_pfits_get_wstart(rebinned_header, order),
00352                "Error reading start wavelength from header");
00353         
00354         check( lambda_end   = uves_pfits_get_wend(rebinned_header, order),
00355                "Error reading end wavelength from header");
00356 
00357         /* Get 1d dispersion relation for this order
00358            f_1d = f(x, m=abs_order) 
00359 
00360            Collapsing a polynomial is slow, so do it
00361            only once per order
00362         */
00363         uves_polynomial_delete(&disprel_1d);
00364         check( disprel_1d = uves_polynomial_collapse(dispersion_relation[1],
00365                                  2,  /* Independent variable number */
00366                                  abs_order),
00367                "Error getting 1d dispersion relation for absolute order #%d", abs_order);
00368 
00369         x = 1;
00370         for (lambda = lambda_start, bin = 1;
00371              lambda < lambda_end + 0.5 * dlambda && bin <= nbins; 
00372              bin++, lambda += dlambda)
00373             {
00374             double flux;
00375             double dldx;
00376             double noise;            /* Only use positions with low noise 
00377                             (middle of blaze function) */
00378             
00379             /* flux  = cpl_image_get(efficiency_spectrum, 
00380                                      bin, order, &pis_rejected);
00381                noise = cpl_image_get(reduced_rebinned_noise, 
00382                bin, order, &pis_rejected); */
00383             flux  = efficiency_data   [(bin-1) + (order-1) * nbins];
00384             noise = reduced_noise_data[(bin-1) + (order-1) * nbins];
00385 
00386 
00387             /*
00388              *   Energy per (time * area * wavelength) =
00389              *    ((electron counts)/gain) * (hc/lambda) / 
00390              *    (time * area * |dlambda/dx|)
00391              *
00392              *   We already divided by exposure time, gain
00393              *   We did not multiply by dlambda/dx during rebinning,
00394              *    so now is the time to do it
00395              */
00396 
00397             /* Solve  f(x,m) = m*lambda  for x.
00398              *
00399              * This is equivalent to solving f_1d(x) = m*lambda
00400             */
00401             
00402             check( x = uves_polynomial_solve_1d(
00403                    disprel_1d, 
00404                    abs_order * lambda, /* right hand side    */
00405                    x,                  /* guess              */
00406                    1),                 /* multiplicity       */
00407                    "Could not solve dispersion relation for x "
00408                    "at (m, lambda) = (%d, %f)", abs_order, lambda);
00409             
00410 
00411 
00412             /*  For constant absolute order number, m:
00413                 dl/dx  =  d (l.m)/dx / m  */
00414             
00415             check( dldx = fabs(uves_polynomial_derivative_2d(
00416                            dispersion_relation[1], 
00417                            x, 
00418                            abs_order, 1) / abs_order),
00419                    "Could not evaluate dispersion relation");
00420             
00421                         /* Don't make a linear interpolation
00422             weight = (lambda - lambda_start) / (lambda_end - lambda_start);
00423             
00424             check( dldx =
00425                    fabs(uves_polynomial_derivative_2d(
00426                     dispersion_relation[1],
00427                     1 , abs_order,
00428                     1) / abs_order) * (1 - weight) +
00429                    fabs(uves_polynomial_derivative_2d(
00430                     dispersion_relation[1],
00431                     nx, abs_order, 1) / abs_order) * weight,
00432                    "Could not evaluate dispersion relation");
00433             */
00434 
00435             flux = flux * 1e16 * 1e17 * H_BAR * SPEED_OF_LIGHT /
00436                 (dldx * lambda * TELESCOPE_EFFECTIVE_AREA);
00437             /* The factor 1e17 accounts for the conversion Joule<-erg
00438              * (10^7) and Angstrom->meters (10^10)
00439              * The factor 1e16 is to correct for the fact that the
00440              * catalogue flux is in units of (10^-16 <standard units>)
00441              */
00442 
00443             if (noise < 3*average_noise)
00444                 {
00445                 check(( cpl_table_set_double(*efficiency, "Wave", row, lambda),
00446                     cpl_table_set_double(*efficiency, "Eff",  row, flux),
00447                     cpl_table_set_double(*efficiency, "Binsize",  row, dldx),
00448                     cpl_table_set_int   (*efficiency, "Order",  row, order),
00449                     row++),
00450                        "Error updating efficiency table row %d", row);
00451                 }
00452             }
00453         }
00454     
00455     /* Remove unused rows of efficiency table */
00456     check( cpl_table_set_size(*efficiency, row), 
00457            "Error setting size of efficiency table to %d rows", row);
00458 
00459     /* Get the "top efficiency" (90% percentile efficiency of middle 20% of each order) */
00460 
00461     *blaze_efficiency = cpl_table_new(norders);
00462     cpl_table_new_column(*blaze_efficiency, "Order", CPL_TYPE_INT);
00463     cpl_table_new_column(*blaze_efficiency, "Wave" , CPL_TYPE_DOUBLE);
00464     cpl_table_new_column(*blaze_efficiency, "Eff"  , CPL_TYPE_DOUBLE);
00465     row = 0;
00466     
00467     for (order = 1; order <= norders; order++)
00468         {
00469         double lambda_min;
00470         double lambda_central_min;
00471         double lambda_central;
00472         double lambda_central_max;
00473         double lambda_max;
00474         double top_efficiency;
00475 
00476         abs_order = uves_absolute_order(first_abs_order, last_abs_order, order);
00477 
00478 
00479         check( lambda_min = uves_pfits_get_wstart(rebinned_header, order),
00480                "Error reading bin width from header");
00481 
00482         check( lambda_max = uves_pfits_get_wend(rebinned_header, order),
00483                "Error reading bin width from header");
00484         
00485         lambda_central_min = lambda_min + 0.4 * (lambda_max - lambda_min);
00486         lambda_central     = lambda_min + 0.5 * (lambda_max - lambda_min);
00487         lambda_central_max = lambda_min + 0.6 * (lambda_max - lambda_min);
00488         
00489         /* Select rows in this order in range 
00490            ]lambda_central_min ; lambda_central_max[ */
00491         cpl_table_select_all(*efficiency);
00492         cpl_table_and_selected_int   (*efficiency, "Order", 
00493                           CPL_EQUAL_TO    , order);
00494         cpl_table_and_selected_double(*efficiency, "Wave" , 
00495                           CPL_GREATER_THAN, lambda_central_min);
00496         cpl_table_and_selected_double(*efficiency, "Wave" , 
00497                           CPL_LESS_THAN   , lambda_central_max);
00498         
00499         uves_msg_debug("%d bins in central 20 %% range of order #%d", 
00500                    cpl_table_count_selected(*efficiency), order);
00501         
00502         if ( cpl_table_count_selected(*efficiency) > 0)
00503             {
00504             uves_free_table(&central_efficiency);
00505             central_efficiency = cpl_table_extract_selected(*efficiency);
00506             
00507             /* Get 90% percentile efficiency */
00508             uves_sort_table_1(central_efficiency, "Eff", false);     /* Ascending */
00509             
00510             top_efficiency = cpl_table_get_double(
00511                 central_efficiency, "Eff", 
00512                 (int) (0.9 * cpl_table_get_nrow(central_efficiency)), NULL);
00513             }
00514         else
00515             {
00516             uves_msg_debug("No wavelength bins in central 20%% range of order #%d", 
00517                        order);
00518             top_efficiency = 0;
00519             }
00520         
00521         uves_msg("Efficiency(lambda = %.2f A) = %.2f%%", 
00522              lambda_central, top_efficiency*100);
00523 
00524         check(( cpl_table_set_int   (*blaze_efficiency, "Order", row, order),
00525             cpl_table_set_double(*blaze_efficiency, "Wave" , row, lambda_central),
00526             cpl_table_set_double(*blaze_efficiency, "Eff"  , row, top_efficiency),
00527             row++),
00528                "Error updating blaze efficiency table");
00529         } /* for order */
00530     }
00531 
00532   cleanup:
00533     uves_free_image(&background);
00534     uves_free_image(&rebinned_spectrum);
00535     uves_free_image(&rebinned_noise);
00536     uves_free_image(&merged_sky);
00537     uves_free_image(&merged_spectrum);
00538     uves_free_image(&merged_noise);
00539     uves_free_image(&reduced_spectrum);
00540     uves_free_image(&reduced_noise);
00541     uves_free_image(&reduced_rebinned);
00542     uves_free_image(&reduced_rebinned_noise);
00543     uves_free_propertylist(&reduced_header);
00544     uves_free_propertylist(&rebinned_header);
00545     uves_polynomial_delete(&disprel_1d);
00546 
00547     uves_free_image(&response_orders);
00548     uves_free_image(&efficiency_spectrum);
00549     uves_free_table(&central_efficiency);
00550     uves_free_table(&info_tbl);
00551     
00552     cpl_free(ref_obj_id);
00553 
00554     if (cpl_error_get_code() != CPL_ERROR_NONE)
00555     {
00556         uves_free_table(efficiency);
00557         uves_free_table(blaze_efficiency);
00558     }
00559     
00560     return cpl_error_get_code();
00561 }

Generated on 8 Mar 2011 for UVES Pipeline Reference Manual by  doxygen 1.6.1