fors_zeropoint_impl.c

00001 /* $Id: fors_zeropoint_impl.c,v 1.83 2010/09/14 07:49:30 cizzo 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: cizzo $
00023  * $Date: 2010/09/14 07:49:30 $
00024  * $Revision: 1.83 $
00025  * $Name: fors-4_8_6 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 #include <fors_zeropoint_impl.h>
00033 
00034 #include <fors_extract.h>
00035 #include <fors_identify.h>
00036 #include <fors_tools.h>
00037 #include <fors_star.h>
00038 #include <fors_std_cat.h>
00039 #include <fors_std_star.h>
00040 #include <fors_image.h>
00041 #include <fors_instrument.h>
00042 #include <fors_data.h>
00043 #include <fors_setting.h>
00044 #include <fors_dfs.h>
00045 #include <fors_qc.h>
00046 #include <fors_pfits.h>
00047 #include <fors_utils.h>
00048 
00049 #include <cpl.h>
00050 
00051 #include <math.h>
00052 
00059 const char *const fors_zeropoint_name = "fors_zeropoint";
00060 const char *const fors_zeropoint_description_short = "Compute zeropoint";
00061 const char *const fors_zeropoint_author = "Jonas M. Larsen";
00062 const char *const fors_zeropoint_email = PACKAGE_BUGREPORT;
00063 const char *const fors_zeropoint_description = 
00064 "Input files:\n"
00065 "  DO category:               Type:       Explanation:              Number:\n"
00066 "  STANDARD_IMG               FITS image  Phot. standard field        1\n"
00067 "  MASTER_BIAS                FITS image  Master bias                 1\n"
00068 "  MASTER_SKY_FLAT_IMG        FITS image  Master sky flatfield        1\n"
00069 "  FLX_STD_IMG                FITS table  Standard star catalog       1+\n"
00070 "  PHOT_TABLE                 FITS table  Filter ext. coeff, color    1\n"
00071 "\n"
00072 "Output files:\n"
00073 "  DO category:               Data type:  Explanation:\n"
00074 "  SOURCES_STD_IMG            FITS image  Unfiltered SExtractor output\n"
00075 "  ALIGNED_PHOT               FITS table\n"
00076 "  PHOT_BACKGROUND_STD_IMG    FITS image  Reduced science image background\n"
00077 "  STANDARD_REDUCED_IMG       FITS image  Reduced std image\n";
00078 
00079 static double
00080 get_zeropoint(fors_star_list *stars, 
00081               double cutoffE,
00082               double cutoffk,
00083               double dext_coeff,
00084               double dcolor_term,
00085               double avg_airmass,
00086               double *dzeropoint,
00087               int *n);
00088 
00089 static cpl_error_code
00090 fors_zeropoint_astrometry(                  const cpl_frameset  *std_cat_frames,
00091                                             char                filter_band,
00092                                             double              color_correct,
00093                                             double              dcolor_correct,
00094                                             const identify_method
00095                                                                 *id_method,
00096                                             fors_star_list      *extracted,
00097                                             cpl_propertylist    *wcs_header,
00098                                             fors_std_star_list  **std_cat);
00099 
00100 static cpl_error_code
00101 fors_zeropoint_astrometry_get_wcs_shift_px( const fors_star_list    *stars,
00102                                             double                  *dx,
00103                                             double                  *dy);
00104 
00105 static cpl_error_code
00106 fors_zeropoint_astrometry_shift_wcs_origin( cpl_propertylist    *header,
00107                                             double  dx,
00108                                             double  dy);
00109 
00110 static cpl_error_code
00111 fors_zeropoint_astrometry_apply_unidentified_xy2radec(
00112                                             fors_star_list          *stars,
00113                                             const cpl_propertylist  *header);
00114 
00115 void
00116 fors_zeropoint_errorstate_dump_as_warning(  unsigned self,
00117                                             unsigned first,
00118                                             unsigned last);
00119 
00124 void fors_zeropoint_define_parameters(cpl_parameterlist *parameters)
00125 {
00126     const char *context = cpl_sprintf("fors.%s", fors_zeropoint_name);
00127     
00128     fors_extract_define_parameters(parameters, context);
00129 
00130     fors_identify_define_parameters(parameters, context);
00131     
00132     const char *name, *full_name;
00133     cpl_parameter *p;
00134 
00135     name = "magcutE";
00136     full_name = cpl_sprintf("%s.%s", context, name);
00137     p = cpl_parameter_new_value(full_name,
00138                                 CPL_TYPE_DOUBLE,
00139                                 "Zeropoint absolute cutoff (magnitude)",
00140                                 context,
00141                                 1.0);
00142     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00143     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00144     cpl_parameterlist_append(parameters, p);
00145     cpl_free((void *)full_name); full_name = NULL;
00146 
00147     name = "magcutk";
00148     full_name = cpl_sprintf("%s.%s", context, name);
00149     p = cpl_parameter_new_value(full_name,
00150                                 CPL_TYPE_DOUBLE,
00151                                 "Zeropoint kappa rejection parameter",
00152                                 context,
00153                                 5.0);
00154     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00155     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00156     cpl_parameterlist_append(parameters, p);
00157     cpl_free((void *)full_name); full_name = NULL;
00158 
00159 
00160     cpl_free((void *)context);
00161 
00162     return;
00163 }
00164 
00165 #undef cleanup
00166 #define cleanup \
00167 do { \
00168     cpl_frameset_delete(std_frame); \
00169     cpl_frameset_delete(master_bias_frame); \
00170     cpl_frameset_delete(master_flat_frame); \
00171     cpl_frameset_delete(std_cat_frames); \
00172     cpl_frameset_delete(phot_table); \
00173     fors_image_delete(&std); \
00174     fors_image_delete_const(&master_bias); \
00175     fors_image_delete(&master_flat); \
00176     cpl_table_delete(aligned_phot); \
00177     cpl_image_delete(background); \
00178     cpl_table_delete(sources); \
00179     fors_extract_method_delete(&em); \
00180     fors_identify_method_delete(&im); \
00181     fors_std_star_list_delete(&cat, fors_std_star_delete); \
00182     /* All std-stars (and non-std-stars) are linked by the respective star */ \
00183     /* objects in "stars", without being referenced by a std-star-list */ \
00184     /* object. So they are deleted together with the function */ \
00185     /* fors_star_delete() while deleting the list "stars". */ \
00186     fors_star_list_delete(&stars, fors_star_delete); \
00187     cpl_free((void *)context); \
00188     fors_setting_delete(&setting); \
00189     cpl_propertylist_delete(qc); \
00190     cpl_propertylist_delete(product_header); \
00191     cpl_propertylist_delete(raw_header); \
00192 } while (0)
00193 
00202 void fors_zeropoint(cpl_frameset *frames, const cpl_parameterlist *parameters)
00203 {
00204     /* Raw */
00205     cpl_frameset *std_frame      = NULL;
00206     fors_image *std              = NULL;
00207 
00208     /* Calibration */
00209     cpl_frameset *master_bias_frame = NULL;
00210     const fors_image *master_bias   = NULL; 
00211 
00212     cpl_frameset *master_flat_frame = NULL;
00213     fors_image *master_flat         = NULL; 
00214 
00215     cpl_frameset *std_cat_frames    = NULL;
00216     fors_std_star_list *cat         = NULL;
00217 
00218     cpl_frameset *phot_table        = NULL;
00219     double color_term, dcolor_term;
00220     double ext_coeff, dext_coeff;
00221     double expected_zeropoint, dexpected_zeropoint;
00222     
00223     
00224     cpl_propertylist *raw_header  = NULL;
00225     
00226     /* Products */
00227     int nzeropoint = -1;             /* Suppress warning */
00228     cpl_table *aligned_phot = NULL;
00229     cpl_propertylist *qc = NULL;
00230     double zeropoint, dzeropoint;
00231     fors_extract_sky_stats sky_stats;
00232     cpl_image *background = NULL;
00233     cpl_table *sources    = NULL;
00234     cpl_propertylist *product_header = NULL;
00235         
00236     /* Parameters */
00237     extract_method  *em = NULL;
00238     identify_method *im = NULL;
00239     double cutoffE, cutoffk;
00240 
00241     /* Other */
00242     const char *context   = NULL;
00243     fors_star_list *stars = NULL;
00244     fors_setting *setting = NULL;
00245     double avg_airmass = 0.0;
00246     
00247     qc = cpl_propertylist_new();
00248     product_header = cpl_propertylist_new();
00249     context = cpl_sprintf("fors.%s", fors_zeropoint_name);
00250     
00251     /* Get parameters */
00252     em = fors_extract_method_new(parameters, context);
00253     assure( !cpl_error_get_code(), return, 
00254             "Could not get extraction parameters" );
00255     
00256     im = fors_identify_method_new(parameters, context);
00257     assure( !cpl_error_get_code(), return, 
00258             "Could not get identification parameters" );
00259 
00260 
00261     cpl_msg_indent_more();
00262     const char *name = cpl_sprintf("%s.%s", context, "magcutE");
00263     cutoffE = dfs_get_parameter_double_const(parameters, 
00264                                             name);
00265     cpl_free((void *)name); name = NULL;
00266     cpl_msg_indent_less();
00267     assure( !cpl_error_get_code(), return, NULL );
00268         
00269     cpl_msg_indent_more();
00270     name = cpl_sprintf("%s.%s", context, "magcutk");
00271     cutoffk = dfs_get_parameter_double_const(parameters, 
00272                                              name);
00273     cpl_free((void *)name); name = NULL;
00274     cpl_msg_indent_less();
00275     assure( !cpl_error_get_code(), return, NULL );
00276         
00277     /* Find raw */
00278     std_frame = fors_frameset_extract(frames, STANDARD_IMG);
00279     assure( cpl_frameset_get_size(std_frame) == 1, return, 
00280             "Exactly 1 %s required. %d found", 
00281             STANDARD_IMG, cpl_frameset_get_size(std_frame) );
00282 
00283     /* Find calibration */
00284     master_bias_frame = fors_frameset_extract(frames, MASTER_BIAS);
00285     assure( cpl_frameset_get_size(master_bias_frame) == 1, return, 
00286             "One %s required. %d found", 
00287             MASTER_BIAS, cpl_frameset_get_size(master_bias_frame) );
00288 
00289     master_flat_frame = fors_frameset_extract(frames, MASTER_SKY_FLAT_IMG);
00290     assure( cpl_frameset_get_size(master_flat_frame) == 1, return, 
00291             "One %s required. %d found", 
00292             MASTER_SKY_FLAT_IMG, cpl_frameset_get_size(master_flat_frame) );
00293 
00294     std_cat_frames = fors_frameset_extract(frames, FLX_STD_IMG);
00295     assure( cpl_frameset_get_size(std_cat_frames) >= 1, return, 
00296             "One or more %s required. %d found",
00297             FLX_STD_IMG, cpl_frameset_get_size(std_cat_frames));
00298 
00299     phot_table = fors_frameset_extract(frames, PHOT_TABLE);
00300     assure( cpl_frameset_get_size(phot_table) == 1, return, 
00301             "One %s required. %d found",
00302             PHOT_TABLE, cpl_frameset_get_size(phot_table));
00303 
00304     /* Done finding frames */
00305 
00306     /* Get setting */
00307     setting = fors_setting_new(cpl_frameset_get_first(std_frame));
00308     assure( !cpl_error_get_code(), return, "Could not get instrument setting" );
00309     
00310     master_bias = fors_image_load(cpl_frameset_get_first(master_bias_frame), 
00311                                   NULL, setting, NULL);
00312     assure( !cpl_error_get_code(), return, 
00313             "Could not load master bias");
00314 
00315     /* Load raw frames, subtract bias */
00316     std = fors_image_load(cpl_frameset_get_first(std_frame), 
00317                           master_bias, setting, NULL);
00318     assure( !cpl_error_get_code(), return, "Could not load standard image");
00319     fors_image_delete_const(&master_bias);
00320 
00321     /* Load master flat */
00322     master_flat = fors_image_load(cpl_frameset_get_first(master_flat_frame), 
00323                                   NULL, setting, NULL);
00324     assure( !cpl_error_get_code(), return, "Could not load master flat");
00325     
00326     /* Divide by flat */
00327     fors_image_divide_scalar(master_flat,
00328                              fors_image_get_median(master_flat, NULL), -1.0);
00329     fors_image_divide(std, master_flat);
00330     assure( !cpl_error_get_code(), return, "Could not divide by master flat");
00331     fors_image_delete(&master_flat);
00332 
00333     /* Extract sources */
00334     stars = fors_extract(std, setting, em, 
00335                          &sky_stats, &background, &sources);
00336     assure( !cpl_error_get_code(), return, "Could not extract objects");
00337 
00338 /* %%% Moved by Carlo - start */
00339 
00340     /* load raw frame header */
00341     raw_header = cpl_propertylist_load(
00342                     cpl_frame_get_filename(
00343                         cpl_frameset_get_first(std_frame)), 0);
00344 
00345     if (raw_header == NULL) {
00346         cpl_msg_error(cpl_func, "Failed to load raw header");
00347         cleanup;
00348         return;
00349     }
00350 
00351     avg_airmass = fors_get_airmass(raw_header);
00352 
00353 /* %%% Moved by Carlo - end */
00354 
00355     if (setting->filter_name != NULL)
00356     {
00357         char            filter_band;
00358         cpl_errorstate  local_ers = cpl_errorstate_get();
00359         
00360         /* load raw frame header */
00361 
00362 /* Moved outside by Carlo - start
00363 
00364         raw_header = cpl_propertylist_load(
00365                         cpl_frame_get_filename(
00366                             cpl_frameset_get_first(std_frame)), 0);
00367         assure(                             cpl_errorstate_is_equal(local_ers),
00368                                             return,
00369                                             "Failed to load raw header");
00370 Moved outside by Carlo - end */
00371         
00372         /* Load filter coefficients */
00373         fors_phot_table_load(cpl_frameset_get_first(phot_table), setting,
00374                              &color_term, &dcolor_term,
00375                              &ext_coeff, &dext_coeff,
00376                              &expected_zeropoint, &dexpected_zeropoint);
00377         assure(                             cpl_errorstate_is_equal(local_ers),
00378                                             return,
00379                                             "Could not load photometry table" );
00380 
00381         filter_band = fors_instrument_filterband_get_by_setting(setting);
00382         
00383         /* Do the whole astrometry:
00384          * load catalogue, apply wcs, do pattern-matching, correct wcs
00385          * (treat errors only as warnings)
00386          */
00387         cpl_msg_info(cpl_func, "Astrometry:");
00388         cpl_msg_indent_more();
00389         fors_zeropoint_astrometry(          std_cat_frames,
00390                                             filter_band,
00391                                             color_term,
00392                                             dcolor_term,
00393                                             im,
00394                                             stars,      /* sources */
00395                                             raw_header, /* wcs */
00396                                             &cat);      /* to draw debug-img */
00397         cpl_msg_indent_less();
00398         if (!cpl_errorstate_is_equal(local_ers))
00399         {
00400             cpl_msg_warning(cpl_func, "Astrometric calibration failed:");
00401             cpl_msg_indent_more();
00402             cpl_errorstate_dump(local_ers,
00403                                 CPL_FALSE,
00404                                 fors_zeropoint_errorstate_dump_as_warning);
00405             cpl_msg_indent_less();
00406             /* reset error */
00407             cpl_errorstate_set(local_ers);
00408         }
00409         /* The astrometric calibration could fail but nonetheless have
00410          * succeeded in identifying some standard stars. So continue trying to
00411          * get the zeropoint anyway. */
00412 
00413         /* Correct for atmospheric extinction, gain, exposure time */
00414         /* FIXME: FAP: use WCS corrected header */
00415         avg_airmass = fors_star_ext_corr(   stars,
00416                                             setting,
00417                                             ext_coeff,
00418                                             dext_coeff,
00419                                             cpl_frameset_get_first(std_frame));
00420         /* Get zeropoint. */
00421         if (cpl_errorstate_is_equal(local_ers))
00422         {
00423             zeropoint = get_zeropoint(      stars,
00424                                             cutoffE,
00425                                             cutoffk,
00426                                             dext_coeff,
00427                                             dcolor_term,
00428                                             avg_airmass,
00429                                             &dzeropoint,
00430                                             &nzeropoint);
00431         }
00432         
00433         if (!cpl_errorstate_is_equal(local_ers))
00434         {
00435             cpl_msg_warning(cpl_func, "Failed to get zeropoint");
00436             cpl_msg_indent_more();
00437             cpl_errorstate_dump(local_ers,
00438                                 CPL_FALSE,
00439                                 fors_zeropoint_errorstate_dump_as_warning);
00440             cpl_msg_indent_less();
00441             /* reset error */
00442             cpl_errorstate_set(local_ers);
00443         }
00444     }
00445     else {
00446        cpl_msg_warning(cpl_func, "Zeropoint computation is not supported "
00447                        "for non-standard filters");
00448        color_term = 0.0;
00449        dcolor_term = 9999.0;
00450        ext_coeff = 0.0;
00451        dext_coeff = 9999.0;
00452        expected_zeropoint = 0.0;
00453        dexpected_zeropoint = 9999.0;
00454        zeropoint = 0.0;
00455        dzeropoint = 0.0;
00456        nzeropoint = 0;
00457     }
00458 
00459     /* QC */
00460     fors_qc_start_group(qc, fors_qc_dic_version, setting->instrument);
00461     
00462     /* FIXME: FAP: use WCS corrected header */
00463     fors_qc_write_group_heading(cpl_frameset_get_first(std_frame),
00464                                 ALIGNED_PHOT,
00465                                 setting->instrument);
00466     assure( !cpl_error_get_code(), return, "Could not write %s QC parameters", 
00467             ALIGNED_PHOT);
00468 
00469 
00470     fors_qc_write_qc_double(qc,
00471                             zeropoint,
00472                             "QC.ZPOINT",
00473                             "mag",
00474                             "Frame zeropoint",
00475                             setting->instrument);
00476     fors_qc_write_qc_double(qc,
00477                             dzeropoint,
00478                             "QC.ZPOINTRMS",
00479                             "mag",
00480                             "Uncertainty of frame zeropoint",
00481                             setting->instrument);
00482     fors_qc_write_qc_int(qc,
00483                          nzeropoint,
00484                          "QC.ZPOINT.NSTARS",
00485                          NULL,
00486                          "Number of stars used for zeropoint computation",
00487                          setting->instrument);
00488     
00489     double derived_ext_coeff, derived_ext_coeff_err;
00490 
00491     if (setting->filter_name != NULL) {
00492         cpl_msg_info(cpl_func,
00493                      "Computing extinction "
00494                      "(assuming zeropoint = %.3f +- %.3f mag)",
00495                      expected_zeropoint,
00496                      dexpected_zeropoint);
00497 
00498         cpl_msg_indent_more();
00499 
00500         if (nzeropoint > 0) {
00501             derived_ext_coeff = ext_coeff +
00502                 (expected_zeropoint - zeropoint) / avg_airmass;
00503             /* Things are very correlated here
00504                (e.g. ext_coeff was used to compute zeropoint).
00505            
00506                The final error on the ext.coeff. depends only
00507                on the reference and computed zeropoints' errors. 
00508                The airmass is assumed errorless.
00509 
00510                We assume the 2 zeropoints' errors are not correlated and
00511                add in quadrature.
00512 
00513                The derived extinction's error does not suffer from the part
00514                of dzeropoint which was due to the error of the assumed 
00515                extinction.
00516             */
00517             derived_ext_coeff_err = sqrt(
00518                 dexpected_zeropoint*dexpected_zeropoint +
00519                 dzeropoint*dzeropoint) / avg_airmass - dext_coeff*dext_coeff;
00520     
00521             cpl_msg_info(cpl_func, "Atmospheric extinction = "
00522                          "%f +- %f mag/airmass", derived_ext_coeff,
00523                          derived_ext_coeff_err);
00524         }
00525         else {
00526             cpl_msg_warning(cpl_func, "Too few stars available, "
00527                             "setting extinction to zero");
00528             derived_ext_coeff = 0;
00529             derived_ext_coeff_err = 9999;
00530         }
00531     }
00532     else {
00533         derived_ext_coeff = 0;
00534         derived_ext_coeff_err = 9999;
00535     }
00536 
00537     fors_qc_write_qc_double(qc,
00538                             derived_ext_coeff,
00539                             "QC.EXTCOEFF",
00540                             "mag/airmass",
00541                             "Atmospheric extinction (mag/airmass)",
00542                             setting->instrument);
00543 
00544     fors_qc_write_qc_double(qc,
00545                             derived_ext_coeff_err,
00546                             "QC.EXTCOEFFERR",
00547                             "mag/airmass",
00548                             "Error on atmospheric extinction (mag/airmass)",
00549                             setting->instrument);
00550     cpl_msg_indent_less();
00551 
00552     fors_qc_end_group();
00553 
00554 
00555     /* Convert to CPL table */
00556     aligned_phot = fors_create_sources_table(stars);
00557     assure( !cpl_error_get_code(), return,
00558             "Failed to create aligned photometry table");
00559 
00560     /* Save products */
00561     /* FIXME: FAP: use WCS corrected header */
00562     fors_dfs_save_table(frames, sources, SOURCES_STD,
00563                         NULL, parameters, fors_zeropoint_name, 
00564                         cpl_frameset_get_first(std_frame));
00565     assure( !cpl_error_get_code(), return, "Saving %s failed",
00566             SOURCES_STD);
00567 
00568     /* Add keywords necessary for fors_photometry 
00569        (just reuse/overload to the qc propertylist variable)
00570     */
00571     cpl_propertylist_update_double(qc, FORS_PFITS_EXPOSURE_TIME, 
00572                                    setting->exposure_time);
00573     cpl_propertylist_update_double(qc, "AIRMASS", avg_airmass);
00574     
00575     cpl_table_fill_invalid_int(aligned_phot, "USE_CAT", 2);
00576     /* FIXME: FAP: use WCS corrected header */
00577     fors_dfs_save_table(frames, aligned_phot, ALIGNED_PHOT,
00578                         qc, parameters, fors_zeropoint_name, 
00579                         cpl_frameset_get_first(std_frame));
00580     assure( !cpl_error_get_code(), return, "Saving %s failed",
00581             ALIGNED_PHOT);
00582     
00583     cpl_propertylist_delete(qc); qc = NULL;
00584 
00585     /* FIXME: FAP: use WCS corrected header */
00586     fors_dfs_add_wcs(product_header,
00587                      cpl_frameset_get_first(std_frame), setting);
00588     /* FIXME: FAP: use WCS corrected header */
00589     fors_dfs_add_exptime(product_header, 
00590                          cpl_frameset_get_first(std_frame), 0.);
00591 
00592     cpl_propertylist_update_double(product_header, "AIRMASS", avg_airmass);
00593     
00594     /* FIXME: FAP: use WCS corrected header */
00595     fors_dfs_save_image(frames, std, STANDARD_REDUCED_IMG,
00596                         product_header, parameters, fors_zeropoint_name, 
00597                         cpl_frameset_get_first(std_frame));
00598     assure( !cpl_error_get_code(), return, "Saving %s failed",
00599             STANDARD_REDUCED_IMG);
00600     
00601     dfs_save_image(frames, background, PHOT_BACKGROUND_STD_IMG,
00602                    product_header, parameters, fors_zeropoint_name, 
00603                    setting->version);
00604     assure( !cpl_error_get_code(), return, "Saving %s failed",
00605             PHOT_BACKGROUND_STD_IMG);
00606         
00607     cpl_image_delete(background); background = NULL;
00608         
00609     if (setting->filter_name == NULL) {
00610 
00611         /* No debug image can be created */
00612 
00613         cleanup;
00614         return;
00615     }
00616 
00617     /* Create debugging image
00618 
00619        Legend:
00620 
00621         ------  (horiz. line):   detected source
00622 
00623           |
00624           |    (vert. line):   catalog position
00625           |
00626 
00627           _
00628          / \     (circle) :   identified
00629          \_/
00630     */
00631 
00632     double color = fors_image_get_min(std);
00633     if (stars != NULL)
00634     {
00635         fors_star *s;
00636         for (s = fors_star_list_first(stars);
00637              s != NULL; 
00638              s = fors_star_list_next(stars)) {
00639             fors_image_draw(std, 0,
00640                             s->pixel->x,
00641                             s->pixel->y,
00642                             10, color);
00643 
00644             if (s->id != NULL && s->id->trusted) {
00645                 fors_image_draw(std, 2,
00646                                 s->pixel->x,
00647                                 s->pixel->y,
00648                                 10, color);
00649             }
00650         }
00651     }
00652     if (cat != NULL)
00653     {
00654         fors_std_star *s;
00655         for (s = fors_std_star_list_first(cat);
00656              s != NULL; 
00657              s = fors_std_star_list_next(cat))
00658         {
00659             if (s->trusted)
00660                 fors_image_draw(std, 1,
00661                             s->pixel->x,
00662                             s->pixel->y,
00663                             10, color);
00664         }
00665         /* FIXME: FAP: use WCS corrected header */
00666         fors_dfs_save_image(frames, std, "DEBUG",
00667                             product_header, parameters, fors_zeropoint_name, 
00668                             cpl_frameset_get_first(std_frame));
00669         assure( !cpl_error_get_code(), return, "Saving %s failed",
00670                 "DEBUG");
00671     }
00672 
00673     cleanup;
00674     return;
00675 }
00676 
00685 static bool
00686 zeropoint_inside(const fors_star *s,
00687                  void *data) 
00688 {
00689     struct {
00690         double hi, lo;   /* magnitude */
00691         double z, kappa; /* avg zeropoint, kappa */
00692     } *cuts = data;
00693     
00694     double z  = fors_star_get_zeropoint(s, NULL);
00695     double dz = fors_star_get_zeropoint_err(s, NULL);
00696 
00697     return
00698         (cuts->lo                 <= z && z <= cuts->hi) ||
00699         (cuts->z - cuts->kappa*dz <= z && z <= cuts->z + cuts->kappa*dz);
00700 }
00701 
00702 #undef cleanup
00703 #define cleanup \
00704 do { \
00705     fors_star_list_delete(&subset, fors_star_delete); \
00706     fors_star_list_delete(&identified, fors_star_delete); \
00707 } while(0)
00708 
00720 static double
00721 get_zeropoint(fors_star_list *stars, 
00722               double cutoffE,
00723               double cutoffk,
00724               double dext_coeff,
00725               double dcolor_term,
00726               double avg_airmass,
00727               double *dzeropoint,
00728               int *n)
00729 {
00730     fors_star_list *subset = NULL;
00731     fors_star_list *identified = 
00732         fors_star_list_extract(stars, fors_star_duplicate,
00733                                fors_star_is_identified, NULL);
00734 
00735     assure( stars != NULL, return 0, NULL );
00736     assure( dzeropoint != NULL, return 0, NULL );
00737     assure( n != NULL, return 0, NULL );
00738 
00739     if ( fors_star_list_size(identified) == 0 ) {
00740         cpl_msg_warning(cpl_func, 
00741                         "No identified stars for zeropoint computation");
00742         *n = 0;
00743         *dzeropoint = 0;
00744         cleanup;
00745         return 0;
00746     }
00747     
00748     cpl_msg_info(cpl_func, "Computing zeropoint (assuming extinction)");
00749     cpl_msg_indent_more();
00750 
00751     double zeropoint;
00752     double red_chisq = -1.0;
00753 
00754     /* This method does not take into account that the error bars are
00755        correlated, and therefore computes an unrealistically low
00756        dzeropoint */
00757     zeropoint = fors_star_list_mean_optimal(identified,
00758                                             fors_star_get_zeropoint, NULL,
00759                                             fors_star_get_zeropoint_err, NULL,
00760                                             dzeropoint,
00761                                             fors_star_list_size(identified) >= 2 ? &red_chisq : NULL);
00762 
00763     cpl_msg_info(cpl_func, "Optimal zeropoint (no rejection, %d stars) = %f mag",
00764                  fors_star_list_size(identified), zeropoint);  
00765     
00766     /* Reject stars that are absolute (0.3 mag) outliers and
00767        kappa sigma outliers. For robustness (against error in the initial
00768        zeropoint estimates) apply the absolute cut in two steps
00769        and update the estimated zeropoint after the first step.
00770     */
00771     struct {
00772         double hi, lo;   /* magnitude */
00773         double z, kappa; /* avg zeropoint, kappa */
00774     } cuts;
00775     cuts.hi = zeropoint + 5*cutoffE;
00776     cuts.lo = zeropoint - 5*cutoffE;
00777     cuts.z = zeropoint;
00778     cuts.kappa = cutoffk;
00779     
00780     subset = fors_star_list_extract(identified, fors_star_duplicate,
00781                                     zeropoint_inside, &cuts);
00782 
00783 
00784     if ( fors_star_list_size(subset) == 0 ) {
00785         cpl_msg_warning(cpl_func, 
00786                         "All stars rejected (%f mag). Cannot "
00787                         "compute zeropoint", 5*cutoffE);
00788         *n = 0;
00789         *dzeropoint = 0;
00790         cleanup;
00791         return 0;
00792     }
00793 
00794     zeropoint = fors_star_list_mean_optimal(subset,
00795                                             fors_star_get_zeropoint, NULL,
00796                                             fors_star_get_zeropoint_err, NULL,
00797                                             dzeropoint,
00798                                             fors_star_list_size(subset) >= 2 ? &red_chisq : NULL);
00799 
00800     cpl_msg_debug(cpl_func, "Optimal zeropoint (%.2f mag, %.2f sigma rejection) = %f mag",
00801                   5*cutoffE, cutoffk, zeropoint);  
00802     
00803     cuts.hi = zeropoint + cutoffE;
00804     cuts.lo = zeropoint - cutoffE;
00805     cuts.z = zeropoint;
00806     cuts.kappa = cutoffk;
00807     
00808     {
00809         fors_star_list *tmp = fors_star_list_duplicate(subset, fors_star_duplicate);
00810         fors_star_list_delete(&subset, fors_star_delete);
00811 
00812         subset = fors_star_list_extract(tmp, fors_star_duplicate,
00813                                         zeropoint_inside, &cuts);
00814 
00815         if ( fors_star_list_size(subset) == 0 ) {
00816             cpl_msg_warning(cpl_func, 
00817                             "All stars rejected (%f mag, %f sigma). Cannot "
00818                             "compute zeropoint", cutoffE, cutoffk);
00819             *n = 0;
00820             *dzeropoint = 0;
00821             cleanup;
00822             return 0;
00823         }
00824 
00825         fors_star_list_delete(&tmp, fors_star_delete);
00826     }
00827 
00828     zeropoint = fors_star_list_mean_optimal(subset,
00829                                             fors_star_get_zeropoint, NULL,
00830                                             fors_star_get_zeropoint_err, NULL,
00831                                             dzeropoint,
00832                                             fors_star_list_size(subset) >= 2 ? &red_chisq : NULL);
00833     
00834     cpl_msg_info(cpl_func, "Optimal zeropoint (%.2f mag, %.2f sigma rejection) = %f mag",
00835                  cutoffE, cutoffk, zeropoint);  
00836     
00837     *n = fors_star_list_size(subset);
00838     {
00839         int outliers = 
00840             fors_star_list_size(identified) - fors_star_list_size(subset);
00841         cpl_msg_info(cpl_func, "%d outlier%s rejected, %d non-outliers",
00842                      outliers, outliers == 1 ? "" : "s",
00843                      *n);
00844     }
00845 
00846     if ( *n == 0 ) {
00847         cpl_msg_warning(cpl_func, 
00848                         "All stars were rejected during zeropoint computation" );
00849         *dzeropoint = 0;
00850         cleanup;
00851         return 0;
00852     }
00853 
00854 
00855 
00856 
00857 
00858 
00859 
00860     /*
00861       Build zeropoint covariance matrix.
00862       We have already the variances from fors_star_get_zeropoint_err().
00863       Non-diagonal terms are
00864          Cij = airmass^2 * Variance(ext.coeff) + color_i * color_j * Variance(color.coeff)
00865 
00866       It was considered and tried to subtract the term
00867                airmass^2 * Variance(ext.coeff)
00868       from every Cij. This has no effect on the relative weights, only the weight's overall
00869       normalization. Since we use the normalization for computing the zeropoint error this
00870       term is kept.
00871 
00872     */
00873     cpl_matrix *covariance = cpl_matrix_new(*n,
00874                                             *n);
00875 
00876     /* Duplicate the list to allow simultaneous iterations */
00877     fors_star_list *ident_dup = fors_star_list_duplicate(subset, fors_star_duplicate);
00878     {
00879       
00880       fors_star *s, *t;
00881       int i, j;
00882       for (s = fors_star_list_first(subset), i = 0;
00883            s != NULL;
00884            s = fors_star_list_next(subset), i++) {
00885 
00886         for (t = fors_star_list_first(ident_dup), j = 0;
00887              t != NULL;
00888              t = fors_star_list_next(ident_dup), j++) {
00889           
00890           double cij;
00891 
00892           if (fors_star_equal(s, t)) {
00893               cij = fors_star_get_zeropoint_err(s, NULL)*fors_star_get_zeropoint_err(s, NULL);
00894               /*  -avg_airmass*avg_airmass*dext_coeff*dext_coeff */
00895           }
00896           else {
00897               cij = s->id->color * t->id->color * dcolor_term*dcolor_term
00898                   + avg_airmass*avg_airmass*dext_coeff*dext_coeff;
00899           }
00900           
00901           cpl_matrix_set(covariance, i, j, cij);
00902         }
00903       }
00904     }
00905     /* cpl_matrix_dump(covariance, stdout); */
00906     /* cpl_matrix_dump(cpl_matrix_invert_create(covariance), stdout); */
00907 
00908     /*
00909       Compute optimal weights, w, as
00910       
00911       w = C^-1 * const
00912 
00913       C    : nxn covariance matrix
00914       const: nx1 constant vector with all elements equal to 1
00915      */
00916 
00917     cpl_matrix *covariance_inverse = cpl_matrix_invert_create(covariance);
00918 
00919     assure( !cpl_error_get_code(), return 0,
00920             "Could not invert zeropoints covariance matrix");
00921 
00922     /*  cpl_matrix_dump(cpl_matrix_product_create(covariance_inverse, covariance), stdout); */
00923 
00924     /* fprintf(stderr, "is_identity = %d\n", cpl_matrix_is_identity(cpl_matrix_product_create(covariance_inverse, covariance),1e-10)); */
00925 
00926     cpl_matrix_delete(covariance); covariance = NULL;
00927 
00928     cpl_matrix *const_vector = cpl_matrix_new(*n, 1);
00929     cpl_matrix_fill(const_vector, 1.0);
00930     
00931     cpl_matrix *weights = cpl_matrix_product_create(covariance_inverse, const_vector);
00932 
00933     cpl_matrix_delete(const_vector); const_vector = NULL;
00934 
00935     /* cpl_matrix_dump(weights, stdout); */
00936     
00937     
00938     {
00939         double wz = 0;
00940         double w = 0;
00941         
00942         int i;
00943         fors_star *s;
00944         for (i = 0, s = fors_star_list_first(subset);
00945              s != NULL;
00946              s = fors_star_list_next(subset), i++) {
00947             
00948             double weight = cpl_matrix_get(weights, i, 0);
00949 
00950             cpl_msg_debug(cpl_func, "Weight_%d = %f", i, weight);
00951             
00952             wz += weight * fors_star_get_zeropoint(s, NULL);
00953             w += weight;
00954 
00955             /* Loop through original list to record the weight of this star */
00956             {
00957                 fors_star *t;
00958                 
00959                 for (t = fors_star_list_first(stars);
00960                      t != NULL;
00961                      t = fors_star_list_next(stars)) {
00962                     
00963                     if (fors_star_equal(s, t)) {
00964                         t->weight = weight;
00965                     }
00966                 }
00967             }
00968         }
00969 
00970         cpl_matrix_delete(weights); weights = NULL;
00971 
00972         cpl_msg_debug(cpl_func, "Sum of weights = %f", w);
00973 
00974         /* 
00975            C is positive definite (because all eigenvalues are positive). Therefore
00976            C^-1 is also positive definite, a property of positive definite matrices.
00977            
00978            Positive definite matrices always have the property that
00979                  z* C z > 0     for any non-zero (complex) vector z
00980 
00981            The sum of the weights is just
00982                 const.* w = const.* C^-1 const.
00983            where const. is our constant vector filled with 1. Therefore the sum of
00984            the weights should always be positive. But make the paranoia check anyway:
00985          */
00986 
00987         assure( w != 0, return 0, "Sum of optimal weights is zero!" );
00988         assure( sqrt(w) != 0, return 0, "Square root of sum of optimal weights is zero!" );
00989         
00990         zeropoint = wz / w;
00991         *dzeropoint = 1 / sqrt(w);
00992     }
00993 
00994     /* Previous code: weighted average, uncorrelated errors
00995 
00996     zeropoint = fors_star_list_mean_optimal(
00997         subset, 
00998         fors_star_get_zeropoint, NULL,
00999         fors_star_get_zeropoint_err, NULL,
01000         dzeropoint,
01001         *n >= 2 ? &red_chisq : NULL);
01002     */
01003     
01004     cpl_msg_info(cpl_func, "Optimal zeropoint = %f +- %f mag", 
01005                  zeropoint, *dzeropoint);
01006 
01007     if (*n >= 2) {
01008         fors_star *s, *t;
01009         int i, j;
01010 
01011         red_chisq = 0;
01012 
01013         for (s = fors_star_list_first(subset), i = 0;
01014              s != NULL;
01015              s = fors_star_list_next(subset), i++) {
01016             
01017             for (t = fors_star_list_first(ident_dup), j = 0;
01018                  t != NULL;
01019                  t = fors_star_list_next(ident_dup), j++) {
01020                 
01021                 red_chisq += 
01022                     (fors_star_get_zeropoint(s, NULL) - zeropoint) *
01023                     (fors_star_get_zeropoint(t, NULL) - zeropoint) *
01024                     cpl_matrix_get(covariance_inverse, i, j);
01025             }
01026         }
01027         red_chisq /= (*n - 1);
01028     }
01029 
01030     cpl_matrix_delete(covariance_inverse); covariance_inverse = NULL;
01031 
01032     fors_star_list_delete(&ident_dup, fors_star_delete);
01033     
01034     cpl_msg_info(cpl_func, "Reduced chi square = %f", red_chisq);
01035     
01036     cpl_msg_indent_less();
01037 
01038     cleanup;
01039     return zeropoint;
01040 }
01041 
01042 #undef cleanup
01043 #define cleanup \
01044 do { \
01045     fors_std_star_list_delete(&internal_cat, fors_std_star_delete); \
01046 } while (0)
01047 
01067 static cpl_error_code
01068 fors_zeropoint_astrometry(                  const cpl_frameset  *std_cat_frames,
01069                                             char                filter_band,
01070                                             double              color_correct,
01071                                             double              dcolor_correct,
01072                                             const identify_method
01073                                                                 *id_method,
01074                                             fors_star_list      *extracted,
01075                                             cpl_propertylist    *wcs_header,
01076                                             fors_std_star_list  **std_cat)
01077 {
01078     double              dcrpix_x = 0,
01079                         dcrpix_y = 0;
01080     fors_std_star_list  *internal_cat = NULL,
01081                         *used_cat;
01082     cpl_errorstate      errstat = cpl_errorstate_get();
01083     
01084     if (std_cat != NULL)
01085         *std_cat = NULL;
01086     
01087     cassure_automsg(                        std_cat_frames != NULL,
01088                                             CPL_ERROR_NULL_INPUT,
01089                                             return cpl_error_get_code());
01090     cassure_automsg(                        id_method != NULL,
01091                                             CPL_ERROR_NULL_INPUT,
01092                                             return cpl_error_get_code());
01093     cassure_automsg(                        extracted != NULL,
01094                                             CPL_ERROR_NULL_INPUT,
01095                                             return cpl_error_get_code());
01096     cassure_automsg(                        wcs_header != NULL,
01097                                             CPL_ERROR_NULL_INPUT,
01098                                             return cpl_error_get_code());
01099 
01100     cpl_msg_info(cpl_func, "Loading standard star catalogue(s):");
01101     cpl_msg_indent_more();
01102     /*
01103     used_cat = internal_cat = fors_std_cat_load_old(
01104                                             std_cat_frames,
01105                                             filter_band,
01106                                             color_term,
01107                                             dcolor_term);
01108     */
01109     used_cat = internal_cat = fors_std_cat_load(
01110                                             std_cat_frames,
01111                                             filter_band,
01112                                             0,  /* don't require all frames */
01113                                             color_correct,
01114                                             dcolor_correct);
01115     cpl_msg_indent_less();
01116     assure(                                 cpl_errorstate_is_equal(errstat),
01117                                             return cpl_error_get_code(),
01118                                             "Std catalogue loading failed");
01119     
01120     /* keep catalogue for output if desired */
01121     if (std_cat != NULL)
01122     {
01123         *std_cat = used_cat;
01124         internal_cat = NULL;
01125     }
01126     if (0) if (used_cat) fors_std_star_print_list(CPL_MSG_DEBUG, used_cat);
01127 
01128     /* get (x,y) std star positions */
01129     fors_std_star_list_apply_wcs(           used_cat, wcs_header);
01130     assure(                                 cpl_errorstate_is_equal(errstat),
01131                                             return cpl_error_get_code(),
01132                                             "Failed to apply WCS to catalogue");
01133 
01134     /* Identify (std stars are duplicated and linked to stars) */
01135     fors_identify(extracted, used_cat, id_method);
01136     assure(                                 cpl_errorstate_is_equal(errstat),
01137                                             return cpl_error_get_code(),
01138                                             "Failed to identify sources");
01139 
01140     /* correct the wcs */
01141     fors_zeropoint_astrometry_get_wcs_shift_px(
01142                                             extracted,
01143                                             &dcrpix_x,
01144                                             &dcrpix_y);
01145     assure(                                 cpl_errorstate_is_equal(errstat),
01146                                             return cpl_error_get_code(),
01147                                             "Failed to determine WCS correction"
01148                                             );
01149 
01150     cpl_msg_info(                           cpl_func,
01151                                             "Correcting the WCS origin by "
01152                                             "(%f, %f)",
01153                                             -dcrpix_x,
01154                                             -dcrpix_y);
01155 
01156     fors_zeropoint_astrometry_shift_wcs_origin(
01157                                             wcs_header,
01158                                             -dcrpix_x,
01159                                             -dcrpix_y);
01160     assure(                                 cpl_errorstate_is_equal(errstat),
01161                                             return cpl_error_get_code(),
01162                                             "Failed to correct WCS origin");
01163 
01164     /* re-apply (x,y) std star positions */
01165     {
01166         /* create a list of the identified std stars */
01167         fors_star   *s;
01168         fors_std_star_list  *identified;
01169         identified = fors_std_star_list_new();
01170 
01171         for (   s = fors_star_list_first(extracted);
01172                 s != NULL;
01173                 s = fors_star_list_next(extracted))
01174         {
01175             if (s->id != NULL)
01176                 fors_std_star_list_insert(  identified,
01177                                             (fors_std_star*)s->id); /* !const */
01178         }
01179 
01180         if (fors_std_star_list_size(identified) > 0)
01181             fors_std_star_list_apply_wcs(identified, wcs_header);
01182 
01183         /* delete the list object but not the std stars */
01184         fors_std_star_list_delete(&identified, NULL);
01185     }
01186     assure(                                 cpl_errorstate_is_equal(errstat),
01187                                             return cpl_error_get_code(),
01188                                             "Failed to correct std (x,y)");
01189 
01190     /* ATTENTION: the following code links fors_std_star* objects to
01191      * the stars, which represent non-std stars (trusted-flag=false).
01192      * make sure later invoked functions respect this flag!
01193      *
01194      * Non-std stars are created and linked to stars.
01195      * Btw., those stars can be any sextracted celestial object. */
01196     cpl_msg_info(cpl_func, "Assigning RA & DEC to non-standard stars");
01197     cpl_msg_indent_more();
01198     fors_zeropoint_astrometry_apply_unidentified_xy2radec(
01199                                             extracted,
01200                                             wcs_header);
01201     cpl_msg_indent_less();
01202     assure(                                 cpl_errorstate_is_equal(errstat),
01203                                             return cpl_error_get_code(),
01204                                             "Failed to apply WCS to non-"
01205                                             "identified stars");
01206 
01207     cleanup;
01208     return (    cpl_errorstate_is_equal(errstat) ?
01209                 CPL_ERROR_NONE :
01210                 cpl_error_get_code());
01211 }
01212 
01213 #undef cleanup
01214 #define cleanup \
01215 do { \
01216     cpl_vector_delete(vdx_long); vdx_long = NULL; \
01217     cpl_vector_delete(vdy_long); vdy_long = NULL; \
01218     cpl_vector_unwrap(vdx_only_std); vdx_only_std = NULL; \
01219     cpl_vector_unwrap(vdy_only_std); vdy_only_std = NULL; \
01220 } while (0)
01221 
01228 static cpl_error_code
01229 fors_zeropoint_astrometry_get_wcs_shift_px( const fors_star_list    *stars,
01230                                             double                  *dx,
01231                                             double                  *dy)
01232 {
01233     const fors_star *s;
01234     int             n_stars,
01235                     n_std_stars = 0;
01236     cpl_vector      *vdx_long = NULL,
01237                     *vdx_only_std = NULL,
01238                     *vdy_long = NULL,
01239                     *vdy_only_std = NULL;
01240     cpl_errorstate  errstat = cpl_errorstate_get();
01241     
01242     /* init output */
01243     if (dx != NULL)
01244         *dx = 0;
01245     if (dy != NULL)
01246         *dy = 0;
01247     
01248     cassure_automsg(                        stars != NULL,
01249                                             CPL_ERROR_NULL_INPUT,
01250                                             return cpl_error_get_code());
01251     cassure_automsg(                        dx != NULL,
01252                                             CPL_ERROR_NULL_INPUT,
01253                                             return cpl_error_get_code());
01254     cassure_automsg(                        dy != NULL,
01255                                             CPL_ERROR_NULL_INPUT,
01256                                             return cpl_error_get_code());
01257     
01258     n_stars = fors_star_list_size(stars);
01259     
01260     cassure_automsg(                        n_stars > 0,
01261                                             CPL_ERROR_DATA_NOT_FOUND,
01262                                             return cpl_error_get_code());
01263     
01264     vdx_long = cpl_vector_new(n_stars);
01265     vdy_long = cpl_vector_new(n_stars);
01266     
01267     for (   s = fors_star_list_first_const(stars);
01268             s != NULL;
01269             s = fors_star_list_next_const(stars))
01270     {
01271         const fors_std_star *id = s->id;
01272         if (id != NULL)
01273         {
01274             cpl_vector_set(vdx_long, n_std_stars, id->pixel->x - s->pixel->x);
01275             cpl_vector_set(vdy_long, n_std_stars, id->pixel->y - s->pixel->y);
01276             n_std_stars++;
01277         }
01278     }
01279     
01280     passure(                                cpl_errorstate_is_equal(errstat),
01281                                             return cpl_error_get_code());
01282     cassure_automsg(                        n_std_stars > 0,
01283                                             CPL_ERROR_DATA_NOT_FOUND,
01284                                             return cpl_error_get_code());
01285     
01286     vdx_only_std = cpl_vector_wrap(n_std_stars, cpl_vector_get_data(vdx_long));
01287     vdy_only_std = cpl_vector_wrap(n_std_stars, cpl_vector_get_data(vdy_long));
01288     
01289     *dx = cpl_vector_get_median(vdx_only_std);
01290     *dy = cpl_vector_get_median(vdy_only_std);
01291     
01292     passure(                                cpl_errorstate_is_equal(errstat),
01293                                             return cpl_error_get_code());
01294     
01295     cleanup;
01296     
01297     return CPL_ERROR_NONE;
01298 }
01299 
01300 #undef cleanup
01301 #define cleanup
01302 
01309 static cpl_error_code
01310 fors_zeropoint_astrometry_shift_wcs_origin( cpl_propertylist    *header,
01311                                             double  dx,
01312                                             double  dy)
01313 {
01314     double          crpix_x,
01315                     crpix_y;
01316     cpl_errorstate  errstat = cpl_errorstate_get();
01317     
01318     cassure_automsg(                        header != NULL,
01319                                             CPL_ERROR_NULL_INPUT,
01320                                             return cpl_error_get_code());
01321     
01322     /* FIXME: wanted: creating wcs from header, modifying wcs, storing
01323      * back wcs into header. This was not possible due to the lack
01324      * of a function to store a wcs in a property list. */
01325     
01326     if (!cpl_propertylist_has(header, "CRPIX1"))
01327     {
01328         cpl_error_set_message(              cpl_func,
01329                                             CPL_ERROR_DATA_NOT_FOUND,
01330                                             "no WCS found in header");
01331         cleanup;
01332         return cpl_error_get_code();
01333     }
01334     if (!cpl_propertylist_has(header, "CRPIX2")
01335         || cpl_propertylist_has(header, "CRPIX3"))
01336     {
01337         cpl_error_set_message(              cpl_func,
01338                                             CPL_ERROR_INCOMPATIBLE_INPUT,
01339                                             "WCS in header is not "
01340                                             "2-dimensional");
01341         cleanup;
01342         return cpl_error_get_code();
01343     }
01344     
01345     
01346     crpix_x = cpl_propertylist_get_double(header, "CRPIX1");
01347     crpix_y = cpl_propertylist_get_double(header, "CRPIX2");
01348     assure(                                 cpl_errorstate_is_equal(errstat),
01349                                             return cpl_error_get_code(),
01350                                             "CRPIXn keywords must be of type "
01351                                             "double");
01352     crpix_x += dx;
01353     crpix_y += dy;
01354     cpl_propertylist_set_double(header, "CRPIX1", crpix_x);
01355     cpl_propertylist_set_double(header, "CRPIX2", crpix_y);
01356     
01357     return (    cpl_errorstate_is_equal(errstat) ?
01358                 CPL_ERROR_NONE :
01359                 cpl_error_get_code());
01360 }
01361 
01362 #undef cleanup
01363 #define cleanup \
01364 do { \
01365     cpl_wcs_delete(wcs); wcs = NULL; \
01366     cpl_matrix_delete(mradec); mradec = NULL; \
01367     cpl_matrix_delete(mxy); mxy = NULL; \
01368     cpl_array_delete(wcs_conversion_status); wcs_conversion_status = NULL; \
01369     fors_std_star_delete(&unknown); \
01370 } while (0)
01371 
01381 static cpl_error_code
01382 fors_zeropoint_astrometry_apply_unidentified_xy2radec(
01383                                             fors_star_list          *stars,
01384                                             const cpl_propertylist  *header)
01385 {
01386     cpl_wcs             *wcs = NULL;
01387     cpl_matrix          *mradec = NULL,
01388                         *mxy = NULL;
01389     cpl_array           *wcs_conversion_status = NULL;
01390     fors_star           *star = NULL;
01391     fors_std_star       *unknown = NULL;
01392     int                 n_unknowns = 0,
01393                         n_wcs_successes = 0,
01394                         n;
01395     int                 *sdat;
01396     union _nant {
01397         unsigned char   bytes[8];
01398         double          val;
01399     } nan;
01400     cpl_errorstate      errstat = cpl_errorstate_get();
01401     
01402     cassure_automsg(                        stars != NULL,
01403                                             CPL_ERROR_NULL_INPUT,
01404                                             return cpl_error_get_code());
01405     cassure_automsg(                        header != NULL,
01406                                             CPL_ERROR_NULL_INPUT,
01407                                             return cpl_error_get_code());
01408     
01409     wcs = cpl_wcs_new_from_propertylist(    header);
01410     assure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code(), NULL);
01411     
01412     {
01413         /* create NaN */
01414         int n;
01415         for (n = 0; n < 8; n++)
01416             nan.bytes[n] = (unsigned char)255;
01417     }
01418     
01419     /* assuming that cpl_wcs_convert has coordinates in rows */
01420     /* count unknowns */
01421     for (   star = fors_star_list_first(stars);
01422             star != NULL;
01423             star = fors_star_list_next(stars))
01424     {
01425         if (star->id == NULL)
01426             n_unknowns++;
01427     }
01428     passure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code());
01429 
01430     if (n_unknowns == 0)
01431         return cpl_error_get_code();
01432             
01433     mxy = cpl_matrix_new(n_unknowns, 2);
01434     passure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code());
01435     
01436     /* copy x,y */
01437     for (   star = fors_star_list_first(stars), n = 0;
01438             star != NULL;
01439             star = fors_star_list_next(stars))
01440     {
01441         if (star->id == NULL)
01442         {
01443             cpl_matrix_set(mxy, n, 0, star->pixel->x);
01444             cpl_matrix_set(mxy, n, 1, star->pixel->y);
01445             n++;
01446         }
01447     }
01448     passure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code());
01449     
01450     cpl_wcs_convert(                        wcs,
01451                                             mxy,
01452                                             &mradec,
01453                                             &wcs_conversion_status,
01454                                             CPL_WCS_PHYS2WORLD);
01455     assure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code(), NULL);
01456     cpl_matrix_delete(mxy); mxy = NULL;
01457     
01458     passure(n_unknowns == cpl_array_get_size(wcs_conversion_status),
01459             return cpl_error_get_code());
01460     
01461     /* FIXME: we have to operate on the data array of wcs_conversion_status,
01462      * because currently cpl_wcs_convert() does the same and thus ignores
01463      * the "valid" flags */
01464     sdat = cpl_array_get_data_int(wcs_conversion_status);
01465     
01466     for (   star = fors_star_list_first(stars), n = 0;
01467             star != NULL;
01468             star = fors_star_list_next(stars))
01469     {
01470         if (star->id == NULL)
01471         {
01472             if (sdat[n] == 0)
01473             {
01474                 double  ra,
01475                         dec;
01476                 n_wcs_successes++;
01477                 
01478                 ra = cpl_matrix_get(mradec, n, 0);
01479                 dec = cpl_matrix_get(mradec, n, 1);
01480                 unknown = fors_std_star_new(ra, dec,
01481                                             nan.val, nan.val,
01482                                             nan.val, nan.val,
01483                                             nan.val, nan.val,
01484                                             nan.val,
01485                                             NULL);  /* no name */
01486                 passure(                    cpl_errorstate_is_equal(errstat),
01487                                             return cpl_error_get_code());
01488                 
01489                 unknown->trusted = false;   /* this star has no catalogue mag*/
01490                 unknown->pixel->x = star->pixel->x;
01491                 unknown->pixel->y = star->pixel->y;
01492                 
01493                 star->id = unknown;
01494                 unknown = NULL;
01495             }
01496             n++;
01497         }
01498     }
01499     
01500     cpl_msg_info(                           cpl_func,
01501                                             "Assigned RA & DEC to %d unknown "
01502                                             "stars",
01503                                             n_wcs_successes);
01504     if (n_wcs_successes < n_unknowns)
01505         cpl_msg_warning(                    cpl_func,
01506                                             "%d WCS conversions failed",
01507                                             n_unknowns - n_wcs_successes);
01508     
01509     cleanup;
01510     
01511     return (    cpl_errorstate_is_equal(errstat) ?
01512                 CPL_ERROR_NONE :
01513                 cpl_error_get_code());
01514 }
01515 
01516 #undef cleanup
01517 #define cleanup
01518 
01525 void
01526 fors_zeropoint_errorstate_dump_as_warning(  unsigned self,
01527                                             unsigned first,
01528                                             unsigned last)
01529 {
01530     const cpl_boolean is_reverse = first > last ? CPL_TRUE : CPL_FALSE;
01531     const unsigned    newest     = is_reverse ? first : last;
01532     /*const unsigned    oldest     = is_reverse ? last : first;*/
01533     self = self;
01534     first = first;
01535     last = last;
01536     /*assert( oldest <= self );
01537     assert( newest >= self );*/
01538     
01539     if (newest == 0)
01540     {
01541         /*assert( oldest == 0);*/
01542         cpl_msg_info(cpl_func, "Success");
01543     }
01544     else
01545     {
01546         /*assert( oldest > 0);*/
01547         cpl_msg_warning(                    cpl_func,
01548                                             "- %s (%s(), %s: %d)",
01549                                             cpl_error_get_message(),
01550                                             cpl_error_get_function(),
01551                                             cpl_error_get_file(),
01552                                             cpl_error_get_line());
01553         /*if (self == last)
01554             cpl_msg_indent_less();*/
01555     }
01556 }
01557 

Generated on Fri Mar 4 09:46:01 2011 for FORS Pipeline Reference Manual by  doxygen 1.4.7