FORS Pipeline Reference Manual 4.9.20
|
00001 /* $Id: fors_photometry_impl.c,v 1.82 2012/01/27 18:53:15 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: 2012/01/27 18:53:15 $ 00024 * $Revision: 1.82 $ 00025 * $Name: fors-4_9_20 $ 00026 */ 00027 00028 #ifdef HAVE_CONFIG_H 00029 #include <config.h> 00030 #endif 00031 00032 #include <fors_photometry_impl.h> 00033 00034 #include <fors_data.h> 00035 #include <fors_qc.h> 00036 #include <fors_dfs.h> 00037 #include <fors_tools.h> 00038 #include <fors_pfits.h> 00039 #include <fors_polynomial.h> 00040 #include <fors_utils.h> 00041 #include <fors_double.h> 00042 #include <fors_extract.h> 00043 00044 #include <cpl.h> 00045 #include <math.h> 00046 #include <assert.h> 00047 #include <string.h> 00048 #include <stdlib.h> 00049 00056 const char *const fors_photometry_name = "fors_photometry"; 00057 const char *const fors_photometry_description_short = "Compute corrected flatfield"; 00058 const char *const fors_photometry_author = "Jonas M. Larsen"; 00059 const char *const fors_photometry_email = PACKAGE_BUGREPORT; 00060 const char *const fors_photometry_description = 00061 "Input files:\n" 00062 " DO category: Type: Explanation: Number:\n" 00063 " PHOT_TABLE FITS table Expected extinction params 1\n" 00064 " ALIGNED_PHOT FITS table Photometry 1+\n" 00065 " MASTER_SKY_FLAT_IMG FITS image Master flat field 1\n" 00066 "\n" 00067 "Output files:\n" 00068 " DO category: Data type: Explanation:\n" 00069 " PHOT_COEFF_TABLE FITS image Observed extinction coefficients\n" 00070 " CORRECTION_MAP FITS image Correction map (magnitude)\n" 00071 " CORRECTION_FACTOR FITS image Correction map (flux)\n" 00072 " MASTER_FLAT_IMG FITS image Corrected master flat field\n"; 00073 00074 typedef enum fors_fit_ncoeff { 00075 FORS_FIT_NCOEFF_NO = 0, 00076 FORS_FIT_NCOEFF_ONE, 00077 FORS_FIT_NCOEFF_PERFRAME, 00078 FORS_FIT_NCOEFF_PERNIGHT 00079 } fors_fit_ncoeff; 00080 00081 const struct fors_fit_ncoeff_paropts { 00082 const char *no, 00083 *one, 00084 *perframe, 00085 *pernight; 00086 } fors_fit_ncoeff_paropts = { "no", 00087 "one", 00088 "perframe", 00089 "pernight"}; 00090 00091 typedef struct entry 00092 { 00093 int frame_index, /* Counting from zero */ 00094 star_index, /* Star identification number, count from 0 */ 00095 atm_ext_index; /* atmospheric extinction index, count from 0 */ 00096 int atm_ext_identifier; 00097 double airmass, 00098 gain, 00099 exptime; 00100 fors_star *star; 00101 } entry; 00102 00103 /* Declare and define entry_list */ 00104 #undef LIST_ELEM 00105 #define LIST_ELEM entry 00106 #undef LIST_DEFINE 00107 #include <list.h> 00108 #define LIST_DEFINE 00109 #include <list.h> 00110 00111 const double arcsec_tol = 5.0; 00112 00113 entry *entry_new( int frame_index, 00114 int star_index, 00115 double airmass, 00116 double gain, 00117 double exptime, 00118 int atm_ext_identifier, 00119 fors_star *star); 00120 00121 void 00122 entry_delete( entry **e); 00123 00124 static void 00125 entry_delete_but_standard( entry **e); 00126 00127 static double 00128 entry_get_powers_x_y( const entry *e, 00129 const cpl_array *powers); 00130 00131 void 00132 entry_list_print( const entry_list *l, 00133 cpl_msg_severity level); 00134 00135 static double 00136 entry_get_powers_airmass_color( const entry *e, 00137 const cpl_array *powers); 00138 00139 static entry_list * 00140 fors_photometry_read_input( const cpl_frameset *alphot_frames, 00141 const fors_setting *setting, 00142 int (*get_atm_ext_id_function)( 00143 const cpl_propertylist *header), 00144 bool import_unknown, 00145 int *n_frames, 00146 fors_std_star_list **std_star_list, 00147 int filter 00148 ); 00149 00150 static fors_std_star* 00151 fors_photometry_read_input_listinsert_star_if_new( 00152 fors_std_star_list *std_list, 00153 fors_std_star *std, 00154 double mind_arcsec); 00155 00156 static void 00157 fors_delete_star_lists( entry_list **el, 00158 fors_std_star_list **sl); 00159 00160 static bool 00161 fors_fits_compare_string( const char *s1, 00162 const char *s2); 00163 00164 static void 00165 fors_matrix_null( cpl_matrix **m); 00166 00167 static void 00168 fors_matrix_append_delete( cpl_matrix **m1, 00169 cpl_matrix **m2); 00170 00171 static double 00172 fors_property_get_num( const cpl_property *prop); 00173 00174 static double 00175 fors_photometry_parameter_get_num( const cpl_parameterlist *parameters, 00176 const char *name, 00177 cpl_type type); 00178 00179 static const char* 00180 fors_photometry_parameter_get_string( const cpl_parameterlist *parameters, 00181 const char *name); 00182 00183 static fors_fit_ncoeff 00184 fors_photometry_parameter_get_ncoeff( const cpl_parameterlist *parameters, 00185 const char *name); 00186 00187 void fors_photometry_define_parameters( cpl_parameterlist *parameters); 00188 00189 static cpl_polynomial* 00190 fors_photometry_define_polyf( int degreef1, 00191 int degreef2); 00192 00193 static cpl_polynomial* 00194 fors_photometry_define_polyp( int degreep); 00195 00196 static cpl_error_code 00197 fors_photometry_poly_new_from_coefficients( const cpl_polynomial *p_def, 00198 const cpl_matrix *coeffs, 00199 const cpl_matrix *cov_coeffs, 00200 cpl_polynomial **poly, 00201 cpl_polynomial **var_poly); 00202 00203 int 00204 fors_photometry_get_timezone_observer( const cpl_propertylist *header); 00205 00206 int 00207 fors_photometry_get_night_id( const cpl_propertylist *header); 00208 00209 static int 00210 fors_photometry_atm_ext_create_index_by_identifier( 00211 entry_list *obs_list); 00212 00213 static int 00214 fors_photometry_atm_ext_create_indices( entry_list *obsl, 00215 fors_fit_ncoeff fit_e); 00216 00217 //static cpl_error_code 00218 static cpl_table * 00219 fors_photometry_atm_ext_print_index_by_framename( 00220 const entry_list *obs_list, 00221 const cpl_frameset *frames); 00222 00223 static cpl_error_code 00224 fors_photometry_check_input_value( double value, 00225 double value_error, 00226 const char *value_name, 00227 const char *input_name, 00228 double min_limit, 00229 double max_limit, 00230 double max_error); 00231 00232 static cpl_error_code 00233 fors_photometry_check_fitparam_atm_ext( entry_list *obsl, 00234 fors_fit_ncoeff fit_e, 00235 bool fit_z); 00236 00237 static cpl_error_code 00238 fors_photometry_adjust_fit_mag_flags( fors_std_star_list *stdl, 00239 entry_list *obsl, 00240 bool override_fit_m, 00241 int *n_mag_fits); 00242 00243 static cpl_error_code 00244 fors_photometry_remove_unnecessary( fors_std_star_list *std_list, 00245 entry_list *obs_list, 00246 int *n_mag_fits); 00247 00248 static cpl_array* 00249 fors_photometry_count_observations( fors_std_star_list *std_list, 00250 entry_list *obs_list); 00251 00252 static cpl_matrix* 00253 build_equations_lhs_matrix_from_parameters( const entry_list *obs_list, 00254 const fors_std_star_list *std_list, 00255 bool fit_z, 00256 bool fit_c, 00257 int *n_fit_e_cols); 00258 00259 static cpl_matrix* 00260 build_equations_lhs_matrix_from_poly( const entry_list *obs_list, 00261 const cpl_polynomial *poly, 00262 const char *pname, 00263 double (*powerfunc)( 00264 const entry*, 00265 const cpl_array*)); 00266 00267 static cpl_error_code 00268 build_equations_rhs_cov( const entry_list *obs_list, 00269 const fors_std_star_list *std_list, 00270 bool fit_z, 00271 bool fit_c, 00272 bool fit_e, 00273 double color_coeff, 00274 double dcolor_coeff, 00275 double ext_coeff, 00276 double dext_coeff, 00277 double zpoint, 00278 double dzpoint, 00279 cpl_matrix **rhs, 00280 cpl_matrix **rhs_cov); 00281 00282 /*----------------------------------------------------------------------------*/ 00288 /*----------------------------------------------------------------------------*/ 00289 entry *entry_new( int frame_index, 00290 int star_index, 00291 double airmass, 00292 double gain, 00293 double exptime, 00294 int atm_ext_identifier, 00295 fors_star *star) 00296 { 00297 entry *e = cpl_malloc(sizeof(*e)); 00298 00299 e->frame_index = frame_index; 00300 e->star_index = star_index; 00301 e->atm_ext_index = -1; /* means undefined */ 00302 e->airmass = airmass; 00303 e->gain = gain; 00304 e->exptime = exptime; 00305 00306 e->atm_ext_identifier = atm_ext_identifier; 00307 00308 e->star = star; 00309 00310 return e; 00311 } 00312 00313 /*----------------------------------------------------------------------------*/ 00318 /*----------------------------------------------------------------------------*/ 00319 void 00320 entry_delete( entry **e) 00321 { 00322 if (e && *e) { 00323 fors_star_delete(&(*e)->star); 00324 cpl_free(*e); *e = NULL; 00325 } 00326 return; 00327 } 00328 00329 /*----------------------------------------------------------------------------*/ 00334 /*----------------------------------------------------------------------------*/ 00335 static void 00336 entry_delete_but_standard( entry **e) 00337 { 00338 if (e && *e) { 00339 fors_star_delete_but_standard(&(*e)->star); 00340 cpl_free(*e); *e = NULL; 00341 } 00342 return; 00343 } 00344 00345 00346 /*----------------------------------------------------------------------------*/ 00352 /*----------------------------------------------------------------------------*/ 00353 void 00354 entry_list_print( const entry_list *l, 00355 cpl_msg_severity level) 00356 { 00357 const entry *e; 00358 00359 fors_msg(level, "Observation list:"); 00360 cpl_msg_indent_more(); 00361 for (e = entry_list_first_const(l); 00362 e != NULL; 00363 e = entry_list_next_const(l)) { 00364 00365 fors_msg(level, 00366 "frame %d, star %d: airmass = %f, gain = %f, exptime = %f s", 00367 e->frame_index, e->star_index, 00368 e->airmass, e->gain, e->exptime); 00369 00370 fors_star_print(level, e->star); 00371 } 00372 cpl_msg_indent_less(); 00373 00374 return; 00375 } 00376 00377 /*----------------------------------------------------------------------------*/ 00378 #undef cleanup 00379 #define cleanup 00380 /*----------------------------------------------------------------------------*/ 00381 static double 00382 entry_get_powers_x_y( const entry *e, 00383 const cpl_array *powers) 00384 { 00385 passure(powers != NULL && e != NULL, return sqrt(-1)); /* return NaN */ 00386 passure(cpl_array_get_size(powers) == 2, return sqrt(-1)); 00387 return pow(e->star->pixel->x, cpl_array_get(powers, 0, NULL)) 00388 * pow(e->star->pixel->y, cpl_array_get(powers, 1, NULL)); 00389 } 00390 00391 /*----------------------------------------------------------------------------*/ 00392 #undef cleanup 00393 #define cleanup 00394 /*----------------------------------------------------------------------------*/ 00395 static double 00396 entry_get_powers_airmass_color( const entry *e, 00397 const cpl_array *powers) 00398 { 00399 passure(powers != NULL && e != NULL, return sqrt(-1)); /* return NaN */ 00400 passure(cpl_array_get_size(powers) == 2, return sqrt(-1)); 00401 return pow(e->airmass, cpl_array_get(powers, 0, NULL)) 00402 * pow(e->star->id->color, cpl_array_get(powers, 1, NULL)); 00403 } 00404 00405 /*----------------------------------------------------------------------------*/ 00412 /*----------------------------------------------------------------------------*/ 00413 static void 00414 fors_delete_star_lists( entry_list **el, 00415 fors_std_star_list **sl) 00416 { 00417 entry *e; 00418 if (el != NULL && *el != NULL) 00419 { 00420 for ( e = entry_list_first(*el); 00421 e != NULL; 00422 e = entry_list_next(*el)) 00423 { 00424 e->star->id = NULL; 00425 } 00426 } 00427 00428 fors_std_star_list_delete(sl, fors_std_star_delete); 00429 entry_list_delete(el, entry_delete); 00430 } 00431 00432 /*----------------------------------------------------------------------------*/ 00441 /*----------------------------------------------------------------------------*/ 00442 static bool 00443 fors_fits_compare_string( const char *s1, 00444 const char *s2) 00445 { 00446 const char *m1 = "", 00447 *m2 = ""; 00448 int len1, 00449 len2; 00450 00451 if (s1 != NULL) 00452 m1 = s1; 00453 if (s2 != NULL) 00454 m2 = s2; 00455 00456 len1 = strlen(m1); 00457 len2 = strlen(m2); 00458 00459 while (len1 > 0 && m1[len1-1] == ' ') len1--; 00460 while (len2 > 0 && m2[len2-1] == ' ') len2--; 00461 00462 if (len1 != len2) 00463 return false; 00464 00465 if (strncmp(m1, m2, len1) != 0) 00466 return false; 00467 00468 return true; 00469 } 00470 00471 00472 /*----------------------------------------------------------------------------*/ 00478 /*----------------------------------------------------------------------------*/ 00479 static void 00480 fors_matrix_null( cpl_matrix **m) 00481 { 00482 if (m != NULL) 00483 { 00484 cpl_matrix_delete(*m); 00485 *m = NULL; 00486 } 00487 } 00488 00489 /*----------------------------------------------------------------------------*/ 00490 /*----------------------------------------------------------------------------*/ 00491 static void 00492 fors_matrix_append_delete( cpl_matrix **m1, 00493 cpl_matrix **m2) 00494 { 00495 if (m1 == NULL || m2 == NULL) 00496 return; 00497 00498 if (*m2 != NULL) 00499 { 00500 if (*m1 == NULL) 00501 { 00502 *m1 = *m2; 00503 *m2 = NULL; 00504 } 00505 else 00506 { 00507 cpl_matrix_append(*m1, *m2, 0); 00508 fors_matrix_null(m2); 00509 } 00510 } 00511 /* else do nothing */ 00512 } 00513 00514 /*----------------------------------------------------------------------------*/ 00515 /*----------------------------------------------------------------------------*/ 00516 static double 00517 fors_property_get_num( const cpl_property *prop) 00518 { 00519 double retval = 0; 00520 cpl_type type; 00521 00522 cassure_automsg( prop != NULL, 00523 CPL_ERROR_NULL_INPUT, 00524 return 0); 00525 00526 type = cpl_property_get_type(prop); 00527 00528 switch (type) 00529 { 00530 case CPL_TYPE_BOOL: 00531 retval = cpl_property_get_bool(prop); 00532 break; 00533 case CPL_TYPE_INT: 00534 retval = cpl_property_get_int(prop); 00535 break; 00536 case CPL_TYPE_FLOAT: 00537 retval = cpl_property_get_float(prop); 00538 break; 00539 case CPL_TYPE_DOUBLE: 00540 retval = cpl_property_get_double(prop); 00541 break; 00542 default: 00543 cpl_error_set_message( cpl_func, CPL_ERROR_INVALID_TYPE, 00544 "type must be bool, int, float or double"); 00545 } 00546 00547 switch (type) 00548 { 00549 case CPL_TYPE_BOOL: 00550 return (fabs(retval) > 0.5) ? 1 : 0; 00551 case CPL_TYPE_INT: 00552 return round(retval); 00553 default: 00554 return retval; 00555 } 00556 } 00557 00558 /*----------------------------------------------------------------------------*/ 00559 /*----------------------------------------------------------------------------*/ 00560 static double 00561 fors_photometry_parameter_get_num( const cpl_parameterlist *parameters, 00562 const char *name, 00563 cpl_type type) 00564 { 00565 char *descriptor; 00566 double retval = -1; 00567 00568 cpl_msg_indent_more(); 00569 descriptor = cpl_sprintf("fors.%s.%s", fors_photometry_name, name); 00570 switch (type) 00571 { 00572 case CPL_TYPE_BOOL: 00573 retval = dfs_get_parameter_bool_const(parameters, descriptor); 00574 break; 00575 case CPL_TYPE_INT: 00576 retval = dfs_get_parameter_int_const(parameters, descriptor); 00577 break; 00578 /* case CPL_TYPE_FLOAT: 00579 retval = dfs_get_parameter_float_const(parameters, descriptor); 00580 break;*/ 00581 case CPL_TYPE_DOUBLE: 00582 retval = dfs_get_parameter_double_const(parameters, descriptor); 00583 break; 00584 default: 00585 cpl_error_set_message( cpl_func, CPL_ERROR_INVALID_TYPE, 00586 "type must be bool, int" 00587 /*", float"*/ 00588 " or double"); 00589 } 00590 cpl_free(descriptor); 00591 cpl_msg_indent_less(); 00592 00593 switch (type) 00594 { 00595 case CPL_TYPE_BOOL: 00596 return (fabs(retval) > 0.5) ? true : false; 00597 case CPL_TYPE_INT: 00598 return round(retval); 00599 default: 00600 return retval; 00601 } 00602 } 00603 00604 /*----------------------------------------------------------------------------*/ 00605 /*----------------------------------------------------------------------------*/ 00606 static const char* 00607 fors_photometry_parameter_get_string( const cpl_parameterlist *parameters, 00608 const char *name) 00609 { 00610 char *descriptor; 00611 const char *retval = NULL; 00612 00613 cpl_msg_indent_more(); 00614 descriptor = cpl_sprintf("fors.%s.%s", fors_photometry_name, name); 00615 00616 retval = dfs_get_parameter_string_const(parameters, descriptor); 00617 00618 cpl_free(descriptor); 00619 cpl_msg_indent_less(); 00620 00621 return retval; 00622 } 00623 00624 /*----------------------------------------------------------------------------*/ 00625 /*----------------------------------------------------------------------------*/ 00626 static fors_fit_ncoeff 00627 fors_photometry_parameter_get_ncoeff( const cpl_parameterlist *parameters, 00628 const char *name) 00629 { 00630 const char *fit_n_str; 00631 fit_n_str = fors_photometry_parameter_get_string( 00632 parameters, 00633 name); 00634 if (fit_n_str == NULL) 00635 { 00636 cpl_error_set_message( cpl_func, 00637 CPL_ERROR_ILLEGAL_INPUT, 00638 "parameter %s not found", 00639 name); 00640 return -1; 00641 } 00642 00643 if (strcmp(fit_n_str, fors_fit_ncoeff_paropts.no) == 0) 00644 return FORS_FIT_NCOEFF_NO; 00645 else if (strcmp(fit_n_str, fors_fit_ncoeff_paropts.one) == 0) 00646 return FORS_FIT_NCOEFF_ONE; 00647 else if (strcmp(fit_n_str, fors_fit_ncoeff_paropts.perframe)== 0) 00648 return FORS_FIT_NCOEFF_PERFRAME; 00649 else if (strcmp(fit_n_str, fors_fit_ncoeff_paropts.pernight)== 0) 00650 return FORS_FIT_NCOEFF_PERNIGHT; 00651 else 00652 { 00653 cpl_error_set_message( cpl_func, 00654 CPL_ERROR_ILLEGAL_INPUT, 00655 "unknown parameter value \"%s\" " 00656 "for %s", 00657 fit_n_str, 00658 name); 00659 return -1; 00660 } 00661 } 00662 00663 /*----------------------------------------------------------------------------*/ 00668 /*----------------------------------------------------------------------------*/ 00669 void fors_photometry_define_parameters( cpl_parameterlist *parameters) 00670 { 00671 const char *context = cpl_sprintf("fors.%s", fors_photometry_name); 00672 00673 const char *name, *full_name; 00674 cpl_parameter *p; 00675 00676 name = "fitz"; 00677 full_name = cpl_sprintf("%s.%s", context, name); 00678 p = cpl_parameter_new_value(full_name, 00679 CPL_TYPE_BOOL, 00680 "Fit zeropoint", 00681 context, 00682 true); 00683 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name); 00684 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00685 cpl_parameterlist_append(parameters, p); 00686 cpl_free((void *)full_name); full_name = NULL; 00687 00688 name = "fit_all_mag"; 00689 full_name = cpl_sprintf("%s.%s", context, name); 00690 p = cpl_parameter_new_value(full_name, 00691 CPL_TYPE_BOOL, 00692 "Always fit star magnitudes", 00693 context, 00694 false); 00695 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name); 00696 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00697 cpl_parameterlist_append(parameters, p); 00698 cpl_free((void *)full_name); full_name = NULL; 00699 00700 name = "fite"; 00701 full_name = cpl_sprintf("%s.%s", context, name); 00702 p = cpl_parameter_new_enum( full_name, 00703 CPL_TYPE_STRING, 00704 "Fit atmospheric extinctions", 00705 context, 00706 fors_fit_ncoeff_paropts.pernight, 00707 4, 00708 fors_fit_ncoeff_paropts.no, 00709 fors_fit_ncoeff_paropts.one, 00710 fors_fit_ncoeff_paropts.perframe, 00711 fors_fit_ncoeff_paropts.pernight); 00712 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name); 00713 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00714 cpl_parameterlist_append(parameters, p); 00715 cpl_free((void *)full_name); full_name = NULL; 00716 00717 name = "fitc"; 00718 full_name = cpl_sprintf("%s.%s", context, name); 00719 p = cpl_parameter_new_value(full_name, 00720 CPL_TYPE_BOOL, 00721 "Fit color correction term", 00722 context, 00723 false); 00724 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name); 00725 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00726 cpl_parameterlist_append(parameters, p); 00727 cpl_free((void *)full_name); full_name = NULL; 00728 00729 name = "use_all_stars"; 00730 full_name = cpl_sprintf("%s.%s", context, name); 00731 p = cpl_parameter_new_value(full_name, 00732 CPL_TYPE_BOOL, 00733 "Use also non-standard stars to fit " 00734 "polynomial f", 00735 context, 00736 false); 00737 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name); 00738 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00739 cpl_parameterlist_append(parameters, p); 00740 cpl_free((void *)full_name); full_name = NULL; 00741 00742 name = "degreef1"; 00743 full_name = cpl_sprintf("%s.%s", context, name); 00744 p = cpl_parameter_new_value(full_name, 00745 CPL_TYPE_INT, 00746 "FLatfield correction map polynomial degree " 00747 "(x)", 00748 context, 00749 0); 00750 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name); 00751 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00752 cpl_parameterlist_append(parameters, p); 00753 cpl_free((void *)full_name); full_name = NULL; 00754 00755 name = "degreef2"; 00756 full_name = cpl_sprintf("%s.%s", context, name); 00757 p = cpl_parameter_new_value(full_name, 00758 CPL_TYPE_INT, 00759 "Flatfield correction map polynomial degree " 00760 "(y), or negative for " 00761 "triangular coefficient matrix", 00762 context, 00763 -1); 00764 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name); 00765 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00766 cpl_parameterlist_append(parameters, p); 00767 cpl_free((void *)full_name); full_name = NULL; 00768 00769 name = "degreep"; 00770 full_name = cpl_sprintf("%s.%s", context, name); 00771 p = cpl_parameter_new_value(full_name, 00772 CPL_TYPE_INT, 00773 "Extinction/color coupling degree", 00774 context, 00775 0); 00776 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name); 00777 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00778 cpl_parameterlist_append(parameters, p); 00779 cpl_free((void *)full_name); full_name = NULL; 00780 00781 cpl_free((void *)context); 00782 00783 return; 00784 } 00785 00786 /*----------------------------------------------------------------------------*/ 00787 #undef cleanup 00788 #define cleanup \ 00789 do { \ 00790 cpl_polynomial_delete(polyf); polyf = NULL; \ 00791 } while (0) 00792 00803 /*----------------------------------------------------------------------------*/ 00804 static cpl_polynomial* 00805 fors_photometry_define_polyf( int degreef1, 00806 int degreef2) 00807 { 00808 int xpow, 00809 ypow; 00810 cpl_polynomial *polyf = NULL; 00811 00812 /* free output pointers */ 00813 cleanup; 00814 00815 /* check input */ 00816 assure(!cpl_error_get_code(), return NULL, "Previous error caught."); 00817 00818 if (degreef1 < 0) 00819 { 00820 cpl_error_set_message( cpl_func, CPL_ERROR_ILLEGAL_INPUT, 00821 "!(degreef1 >= 0)"); 00822 return NULL; 00823 } 00824 00825 /* define the polynomial */ 00826 polyf = cpl_polynomial_new(2); /* 2 dimensions */ 00827 for (xpow = 0; xpow <= degreef1; xpow++) 00828 { 00829 for (ypow = 0; 00830 (degreef2 >= 0) ? (ypow <= degreef2) : (xpow + ypow <= degreef1); 00831 ypow++) 00832 { 00833 if (xpow+ypow > 0) 00834 { 00835 cpl_size pows[2]; 00836 pows[0] = xpow; 00837 pows[1] = ypow; 00838 cpl_polynomial_set_coeff(polyf, pows, 1.0); 00839 } 00840 } 00841 } 00842 00843 fors_polynomial_dump(polyf, "polynomial definition f", CPL_MSG_DEBUG, NULL); 00844 00845 /* consistency check */ 00846 if (degreef2 >= 0) 00847 { 00848 cassure(fors_polynomial_count_coeff(polyf) 00849 == (degreef1+1)*(degreef2+1)-1, 00850 CPL_ERROR_UNSPECIFIED, 00851 return polyf, 00852 "Consistency check for rectangular f polynomial failed"); 00853 } 00854 else 00855 { 00856 cassure(fors_polynomial_count_coeff(polyf) 00857 == ((degreef1+1)*(degreef1+2))/2-1, 00858 CPL_ERROR_UNSPECIFIED, 00859 return polyf, 00860 "Consistency check for triangular f polynomial failed"); 00861 } 00862 00863 return polyf; 00864 } 00865 00866 /*----------------------------------------------------------------------------*/ 00867 #undef cleanup 00868 #define cleanup \ 00869 do { \ 00870 cpl_polynomial_delete(polyp); polyp = NULL; \ 00871 } while (0) 00872 00883 /*----------------------------------------------------------------------------*/ 00884 static cpl_polynomial* 00885 fors_photometry_define_polyp( int degreep) 00886 { 00887 int k, 00888 l; 00889 cpl_polynomial *polyp = NULL; 00890 00891 /* free output pointers */ 00892 cleanup; 00893 00894 /* check input */ 00895 assure(!cpl_error_get_code(), return NULL, "Previous error caught."); 00896 00897 cassure( degreep >= 0, 00898 CPL_ERROR_ILLEGAL_INPUT, 00899 return polyp, 00900 "!(degreep >= 0)"); 00901 00902 /* define the polynomial */ 00903 polyp = cpl_polynomial_new(2); /* 2 dimensions */ 00904 00905 for (k = 0; k <= degreep; k++) { 00906 for (l = 0; k + l <= degreep; l++) 00907 if (k+l > 1) { 00908 cpl_size pows[2]; 00909 pows[0] = k; 00910 pows[1] = l; 00911 cpl_polynomial_set_coeff(polyp, pows, 1.0); 00912 } 00913 } 00914 00915 fors_polynomial_dump(polyp, "polynomial definition p", CPL_MSG_DEBUG, NULL); 00916 00917 /* consistency check */ 00918 { 00919 int npars = degreep >= 2 ? ((degreep+1)*(degreep+2))/2-3 : 0; 00920 cassure(fors_polynomial_count_coeff(polyp) == npars, 00921 CPL_ERROR_UNSPECIFIED, 00922 return polyp, 00923 "Consistency check for triangular p polynomial failed"); 00924 } 00925 00926 return polyp; 00927 } 00928 00929 /*----------------------------------------------------------------------------*/ 00930 #undef cleanup 00931 #define cleanup \ 00932 do { \ 00933 if (poly != NULL) { cpl_polynomial_delete(*poly); *poly = NULL; } \ 00934 if (var_poly != NULL) {cpl_polynomial_delete(*var_poly); *var_poly = NULL;}\ 00935 } while (0) 00936 00950 /*----------------------------------------------------------------------------*/ 00951 static cpl_error_code 00952 fors_photometry_poly_new_from_coefficients( const cpl_polynomial *p_def, 00953 const cpl_matrix *coeffs, 00954 const cpl_matrix *cov_coeffs, 00955 cpl_polynomial **poly, 00956 cpl_polynomial **var_poly) 00957 { 00958 int n_coeffs; 00959 cpl_errorstate errstat = cpl_errorstate_get(); 00960 00961 /* free output pointers */ 00962 cleanup; 00963 00964 cassure_automsg( p_def != NULL, 00965 CPL_ERROR_NULL_INPUT, 00966 return cpl_error_get_code()); 00967 cassure_automsg( poly != NULL, 00968 CPL_ERROR_NULL_INPUT, 00969 return cpl_error_get_code()); 00970 00971 n_coeffs = fors_polynomial_count_coeff( p_def); 00972 cassure_automsg( n_coeffs == 0 || coeffs != NULL, 00973 CPL_ERROR_NULL_INPUT, 00974 return cpl_error_get_code()); 00975 cassure_automsg( n_coeffs == 0 00976 || var_poly == NULL 00977 || cov_coeffs != NULL, 00978 CPL_ERROR_NULL_INPUT, 00979 return cpl_error_get_code()); 00980 if (n_coeffs > 0) 00981 { 00982 00983 cassure_automsg( cpl_matrix_get_ncol(coeffs) == 1, 00984 CPL_ERROR_ILLEGAL_INPUT, 00985 return cpl_error_get_code()); 00986 cassure_automsg( cpl_matrix_get_nrow(coeffs) 00987 == n_coeffs, 00988 CPL_ERROR_INCOMPATIBLE_INPUT, 00989 return cpl_error_get_code()); 00990 if (var_poly != NULL) 00991 { 00992 cassure_automsg( cpl_matrix_get_nrow(cov_coeffs) 00993 == n_coeffs, 00994 CPL_ERROR_INCOMPATIBLE_INPUT, 00995 return cpl_error_get_code()); 00996 cassure( cpl_matrix_get_nrow(cov_coeffs) 00997 == cpl_matrix_get_ncol(cov_coeffs), 00998 CPL_ERROR_INCOMPATIBLE_INPUT, 00999 return cpl_error_get_code(), 01000 "cov_coeffs is not square"); 01001 } 01002 *poly = cpl_polynomial_duplicate( p_def); 01003 fors_polynomial_set_existing_coeff( *poly, 01004 cpl_matrix_get_data_const(coeffs), 01005 n_coeffs); 01006 passure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code()); 01007 01008 if (var_poly != NULL) 01009 *var_poly = fors_polynomial_create_variance_polynomial( 01010 p_def, 01011 cov_coeffs); 01012 passure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code()); 01013 } 01014 else /* create empty polynomial */ 01015 { 01016 *poly = cpl_polynomial_new( cpl_polynomial_get_dimension( 01017 p_def)); 01018 if (var_poly != NULL) 01019 *var_poly = cpl_polynomial_new( cpl_polynomial_get_dimension( 01020 p_def)); 01021 } 01022 passure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code()); 01023 01024 return (cpl_errorstate_is_equal(errstat) ? 01025 CPL_ERROR_NONE : 01026 cpl_error_get_code()); 01027 } 01028 01029 /*----------------------------------------------------------------------------*/ 01030 #undef cleanup 01031 #define cleanup 01032 01037 /*----------------------------------------------------------------------------*/ 01038 int 01039 fors_photometry_get_timezone_observer( const cpl_propertylist *header) 01040 { 01041 const cpl_property *prop; 01042 01043 cassure_automsg( header != NULL, 01044 CPL_ERROR_NULL_INPUT, 01045 return 0); 01046 01047 do { 01048 const char *origin; 01049 01050 prop = cpl_propertylist_get_property_const(header, "ORIGIN"); 01051 if (prop == NULL) 01052 { 01053 cpl_error_set_message( cpl_func, 01054 CPL_ERROR_DATA_NOT_FOUND, 01055 "Couldn't find the keyword ORIGIN"); 01056 return 0; 01057 } 01058 01059 if (cpl_property_get_type(prop) != CPL_TYPE_STRING) 01060 break; 01061 01062 if ((origin = cpl_property_get_string(prop)) == NULL) 01063 break; 01064 01065 if (!fors_fits_compare_string(origin, "ESO")) 01066 break; 01067 01068 /* We're at ESO, i.e. in Chile */ 01069 return -3; 01070 01071 } while (0); 01072 01073 cpl_error_set_message( cpl_func, 01074 CPL_ERROR_ILLEGAL_INPUT, 01075 "Don't know the originator of the " 01076 "frame specified in ORIGIN"); 01077 return 0; 01078 } 01079 01080 /*----------------------------------------------------------------------------*/ 01081 #undef cleanup 01082 #define cleanup 01083 01090 /*----------------------------------------------------------------------------*/ 01091 int 01092 fors_photometry_get_night_id( const cpl_propertylist *header) 01093 { 01094 const cpl_property *prop; 01095 cpl_errorstate errstat = cpl_errorstate_get(); 01096 01097 cassure_automsg( header != NULL, 01098 CPL_ERROR_NULL_INPUT, 01099 return 0); 01100 01101 /* try to get the Modified Julian Date */ 01102 prop = cpl_propertylist_get_property_const(header, "MJD-OBS"); 01103 if (prop != NULL) 01104 { 01105 double mjd, 01106 jd, 01107 timezone; 01108 int localstartday; 01109 mjd = fors_property_get_num(prop); 01110 assure( cpl_errorstate_is_equal(errstat), 01111 return 0, 01112 "Could not interprete Modified " 01113 "Julian Date keyword MJD-OBS"); 01114 01115 /* The Julian Calendar starts at noon in Greenwich, counting days. 01116 * The definition of MJD (FITS standard) is: 01117 * MJD = JD - 2'400'000.5 01118 * The "xxx.5" means it starts some day at midnight (in Greenwich). 01119 * We want a day definition again that starts at noon, so to have 01120 * something standard, convert back to Julian date. 01121 */ 01122 jd = mjd + 2400000.5; 01123 01124 /* Get the timezone of the observation location. The timezone is not 01125 * perfect to determine sunrise/sunset times, but we don't care 01126 * since we don't expect any observations +/- 2h around noon. 01127 */ 01128 timezone = fors_photometry_get_timezone_observer(header); 01129 01130 /* Correct for the timezone. Now we have something like a 01131 * "Julian Local Time Date" */ 01132 jd += (double)timezone / 24.0; 01133 01134 /* Since the Julian days start every noon, we just round down and 01135 * have the date of the day in which the night started */ 01136 localstartday = floor(jd); 01137 cpl_msg_debug( cpl_func, 01138 "Julian day no. of observation " 01139 "night: %d", 01140 localstartday); 01141 01142 return localstartday; 01143 } 01144 01145 /* So far, no alternative for MJD-OBS is provided. If there should be one 01146 * in future, remember to check for inconsistencies between the frames. */ 01147 cpl_error_set_message( cpl_func, 01148 CPL_ERROR_DATA_NOT_FOUND, 01149 "Couldn't find the keyword " 01150 "MJD-OBS"); 01151 return 0; 01152 } 01153 01154 /*----------------------------------------------------------------------------*/ 01155 #undef cleanup 01156 #define cleanup \ 01157 do { \ 01158 cpl_free(ident_array); ident_array = NULL; \ 01159 } while (0) 01160 01168 /*----------------------------------------------------------------------------*/ 01169 static int 01170 fors_photometry_atm_ext_create_index_by_identifier( 01171 entry_list *obs_list) 01172 { 01173 entry *e; 01174 int *ident_array; 01175 int n_entries, 01176 n_idents = 0; 01177 cpl_errorstate errstat = cpl_errorstate_get(); 01178 01179 cassure_automsg( obs_list != NULL, 01180 CPL_ERROR_NULL_INPUT, 01181 return 0); 01182 01183 n_entries = entry_list_size(obs_list); 01184 ident_array = cpl_malloc(n_entries * sizeof(*ident_array)); 01185 01186 for ( e = entry_list_first(obs_list); 01187 e != NULL; 01188 e = entry_list_next(obs_list)) 01189 { 01190 int i; 01191 bool found = false; 01192 for (i = 0; i < n_idents && !found; i++) 01193 { 01194 if (e->atm_ext_identifier == ident_array[i]) 01195 { 01196 found = true; 01197 e->atm_ext_index = i; 01198 } 01199 } 01200 if (!found) 01201 { 01202 ident_array[n_idents] = e->atm_ext_identifier; 01203 e->atm_ext_index = n_idents; 01204 01205 cpl_msg_debug( cpl_func, 01206 "Creating atm. extinction index " 01207 "%2d for identifier %d", 01208 n_idents, 01209 ident_array[n_idents]); 01210 01211 n_idents++; 01212 } 01213 } 01214 01215 passure( cpl_errorstate_is_equal(errstat), 01216 return 0); 01217 01218 cpl_free(ident_array); 01219 return n_idents; 01220 } 01221 01222 /*----------------------------------------------------------------------------*/ 01223 #undef cleanup 01224 #define cleanup 01225 01241 /*----------------------------------------------------------------------------*/ 01242 static int 01243 fors_photometry_atm_ext_create_indices( entry_list *obsl, 01244 fors_fit_ncoeff fit_e) 01245 { 01246 entry *e; 01247 int n_atm_ext_indices = 0; 01248 cpl_errorstate errstat = cpl_errorstate_get(); 01249 01250 cassure_automsg( obsl != NULL, 01251 CPL_ERROR_NULL_INPUT, 01252 return -1); 01253 01254 if (fit_e != FORS_FIT_NCOEFF_NO 01255 && fit_e != FORS_FIT_NCOEFF_ONE 01256 && fit_e != FORS_FIT_NCOEFF_PERFRAME) 01257 { 01258 /* if FORS_FIT_NCOEFF_PERNIGHT or any other future option which 01259 * has set an identifier */ 01260 n_atm_ext_indices = 01261 fors_photometry_atm_ext_create_index_by_identifier(obsl); 01262 } 01263 else 01264 { 01265 if (fit_e == FORS_FIT_NCOEFF_NO) 01266 { 01267 for (e = entry_list_first(obsl); e!=NULL; e = entry_list_next(obsl)) 01268 e->atm_ext_index = -1; 01269 n_atm_ext_indices = 0; 01270 } 01271 else if (fit_e == FORS_FIT_NCOEFF_ONE) 01272 { 01273 for (e = entry_list_first(obsl); e!=NULL; e = entry_list_next(obsl)) 01274 e->atm_ext_index = 0; 01275 n_atm_ext_indices = 1; 01276 } 01277 else if (fit_e == FORS_FIT_NCOEFF_PERFRAME) 01278 { 01279 for (e = entry_list_first(obsl); e!=NULL; e = entry_list_next(obsl)) 01280 { 01281 e->atm_ext_index = e->frame_index; 01282 if (e->frame_index >= n_atm_ext_indices) 01283 n_atm_ext_indices = e->frame_index + 1; 01284 } 01285 } 01286 } 01287 01288 if (!cpl_errorstate_is_equal(errstat)) 01289 cpl_error_set_where(cpl_func); 01290 01291 return (cpl_errorstate_is_equal(errstat) ? n_atm_ext_indices : -1); 01292 } 01293 01294 /*----------------------------------------------------------------------------*/ 01295 #undef cleanup 01296 #define cleanup \ 01297 do { \ 01298 if (frame_printed != NULL) \ 01299 { \ 01300 cpl_free(frame_printed); \ 01301 frame_printed = NULL; \ 01302 } \ 01303 } while (0) 01304 01310 /*----------------------------------------------------------------------------*/ 01311 //static cpl_error_code 01312 static cpl_table * 01313 fors_photometry_atm_ext_print_index_by_framename( 01314 const entry_list *obs_list, 01315 const cpl_frameset *frames) 01316 { 01317 const entry *e; 01318 bool *frame_printed = NULL; 01319 int n_frames, 01320 ext_index, 01321 max_ext_index, 01322 n; 01323 int row = 0; 01324 cpl_table *summary; 01325 cpl_errorstate errstat = cpl_errorstate_get(); 01326 01327 cassure_automsg( obs_list != NULL, 01328 CPL_ERROR_NULL_INPUT, 01329 return NULL); 01330 cassure_automsg( frames != NULL, 01331 CPL_ERROR_NULL_INPUT, 01332 return NULL); 01333 01334 n_frames = cpl_frameset_get_size(frames); 01335 frame_printed = cpl_malloc(n_frames * sizeof(*frame_printed)); 01336 01337 summary = cpl_table_new(n_frames); 01338 cpl_table_new_column(summary, "filename", CPL_TYPE_STRING); 01339 cpl_table_new_column(summary, "index", CPL_TYPE_INT); 01340 01341 max_ext_index = -1; 01342 for ( e = entry_list_first_const(obs_list); 01343 e != NULL; 01344 e = entry_list_next_const(obs_list)) 01345 { 01346 if (e->atm_ext_index > max_ext_index) 01347 max_ext_index = e->atm_ext_index; 01348 } 01349 01350 if (max_ext_index >= 0) 01351 cpl_msg_info( cpl_func, 01352 "Assignment of atmospheric " 01353 "extinction indices:"); 01354 01355 for (ext_index = 0; ext_index <= max_ext_index; ext_index++) 01356 { 01357 bool first_file = true; 01358 char estr[15]; 01359 for (n = 0; n < n_frames; n++) 01360 frame_printed[n] = false; 01361 01362 cpl_msg_indent_more(); 01363 sprintf(estr, "E_%d: ", ext_index); 01364 estr[9] = '\0'; 01365 01366 for ( e = entry_list_first_const(obs_list); 01367 e != NULL; 01368 e = entry_list_next_const(obs_list)) 01369 { 01370 if (e->atm_ext_index == ext_index) 01371 { 01372 cassure_automsg( e->frame_index >= 0 01373 && e->frame_index < n_frames, 01374 CPL_ERROR_ILLEGAL_INPUT, 01375 { 01376 cpl_msg_indent_less(); 01377 return NULL; 01378 }); 01379 01380 if (!frame_printed[e->frame_index]) 01381 { 01382 const cpl_frame *f; 01383 01384 f = cpl_frameset_get_frame_const(frames, e->frame_index); 01385 if (first_file) 01386 { 01387 cpl_msg_info( cpl_func, 01388 "%s%s", 01389 estr, 01390 cpl_frame_get_filename(f)); 01391 } 01392 else 01393 { 01394 cpl_msg_info( cpl_func, 01395 " %s", 01396 cpl_frame_get_filename(f)); 01397 } 01398 frame_printed[e->frame_index] = true; 01399 first_file = false; 01400 01401 /* 01402 * This tail is added to store the filename / index 01403 * in a summary table. 01404 */ 01405 01406 cpl_table_set_string(summary, "filename", row, 01407 cpl_frame_get_filename(f)); 01408 cpl_table_set_int(summary, "index", row, ext_index); 01409 row++; 01410 01411 } 01412 } 01413 01414 01415 } 01416 cpl_msg_indent_less(); 01417 } 01418 01419 // cpl_table_save(summary, NULL, NULL, "summary.fits", CPL_IO_CREATE); 01420 01421 cleanup; 01422 01423 passure( cpl_errorstate_is_equal(errstat), 01424 return NULL); 01425 01426 return summary; 01427 } 01428 01429 /*----------------------------------------------------------------------------*/ 01430 #undef cleanup 01431 #define cleanup 01432 01445 /*----------------------------------------------------------------------------*/ 01446 static cpl_error_code 01447 fors_photometry_check_input_value( double value, 01448 double value_error, 01449 const char *value_name, 01450 const char *input_name, 01451 double min_limit, 01452 double max_limit, 01453 double max_error) 01454 { 01455 cpl_errorstate errstat = cpl_errorstate_get(); 01456 01457 if (value < min_limit || value > max_limit) 01458 { 01459 cpl_error_set_message( cpl_func, 01460 CPL_ERROR_ILLEGAL_INPUT, 01461 "invalid %s (%f)" 01462 "%s%s" 01463 ", either correct input, or try to " 01464 "re-run this recipe with fitting " 01465 "%s enabled", 01466 value_name, 01467 value, 01468 (input_name != NULL)?" read from ":"", 01469 (input_name != NULL)?input_name:"", 01470 value_name); 01471 } 01472 else if (value_error > max_error || value_error < 0) 01473 { 01474 char exceed_max_err[30]; 01475 sprintf(exceed_max_err, "> %f", max_error); 01476 cpl_error_set_message( cpl_func, 01477 CPL_ERROR_ILLEGAL_INPUT, 01478 "unreliable %s ((error = %g) %s)" 01479 "%s%s" 01480 ", either recompute input, or try " 01481 "to re-run this recipe with " 01482 "fitting %s enabled", 01483 value_name, 01484 value_error, 01485 (value_error < 0) ? 01486 "< 0" : exceed_max_err, 01487 (input_name != NULL)?" read from ":"", 01488 (input_name != NULL)?input_name:"", 01489 value_name); 01490 } 01491 else 01492 { 01493 cpl_msg_info( cpl_func, 01494 "Using input value%s%s: " 01495 "%s = %f +- %f", 01496 (input_name != NULL)?" from ":"", 01497 (input_name != NULL)?input_name:"", 01498 value_name, 01499 value, 01500 value_error); 01501 } 01502 01503 return (cpl_errorstate_is_equal(errstat) ? 01504 CPL_ERROR_NONE : 01505 cpl_error_get_code()); 01506 } 01507 01508 /*----------------------------------------------------------------------------*/ 01509 #undef cleanup 01510 #define cleanup \ 01511 do { \ 01512 cpl_array_delete(airmasses); airmasses = NULL; \ 01513 } while (0) 01514 01520 /*----------------------------------------------------------------------------*/ 01521 static cpl_error_code 01522 fors_photometry_check_fitparam_atm_ext( entry_list *obsl, 01523 fors_fit_ncoeff fit_e, 01524 bool fit_z) 01525 { 01526 entry *e; 01527 int n_atm_ext_indices = 0; 01528 cpl_array *airmasses = NULL; 01529 cpl_errorstate errstat = cpl_errorstate_get(); 01530 01531 cassure_automsg( obsl != NULL, 01532 CPL_ERROR_NULL_INPUT, 01533 return cpl_error_get_code()); 01534 01535 /* we only have a problem if we want to fit the zeropoint and the 01536 * atmospheric extinction at the same time, but there are not 01537 * enough airmasses */ 01538 if (!fit_z || fit_e == FORS_FIT_NCOEFF_NO) 01539 { 01540 return CPL_ERROR_NONE; 01541 } 01542 01543 /* count the indices */ 01544 for (e = entry_list_first(obsl); e!=NULL; e = entry_list_next(obsl)) 01545 { 01546 if (e->atm_ext_index >= n_atm_ext_indices) 01547 n_atm_ext_indices = e->atm_ext_index + 1; 01548 } 01549 01550 /*assure( cpl_errorstate_is_equal(errstat), 01551 return cpl_error_get_code(), 01552 NULL);*/ 01553 01554 /* Check whether there are at least 2 different airmasses for 01555 * at least 1 atmospheric extinction 01556 */ 01557 if (n_atm_ext_indices > 0) 01558 { 01559 bool multiple_found = false; 01560 01561 airmasses = cpl_array_new(n_atm_ext_indices, CPL_TYPE_DOUBLE); 01562 01563 for ( e = entry_list_first(obsl); 01564 e != NULL; 01565 e = entry_list_next(obsl)) 01566 { 01567 double first_airmass; 01568 int is_set; 01569 first_airmass = cpl_array_get_double( 01570 airmasses, 01571 e->atm_ext_index, 01572 &is_set); 01573 passure( cpl_errorstate_is_equal(errstat), 01574 return cpl_error_get_code()); 01575 is_set = (is_set == 0); 01576 if (!is_set) 01577 cpl_array_set_double(airmasses, e->atm_ext_index, e->airmass); 01578 else 01579 { 01580 /* if there is a different airmass for this ext index */ 01581 if (fabs(e->airmass - first_airmass) > 10*DBL_EPSILON) 01582 { 01583 multiple_found = true; 01584 break; 01585 } 01586 /* we won't check here whether the difference in airmass is 01587 * too small to get reliable results, that will turn out 01588 * in the errors of the output after fitting */ 01589 } 01590 } 01591 01592 if (!multiple_found) 01593 { 01594 if (n_atm_ext_indices > 1) 01595 cpl_msg_error( cpl_func, 01596 "No atmospheric extinction was " 01597 "observed at different airmasses."); 01598 else 01599 cpl_msg_error( cpl_func, 01600 "Atmospheric extinction was not " 01601 "observed at different airmasses."); 01602 } 01603 cassure( multiple_found, 01604 CPL_ERROR_ILLEGAL_INPUT, 01605 return cpl_error_get_code(), 01606 "For fitting the zeropoint and " 01607 "atmospheric extinction, " 01608 "there must be >= 2 different " 01609 "airmasses for at least 1 " 01610 "atmospheric extinction"); 01611 } 01612 01613 cpl_array_delete(airmasses); 01614 01615 return (cpl_errorstate_is_equal(errstat) ? 01616 CPL_ERROR_NONE : 01617 cpl_error_get_code()); 01618 } 01619 01620 /*----------------------------------------------------------------------------*/ 01621 /*----------------------------------------------------------------------------*/ 01622 static void 01623 myprintf(const char *format, ...) 01624 { 01625 va_list al; 01626 01627 va_start(al, format); 01628 //vprintf(format, al); 01629 va_end(al); 01630 01631 return; 01632 } 01633 01634 01635 /*----------------------------------------------------------------------------*/ 01636 /* Internal CPL function, duplicated */ 01637 /*----------------------------------------------------------------------------*/ 01638 static cpl_matrix * matrix_product_normal_create(const cpl_matrix * self) 01639 { 01640 double sum; 01641 cpl_matrix * product; 01642 const double * ai = cpl_matrix_get_data_const(self); 01643 const double * aj; 01644 double * bwrite; 01645 const int m = cpl_matrix_get_nrow(self); 01646 const int n = cpl_matrix_get_ncol(self); 01647 int i, j, k; 01648 01649 01650 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, NULL); 01651 01652 #if 0 01653 /* Initialize all values to zero. 01654 This is done to avoid access of uninitilized memory, in case 01655 someone passes the matrix to for example cpl_matrix_dump(). */ 01656 product = cpl_matrix_new(m, m); 01657 bwrite = cpl_matrix_get_data(product); 01658 #else 01659 bwrite = (double *) cpl_malloc(m * m * sizeof(double)); 01660 product = cpl_matrix_wrap(m, m, bwrite); 01661 #endif 01662 01663 /* The result at (i,j) is the dot-product of i'th and j'th row */ 01664 for (i = 0; i < m; i++, bwrite += m, ai += n) { 01665 aj = ai; /* aj points to first entry in j'th row */ 01666 for (j = i; j < m; j++, aj += n) { 01667 sum = 0.0; 01668 for (k = 0; k < n; k++) { 01669 sum += ai[k] * aj[k]; 01670 } 01671 bwrite[j] = sum; 01672 } 01673 } 01674 01675 return product; 01676 } 01677 01678 /*----------------------------------------------------------------------------*/ 01679 #undef cleanup 01680 #define cleanup \ 01681 do { \ 01682 fors_matrix_null(&solution); \ 01683 fors_matrix_null(&cov1); \ 01684 fors_matrix_null(&At); \ 01685 fors_matrix_null(&AtC); \ 01686 fors_matrix_null(&AtCA); \ 01687 fors_matrix_null(&p); \ 01688 fors_matrix_null(&Ap); \ 01689 fors_matrix_null(&bAp); \ 01690 fors_matrix_null(&bApt); \ 01691 fors_matrix_null(&C1bAp); \ 01692 fors_matrix_null(&chi2); \ 01693 } while (0) 01694 /* 01695 @brief Linear correlated weighted least squares fit 01696 @param coeff design matrix (A) 01697 @param rhs right hand side (b) 01698 @param cov_rhs covariance of b (C) 01699 @param red_chisq (output) reduced chi squared, or NULL 01700 01701 Similar to cpl_matrix_solve_normal, except the output matrix is not 01702 a m x 1 matrix 01703 01704 x0 01705 x1 01706 x2 01707 : 01708 01709 but an m x (m+1) matrix 01710 01711 x0 C00 C01 C02 ... 01712 x1 C10 C11 01713 x2 C20 . 01714 : : . 01715 01716 where the first column is the least chi squared solution to the 01717 overdetermined equation system Ax = b, given the covariance, C, of b. 01718 01719 and the last m columns is the covariance matrix of the solution 01720 (A^t C^-1 A)^-1 01721 01722 The reduced chi squared is given by 01723 01724 (b-Ap)^t C^-1 (b-Ap) / (degrees of freedom) 01725 01726 where degrees of freedom = |b| - |p| 01727 01728 */ 01729 /*----------------------------------------------------------------------------*/ 01730 static cpl_matrix * 01731 solve_normal(const cpl_matrix *coeff, 01732 const cpl_matrix *rhs, 01733 const cpl_matrix *cov_rhs, 01734 double *red_chisq) 01735 { 01736 cpl_matrix *solution = NULL; 01737 cpl_matrix *cov1 = NULL; /* C^-1 */ 01738 cpl_matrix *At = NULL; /* A^t */ 01739 cpl_matrix *AtC = NULL; /* A^t C^-1 */ 01740 cpl_matrix *AtCA = NULL; /* A^t C^-1 A */ 01741 cpl_matrix *p = NULL; 01742 cpl_matrix *Ap = NULL; 01743 cpl_matrix *bAp = NULL; 01744 cpl_matrix *bApt = NULL; 01745 cpl_matrix *C1bAp = NULL; 01746 cpl_matrix *chi2 = NULL; 01747 cpl_error_code error; 01748 01749 cpl_ensure(coeff != NULL, CPL_ERROR_NULL_INPUT, NULL); 01750 cpl_ensure(rhs != NULL, CPL_ERROR_NULL_INPUT, NULL); 01751 cpl_ensure(cov_rhs != NULL, CPL_ERROR_NULL_INPUT, NULL); 01752 01753 /* The overall time is probably dominated by this 01754 matrix inversion which is O(n^3) if C is nxn */ 01755 cov1 = cpl_matrix_invert_create(cov_rhs); 01756 01757 assure( cov1 != NULL, return NULL, 01758 "Could not invert covariance matrix. Make sure that provided " 01759 "errors are positive"); 01760 /* The covariance matrix is singular if one (or more) eigenvalue is 01761 zero, i.e. if there exist a unitary transformation (rotation of 01762 coordinates) that makes the variance of one of the new coordinates 01763 zero (and therefore a failure at this place is probably because the 01764 user has provided some non-positive error). 01765 */ 01766 01767 At = cpl_matrix_transpose_create(coeff); 01768 01769 AtC = cpl_matrix_product_create(At, cov1); 01770 01771 fors_matrix_null(&At); 01772 01773 AtCA = cpl_matrix_product_create(AtC, coeff); 01774 01775 solution = cpl_matrix_product_create(AtC, rhs); 01776 cpl_matrix_set_size(solution, 01777 cpl_matrix_get_nrow(solution), 01778 1 + cpl_matrix_get_nrow(solution)); 01779 { 01780 int i = 0; 01781 for (i = 0; i < cpl_matrix_get_nrow(solution); i++) { 01782 cpl_matrix_set(solution, i, i+1, 1); 01783 } 01784 } 01785 01786 fors_matrix_null(&AtC); 01787 01788 //cpl_matrix_dump(AtCA, stdout); 01789 //cpl_matrix_dump(solution, stdout); 01790 01791 error = cpl_matrix_decomp_chol(AtCA); 01792 if (!error) { 01793 error = cpl_matrix_solve_chol(AtCA, solution); 01794 } 01795 01796 fors_matrix_null(&AtCA); 01797 01798 if (error) { 01799 cleanup; 01800 cpl_ensure(0, error, NULL); 01801 } 01802 01803 01804 if (red_chisq != NULL) { 01805 01806 /* Get first column vector, p, of solution */ 01807 p = cpl_matrix_duplicate(solution); 01808 cpl_matrix_set_size(p, cpl_matrix_get_nrow(p), 1); 01809 01810 Ap = cpl_matrix_product_create(coeff, p); 01811 01812 bAp = cpl_matrix_duplicate(rhs); 01813 cpl_matrix_subtract(bAp, Ap); 01814 01815 bApt = cpl_matrix_transpose_create(bAp); 01816 01817 C1bAp = cpl_matrix_product_create(cov1, bAp); 01818 01819 chi2 = cpl_matrix_product_create(bApt, C1bAp); 01820 01821 passure(cpl_matrix_get_nrow(chi2) == 1 && 01822 cpl_matrix_get_ncol(chi2) == 1, return NULL); 01823 01824 *red_chisq = cpl_matrix_get(chi2, 0, 0) / 01825 (cpl_matrix_get_nrow(rhs) - cpl_matrix_get_nrow(p)); 01826 01827 } 01828 01829 cpl_matrix *return_solution = solution; solution = NULL; 01830 cleanup; 01831 01832 return return_solution; 01833 } 01834 01835 /*----------------------------------------------------------------------------*/ 01836 #undef cleanup 01837 #define cleanup \ 01838 do { \ 01839 cpl_frameset_delete((cpl_frameset *)aligned_phot_frames); \ 01840 cpl_frameset_delete((cpl_frameset *)master_flat_frame); \ 01841 cpl_frameset_delete((cpl_frameset *)phot_table); \ 01842 fors_setting_delete(&setting); \ 01843 fors_image_delete(&master_flat); \ 01844 fors_image_delete(&correction); \ 01845 cpl_table_delete(phot_coeff); \ 01846 cpl_table_delete(summary); \ 01847 fors_delete_star_lists(&obs, &std_star_list); \ 01848 cpl_array_delete(n_std_star_obs); n_std_star_obs = NULL; \ 01849 fors_matrix_null(&eqn_lhs); \ 01850 fors_matrix_null(&eqn_rhs); \ 01851 fors_matrix_null(&eqn_cov_rhs); \ 01852 fors_matrix_null(&eqn_result); \ 01853 fors_matrix_null(&tmp_mat); \ 01854 fors_matrix_null(&result_polyf); \ 01855 fors_matrix_null(&result_cov_polyf); \ 01856 fors_matrix_null(&result_params); \ 01857 fors_matrix_null(&result_cov_params); \ 01858 fors_matrix_null(&result_polyp); \ 01859 fors_matrix_null(&result_cov_polyp); \ 01860 cpl_polynomial_delete(polyf); polyf = NULL; \ 01861 cpl_polynomial_delete(polyf_definition); polyf_definition = NULL; \ 01862 cpl_polynomial_delete(polyf_variance); polyf_variance = NULL; \ 01863 cpl_polynomial_delete(polyp); polyp = NULL; \ 01864 cpl_polynomial_delete(polyp_definition); polyp_definition = NULL; \ 01865 } while (0) 01866 01875 /*----------------------------------------------------------------------------*/ 01876 void fors_photometry(cpl_frameset *frames, const cpl_parameterlist *parameters) 01877 { 01878 /* Input */ 01879 const cpl_frameset *aligned_phot_frames = NULL, 01880 *master_flat_frame = NULL, 01881 *phot_table = NULL; 01882 fors_image *master_flat = NULL; 01883 01884 /* Products */ 01885 fors_image *correction = NULL; 01886 cpl_table *phot_coeff = NULL; 01887 cpl_table *summary = NULL; 01888 01889 /* Star lists */ 01890 fors_std_star_list *std_star_list = NULL; 01891 entry_list *obs = NULL; 01892 cpl_array *n_std_star_obs = NULL; 01893 01894 /* Equation system */ 01895 cpl_matrix *eqn_lhs = NULL, 01896 *eqn_rhs = NULL, 01897 *eqn_cov_rhs = NULL, 01898 *eqn_result = NULL, 01899 *result_polyf = NULL, 01900 *result_cov_polyf = NULL, 01901 *result_params = NULL, 01902 *result_cov_params = NULL, 01903 *result_polyp = NULL, 01904 *result_cov_polyp = NULL, 01905 *tmp_mat = NULL; 01906 01907 /* polynomials to fit */ 01908 cpl_polynomial *polyf = NULL, 01909 *polyf_definition = NULL, 01910 *polyf_variance = NULL, 01911 *polyp = NULL, 01912 *polyp_definition = NULL; 01913 01914 /* Other */ 01915 fors_setting *setting = NULL; 01916 const char *tag = NULL; 01917 int row; 01918 01919 /* Photometric parameters */ 01920 cpl_propertylist *qc = NULL; 01921 double qc_zeropoint = -1.0; 01922 double qc_zeropoint_err = -1.0; 01923 double qc_extinction = -1.0; 01924 double qc_extinction_err = -1.0; 01925 double qc_colorterm = -1.0; 01926 double qc_colorterm_err = -1.0; 01927 01928 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 01929 /* Find input */ 01930 aligned_phot_frames = fors_frameset_extract(frames, ALIGNED_PHOT); 01931 cassure(cpl_frameset_get_size(aligned_phot_frames) > 0, 01932 CPL_ERROR_DATA_NOT_FOUND, 01933 return, 01934 "No %s provided", ALIGNED_PHOT); 01935 01936 master_flat_frame = fors_frameset_extract(frames, MASTER_SKY_FLAT_IMG); 01937 cassure(cpl_frameset_get_size(master_flat_frame) > 0, 01938 CPL_ERROR_DATA_NOT_FOUND, 01939 return, 01940 "No %s provided", MASTER_SKY_FLAT_IMG); 01941 01942 phot_table = fors_frameset_extract(frames, PHOT_TABLE); 01943 cassure(cpl_frameset_get_size(phot_table) == 1, 01944 CPL_ERROR_DATA_NOT_FOUND, 01945 return, 01946 "One %s required. %d found", 01947 PHOT_TABLE, cpl_frameset_get_size(phot_table)); 01948 01949 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 01950 /* Get command line parameters */ 01951 bool fit_z, 01952 override_fit_m, 01953 fit_c, 01954 use_all; 01955 int degreef1, 01956 degreef2, 01957 degreep; 01958 fors_fit_ncoeff fit_e; 01959 01960 degreef1 = fors_photometry_parameter_get_num( 01961 parameters, 01962 "degreef1", 01963 CPL_TYPE_INT); 01964 degreef2 = fors_photometry_parameter_get_num( 01965 parameters, 01966 "degreef2", 01967 CPL_TYPE_INT); 01968 degreep = fors_photometry_parameter_get_num( 01969 parameters, 01970 "degreep", 01971 CPL_TYPE_INT); 01972 fit_z = fors_photometry_parameter_get_num( 01973 parameters, 01974 "fitz", 01975 CPL_TYPE_BOOL); 01976 override_fit_m = fors_photometry_parameter_get_num( 01977 parameters, 01978 "fit_all_mag", 01979 CPL_TYPE_BOOL); 01980 fit_c = fors_photometry_parameter_get_num( 01981 parameters, 01982 "fitc", 01983 CPL_TYPE_BOOL); 01984 use_all = fors_photometry_parameter_get_num( 01985 parameters, 01986 "use_all_stars", 01987 CPL_TYPE_BOOL); 01988 fit_e = fors_photometry_parameter_get_ncoeff( 01989 parameters, 01990 "fite"); 01991 assure( !cpl_error_get_code(), return, NULL ); 01992 01993 if (fit_e == FORS_FIT_NCOEFF_PERFRAME 01994 && fit_z == true) 01995 { 01996 cpl_error_set_message( cpl_func, 01997 CPL_ERROR_ILLEGAL_INPUT, 01998 "Fitting one atmospheric " 01999 "extinction per frame and the " 02000 "zeropoint is ambiguous and " 02001 "therefore not possible"); 02002 return; 02003 } 02004 02005 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 02006 /* Get instrument and filter settings */ 02007 02008 setting = fors_setting_new( cpl_frameset_get_first_const( 02009 aligned_phot_frames)); 02010 assure( !cpl_error_get_code(), 02011 return, 02012 "Could not get instrument setting"); 02013 02014 /* Load filter coefficients */ 02015 struct phot_input { 02016 double color_coeff, 02017 dcolor_coeff, 02018 ext, 02019 dext, 02020 zpoint, 02021 dzpoint; 02022 } phot_input; 02023 02024 phot_input.color_coeff = 0.0; 02025 phot_input.dcolor_coeff = 0.0; 02026 phot_input.ext = 0.0; 02027 phot_input.dext = 0.0; 02028 phot_input.zpoint = 0.0; 02029 phot_input.dzpoint = 0.0; 02030 02031 cpl_msg_info(cpl_func, "Loading photometry table"); 02032 fors_phot_table_load( cpl_frameset_get_first_const( 02033 phot_table), 02034 setting, 02035 fit_c ? NULL 02036 : &phot_input.color_coeff, 02037 fit_c ? NULL 02038 : &phot_input.dcolor_coeff, 02039 fit_e != FORS_FIT_NCOEFF_NO ? NULL 02040 : &phot_input.ext, 02041 fit_e != FORS_FIT_NCOEFF_NO ? NULL 02042 : &phot_input.dext, 02043 fit_z ? NULL 02044 : &phot_input.zpoint, 02045 fit_z ? NULL 02046 : &phot_input.dzpoint); 02047 assure( !cpl_error_get_code(), 02048 return, 02049 "Could not load photometry table"); 02050 02051 /* Check fixed photometric input */ 02052 cpl_msg_indent_more(); 02053 if (!fit_c) 02054 { 02055 fors_photometry_check_input_value( phot_input.color_coeff, 02056 phot_input.dcolor_coeff, 02057 "color correction term", 02058 NULL/*"photometry table"*/, 02059 -10,/* min limit */ 02060 10, /* max limit */ 02061 1); /* max error */ 02062 } 02063 if (fit_e == FORS_FIT_NCOEFF_NO) 02064 { 02065 fors_photometry_check_input_value( phot_input.ext, 02066 phot_input.dext, 02067 "atmospheric extinction", 02068 NULL/*"photometry table"*/, 02069 0, /* min limit */ 02070 5, /* max limit */ 02071 1); /* max error */ 02072 } 02073 if (!fit_z) 02074 { 02075 fors_photometry_check_input_value( phot_input.zpoint, 02076 phot_input.dzpoint, 02077 "zeropoint", 02078 NULL/*"photometry table"*/, 02079 0, /* min limit */ 02080 50, /* max limit */ 02081 1); /* max error */ 02082 } 02083 cpl_msg_indent_less(); 02084 if (cpl_error_get_code() != CPL_ERROR_NONE) 02085 return; 02086 02087 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 02088 /* Read input observation table */ 02089 int n_mag_fits, 02090 n_frames; 02091 int (*get_atm_ext_id_func)(const cpl_propertylist*); 02092 02093 cpl_msg_info( cpl_func, 02094 "Importing %s tables:", 02095 ALIGNED_PHOT); 02096 cpl_msg_indent_more(); 02097 02098 switch (fit_e) 02099 { 02100 case FORS_FIT_NCOEFF_PERNIGHT: 02101 get_atm_ext_id_func = fors_photometry_get_night_id; 02102 break; 02103 default: 02104 get_atm_ext_id_func = NULL; 02105 } 02106 02107 obs = fors_photometry_read_input( aligned_phot_frames, 02108 setting, 02109 get_atm_ext_id_func, 02110 use_all, 02111 &n_frames, 02112 &std_star_list, 02113 degreef1 < 1); 02114 assure(!cpl_error_get_code(), return, NULL); 02115 02116 fors_photometry_adjust_fit_mag_flags( std_star_list, 02117 obs, 02118 override_fit_m, 02119 &n_mag_fits); 02120 assure(!cpl_error_get_code(), return, NULL); 02121 02122 fors_photometry_atm_ext_create_indices( obs, 02123 fit_e); 02124 passure(!cpl_error_get_code(), return); 02125 02126 if (fit_e != FORS_FIT_NCOEFF_NO && fit_e != FORS_FIT_NCOEFF_ONE) 02127 { 02128 summary = fors_photometry_atm_ext_print_index_by_framename( 02129 obs, 02130 aligned_phot_frames); 02131 assure(!cpl_error_get_code(), return, "Internal error" ); 02132 } 02133 02134 fors_photometry_remove_unnecessary( std_star_list, 02135 obs, 02136 &n_mag_fits); 02137 assure(!cpl_error_get_code(), return, NULL); 02138 02139 fors_photometry_check_fitparam_atm_ext(obs, fit_e, fit_z); 02140 assure(!cpl_error_get_code(), return, NULL); 02141 02142 entry_list_print(obs, CPL_MSG_DEBUG); 02143 02144 { 02145 int ntot, 02146 n_std_stars; 02147 ntot = entry_list_size(obs); 02148 n_std_stars = fors_std_star_list_size(std_star_list); 02149 02150 cpl_msg_info(cpl_func, 02151 "Found %d table%s, %d star%s, %d unique star%s, " 02152 "%d magnitude%s to determine", 02153 n_frames, n_frames != 1 ? "s" : "", 02154 ntot, ntot != 1 ? "s" : "", 02155 n_std_stars, n_std_stars != 1 ? "s" : "", 02156 n_mag_fits, n_mag_fits != 1 ? "s" : ""); 02157 } 02158 cpl_msg_indent_less(); 02159 02160 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 02161 /* Build equation system */ 02162 int n_coeff_polyf = 0, 02163 n_coeff_polyp = 0, 02164 n_coeff_params = 0, 02165 n_coeff_params_ext = 0; 02166 fors_matrix_null(&eqn_lhs); 02167 02168 polyf_definition = fors_photometry_define_polyf( 02169 degreef1, 02170 degreef2); 02171 polyp_definition = fors_photometry_define_polyp( 02172 degreep); 02173 assure(!cpl_error_get_code(), return, NULL); 02174 02175 /* Left hand side */ 02176 tmp_mat = build_equations_lhs_matrix_from_poly( 02177 obs, 02178 polyf_definition, 02179 "f", 02180 &entry_get_powers_x_y); 02181 assure(!cpl_error_get_code(), return, NULL); 02182 if (tmp_mat != NULL) n_coeff_polyf = cpl_matrix_get_ncol(tmp_mat); 02183 fors_matrix_append_delete(&eqn_lhs, &tmp_mat); 02184 02185 tmp_mat = build_equations_lhs_matrix_from_parameters( 02186 obs, 02187 std_star_list, 02188 fit_z, 02189 fit_c, 02190 &n_coeff_params_ext); 02191 assure(!cpl_error_get_code(), return, NULL); 02192 if (tmp_mat != NULL) n_coeff_params = cpl_matrix_get_ncol(tmp_mat); 02193 fors_matrix_append_delete(&eqn_lhs, &tmp_mat); 02194 02195 tmp_mat = build_equations_lhs_matrix_from_poly( 02196 obs, 02197 polyp_definition, 02198 "p", 02199 &entry_get_powers_airmass_color); 02200 assure(!cpl_error_get_code(), return, NULL); 02201 if (tmp_mat != NULL) n_coeff_polyp = cpl_matrix_get_ncol(tmp_mat); 02202 fors_matrix_append_delete(&eqn_lhs, &tmp_mat); 02203 02204 /* Right hand side */ 02205 build_equations_rhs_cov( obs, 02206 std_star_list, 02207 fit_z, 02208 fit_c, 02209 (n_coeff_params_ext > 0),/* fit_e */ 02210 phot_input.color_coeff, 02211 phot_input.dcolor_coeff, 02212 phot_input.ext, 02213 phot_input.dext, 02214 phot_input.zpoint, 02215 phot_input.dzpoint, 02216 &eqn_rhs, 02217 &eqn_cov_rhs); 02218 /*cpl_msg_info(cpl_func, "lhs"); 02219 cpl_matrix_dump(eqn_lhs, stdout); 02220 cpl_msg_info(cpl_func, "rhs"); 02221 cpl_matrix_dump(eqn_rhs, stdout); 02222 cpl_msg_info(cpl_func, "cov_rhs"); 02223 cpl_matrix_dump(eqn_cov_rhs, stdout);*/ 02224 02225 assure( !cpl_error_get_code(), return, "Could not setup rhs equations" ); 02226 02227 int n_parameters = cpl_matrix_get_ncol(eqn_lhs); 02228 fors_matrix_null(&tmp_mat); 02229 02230 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 02231 /* Solve the equation system */ 02232 { 02233 int eqn_nrows = cpl_matrix_get_nrow(eqn_lhs); 02234 cpl_msg_info(cpl_func, "Solving %d equation%s for %d parameter%s", 02235 eqn_nrows, eqn_nrows != 1 ? "s" : "", 02236 n_parameters, n_parameters != 1 ? "s" : ""); 02237 } 02238 02239 /* Solve this overdetermined set of equations in the least chi squared 02240 sense using Cholesky-decomposition, output matrix 02241 is the solution vector (1st column) and the covariance matrix 02242 in the remaining columns. 02243 */ 02244 double red_chisq; 02245 eqn_result = solve_normal( eqn_lhs, 02246 eqn_rhs, 02247 eqn_cov_rhs, 02248 &red_chisq); 02249 fors_matrix_null(&eqn_lhs); 02250 fors_matrix_null(&eqn_rhs); 02251 fors_matrix_null(&eqn_cov_rhs); 02252 02253 assure( !cpl_error_get_code(), return, "Could not solve equation system"); 02254 02255 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 02256 /* Extract the partial results, propagate polynomial error */ 02257 02258 /* Print solution, convert to CPL polynomial */ 02259 int offset = 0; 02260 { 02261 int size = n_coeff_polyf; 02262 if (size > 0) 02263 { 02264 result_polyf = cpl_matrix_extract( 02265 eqn_result, 02266 offset, 0, 02267 1, 1, 02268 size, 1); 02269 result_cov_polyf = cpl_matrix_extract( 02270 eqn_result, 02271 offset, 1+offset, 02272 1, 1, 02273 size, size); 02274 offset += size; 02275 } 02276 } 02277 { 02278 int size = n_coeff_params; 02279 if (size > 0) 02280 { 02281 result_params = cpl_matrix_extract( 02282 eqn_result, 02283 offset, 0, 02284 1, 1, 02285 size, 1); 02286 result_cov_params = cpl_matrix_extract( 02287 eqn_result, 02288 offset, 1+offset, 02289 1, 1, 02290 size, size); 02291 } 02292 offset += size; 02293 } 02294 { 02295 int size = n_coeff_polyp; 02296 if (size > 0) 02297 { 02298 result_polyp = cpl_matrix_extract( 02299 eqn_result, 02300 offset, 0, 02301 1, 1, 02302 size, 1); 02303 result_cov_polyp = cpl_matrix_extract(eqn_result, 02304 offset, 1+offset, 02305 1, 1, 02306 size, size); 02307 } 02308 offset += size; 02309 } 02310 passure(!cpl_error_get_code(), return); 02311 02312 fors_photometry_poly_new_from_coefficients( 02313 polyf_definition, 02314 result_polyf, /* NULL if f empty*/ 02315 result_cov_polyf,/* NULL if f emp.*/ 02316 &polyf, 02317 &polyf_variance); 02318 passure(!cpl_error_get_code(), return); 02319 fors_photometry_poly_new_from_coefficients( 02320 polyp_definition, 02321 result_polyp, /* NULL if p empty*/ 02322 NULL,/* NULL if p emp.*/ 02323 &polyp, 02324 NULL); 02325 passure(!cpl_error_get_code(), return); 02326 02327 cpl_msg_indent_more(); 02328 fors_polynomial_dump(polyf, "f", CPL_MSG_INFO, polyf_definition); 02329 fors_polynomial_dump(polyp, "p", CPL_MSG_INFO, polyp_definition); 02330 cpl_msg_indent_less(); 02331 02332 { 02333 /* magnitudes */ 02334 int k, 02335 i = 0; 02336 const fors_std_star *std; 02337 02338 /* count observations of std star objects */ 02339 n_std_star_obs = fors_photometry_count_observations( 02340 std_star_list, 02341 obs); 02342 passure(!cpl_error_get_code(), return); 02343 02344 cpl_msg_indent_more(); 02345 for ( std = fors_std_star_list_first_const(std_star_list), k = 0; 02346 std != NULL; 02347 std = fors_std_star_list_next_const(std_star_list), k++) 02348 { 02349 if (std->trusted) /* !(fit magnitude) */ 02350 { 02351 cpl_msg_info(cpl_func, "M%d = %f +- %f mag (fixed, %s, %d obs)", 02352 k, 02353 std->magnitude, 02354 std->dmagnitude, 02355 std->name, 02356 cpl_array_get_int(n_std_star_obs, k, NULL)); 02357 } 02358 else { 02359 cpl_msg_info(cpl_func, "M%d = %f +- %f mag (free, %s, %d obs)", 02360 k, 02361 cpl_matrix_get(result_params, i, 0), 02362 sqrt(cpl_matrix_get(result_cov_params, i, i)), 02363 std->name, 02364 cpl_array_get_int(n_std_star_obs, k, NULL)); 02365 i++; 02366 } 02367 } 02368 cpl_msg_indent_less(); 02369 passure(!cpl_error_get_code(), return); 02370 02371 cpl_array_delete(n_std_star_obs); n_std_star_obs = NULL; 02372 fors_std_star_list_delete(&std_star_list, fors_std_star_delete); 02373 entry_list_delete(&obs, entry_delete_but_standard); obs = NULL; 02374 02375 /* zeropoint */ 02376 cpl_msg_indent_more(); 02377 if (fit_z) 02378 { 02379 qc_zeropoint = cpl_matrix_get(result_params, i, 0); 02380 qc_zeropoint_err = sqrt(cpl_matrix_get(result_cov_params, i, i)); 02381 cpl_msg_info(cpl_func, "Z = %f +- %f mag", 02382 qc_zeropoint, 02383 qc_zeropoint_err); 02384 i++; 02385 } 02386 cpl_msg_indent_less(); 02387 passure(!cpl_error_get_code(), return); 02388 02389 /* extinction */ 02390 cpl_msg_indent_more(); 02391 if (n_coeff_params_ext > 0) 02392 { 02393 qc_extinction = cpl_matrix_get(result_params, i, 0); 02394 qc_extinction_err = sqrt(cpl_matrix_get(result_cov_params, i, i)); 02395 if (n_coeff_params_ext == 1) 02396 { 02397 cpl_msg_info(cpl_func, "E = %f +- %f mag/airmass", 02398 qc_extinction, 02399 qc_extinction_err); 02400 i++; 02401 } 02402 else 02403 { 02404 if (summary) { 02405 cpl_table_new_column(summary, "EXT", CPL_TYPE_DOUBLE); 02406 cpl_table_new_column(summary, "DEXT", CPL_TYPE_DOUBLE); 02407 if (fit_e == FORS_FIT_NCOEFF_PERFRAME) { 02408 cpl_table_new_column(summary, "MJD-OBS", 02409 CPL_TYPE_DOUBLE); 02410 } 02411 if (fit_e == FORS_FIT_NCOEFF_PERNIGHT) { 02412 cpl_table_new_column(summary, "MJD-NIGHT", 02413 CPL_TYPE_INT); 02414 } 02415 02416 } 02417 02418 for (k = 0; k < n_coeff_params_ext; k++) 02419 { 02420 double ext = cpl_matrix_get(result_params, i, 0); 02421 double dext = sqrt(cpl_matrix_get(result_cov_params, i, i)); 02422 02423 cpl_msg_info(cpl_func, "E_%d = %f +- %f mag/airmass", 02424 k, ext, dext); 02425 02426 if (summary) { 02427 cpl_table_select_all(summary); 02428 cpl_table_and_selected_int(summary, "index", 02429 CPL_EQUAL_TO, k); 02430 for (row = 0; row < n_frames; row++) { 02431 if (cpl_table_is_selected(summary, row)) { 02432 const char *filename = 02433 cpl_table_get_string(summary, "filename", row); 02434 cpl_propertylist *plist = 02435 cpl_propertylist_load_regexp(filename, 0, 02436 "MJD-OBS|ORIGIN", 02437 0); 02438 02439 cpl_table_set_double(summary, 02440 "EXT", row, ext); 02441 cpl_table_set_double(summary, 02442 "DEXT", row, dext); 02443 if (fit_e == FORS_FIT_NCOEFF_PERFRAME) { 02444 cpl_table_set_double(summary, 02445 "MJD-OBS", row, 02446 cpl_propertylist_get_double(plist, 02447 "MJD-OBS")); 02448 } 02449 if (fit_e == FORS_FIT_NCOEFF_PERNIGHT) { 02450 cpl_table_set_int(summary, "MJD-NIGHT", 02451 row, 02452 fors_photometry_get_night_id(plist)); 02453 } 02454 02455 cpl_propertylist_delete(plist); 02456 } 02457 } 02458 } 02459 02460 i++; 02461 } 02462 } 02463 } 02464 cpl_msg_indent_less(); 02465 passure(!cpl_error_get_code(), return); 02466 02467 if (summary) { 02468 cpl_table_select_all(summary); 02469 cpl_table_erase_column(summary, "index"); 02470 } 02471 02472 /* color */ 02473 cpl_msg_indent_more(); 02474 if (fit_c) { 02475 /* Note different sign convention. The values 02476 provided in PHOT_TABLEs are actually -c. 02477 As in fors_std_cat_load() 02478 */ 02479 qc_colorterm = cpl_matrix_get(result_params, i, 0); 02480 qc_colorterm = -qc_colorterm; /* External convention */ 02481 qc_colorterm_err = sqrt(cpl_matrix_get(result_cov_params, i, i)); 02482 cpl_msg_info(cpl_func, "C_correction = %f +- %f", 02483 qc_colorterm, qc_colorterm_err); 02484 i++; 02485 } 02486 cpl_msg_indent_less(); 02487 passure(!cpl_error_get_code(), return); 02488 02489 /* Abort if crazy values... */ 02490 if (qc_zeropoint_err > 1.0) { 02491 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT, 02492 "Unreliable zeropoint!"); 02493 cleanup; 02494 return; 02495 } 02496 if (qc_extinction_err > 1.0) { 02497 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT, 02498 "Unreliable atmospheric extinction!"); 02499 cleanup; 02500 return; 02501 } 02502 if (qc_colorterm_err > 1.0) { 02503 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT, 02504 "Unreliable color correction term!"); 02505 cleanup; 02506 return; 02507 } 02508 if (qc_extinction_err > 0.0 && qc_extinction <= 0.0) { 02509 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT, 02510 "Impossible atmospheric extinction!"); 02511 cleanup; 02512 return; 02513 } 02514 passure(!cpl_error_get_code(), return); 02515 02516 cpl_msg_indent_more(); 02517 cpl_msg_info(cpl_func, "Reduced chi square = %f", red_chisq); 02518 cpl_msg_indent_less(); 02519 02520 } 02521 passure(!cpl_error_get_code(), return); 02522 /* Code checks: 02523 * - polynomials must exist (also if empty), they might be used later */ 02524 passure(polyf != NULL, return); 02525 passure(polyp != NULL, return); 02526 02527 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 02528 /* Compute correction image, apply to master flat */ 02529 { 02530 int nx, 02531 ny; 02532 02533 master_flat = fors_image_load( cpl_frameset_get_first_const( 02534 master_flat_frame), 02535 NULL, setting, NULL); 02536 assure( !cpl_error_get_code(), return, "Could not load master flat"); 02537 02538 nx = fors_image_get_size_x(master_flat); 02539 ny = fors_image_get_size_y(master_flat); 02540 cpl_image *correction_map = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 02541 cpl_image *correction_map_v = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 02542 02543 cpl_msg_info(cpl_func, "Creating correction map (magnitude)"); 02544 cpl_image_fill_polynomial(correction_map, polyf, 02545 1.0, 1.0, 1.0, 1.0); 02546 passure(!cpl_error_get_code(), return); 02547 cpl_image_fill_polynomial(correction_map_v, polyf_variance, 02548 1.0, 1.0, 1.0, 1.0); 02549 passure(!cpl_error_get_code(), return); 02550 02551 correction = fors_image_new(correction_map, correction_map_v); 02552 } 02553 passure(!cpl_error_get_code(), return); 02554 02555 cpl_polynomial_delete(polyf); polyf = NULL; 02556 cpl_polynomial_delete(polyf_variance); polyf_variance = NULL; 02557 fors_matrix_null(&eqn_result); 02558 02559 if (qc_zeropoint_err > 0.0 || 02560 qc_extinction_err > 0.0 || 02561 qc_colorterm_err > 0.0) { 02562 02563 phot_coeff = fors_phot_coeff_create(setting, 02564 qc_colorterm, 02565 qc_colorterm_err, 02566 qc_extinction, 02567 qc_extinction_err, 02568 qc_zeropoint, 02569 qc_zeropoint_err); 02570 02571 /* 02572 * Write QCs 02573 */ 02574 02575 qc = cpl_propertylist_new(); 02576 02577 fors_qc_start_group(qc, fors_qc_dic_version, setting->instrument); 02578 02579 /* 02580 fors_qc_write_group_heading(cpl_frameset_get_first_const(master_flat_frame), 02581 CORRECTION_MAP, 02582 setting->instrument); 02583 assure( !cpl_error_get_code(), return, "Could not write %s QC parameters", 02584 CORRECTION_MAP); 02585 */ 02586 02587 if (qc_zeropoint_err > 0.0) { 02588 fors_qc_write_qc_double(qc, 02589 qc_zeropoint, 02590 "QC.INSTRUMENT.ZEROPOINT", 02591 "mag", 02592 "Instrument zeropoint", 02593 setting->instrument); 02594 02595 fors_qc_write_qc_double(qc, 02596 qc_zeropoint_err, 02597 "QC.INSTRUMENT.ZEROPOINT.ERROR", 02598 "mag", 02599 "Instrument zeropoint error", 02600 setting->instrument); 02601 } 02602 02603 if (qc_extinction_err > 0.0 && summary == NULL) { 02604 fors_qc_write_qc_double(qc, 02605 qc_extinction, 02606 "QC.ATMOSPHERIC.EXTINCTION", 02607 "mag/airmass", 02608 "Atmospheric extinction", 02609 setting->instrument); 02610 02611 fors_qc_write_qc_double(qc, 02612 qc_extinction_err, 02613 "QC.ATMOSPHERIC.EXTINCTION.ERROR", 02614 "mag/airmass", 02615 "Atmospheric extinction error", 02616 setting->instrument); 02617 } 02618 02619 if (qc_colorterm_err > 0.0) { 02620 fors_qc_write_qc_double(qc, 02621 qc_colorterm, 02622 "QC.COLOR.CORRECTION", 02623 NULL, 02624 "Linear color correction term", 02625 setting->instrument); 02626 02627 fors_qc_write_qc_double(qc, 02628 qc_colorterm_err, 02629 "QC.COLOR.CORRECTION.ERROR", 02630 NULL, 02631 "Linear color correction term error", 02632 setting->instrument); 02633 } 02634 02635 fors_qc_end_group(); 02636 02637 /* 02638 * End write QCs 02639 */ 02640 } 02641 passure(!cpl_error_get_code(), return); 02642 02643 if (summary && phot_coeff) { 02644 cpl_table_erase_column(phot_coeff, "EXT"); 02645 cpl_table_erase_column(phot_coeff, "DEXT"); 02646 if (1 == cpl_table_get_ncol(phot_coeff)) { 02647 cpl_table_delete(phot_coeff); 02648 phot_coeff = NULL; 02649 } 02650 } 02651 02652 if (phot_coeff) { 02653 fors_dfs_save_table(frames, phot_coeff, PHOT_COEFF_TABLE, 02654 qc, parameters, fors_photometry_name, 02655 cpl_frameset_get_first_const(master_flat_frame)); 02656 cpl_propertylist_delete(qc); qc = NULL; 02657 } 02658 02659 assure( !cpl_error_get_code(), return, "Saving %s failed", 02660 PHOT_COEFF_TABLE); 02661 02662 if (summary) { 02663 if (fit_e == FORS_FIT_NCOEFF_PERFRAME) { 02664 tag = EXTINCTION_PER_FRAME; 02665 } 02666 if (fit_e == FORS_FIT_NCOEFF_PERNIGHT) { 02667 tag = EXTINCTION_PER_NIGHT; 02668 } 02669 fors_dfs_save_table(frames, summary, tag, NULL, parameters, 02670 fors_photometry_name, 02671 cpl_frameset_get_first_const(master_flat_frame)); 02672 } 02673 02674 assure( !cpl_error_get_code(), return, "Saving %s failed", tag); 02675 02676 if (degreef1 > 0) { 02677 02678 fors_dfs_save_image(frames, correction, CORRECTION_MAP, 02679 qc, parameters, fors_photometry_name, 02680 cpl_frameset_get_first_const(master_flat_frame)); 02681 02682 } 02683 02684 assure( !cpl_error_get_code(), return, "Saving %s failed", 02685 CORRECTION_MAP); 02686 02687 cpl_propertylist_delete(qc); 02688 02689 /* Convert from magnitude to flux. 02690 F = 10^(-0.4 m) 02691 */ 02692 if (degreef1 > 0) { 02693 cpl_msg_info(cpl_func, "Creating correction map (flux)"); 02694 02695 fors_image_multiply_scalar(correction, -0.4, -1); 02696 fors_image_exponential(correction, 10, -1); 02697 02698 /* Normalize to median = 1 */ 02699 fors_image_divide_scalar(correction, 02700 fors_image_get_median(correction, NULL), -1.0); 02701 02702 fors_dfs_save_image(frames, correction, CORRECTION_FACTOR, 02703 NULL, parameters, fors_photometry_name, 02704 cpl_frameset_get_first_const(master_flat_frame)); 02705 02706 assure( !cpl_error_get_code(), return, "Saving %s failed", 02707 CORRECTION_FACTOR); 02708 } 02709 02710 if (degreef1 > 0) { 02711 cpl_msg_info(cpl_func, "Creating corrected master flat"); 02712 fors_image_multiply(master_flat, correction); 02713 02714 fors_dfs_save_image(frames, master_flat, MASTER_FLAT_IMG, 02715 NULL, parameters, fors_photometry_name, 02716 cpl_frameset_get_first_const(master_flat_frame)); 02717 assure( !cpl_error_get_code(), return, "Saving %s failed", 02718 MASTER_FLAT_IMG); 02719 } 02720 02721 cleanup; 02722 return; 02723 } 02724 02725 /*----------------------------------------------------------------------------*/ 02726 #undef cleanup 02727 #define cleanup \ 02728 do { \ 02729 fors_std_star_delete(&std_star); \ 02730 cpl_propertylist_delete(header); header = NULL; \ 02731 cpl_table_delete(aligned_phot); aligned_phot = NULL; \ 02732 fors_setting_delete(&setting_f); \ 02733 fors_delete_star_lists(&obs, std_star_list); \ 02734 fors_star_delete_but_standard(&obs_star); \ 02735 fors_std_star_delete(&std_star); \ 02736 \ 02737 *n_frames = 0; \ 02738 } while (0) 02739 02754 /*----------------------------------------------------------------------------*/ 02755 static entry_list * 02756 fors_photometry_read_input( const cpl_frameset *alphot_frames, 02757 const fors_setting *setting, 02758 int (*get_atm_ext_id_function)( 02759 const cpl_propertylist *header), 02760 bool import_unknown, 02761 int *n_frames, 02762 fors_std_star_list **std_star_list, 02763 int filter) 02764 { 02765 entry_list *obs = NULL; 02766 fors_setting *setting_f = NULL; 02767 fors_star *obs_star = NULL; 02768 fors_std_star *std_star = NULL; 02769 cpl_propertylist *header = NULL; 02770 cpl_table *aligned_phot = NULL; 02771 const cpl_frame *f; 02772 int iframe, 02773 inonstd = 0; 02774 cpl_errorstate errstat = cpl_errorstate_get(); 02775 02776 /* init output pointers */ 02777 cleanup; 02778 02779 /* prepare */ 02780 obs = entry_list_new(); 02781 *std_star_list = fors_std_star_list_new(); 02782 02783 /* 02784 * Loop on all aligned photometric tables in input, and count the 02785 * found frames in iframe. 02786 */ 02787 for (f = cpl_frameset_get_first_const(alphot_frames), iframe = 0; 02788 f != NULL; 02789 f = cpl_frameset_get_next_const(alphot_frames), iframe++) 02790 { 02791 const char *filename; 02792 int atm_ext_id = 0; 02793 double airmass; 02794 02795 filename = cpl_frame_get_filename(f); 02796 cpl_msg_info(cpl_func, "Loading %s", filename); 02797 cpl_msg_indent_more(); 02798 02799 aligned_phot = cpl_table_load(filename, 1, 1); 02800 assure( cpl_errorstate_is_equal(errstat), 02801 return NULL, 02802 "Could not load %s", 02803 filename); 02804 /* %%% */ 02805 if (filter && cpl_table_has_column(aligned_phot, "WEIGHT")) { 02806 cpl_table_and_selected_double(aligned_phot, 02807 "WEIGHT", CPL_LESS_THAN, 1.0); 02808 cpl_table_and_selected_double(aligned_phot, 02809 "WEIGHT", CPL_GREATER_THAN, -1.0); 02810 cpl_table_erase_selected(aligned_phot); 02811 } 02812 /* %%% */ 02813 02814 header = cpl_propertylist_load(filename, 0); 02815 assure( cpl_errorstate_is_equal(errstat), 02816 return NULL, 02817 "Could not load %s header", 02818 filename); 02819 02820 /* 02821 * Load and verify setting for this frame 02822 */ 02823 fors_setting_verify(setting, f, &setting_f); 02824 02825 airmass = cpl_propertylist_get_double(header, "AIRMASS"); 02826 assure( cpl_errorstate_is_equal(errstat), 02827 return NULL, 02828 "%s: Could not read %s", 02829 filename, "AIRMASS"); 02830 02831 /* FIXME: 02832 * This whole section is for verifying the input table. The 02833 * structure of this table is probably defined in some other 02834 * place too... Likely this is a dependency between modules 02835 * that should be eliminated. Please check... (C.Izzo, 28.01.08) 02836 */ 02837 struct { 02838 const char *name; 02839 cpl_type type; 02840 bool optional; 02841 } col[] = 02842 {{"RA", CPL_TYPE_DOUBLE, false}, 02843 {"DEC", CPL_TYPE_DOUBLE, false}, 02844 {"X", CPL_TYPE_DOUBLE, false}, 02845 {"Y", CPL_TYPE_DOUBLE, false}, 02846 {"FWHM", CPL_TYPE_DOUBLE, false}, 02847 {"A", CPL_TYPE_DOUBLE, false}, 02848 {"B", CPL_TYPE_DOUBLE, false}, 02849 {"THETA", CPL_TYPE_DOUBLE, false}, 02850 {"INSTR_MAG", CPL_TYPE_DOUBLE, false}, 02851 {"DINSTR_MAG", CPL_TYPE_DOUBLE, false}, 02852 {"CAT_MAG", CPL_TYPE_DOUBLE, false}, 02853 {"DCAT_MAG", CPL_TYPE_DOUBLE, false}, 02854 {"MAG", CPL_TYPE_DOUBLE, false}, 02855 {"DMAG", CPL_TYPE_DOUBLE, false}, 02856 {"COLOR", CPL_TYPE_DOUBLE, false}, 02857 {"DCOLOR", CPL_TYPE_DOUBLE, true}, /* miss in old data */ 02858 {"COV_CATM_COL", CPL_TYPE_DOUBLE, true}, /* miss in old data */ 02859 {"CLASS_STAR", CPL_TYPE_DOUBLE, false}, 02860 {"USE_CAT", CPL_TYPE_INT, false}, 02861 {"OBJECT", CPL_TYPE_STRING, false}}; 02862 { 02863 unsigned i = 0; 02864 for (i = 0; i < sizeof(col) / sizeof(*col); i++) 02865 { 02866 bool exists; 02867 exists = cpl_table_has_column(aligned_phot, col[i].name); 02868 cassure(exists || col[i].optional, 02869 CPL_ERROR_DATA_NOT_FOUND, 02870 return NULL, 02871 "%s: Missing column %s", filename, col[i].name); 02872 cassure((!exists) || 02873 cpl_table_get_column_type(aligned_phot, col[i].name) 02874 == col[i].type, 02875 CPL_ERROR_INVALID_TYPE, 02876 return NULL, 02877 "%s: column %s: Type is %s, %s expected ", 02878 filename, 02879 col[i].name, 02880 fors_type_get_string( 02881 cpl_table_get_column_type(aligned_phot, 02882 col[i].name) 02883 ), 02884 fors_type_get_string(col[i].type)); 02885 } 02886 } /* Table check done */ 02887 02888 if (get_atm_ext_id_function != NULL) 02889 { 02890 atm_ext_id = get_atm_ext_id_function(header); 02891 assure( cpl_errorstate_is_equal(errstat), 02892 return NULL, 02893 "Getting atmospheric extinction " 02894 "identifier failed."); 02895 } 02896 02897 /* 02898 * Get IDed stars in this table: 02899 */ 02900 int i; 02901 for (i = 0; i < cpl_table_get_nrow(aligned_phot); i++) 02902 { 02903 obs_star = fors_star_new_from_table( 02904 aligned_phot, 02905 i, 02906 "X", "Y", 02907 "FWHM", 02908 "A", "B", 02909 "THETA", 02910 "INSTR_MAG", "DINSTR_MAG", 02911 "CLASS_STAR"); 02912 std_star = fors_std_star_new_from_table( 02913 aligned_phot, 02914 i, 02915 "RA", "DEC", 02916 "MAG", "DMAG", 02917 "CAT_MAG", "DCAT_MAG", 02918 "COLOR", NULL, /* DCOLOR */ 02919 NULL, /* COV_CATM_COL */ 02920 NULL, NULL, 02921 "OBJECT"); 02922 /* compatibility with old fors_zeropoint products */ 02923 if (cpl_table_has_column(aligned_phot, "DCOLOR") 02924 && cpl_table_has_column(aligned_phot, "COV_CATM_COL")) 02925 { 02926 std_star->dcolor = cpl_table_get( 02927 aligned_phot, 02928 "DCOLOR", 02929 i, 02930 NULL); 02931 std_star->cov_catm_color = cpl_table_get( 02932 aligned_phot, 02933 "COV_CATM_COL", 02934 i, 02935 NULL); 02936 } 02937 /* 02938 * The star and the standard star are the same star. 02939 * The star is detector-oriented, the standard star 02940 * is its identification and includes physical propeties. 02941 * Here the information is linked together, and the 02942 * standard star is "owned" by the star object - so 02943 * it should not be destroyed. (C.Izzo, 28.01.08) 02944 */ 02945 obs_star->id = std_star; 02946 02947 /* Use catalog magnitude xor fit the magnitude: */ 02948 std_star->trusted = (0 != cpl_table_get_int( 02949 aligned_phot, "USE_CAT", i, NULL)); 02950 02951 assure( cpl_errorstate_is_equal(errstat) 02952 && obs_star != NULL 02953 && std_star != NULL, 02954 return NULL, 02955 "Reading from aligned photometry " 02956 "table failed."); 02957 02958 cassure( obs_star->dmagnitude > 0, 02959 CPL_ERROR_ILLEGAL_INPUT, 02960 return NULL, 02961 "Non-positive magnitude error: " 02962 "%f mag at row %d", 02963 obs_star->dmagnitude, 02964 i+1); 02965 02966 /*fors_star_print(CPL_MSG_DEBUG, obs_star); 02967 fors_std_star_print(CPL_MSG_DEBUG, std_star);*/ 02968 02969 if (! fors_extract_check_sex_star(obs_star, NULL)) 02970 { 02971 02972 cpl_msg_warning(cpl_func, "Rejecting object no. %d from " 02973 "frame %d, " 02974 "which should have been caught " 02975 "by recent fors_zeropoint recipe. " 02976 "Consider reprocessing input data.", 02977 i+1, iframe+1); 02978 fors_std_star_delete(&std_star); 02979 } 02980 else if (std_star->name != NULL && (std_star->name)[0] != '\0') 02981 { 02982 /* Object with name is standard star */ 02983 /* Avoid duplicate standard star list entries. */ 02984 std_star = fors_photometry_read_input_listinsert_star_if_new( 02985 *std_star_list, 02986 std_star, 02987 arcsec_tol); 02988 } 02989 else if (import_unknown) /* import non-std stars */ 02990 { 02991 fors_std_star *s_in_list; 02992 02993 std_star->trusted = false; /* don't trust ignoring table flag*/ 02994 02995 s_in_list = fors_photometry_read_input_listinsert_star_if_new( 02996 *std_star_list, 02997 std_star, 02998 arcsec_tol); 02999 03000 if (s_in_list == std_star) /* made it into list */ 03001 { 03002 char name[16]; 03003 sprintf(name, "non-std-%d", inonstd); 03004 fors_std_star_set_name(std_star, name); 03005 inonstd++; 03006 } 03007 03008 std_star = s_in_list; 03009 } 03010 else 03011 { 03012 fors_std_star_delete(&std_star); 03013 } 03014 03015 if (std_star != NULL) 03016 { 03017 entry *e; 03018 obs_star->id = std_star; 03019 /* cannot identify std star id yet, because the used list 03020 * object totally scrambles the order (for whatever reason) */ 03021 e = entry_new( iframe, 03022 -1, 03023 airmass, 03024 setting_f->average_gain, 03025 setting_f->exposure_time, 03026 atm_ext_id, 03027 obs_star); 03028 entry_list_insert( obs, e); 03029 } 03030 else 03031 { 03032 fors_star_delete_but_standard(&obs_star); 03033 } 03034 03035 }/* for each star */ 03036 03037 cpl_propertylist_delete(header); header = NULL; 03038 cpl_table_delete(aligned_phot); aligned_phot = NULL; 03039 fors_setting_delete(&setting_f); 03040 03041 cpl_msg_indent_less(); 03042 }/* For each table */ 03043 03044 *n_frames = iframe; 03045 03046 03047 /* The used list object is actually fed in reverse order (because there 03048 * is only the function list_insert, but not list_append). But we would 03049 * like to access the elements in the same order as we imported them, so 03050 * the fix was the invention of the function list_reverse(). 03051 * hlorch, 17.02.2009 */ 03052 entry_list_reverse(obs); 03053 fors_std_star_list_reverse(*std_star_list); 03054 03055 /* determine the observation's object id */ 03056 { 03057 fors_std_star *ref; 03058 entry *e; 03059 03060 for (e = entry_list_first(obs); e != NULL; e = entry_list_next(obs)) 03061 { 03062 int i; 03063 for ( ref = fors_std_star_list_first(*std_star_list), i = 0; 03064 ref != NULL; 03065 ref = fors_std_star_list_next(*std_star_list), i++) 03066 { 03067 if (e->star->id == ref) 03068 { 03069 e->star_index = i; 03070 break; 03071 } 03072 } 03073 } 03074 } 03075 03076 cassure( entry_list_size(obs) > 0, 03077 CPL_ERROR_DATA_NOT_FOUND, 03078 return NULL, 03079 "No stars found"); 03080 03081 return obs; 03082 } 03083 03084 /*----------------------------------------------------------------------------*/ 03085 #undef cleanup 03086 #define cleanup 03087 03100 /*----------------------------------------------------------------------------*/ 03101 static fors_std_star* 03102 fors_photometry_read_input_listinsert_star_if_new( 03103 fors_std_star_list *std_list, 03104 fors_std_star *std, 03105 double mind_arcsec) 03106 { 03107 cpl_errorstate errstat = cpl_errorstate_get(); 03108 bool found = false; 03109 03110 cassure_automsg( std_list != NULL, 03111 CPL_ERROR_NULL_INPUT, 03112 return std); 03113 cassure_automsg( std != NULL, 03114 CPL_ERROR_NULL_INPUT, 03115 return std); 03116 cassure_automsg( mind_arcsec > 0, 03117 CPL_ERROR_ILLEGAL_INPUT, 03118 return std); 03119 03120 if (fors_std_star_list_size(std_list) > 0) 03121 { 03122 fors_std_star *nearest; 03123 double dist_arcsec; 03124 /* Only if the nearest standard star is farther 03125 * away than 5 arcsecs, insert this standard star 03126 * in the standard star list. */ 03127 nearest = fors_std_star_list_kth_val( 03128 std_list, 1, 03129 (fors_std_star_list_func_eval) 03130 fors_std_star_dist_arcsec, 03131 std); 03132 passure(cpl_errorstate_is_equal(errstat), return std); 03133 03134 dist_arcsec = fors_std_star_dist_arcsec(nearest, std); 03135 passure(cpl_errorstate_is_equal(errstat), return std); 03136 03137 cpl_msg_debug( cpl_func, 03138 "dist = %f arcseconds", 03139 dist_arcsec); 03140 03141 if (dist_arcsec < mind_arcsec) 03142 { 03143 /* trust a star only if it's always trusted */ 03144 nearest->trusted &= std->trusted; 03145 /* delete the new star and link to the old one */ 03146 fors_std_star_delete(&std); 03147 std = nearest; 03148 found = true; 03149 } 03150 } 03151 03152 if (!found) 03153 { 03154 fors_std_star_list_insert(std_list, std); 03155 } 03156 03157 return std; 03158 } 03159 03160 /*----------------------------------------------------------------------------*/ 03161 #undef cleanup 03162 #define cleanup 03163 /* 03164 * @brief Adjust @em trusted flags. 03165 * @param stdl Standard star list 03166 * @param el Observation entry list 03167 * @param override_fit_m Flag whether to fit all catalog magnitudes 03168 * @param n_mag_fits (Output) number of magnitudes to fit 03169 * @return CPL error code 03170 */ 03171 /*----------------------------------------------------------------------------*/ 03172 static cpl_error_code 03173 fors_photometry_adjust_fit_mag_flags( fors_std_star_list *stdl, 03174 entry_list *obsl, 03175 bool override_fit_m, 03176 int *n_mag_fits) 03177 { 03178 fors_std_star *std; 03179 cpl_errorstate errstat = cpl_errorstate_get(); 03180 03181 cassure_automsg( stdl != NULL, 03182 CPL_ERROR_NULL_INPUT, 03183 return cpl_error_get_code()); 03184 cassure_automsg( obsl != NULL, 03185 CPL_ERROR_NULL_INPUT, 03186 return cpl_error_get_code()); 03187 cassure_automsg( n_mag_fits != NULL, 03188 CPL_ERROR_NULL_INPUT, 03189 return cpl_error_get_code()); 03190 03191 *n_mag_fits = 0; 03192 03193 /* If (override_fit_m), then fit all magnitudes. 03194 * The intention is to fit in a best way the f polynomial. Just one 03195 * star is necessary to fix the offset, so just don't fit the magnitude 03196 * of the first one. */ 03197 if (override_fit_m) 03198 { 03199 std = fors_std_star_list_first(stdl); 03200 /* find the first trusted object */ 03201 while (std != NULL && std->trusted == false) 03202 { 03203 std = fors_std_star_list_next(stdl); 03204 (*n_mag_fits)++; 03205 } 03206 /* keep this one */ 03207 if (std != NULL) 03208 std = fors_std_star_list_next(stdl); 03209 /* and set the rest to non-trusted */ 03210 for ( ; std != NULL; std = fors_std_star_list_next(stdl)) 03211 { 03212 std->trusted = false; 03213 (*n_mag_fits)++; 03214 } 03215 } 03216 else 03217 { 03218 for ( std = fors_std_star_list_first(stdl); 03219 std != NULL; 03220 std = fors_std_star_list_next(stdl)) 03221 { 03222 if(! std->trusted) 03223 (*n_mag_fits)++; 03224 } 03225 } 03226 03227 return (cpl_errorstate_is_equal(errstat) ? 03228 CPL_ERROR_NONE : 03229 cpl_error_get_code()); 03230 } 03231 03232 /*----------------------------------------------------------------------------*/ 03233 #undef cleanup 03234 #define cleanup \ 03235 do { \ 03236 cpl_array_delete(n_obs_per_std); n_obs_per_std = NULL; \ 03237 fors_std_star_list_delete(&std_list_copy, NULL); \ 03238 entry_list_delete(&obs_list_copy, NULL); \ 03239 } while (0) 03240 03247 /*----------------------------------------------------------------------------*/ 03248 static cpl_error_code 03249 fors_photometry_remove_unnecessary( fors_std_star_list *std_list, 03250 entry_list *obs_list, 03251 int *n_mag_fits) 03252 { 03253 cpl_array *n_obs_per_std = NULL; 03254 fors_std_star_list *std_list_copy = NULL; 03255 entry_list *obs_list_copy = NULL; 03256 fors_std_star *std; 03257 entry *obs; 03258 int n_std_stars, 03259 n_removed = 0, 03260 n; 03261 cpl_errorstate errstat = cpl_errorstate_get(); 03262 03263 cassure_automsg( std_list != NULL, 03264 CPL_ERROR_NULL_INPUT, 03265 return cpl_error_get_code()); 03266 cassure_automsg( obs_list != NULL, 03267 CPL_ERROR_NULL_INPUT, 03268 return cpl_error_get_code()); 03269 cassure_automsg( n_mag_fits != NULL, 03270 CPL_ERROR_NULL_INPUT, 03271 return cpl_error_get_code()); 03272 03273 *n_mag_fits = 0; 03274 03275 n_std_stars = fors_std_star_list_size(std_list); 03276 03277 n_obs_per_std = fors_photometry_count_observations(std_list, obs_list); 03278 passure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code()); 03279 03280 /* We are not so sure what happens if we iterate the FORS list and at the 03281 * same time remove entries, so copy the list to temporarily keep the 03282 * pointers. */ 03283 std_list_copy = fors_std_star_list_duplicate(std_list, NULL); 03284 obs_list_copy = entry_list_duplicate(obs_list, NULL); 03285 03286 /* first remove all unnecessary observation entries */ 03287 for ( obs = entry_list_first(obs_list_copy); 03288 obs != NULL; 03289 obs = entry_list_next(obs_list_copy)) 03290 { 03291 int n_obs; 03292 bool remove = false; 03293 03294 remove |= (obs->star_index < 0 || obs->star_index >= n_std_stars); 03295 03296 n_obs = cpl_array_get_int(n_obs_per_std, obs->star_index, NULL); 03297 assure( cpl_errorstate_is_equal(errstat), 03298 return cpl_error_get_code(), 03299 NULL); 03300 remove |= (n_obs < 2 && !obs->star->id->trusted); 03301 03302 if (remove) 03303 { 03304 entry_list_remove(obs_list, obs); 03305 entry_delete_but_standard(&obs); 03306 } 03307 } 03308 03309 for ( std = fors_std_star_list_first(std_list_copy), n = 0; 03310 std != NULL; 03311 std = fors_std_star_list_next(std_list_copy), n++) 03312 { 03313 int n_obs; 03314 03315 n_obs = cpl_array_get_int(n_obs_per_std, n, NULL); 03316 assure( cpl_errorstate_is_equal(errstat), 03317 return cpl_error_get_code(), 03318 NULL); 03319 03320 if (n_obs < 2 && !std->trusted) 03321 { 03322 fors_std_star_list_remove(std_list, std); 03323 fors_std_star_delete(&std); 03324 n_removed++; 03325 } 03326 else if(!std->trusted) 03327 { 03328 (*n_mag_fits)++; 03329 } 03330 } 03331 03332 cleanup; /* don't need that anymore */ 03333 03334 /* Set the new star indices */ 03335 for ( obs = entry_list_first(obs_list); 03336 obs != NULL; 03337 obs = entry_list_next(obs_list)) 03338 { 03339 for ( std = fors_std_star_list_first(std_list), n = 0; 03340 std != NULL; 03341 std = fors_std_star_list_next(std_list), n++) 03342 { 03343 if (obs->star->id == std) 03344 { 03345 obs->star_index = n; 03346 break; 03347 } 03348 } 03349 } 03350 03351 if (n_removed > 0) 03352 cpl_msg_info( cpl_func, 03353 "Discarded %d untrusted/fitted objects which were " 03354 "observed only once (and therefore don't contribute).", 03355 n_removed); 03356 03357 cleanup; 03358 return (cpl_errorstate_is_equal(errstat) ? 03359 CPL_ERROR_NONE : 03360 cpl_error_get_code()); 03361 } 03362 03363 /*----------------------------------------------------------------------------*/ 03364 #undef cleanup 03365 #define cleanup \ 03366 do { \ 03367 cpl_array_unwrap(n_obs_a); n_obs_a = NULL; \ 03368 cpl_free(n_obs); n_obs = NULL; \ 03369 } while (0) 03370 03377 /*----------------------------------------------------------------------------*/ 03378 static cpl_array* 03379 fors_photometry_count_observations( fors_std_star_list *std_list, 03380 entry_list *obs_list) 03381 { 03382 int *n_obs = NULL; 03383 cpl_array *n_obs_a = NULL; 03384 entry *e; 03385 int n_std_stars; 03386 03387 cassure_automsg( std_list != NULL, 03388 CPL_ERROR_NULL_INPUT, 03389 return n_obs_a); 03390 cassure_automsg( obs_list != NULL, 03391 CPL_ERROR_NULL_INPUT, 03392 return n_obs_a); 03393 03394 n_std_stars = fors_std_star_list_size(std_list); 03395 n_obs = cpl_calloc(n_std_stars, sizeof(*n_obs)); 03396 03397 for ( e = entry_list_first(obs_list); 03398 e != NULL; 03399 e = entry_list_next(obs_list)) 03400 { 03401 ppassure( e->star_index >= 0 03402 && e->star_index < n_std_stars, 03403 CPL_ERROR_UNSPECIFIED, 03404 return n_obs_a); 03405 n_obs[e->star_index]++; 03406 } 03407 03408 n_obs_a = cpl_array_wrap_int(n_obs, n_std_stars); 03409 return n_obs_a; 03410 } 03411 03412 /*----------------------------------------------------------------------------*/ 03413 #undef cleanup 03414 #define cleanup \ 03415 do { \ 03416 fors_matrix_null(&lhs); \ 03417 if (n_fit_e_cols != NULL) \ 03418 *n_fit_e_cols = 0; \ 03419 } while (0) 03420 03444 /*----------------------------------------------------------------------------*/ 03445 static cpl_matrix* 03446 build_equations_lhs_matrix_from_parameters( const entry_list *obs_list, 03447 const fors_std_star_list *std_list, 03448 bool fit_z, 03449 bool fit_c, 03450 int *n_fit_e_cols) 03451 { 03452 int n_std_stars, 03453 n_obs, 03454 n_col, 03455 n_fit_std_mag = 0, 03456 n_frames, 03457 n_atm_ext, /* nr of atm. extinction coefficients */ 03458 row; 03459 const entry *e; 03460 const fors_std_star 03461 *std; 03462 cpl_matrix *lhs = NULL; 03463 bool printed = false; 03464 03465 /* free output pointers */ 03466 cleanup; 03467 03468 /* check input */ 03469 assure(!cpl_error_get_code(), return lhs, "Previous error caught."); 03470 03471 ppassure( obs_list != NULL 03472 && std_list != NULL, 03473 CPL_ERROR_NULL_INPUT, 03474 return lhs); 03475 03476 n_std_stars = fors_std_star_list_size(std_list); 03477 n_obs = entry_list_size(obs_list); 03478 03479 cassure( n_std_stars > 0 && n_obs > 0, 03480 CPL_ERROR_DATA_NOT_FOUND, 03481 return lhs, 03482 "Empty input list"); 03483 03484 /* prepare */ 03485 n_obs = entry_list_size(obs_list); 03486 for ( std = fors_std_star_list_first_const(std_list); 03487 std != NULL; 03488 std = fors_std_star_list_next_const(std_list)) 03489 { 03490 n_fit_std_mag += !(std->trusted); 03491 } 03492 03493 n_frames = 0; 03494 n_atm_ext = 0; 03495 for ( e = entry_list_first_const(obs_list); 03496 e != NULL; 03497 e = entry_list_next_const(obs_list)) 03498 { 03499 /* assume indices counting from 0 */ 03500 if (e->frame_index + 1 > n_frames) 03501 n_frames = e->frame_index + 1; 03502 if (e->atm_ext_index + 1 > n_atm_ext) 03503 n_atm_ext = e->atm_ext_index + 1; 03504 } 03505 if (n_atm_ext < 0) n_atm_ext = 0; 03506 passure(!cpl_error_get_code(), return lhs); 03507 03508 n_col = n_fit_std_mag 03509 + ((fit_z) ? 1 : 0) 03510 + n_atm_ext 03511 + ((fit_c) ? 1 : 0); 03512 03513 if (n_col == 0) /* if nothing to be fitted here */ 03514 { 03515 cleanup; 03516 return lhs; /* NULL */ 03517 } 03518 03519 lhs = cpl_matrix_new(n_obs, n_col); 03520 passure(!cpl_error_get_code(), return lhs); 03521 03522 /* start */ 03523 /* FIXME: FAP: insert visual comments here */ 03524 for (e = entry_list_first_const(obs_list), row = 0; 03525 e != NULL; 03526 e = entry_list_next_const(obs_list), row++) 03527 { 03528 int col = 0, 03529 k; 03530 03531 /* Star not identified, should not happen */ 03532 ppassure( e->star_index >= 0, 03533 CPL_ERROR_ILLEGAL_INPUT, 03534 return lhs); 03535 03536 if (n_fit_std_mag > 0) /* one column per std. star's magnitude to fit */ 03537 { 03538 for ( std = fors_std_star_list_first_const(std_list), k = 0; 03539 std != NULL; 03540 std = fors_std_star_list_next_const(std_list), k++) 03541 { 03542 if (!(std->trusted)) 03543 { 03544 if (!printed) 03545 cpl_msg_debug( cpl_func, 03546 "Creating column for mag(M%d)", 03547 k); 03548 if (e->star->id == std) 03549 cpl_matrix_set(lhs, row, col, 1); 03550 col++; 03551 } 03552 } 03553 } 03554 03555 if (fit_z) 03556 { 03557 if (!printed) 03558 cpl_msg_debug(cpl_func, "Creating column for Z"); 03559 cpl_matrix_set(lhs, row, col++, -1); 03560 } 03561 03562 if (n_atm_ext > 0) 03563 { 03564 for (k = 0; k < n_atm_ext; k++) 03565 { 03566 if (!printed) 03567 cpl_msg_debug(cpl_func, "Creating column for E_%d", k); 03568 double val = (k == e->atm_ext_index) ? e->airmass : 0; 03569 cpl_matrix_set(lhs, row, col++, val); 03570 } 03571 } 03572 03573 if (fit_c) /* fit color coeff */ 03574 { 03575 double c; 03576 if (!printed) 03577 cpl_msg_debug(cpl_func, "Creating column for color " 03578 "correction term"); 03579 c = e->star->id->color; 03580 /* if (fit_mag), then fit observed magnitude, not corrected by 03581 * catalogue color, or in other words: set std.star elements 03582 * to zero */ 03583 if (!(e->star->id->trusted)) 03584 c = 0; 03585 cpl_matrix_set(lhs, row, col++, c); 03586 } 03587 printed = true; 03588 } 03589 passure(!cpl_error_get_code(), return lhs); 03590 03591 if (n_fit_e_cols != NULL) 03592 *n_fit_e_cols = n_atm_ext; 03593 03594 return lhs; 03595 } 03596 03597 /*----------------------------------------------------------------------------*/ 03598 #undef cleanup 03599 #define cleanup \ 03600 do { \ 03601 fors_matrix_null(&mat); \ 03602 cpl_array_delete(Apowers); Apowers = NULL; \ 03603 } while (0) 03604 03622 /*----------------------------------------------------------------------------*/ 03623 static cpl_matrix* 03624 build_equations_lhs_matrix_from_poly( const entry_list *obs_list, 03625 const cpl_polynomial *poly, 03626 const char *pname, 03627 double (*powerfunc)( 03628 const entry*, 03629 const cpl_array*)) 03630 { 03631 int n_obs, 03632 n_coeff, 03633 n_dims, 03634 row; 03635 cpl_matrix *mat = NULL; 03636 cpl_array *Apowers = NULL; 03637 int *ipowers; 03638 cpl_size *ipowers_size; 03639 const entry *e; 03640 cpl_error_code errc; 03641 bool printed = false; 03642 int i; 03643 03644 assure(!(errc=cpl_error_get_code()), return NULL, "Previous error caught."); 03645 03646 /* check input */ 03647 ppassure( poly != NULL && obs_list != NULL, 03648 CPL_ERROR_NULL_INPUT, 03649 return NULL); 03650 03651 /* init */ 03652 n_obs = entry_list_size(obs_list); 03653 n_coeff = fors_polynomial_count_coeff(poly); 03654 passure(!cpl_error_get_code(), return NULL); 03655 03656 if (n_coeff == 0) 03657 return NULL; 03658 03659 mat = cpl_matrix_new(n_obs, n_coeff); 03660 03661 /* start */ 03662 n_dims = cpl_polynomial_get_dimension(poly); 03663 Apowers = cpl_array_new(n_dims, CPL_TYPE_INT); 03664 cpl_array_fill_window_int(Apowers, 0, n_dims, 0); 03665 ipowers = cpl_array_get_data_int(Apowers); 03666 passure(!cpl_error_get_code(), return NULL); 03667 03668 //This is a workaround until cpl_array supports CPL_SIZE type elements. 03669 ipowers_size = cpl_malloc(n_dims*sizeof(ipowers_size)); 03670 for (i=0; i<n_dims; i++) 03671 ipowers_size[i] = ipowers[i]; 03672 03673 for (e = entry_list_first_const(obs_list), row = 0; 03674 e != NULL; 03675 e = entry_list_next_const(obs_list), row++) 03676 { 03677 int col = 0; 03678 bool overflow; 03679 03680 overflow = fors_polynomial_powers_find_first_coeff(poly, ipowers_size); 03681 while (!overflow) 03682 { 03683 if (!printed) 03684 { 03685 char *cn = fors_polynomial_sprint_coeff(poly, ipowers_size, pname); 03686 if (cn != NULL) 03687 { 03688 cpl_msg_debug(cpl_func, "Creating column for %s", cn); 03689 cpl_free(cn); 03690 } 03691 } 03692 cpl_matrix_set(mat, row, col++, (*powerfunc)(e, Apowers)); 03693 passure(!cpl_error_get_code(), return NULL); 03694 03695 overflow = fors_polynomial_powers_find_next_coeff(poly, ipowers_size); 03696 } 03697 03698 printed = true; 03699 } 03700 03701 cpl_array_delete(Apowers); 03702 03703 return mat; 03704 } 03705 03706 /*----------------------------------------------------------------------------*/ 03707 #undef cleanup 03708 #define cleanup \ 03709 do { \ 03710 fors_matrix_null(&rhs_input_cov); \ 03711 fors_matrix_null(&rhs_jacobian); \ 03712 fors_matrix_null(&rhs_input); \ 03713 fors_matrix_null(&rhs_jacobian_T); \ 03714 fors_matrix_null(&tmp_matrix); \ 03715 fors_matrix_null(rhs); \ 03716 fors_matrix_null(rhs_cov); \ 03717 } while (0) 03718 03733 /*----------------------------------------------------------------------------*/ 03734 static cpl_error_code 03735 build_equations_rhs_cov( const entry_list *obs_list, 03736 const fors_std_star_list *std_list, 03737 bool fit_z, 03738 bool fit_c, 03739 bool fit_e, 03740 double color_coeff, 03741 double dcolor_coeff, 03742 double ext_coeff, 03743 double dext_coeff, 03744 double zpoint, 03745 double dzpoint, 03746 cpl_matrix **rhs, 03747 cpl_matrix **rhs_cov) 03748 { 03749 /* This function computes the following 03750 * (with i = index of referenced std. star): 03751 * 03752 * rhs_obs = m_obs (instrumental magnitude) 03753 * - (!fit_mag_i) ? cat_mag_i : 0 03754 * + (!fit_c) ? color_i * color_coeff : 0 03755 * - (!fit_e) ? airmass_f * ext_coeff : 0 03756 * + (!fit_z) ? zpoint : 0 03757 * - magscale(gain) 03758 * - magscale(exposure_time); 03759 * 03760 * It does it by generating 3 matrices: the inputs matrix, a Jacobian, and 03761 * an inputs covariance matrix. Using these, the rhs and its covariance 03762 * matrix are computed. 03763 */ 03764 cpl_matrix *rhs_input_cov = NULL, 03765 *rhs_jacobian = NULL, 03766 *rhs_input = NULL, 03767 *rhs_jacobian_T = NULL, 03768 *tmp_matrix = NULL; 03769 int n_std_stars, 03770 n_obs, 03771 n_col, 03772 r, 03773 c; 03774 const fors_std_star 03775 *std; 03776 const entry *obs; 03777 bool printed_debug = false; 03778 cpl_errorstate errstat = cpl_errorstate_get(); 03779 03780 /* free output pointers */ 03781 cleanup; 03782 03783 /* check input */ 03784 cassure_automsg( obs_list != NULL, 03785 CPL_ERROR_NULL_INPUT, 03786 return cpl_error_get_code()); 03787 cassure_automsg( std_list != NULL, 03788 CPL_ERROR_NULL_INPUT, 03789 return cpl_error_get_code()); 03790 cassure_automsg( rhs != NULL, 03791 CPL_ERROR_NULL_INPUT, 03792 return cpl_error_get_code()); 03793 cassure_automsg( rhs_cov != NULL, 03794 CPL_ERROR_NULL_INPUT, 03795 return cpl_error_get_code()); 03796 03797 n_std_stars = fors_std_star_list_size(std_list); 03798 n_obs = entry_list_size(obs_list); 03799 03800 cassure( n_std_stars > 0 && n_obs > 0, 03801 CPL_ERROR_DATA_NOT_FOUND, 03802 return cpl_error_get_code(), 03803 "Empty input list"); 03804 03805 /* start */ 03806 n_col = n_std_stars*2 + 3; 03807 03808 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 03809 /* build the following input covariance matrix: 03810 * 03811 * v_mag_0 cov_mc_0 0 0 0 0 0 03812 * cov_mc_0 v_color_0 0 0 0 0 0 03813 * 0 0 v_mag_1 cov_mc_1 0 0 0 03814 * 0 0 cov_mc_1 v_color_1 0 0 0 03815 * ... 03816 * 0 0 0 0 v_color_coef 0 0 03817 * 0 0 0 0 0 v_ext_coef 0 03818 * 0 0 0 0 0 0 v_zpoint 03819 */ 03820 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 03821 rhs_input_cov = cpl_matrix_new(n_col, n_col); 03822 for ( std = fors_std_star_list_first_const(std_list), c = 0; 03823 std != NULL; 03824 std = fors_std_star_list_next_const(std_list), c += 2) 03825 { 03826 double dcatm = std->dcat_magnitude, 03827 dcolor = std->dcolor, 03828 cov_catmag_color = std->cov_catm_color; 03829 03830 /* To new maintainers: first understand the rest of the 03831 * function without the following if-statement. */ 03832 if (!(dcolor > 0) || isnan(cov_catmag_color)) 03833 { 03834 /* If we have old fors_zeropoint input data, i.e. 03835 * if dcolor and cov_catmag_color are not set, then: 03836 * 03837 * use the mag entry in the covariance matrix and in the rhs input 03838 * vector: 03839 * - depently on fit_c, use the catalogue magnitude or the 03840 * color corrected magnitude, and 03841 * - set the color +- dcolor entry to 0 +- 0. 03842 * 03843 * The color corrected magnitude, computed by the old 03844 * fors_zeropoint recipe, included the correlation between 03845 * magnitude and color index, using the color correction term 03846 * from the then used photometric table. 03847 */ 03848 cov_catmag_color = 0; 03849 dcolor = 0; 03850 if (std->trusted) /* !(fit magnitude), not really necessary 03851 because Jacobian takes care 03852 of (!(std->trusted)) */ 03853 { 03854 if (!fit_c) 03855 { 03856 cassure( dcatm > 0, 03857 CPL_ERROR_ILLEGAL_INPUT, 03858 return cpl_error_get_code(), 03859 "Could not determine color " 03860 "corrected magnitude with error " 03861 "estimate of object %s", 03862 (std->name != NULL) ? 03863 std->name : "unknown"); 03864 dcatm = std->dmagnitude; /* color corrected mag */ 03865 if (!printed_debug) 03866 { 03867 cpl_msg_debug( cpl_func, 03868 "Having old fors_zeropoint data. " 03869 "Using color corrected magnitudes " 03870 "instead of catalogue magnitude " 03871 "and color separately."); 03872 printed_debug = true; 03873 } 03874 } 03875 } 03876 /* else fit the observed magnitude, i.e. not correcting by 03877 * the catalogue color (see Jacobian), so don't care about 03878 * missing color entries */ 03879 } 03880 03881 cpl_matrix_set(rhs_input_cov, c, c, dcatm*dcatm); 03882 cpl_matrix_set(rhs_input_cov, c+1, c+1, dcolor*dcolor); 03883 cpl_matrix_set(rhs_input_cov, c, c+1, cov_catmag_color); 03884 cpl_matrix_set(rhs_input_cov, c+1, c, cov_catmag_color); 03885 } 03886 cpl_matrix_set(rhs_input_cov, c, c, dcolor_coeff*dcolor_coeff); 03887 cpl_matrix_set(rhs_input_cov, c+1, c+1, dext_coeff*dext_coeff); 03888 cpl_matrix_set(rhs_input_cov, c+1, c+1, dzpoint*dzpoint); 03889 03890 passure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code()); 03891 03892 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 03893 /* build the following Jacobi matrix 03894 * with: i = index of referenced std. star, 03895 * f = index of frame 03896 * A = airmass, 03897 * G = color correction term 03898 * C = color 03899 * 03900 * ... (!fit_mag_i)*1 -(!fit_c)*G ... -(!fit_c)*C_i (!fit_e)*A_f -(!fit_z)*1 03901 * . 03902 * . 03903 * . 03904 * 03905 * and multiply by (-1) to subtract the input. 03906 * fit_c appears twice with the coefficients required to compute the 03907 * rhs covariance matrix. 03908 * In principle, the airmass index could also be the index of the 03909 * measurement/observation of the star, since it is taken from the obs 03910 * object. 03911 */ 03912 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 03913 rhs_jacobian = cpl_matrix_new(n_obs, n_col); 03914 for ( obs = entry_list_first_const(obs_list), r = 0; 03915 obs != NULL; 03916 obs = entry_list_next_const(obs_list), r++) 03917 { 03918 bool fit_mag, 03919 compensate_color; 03920 03921 c = obs->star_index * 2; 03922 fit_mag = !(obs->star->id->trusted); 03923 /* if (fit_mag), then fit observed magnitude, not corrected by 03924 * catalogue color */ 03925 compensate_color = (!fit_c) && (!fit_mag); 03926 03927 cpl_matrix_set(rhs_jacobian, r, c, -(!fit_mag)*1.0); 03928 cpl_matrix_set(rhs_jacobian, r, c+1, +(compensate_color)*color_coeff); 03929 03930 cpl_matrix_set(rhs_jacobian, r, n_col-3, + (compensate_color) 03931 * obs->star->id->color); 03932 cpl_matrix_set(rhs_jacobian, r, n_col-2, -(!fit_e)*obs->airmass); 03933 cpl_matrix_set(rhs_jacobian, r, n_col-1, +(!fit_z)*1.0); 03934 } 03935 03936 passure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code()); 03937 03938 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 03939 /* Prepare the rhs input vector: 03940 * 03941 * [... cat_mag_i color_i ... 0 ext_coef zpoint]^T 03942 * 03943 * Here, the term C*G shall only be used once, so set the other occurrence 03944 * to 0. 03945 */ 03946 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 03947 rhs_input = cpl_matrix_new(n_col, 1); 03948 for ( std = fors_std_star_list_first_const(std_list), r = 0; 03949 std != NULL; 03950 std = fors_std_star_list_next_const(std_list), r += 2) 03951 { 03952 double catm = std->cat_magnitude, 03953 color = std->color; 03954 03955 /* To new maintainers: first understand the rest of the 03956 * function without the following if-statement. */ 03957 if (!(std->dcolor > 0) || isnan(std->cov_catm_color)) 03958 { 03959 /* see above */ 03960 color = 0; 03961 if (std->trusted) /* !(fit magnitude) */ 03962 { 03963 if (!fit_c) 03964 catm = std->magnitude; /* color corrected mag */ 03965 } 03966 } 03967 03968 cpl_matrix_set(rhs_input, r, 0, catm); 03969 cpl_matrix_set(rhs_input, r+1, 0, color); 03970 } 03971 /* we already have color_i*color_coeff 03972 *cpl_matrix_set(rhs_input, r, 0, 0);*/ 03973 cpl_matrix_set(rhs_input, r+1, 0, ext_coeff); 03974 cpl_matrix_set(rhs_input, r+2, 0, zpoint); 03975 03976 passure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code()); 03977 03978 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 03979 /* ...and compute the results... */ 03980 *rhs = cpl_matrix_product_create(rhs_jacobian, rhs_input); 03981 passure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code()); 03982 03983 rhs_jacobian_T = cpl_matrix_transpose_create(rhs_jacobian); 03984 tmp_matrix = cpl_matrix_product_create(rhs_input_cov, rhs_jacobian_T); 03985 passure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code()); 03986 *rhs_cov = cpl_matrix_product_create(rhs_jacobian, tmp_matrix); 03987 passure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code()); 03988 03989 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 03990 /* add the missing contributions: 03991 * 1. rhs : instrumental magnitude, subtract gain and exptime 03992 * 2. rhs_cov: variance of instrumental magnitude 03993 */ 03994 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 03995 for ( obs = entry_list_first_const(obs_list), r = 0; 03996 obs != NULL; 03997 obs = entry_list_next_const(obs_list), r++) 03998 { 03999 cpl_matrix_set(*rhs, r, 0, cpl_matrix_get(*rhs, r, 0) 04000 + obs->star->magnitude 04001 + 2.5*log10(obs->gain) 04002 + 2.5*log10(obs->exptime)); 04003 cpl_matrix_set(*rhs_cov, r, r, cpl_matrix_get(*rhs_cov, r, r) 04004 + obs->star->dmagnitude 04005 * obs->star->dmagnitude); 04006 } 04007 04008 fors_matrix_null(&rhs_input_cov); 04009 fors_matrix_null(&rhs_jacobian); 04010 fors_matrix_null(&rhs_input); 04011 fors_matrix_null(&rhs_jacobian_T); 04012 fors_matrix_null(&tmp_matrix); 04013 04014 return ( cpl_errorstate_is_equal(errstat) ? 04015 CPL_ERROR_NONE : 04016 cpl_error_get_code()); 04017 } 04018 04019