00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031
00032 #include <fors_setting.h>
00033
00034 #include <fors_instrument.h>
00035 #include <fors_dfs.h>
00036 #include <fors_pfits.h>
00037 #include <fors_utils.h>
00038
00039 #include <cpl.h>
00040 #include <stdbool.h>
00041 #include <string.h>
00042 #include <math.h>
00043
00044
00048
00049
00052 static fors_setting *
00053 fors_setting_new_level(const cpl_frame *raw, cpl_msg_severity level);
00054
00055
00063 fors_setting *
00064 fors_setting_new(const cpl_frame *raw)
00065 {
00066 return fors_setting_new_level(raw, CPL_MSG_INFO);
00067 }
00068
00069 #undef cleanup
00070 #define cleanup \
00071 do { \
00072 cpl_propertylist_delete(header); \
00073 } while (0)
00074
00081 static fors_setting *
00082 fors_setting_new_level(const cpl_frame *raw, cpl_msg_severity level)
00083 {
00084 fors_setting *s = NULL;
00085 const char *filename;
00086 cpl_propertylist *header = NULL;
00087
00088 assure( raw != NULL, return NULL, NULL );
00089
00090 fors_msg(level, "Instrument setting:");
00091 cpl_msg_indent_more();
00092
00093
00094 filename = cpl_frame_get_filename(raw);
00095 assure( filename != NULL, return NULL, "Missing frame filename" );
00096 header = cpl_propertylist_load(filename, 0);
00097 assure( !cpl_error_get_code(), return NULL,
00098 "Could not read %s primary header", filename );
00099
00100 cpl_msg_debug(cpl_func, "Reading setting from %s", filename );
00101
00102
00103 s = cpl_malloc(sizeof(*s));
00104
00105 s->binx = cpl_propertylist_get_int(header, FORS_PFITS_BINX);
00106 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00107 cpl_msg_error(cpl_func,
00108 "Keyword %s is not an integer", FORS_PFITS_BINX);
00109 }
00110 assure( !cpl_error_get_code(), return s,
00111 "Could not read %s from %s header",
00112 FORS_PFITS_BINX, filename);
00113
00114 fors_msg(level, "Detector x-binning (%s) = %d", FORS_PFITS_BINX, s->binx);
00115
00116 s->biny = cpl_propertylist_get_int(header, FORS_PFITS_BINY);
00117 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00118 cpl_msg_error(cpl_func,
00119 "Keyword %s is not an integer", FORS_PFITS_BINY);
00120 }
00121 assure( !cpl_error_get_code(), return s,
00122 "Could not read %s from %s header",
00123 FORS_PFITS_BINY, filename);
00124
00125 fors_msg(level, "Detector y-binning (%s) = %d", FORS_PFITS_BINY, s->biny);
00126
00127
00128 if (cpl_propertylist_has(header, FORS_PFITS_PRESCANX)) {
00129
00130 s->prescan_x = cpl_propertylist_get_int(header, FORS_PFITS_PRESCANX);
00131 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00132 cpl_msg_error(cpl_func,
00133 "Keyword %s is not an integer", FORS_PFITS_PRESCANX);
00134 }
00135 assure( !cpl_error_get_code(), return s,
00136 "Could not read %s from %s header",
00137 FORS_PFITS_PRESCANX, filename);
00138
00139 }
00140 else {
00141 s->prescan_x = 0;
00142 }
00143
00144 fors_msg(level, "Detector x-prescan (%s) = %d",
00145 FORS_PFITS_PRESCANX, s->prescan_x);
00146
00147
00148 if (cpl_propertylist_has(header, FORS_PFITS_PRESCANY)) {
00149
00150 s->prescan_y = cpl_propertylist_get_int(header, FORS_PFITS_PRESCANY);
00151 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00152 cpl_msg_error(cpl_func,
00153 "Keyword %s is not an integer", FORS_PFITS_PRESCANY);
00154 }
00155 assure( !cpl_error_get_code(), return s,
00156 "Could not read %s from %s header",
00157 FORS_PFITS_PRESCANY, filename);
00158
00159 }
00160 else {
00161 s->prescan_y = 0;
00162 }
00163
00164 fors_msg(level, "Detector y-prescan (%s) = %d",
00165 FORS_PFITS_PRESCANY, s->prescan_y);
00166
00167
00168 if (cpl_propertylist_has(header, FORS_PFITS_FILTER_NAME)) {
00169
00170 s->filter_name = cpl_propertylist_get_string(header,
00171 FORS_PFITS_FILTER_NAME);
00172 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00173 cpl_msg_error(cpl_func,
00174 "Keyword %s is not a string",
00175 FORS_PFITS_FILTER_NAME);
00176 }
00177 assure( !cpl_error_get_code(), return s,
00178 "Could not read %s from %s header",
00179 FORS_PFITS_FILTER_NAME, filename);
00180
00181
00182
00183 s->filter_name = cpl_strdup(s->filter_name);
00184
00185 fors_msg(level, "Filter name (%s) = %s",
00186 FORS_PFITS_FILTER_NAME, s->filter_name);
00187
00188 cpl_errorstate es = cpl_errorstate_get();
00189 s->filterband = fors_instrument_filterband_get_by_setting(s);
00190
00191 cpl_errorstate_set(es);
00192
00193 bool recognized = fors_instrument_filterband_is_defined(s->filterband);
00194
00195
00196
00197 if (!recognized) {
00198 cpl_msg_warning(cpl_func, "Non-standard filter...");
00199
00200 cpl_free(s->filter_name);
00201 s->filter_name = NULL;
00202 }
00203
00204
00205
00206
00207
00208
00209 }
00210 else {
00211
00212 s->filterband = fors_instrument_filterband_value_unknown();
00213
00214 s->filter_name = NULL;
00215 }
00216
00217 if (cpl_propertylist_has(header, FORS_PFITS_EXPOSURE_TIME)) {
00218 s->exposure_time = cpl_propertylist_get_double(header,
00219 FORS_PFITS_EXPOSURE_TIME);
00220 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00221 cpl_msg_error(cpl_func,
00222 "Keyword %s is not a double precision type",
00223 FORS_PFITS_EXPOSURE_TIME);
00224 }
00225 assure( !cpl_error_get_code(), return s,
00226 "Could not read %s from %s header",
00227 FORS_PFITS_EXPOSURE_TIME, filename);
00228
00229 fors_msg(level, "Exposure time (%s) = %f s",
00230 FORS_PFITS_EXPOSURE_TIME, s->exposure_time);
00231 }
00232 else {
00233 cpl_msg_debug(cpl_func, "%s: Missing keyword '%s'",
00234 filename, FORS_PFITS_EXPOSURE_TIME);
00235 }
00236
00237 s->pixel_scale = cpl_propertylist_get_double(header, FORS_PFITS_PIXSCALE);
00238 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00239 cpl_msg_error(cpl_func,
00240 "Keyword %s is not a double precision type",
00241 FORS_PFITS_PIXSCALE);
00242 }
00243 assure( !cpl_error_get_code(), return s,
00244 "Could not read %s from %s header",
00245 FORS_PFITS_PIXSCALE, filename);
00246
00247 fors_msg(level, "Pixel scale (%s) = %f arcsec/pixel",
00248 FORS_PFITS_PIXSCALE, s->pixel_scale);
00249
00250 assure( s->pixel_scale > 0, return s,
00251 "%s: %s is non-positive (%f arcsec/pixel)",
00252 filename, FORS_PFITS_PIXSCALE, s->pixel_scale);
00253
00254 s->version = fors_dfs_pipeline_version(header, &(s->instrument));
00255 assure( !cpl_error_get_code(), return s,
00256 "Could not read instrument version from %s header",
00257 filename);
00258
00259 fors_msg(level, "Instrument (%s) = %s",
00260 FORS_PFITS_INSTRUME, s->instrument);
00261
00262 {
00263 int outputs = cpl_propertylist_get_int(header, FORS_PFITS_OUTPUTS);
00264 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00265 cpl_msg_error(cpl_func,
00266 "Keyword %s is not integer",
00267 FORS_PFITS_OUTPUTS);
00268 }
00269 assure( !cpl_error_get_code(), return s,
00270 "Could not read %s from %s header",
00271 FORS_PFITS_OUTPUTS, filename);
00272
00273 fors_msg(level, "Output ports (%s) = %d",
00274 FORS_PFITS_OUTPUTS, outputs);
00275
00276
00277
00278
00279 assure( outputs == 1 || outputs == 4, return s,
00280 "1 or 4 output ports required");
00281
00282 int i;
00283 s->average_gain = 0;
00284 s->ron = 0;
00285 for(i = 0; i < outputs; i++) {
00286
00287 double conad = cpl_propertylist_get_double(header,
00288 FORS_PFITS_CONAD[i]);
00289 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00290 cpl_msg_error(cpl_func,
00291 "Keyword %s is not a double precision type",
00292 FORS_PFITS_CONAD[i]);
00293 }
00294 assure( !cpl_error_get_code(), return s,
00295 "Could not read %s from %s header",
00296 FORS_PFITS_CONAD[i], filename);
00297
00298 fors_msg(level, "Gain factor (%s) = %.2f e-/ADU",
00299 FORS_PFITS_CONAD[i], conad);
00300
00301 assure( conad > 0, return s, "%s: Illegal %s: %f, must be positive",
00302 filename, FORS_PFITS_CONAD[i], conad);
00303
00304 double ron = cpl_propertylist_get_double(header, FORS_PFITS_RON[i]);
00305 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00306 cpl_msg_error(cpl_func,
00307 "Keyword %s is not a double precision type",
00308 FORS_PFITS_RON[i]);
00309 }
00310 assure( !cpl_error_get_code(), return s,
00311 "Could not read %s from %s header",
00312 FORS_PFITS_RON[i], filename);
00313
00314 assure( ron > 0, return s,
00315 "%s: Illegal %s: %f, must be positive",
00316 filename, FORS_PFITS_RON[i], ron);
00317
00318 ron /= conad;
00319
00320 fors_msg(level, "Read-out-noise (%s) = %.2f ADU",
00321 FORS_PFITS_RON[i], ron);
00322
00323
00324 s->ron += ron;
00325 s->average_gain += 1.0/conad;
00326 }
00327
00328
00329 s->ron /= outputs;
00330 s->average_gain /= outputs;
00331
00332 if (outputs > 1) {
00333 fors_msg(level, "Average gain factor = %.2f e-/ADU",
00334 1.0/s->average_gain);
00335
00336 fors_msg(level, "Read-out-noise = %.2f ADU",
00337 s->ron);
00338 }
00339 }
00340
00341 s->read_clock = cpl_propertylist_get_string(header, FORS_PFITS_READ_CLOCK);
00342 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00343 cpl_msg_error(cpl_func,
00344 "Keyword %s is not a string",
00345 FORS_PFITS_READ_CLOCK);
00346 }
00347 assure( !cpl_error_get_code(), return s,
00348 "Could not read %s from %s header",
00349 FORS_PFITS_READ_CLOCK, filename);
00350
00351 s->read_clock = cpl_strdup(s->read_clock);
00352
00353 fors_msg(level, "Readout clock pattern (%s) = %s",
00354 FORS_PFITS_READ_CLOCK, s->read_clock);
00355
00356
00357 s->chip_id = cpl_propertylist_get_string(header, FORS_PFITS_CHIP_ID);
00358 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00359 cpl_msg_error(cpl_func,
00360 "Keyword %s is not a string",
00361 FORS_PFITS_CHIP_ID);
00362 }
00363 assure( !cpl_error_get_code(), return s,
00364 "Could not read %s from %s header",
00365 FORS_PFITS_CHIP_ID, filename);
00366
00367 s->chip_id = cpl_strdup(s->chip_id);
00368
00369
00370 fors_msg(level, "Chip ID (%s) = %s",
00371 FORS_PFITS_CHIP_ID, s->chip_id);
00372
00373 cpl_msg_indent_less();
00374
00375 cleanup;
00376 return s;
00377 }
00378
00379 #undef cleanup
00380 #define cleanup \
00381 do { \
00382 fors_setting_delete(&input_setting); \
00383 } while (0)
00384
00394 void
00395 fors_setting_verify(const fors_setting *ref_setting, const cpl_frame *frame,
00396 fors_setting **setting)
00397 {
00398 fors_setting *input_setting = NULL;
00399
00400 assure( ref_setting != NULL, return, NULL );
00401 assure( frame != NULL, return, NULL );
00402 assure( cpl_frame_get_filename(frame) != NULL, return, NULL );
00403
00404 input_setting = fors_setting_new_level(frame, CPL_MSG_DEBUG);
00405
00406 assure( !cpl_error_get_code(), return,
00407 "Could not get %s instrument setting",
00408 cpl_frame_get_filename(frame));
00409
00410
00411 if (ref_setting->binx != input_setting->binx ||
00412 ref_setting->biny != input_setting->biny) {
00413 cpl_msg_warning(cpl_func, "Incompatible CCD binning: %dx%d",
00414 input_setting->binx, input_setting->biny);
00415 }
00416
00417 if (ref_setting->filter_name != NULL &&
00418 input_setting->filter_name != NULL &&
00419 strcmp(ref_setting->filter_name, input_setting->filter_name) != 0) {
00420 cpl_msg_warning(cpl_func, "Incompatible filter names: '%s'",
00421 input_setting->filter_name);
00422 }
00423
00424 if ((ref_setting->prescan_x != input_setting->prescan_x &&
00425 input_setting->prescan_x != 0) ||
00426 (ref_setting->prescan_y != input_setting->prescan_y &&
00427 input_setting->prescan_y != 0)) {
00428 cpl_msg_warning(cpl_func, "Incompatible CCD x-prescan areas: %dx%d",
00429 input_setting->prescan_x,
00430 input_setting->prescan_y);
00431 }
00432
00433
00434
00435 if (fabs((ref_setting->average_gain - input_setting->average_gain) /
00436 ref_setting->average_gain) > 0.01) {
00437
00438 cpl_msg_warning(cpl_func, "Incompatible gain factor: %f e-/ADU",
00439 input_setting->average_gain);
00440 }
00441
00442
00443 if (fabs((ref_setting->ron - input_setting->ron) /
00444 ref_setting->ron) > 0.01) {
00445 cpl_msg_warning(cpl_func, "Incompatible read-out-noise: %f ADU",
00446 input_setting->ron);
00447 }
00448
00449 if (fabs((ref_setting->pixel_scale - input_setting->pixel_scale) /
00450 ref_setting->pixel_scale) > 0.01) {
00451 cpl_msg_warning(cpl_func, "Incompatible pixel scale: %f arcsec/pixel",
00452 input_setting->pixel_scale);
00453 }
00454
00455 if (strcmp(ref_setting->chip_id, input_setting->chip_id) != 0) {
00456 cpl_msg_warning(cpl_func, "Incompatible chip ID: '%s'",
00457 input_setting->chip_id);
00458 }
00459
00460 if (strcmp(ref_setting->read_clock, input_setting->read_clock) != 0) {
00461 cpl_msg_warning(cpl_func, "Incompatible readout clock pattern: '%s'",
00462 input_setting->read_clock);
00463 }
00464
00465 if (strcmp(ref_setting->instrument, input_setting->instrument) != 0) {
00466 cpl_msg_warning(cpl_func, "Incompatible instrument name: '%s'",
00467 input_setting->instrument);
00468 }
00469
00470 if (strcmp(ref_setting->version, input_setting->version) != 0) {
00471 cpl_msg_warning(cpl_func, "Incompatible version: '%s'",
00472 input_setting->version);
00473 }
00474
00475
00476 if (setting != NULL) {
00477 *setting = input_setting;
00478 input_setting = NULL;
00479 }
00480
00481 cleanup;
00482 return;
00483
00484 }
00485
00486
00487
00492 void fors_setting_delete(fors_setting **s)
00493 {
00494 if (s && *s) {
00495 if ((*s)->filter_name != NULL) cpl_free((void *)((*s)->filter_name));
00496 cpl_free((void *)((*s)->read_clock));
00497 cpl_free((void *)((*s)->chip_id));
00498 cpl_free((void *)((*s)->version));
00499 cpl_free((void *)((*s)->instrument));
00500 cpl_free(*s); *s = NULL;
00501 }
00502 return;
00503 }
00504