fors_photometry_impl.c

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

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