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 <string.h>
00037
00038 #include "naco_recipe.h"
00039 #include "irplib_flat.h"
00040
00041
00042
00043
00044
00045 #define RECIPE_STRING "naco_img_twflat"
00046
00047
00048
00049
00050
00051 static cpl_imagelist * naco_img_twflat_reduce(const irplib_framelist *,
00052 const irplib_framelist *);
00053
00054 static cpl_error_code naco_img_twflat_qc(cpl_propertylist *,
00055 const irplib_framelist *);
00056
00057 static cpl_error_code naco_img_twflat_save(cpl_frameset *,
00058 const cpl_parameterlist *,
00059 const cpl_propertylist *,
00060 const cpl_imagelist *,
00061 const cpl_image *, int,
00062 const irplib_framelist *);
00063
00064 static char * naco_img_twflat_make_tag(const cpl_frame*,
00065 const cpl_propertylist *, int);
00066
00067 static char * naco_img_twflat_make_dark_tag(const cpl_frame*,
00068 const cpl_propertylist *, int);
00069
00070 NACO_RECIPE_DEFINE(naco_img_twflat,
00071 NACO_PARAM_REJBORD |
00072 NACO_PARAM_BPMTHRES |
00073 NACO_PARAM_PROPFIT |
00074 NACO_PARAM_BPM |
00075 NACO_PARAM_ERRORMAP |
00076 NACO_PARAM_INTCEPT,
00077 "Twilight flat recipe",
00078 RECIPE_STRING " -- NACO imaging flat-field creation from "
00079 "twilight images.\n"
00080 "The files listed in the Set Of Frames (sof-file) must be tagged:\n"
00081 "raw-file.fits " NACO_IMG_TWFLAT_RAW " or\n"
00082 "raw-or-calib-file.fits " NACO_IMG_DARK_RAW "\n"
00083 "The flat frames are divided into groups, each group having identical "
00084 "instrument settings. Each group of flats is reduced independently of "
00085 "each other. For each group of flats, the set of frames shall contain "
00086 "either zero, one or n dark frames with the same instrument settings, "
00087 "where n is the number of flats in the group.");
00088
00089
00090
00091
00092
00093 static struct {
00094 int rej_left;
00095 int rej_right;
00096 int rej_bottom;
00097 int rej_top;
00098 double low_thresh;
00099 double high_thresh;
00100 int prop_flag;
00101 int bpm_flag;
00102 int errmap_flag;
00103 int intercept_flag;
00104 } naco_img_twflat_config;
00105
00106
00110
00111
00112
00113
00114
00115
00116
00123
00124 static int naco_img_twflat(cpl_frameset * framelist,
00125 const cpl_parameterlist * parlist)
00126 {
00127 cpl_errorstate cleanstate = cpl_errorstate_get();
00128 irplib_framelist * allframes = NULL;
00129 irplib_framelist * flatframes = NULL;
00130 irplib_framelist * darkframes = NULL;
00131 irplib_framelist * f_one = NULL;
00132 irplib_framelist * d_one = NULL;
00133 cpl_imagelist * twflat = NULL;
00134 cpl_image * bpm_im = NULL;
00135 cpl_mask * bpm = NULL;
00136 cpl_propertylist * qclist = cpl_propertylist_new();
00137 const char ** taglist = NULL;
00138 const char * sval;
00139 int nb_good = 0;
00140 int nsets;
00141 int i;
00142
00143
00144
00145 sval = naco_parameterlist_get_string(parlist, RECIPE_STRING,
00146 NACO_PARAM_REJBORD);
00147 skip_if (0);
00148 skip_if (sscanf(sval, "%d %d %d %d",
00149 &naco_img_twflat_config.rej_left,
00150 &naco_img_twflat_config.rej_right,
00151 &naco_img_twflat_config.rej_bottom,
00152 &naco_img_twflat_config.rej_top) != 4);
00153
00154
00155 sval = naco_parameterlist_get_string(parlist, RECIPE_STRING,
00156 NACO_PARAM_BPMTHRES);
00157 skip_if (0);
00158 skip_if (sscanf(sval, "%lg %lg",
00159 &naco_img_twflat_config.low_thresh,
00160 &naco_img_twflat_config.high_thresh) !=2 );
00161
00162 naco_img_twflat_config.prop_flag
00163 = naco_parameterlist_get_bool(parlist, RECIPE_STRING, NACO_PARAM_PROPFIT);
00164 skip_if (0);
00165
00166 naco_img_twflat_config.bpm_flag
00167 = naco_parameterlist_get_bool(parlist, RECIPE_STRING, NACO_PARAM_BPM);
00168 skip_if (0);
00169
00170 naco_img_twflat_config.errmap_flag
00171 = naco_parameterlist_get_bool(parlist, RECIPE_STRING, NACO_PARAM_ERRORMAP);
00172 skip_if (0);
00173
00174 naco_img_twflat_config.intercept_flag
00175 = naco_parameterlist_get_bool(parlist, RECIPE_STRING, NACO_PARAM_INTCEPT);
00176
00177
00178 skip_if (naco_dfs_set_groups(framelist));
00179
00180 allframes = irplib_framelist_cast(framelist);
00181 skip_if(allframes == NULL);
00182
00183 flatframes = irplib_framelist_extract(allframes, NACO_IMG_TWFLAT_RAW);
00184 skip_if(flatframes == NULL);
00185
00186 skip_if(irplib_framelist_load_propertylist_all(flatframes, 0, "^("
00187 IRPLIB_PFITS_REGEXP_RECAL "|"
00188 NACO_PFITS_REGEXP_TWFLAT
00189 ")$", CPL_FALSE));
00190
00191 darkframes = irplib_framelist_extract(allframes, NACO_IMG_DARK_RAW);
00192 irplib_framelist_empty(allframes);
00193
00194 if (darkframes == NULL) {
00195 naco_error_reset("The set of frames has no darks:");
00196 } else {
00197
00198 skip_if(0);
00199
00200 skip_if(irplib_framelist_load_propertylist_all(darkframes, 0, "^("
00201 NACO_PFITS_REGEXP_TWFLAT_DARK
00202 ")$", CPL_FALSE));
00203
00204 cpl_free(naco_framelist_set_tag(darkframes,
00205 naco_img_twflat_make_dark_tag,
00206 &nsets));
00207 skip_if(0);
00208 }
00209
00210 taglist = naco_framelist_set_tag(flatframes, naco_img_twflat_make_tag,
00211 &nsets);
00212 skip_if(taglist == NULL);
00213
00214 cpl_msg_info(cpl_func, "Identified %d setting(s) in %d flat frame(s)",
00215 nsets, irplib_framelist_get_size(flatframes));
00216
00217
00218 for (i=0 ; i < nsets ; i++) {
00219 int nflats;
00220
00221
00222 f_one = irplib_framelist_extract(flatframes, taglist[i]);
00223
00224 nflats = irplib_framelist_get_size(f_one);
00225
00226
00227 skip_if(irplib_framelist_set_tag_all(f_one, NACO_IMG_TWFLAT_RAW));
00228
00229 cpl_msg_info(cpl_func, "Reducing flat frame set %d of %d (size=%d) "
00230 "with setting: %s", i+1, nsets, nflats, taglist[i]);
00231
00232 if (darkframes != NULL) {
00233 const char * post_filter = strchr(taglist[i], ':');
00234
00235 bug_if(post_filter == NULL);
00236
00237
00238 d_one = irplib_framelist_extract(darkframes, 1+post_filter);
00239 if (d_one == NULL) {
00240 naco_error_reset("None of the darks match this setting:");
00241 } else {
00242
00243 bug_if (irplib_framelist_set_tag_all(d_one,
00244 NACO_IMG_DARK_RAW));
00245 }
00246 }
00247
00248 twflat = naco_img_twflat_reduce(f_one, d_one);
00249
00250 if (twflat == NULL) {
00251 if (nsets > 1)
00252 irplib_error_recover(cleanstate, "Could not reduce set %d:", i+1);
00253 } else {
00254 if (naco_img_twflat_config.bpm_flag) {
00255
00256 if ((bpm = cpl_mask_threshold_image_create(
00257 cpl_imagelist_get(twflat, 0),
00258 naco_img_twflat_config.low_thresh,
00259 naco_img_twflat_config.high_thresh)) == NULL) {
00260 cpl_msg_warning(cpl_func, "Could not create the bad pixel "
00261 "map: '%s' at %s", cpl_error_get_message(),
00262 cpl_error_get_where());
00263 cpl_error_reset();
00264 } else {
00265 skip_if(cpl_mask_not(bpm));
00266 bpm_im = cpl_image_new_from_mask(bpm);
00267 cpl_mask_delete(bpm);
00268 bpm = NULL;
00269 }
00270 }
00271
00272 cpl_msg_info(cpl_func, "Saving the products");
00273 if (d_one != NULL) {
00274
00275
00276 cpl_frame * frame = NULL;
00277 const cpl_boolean is_calib = irplib_framelist_get_size(d_one)
00278 == 1 ? CPL_TRUE : CPL_FALSE;
00279
00280 while (irplib_framelist_get_size(d_one) > 0) {
00281 frame = irplib_framelist_unset(d_one, 0, NULL);
00282
00283
00284 if (is_calib)
00285 bug_if(cpl_frame_set_group(frame,
00286 CPL_FRAME_GROUP_CALIB));
00287
00288 bug_if(irplib_framelist_set(f_one, frame, nflats++));
00289
00290 frame = NULL;
00291 }
00292 cpl_frame_delete(frame);
00293 bug_if(irplib_framelist_get_size(d_one) != 0);
00294 }
00295
00296 skip_if(naco_img_twflat_qc(qclist, f_one));
00297
00298 skip_if(naco_img_twflat_save(framelist, parlist, qclist,
00299 twflat, bpm_im, i+1, f_one));
00300 nb_good++;
00301 cpl_propertylist_empty(qclist);
00302 cpl_image_delete(bpm_im);
00303 cpl_imagelist_delete(twflat);
00304 bpm_im = NULL;
00305 twflat = NULL;
00306 }
00307
00308 irplib_framelist_delete(f_one);
00309 irplib_framelist_delete(d_one);
00310 f_one = NULL;
00311 d_one = NULL;
00312 }
00313
00314 irplib_ensure(nb_good > 0, CPL_ERROR_DATA_NOT_FOUND,
00315 "None of the %d sets could be reduced", nsets);
00316
00317 end_skip;
00318
00319 irplib_framelist_delete(allframes);
00320 irplib_framelist_delete(flatframes);
00321 irplib_framelist_delete(darkframes);
00322 irplib_framelist_delete(f_one);
00323 irplib_framelist_delete(d_one);
00324 cpl_mask_delete(bpm);
00325 cpl_image_delete(bpm_im);
00326 cpl_imagelist_delete(twflat);
00327 cpl_free(taglist);
00328 cpl_propertylist_delete(qclist);
00329
00330 return cpl_error_get_code();
00331 }
00332
00333
00345
00346 static cpl_imagelist * naco_img_twflat_reduce(const irplib_framelist * f_one,
00347 const irplib_framelist * d_one)
00348 {
00349 const cpl_propertylist * plist
00350 = irplib_framelist_get_propertylist_const(f_one, 0);
00351 const char * filter = naco_pfits_get_filter(plist);
00352 const char * tpl_id = naco_pfits_get_templateid(plist);
00353 const char * rom_name = naco_pfits_get_rom_name(plist);
00354 cpl_imagelist * i_one = NULL;
00355 cpl_image * dark = NULL;
00356 cpl_imagelist * results = NULL;
00357 cpl_stats * stats_img = NULL;
00358 cpl_image * flat;
00359 double min_count = DBL_MAX;
00360 double max_count = DBL_MAX;
00361 double norm;
00362 const double dit = naco_pfits_get_dit(plist);
00363 const int nflats = irplib_framelist_get_size(f_one);
00364 const int ndarks = d_one == NULL ? 0
00365 : irplib_framelist_get_size(d_one);
00366 int i;
00367 cpl_boolean ok_nonpositive;
00368
00369
00370 bug_if (0);
00371
00372 cpl_msg_info(cpl_func, "Filter: [%s]", filter);
00373 cpl_msg_info(cpl_func, "Read-out mode: [%s]", rom_name);
00374 cpl_msg_info(cpl_func, "DIT: [%g]", dit);
00375
00376 cpl_msg_info(cpl_func, "Reducing %d flats with subtraction of %d dark(s)",
00377 nflats, ndarks);
00378
00379 irplib_ensure(ndarks == 0 || ndarks == 1 || ndarks == nflats,
00380 CPL_ERROR_INCOMPATIBLE_INPUT,
00381 "Cannot reduce %d flats with %d darks", nflats, ndarks);
00382
00383 ok_nonpositive = strncmp(tpl_id, "NACO_img_cal_SkyFlats",
00384 IRPLIB_FITS_STRLEN) == 0 &&
00385 strncmp(rom_name, "Uncorr", IRPLIB_FITS_STRLEN) == 0
00386 ? CPL_TRUE : CPL_FALSE;
00387
00388
00389 cpl_msg_info(cpl_func, "---> Loading input set");
00390 irplib_check(i_one = irplib_imagelist_load_framelist(f_one, CPL_TYPE_FLOAT,
00391 0, 0),
00392 "Could not load the images of the flat frames");
00393
00394
00395 cpl_msg_info(cpl_func, "---> Computing stats");
00396 cpl_msg_info(cpl_func, "image min max med rms");
00397 cpl_msg_info(cpl_func, "---------------------------------------------");
00398 for (i = 0 ; i < nflats ; i++) {
00399 double curr_count;
00400
00401 flat = cpl_imagelist_get(i_one, i);
00402
00403 bug_if( flat == NULL);
00404
00405 stats_img = cpl_stats_new_from_image(flat, CPL_STATS_MIN
00406 | CPL_STATS_MAX
00407 | CPL_STATS_STDEV
00408 | CPL_STATS_MEDIAN);
00409
00410 bug_if (stats_img == NULL);
00411
00412 curr_count = cpl_stats_get_median(stats_img);
00413
00414 cpl_msg_info(cpl_func, "%02d %10.2f %10.2f %10.2f %10.2f", i+1,
00415 cpl_stats_get_min(stats_img), cpl_stats_get_max(stats_img),
00416 curr_count, cpl_stats_get_stdev(stats_img));
00417
00418 cpl_stats_delete(stats_img);
00419 stats_img = NULL;
00420
00421 if (i==0 || curr_count < min_count) min_count = curr_count;
00422 if (i==0 || curr_count > max_count) max_count = curr_count;
00423
00424
00425
00426 irplib_ensure (ok_nonpositive || curr_count > 0.0,
00427 CPL_ERROR_ILLEGAL_INPUT,
00428 "Flat %d has negative flux=%g using template=%s", i+1,
00429 curr_count, tpl_id);
00430
00431 if (ndarks == 0) continue;
00432
00433
00434
00435 if (i == 0 || ndarks > 1) {
00436 const cpl_frame * frame = irplib_framelist_get_const(d_one, i);
00437 const char * name = cpl_frame_get_filename(frame);
00438
00439 cpl_image_delete(dark);
00440 irplib_check(dark = cpl_image_load(name, CPL_TYPE_FLOAT, 0, 0),
00441 "Could not load FITS-image from %s", name);
00442 }
00443
00444 skip_if (cpl_image_subtract(flat, dark));
00445
00446 }
00447
00448 cpl_msg_info(cpl_func, "---------------------------------------------");
00449
00450 if (ndarks > 0) {
00451
00452 cpl_image_delete(dark);
00453 dark = NULL;
00454
00455
00456 cpl_msg_info(cpl_func, "Switching to proportional fit");
00457 naco_img_twflat_config.prop_flag = 1;
00458
00459 } else if (!naco_img_twflat_config.prop_flag) {
00460
00461 const double min_grad = 4.0;
00462
00463 if (fabs(max_count) < min_grad * fabs(min_count)) {
00464 const double grad = fabs(max_count/min_count);
00465
00466 cpl_msg_warning(cpl_func, "Low flux gradient: %g < %g", grad,
00467 min_grad);
00468 cpl_msg_warning(cpl_func,"A proportional fit may give better "
00469 "results (Requires either a single master dark "
00470 "frame or one dark per flat frame)");
00471 }
00472 }
00473
00474
00475 if (naco_img_twflat_config.prop_flag) {
00476 cpl_msg_info(cpl_func, "---> Fitting slopes proportionally");
00477 results = irplib_flat_fit_set(i_one, 0);
00478 irplib_ensure(results != NULL, CPL_ERROR_ILLEGAL_INPUT,
00479 "Could not create twilight flat-field with "
00480 "proportional fit");
00481 } else {
00482 cpl_msg_info(cpl_func, "---> Fitting slopes non-proportionally");
00483 results = irplib_flat_fit_set(i_one, 1);
00484 irplib_ensure(results != NULL, CPL_ERROR_ILLEGAL_INPUT,
00485 "Could not create twilight flat-field with "
00486 "non-proportional fit");
00487 }
00488 cpl_imagelist_delete(i_one);
00489 i_one = NULL;
00490
00491
00492 flat = cpl_imagelist_get(results, 0);
00493 bug_if( flat == NULL);
00494 irplib_check(norm =
00495 cpl_image_get_mean_window(flat,
00496 naco_img_twflat_config.rej_left+1,
00497 naco_img_twflat_config.rej_bottom+1,
00498 cpl_image_get_size_x(flat)
00499 -naco_img_twflat_config.rej_right,
00500 cpl_image_get_size_y(flat)
00501 -naco_img_twflat_config.rej_top);
00502 cpl_image_divide_scalar(flat, norm),
00503 "Could not normalize gain with norm=%g", norm);
00504
00505 end_skip;
00506
00507 cpl_imagelist_delete(i_one);
00508 cpl_stats_delete(stats_img);
00509 cpl_image_delete(dark);
00510
00511 if (cpl_error_get_code()) {
00512 cpl_imagelist_delete(results);
00513 results = NULL;
00514 }
00515
00516 return results;
00517 }
00518
00519
00520
00527
00528 static cpl_error_code naco_img_twflat_qc(cpl_propertylist * qclist,
00529 const irplib_framelist * rawframes)
00530 {
00531
00532 const cpl_propertylist * reflist
00533 = irplib_framelist_get_propertylist_const(rawframes, 0);
00534
00535
00536 bug_if (0);
00537
00538 bug_if (cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
00539 IRPLIB_PFITS_REGEXP_RECAL
00540 ")$", 0));
00541
00542 bug_if (irplib_pfits_set_airmass(qclist, rawframes));
00543
00544 end_skip;
00545
00546 return cpl_error_get_code();
00547 }
00548
00549
00561
00562 static cpl_error_code naco_img_twflat_save(cpl_frameset * set_tot,
00563 const cpl_parameterlist * parlist,
00564 const cpl_propertylist * qclist,
00565 const cpl_imagelist * flat,
00566 const cpl_image * bpm,
00567 int set_nb,
00568 const irplib_framelist * f_one)
00569 {
00570
00571 cpl_frameset * rawframes = irplib_frameset_cast(f_one);
00572 char * filename = NULL;
00573 const int nflats = cpl_imagelist_get_size(flat);
00574
00575
00576
00577 bug_if (nflats != 2 && nflats != 3);
00578
00579
00580 filename = cpl_sprintf(RECIPE_STRING "_set%02d" CPL_DFS_FITS, set_nb);
00581 skip_if (irplib_dfs_save_image(set_tot, parlist, rawframes,
00582 cpl_imagelist_get_const(flat, 0),
00583 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
00584 NACO_IMG_TWFLAT_RES, qclist, NULL, naco_pipe_id,
00585 filename));
00586
00587 if (bpm != NULL) {
00588
00589 cpl_free(filename);
00590 filename = cpl_sprintf(RECIPE_STRING "_set%02d_bpm" CPL_DFS_FITS,
00591 set_nb);
00592 skip_if (irplib_dfs_save_image(set_tot, parlist, rawframes, bpm,
00593 CPL_BPP_8_UNSIGNED, RECIPE_STRING,
00594 NACO_IMG_TWFLAT_BPM, qclist, NULL,
00595 naco_pipe_id, filename));
00596 }
00597
00598 if (naco_img_twflat_config.intercept_flag && nflats == 3) {
00599
00600 cpl_free(filename);
00601 filename = cpl_sprintf(RECIPE_STRING "_set%02d_inter"
00602 CPL_DFS_FITS, set_nb);
00603 skip_if (irplib_dfs_save_image(set_tot, parlist, rawframes,
00604 cpl_imagelist_get_const(flat, 1),
00605 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
00606 NACO_IMG_TWFLAT_INTER, qclist, NULL,
00607 naco_pipe_id, filename));
00608 }
00609
00610 if (naco_img_twflat_config.errmap_flag) {
00611
00612 cpl_free(filename);
00613 filename = cpl_sprintf(RECIPE_STRING "_set%02d_errmap"
00614 CPL_DFS_FITS, set_nb);
00615 skip_if (irplib_dfs_save_image(set_tot, parlist, rawframes,
00616 cpl_imagelist_get_const(flat, nflats - 1),
00617 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
00618 NACO_IMG_TWFLAT_ERRMAP, qclist, NULL,
00619 naco_pipe_id, filename));
00620 }
00621
00622 end_skip;
00623
00624 cpl_free(filename);
00625 cpl_frameset_delete(rawframes);
00626
00627 return cpl_error_get_code();
00628 }
00629
00630
00643
00644 static char * naco_img_twflat_make_tag(const cpl_frame* self,
00645 const cpl_propertylist* plist, int dummy)
00646 {
00647
00648 char * tag = NULL;
00649 const char * filter;
00650 const char * mode;
00651 const char * name;
00652 double dit;
00653
00654
00655 bug_if (cpl_error_get_code());
00656
00657 bug_if(self == NULL);
00658 bug_if(plist == NULL);
00659 bug_if(dummy < 0);
00660
00661
00662
00663 filter = naco_pfits_get_filter(plist);
00664 skip_if(cpl_error_get_code());
00665
00666
00667 name = naco_pfits_get_rom_name(plist);
00668 skip_if(cpl_error_get_code());
00669
00670
00671 mode = naco_pfits_get_mode(plist);
00672 skip_if(cpl_error_get_code());
00673
00674
00675 dit = naco_pfits_get_dit(plist);
00676 skip_if(cpl_error_get_code());
00677
00678 tag = cpl_sprintf("%s:%s:%s:%.5f", filter,
00679 name, mode, dit);
00680 bug_if(tag == NULL);
00681
00682 end_skip;
00683
00684 if (cpl_error_get_code()) {
00685 cpl_free(tag);
00686 tag = NULL;
00687 }
00688
00689 return tag;
00690
00691 }
00692
00693
00694
00706
00707 static char * naco_img_twflat_make_dark_tag(const cpl_frame * self,
00708 const cpl_propertylist * plist,
00709 int dummy)
00710 {
00711 char * tag = NULL;
00712 const char * mode;
00713 const char * name;
00714 double dit;
00715
00716
00717 bug_if (cpl_error_get_code());
00718
00719 bug_if(self == NULL);
00720 bug_if(plist == NULL);
00721 bug_if(dummy < 0);
00722
00723
00724
00725 name = naco_pfits_get_rom_name(plist);
00726 skip_if(cpl_error_get_code());
00727
00728
00729 mode = naco_pfits_get_mode(plist);
00730 skip_if(cpl_error_get_code());
00731
00732
00733 dit = naco_pfits_get_dit(plist);
00734 skip_if(cpl_error_get_code());
00735
00736 tag = cpl_sprintf("%s:%s:%.5f", name, mode, dit);
00737 bug_if(tag == NULL);
00738
00739 end_skip;
00740
00741 if (cpl_error_get_code()) {
00742 cpl_free(tag);
00743 tag = NULL;
00744 }
00745
00746 return tag;
00747
00748 }