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