32 #include <fors_setting.h>
34 #include <fors_instrument.h>
36 #include <fors_pfits.h>
37 #include <fors_utils.h>
72 cpl_propertylist_delete(header); \
86 cpl_propertylist *header = NULL;
88 assure( raw != NULL,
return NULL, NULL );
90 fors_msg(level,
"Instrument setting:");
91 cpl_msg_indent_more();
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 );
100 cpl_msg_debug(cpl_func,
"Reading setting from %s", filename );
103 s = cpl_malloc(
sizeof(*s));
105 s->filter_name = NULL;
106 s->read_clock = NULL;
108 s->instrument = NULL;
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);
116 assure( !cpl_error_get_code(),
return s,
117 "Could not read %s from %s header",
118 FORS_PFITS_BINX, filename);
120 fors_msg(level,
"Detector x-binning (%s) = %d", FORS_PFITS_BINX, s->binx);
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);
127 assure( !cpl_error_get_code(),
return s,
128 "Could not read %s from %s header",
129 FORS_PFITS_BINY, filename);
131 fors_msg(level,
"Detector y-binning (%s) = %d", FORS_PFITS_BINY, s->biny);
134 if (cpl_propertylist_has(header, FORS_PFITS_PRESCANX)) {
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);
141 assure( !cpl_error_get_code(),
return s,
142 "Could not read %s from %s header",
143 FORS_PFITS_PRESCANX, filename);
150 fors_msg(level,
"Detector x-prescan (%s) = %d",
151 FORS_PFITS_PRESCANX, s->prescan_x);
154 if (cpl_propertylist_has(header, FORS_PFITS_PRESCANY)) {
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);
161 assure( !cpl_error_get_code(),
return s,
162 "Could not read %s from %s header",
163 FORS_PFITS_PRESCANY, filename);
170 fors_msg(level,
"Detector y-prescan (%s) = %d",
171 FORS_PFITS_PRESCANY, s->prescan_y);
174 if (cpl_propertylist_has(header, FORS_PFITS_FILTER_NAME)) {
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);
183 assure( !cpl_error_get_code(),
return s,
184 "Could not read %s from %s header",
185 FORS_PFITS_FILTER_NAME, filename);
189 s->filter_name = cpl_strdup(s->filter_name);
191 fors_msg(level,
"Filter name (%s) = %s",
192 FORS_PFITS_FILTER_NAME, s->filter_name);
194 cpl_errorstate es = cpl_errorstate_get();
195 s->filterband = fors_instrument_filterband_get_by_setting(s);
197 cpl_errorstate_set(es);
199 bool recognized = fors_instrument_filterband_is_defined(s->filterband);
204 cpl_msg_warning(cpl_func,
"Non-standard filter...");
206 cpl_free(s->filter_name);
207 s->filter_name = NULL;
218 s->filterband = fors_instrument_filterband_value_unknown();
220 s->filter_name = NULL;
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);
231 assure( !cpl_error_get_code(),
return s,
232 "Could not read %s from %s header",
233 FORS_PFITS_EXPOSURE_TIME, filename);
235 fors_msg(level,
"Exposure time (%s) = %f s",
236 FORS_PFITS_EXPOSURE_TIME, s->exposure_time);
239 cpl_msg_debug(cpl_func,
"%s: Missing keyword '%s'",
240 filename, FORS_PFITS_EXPOSURE_TIME);
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);
249 assure( !cpl_error_get_code(),
return s,
250 "Could not read %s from %s header",
251 FORS_PFITS_PIXSCALE, filename);
253 fors_msg(level,
"Pixel scale (%s) = %f arcsec/pixel",
254 FORS_PFITS_PIXSCALE, s->pixel_scale);
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);
261 assure( !cpl_error_get_code(),
return s,
262 "Could not read instrument version from %s header",
265 fors_msg(level,
"Instrument (%s) = %s",
266 FORS_PFITS_INSTRUME, s->instrument);
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",
275 assure( !cpl_error_get_code(),
return s,
276 "Could not read %s from %s header",
277 FORS_PFITS_OUTPUTS, filename);
279 fors_msg(level,
"Output ports (%s) = %d",
280 FORS_PFITS_OUTPUTS, outputs);
285 assure( outputs == 1 || outputs == 4,
return s,
286 "1 or 4 output ports required");
291 for(i = 0; i < outputs; i++) {
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]);
300 assure( !cpl_error_get_code(),
return s,
301 "Could not read %s from %s header",
302 FORS_PFITS_CONAD[i], filename);
304 fors_msg(level,
"Gain factor (%s) = %.2f e-/ADU",
305 FORS_PFITS_CONAD[i], conad);
307 assure( conad > 0,
return s,
"%s: Illegal %s: %f, must be positive",
308 filename, FORS_PFITS_CONAD[i], conad);
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",
316 assure( !cpl_error_get_code(),
return s,
317 "Could not read %s from %s header",
318 FORS_PFITS_RON[i], filename);
320 assure( ron > 0,
return s,
321 "%s: Illegal %s: %f, must be positive",
322 filename, FORS_PFITS_RON[i], ron);
326 fors_msg(level,
"Nominal read-out-noise (%s) = %.2f ADU",
327 FORS_PFITS_RON[i], ron);
331 s->average_gain += 1.0/conad;
336 s->average_gain /= outputs;
339 fors_msg(level,
"Average gain factor = %.2f e-/ADU",
340 1.0/s->average_gain);
342 fors_msg(level,
"Read-out-noise = %.2f ADU",
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);
353 assure( !cpl_error_get_code(),
return s,
354 "Could not read %s from %s header",
355 FORS_PFITS_READ_CLOCK, filename);
357 s->read_clock = cpl_strdup(s->read_clock);
359 fors_msg(level,
"Readout clock pattern (%s) = %s",
360 FORS_PFITS_READ_CLOCK, s->read_clock);
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",
369 assure( !cpl_error_get_code(),
return s,
370 "Could not read %s from %s header",
371 FORS_PFITS_CHIP_ID, filename);
373 s->chip_id = cpl_strdup(s->chip_id);
376 fors_msg(level,
"Chip ID (%s) = %s",
377 FORS_PFITS_CHIP_ID, s->chip_id);
379 cpl_msg_indent_less();
388 fors_setting_delete(&input_setting); \
406 assure( ref_setting != NULL,
return, NULL );
407 assure( frame != NULL,
return, NULL );
408 assure( cpl_frame_get_filename(frame) != NULL,
return, NULL );
412 assure( !cpl_error_get_code(),
return,
413 "Could not get %s instrument setting",
414 cpl_frame_get_filename(frame));
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);
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);
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);
441 if (fabs((ref_setting->average_gain - input_setting->average_gain) /
442 ref_setting->average_gain) > 0.01) {
444 cpl_msg_warning(cpl_func,
"Incompatible gain factor: %f e-/ADU",
445 input_setting->average_gain);
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",
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);
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);
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);
471 if (strcmp(ref_setting->instrument, input_setting->instrument) != 0) {
472 cpl_msg_warning(cpl_func,
"Incompatible instrument name: '%s'",
473 input_setting->instrument);
476 if (strcmp(ref_setting->version, input_setting->version) != 0) {
477 cpl_msg_warning(cpl_func,
"Incompatible version: '%s'",
478 input_setting->version);
482 if (setting != NULL) {
483 *setting = input_setting;
484 input_setting = NULL;
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;
fors_setting * fors_setting_new(const cpl_frame *raw)
Create setting from FITS header.
static fors_setting * fors_setting_new_level(const cpl_frame *raw, cpl_msg_severity level)
Create setting from FITS header.
void fors_setting_verify(const fors_setting *ref_setting, const cpl_frame *frame, fors_setting **setting)
Verify that instrument settings are compatible.
void fors_setting_delete(fors_setting **s)
Deallocate and and set pointer to NULL.
const char * fors_dfs_pipeline_version(const cpl_propertylist *header, const char **instrument_version)
Get pipeline and instrument versions.