FORS Pipeline Reference Manual 4.9.20
fors_img_science_impl.c
00001 /* $Id: fors_img_science_impl.c,v 1.49 2013/02/15 10:54:52 cgarcia Exp $
00002  *
00003  * This file is part of the FORS Library
00004  * Copyright (C) 2002-2010 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00019  */
00020 
00021 /*
00022  * $Author: cgarcia $
00023  * $Date: 2013/02/15 10:54:52 $
00024  * $Revision: 1.49 $
00025  * $Name: fors-4_9_20 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 #include <fors_img_science_impl.h>
00033 
00034 #include <fors_extract.h>
00035 #include <fors_tools.h>
00036 #include <fors_setting.h>
00037 #include <fors_data.h>
00038 #include <fors_image.h>
00039 #include <fors_qc.h>
00040 #include <fors_dfs.h>
00041 #include <fors_utils.h>
00042 
00043 #include <cpl.h>
00044 #include <math.h>
00045 #include <stdbool.h>
00046 
00053 const char *const fors_img_science_name = "fors_img_science";
00054 const char *const fors_img_science_description_short = "Reduce scientific exposure";
00055 const char *const fors_img_science_author = "Jonas M. Larsen";
00056 const char *const fors_img_science_email = PACKAGE_BUGREPORT;
00057 const char *const fors_img_science_description = 
00058 "Input files:\n"
00059 "  DO category:               Type:       Explanation:             Number:\n"
00060 "  SCIENCE_IMG                Raw         Science image               1\n"
00061 "  MASTER_BIAS                FITS image  Master bias                 1\n"
00062 "  MASTER_SKY_FLAT_IMG        FITS image  Master sky flat field       1\n"
00063 "\n"
00064 "Output files:\n"
00065 "  DO category:               Data type:  Explanation:\n"
00066 "  SCIENCE_REDUCED_IMG        FITS image  Reduced science image\n"
00067 "  PHOT_BACKGROUND_SCI_IMG    FITS image  Reduced science image background\n"
00068 "  SOURCES_SCI_IMG            FITS image  Unfiltered SExtractor output\n"
00069 "  OBJECT_TABLE_SCI_IMG       FITS table  Extracted sources properties\n";
00070 
00071 
00072 static double
00073 get_image_quality(const fors_star_list *sources, double *image_quality_err,
00074                   double *stellarity,
00075                   double *ellipticity,
00076                   double *ellipticity_rms);
00077 
00078 #undef cleanup
00079 #define cleanup \
00080 do { \
00081     cpl_free((void *)full_name); \
00082 } while (0)
00083 
00089 void fors_img_science_define_parameters(cpl_parameterlist *parameters)
00090 {
00091     cpl_parameter *p;
00092     const char *context = cpl_sprintf("fors.%s", fors_img_science_name);
00093     const char *full_name = NULL;
00094     const char *name;
00095 
00096     /*  This parameter is not yet implemented
00097     name = "cr_remove";
00098     full_name = cpl_sprintf("%s.%s", context, name);
00099     p = cpl_parameter_new_value(full_name,
00100                                 CPL_TYPE_BOOL,
00101                                 "Cosmic ray removal",
00102                                 context,
00103                                 false);
00104     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00105     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00106     cpl_parameterlist_append(parameters, p);
00107     cpl_free((void *)full_name); full_name = NULL;
00108     */
00109 
00110     name = "magsyserr";
00111     full_name = cpl_sprintf("%s.%s", context, name);
00112     p = cpl_parameter_new_value(full_name,
00113                                 CPL_TYPE_DOUBLE,
00114                                 "Systematic error in magnitude",
00115                                 context,
00116                                 0.01);
00117     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00118     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00119     cpl_parameterlist_append(parameters, p);
00120     cpl_free((void *)full_name); full_name = NULL;
00121 
00122     fors_extract_define_parameters(parameters, context);
00123     
00124     cpl_free((void *)context);
00125 
00126     return;
00127 }
00128 
00129 
00130 #undef cleanup
00131 #define cleanup \
00132 do { \
00133     cpl_frameset_delete(sci_frame); \
00134     cpl_frameset_delete(master_bias_frame); \
00135     cpl_frameset_delete(master_flat_frame); \
00136     fors_image_delete(&sci); \
00137     fors_image_delete_const(&master_bias); \
00138     fors_image_delete(&master_flat); \
00139     cpl_table_delete(phot); \
00140     cpl_table_delete(sources); \
00141     cpl_image_delete(background); \
00142     fors_extract_method_delete(&em); \
00143     fors_star_list_delete(&stars, fors_star_delete); \
00144     cpl_free((void *)context); \
00145     fors_setting_delete(&setting); \
00146     cpl_propertylist_delete(qc); \
00147     cpl_propertylist_delete(product_header); \
00148     cpl_propertylist_delete(header); \
00149 } while (0)
00150 
00151 /* %%% Removed from cleanup
00152     cpl_frameset_delete(phot_table); \
00153 */
00154 
00161 void fors_img_science(cpl_frameset *frames, const cpl_parameterlist *parameters)
00162 {
00163     /* Raw */
00164     cpl_frameset *sci_frame      = NULL;
00165     fors_image *sci              = NULL;
00166 
00167     /* Calibration */
00168     cpl_frameset *master_bias_frame = NULL;
00169     const fors_image *master_bias   = NULL; 
00170 
00171     cpl_frameset *master_flat_frame = NULL;
00172     fors_image *master_flat         = NULL; 
00173 
00174 /* %%%
00175     cpl_frameset *phot_table        = NULL;
00176     double ext_coeff, dext_coeff;
00177 */
00178 
00179     /* Products */
00180     cpl_propertylist *qc = cpl_propertylist_new();
00181     cpl_propertylist *product_header = cpl_propertylist_new();
00182     cpl_propertylist *header = NULL;
00183     cpl_table *phot = NULL;
00184     fors_extract_sky_stats sky_stats;
00185     cpl_image *background = NULL;
00186     cpl_table *sources = NULL;
00187 
00188     /* Parameters */
00189     extract_method  *em = NULL;
00190     double           magsyserr;
00191 
00192     /* Other */
00193     const char *context   = cpl_sprintf("fors.%s", fors_img_science_name);
00194     fors_star_list *stars = NULL;
00195     fors_setting *setting = NULL;
00196     double avg_airmass = 0.0;
00197     char *name;
00198 
00199     /* Get parameters */
00200     em = fors_extract_method_new(parameters, context);
00201     assure( !cpl_error_get_code(), return, 
00202             "Could not get extraction parameters" );
00203 
00204     cpl_msg_indent_more();
00205     name = cpl_sprintf("%s.%s", context, "magsyserr");
00206     magsyserr = dfs_get_parameter_double_const(parameters,
00207                                                name);
00208     cpl_free((void *)name); name = NULL;
00209     cpl_msg_indent_less();
00210     assure( !cpl_error_get_code(), return, NULL );
00211     assure( magsyserr >= 0, return, 
00212             "Input systematic error (magsyserr=%f) cannot be negative",
00213             magsyserr);
00214     
00215     /* Find raw */
00216     sci_frame = fors_frameset_extract(frames, SCIENCE_IMG);
00217     assure( cpl_frameset_get_size(sci_frame) == 1, return, 
00218             "Exactly 1 %s required. %"CPL_SIZE_FORMAT" found", 
00219             SCIENCE_IMG, cpl_frameset_get_size(sci_frame) );
00220 
00221     /* Find calibration */
00222     master_bias_frame = fors_frameset_extract(frames, MASTER_BIAS);
00223     assure( cpl_frameset_get_size(master_bias_frame) == 1, return, 
00224             "One %s required. %"CPL_SIZE_FORMAT" found", 
00225             MASTER_BIAS, cpl_frameset_get_size(master_bias_frame) );
00226 
00227     master_flat_frame = fors_frameset_extract(frames, MASTER_SKY_FLAT_IMG);
00228     assure( cpl_frameset_get_size(master_flat_frame) == 1, return, 
00229             "One %s required. %"CPL_SIZE_FORMAT" found", 
00230             MASTER_SKY_FLAT_IMG, cpl_frameset_get_size(master_flat_frame) );
00231 
00232 /* %%%
00233     phot_table = fors_frameset_extract(frames, PHOT_TABLE);
00234     assure( cpl_frameset_get_size(phot_table) == 1, return, 
00235             "One %s required. %d found",
00236             PHOT_TABLE, cpl_frameset_get_size(phot_table));
00237 */
00238 
00239     /* Done finding frames */
00240 
00241     /* Get instrument setting */
00242     setting = fors_setting_new(cpl_frameset_get_first(sci_frame));
00243     assure( !cpl_error_get_code(), return, "Could not get instrument setting" );
00244 
00245 
00246     master_bias = fors_image_load(cpl_frameset_get_first(master_bias_frame), 
00247                                   NULL, setting, NULL);
00248     assure( !cpl_error_get_code(), return, 
00249             "Could not load master bias");
00250 
00251     /* Load raw frames, subtract bias */
00252     sci = fors_image_load(cpl_frameset_get_first(sci_frame), master_bias, 
00253                           setting, NULL);
00254     assure( !cpl_error_get_code(), return, "Could not load standard image");
00255     fors_image_delete_const(&master_bias);
00256 
00257     /* Load master flat */
00258     master_flat = fors_image_load(cpl_frameset_get_first(master_flat_frame), 
00259                                   NULL, setting, NULL);
00260     assure( !cpl_error_get_code(), return, "Could not load master flat");
00261     
00262     /* Divide by normalized flat */
00263     fors_image_divide_scalar(master_flat,
00264                              fors_image_get_median(master_flat, NULL), -1.0);
00265 
00266     fors_image_divide(sci, master_flat);
00267     assure( !cpl_error_get_code(), return, "Could not divide by master flat");
00268     fors_image_delete(&master_flat);
00269 
00270     /* Extract sources */
00271     stars = fors_extract(sci, setting, em, magsyserr,
00272              &sky_stats, &background, &sources);
00273     assure( !cpl_error_get_code(), return, "Could not extract objects");  
00274 
00275     /* QC */
00276     fors_qc_start_group(qc, fors_qc_dic_version, setting->instrument);
00277     
00278     fors_qc_write_group_heading(cpl_frameset_get_first(sci_frame),
00279                                 PHOTOMETRY_TABLE,
00280                                 setting->instrument);
00281     assure( !cpl_error_get_code(), return, "Could not write %s QC parameters", 
00282             PHOTOMETRY_TABLE);
00283 
00284 
00285     double sky_mag;
00286     double sky_mag_rms;
00287     if (sky_stats.mean > 0) {
00288         sky_mag = -2.5*log(sky_stats.mean /
00289                            (setting->pixel_scale*setting->pixel_scale))/log(10);
00290     }
00291     else {
00292         cpl_msg_warning(cpl_func, 
00293                         "Average sky background is negative (%f ADU), "
00294                         "cannot compute magnitude, setting QC.SKYAVG to 99999.",
00295                         sky_stats.mean);
00296         sky_mag = 99999.;
00297     }
00298     fors_qc_write_qc_double(qc,
00299                             sky_mag,
00300                             "QC.SKYAVG",
00301                             "mag/arcsec^2",
00302                             "Mean of sky background",
00303                             setting->instrument);
00304     
00305     if (sky_stats.median > 0) {
00306         sky_mag = -2.5*log(sky_stats.median /
00307                            (setting->pixel_scale*setting->pixel_scale))/log(10);
00308         /* deltaM = -2.5*log10(e)*deltaF/F */
00309         sky_mag_rms = fabs(-2.5 * (1.0/log(10))*sky_stats.rms/sky_stats.median);
00310     }
00311     else {
00312         cpl_msg_warning(cpl_func, 
00313                         "Median sky background is negative (%f ADU), "
00314                         "cannot compute magnitude: setting both QC.SKYMED "
00315                         "and QC.SKYRMS to 99999.",
00316                         sky_mag);
00317         sky_mag = 99999.;
00318         sky_mag_rms = 99999.;
00319     }
00320     fors_qc_write_qc_double(qc,
00321                             sky_mag,
00322                             "QC.SKYMED",
00323                             "mag/arcsec^2",
00324                             "Median of sky background",
00325                             setting->instrument);
00326 
00327     fors_qc_write_qc_double(qc,
00328                             sky_mag_rms,
00329                             "QC.SKYRMS",
00330                             "mag/arcsec^2",
00331                             "Standard deviation of sky background",
00332                             setting->instrument);
00333 
00334     double image_quality_error;
00335     double stellarity;
00336     double ellipticity, ellipticity_rms;
00337     double image_quality = get_image_quality(stars, 
00338                                              &image_quality_error,
00339                                              &stellarity,
00340                                              &ellipticity,
00341                                              &ellipticity_rms);
00342 
00343     if (image_quality > 0.) {
00344         image_quality *= TWOSQRT2LN2 * setting->pixel_scale;
00345         image_quality_error *= TWOSQRT2LN2 * setting->pixel_scale;
00346     }
00347 
00348     fors_qc_write_qc_double(qc,
00349                             image_quality,
00350                             "QC.IMGQU",
00351                             "arcsec",
00352                             "Image quality of scientific exposure",
00353                             setting->instrument);
00354 
00355     fors_qc_write_qc_double(qc,
00356                             image_quality_error,
00357                             "QC.IMGQUERR",
00358                             "arcsec",
00359                             "Uncertainty of image quality",
00360                             setting->instrument);
00361 
00362     fors_qc_write_qc_double(qc,
00363                             stellarity,
00364                             "QC.STELLAVG",
00365                             NULL,
00366                             "Mean stellarity index",
00367                             setting->instrument);
00368 
00369     fors_qc_write_qc_double(qc,
00370                             ellipticity,
00371                             "QC.IMGQUELL",
00372                             NULL,
00373                             "Mean star ellipticity",
00374                             setting->instrument);
00375 
00376     fors_qc_write_qc_double(qc,
00377                             ellipticity_rms,
00378                             "QC.IMGQUELLERR",
00379                             NULL,
00380                             "Standard deviation of star ellipticities",
00381                             setting->instrument);
00382 
00383     fors_qc_end_group();
00384 
00385     /* Save SCIENCE_REDUCED, PHOT_BACKGROUND_SCI_IMG */
00386 
00387 /* %%% */
00388 
00389     header = cpl_propertylist_load(
00390                         cpl_frame_get_filename(
00391                            cpl_frameset_get_first(sci_frame)), 0);
00392 
00393     if (header == NULL) {
00394         cpl_msg_error(cpl_func, "Failed to load raw header");
00395         cleanup;
00396         return;
00397     }
00398 
00399     avg_airmass = fors_get_airmass(header);
00400 
00401     cpl_propertylist_update_double(qc, "AIRMASS", avg_airmass);
00402     cpl_propertylist_update_double(product_header, "AIRMASS", avg_airmass);
00403 
00404 /* %%% */
00405 
00406     fors_dfs_add_wcs(qc, cpl_frameset_get_first(sci_frame), setting);
00407     fors_dfs_add_exptime(qc, cpl_frameset_get_first(sci_frame), 0.);
00408     fors_dfs_add_wcs(product_header, cpl_frameset_get_first(sci_frame), 
00409                      setting);
00410     fors_dfs_add_exptime(product_header, cpl_frameset_get_first(sci_frame), 0.);
00411 
00412     fors_dfs_save_image(frames, sci, SCIENCE_REDUCED_IMG,
00413                         qc, parameters, fors_img_science_name, 
00414                         cpl_frameset_get_first(sci_frame));
00415     assure( !cpl_error_get_code(), return, "Saving %s failed",
00416             SCIENCE_REDUCED_IMG);
00417 
00418     fors_image_delete(&sci);
00419     
00420     dfs_save_image(frames, background, PHOT_BACKGROUND_SCI_IMG,
00421                    product_header, parameters, fors_img_science_name, 
00422                    setting->version);
00423     assure( !cpl_error_get_code(), return, "Saving %s failed",
00424             PHOT_BACKGROUND_SCI_IMG);
00425 
00426     cpl_image_delete(background); background = NULL;
00427     
00428     /* Load filter coefficients */
00429 
00430 /* %%%
00431     fors_phot_table_load(cpl_frameset_get_first(phot_table), setting,
00432                          NULL, NULL, 
00433              &ext_coeff, &dext_coeff,
00434              NULL, NULL);
00435     assure( !cpl_error_get_code(), return, "Could not load photometry table" );
00436 */
00437 
00438     /* Correct for atmospheric extinction */
00439 /* %%%
00440     fors_star_ext_corr(stars, setting, ext_coeff, dext_coeff,
00441                        cpl_frameset_get_first(sci_frame));
00442     assure( !cpl_error_get_code(), return, 
00443             "Extinction correction failed");
00444 */
00445 
00446     /* Create, save FITS product */
00447     phot = fors_create_sources_table(stars);
00448     assure( !cpl_error_get_code(), return,
00449             "Failed to create extracted sources table");
00450 
00451     /*
00452      * Eliminate unused columns from photometry table
00453      */
00454 
00455     cpl_table_erase_column(phot, "INSTR_CMAG");
00456     cpl_table_erase_column(phot, "DINSTR_CMAG");
00457     cpl_table_erase_column(phot, "OBJECT");
00458     cpl_table_erase_column(phot, "MAG");
00459     cpl_table_erase_column(phot, "DMAG");
00460     cpl_table_erase_column(phot, "CAT_MAG");
00461     cpl_table_erase_column(phot, "DCAT_MAG");
00462     cpl_table_erase_column(phot, "COLOR");
00463     /* new columns since 4.4.10 */
00464     if (cpl_table_has_column(phot, "DCOLOR"))
00465         cpl_table_erase_column(phot, "DCOLOR");
00466     if (cpl_table_has_column(phot, "COV_CATM_COL"))
00467         cpl_table_erase_column(phot, "COV_CATM_COL");
00468     cpl_table_erase_column(phot, "USE_CAT");
00469     cpl_table_erase_column(phot, "SHIFT_X");
00470     cpl_table_erase_column(phot, "SHIFT_Y");
00471     cpl_table_erase_column(phot, "ZEROPOINT");
00472     cpl_table_erase_column(phot, "DZEROPOINT");
00473     cpl_table_erase_column(phot, "WEIGHT");
00474 
00475     fors_dfs_save_table(frames, sources, SOURCES_SCI,
00476                         NULL, parameters, fors_img_science_name, 
00477                         cpl_frameset_get_first(sci_frame));
00478     assure( !cpl_error_get_code(), return, "Saving %s failed",
00479             SOURCES_SCI);
00480 
00481     fors_dfs_save_table(frames, phot, PHOTOMETRY_TABLE,
00482                         NULL, parameters, fors_img_science_name, 
00483                         cpl_frameset_get_first(sci_frame));
00484     assure( !cpl_error_get_code(), return, "Saving %s failed",
00485             PHOTOMETRY_TABLE);
00486 
00487     cleanup;
00488     return;
00489 }
00490 
00491 #undef cleanup
00492 #define cleanup
00493 
00499 static bool
00500 is_star(const fors_star *s, void *data)
00501 {
00502     data = data;
00503     assure( s != NULL, return false, NULL );
00504 
00505 /*FIXME
00506   All stars for the moment... */
00507 
00508     return s->stellarity_index >= 0.7;
00509 }
00510 
00511 #undef cleanup
00512 #define cleanup \
00513 do { \
00514     fors_star_list_delete(&stars, fors_star_delete); \
00515 } while(0)
00516 
00529 static double
00530 get_image_quality(const fors_star_list *sources, double *image_quality_err,
00531                   double *stellarity,
00532                   double *ellipticity,
00533                   double *ellipticity_rms)
00534 {
00535     fors_star_list *stars = fors_star_list_extract(sources,
00536                                                    fors_star_duplicate,
00537                                                    is_star, NULL);
00538 
00539     double fwhm;
00540     if (fors_star_list_size(stars) >= 1) {
00541         *image_quality_err = fors_star_list_mad(stars, fors_star_extension, NULL) 
00542             * STDEV_PR_MAD;
00543         
00544         fwhm = fors_star_list_median(stars, fors_star_extension , NULL);
00545         
00546         *stellarity      = fors_star_list_mean(stars, fors_star_stellarity, NULL);
00547         *ellipticity     = fors_star_list_mean(stars, fors_star_ellipticity, NULL);
00548         *ellipticity_rms = fors_star_list_mad(stars, fors_star_ellipticity, NULL)
00549             * STDEV_PR_MAD;
00550     }
00551     else {
00552         cpl_msg_warning(cpl_func, "No stars found! Cannot compute image quality, "
00553                         "setting QC parameters to -1");
00554 
00555         /* -1 is not a valid value for any of these */
00556         *image_quality_err = -1;
00557         fwhm = -1;
00558         *stellarity = -1;
00559         *ellipticity = -1;
00560         *ellipticity_rms = -1;
00561     }
00562 
00563     cleanup;
00564     return fwhm;
00565 }
00566