00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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 \
00183 \
00184 \
00185 \
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
00205 cpl_frameset *std_frame = NULL;
00206 fors_image *std = NULL;
00207
00208
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
00227 int nzeropoint = -1;
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
00237 extract_method *em = NULL;
00238 identify_method *im = NULL;
00239 double cutoffE, cutoffk;
00240
00241
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
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
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
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
00305
00306
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
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
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
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
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
00339
00340
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
00354
00355 if (setting->filter_name != NULL)
00356 {
00357 char filter_band;
00358 cpl_errorstate local_ers = cpl_errorstate_get();
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
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
00384
00385
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,
00395 raw_header,
00396 &cat);
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
00407 cpl_errorstate_set(local_ers);
00408 }
00409
00410
00411
00412
00413
00414
00415 avg_airmass = fors_star_ext_corr( stars,
00416 setting,
00417 ext_coeff,
00418 dext_coeff,
00419 cpl_frameset_get_first(std_frame));
00420
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
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
00460 fors_qc_start_group(qc, fors_qc_dic_version, setting->instrument);
00461
00462
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
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
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
00556 aligned_phot = fors_create_sources_table(stars);
00557 assure( !cpl_error_get_code(), return,
00558 "Failed to create aligned photometry table");
00559
00560
00561
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
00569
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
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
00586 fors_dfs_add_wcs(product_header,
00587 cpl_frameset_get_first(std_frame), setting);
00588
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
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
00612
00613 cleanup;
00614 return;
00615 }
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
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
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;
00691 double z, 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
00755
00756
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
00767
00768
00769
00770
00771 struct {
00772 double hi, lo;
00773 double z, 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
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873 cpl_matrix *covariance = cpl_matrix_new(*n,
00874 *n);
00875
00876
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
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
00906
00907
00908
00909
00910
00911
00912
00913
00914
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
00923
00924
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
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
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
00976
00977
00978
00979
00980
00981
00982
00983
00984
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
00995
00996
00997
00998
00999
01000
01001
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
01104
01105
01106
01107
01108
01109 used_cat = internal_cat = fors_std_cat_load(
01110 std_cat_frames,
01111 filter_band,
01112 0,
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
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
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
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
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
01165 {
01166
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);
01178 }
01179
01180 if (fors_std_star_list_size(identified) > 0)
01181 fors_std_star_list_apply_wcs(identified, wcs_header);
01182
01183
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
01191
01192
01193
01194
01195
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
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
01323
01324
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
01414 int n;
01415 for (n = 0; n < 8; n++)
01416 nan.bytes[n] = (unsigned char)255;
01417 }
01418
01419
01420
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
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
01462
01463
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);
01486 passure( cpl_errorstate_is_equal(errstat),
01487 return cpl_error_get_code());
01488
01489 unknown->trusted = false;
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
01533 self = self;
01534 first = first;
01535 last = last;
01536
01537
01538
01539 if (newest == 0)
01540 {
01541
01542 cpl_msg_info(cpl_func, "Success");
01543 }
01544 else
01545 {
01546
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
01554
01555 }
01556 }
01557