FORS Pipeline Reference Manual  5.0.9
fors_tools.c
1 /* $Id: fors_tools.c,v 1.22 2012-08-07 15:26:53 cgarcia Exp $
2  *
3  * This file is part of the FORS Library
4  * Copyright (C) 2002-2010 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /*
22  * $Author: cgarcia $
23  * $Date: 2012-08-07 15:26:53 $
24  * $Revision: 1.22 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 #include <math.h>
33 #include <fors_tools.h>
34 
35 #include <fors_pfits.h>
36 #include <fors_utils.h>
37 
38 #include <cpl.h>
39 #include <stdbool.h>
40 #include <assert.h>
41 
42 /*----------------------------------------------------------------------------*/
46 /*----------------------------------------------------------------------------*/
47 
50 #undef cleanup
51 #define cleanup \
52 do { \
53  cpl_propertylist_delete(header); \
54 } while(0)
55 
64 double
65 fors_star_ext_corr(fors_star_list *stars,
66  const fors_setting *setting,
67  double ext_coeff,
68  double dext_coeff,
69  const cpl_frame *raw_frame)
70 {
71  cpl_propertylist *header = NULL;
72 
73 
74  cpl_msg_info(cpl_func, "Extinction correction");
75 
76  assure( cpl_frame_get_filename(raw_frame) != NULL, return -1, NULL );
77 
78  header = cpl_propertylist_load(cpl_frame_get_filename(raw_frame), 0);
79  assure( !cpl_error_get_code(), return -1,
80  "Failed to load %s primary header",
81  cpl_frame_get_filename(raw_frame));
82 
83 
84  double avg_airmass = fors_get_airmass(header);
85  assure( !cpl_error_get_code(), return -1,
86  "%s: Could not read airmass",
87  cpl_frame_get_filename(raw_frame));
88 
89  cpl_msg_indent_more();
90  cpl_msg_info(cpl_func, "Exposure time = %f s", setting->exposure_time);
91  cpl_msg_info(cpl_func, "Gain = %f ADU/e-", setting->average_gain);
92  cpl_msg_info(cpl_func, "Ext. coeff. = %f +- %f mag/airmass",
93  ext_coeff, dext_coeff);
94  cpl_msg_info(cpl_func, "Avg. airmass = %f airmass", avg_airmass);
95  /* The quantity and the unit are both 'airmass' */
96 
97  cpl_msg_indent_less();
98 
99  {
100  fors_star *star;
101 
102  for (star = fors_star_list_first(stars);
103  star != NULL;
104  star = fors_star_list_next(stars)) {
105  star->magnitude_corr = star->magnitude
106  + 2.5*log(setting->average_gain)/log(10)
107  + 2.5*log(setting->exposure_time)/log(10)
108  - ext_coeff * avg_airmass;
109 
110  /* Propagate error from ext.coeff.
111  gain, exptime and airmass
112  have zero error */
113  star->dmagnitude_corr = sqrt(star->dmagnitude * star->dmagnitude
114  + dext_coeff*dext_coeff * avg_airmass*avg_airmass);
115  }
116  }
117 
118  cleanup;
119  return avg_airmass;
120 }
121 
129 cpl_table *
130 fors_create_sources_table(fors_star_list *sources)
131 {
132  cpl_table *t = NULL;
133 
134  t = cpl_table_new(fors_star_list_size(sources));
135  cpl_table_new_column(t, "X", CPL_TYPE_DOUBLE);
136  cpl_table_new_column(t, "Y", CPL_TYPE_DOUBLE);
137  cpl_table_new_column(t, "FWHM", CPL_TYPE_DOUBLE);
138  cpl_table_new_column(t, "A", CPL_TYPE_DOUBLE);
139  cpl_table_new_column(t, "B", CPL_TYPE_DOUBLE);
140  cpl_table_new_column(t, "THETA", CPL_TYPE_DOUBLE);
141  cpl_table_new_column(t, "ELL", CPL_TYPE_DOUBLE);
142  cpl_table_new_column(t, "INSTR_MAG", CPL_TYPE_DOUBLE);
143  cpl_table_new_column(t, "DINSTR_MAG", CPL_TYPE_DOUBLE);
144  cpl_table_new_column(t, "INSTR_CMAG", CPL_TYPE_DOUBLE);
145  cpl_table_new_column(t, "DINSTR_CMAG", CPL_TYPE_DOUBLE);
146  cpl_table_new_column(t, "CLASS_STAR", CPL_TYPE_DOUBLE);
147 
148  cpl_table_new_column(t, "OBJECT", CPL_TYPE_STRING);
149  cpl_table_new_column(t, "RA", CPL_TYPE_DOUBLE);
150  cpl_table_new_column(t, "DEC", CPL_TYPE_DOUBLE);
151  cpl_table_new_column(t, "MAG", CPL_TYPE_DOUBLE);
152  cpl_table_new_column(t, "DMAG", CPL_TYPE_DOUBLE);
153  cpl_table_new_column(t, "CAT_MAG", CPL_TYPE_DOUBLE);
154  cpl_table_new_column(t, "DCAT_MAG", CPL_TYPE_DOUBLE);
155  cpl_table_new_column(t, "COLOR", CPL_TYPE_DOUBLE);
156  cpl_table_new_column(t, "DCOLOR", CPL_TYPE_DOUBLE);
157  cpl_table_new_column(t, "COV_CATM_COL", CPL_TYPE_DOUBLE);
158  cpl_table_new_column(t, "USE_CAT", CPL_TYPE_INT);
159  /* Shift in x and y between initial guess FITS header WCS position
160  and measured position */
161  cpl_table_new_column(t, "SHIFT_X", CPL_TYPE_DOUBLE);
162  cpl_table_new_column(t, "SHIFT_Y", CPL_TYPE_DOUBLE);
163  cpl_table_new_column(t, "ZEROPOINT", CPL_TYPE_DOUBLE);
164  cpl_table_new_column(t, "DZEROPOINT", CPL_TYPE_DOUBLE);
165  cpl_table_new_column(t, "WEIGHT", CPL_TYPE_DOUBLE);
166 
167  {
168  fors_star *s;
169  int i;
170  for (s = fors_star_list_first(sources), i = 0;
171  s != NULL;
172  s = fors_star_list_next(sources), i++) {
173 
174  const fors_std_star *id = s->id;
175 
176  cpl_table_set_double(t, "X", i, s->pixel->x);
177  cpl_table_set_double(t, "Y", i, s->pixel->y);
178  cpl_table_set_double(t, "FWHM", i, s->fwhm);
179  cpl_table_set_double(t, "A", i, s->semi_major);
180  cpl_table_set_double(t, "B", i, s->semi_minor);
181  cpl_table_set_double(t, "THETA", i, s->orientation);
182  cpl_table_set_double(t, "ELL", i, fors_star_ellipticity(s, NULL));
183  cpl_table_set_double(t, "INSTR_MAG", i, s->magnitude);
184  cpl_table_set_double(t, "DINSTR_MAG", i, s->dmagnitude);
185  cpl_table_set_double(t, "INSTR_CMAG", i, s->magnitude_corr);
186  cpl_table_set_double(t, "DINSTR_CMAG", i, s->dmagnitude_corr);
187  cpl_table_set_double(t, "CLASS_STAR", i, s->stellarity_index);
188  cpl_table_set_double(t, "WEIGHT", i, s->weight);
189 
190  if (id != NULL)
191  {
192  cpl_table_set_string(t, "OBJECT", i, id->name); /* possibly NULL */
193  cpl_table_set_double(t, "RA", i, id->ra);
194  cpl_table_set_double(t, "DEC", i, id->dec);
195  cpl_table_set_double(t, "MAG", i, id->magnitude);
196  cpl_table_set_double(t, "DMAG", i, id->dmagnitude);
197  cpl_table_set_double(t, "CAT_MAG", i, id->cat_magnitude);
198  cpl_table_set_double(t, "DCAT_MAG", i, id->dcat_magnitude);
199  cpl_table_set_double(t, "COLOR", i, id->color);
200  cpl_table_set_double(t, "DCOLOR", i, id->dcolor);
201  cpl_table_set_double(t, "COV_CATM_COL", i, id->cov_catm_color);
202  cpl_table_set_double(t, "SHIFT_X", i, s->pixel->x
203  - id->pixel->x);
204  cpl_table_set_double(t, "SHIFT_Y", i, s->pixel->y
205  - id->pixel->y);
206  cpl_table_set_double(t, "ZEROPOINT", i,
207  fors_star_get_zeropoint(s, NULL));
208  cpl_table_set_double(t, "DZEROPOINT", i,
209  fors_star_get_zeropoint_err(s, NULL));
210  /* fit this magnitude in fors_photometry? (fit = !trusted) */
211  cpl_table_set_int (t, "USE_CAT", i,
212  ((id->trusted) ? 1 : 0));
213  }
214  else {
215  cpl_table_set_invalid(t, "RA" , i);
216  cpl_table_set_invalid(t, "DEC", i);
217  cpl_table_set_invalid(t, "MAG", i);
218  cpl_table_set_invalid(t, "DMAG", i);
219  cpl_table_set_invalid(t, "SHIFT_X", i);
220  cpl_table_set_invalid(t, "SHIFT_Y", i);
221  cpl_table_set_invalid(t, "ZEROPOINT", i);
222  cpl_table_set_invalid(t, "DZEROPOINT", i);
223  }
224  }
225  }
226 
227  return t;
228 }
229 
230 #undef cleanup
231 #define cleanup \
232 do { \
233  fors_image_delete(&image); \
234  fors_image_delete(&image2); \
235 } while(0)
236 
243 double
245  double convert_ADU,
246  double master_noise)
247 {
248  double master_fixed_pattern_noise;
249  fors_image *image = NULL;
250  fors_image *image2 = NULL;
251 
252  assure( master != NULL, return -1, NULL );
253 
254  /* Use central 101x101 window
255  and 101x101 window shifted (10, 10) from center
256  */
257  if (fors_image_get_size_x(master) >= 121 &&
258  fors_image_get_size_y(master) >= 121) {
259 
260  int mid_x = (fors_image_get_size_x(master) + 1) / 2;
261  int mid_y = (fors_image_get_size_y(master) + 1) / 2;
262 
263  image = fors_image_duplicate(master);
264  fors_image_crop(image,
265  mid_x - 50, mid_y - 50,
266  mid_x + 50, mid_y + 50);
267 
268  image2 = fors_image_duplicate(master);
269  fors_image_crop(image2,
270  mid_x + 10 - 50, mid_y + 10 - 50,
271  mid_x + 10 + 50, mid_y + 10 + 50);
272 
273  fors_image_subtract(image, image2);
274 
275  master_fixed_pattern_noise =
276  fors_image_get_stdev(image, NULL) / sqrt(2);
277 
278  /* Convert to ADU */
279  master_fixed_pattern_noise *= convert_ADU;
280 
281  /* Subtract photon noise */
282  if (master_fixed_pattern_noise >= master_noise) {
283 
284  master_fixed_pattern_noise = sqrt(master_fixed_pattern_noise*
285  master_fixed_pattern_noise
286  -
287  master_noise*
288  master_noise);
289  }
290  else {
291  cpl_msg_warning(cpl_func,
292  "Zero-shift noise (%f ADU) is greater than "
293  "accumulated zero-shift and fixed pattern noise (%f ADU), "
294  "setting fixed pattern noise to zero",
295  master_noise,
296  master_fixed_pattern_noise);
297  master_fixed_pattern_noise = 0;
298  }
299  }
300  else {
301  cpl_msg_warning(cpl_func,
302  "Master flat too small (%dx%d), "
303  "need size 121x121 to compute master flat "
304  "fixed pattern noise",
305  fors_image_get_size_x(master),
306  fors_image_get_size_y(master));
307  master_fixed_pattern_noise = -1;
308  }
309 
310  cleanup;
311  return master_fixed_pattern_noise;
312 }
313 
314 
315 #undef cleanup
316 #define cleanup \
317 do { \
318  fors_image_delete(&image); \
319  fors_image_delete(&image2); \
320 } while(0)
321 
328 double
330  const fors_image *second_raw,
331  double ron)
332 {
333  double bias_fixed_pattern_noise;
334  fors_image *image = NULL;
335  fors_image *image2 = NULL;
336  int nx, ny;
337 
338  assure( first_raw != NULL, return -1, NULL );
339  assure( second_raw != NULL, return -1, NULL );
340 
341  /*
342  * Extract the largest possible two windows shifted (10, 10)
343  */
344 
345  nx = fors_image_get_size_x(first_raw);
346  ny = fors_image_get_size_y(first_raw);
347 
348  image = fors_image_duplicate(first_raw);
349  fors_image_crop(image,
350  1, 1,
351  nx - 10, ny - 10);
352 
353  image2 = fors_image_duplicate(second_raw);
354  fors_image_crop(image2,
355  11, 11,
356  nx, ny);
357 
358  fors_image_subtract(image, image2);
359 
360  bias_fixed_pattern_noise = fors_image_get_stdev_robust(image, 50, NULL)
361  / sqrt(2);
362 
363  /*
364  * Subtract ron quadratically
365  */
366 
367  if (bias_fixed_pattern_noise > ron) {
368 
369  bias_fixed_pattern_noise = sqrt(bias_fixed_pattern_noise *
370  bias_fixed_pattern_noise
371  -
372  ron * ron);
373  }
374  else {
375  cpl_msg_warning(cpl_func,
376  "Zero-shift noise (%f ADU) is greater than "
377  "accumulated zero-shift and fixed pattern "
378  "noise (%f ADU), "
379  "setting fixed pattern noise to zero",
380  ron,
381  bias_fixed_pattern_noise);
382  bias_fixed_pattern_noise = 0;
383  }
384 
385  cleanup;
386  return bias_fixed_pattern_noise;
387 }
388 
389 
390 #undef cleanup
391 #define cleanup
392 
397 double
398 fors_get_airmass(const cpl_propertylist *header)
399 {
400  double airmass_start, airmass_end;
401  airmass_start = cpl_propertylist_get_double(header, FORS_PFITS_AIRMASS_START);
402  assure( !cpl_error_get_code(), return -1,
403  "Could not read %s from header",
404  FORS_PFITS_AIRMASS_START);
405 
406  airmass_end = cpl_propertylist_get_double(header, FORS_PFITS_AIRMASS_END);
407  if(cpl_error_get_code())
408  {
409  cpl_msg_warning(cpl_func, "Could not read %s. Using only keyword %s",
410  FORS_PFITS_AIRMASS_END, FORS_PFITS_AIRMASS_START);
411  cpl_error_reset();
412  return airmass_start;
413  }
414 
415  return 0.5 * (airmass_start + airmass_end);
416 }
417 
418 int fors_isnan(double x)
419 {
420  return isnan(x);
421 }
422 
423 
double fors_image_get_stdev_robust(const fors_image *image, double cut, double *dstdev)
Get robust empirical stdev of data.
Definition: fors_image.c:1394
double fors_star_ellipticity(const fors_star *s, void *data)
Get star ellipticity.
Definition: fors_star.c:402
double fors_fixed_pattern_noise_bias(const fors_image *first_raw, const fors_image *second_raw, double ron)
Compute fixed pattern noise in bias.
Definition: fors_tools.c:329
void fors_image_subtract(fors_image *left, const fors_image *right)
Subtract images.
Definition: fors_image.c:595
double fors_fixed_pattern_noise(const fors_image *master, double convert_ADU, double master_noise)
Compute fixed pattern noise in flat field.
Definition: fors_tools.c:244
void fors_image_crop(fors_image *image, int xlo, int ylo, int xhi, int yhi)
Crop image.
Definition: fors_image.c:1008
double fors_star_ext_corr(fors_star_list *stars, const fors_setting *setting, double ext_coeff, double dext_coeff, const cpl_frame *raw_frame)
Correct for extinction, gain, exposure time.
Definition: fors_tools.c:65
double fors_image_get_stdev(const fors_image *image, double *dstdev)
Get empirical stdev of data.
Definition: fors_image.c:1373
cpl_size fors_image_get_size_y(const fors_image *image)
Get image height.
Definition: fors_image.c:514
#define assure(EXPR)
Definition: list.c:101
double fors_star_get_zeropoint_err(const fors_star *s, void *data)
Get zeropoint error.
Definition: fors_star.c:522
cpl_size fors_image_get_size_x(const fors_image *image)
Get image width.
Definition: fors_image.c:501
double fors_get_airmass(const cpl_propertylist *header)
Compute average airmass.
Definition: fors_tools.c:398
cpl_table * fors_create_sources_table(fors_star_list *sources)
Create product.
Definition: fors_tools.c:130
double fors_star_get_zeropoint(const fors_star *s, void *data)
Get zeropoint.
Definition: fors_star.c:504
fors_image * fors_image_duplicate(const fors_image *image)
Copy constructor.
Definition: fors_image.c:151