00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031
00032 #include <fors_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,
00094 star_index,
00095 atm_ext_index;
00096 int atm_ext_identifier;
00097 double airmass,
00098 gain,
00099 exptime;
00100 fors_star *star;
00101 } entry;
00102
00103
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
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;
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));
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));
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
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
00579
00580
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
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
00813 cleanup;
00814
00815
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
00826 polyf = cpl_polynomial_new(2);
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 int 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
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
00892 cleanup;
00893
00894
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
00903 polyp = cpl_polynomial_new(2);
00904
00905 for (k = 0; k <= degreep; k++) {
00906 for (l = 0; k + l <= degreep; l++)
00907 if (k+l > 1) {
00908 int 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
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
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
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
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
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
01116
01117
01118
01119
01120
01121
01122 jd = mjd + 2400000.5;
01123
01124
01125
01126
01127
01128 timezone = fors_photometry_get_timezone_observer(header);
01129
01130
01131
01132 jd += (double)timezone / 24.0;
01133
01134
01135
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
01146
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
01259
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
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
01403
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
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
01536
01537
01538 if (!fit_z || fit_e == FORS_FIT_NCOEFF_NO)
01539 {
01540 return CPL_ERROR_NONE;
01541 }
01542
01543
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
01551
01552
01553
01554
01555
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
01581 if (fabs(e->airmass - first_airmass) > 10*DBL_EPSILON)
01582 {
01583 multiple_found = true;
01584 break;
01585 }
01586
01587
01588
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
01629 va_end(al);
01630
01631 return;
01632 }
01633
01634
01635
01636
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
01654
01655
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
01664 for (i = 0; i < m; i++, bwrite += m, ai += n) {
01665 aj = ai;
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
01696
01697
01698
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715
01716
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726
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;
01738 cpl_matrix *At = NULL;
01739 cpl_matrix *AtC = NULL;
01740 cpl_matrix *AtCA = NULL;
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
01754
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
01761
01762
01763
01764
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
01789
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
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
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
01885 fors_image *correction = NULL;
01886 cpl_table *phot_coeff = NULL;
01887 cpl_table *summary = NULL;
01888
01889
01890 fors_std_star_list *std_star_list = NULL;
01891 entry_list *obs = NULL;
01892 cpl_array *n_std_star_obs = NULL;
01893
01894
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
01908 cpl_polynomial *polyf = NULL,
01909 *polyf_definition = NULL,
01910 *polyf_variance = NULL,
01911 *polyp = NULL,
01912 *polyp_definition = NULL;
01913
01914
01915 fors_setting *setting = NULL;
01916 const char *tag = NULL;
01917 int row;
01918
01919
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
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
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
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
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
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,
02059 -10,
02060 10,
02061 1);
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,
02069 0,
02070 5,
02071 1);
02072 }
02073 if (!fit_z)
02074 {
02075 fors_photometry_check_input_value( phot_input.zpoint,
02076 phot_input.dzpoint,
02077 "zeropoint",
02078 NULL,
02079 0,
02080 50,
02081 1);
02082 }
02083 cpl_msg_indent_less();
02084 if (cpl_error_get_code() != CPL_ERROR_NONE)
02085 return;
02086
02087
02088
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
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
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
02205 build_equations_rhs_cov( obs,
02206 std_star_list,
02207 fit_z,
02208 fit_c,
02209 (n_coeff_params_ext > 0),
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
02219
02220
02221
02222
02223
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
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
02240
02241
02242
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
02257
02258
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,
02315 result_cov_polyf,
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,
02322 NULL,
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
02334 int k,
02335 i = 0;
02336 const fors_std_star *std;
02337
02338
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)
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
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
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
02473 cpl_msg_indent_more();
02474 if (fit_c) {
02475
02476
02477
02478
02479 qc_colorterm = cpl_matrix_get(result_params, i, 0);
02480 qc_colorterm = -qc_colorterm;
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
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
02523
02524 passure(polyf != NULL, return);
02525 passure(polyp != NULL, return);
02526
02527
02528
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
02573
02574
02575 qc = cpl_propertylist_new();
02576
02577 fors_qc_start_group(qc, fors_qc_dic_version, setting->instrument);
02578
02579
02580
02581
02582
02583
02584
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
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
02690
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
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
02777 cleanup;
02778
02779
02780 obs = entry_list_new();
02781 *std_star_list = fors_std_star_list_new();
02782
02783
02784
02785
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
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
02832
02833
02834
02835
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},
02858 {"COV_CATM_COL", CPL_TYPE_DOUBLE, true},
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 }
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
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,
02919 NULL,
02920 NULL, NULL,
02921 "OBJECT");
02922
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
02939
02940
02941
02942
02943
02944
02945 obs_star->id = std_star;
02946
02947
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
02967
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
02983
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)
02990 {
02991 fors_std_star *s_in_list;
02992
02993 std_star->trusted = false;
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)
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
03020
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 }
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 }
03043
03044 *n_frames = iframe;
03045
03046
03047
03048
03049
03050
03051
03052 entry_list_reverse(obs);
03053 fors_std_star_list_reverse(*std_star_list);
03054
03055
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
03125
03126
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
03144 nearest->trusted &= std->trusted;
03145
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
03165
03166
03167
03168
03169
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
03194
03195
03196
03197 if (override_fit_m)
03198 {
03199 std = fors_std_star_list_first(stdl);
03200
03201 while (std != NULL && std->trusted == false)
03202 {
03203 std = fors_std_star_list_next(stdl);
03204 (*n_mag_fits)++;
03205 }
03206
03207 if (std != NULL)
03208 std = fors_std_star_list_next(stdl);
03209
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
03281
03282
03283 std_list_copy = fors_std_star_list_duplicate(std_list, NULL);
03284 obs_list_copy = entry_list_duplicate(obs_list, NULL);
03285
03286
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;
03333
03334
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,
03458 row;
03459 const entry *e;
03460 const fors_std_star
03461 *std;
03462 cpl_matrix *lhs = NULL;
03463 bool printed = false;
03464
03465
03466 cleanup;
03467
03468
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
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
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)
03514 {
03515 cleanup;
03516 return lhs;
03517 }
03518
03519 lhs = cpl_matrix_new(n_obs, n_col);
03520 passure(!cpl_error_get_code(), return lhs);
03521
03522
03523
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
03532 ppassure( e->star_index >= 0,
03533 CPL_ERROR_ILLEGAL_INPUT,
03534 return lhs);
03535
03536 if (n_fit_std_mag > 0)
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)
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
03581
03582
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 const entry *e;
03639 cpl_error_code errc;
03640 bool printed = false;
03641
03642 assure(!(errc=cpl_error_get_code()), return NULL, "Previous error caught.");
03643
03644
03645 ppassure( poly != NULL && obs_list != NULL,
03646 CPL_ERROR_NULL_INPUT,
03647 return NULL);
03648
03649
03650 n_obs = entry_list_size(obs_list);
03651 n_coeff = fors_polynomial_count_coeff(poly);
03652 passure(!cpl_error_get_code(), return NULL);
03653
03654 if (n_coeff == 0)
03655 return NULL;
03656
03657 mat = cpl_matrix_new(n_obs, n_coeff);
03658
03659
03660 n_dims = cpl_polynomial_get_dimension(poly);
03661 Apowers = cpl_array_new(n_dims, CPL_TYPE_INT);
03662 cpl_array_fill_window_int(Apowers, 0, n_dims, 0);
03663 ipowers = cpl_array_get_data_int(Apowers);
03664 passure(!cpl_error_get_code(), return NULL);
03665
03666
03667
03668 for (e = entry_list_first_const(obs_list), row = 0;
03669 e != NULL;
03670 e = entry_list_next_const(obs_list), row++)
03671 {
03672 int col = 0;
03673 bool overflow;
03674
03675 overflow = fors_polynomial_powers_find_first_coeff(poly, ipowers);
03676 while (!overflow)
03677 {
03678 if (!printed)
03679 {
03680 char *cn = fors_polynomial_sprint_coeff(poly, ipowers, pname);
03681 if (cn != NULL)
03682 {
03683 cpl_msg_debug(cpl_func, "Creating column for %s", cn);
03684 cpl_free(cn);
03685 }
03686 }
03687 cpl_matrix_set(mat, row, col++, (*powerfunc)(e, Apowers));
03688 passure(!cpl_error_get_code(), return NULL);
03689
03690 overflow = fors_polynomial_powers_find_next_coeff(poly, ipowers);
03691 }
03692
03693 printed = true;
03694 }
03695
03696 cpl_array_delete(Apowers);
03697
03698 return mat;
03699 }
03700
03701
03702 #undef cleanup
03703 #define cleanup \
03704 do { \
03705 fors_matrix_null(&rhs_input_cov); \
03706 fors_matrix_null(&rhs_jacobian); \
03707 fors_matrix_null(&rhs_input); \
03708 fors_matrix_null(&rhs_jacobian_T); \
03709 fors_matrix_null(&tmp_matrix); \
03710 fors_matrix_null(rhs); \
03711 fors_matrix_null(rhs_cov); \
03712 } while (0)
03713
03728
03729 static cpl_error_code
03730 build_equations_rhs_cov( const entry_list *obs_list,
03731 const fors_std_star_list *std_list,
03732 bool fit_z,
03733 bool fit_c,
03734 bool fit_e,
03735 double color_coeff,
03736 double dcolor_coeff,
03737 double ext_coeff,
03738 double dext_coeff,
03739 double zpoint,
03740 double dzpoint,
03741 cpl_matrix **rhs,
03742 cpl_matrix **rhs_cov)
03743 {
03744
03745
03746
03747
03748
03749
03750
03751
03752
03753
03754
03755
03756
03757
03758
03759 cpl_matrix *rhs_input_cov = NULL,
03760 *rhs_jacobian = NULL,
03761 *rhs_input = NULL,
03762 *rhs_jacobian_T = NULL,
03763 *tmp_matrix = NULL;
03764 int n_std_stars,
03765 n_obs,
03766 n_col,
03767 r,
03768 c;
03769 const fors_std_star
03770 *std;
03771 const entry *obs;
03772 bool printed_debug = false;
03773 cpl_errorstate errstat = cpl_errorstate_get();
03774
03775
03776 cleanup;
03777
03778
03779 cassure_automsg( obs_list != NULL,
03780 CPL_ERROR_NULL_INPUT,
03781 return cpl_error_get_code());
03782 cassure_automsg( std_list != NULL,
03783 CPL_ERROR_NULL_INPUT,
03784 return cpl_error_get_code());
03785 cassure_automsg( rhs != NULL,
03786 CPL_ERROR_NULL_INPUT,
03787 return cpl_error_get_code());
03788 cassure_automsg( rhs_cov != NULL,
03789 CPL_ERROR_NULL_INPUT,
03790 return cpl_error_get_code());
03791
03792 n_std_stars = fors_std_star_list_size(std_list);
03793 n_obs = entry_list_size(obs_list);
03794
03795 cassure( n_std_stars > 0 && n_obs > 0,
03796 CPL_ERROR_DATA_NOT_FOUND,
03797 return cpl_error_get_code(),
03798 "Empty input list");
03799
03800
03801 n_col = n_std_stars*2 + 3;
03802
03803
03804
03805
03806
03807
03808
03809
03810
03811
03812
03813
03814
03815
03816 rhs_input_cov = cpl_matrix_new(n_col, n_col);
03817 for ( std = fors_std_star_list_first_const(std_list), c = 0;
03818 std != NULL;
03819 std = fors_std_star_list_next_const(std_list), c += 2)
03820 {
03821 double dcatm = std->dcat_magnitude,
03822 dcolor = std->dcolor,
03823 cov_catmag_color = std->cov_catm_color;
03824
03825
03826
03827 if (!(dcolor > 0) || isnan(cov_catmag_color))
03828 {
03829
03830
03831
03832
03833
03834
03835
03836
03837
03838
03839
03840
03841
03842
03843 cov_catmag_color = 0;
03844 dcolor = 0;
03845 if (std->trusted)
03846
03847
03848 {
03849 if (!fit_c)
03850 {
03851 cassure( dcatm > 0,
03852 CPL_ERROR_ILLEGAL_INPUT,
03853 return cpl_error_get_code(),
03854 "Could not determine color "
03855 "corrected magnitude with error "
03856 "estimate of object %s",
03857 (std->name != NULL) ?
03858 std->name : "unknown");
03859 dcatm = std->dmagnitude;
03860 if (!printed_debug)
03861 {
03862 cpl_msg_debug( cpl_func,
03863 "Having old fors_zeropoint data. "
03864 "Using color corrected magnitudes "
03865 "instead of catalogue magnitude "
03866 "and color separately.");
03867 printed_debug = true;
03868 }
03869 }
03870 }
03871
03872
03873
03874 }
03875
03876 cpl_matrix_set(rhs_input_cov, c, c, dcatm*dcatm);
03877 cpl_matrix_set(rhs_input_cov, c+1, c+1, dcolor*dcolor);
03878 cpl_matrix_set(rhs_input_cov, c, c+1, cov_catmag_color);
03879 cpl_matrix_set(rhs_input_cov, c+1, c, cov_catmag_color);
03880 }
03881 cpl_matrix_set(rhs_input_cov, c, c, dcolor_coeff*dcolor_coeff);
03882 cpl_matrix_set(rhs_input_cov, c+1, c+1, dext_coeff*dext_coeff);
03883 cpl_matrix_set(rhs_input_cov, c+1, c+1, dzpoint*dzpoint);
03884
03885 passure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code());
03886
03887
03888
03889
03890
03891
03892
03893
03894
03895
03896
03897
03898
03899
03900
03901
03902
03903
03904
03905
03906
03907
03908 rhs_jacobian = cpl_matrix_new(n_obs, n_col);
03909 for ( obs = entry_list_first_const(obs_list), r = 0;
03910 obs != NULL;
03911 obs = entry_list_next_const(obs_list), r++)
03912 {
03913 bool fit_mag,
03914 compensate_color;
03915
03916 c = obs->star_index * 2;
03917 fit_mag = !(obs->star->id->trusted);
03918
03919
03920 compensate_color = (!fit_c) && (!fit_mag);
03921
03922 cpl_matrix_set(rhs_jacobian, r, c, -(!fit_mag)*1.0);
03923 cpl_matrix_set(rhs_jacobian, r, c+1, +(compensate_color)*color_coeff);
03924
03925 cpl_matrix_set(rhs_jacobian, r, n_col-3, + (compensate_color)
03926 * obs->star->id->color);
03927 cpl_matrix_set(rhs_jacobian, r, n_col-2, -(!fit_e)*obs->airmass);
03928 cpl_matrix_set(rhs_jacobian, r, n_col-1, +(!fit_z)*1.0);
03929 }
03930
03931 passure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code());
03932
03933
03934
03935
03936
03937
03938
03939
03940
03941
03942 rhs_input = cpl_matrix_new(n_col, 1);
03943 for ( std = fors_std_star_list_first_const(std_list), r = 0;
03944 std != NULL;
03945 std = fors_std_star_list_next_const(std_list), r += 2)
03946 {
03947 double catm = std->cat_magnitude,
03948 color = std->color;
03949
03950
03951
03952 if (!(std->dcolor > 0) || isnan(std->cov_catm_color))
03953 {
03954
03955 color = 0;
03956 if (std->trusted)
03957 {
03958 if (!fit_c)
03959 catm = std->magnitude;
03960 }
03961 }
03962
03963 cpl_matrix_set(rhs_input, r, 0, catm);
03964 cpl_matrix_set(rhs_input, r+1, 0, color);
03965 }
03966
03967
03968 cpl_matrix_set(rhs_input, r+1, 0, ext_coeff);
03969 cpl_matrix_set(rhs_input, r+2, 0, zpoint);
03970
03971 passure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code());
03972
03973
03974
03975 *rhs = cpl_matrix_product_create(rhs_jacobian, rhs_input);
03976 passure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code());
03977
03978 rhs_jacobian_T = cpl_matrix_transpose_create(rhs_jacobian);
03979 tmp_matrix = cpl_matrix_product_create(rhs_input_cov, rhs_jacobian_T);
03980 passure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code());
03981 *rhs_cov = cpl_matrix_product_create(rhs_jacobian, tmp_matrix);
03982 passure(cpl_errorstate_is_equal(errstat), return cpl_error_get_code());
03983
03984
03985
03986
03987
03988
03989
03990 for ( obs = entry_list_first_const(obs_list), r = 0;
03991 obs != NULL;
03992 obs = entry_list_next_const(obs_list), r++)
03993 {
03994 cpl_matrix_set(*rhs, r, 0, cpl_matrix_get(*rhs, r, 0)
03995 + obs->star->magnitude
03996 + 2.5*log10(obs->gain)
03997 + 2.5*log10(obs->exptime));
03998 cpl_matrix_set(*rhs_cov, r, r, cpl_matrix_get(*rhs_cov, r, r)
03999 + obs->star->dmagnitude
04000 * obs->star->dmagnitude);
04001 }
04002
04003 fors_matrix_null(&rhs_input_cov);
04004 fors_matrix_null(&rhs_jacobian);
04005 fors_matrix_null(&rhs_input);
04006 fors_matrix_null(&rhs_jacobian_T);
04007 fors_matrix_null(&tmp_matrix);
04008
04009 return ( cpl_errorstate_is_equal(errstat) ?
04010 CPL_ERROR_NONE :
04011 cpl_error_get_code());
04012 }
04013
04014