FORS Pipeline Reference Manual  5.0.9
fors_setting.c
1 /* $Id: fors_setting.c,v 1.19 2010-09-14 07:49:30 cizzo 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: cizzo $
23  * $Date: 2010-09-14 07:49:30 $
24  * $Revision: 1.19 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 #include <fors_setting.h>
33 
34 #include <fors_instrument.h>
35 #include <fors_dfs.h>
36 #include <fors_pfits.h>
37 #include <fors_utils.h>
38 
39 #include <cpl.h>
40 #include <stdbool.h>
41 #include <string.h>
42 #include <math.h>
43 
44 /*----------------------------------------------------------------------------*/
48 /*----------------------------------------------------------------------------*/
49 
52 static fors_setting *
53 fors_setting_new_level(const cpl_frame *raw, cpl_msg_severity level);
54 
55 
64 fors_setting_new(const cpl_frame *raw)
65 {
66  return fors_setting_new_level(raw, CPL_MSG_INFO);
67 }
68 
69 #undef cleanup
70 #define cleanup \
71 do { \
72  cpl_propertylist_delete(header); \
73 } while (0)
74 
81 static fors_setting *
82 fors_setting_new_level(const cpl_frame *raw, cpl_msg_severity level)
83 {
84  fors_setting *s = NULL;
85  const char *filename;
86  cpl_propertylist *header = NULL;
87 
88  assure( raw != NULL, return NULL, NULL );
89 
90  fors_msg(level, "Instrument setting:");
91  cpl_msg_indent_more();
92 
93  /* Load header */
94  filename = cpl_frame_get_filename(raw);
95  assure( filename != NULL, return NULL, "Missing frame filename" );
96  header = cpl_propertylist_load(filename, 0);
97  assure( !cpl_error_get_code(), return NULL,
98  "Could not read %s primary header", filename );
99 
100  cpl_msg_debug(cpl_func, "Reading setting from %s", filename );
101 
102  /* Read relevant contents */
103  s = cpl_malloc(sizeof(*s));
104 
105  s->filter_name = NULL;
106  s->read_clock = NULL;
107  s->chip_id = NULL;
108  s->instrument = NULL;
109  s->version = NULL;
110 
111  s->binx = cpl_propertylist_get_int(header, FORS_PFITS_BINX);
112  if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
113  cpl_msg_error(cpl_func,
114  "Keyword %s is not an integer", FORS_PFITS_BINX);
115  }
116  assure( !cpl_error_get_code(), return s,
117  "Could not read %s from %s header",
118  FORS_PFITS_BINX, filename);
119 
120  fors_msg(level, "Detector x-binning (%s) = %d", FORS_PFITS_BINX, s->binx);
121 
122  s->biny = cpl_propertylist_get_int(header, FORS_PFITS_BINY);
123  if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
124  cpl_msg_error(cpl_func,
125  "Keyword %s is not an integer", FORS_PFITS_BINY);
126  }
127  assure( !cpl_error_get_code(), return s,
128  "Could not read %s from %s header",
129  FORS_PFITS_BINY, filename);
130 
131  fors_msg(level, "Detector y-binning (%s) = %d", FORS_PFITS_BINY, s->biny);
132 
133 
134  if (cpl_propertylist_has(header, FORS_PFITS_PRESCANX)) {
135 
136  s->prescan_x = cpl_propertylist_get_int(header, FORS_PFITS_PRESCANX);
137  if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
138  cpl_msg_error(cpl_func,
139  "Keyword %s is not an integer", FORS_PFITS_PRESCANX);
140  }
141  assure( !cpl_error_get_code(), return s,
142  "Could not read %s from %s header",
143  FORS_PFITS_PRESCANX, filename);
144 
145  }
146  else {
147  s->prescan_x = 0;
148  }
149 
150  fors_msg(level, "Detector x-prescan (%s) = %d",
151  FORS_PFITS_PRESCANX, s->prescan_x);
152 
153 
154  if (cpl_propertylist_has(header, FORS_PFITS_PRESCANY)) {
155 
156  s->prescan_y = cpl_propertylist_get_int(header, FORS_PFITS_PRESCANY);
157  if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
158  cpl_msg_error(cpl_func,
159  "Keyword %s is not an integer", FORS_PFITS_PRESCANY);
160  }
161  assure( !cpl_error_get_code(), return s,
162  "Could not read %s from %s header",
163  FORS_PFITS_PRESCANY, filename);
164 
165  }
166  else {
167  s->prescan_y = 0;
168  }
169 
170  fors_msg(level, "Detector y-prescan (%s) = %d",
171  FORS_PFITS_PRESCANY, s->prescan_y);
172 
173 
174  if (cpl_propertylist_has(header, FORS_PFITS_FILTER_NAME)) {
175 
176  s->filter_name = cpl_propertylist_get_string(header,
177  FORS_PFITS_FILTER_NAME);
178  if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
179  cpl_msg_error(cpl_func,
180  "Keyword %s is not a string",
181  FORS_PFITS_FILTER_NAME);
182  }
183  assure( !cpl_error_get_code(), return s,
184  "Could not read %s from %s header",
185  FORS_PFITS_FILTER_NAME, filename);
186 
187  /* Allocate new string (after the check for NULL and
188  before deallocating the cpl_propertylist) */
189  s->filter_name = cpl_strdup(s->filter_name);
190 
191  fors_msg(level, "Filter name (%s) = %s",
192  FORS_PFITS_FILTER_NAME, s->filter_name);
193 
194  cpl_errorstate es = cpl_errorstate_get();
195  s->filterband = fors_instrument_filterband_get_by_setting(s);
196  /* for some reason, the old code did not set an error, so reset */
197  cpl_errorstate_set(es);
198 
199  bool recognized = fors_instrument_filterband_is_defined(s->filterband);
200 
201 /* %%% New part... */
202 
203  if (!recognized) {
204  cpl_msg_warning(cpl_func, "Non-standard filter...");
205  /*s->filter = FILTER_U;*/ //fixme
206  cpl_free(s->filter_name);
207  s->filter_name = NULL;
208  }
209 
210 /***
211  assure( recognized, return s, "%s: %s: Unrecognized filter name: '%s'",
212  filename, FORS_PFITS_FILTER_NAME, s->filter_name );
213 ***/
214 
215  }
216  else {
217  /* No raw frame filter (e.g. rawbias) */
218  s->filterband = fors_instrument_filterband_value_unknown();
219  /*s->filter = FILTER_U;*/ //fixme
220  s->filter_name = NULL;
221  }
222 
223  if (cpl_propertylist_has(header, FORS_PFITS_EXPOSURE_TIME)) {
224  s->exposure_time = cpl_propertylist_get_double(header,
225  FORS_PFITS_EXPOSURE_TIME);
226  if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
227  cpl_msg_error(cpl_func,
228  "Keyword %s is not a double precision type",
229  FORS_PFITS_EXPOSURE_TIME);
230  }
231  assure( !cpl_error_get_code(), return s,
232  "Could not read %s from %s header",
233  FORS_PFITS_EXPOSURE_TIME, filename);
234 
235  fors_msg(level, "Exposure time (%s) = %f s",
236  FORS_PFITS_EXPOSURE_TIME, s->exposure_time);
237  }
238  else {
239  cpl_msg_debug(cpl_func, "%s: Missing keyword '%s'",
240  filename, FORS_PFITS_EXPOSURE_TIME);
241  }
242 
243  s->pixel_scale = cpl_propertylist_get_double(header, FORS_PFITS_PIXSCALE);
244  if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
245  cpl_msg_error(cpl_func,
246  "Keyword %s is not a double precision type",
247  FORS_PFITS_PIXSCALE);
248  }
249  assure( !cpl_error_get_code(), return s,
250  "Could not read %s from %s header",
251  FORS_PFITS_PIXSCALE, filename);
252 
253  fors_msg(level, "Pixel scale (%s) = %f arcsec/pixel",
254  FORS_PFITS_PIXSCALE, s->pixel_scale);
255 
256  assure( s->pixel_scale > 0, return s,
257  "%s: %s is non-positive (%f arcsec/pixel)",
258  filename, FORS_PFITS_PIXSCALE, s->pixel_scale);
259 
260  s->version = fors_dfs_pipeline_version(header, &(s->instrument));
261  assure( !cpl_error_get_code(), return s,
262  "Could not read instrument version from %s header",
263  filename);
264 
265  fors_msg(level, "Instrument (%s) = %s",
266  FORS_PFITS_INSTRUME, s->instrument);
267 
268  {
269  int outputs = cpl_propertylist_get_int(header, FORS_PFITS_OUTPUTS);
270  if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
271  cpl_msg_error(cpl_func,
272  "Keyword %s is not integer",
273  FORS_PFITS_OUTPUTS);
274  }
275  assure( !cpl_error_get_code(), return s,
276  "Could not read %s from %s header",
277  FORS_PFITS_OUTPUTS, filename);
278 
279  fors_msg(level, "Output ports (%s) = %d",
280  FORS_PFITS_OUTPUTS, outputs);
281 
282  /* Support only new and old FORS data, where the approximation
283  about using average ron/conad is fine.
284  */
285  assure( outputs == 1 || outputs == 4, return s,
286  "1 or 4 output ports required");
287 
288  int i;
289  s->average_gain = 0;
290  s->ron = 0;
291  for(i = 0; i < outputs; i++) {
292 
293  double conad = cpl_propertylist_get_double(header,
294  FORS_PFITS_CONAD[i]);
295  if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
296  cpl_msg_error(cpl_func,
297  "Keyword %s is not a double precision type",
298  FORS_PFITS_CONAD[i]);
299  }
300  assure( !cpl_error_get_code(), return s,
301  "Could not read %s from %s header",
302  FORS_PFITS_CONAD[i], filename);
303 
304  fors_msg(level, "Gain factor (%s) = %.2f e-/ADU",
305  FORS_PFITS_CONAD[i], conad);
306 
307  assure( conad > 0, return s, "%s: Illegal %s: %f, must be positive",
308  filename, FORS_PFITS_CONAD[i], conad);
309 
310  double ron = cpl_propertylist_get_double(header, FORS_PFITS_RON[i]);
311  if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
312  cpl_msg_error(cpl_func,
313  "Keyword %s is not a double precision type",
314  FORS_PFITS_RON[i]);
315  }
316  assure( !cpl_error_get_code(), return s,
317  "Could not read %s from %s header",
318  FORS_PFITS_RON[i], filename);
319 
320  assure( ron > 0, return s,
321  "%s: Illegal %s: %f, must be positive",
322  filename, FORS_PFITS_RON[i], ron);
323 
324  ron /= conad; /* electrons -> ADU */
325 
326  fors_msg(level, "Nominal read-out-noise (%s) = %.2f ADU",
327  FORS_PFITS_RON[i], ron);
328 
329  /* accumulate */
330  s->ron += ron;
331  s->average_gain += 1.0/conad;
332  }
333 
334  /* get average */
335  s->ron /= outputs;
336  s->average_gain /= outputs;
337 
338  if (outputs > 1) {
339  fors_msg(level, "Average gain factor = %.2f e-/ADU",
340  1.0/s->average_gain);
341 
342  fors_msg(level, "Read-out-noise = %.2f ADU",
343  s->ron);
344  }
345  }
346 
347  s->read_clock = cpl_propertylist_get_string(header, FORS_PFITS_READ_CLOCK);
348  if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
349  cpl_msg_error(cpl_func,
350  "Keyword %s is not a string",
351  FORS_PFITS_READ_CLOCK);
352  }
353  assure( !cpl_error_get_code(), return s,
354  "Could not read %s from %s header",
355  FORS_PFITS_READ_CLOCK, filename);
356 
357  s->read_clock = cpl_strdup(s->read_clock);
358 
359  fors_msg(level, "Readout clock pattern (%s) = %s",
360  FORS_PFITS_READ_CLOCK, s->read_clock);
361 
362 
363  s->chip_id = cpl_propertylist_get_string(header, FORS_PFITS_CHIP_ID);
364  if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
365  cpl_msg_error(cpl_func,
366  "Keyword %s is not a string",
367  FORS_PFITS_CHIP_ID);
368  }
369  assure( !cpl_error_get_code(), return s,
370  "Could not read %s from %s header",
371  FORS_PFITS_CHIP_ID, filename);
372 
373  s->chip_id = cpl_strdup(s->chip_id);
374 
375 
376  fors_msg(level, "Chip ID (%s) = %s",
377  FORS_PFITS_CHIP_ID, s->chip_id);
378 
379  cpl_msg_indent_less();
380 
381  cleanup;
382  return s;
383 }
384 
385 #undef cleanup
386 #define cleanup \
387 do { \
388  fors_setting_delete(&input_setting); \
389 } while (0)
390 
400 void
401 fors_setting_verify(const fors_setting *ref_setting, const cpl_frame *frame,
402  fors_setting **setting)
403 {
404  fors_setting *input_setting = NULL;
405 
406  assure( ref_setting != NULL, return, NULL );
407  assure( frame != NULL, return, NULL );
408  assure( cpl_frame_get_filename(frame) != NULL, return, NULL );
409 
410  input_setting = fors_setting_new_level(frame, CPL_MSG_DEBUG);
411 
412  assure( !cpl_error_get_code(), return,
413  "Could not get %s instrument setting",
414  cpl_frame_get_filename(frame));
415 
416 
417  if (ref_setting->binx != input_setting->binx ||
418  ref_setting->biny != input_setting->biny) {
419  cpl_msg_warning(cpl_func, "Incompatible CCD binning: %dx%d",
420  input_setting->binx, input_setting->biny);
421  }
422 
423  if (ref_setting->filter_name != NULL &&
424  input_setting->filter_name != NULL &&
425  strcmp(ref_setting->filter_name, input_setting->filter_name) != 0) {
426  cpl_msg_warning(cpl_func, "Incompatible filter names: '%s'",
427  input_setting->filter_name);
428  }
429 
430  if ((ref_setting->prescan_x != input_setting->prescan_x &&
431  input_setting->prescan_x != 0) ||
432  (ref_setting->prescan_y != input_setting->prescan_y &&
433  input_setting->prescan_y != 0)) {
434  cpl_msg_warning(cpl_func, "Incompatible CCD x-prescan areas: %dx%d",
435  input_setting->prescan_x,
436  input_setting->prescan_y);
437  }
438 
439  /* no check on exposure time */
440 
441  if (fabs((ref_setting->average_gain - input_setting->average_gain) /
442  ref_setting->average_gain) > 0.01) {
443 
444  cpl_msg_warning(cpl_func, "Incompatible gain factor: %f e-/ADU",
445  input_setting->average_gain);
446  }
447 
448 
449  if (fabs((ref_setting->ron - input_setting->ron) /
450  ref_setting->ron) > 0.01) {
451  cpl_msg_warning(cpl_func, "Incompatible read-out-noise: %f ADU",
452  input_setting->ron);
453  }
454 
455  if (fabs((ref_setting->pixel_scale - input_setting->pixel_scale) /
456  ref_setting->pixel_scale) > 0.01) {
457  cpl_msg_warning(cpl_func, "Incompatible pixel scale: %f arcsec/pixel",
458  input_setting->pixel_scale);
459  }
460 
461  if (strcmp(ref_setting->chip_id, input_setting->chip_id) != 0) {
462  cpl_msg_warning(cpl_func, "Incompatible chip ID: '%s'",
463  input_setting->chip_id);
464  }
465 
466  if (strcmp(ref_setting->read_clock, input_setting->read_clock) != 0) {
467  cpl_msg_warning(cpl_func, "Incompatible readout clock pattern: '%s'",
468  input_setting->read_clock);
469  }
470 
471  if (strcmp(ref_setting->instrument, input_setting->instrument) != 0) {
472  cpl_msg_warning(cpl_func, "Incompatible instrument name: '%s'",
473  input_setting->instrument);
474  }
475 
476  if (strcmp(ref_setting->version, input_setting->version) != 0) {
477  cpl_msg_warning(cpl_func, "Incompatible version: '%s'",
478  input_setting->version);
479  }
480 
481  /* Return setting if requested */
482  if (setting != NULL) {
483  *setting = input_setting;
484  input_setting = NULL;
485  }
486 
487  cleanup;
488  return;
489 
490 }
491 
492 
493 
499 {
500  if (s && *s) {
501  if ((*s)->filter_name != NULL) cpl_free((void *)((*s)->filter_name));
502  cpl_free((void *)((*s)->read_clock));
503  cpl_free((void *)((*s)->chip_id));
504  cpl_free((void *)((*s)->version));
505  cpl_free((void *)((*s)->instrument));
506  cpl_free(*s); *s = NULL;
507  }
508  return;
509 }
510 
fors_setting * fors_setting_new(const cpl_frame *raw)
Create setting from FITS header.
Definition: fors_setting.c:64
static fors_setting * fors_setting_new_level(const cpl_frame *raw, cpl_msg_severity level)
Create setting from FITS header.
Definition: fors_setting.c:82
void fors_setting_verify(const fors_setting *ref_setting, const cpl_frame *frame, fors_setting **setting)
Verify that instrument settings are compatible.
Definition: fors_setting.c:401
#define assure(EXPR)
Definition: list.c:101
void fors_setting_delete(fors_setting **s)
Deallocate and and set pointer to NULL.
Definition: fors_setting.c:498
const char * fors_dfs_pipeline_version(const cpl_propertylist *header, const char **instrument_version)
Get pipeline and instrument versions.
Definition: fors_dfs.c:360