FORS Pipeline Reference Manual 4.9.20
|
00001 /* $Id: fors_tools.c,v 1.22 2012/08/07 15:26:53 cgarcia Exp $ 00002 * 00003 * This file is part of the FORS Library 00004 * Copyright (C) 2002-2010 European Southern Observatory 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00021 /* 00022 * $Author: cgarcia $ 00023 * $Date: 2012/08/07 15:26:53 $ 00024 * $Revision: 1.22 $ 00025 * $Name: fors-4_9_20 $ 00026 */ 00027 00028 #ifdef HAVE_CONFIG_H 00029 #include <config.h> 00030 #endif 00031 00032 #include <fors_tools.h> 00033 00034 #include <fors_pfits.h> 00035 #include <fors_utils.h> 00036 00037 #include <cpl.h> 00038 #include <math.h> 00039 #include <stdbool.h> 00040 #include <assert.h> 00041 00042 /*----------------------------------------------------------------------------*/ 00046 /*----------------------------------------------------------------------------*/ 00047 00050 #undef cleanup 00051 #define cleanup \ 00052 do { \ 00053 cpl_propertylist_delete(header); \ 00054 } while(0) 00055 00064 double 00065 fors_star_ext_corr(fors_star_list *stars, 00066 const fors_setting *setting, 00067 double ext_coeff, 00068 double dext_coeff, 00069 const cpl_frame *raw_frame) 00070 { 00071 cpl_propertylist *header = NULL; 00072 00073 00074 cpl_msg_info(cpl_func, "Extinction correction"); 00075 00076 assure( cpl_frame_get_filename(raw_frame) != NULL, return -1, NULL ); 00077 00078 header = cpl_propertylist_load(cpl_frame_get_filename(raw_frame), 0); 00079 assure( !cpl_error_get_code(), return -1, 00080 "Failed to load %s primary header", 00081 cpl_frame_get_filename(raw_frame)); 00082 00083 00084 double avg_airmass = fors_get_airmass(header); 00085 assure( !cpl_error_get_code(), return -1, 00086 "%s: Could not read airmass", 00087 cpl_frame_get_filename(raw_frame)); 00088 00089 cpl_msg_indent_more(); 00090 cpl_msg_info(cpl_func, "Exposure time = %f s", setting->exposure_time); 00091 cpl_msg_info(cpl_func, "Gain = %f ADU/e-", setting->average_gain); 00092 cpl_msg_info(cpl_func, "Ext. coeff. = %f +- %f mag/airmass", 00093 ext_coeff, dext_coeff); 00094 cpl_msg_info(cpl_func, "Avg. airmass = %f airmass", avg_airmass); 00095 /* The quantity and the unit are both 'airmass' */ 00096 00097 cpl_msg_indent_less(); 00098 00099 { 00100 fors_star *star; 00101 00102 for (star = fors_star_list_first(stars); 00103 star != NULL; 00104 star = fors_star_list_next(stars)) { 00105 star->magnitude_corr = star->magnitude 00106 + 2.5*log(setting->average_gain)/log(10) 00107 + 2.5*log(setting->exposure_time)/log(10) 00108 - ext_coeff * avg_airmass; 00109 00110 /* Propagate error from ext.coeff. 00111 gain, exptime and airmass 00112 have zero error */ 00113 star->dmagnitude_corr = sqrt(star->dmagnitude * star->dmagnitude 00114 + dext_coeff*dext_coeff * avg_airmass*avg_airmass); 00115 } 00116 } 00117 00118 cleanup; 00119 return avg_airmass; 00120 } 00121 00129 cpl_table * 00130 fors_create_sources_table(fors_star_list *sources) 00131 { 00132 cpl_table *t = NULL; 00133 00134 t = cpl_table_new(fors_star_list_size(sources)); 00135 cpl_table_new_column(t, "X", CPL_TYPE_DOUBLE); 00136 cpl_table_new_column(t, "Y", CPL_TYPE_DOUBLE); 00137 cpl_table_new_column(t, "FWHM", CPL_TYPE_DOUBLE); 00138 cpl_table_new_column(t, "A", CPL_TYPE_DOUBLE); 00139 cpl_table_new_column(t, "B", CPL_TYPE_DOUBLE); 00140 cpl_table_new_column(t, "THETA", CPL_TYPE_DOUBLE); 00141 cpl_table_new_column(t, "ELL", CPL_TYPE_DOUBLE); 00142 cpl_table_new_column(t, "INSTR_MAG", CPL_TYPE_DOUBLE); 00143 cpl_table_new_column(t, "DINSTR_MAG", CPL_TYPE_DOUBLE); 00144 cpl_table_new_column(t, "INSTR_CMAG", CPL_TYPE_DOUBLE); 00145 cpl_table_new_column(t, "DINSTR_CMAG", CPL_TYPE_DOUBLE); 00146 cpl_table_new_column(t, "CLASS_STAR", CPL_TYPE_DOUBLE); 00147 00148 cpl_table_new_column(t, "OBJECT", CPL_TYPE_STRING); 00149 cpl_table_new_column(t, "RA", CPL_TYPE_DOUBLE); 00150 cpl_table_new_column(t, "DEC", CPL_TYPE_DOUBLE); 00151 cpl_table_new_column(t, "MAG", CPL_TYPE_DOUBLE); 00152 cpl_table_new_column(t, "DMAG", CPL_TYPE_DOUBLE); 00153 cpl_table_new_column(t, "CAT_MAG", CPL_TYPE_DOUBLE); 00154 cpl_table_new_column(t, "DCAT_MAG", CPL_TYPE_DOUBLE); 00155 cpl_table_new_column(t, "COLOR", CPL_TYPE_DOUBLE); 00156 cpl_table_new_column(t, "DCOLOR", CPL_TYPE_DOUBLE); 00157 cpl_table_new_column(t, "COV_CATM_COL", CPL_TYPE_DOUBLE); 00158 cpl_table_new_column(t, "USE_CAT", CPL_TYPE_INT); 00159 /* Shift in x and y between initial guess FITS header WCS position 00160 and measured position */ 00161 cpl_table_new_column(t, "SHIFT_X", CPL_TYPE_DOUBLE); 00162 cpl_table_new_column(t, "SHIFT_Y", CPL_TYPE_DOUBLE); 00163 cpl_table_new_column(t, "ZEROPOINT", CPL_TYPE_DOUBLE); 00164 cpl_table_new_column(t, "DZEROPOINT", CPL_TYPE_DOUBLE); 00165 cpl_table_new_column(t, "WEIGHT", CPL_TYPE_DOUBLE); 00166 00167 { 00168 fors_star *s; 00169 int i; 00170 for (s = fors_star_list_first(sources), i = 0; 00171 s != NULL; 00172 s = fors_star_list_next(sources), i++) { 00173 00174 const fors_std_star *id = s->id; 00175 00176 cpl_table_set_double(t, "X", i, s->pixel->x); 00177 cpl_table_set_double(t, "Y", i, s->pixel->y); 00178 cpl_table_set_double(t, "FWHM", i, s->fwhm); 00179 cpl_table_set_double(t, "A", i, s->semi_major); 00180 cpl_table_set_double(t, "B", i, s->semi_minor); 00181 cpl_table_set_double(t, "THETA", i, s->orientation); 00182 cpl_table_set_double(t, "ELL", i, fors_star_ellipticity(s, NULL)); 00183 cpl_table_set_double(t, "INSTR_MAG", i, s->magnitude); 00184 cpl_table_set_double(t, "DINSTR_MAG", i, s->dmagnitude); 00185 cpl_table_set_double(t, "INSTR_CMAG", i, s->magnitude_corr); 00186 cpl_table_set_double(t, "DINSTR_CMAG", i, s->dmagnitude_corr); 00187 cpl_table_set_double(t, "CLASS_STAR", i, s->stellarity_index); 00188 cpl_table_set_double(t, "WEIGHT", i, s->weight); 00189 00190 if (id != NULL) 00191 { 00192 cpl_table_set_string(t, "OBJECT", i, id->name); /* possibly NULL */ 00193 cpl_table_set_double(t, "RA", i, id->ra); 00194 cpl_table_set_double(t, "DEC", i, id->dec); 00195 cpl_table_set_double(t, "MAG", i, id->magnitude); 00196 cpl_table_set_double(t, "DMAG", i, id->dmagnitude); 00197 cpl_table_set_double(t, "CAT_MAG", i, id->cat_magnitude); 00198 cpl_table_set_double(t, "DCAT_MAG", i, id->dcat_magnitude); 00199 cpl_table_set_double(t, "COLOR", i, id->color); 00200 cpl_table_set_double(t, "DCOLOR", i, id->dcolor); 00201 cpl_table_set_double(t, "COV_CATM_COL", i, id->cov_catm_color); 00202 cpl_table_set_double(t, "SHIFT_X", i, s->pixel->x 00203 - id->pixel->x); 00204 cpl_table_set_double(t, "SHIFT_Y", i, s->pixel->y 00205 - id->pixel->y); 00206 cpl_table_set_double(t, "ZEROPOINT", i, 00207 fors_star_get_zeropoint(s, NULL)); 00208 cpl_table_set_double(t, "DZEROPOINT", i, 00209 fors_star_get_zeropoint_err(s, NULL)); 00210 /* fit this magnitude in fors_photometry? (fit = !trusted) */ 00211 cpl_table_set_int (t, "USE_CAT", i, 00212 ((id->trusted) ? 1 : 0)); 00213 } 00214 else { 00215 cpl_table_set_invalid(t, "RA" , i); 00216 cpl_table_set_invalid(t, "DEC", i); 00217 cpl_table_set_invalid(t, "MAG", i); 00218 cpl_table_set_invalid(t, "DMAG", i); 00219 cpl_table_set_invalid(t, "SHIFT_X", i); 00220 cpl_table_set_invalid(t, "SHIFT_Y", i); 00221 cpl_table_set_invalid(t, "ZEROPOINT", i); 00222 cpl_table_set_invalid(t, "DZEROPOINT", i); 00223 } 00224 } 00225 } 00226 00227 return t; 00228 } 00229 00230 #undef cleanup 00231 #define cleanup \ 00232 do { \ 00233 fors_image_delete(&image); \ 00234 fors_image_delete(&image2); \ 00235 } while(0) 00236 00243 double 00244 fors_fixed_pattern_noise(const fors_image *master, 00245 double convert_ADU, 00246 double master_noise) 00247 { 00248 double master_fixed_pattern_noise; 00249 fors_image *image = NULL; 00250 fors_image *image2 = NULL; 00251 00252 assure( master != NULL, return -1, NULL ); 00253 00254 /* Use central 101x101 window 00255 and 101x101 window shifted (10, 10) from center 00256 */ 00257 if (fors_image_get_size_x(master) >= 121 && 00258 fors_image_get_size_y(master) >= 121) { 00259 00260 int mid_x = (fors_image_get_size_x(master) + 1) / 2; 00261 int mid_y = (fors_image_get_size_y(master) + 1) / 2; 00262 00263 image = fors_image_duplicate(master); 00264 fors_image_crop(image, 00265 mid_x - 50, mid_y - 50, 00266 mid_x + 50, mid_y + 50); 00267 00268 image2 = fors_image_duplicate(master); 00269 fors_image_crop(image2, 00270 mid_x + 10 - 50, mid_y + 10 - 50, 00271 mid_x + 10 + 50, mid_y + 10 + 50); 00272 00273 fors_image_subtract(image, image2); 00274 00275 master_fixed_pattern_noise = 00276 fors_image_get_stdev(image, NULL) / sqrt(2); 00277 00278 /* Convert to ADU */ 00279 master_fixed_pattern_noise *= convert_ADU; 00280 00281 /* Subtract photon noise */ 00282 if (master_fixed_pattern_noise >= master_noise) { 00283 00284 master_fixed_pattern_noise = sqrt(master_fixed_pattern_noise* 00285 master_fixed_pattern_noise 00286 - 00287 master_noise* 00288 master_noise); 00289 } 00290 else { 00291 cpl_msg_warning(cpl_func, 00292 "Zero-shift noise (%f ADU) is greater than " 00293 "accumulated zero-shift and fixed pattern noise (%f ADU), " 00294 "setting fixed pattern noise to zero", 00295 master_noise, 00296 master_fixed_pattern_noise); 00297 master_fixed_pattern_noise = 0; 00298 } 00299 } 00300 else { 00301 cpl_msg_warning(cpl_func, 00302 "Master flat too small (%dx%d), " 00303 "need size 121x121 to compute master flat " 00304 "fixed pattern noise", 00305 fors_image_get_size_x(master), 00306 fors_image_get_size_y(master)); 00307 master_fixed_pattern_noise = -1; 00308 } 00309 00310 cleanup; 00311 return master_fixed_pattern_noise; 00312 } 00313 00314 00315 #undef cleanup 00316 #define cleanup \ 00317 do { \ 00318 fors_image_delete(&image); \ 00319 fors_image_delete(&image2); \ 00320 } while(0) 00321 00328 double 00329 fors_fixed_pattern_noise_bias(const fors_image *first_raw, 00330 const fors_image *second_raw, 00331 double ron) 00332 { 00333 double bias_fixed_pattern_noise; 00334 fors_image *image = NULL; 00335 fors_image *image2 = NULL; 00336 int nx, ny; 00337 00338 assure( first_raw != NULL, return -1, NULL ); 00339 assure( second_raw != NULL, return -1, NULL ); 00340 00341 /* 00342 * Extract the largest possible two windows shifted (10, 10) 00343 */ 00344 00345 nx = fors_image_get_size_x(first_raw); 00346 ny = fors_image_get_size_y(first_raw); 00347 00348 image = fors_image_duplicate(first_raw); 00349 fors_image_crop(image, 00350 1, 1, 00351 nx - 10, ny - 10); 00352 00353 image2 = fors_image_duplicate(second_raw); 00354 fors_image_crop(image2, 00355 11, 11, 00356 nx, ny); 00357 00358 fors_image_subtract(image, image2); 00359 00360 bias_fixed_pattern_noise = fors_image_get_stdev_robust(image, 50, NULL) 00361 / sqrt(2); 00362 00363 /* 00364 * Subtract ron quadratically 00365 */ 00366 00367 if (bias_fixed_pattern_noise > ron) { 00368 00369 bias_fixed_pattern_noise = sqrt(bias_fixed_pattern_noise * 00370 bias_fixed_pattern_noise 00371 - 00372 ron * ron); 00373 } 00374 else { 00375 cpl_msg_warning(cpl_func, 00376 "Zero-shift noise (%f ADU) is greater than " 00377 "accumulated zero-shift and fixed pattern " 00378 "noise (%f ADU), " 00379 "setting fixed pattern noise to zero", 00380 ron, 00381 bias_fixed_pattern_noise); 00382 bias_fixed_pattern_noise = 0; 00383 } 00384 00385 cleanup; 00386 return bias_fixed_pattern_noise; 00387 } 00388 00389 00390 #undef cleanup 00391 #define cleanup 00392 00397 double 00398 fors_get_airmass(const cpl_propertylist *header) 00399 { 00400 double airmass_start, airmass_end; 00401 airmass_start = cpl_propertylist_get_double(header, FORS_PFITS_AIRMASS_START); 00402 assure( !cpl_error_get_code(), return -1, 00403 "Could not read %s from header", 00404 FORS_PFITS_AIRMASS_START); 00405 00406 airmass_end = cpl_propertylist_get_double(header, FORS_PFITS_AIRMASS_END); 00407 if(cpl_error_get_code()) 00408 { 00409 cpl_msg_warning(cpl_func, "Could not read %s. Using only keyword %s", 00410 FORS_PFITS_AIRMASS_END, FORS_PFITS_AIRMASS_START); 00411 cpl_error_reset(); 00412 return airmass_start; 00413 } 00414 00415 return 0.5 * (airmass_start + airmass_end); 00416 } 00417