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