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->filter_name = NULL;
00106 s->read_clock = NULL;
00107 s->chip_id = NULL;
00108 s->instrument = NULL;
00109 s->version = NULL;
00110
00111 s->binx = cpl_propertylist_get_int(header, FORS_PFITS_BINX);
00112 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00113 cpl_msg_error(cpl_func,
00114 "Keyword %s is not an integer", FORS_PFITS_BINX);
00115 }
00116 assure( !cpl_error_get_code(), return s,
00117 "Could not read %s from %s header",
00118 FORS_PFITS_BINX, filename);
00119
00120 fors_msg(level, "Detector x-binning (%s) = %d", FORS_PFITS_BINX, s->binx);
00121
00122 s->biny = cpl_propertylist_get_int(header, FORS_PFITS_BINY);
00123 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00124 cpl_msg_error(cpl_func,
00125 "Keyword %s is not an integer", FORS_PFITS_BINY);
00126 }
00127 assure( !cpl_error_get_code(), return s,
00128 "Could not read %s from %s header",
00129 FORS_PFITS_BINY, filename);
00130
00131 fors_msg(level, "Detector y-binning (%s) = %d", FORS_PFITS_BINY, s->biny);
00132
00133
00134 if (cpl_propertylist_has(header, FORS_PFITS_PRESCANX)) {
00135
00136 s->prescan_x = cpl_propertylist_get_int(header, FORS_PFITS_PRESCANX);
00137 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00138 cpl_msg_error(cpl_func,
00139 "Keyword %s is not an integer", FORS_PFITS_PRESCANX);
00140 }
00141 assure( !cpl_error_get_code(), return s,
00142 "Could not read %s from %s header",
00143 FORS_PFITS_PRESCANX, filename);
00144
00145 }
00146 else {
00147 s->prescan_x = 0;
00148 }
00149
00150 fors_msg(level, "Detector x-prescan (%s) = %d",
00151 FORS_PFITS_PRESCANX, s->prescan_x);
00152
00153
00154 if (cpl_propertylist_has(header, FORS_PFITS_PRESCANY)) {
00155
00156 s->prescan_y = cpl_propertylist_get_int(header, FORS_PFITS_PRESCANY);
00157 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00158 cpl_msg_error(cpl_func,
00159 "Keyword %s is not an integer", FORS_PFITS_PRESCANY);
00160 }
00161 assure( !cpl_error_get_code(), return s,
00162 "Could not read %s from %s header",
00163 FORS_PFITS_PRESCANY, filename);
00164
00165 }
00166 else {
00167 s->prescan_y = 0;
00168 }
00169
00170 fors_msg(level, "Detector y-prescan (%s) = %d",
00171 FORS_PFITS_PRESCANY, s->prescan_y);
00172
00173
00174 if (cpl_propertylist_has(header, FORS_PFITS_FILTER_NAME)) {
00175
00176 s->filter_name = cpl_propertylist_get_string(header,
00177 FORS_PFITS_FILTER_NAME);
00178 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00179 cpl_msg_error(cpl_func,
00180 "Keyword %s is not a string",
00181 FORS_PFITS_FILTER_NAME);
00182 }
00183 assure( !cpl_error_get_code(), return s,
00184 "Could not read %s from %s header",
00185 FORS_PFITS_FILTER_NAME, filename);
00186
00187
00188
00189 s->filter_name = cpl_strdup(s->filter_name);
00190
00191 fors_msg(level, "Filter name (%s) = %s",
00192 FORS_PFITS_FILTER_NAME, s->filter_name);
00193
00194 cpl_errorstate es = cpl_errorstate_get();
00195 s->filterband = fors_instrument_filterband_get_by_setting(s);
00196
00197 cpl_errorstate_set(es);
00198
00199 bool recognized = fors_instrument_filterband_is_defined(s->filterband);
00200
00201
00202
00203 if (!recognized) {
00204 cpl_msg_warning(cpl_func, "Non-standard filter...");
00205
00206 cpl_free(s->filter_name);
00207 s->filter_name = NULL;
00208 }
00209
00210
00211
00212
00213
00214
00215 }
00216 else {
00217
00218 s->filterband = fors_instrument_filterband_value_unknown();
00219
00220 s->filter_name = NULL;
00221 }
00222
00223 if (cpl_propertylist_has(header, FORS_PFITS_EXPOSURE_TIME)) {
00224 s->exposure_time = cpl_propertylist_get_double(header,
00225 FORS_PFITS_EXPOSURE_TIME);
00226 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00227 cpl_msg_error(cpl_func,
00228 "Keyword %s is not a double precision type",
00229 FORS_PFITS_EXPOSURE_TIME);
00230 }
00231 assure( !cpl_error_get_code(), return s,
00232 "Could not read %s from %s header",
00233 FORS_PFITS_EXPOSURE_TIME, filename);
00234
00235 fors_msg(level, "Exposure time (%s) = %f s",
00236 FORS_PFITS_EXPOSURE_TIME, s->exposure_time);
00237 }
00238 else {
00239 cpl_msg_debug(cpl_func, "%s: Missing keyword '%s'",
00240 filename, FORS_PFITS_EXPOSURE_TIME);
00241 }
00242
00243 s->pixel_scale = cpl_propertylist_get_double(header, FORS_PFITS_PIXSCALE);
00244 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00245 cpl_msg_error(cpl_func,
00246 "Keyword %s is not a double precision type",
00247 FORS_PFITS_PIXSCALE);
00248 }
00249 assure( !cpl_error_get_code(), return s,
00250 "Could not read %s from %s header",
00251 FORS_PFITS_PIXSCALE, filename);
00252
00253 fors_msg(level, "Pixel scale (%s) = %f arcsec/pixel",
00254 FORS_PFITS_PIXSCALE, s->pixel_scale);
00255
00256 assure( s->pixel_scale > 0, return s,
00257 "%s: %s is non-positive (%f arcsec/pixel)",
00258 filename, FORS_PFITS_PIXSCALE, s->pixel_scale);
00259
00260 s->version = fors_dfs_pipeline_version(header, &(s->instrument));
00261 assure( !cpl_error_get_code(), return s,
00262 "Could not read instrument version from %s header",
00263 filename);
00264
00265 fors_msg(level, "Instrument (%s) = %s",
00266 FORS_PFITS_INSTRUME, s->instrument);
00267
00268 {
00269 int outputs = cpl_propertylist_get_int(header, FORS_PFITS_OUTPUTS);
00270 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00271 cpl_msg_error(cpl_func,
00272 "Keyword %s is not integer",
00273 FORS_PFITS_OUTPUTS);
00274 }
00275 assure( !cpl_error_get_code(), return s,
00276 "Could not read %s from %s header",
00277 FORS_PFITS_OUTPUTS, filename);
00278
00279 fors_msg(level, "Output ports (%s) = %d",
00280 FORS_PFITS_OUTPUTS, outputs);
00281
00282
00283
00284
00285 assure( outputs == 1 || outputs == 4, return s,
00286 "1 or 4 output ports required");
00287
00288 int i;
00289 s->average_gain = 0;
00290 s->ron = 0;
00291 for(i = 0; i < outputs; i++) {
00292
00293 double conad = cpl_propertylist_get_double(header,
00294 FORS_PFITS_CONAD[i]);
00295 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00296 cpl_msg_error(cpl_func,
00297 "Keyword %s is not a double precision type",
00298 FORS_PFITS_CONAD[i]);
00299 }
00300 assure( !cpl_error_get_code(), return s,
00301 "Could not read %s from %s header",
00302 FORS_PFITS_CONAD[i], filename);
00303
00304 fors_msg(level, "Gain factor (%s) = %.2f e-/ADU",
00305 FORS_PFITS_CONAD[i], conad);
00306
00307 assure( conad > 0, return s, "%s: Illegal %s: %f, must be positive",
00308 filename, FORS_PFITS_CONAD[i], conad);
00309
00310 double ron = cpl_propertylist_get_double(header, FORS_PFITS_RON[i]);
00311 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00312 cpl_msg_error(cpl_func,
00313 "Keyword %s is not a double precision type",
00314 FORS_PFITS_RON[i]);
00315 }
00316 assure( !cpl_error_get_code(), return s,
00317 "Could not read %s from %s header",
00318 FORS_PFITS_RON[i], filename);
00319
00320 assure( ron > 0, return s,
00321 "%s: Illegal %s: %f, must be positive",
00322 filename, FORS_PFITS_RON[i], ron);
00323
00324 ron /= conad;
00325
00326 fors_msg(level, "Read-out-noise (%s) = %.2f ADU",
00327 FORS_PFITS_RON[i], ron);
00328
00329
00330 s->ron += ron;
00331 s->average_gain += 1.0/conad;
00332 }
00333
00334
00335 s->ron /= outputs;
00336 s->average_gain /= outputs;
00337
00338 if (outputs > 1) {
00339 fors_msg(level, "Average gain factor = %.2f e-/ADU",
00340 1.0/s->average_gain);
00341
00342 fors_msg(level, "Read-out-noise = %.2f ADU",
00343 s->ron);
00344 }
00345 }
00346
00347 s->read_clock = cpl_propertylist_get_string(header, FORS_PFITS_READ_CLOCK);
00348 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00349 cpl_msg_error(cpl_func,
00350 "Keyword %s is not a string",
00351 FORS_PFITS_READ_CLOCK);
00352 }
00353 assure( !cpl_error_get_code(), return s,
00354 "Could not read %s from %s header",
00355 FORS_PFITS_READ_CLOCK, filename);
00356
00357 s->read_clock = cpl_strdup(s->read_clock);
00358
00359 fors_msg(level, "Readout clock pattern (%s) = %s",
00360 FORS_PFITS_READ_CLOCK, s->read_clock);
00361
00362
00363 s->chip_id = cpl_propertylist_get_string(header, FORS_PFITS_CHIP_ID);
00364 if (CPL_ERROR_TYPE_MISMATCH == cpl_error_get_code()) {
00365 cpl_msg_error(cpl_func,
00366 "Keyword %s is not a string",
00367 FORS_PFITS_CHIP_ID);
00368 }
00369 assure( !cpl_error_get_code(), return s,
00370 "Could not read %s from %s header",
00371 FORS_PFITS_CHIP_ID, filename);
00372
00373 s->chip_id = cpl_strdup(s->chip_id);
00374
00375
00376 fors_msg(level, "Chip ID (%s) = %s",
00377 FORS_PFITS_CHIP_ID, s->chip_id);
00378
00379 cpl_msg_indent_less();
00380
00381 cleanup;
00382 return s;
00383 }
00384
00385 #undef cleanup
00386 #define cleanup \
00387 do { \
00388 fors_setting_delete(&input_setting); \
00389 } while (0)
00390
00400 void
00401 fors_setting_verify(const fors_setting *ref_setting, const cpl_frame *frame,
00402 fors_setting **setting)
00403 {
00404 fors_setting *input_setting = NULL;
00405
00406 assure( ref_setting != NULL, return, NULL );
00407 assure( frame != NULL, return, NULL );
00408 assure( cpl_frame_get_filename(frame) != NULL, return, NULL );
00409
00410 input_setting = fors_setting_new_level(frame, CPL_MSG_DEBUG);
00411
00412 assure( !cpl_error_get_code(), return,
00413 "Could not get %s instrument setting",
00414 cpl_frame_get_filename(frame));
00415
00416
00417 if (ref_setting->binx != input_setting->binx ||
00418 ref_setting->biny != input_setting->biny) {
00419 cpl_msg_warning(cpl_func, "Incompatible CCD binning: %dx%d",
00420 input_setting->binx, input_setting->biny);
00421 }
00422
00423 if (ref_setting->filter_name != NULL &&
00424 input_setting->filter_name != NULL &&
00425 strcmp(ref_setting->filter_name, input_setting->filter_name) != 0) {
00426 cpl_msg_warning(cpl_func, "Incompatible filter names: '%s'",
00427 input_setting->filter_name);
00428 }
00429
00430 if ((ref_setting->prescan_x != input_setting->prescan_x &&
00431 input_setting->prescan_x != 0) ||
00432 (ref_setting->prescan_y != input_setting->prescan_y &&
00433 input_setting->prescan_y != 0)) {
00434 cpl_msg_warning(cpl_func, "Incompatible CCD x-prescan areas: %dx%d",
00435 input_setting->prescan_x,
00436 input_setting->prescan_y);
00437 }
00438
00439
00440
00441 if (fabs((ref_setting->average_gain - input_setting->average_gain) /
00442 ref_setting->average_gain) > 0.01) {
00443
00444 cpl_msg_warning(cpl_func, "Incompatible gain factor: %f e-/ADU",
00445 input_setting->average_gain);
00446 }
00447
00448
00449 if (fabs((ref_setting->ron - input_setting->ron) /
00450 ref_setting->ron) > 0.01) {
00451 cpl_msg_warning(cpl_func, "Incompatible read-out-noise: %f ADU",
00452 input_setting->ron);
00453 }
00454
00455 if (fabs((ref_setting->pixel_scale - input_setting->pixel_scale) /
00456 ref_setting->pixel_scale) > 0.01) {
00457 cpl_msg_warning(cpl_func, "Incompatible pixel scale: %f arcsec/pixel",
00458 input_setting->pixel_scale);
00459 }
00460
00461 if (strcmp(ref_setting->chip_id, input_setting->chip_id) != 0) {
00462 cpl_msg_warning(cpl_func, "Incompatible chip ID: '%s'",
00463 input_setting->chip_id);
00464 }
00465
00466 if (strcmp(ref_setting->read_clock, input_setting->read_clock) != 0) {
00467 cpl_msg_warning(cpl_func, "Incompatible readout clock pattern: '%s'",
00468 input_setting->read_clock);
00469 }
00470
00471 if (strcmp(ref_setting->instrument, input_setting->instrument) != 0) {
00472 cpl_msg_warning(cpl_func, "Incompatible instrument name: '%s'",
00473 input_setting->instrument);
00474 }
00475
00476 if (strcmp(ref_setting->version, input_setting->version) != 0) {
00477 cpl_msg_warning(cpl_func, "Incompatible version: '%s'",
00478 input_setting->version);
00479 }
00480
00481
00482 if (setting != NULL) {
00483 *setting = input_setting;
00484 input_setting = NULL;
00485 }
00486
00487 cleanup;
00488 return;
00489
00490 }
00491
00492
00493
00498 void fors_setting_delete(fors_setting **s)
00499 {
00500 if (s && *s) {
00501 if ((*s)->filter_name != NULL) cpl_free((void *)((*s)->filter_name));
00502 cpl_free((void *)((*s)->read_clock));
00503 cpl_free((void *)((*s)->chip_id));
00504 cpl_free((void *)((*s)->version));
00505 cpl_free((void *)((*s)->instrument));
00506 cpl_free(*s); *s = NULL;
00507 }
00508 return;
00509 }
00510