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
00033
00034
00035
00036 #include "crires_recipe.h"
00037
00038 #include "crires_combine.h"
00039
00040
00041
00042
00043
00044 #define RECIPE_STRING "crires_win_flat"
00045
00046
00047
00048
00049
00050 static cpl_imagelist * crires_win_flat_reduce(cpl_frameset *, const char *,
00051 const char *) ;
00052 static cpl_imagelist * crires_win_flat_bpm(cpl_imagelist *, double,
00053 double, double) ;
00054 static int crires_win_flat_save(const cpl_imagelist *, const cpl_imagelist *,
00055 int, cpl_frameset *, const cpl_parameterlist *, cpl_frameset *) ;
00056 static int crires_win_flat_compare(const cpl_frame *, const cpl_frame *) ;
00057
00058 static char crires_win_flat_description[] =
00059 "crires_win_flat -- Flat-field recipe in Windowing mode\n"
00060 "The files listed in the Set Of Frames (sof-file) must be tagged:\n"
00061 "raw-file.fits "CRIRES_WIN_FLAT_RAW" or\n"
00062 "dark-file.fits "CRIRES_CALPRO_DARK" or\n"
00063 "detlin-file.fits "CRIRES_CALPRO_COEFFS_CUBE".\n" ;
00064
00065 CRIRES_RECIPE_DEFINE(crires_win_flat,
00066 CRIRES_PARAM_THRESHOLDS |
00067 CRIRES_PARAM_BPM_RATE |
00068 CRIRES_PARAM_REPLACE |
00069 CRIRES_PARAM_KAPPA_SIGCLIP |
00070 CRIRES_PARAM_COLLAPSE_METH,
00071 "Flatfield recipe in Windowing mode",
00072 crires_win_flat_description) ;
00073
00074
00075
00076
00077
00078 static struct {
00079
00080 double bpm_low ;
00081 double bpm_high ;
00082 double bpm_lines_ratio ;
00083 int replace_flag ;
00084 double kappa_sigclip ;
00085 crires_collapse_method coll_meth ;
00086
00087 int bpm_nb[CRIRES_NB_DETECTORS] ;
00088 double flat_mean[CRIRES_NB_DETECTORS] ;
00089 double flat_stdev[CRIRES_NB_DETECTORS] ;
00090 double flat_flux[CRIRES_NB_DETECTORS] ;
00091 double flat_master_rms[CRIRES_NB_DETECTORS] ;
00092 } crires_win_flat_config ;
00093
00094
00095
00096
00097
00098
00105
00106 static int crires_win_flat(
00107 cpl_frameset * frameset,
00108 const cpl_parameterlist * parlist)
00109 {
00110 const char * sval ;
00111 cpl_size * labels ;
00112 cpl_size nlabels ;
00113 cpl_frameset * rawframes ;
00114 const char * dark ;
00115 const char * detlin ;
00116 cpl_imagelist * flat ;
00117 cpl_frameset * flat_one ;
00118 cpl_imagelist * bpm ;
00119 int i ;
00120
00121
00122 rawframes = NULL ;
00123 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
00124 crires_win_flat_config.bpm_nb[i] = -1 ;
00125 crires_win_flat_config.flat_mean[i] = -1.0 ;
00126 crires_win_flat_config.flat_stdev[i] = -1.0 ;
00127 crires_win_flat_config.flat_flux[i] = -1.0 ;
00128 crires_win_flat_config.flat_master_rms[i] = -1.0 ;
00129 }
00130
00131
00132 sval = crires_parameterlist_get_string(parlist, RECIPE_STRING,
00133 CRIRES_PARAM_THRESHOLDS) ;
00134 if (sscanf(sval, "%lg,%lg",
00135 &crires_win_flat_config.bpm_low,
00136 &crires_win_flat_config.bpm_high)!=2) {
00137 return -1 ;
00138 }
00139 crires_win_flat_config.replace_flag = crires_parameterlist_get_bool(
00140 parlist, RECIPE_STRING, CRIRES_PARAM_REPLACE) ;
00141 crires_win_flat_config.bpm_lines_ratio = crires_parameterlist_get_double(
00142 parlist, RECIPE_STRING, CRIRES_PARAM_BPM_RATE) ;
00143 crires_win_flat_config.kappa_sigclip = crires_parameterlist_get_double(
00144 parlist, RECIPE_STRING, CRIRES_PARAM_KAPPA_SIGCLIP) ;
00145 sval = crires_parameterlist_get_string(parlist, RECIPE_STRING,
00146 CRIRES_PARAM_COLLAPSE_METH) ;
00147 if (!strcmp(sval, "avg"))
00148 crires_win_flat_config.coll_meth = CRIRES_COLLAPSE_AVG ;
00149 else if (!strcmp(sval, "med"))
00150 crires_win_flat_config.coll_meth = CRIRES_COLLAPSE_MED ;
00151 else if (!strcmp(sval, "sig"))
00152 crires_win_flat_config.coll_meth = CRIRES_COLLAPSE_SIG ;
00153 else {
00154 cpl_msg_error(__func__, "Invalid collapse method specified");
00155 return -1;
00156 }
00157
00158
00159 if (crires_dfs_set_groups(frameset, "crires_win_flat")) {
00160 cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
00161 return -1 ;
00162 }
00163
00164
00165 dark = crires_extract_filename(frameset, CRIRES_CALPRO_DARK_WIN) ;
00166 detlin = crires_extract_filename(frameset, CRIRES_CALPRO_COEFFS_CUBE) ;
00167
00168
00169 if ((rawframes = crires_extract_frameset(frameset,
00170 CRIRES_WIN_FLAT_RAW)) == NULL) {
00171 cpl_msg_error(__func__, "No raw frame in input") ;
00172 return -1 ;
00173 }
00174
00175
00176 if ((labels = cpl_frameset_labelise(rawframes, crires_win_flat_compare,
00177 &nlabels)) == NULL) {
00178 cpl_msg_error(__func__, "Cannot labelise input frames") ;
00179 cpl_frameset_delete(rawframes) ;
00180 return -1 ;
00181 }
00182
00183
00184 for (i=0 ; i<(int)nlabels ; i++) {
00185
00186 cpl_msg_info(__func__, "Reduce data set %d / %"CPL_SIZE_FORMAT,
00187 i+1, nlabels);
00188 cpl_msg_indent_more() ;
00189 flat_one = cpl_frameset_extract(rawframes, labels, (cpl_size)i) ;
00190 flat = crires_win_flat_reduce(flat_one, dark, detlin) ;
00191 cpl_msg_indent_less() ;
00192
00193
00194 cpl_msg_info(__func__, "Save the products") ;
00195 cpl_msg_indent_more() ;
00196 if (flat == NULL) {
00197 cpl_msg_warning(__func__, "Cannot reduce set nb %d", i+1) ;
00198 } else {
00199 if ((bpm = crires_win_flat_bpm(flat,
00200 crires_win_flat_config.bpm_low,
00201 crires_win_flat_config.bpm_high,
00202 crires_win_flat_config.bpm_lines_ratio)) == NULL) {
00203 cpl_msg_warning(__func__, "Cannot create bad pixels map") ;
00204 }
00205 crires_win_flat_save(flat, bpm, i+1, flat_one, parlist, frameset) ;
00206 cpl_imagelist_delete(flat) ;
00207 cpl_imagelist_delete(bpm) ;
00208 }
00209 cpl_msg_indent_less() ;
00210 cpl_frameset_delete(flat_one) ;
00211 }
00212 cpl_frameset_delete(rawframes) ;
00213 cpl_free(labels) ;
00214
00215
00216 if (cpl_error_get_code()) return -1 ;
00217 else return 0 ;
00218 }
00219
00220
00228
00229 static cpl_imagelist * crires_win_flat_reduce(
00230 cpl_frameset * flatframes,
00231 const char * dark,
00232 const char * detlin)
00233 {
00234 cpl_propertylist * plist ;
00235 cpl_frame * ref_frame ;
00236 const char * fname ;
00237 int nframes ;
00238 double dit_frame, dit_dark ;
00239 cpl_imagelist * in ;
00240 cpl_imagelist * out ;
00241 cpl_vector * medians ;
00242 double median ;
00243 cpl_image * ima[CRIRES_NB_DETECTORS] ;
00244 int offset_y, stripe_y, center_y ;
00245 int i, j, k ;
00246
00247
00248 if (flatframes == NULL) return NULL ;
00249
00250
00251 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
00252 ima[i] = NULL ;
00253 }
00254 nframes = cpl_frameset_get_size(flatframes) ;
00255
00256
00257 ref_frame = cpl_frameset_get_frame(flatframes, 0) ;
00258 fname = cpl_frame_get_filename(ref_frame) ;
00259 if ((plist=cpl_propertylist_load(fname, 0)) == NULL) {
00260 cpl_msg_error(__func__, "Getting header from RAW file");
00261 cpl_msg_indent_less() ;
00262 return NULL ;
00263 }
00264 dit_frame = crires_pfits_get_dit(plist) ;
00265 offset_y = crires_pfits_get_stripe_offsety(plist) ;
00266 center_y = crires_pfits_get_stripe_centery(plist) ;
00267 cpl_propertylist_delete(plist) ;
00268 if (cpl_error_get_code()) {
00269 cpl_msg_error(__func__,
00270 "Cannot get the DIT or STRIPE keywords from RAW file") ;
00271 cpl_msg_indent_less() ;
00272 return NULL ;
00273 }
00274 cpl_msg_info(__func__, "DIT value: %g sec.", dit_frame) ;
00275
00276
00277 if (dark != NULL) {
00278 cpl_msg_info(__func__, "Verify the dark DIT") ;
00279 cpl_msg_indent_more() ;
00280 if ((plist=cpl_propertylist_load(dark, 0)) == NULL) {
00281 cpl_msg_error(__func__, "Getting header from DARK");
00282 cpl_msg_indent_less() ;
00283 return NULL ;
00284 }
00285 dit_dark = crires_pfits_get_dit(plist) ;
00286 cpl_propertylist_delete(plist) ;
00287 if (cpl_error_get_code()) {
00288 cpl_msg_error(__func__, "Cannot get the DIT from DARK") ;
00289 cpl_msg_indent_less() ;
00290 return NULL ;
00291 }
00292 if (fabs(dit_dark-dit_frame) > 1e-5) {
00293 cpl_msg_error(__func__, "Mismatch RAW DIT (%g) / DARK DIT (%g)",
00294 dit_frame, dit_dark) ;
00295 cpl_msg_indent_less() ;
00296 return NULL ;
00297 }
00298 cpl_msg_indent_less() ;
00299
00300
00301 if (crire_stripe_keys_mismatch(fname, dark)) {
00302 cpl_msg_error(__func__,
00303 "Mismatch of STRIPE keys with the dark frame") ;
00304 return NULL ;
00305 }
00306 }
00307
00308
00309 for (i=1 ; i<CRIRES_NB_DETECTORS-1 ; i++) {
00310 cpl_msg_info(__func__, "Compute the MASTER FLAT for chip nb %d", i+1) ;
00311 cpl_msg_indent_more() ;
00312
00313
00314 in = crires_load_frameset(flatframes, CRIRES_ILLUM_FULL_DETECTOR,
00315 i+1, CPL_TYPE_FLOAT) ;
00316 stripe_y = (int)(cpl_image_get_size_y(cpl_imagelist_get(in, 0))/2.0) ;
00317
00318
00319 if (crires_calib_chip_list(in, CRIRES_ILLUM_FULL_DETECTOR, i+1,
00320 NULL, dark, NULL, detlin, dit_frame, center_y, offset_y,
00321 stripe_y)) {
00322 cpl_msg_error(__func__, "Cannot apply the calibrations") ;
00323 cpl_imagelist_delete(in) ;
00324 for (j=1 ; j<i ; j++)
00325 cpl_image_delete(ima[j]);
00326 return NULL ;
00327 }
00328
00329
00330 medians = cpl_vector_new(nframes) ;
00331
00332
00333 cpl_msg_info(__func__, "Normalise with the median") ;
00334 for (j=0 ; j<nframes ; j++) {
00335 median = cpl_image_get_median(cpl_imagelist_get(in, j)) ;
00336 if (cpl_error_get_code()) {
00337 cpl_msg_error(__func__, "Cannot compute the median") ;
00338 cpl_imagelist_delete(in) ;
00339 cpl_vector_delete(medians) ;
00340 for (k=1 ; k<i ; k++)
00341 cpl_image_delete(ima[k]);
00342 return NULL ;
00343 }
00344 cpl_vector_set(medians, j, median) ;
00345 if (fabs(median) > 1e-3)
00346 cpl_image_divide_scalar(cpl_imagelist_get(in, j), median) ;
00347 }
00348
00349
00350 crires_win_flat_config.flat_mean[i] = cpl_vector_get_mean(medians) ;
00351 if (cpl_vector_get_size(medians) > 1)
00352 crires_win_flat_config.flat_stdev[i]=cpl_vector_get_stdev(medians);
00353 else
00354 crires_win_flat_config.flat_stdev[i] = -1.0 ;
00355 crires_win_flat_config.flat_flux[i] =
00356 crires_win_flat_config.flat_mean[i] / dit_frame ;
00357
00358
00359 if ((ima[i] = crires_combine_collapse_imagelist(in, medians,
00360 crires_win_flat_config.kappa_sigclip,
00361 i+1,
00362 crires_win_flat_config.coll_meth)) == NULL) {
00363 cpl_msg_error(__func__, "Cannot average the flats") ;
00364 cpl_imagelist_delete(in) ;
00365 cpl_vector_delete(medians) ;
00366 for (j=1 ; j<i ; j++)
00367 cpl_image_delete(ima[j]);
00368 return NULL ;
00369 }
00370 cpl_vector_delete(medians) ;
00371 cpl_imagelist_delete(in) ;
00372
00373
00374 crires_win_flat_config.flat_master_rms[i] =
00375 cpl_image_get_stdev(ima[i]) ;
00376
00377 cpl_msg_indent_less() ;
00378 }
00379
00380
00381 if (ima[1] != NULL) {
00382 ima[0] = cpl_image_duplicate(ima[1]) ;
00383 cpl_image_multiply_scalar(ima[0], 0.0) ;
00384 ima[CRIRES_NB_DETECTORS-1] = cpl_image_duplicate(ima[0]) ;
00385 }
00386
00387
00388 out = cpl_imagelist_new() ;
00389 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++)
00390 cpl_imagelist_set(out, ima[i], i) ;
00391
00392 return out ;
00393 }
00394
00395
00404
00405 static cpl_imagelist * crires_win_flat_bpm(
00406 cpl_imagelist * flat,
00407 double low,
00408 double high,
00409 double bad_per_line_limit)
00410 {
00411 cpl_imagelist * bpm ;
00412 int nima ;
00413 cpl_image * bpm_cur ;
00414 cpl_mask * mask_cur ;
00415 cpl_binary * pmask_cur ;
00416 int nx, ny, cur_bp_nb ;
00417 int i, j, k ;
00418
00419
00420 if (flat == NULL) return NULL ;
00421
00422
00423 nima = cpl_imagelist_get_size(flat) ;
00424
00425
00426 bpm = cpl_imagelist_new() ;
00427
00428
00429 for (i=0 ; i<nima ; i++) {
00430
00431 if ((mask_cur = cpl_mask_threshold_image_create(
00432 cpl_imagelist_get(flat, i), low, high)) == NULL) {
00433 cpl_msg_error(__func__, "Cannot create bad pixels map") ;
00434 cpl_imagelist_delete(bpm) ;
00435 return NULL ;
00436 }
00437 cpl_mask_not(mask_cur) ;
00438
00439
00440
00441
00442
00443
00444
00445 nx = cpl_mask_get_size_x(mask_cur) ;
00446 ny = cpl_mask_get_size_y(mask_cur) ;
00447 pmask_cur = cpl_mask_get_data(mask_cur) ;
00448 for (j=0 ; j<ny ; j++) {
00449 cur_bp_nb = cpl_mask_count_window(mask_cur, 1, j+1, nx, j+1) ;
00450
00451 if (cur_bp_nb > bad_per_line_limit * nx) {
00452
00453 for (k=0 ; k<nx ; k++) {
00454 pmask_cur[k+j*nx] = CPL_BINARY_0 ;
00455 }
00456 }
00457 }
00458
00459
00460 bpm_cur = cpl_image_new_from_mask(mask_cur) ;
00461 crires_win_flat_config.bpm_nb[i] = cpl_mask_count(mask_cur) ;
00462 cpl_mask_delete(mask_cur) ;
00463 cpl_imagelist_set(bpm, bpm_cur, i) ;
00464
00465
00466 if (crires_win_flat_config.replace_flag) {
00467 cpl_image_threshold(cpl_imagelist_get(flat, i),
00468 low, high, 1.0, 1.0) ;
00469 }
00470 }
00471 return bpm ;
00472 }
00473
00474
00484
00485 static int crires_win_flat_save(
00486 const cpl_imagelist * flat,
00487 const cpl_imagelist * bpm,
00488 int set_nb,
00489 cpl_frameset * set,
00490 const cpl_parameterlist * parlist,
00491 cpl_frameset * set_tot)
00492 {
00493 cpl_propertylist ** qclists ;
00494 const cpl_frame * ref_frame ;
00495 char * filename ;
00496 cpl_propertylist * inputlist ;
00497 const char * recipe_name = "crires_win_flat" ;
00498 int i ;
00499
00500
00501 ref_frame = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW) ;
00502
00503
00504 qclists = cpl_malloc(CRIRES_NB_DETECTORS * sizeof(cpl_propertylist*)) ;
00505 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
00506 qclists[i] = cpl_propertylist_new() ;
00507 cpl_propertylist_append_int(qclists[i], "ESO QC NBBAD",
00508 crires_win_flat_config.bpm_nb[i]) ;
00509 cpl_propertylist_append_double(qclists[i], "ESO QC FLAT MEAN",
00510 crires_win_flat_config.flat_mean[i]) ;
00511 cpl_propertylist_append_double(qclists[i], "ESO QC FLAT STDEV",
00512 crires_win_flat_config.flat_stdev[i]) ;
00513 cpl_propertylist_append_double(qclists[i], "ESO QC FLAT FLUX",
00514 crires_win_flat_config.flat_flux[i]) ;
00515 cpl_propertylist_append_double(qclists[i], "ESO QC FLAT MASTER RMS",
00516 crires_win_flat_config.flat_master_rms[i]) ;
00517
00518
00519 inputlist = cpl_propertylist_load_regexp(
00520 cpl_frame_get_filename(ref_frame), i+1,
00521 CRIRES_HEADER_EXT_FORWARD, 0) ;
00522 cpl_propertylist_copy_property_regexp(qclists[i], inputlist,
00523 CRIRES_HEADER_EXT_FORWARD, 0) ;
00524 cpl_propertylist_delete(inputlist) ;
00525 }
00526
00527
00528 filename = cpl_sprintf("%s_set%02d.fits", recipe_name, set_nb) ;
00529 crires_image_save(set_tot,
00530 parlist,
00531 set,
00532 flat,
00533 recipe_name,
00534 CRIRES_CALPRO_FLAT_WIN,
00535 CRIRES_PROTYPE_FLAT,
00536 CRIRES_ILLUM_FULL_DETECTOR,
00537 NULL,
00538 (const cpl_propertylist**)qclists,
00539 PACKAGE "/" PACKAGE_VERSION,
00540 filename) ;
00541 cpl_free(filename) ;
00542
00543
00544 if (bpm != NULL) {
00545 filename = cpl_sprintf("%s_set%02d_bpm.fits", recipe_name, set_nb) ;
00546 crires_image_save(set_tot,
00547 parlist,
00548 set,
00549 bpm,
00550 recipe_name,
00551 CRIRES_CALPRO_BPM_WIN,
00552 CRIRES_PROTYPE_BPM,
00553 CRIRES_ILLUM_FULL_DETECTOR,
00554 NULL,
00555 (const cpl_propertylist**)qclists,
00556 PACKAGE "/" PACKAGE_VERSION,
00557 filename) ;
00558 cpl_free(filename) ;
00559 }
00560
00561
00562 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
00563 cpl_propertylist_delete(qclists[i]) ;
00564 }
00565 cpl_free(qclists) ;
00566 return 0;
00567 }
00568
00569
00576
00577 static int crires_win_flat_compare(
00578 const cpl_frame * frame1,
00579 const cpl_frame * frame2)
00580 {
00581 int comparison ;
00582 cpl_propertylist * plist1 ;
00583 cpl_propertylist * plist2 ;
00584 double dval1, dval2 ;
00585
00586
00587 if (frame1==NULL || frame2==NULL) return -1 ;
00588
00589
00590 if ((plist1=cpl_propertylist_load(cpl_frame_get_filename(frame1),0))==NULL){
00591 cpl_msg_error(__func__, "getting header from reference frame");
00592 return -1 ;
00593 }
00594 if ((plist2=cpl_propertylist_load(cpl_frame_get_filename(frame2),0))==NULL){
00595 cpl_msg_error(__func__, "getting header from reference frame");
00596 cpl_propertylist_delete(plist1) ;
00597 return -1 ;
00598 }
00599
00600
00601 if (cpl_error_get_code()) {
00602 cpl_propertylist_delete(plist1) ;
00603 cpl_propertylist_delete(plist2) ;
00604 return -1 ;
00605 }
00606
00607 comparison = 1 ;
00608
00609
00610 dval1 = crires_pfits_get_dit(plist1) ;
00611 dval2 = crires_pfits_get_dit(plist2) ;
00612 if (cpl_error_get_code()) {
00613 cpl_msg_error(__func__, "Cannot get the DIT");
00614 cpl_propertylist_delete(plist1) ;
00615 cpl_propertylist_delete(plist2) ;
00616 return -1 ;
00617 }
00618 if (fabs(dval1-dval2) > 1e-3) comparison = 0 ;
00619
00620
00621 dval1 = crires_pfits_get_refwlen(plist1) ;
00622 dval2 = crires_pfits_get_refwlen(plist2) ;
00623 if (cpl_error_get_code()) {
00624 cpl_msg_error(__func__, "Cannot get the reference wavelength");
00625 cpl_propertylist_delete(plist1) ;
00626 cpl_propertylist_delete(plist2) ;
00627 return -1 ;
00628 }
00629 if (fabs(dval1-dval2) > 1e-3) comparison = 0 ;
00630
00631
00632 dval1 = crires_pfits_get_bafflepos(plist1) ;
00633 dval2 = crires_pfits_get_bafflepos(plist2) ;
00634 if (cpl_error_get_code()) {
00635 cpl_msg_error(__func__, "Cannot get the baffle position");
00636 cpl_propertylist_delete(plist1) ;
00637 cpl_propertylist_delete(plist2) ;
00638 return -1 ;
00639 }
00640 if (fabs(dval1-dval2) > 1e-3) comparison = 0 ;
00641
00642 cpl_propertylist_delete(plist1) ;
00643 cpl_propertylist_delete(plist2) ;
00644 return comparison ;
00645 }
00646