38 #include "naco_recipe.h"
39 #include "irplib_flat.h"
45 #define RECIPE_STRING "naco_img_twflat"
51 static cpl_imagelist * naco_img_twflat_reduce(
const irplib_framelist *,
52 const irplib_framelist *);
54 static cpl_error_code naco_img_twflat_threshold(cpl_image *);
56 static cpl_error_code naco_img_twflat_qc(cpl_propertylist *,
57 const irplib_framelist *);
59 static cpl_error_code naco_img_twflat_save(cpl_frameset *,
60 const cpl_parameterlist *,
61 const cpl_propertylist *,
62 const cpl_imagelist *,
63 const cpl_image *,
int,
64 const irplib_framelist *);
66 static char * naco_img_twflat_make_tag(
const cpl_frame*,
67 const cpl_propertylist *,
int);
69 static char * naco_img_twflat_make_dark_tag(
const cpl_frame*,
70 const cpl_propertylist *,
int);
72 NACO_RECIPE_DEFINE(naco_img_twflat,
79 "Twilight flat recipe",
80 RECIPE_STRING
" -- NACO imaging flat-field creation from "
82 "The files listed in the Set Of Frames (sof-file) must be tagged:\n"
83 "raw-file.fits " NACO_IMG_TWFLAT_RAW
" or\n"
84 "raw-or-calib-file.fits " NACO_IMG_DARK_RAW
"\n"
85 "The flat frames are divided into groups, each group having identical "
86 "instrument settings. Each group of flats is reduced independently of "
87 "each other. For each group of flats, the set of frames shall contain "
88 "either zero, one or n dark frames with the same instrument settings, "
89 "where n is the number of flats in the group.");
106 } naco_img_twflat_config;
126 static int naco_img_twflat(cpl_frameset * framelist,
127 const cpl_parameterlist * parlist)
129 cpl_errorstate cleanstate = cpl_errorstate_get();
130 irplib_framelist * allframes = NULL;
131 irplib_framelist * flatframes = NULL;
132 irplib_framelist * darkframes = NULL;
133 irplib_framelist * f_one = NULL;
134 irplib_framelist * d_one = NULL;
135 cpl_imagelist * twflat = NULL;
136 cpl_image * bpm_im = NULL;
137 cpl_mask * bpm = NULL;
138 cpl_propertylist * qclist = cpl_propertylist_new();
139 const char ** taglist = NULL;
150 skip_if_ne(sscanf(sval,
"%d %d %d %d",
151 &naco_img_twflat_config.rej_left,
152 &naco_img_twflat_config.rej_right,
153 &naco_img_twflat_config.rej_bottom,
154 &naco_img_twflat_config.rej_top), 4,
155 "number(s) in string parameter (%s): \"%s\"",
156 CPL_XSTRINGIFY(NACO_PARAM_REJBORD), sval);
160 NACO_PARAM_BPMTHRES);
162 skip_if_ne(sscanf(sval,
"%lg %lg",
163 &naco_img_twflat_config.low_thresh,
164 &naco_img_twflat_config.high_thresh), 2,
165 "number(s) in string parameter (%s): \"%s\"",
166 CPL_XSTRINGIFY(NACO_PARAM_BPMTHRES), sval);
169 naco_img_twflat_config.prop_flag
173 naco_img_twflat_config.bpm_flag
177 naco_img_twflat_config.errmap_flag
181 naco_img_twflat_config.intercept_flag
187 allframes = irplib_framelist_cast(framelist);
188 skip_if(allframes == NULL);
190 flatframes = irplib_framelist_extract(allframes, NACO_IMG_TWFLAT_RAW);
191 skip_if(flatframes == NULL);
193 skip_if(irplib_framelist_load_propertylist_all(flatframes, 0,
"^("
194 IRPLIB_PFITS_REGEXP_RECAL
"|"
195 NACO_PFITS_REGEXP_TWFLAT
198 darkframes = irplib_framelist_extract(allframes, NACO_IMG_DARK_RAW);
199 irplib_framelist_empty(allframes);
201 if (darkframes == NULL) {
202 naco_error_reset(
"The set of frames has no darks:");
207 skip_if(irplib_framelist_load_propertylist_all(darkframes, 0,
"^("
208 NACO_PFITS_REGEXP_TWFLAT_DARK
212 naco_img_twflat_make_dark_tag,
219 skip_if(taglist == NULL);
221 cpl_msg_info(cpl_func,
"Identified %d setting(s) in %d flat frame(s)",
222 nsets, irplib_framelist_get_size(flatframes));
225 for (i=0 ; i < nsets ; i++) {
229 f_one = irplib_framelist_extract(flatframes, taglist[i]);
231 nflats = irplib_framelist_get_size(f_one);
234 skip_if(irplib_framelist_set_tag_all(f_one, NACO_IMG_TWFLAT_RAW));
236 cpl_msg_info(cpl_func,
"Reducing flat frame set %d of %d (size=%d) "
237 "with setting: %s", i+1, nsets, nflats, taglist[i]);
239 if (darkframes != NULL) {
240 const char * post_filter = strchr(taglist[i],
':');
242 bug_if(post_filter == NULL);
245 d_one = irplib_framelist_extract(darkframes, 1+post_filter);
247 naco_error_reset(
"None of the darks match this setting:");
250 bug_if (irplib_framelist_set_tag_all(d_one,
255 twflat = naco_img_twflat_reduce(f_one, d_one);
257 if (twflat == NULL) {
259 irplib_error_recover(cleanstate,
"Could not reduce set %d:", i+1);
261 if (naco_img_twflat_config.bpm_flag) {
263 if ((bpm = cpl_mask_threshold_image_create(
264 cpl_imagelist_get(twflat, 0),
265 naco_img_twflat_config.low_thresh,
266 naco_img_twflat_config.high_thresh)) == NULL) {
267 cpl_msg_warning(cpl_func,
"Could not create the bad pixel "
268 "map: '%s' at %s", cpl_error_get_message(),
269 cpl_error_get_where());
272 skip_if(cpl_mask_not(bpm));
273 bpm_im = cpl_image_new_from_mask(bpm);
274 cpl_mask_delete(bpm);
279 cpl_msg_info(cpl_func,
"Saving the products");
283 cpl_frame * frame = NULL;
284 const cpl_boolean is_calib = irplib_framelist_get_size(d_one)
285 == 1 ? CPL_TRUE : CPL_FALSE;
287 while (irplib_framelist_get_size(d_one) > 0) {
288 frame = irplib_framelist_unset(d_one, 0, NULL);
292 bug_if(cpl_frame_set_group(frame,
293 CPL_FRAME_GROUP_CALIB));
295 bug_if(irplib_framelist_set(f_one, frame, nflats++));
299 cpl_frame_delete(frame);
300 bug_if(irplib_framelist_get_size(d_one) != 0);
303 skip_if(naco_img_twflat_qc(qclist, f_one));
305 skip_if(naco_img_twflat_save(framelist, parlist, qclist,
306 twflat, bpm_im, i+1, f_one));
308 cpl_propertylist_empty(qclist);
309 cpl_image_delete(bpm_im);
310 cpl_imagelist_delete(twflat);
315 irplib_framelist_delete(f_one);
316 irplib_framelist_delete(d_one);
321 irplib_ensure(nb_good > 0, CPL_ERROR_DATA_NOT_FOUND,
322 "None of the %d sets could be reduced", nsets);
326 irplib_framelist_delete(allframes);
327 irplib_framelist_delete(flatframes);
328 irplib_framelist_delete(darkframes);
329 irplib_framelist_delete(f_one);
330 irplib_framelist_delete(d_one);
331 cpl_mask_delete(bpm);
332 cpl_image_delete(bpm_im);
333 cpl_imagelist_delete(twflat);
335 cpl_propertylist_delete(qclist);
337 return cpl_error_get_code();
353 static cpl_imagelist * naco_img_twflat_reduce(
const irplib_framelist * f_one,
354 const irplib_framelist * d_one)
356 const cpl_propertylist * plist
357 = irplib_framelist_get_propertylist_const(f_one, 0);
361 cpl_imagelist * i_one = NULL;
362 cpl_image * dark = NULL;
363 cpl_imagelist * results = NULL;
364 cpl_stats * stats_img = NULL;
366 double min_count = DBL_MAX;
367 double max_count = DBL_MAX;
370 const int nflats = irplib_framelist_get_size(f_one);
371 const int ndarks = d_one == NULL ? 0
372 : irplib_framelist_get_size(d_one);
374 cpl_boolean ok_nonpositive;
379 cpl_msg_info(cpl_func,
"Filter: [%s]", filter);
380 cpl_msg_info(cpl_func,
"Read-out mode: [%s]", rom_name);
381 cpl_msg_info(cpl_func,
"DIT: [%g]", dit);
383 cpl_msg_info(cpl_func,
"Reducing %d flats with subtraction of %d dark(s)",
386 irplib_ensure(ndarks == 0 || ndarks == 1 || ndarks == nflats,
387 CPL_ERROR_INCOMPATIBLE_INPUT,
388 "Cannot reduce %d flats with %d darks", nflats, ndarks);
390 ok_nonpositive = strncmp(tpl_id,
"NACO_img_cal_SkyFlats",
391 IRPLIB_FITS_STRLEN) == 0 &&
392 strncmp(rom_name,
"Uncorr", IRPLIB_FITS_STRLEN) == 0
393 ? CPL_TRUE : CPL_FALSE;
396 cpl_msg_info(cpl_func,
"---> Loading input set");
397 irplib_check(i_one = irplib_imagelist_load_framelist(f_one, CPL_TYPE_FLOAT,
399 "Could not load the images of the flat frames");
402 cpl_msg_info(cpl_func,
"---> Computing stats");
403 cpl_msg_info(cpl_func,
"image min max med rms");
404 cpl_msg_info(cpl_func,
"---------------------------------------------");
405 for (i = 0 ; i < nflats ; i++) {
408 flat = cpl_imagelist_get(i_one, i);
410 bug_if( flat == NULL);
412 stats_img = cpl_stats_new_from_image(flat, CPL_STATS_MIN
417 bug_if (stats_img == NULL);
419 curr_count = cpl_stats_get_median(stats_img);
421 cpl_msg_info(cpl_func,
"%02d %10.2f %10.2f %10.2f %10.2f", i+1,
422 cpl_stats_get_min(stats_img), cpl_stats_get_max(stats_img),
423 curr_count, cpl_stats_get_stdev(stats_img));
425 cpl_stats_delete(stats_img);
428 if (i==0 || curr_count < min_count) min_count = curr_count;
429 if (i==0 || curr_count > max_count) max_count = curr_count;
433 irplib_ensure (ok_nonpositive || curr_count > 0.0,
434 CPL_ERROR_ILLEGAL_INPUT,
435 "Flat %d has negative flux=%g using template=%s", i+1,
438 if (ndarks == 0)
continue;
442 if (i == 0 || ndarks > 1) {
443 const cpl_frame * frame = irplib_framelist_get_const(d_one, i);
444 const char * name = cpl_frame_get_filename(frame);
446 cpl_image_delete(dark);
447 irplib_check(dark = cpl_image_load(name, CPL_TYPE_FLOAT, 0, 0),
448 "Could not load FITS-image from %s", name);
451 skip_if (cpl_image_subtract(flat, dark));
455 cpl_msg_info(cpl_func,
"---------------------------------------------");
459 cpl_image_delete(dark);
463 cpl_msg_info(cpl_func,
"Switching to proportional fit");
464 naco_img_twflat_config.prop_flag = 1;
466 }
else if (!naco_img_twflat_config.prop_flag) {
468 const double min_grad = 4.0;
470 if (fabs(max_count) < min_grad * fabs(min_count)) {
471 const double grad = fabs(max_count/min_count);
473 cpl_msg_warning(cpl_func,
"Low flux gradient: %g < %g", grad,
475 cpl_msg_warning(cpl_func,
"A proportional fit may give better "
476 "results (Requires either a single master dark "
477 "frame or one dark per flat frame)");
482 if (naco_img_twflat_config.prop_flag) {
483 cpl_msg_info(cpl_func,
"---> Fitting slopes proportionally");
484 results = irplib_flat_fit_set(i_one, 0);
485 irplib_ensure(results != NULL, CPL_ERROR_ILLEGAL_INPUT,
486 "Could not create twilight flat-field with "
489 cpl_msg_info(cpl_func,
"---> Fitting slopes non-proportionally");
490 results = irplib_flat_fit_set(i_one, 1);
491 irplib_ensure(results != NULL, CPL_ERROR_ILLEGAL_INPUT,
492 "Could not create twilight flat-field with "
493 "non-proportional fit");
495 cpl_imagelist_delete(i_one);
499 flat = cpl_imagelist_get(results, 0);
500 bug_if( flat == NULL);
502 bug_if(naco_img_twflat_threshold(flat));
505 cpl_image_get_mean_window(flat,
506 naco_img_twflat_config.rej_left+1,
507 naco_img_twflat_config.rej_bottom+1,
508 cpl_image_get_size_x(flat)
509 -naco_img_twflat_config.rej_right,
510 cpl_image_get_size_y(flat)
511 -naco_img_twflat_config.rej_top);
512 cpl_image_divide_scalar(flat, norm),
513 "Could not normalize gain with norm=%g", norm);
517 cpl_imagelist_delete(i_one);
518 cpl_stats_delete(stats_img);
519 cpl_image_delete(dark);
521 if (cpl_error_get_code()) {
522 cpl_imagelist_delete(results);
537 static cpl_error_code naco_img_twflat_threshold(cpl_image *
self)
540 cpl_stats * fstats = cpl_stats_new_from_image(
self, CPL_STATS_MIN
543 if (cpl_stats_get_min(fstats) <= 0.0) {
544 cpl_mask * bpm = cpl_image_get_bpm(
self);
548 bug_if(cpl_mask_threshold_image(bpm,
self, 0.0, DBL_MAX, CPL_BINARY_0));
549 nbad = cpl_image_count_rejected(
self);
551 bug_if(cpl_image_fill_rejected(
self, 1.0));
553 cpl_msg_warning(cpl_func,
"Set %d pixel(s) with non-positive gain "
554 "(down to %g at (%d,%d)) to 1", (
int)nbad,
555 cpl_stats_get_min(fstats),
556 (
int)cpl_stats_get_min_x(fstats),
557 (
int)cpl_stats_get_min_y(fstats));
562 cpl_stats_delete(fstats);
564 return cpl_error_get_code();
576 static cpl_error_code naco_img_twflat_qc(cpl_propertylist * qclist,
577 const irplib_framelist * rawframes)
580 const cpl_propertylist * reflist
581 = irplib_framelist_get_propertylist_const(rawframes, 0);
586 bug_if (cpl_propertylist_copy_property_regexp(qclist, reflist,
"^("
587 IRPLIB_PFITS_REGEXP_RECAL
594 return cpl_error_get_code();
610 static cpl_error_code naco_img_twflat_save(cpl_frameset * set_tot,
611 const cpl_parameterlist * parlist,
612 const cpl_propertylist * qclist,
613 const cpl_imagelist * flat,
614 const cpl_image * bpm,
616 const irplib_framelist * f_one)
619 cpl_frameset * rawframes = irplib_frameset_cast(f_one);
620 char * filename = NULL;
621 const int nflats = cpl_imagelist_get_size(flat);
625 bug_if (nflats != 2 && nflats != 3);
628 filename = cpl_sprintf(RECIPE_STRING
"_set%02d" CPL_DFS_FITS, set_nb);
629 skip_if (irplib_dfs_save_image(set_tot, parlist, rawframes,
630 cpl_imagelist_get_const(flat, 0),
631 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
632 NACO_IMG_TWFLAT_RES, qclist, NULL, naco_pipe_id,
638 filename = cpl_sprintf(RECIPE_STRING
"_set%02d_bpm" CPL_DFS_FITS,
640 skip_if (irplib_dfs_save_image(set_tot, parlist, rawframes, bpm,
641 CPL_BPP_8_UNSIGNED, RECIPE_STRING,
642 NACO_IMG_TWFLAT_BPM, qclist, NULL,
643 naco_pipe_id, filename));
646 if (naco_img_twflat_config.intercept_flag && nflats == 3) {
649 filename = cpl_sprintf(RECIPE_STRING
"_set%02d_inter"
650 CPL_DFS_FITS, set_nb);
651 skip_if (irplib_dfs_save_image(set_tot, parlist, rawframes,
652 cpl_imagelist_get_const(flat, 1),
653 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
654 NACO_IMG_TWFLAT_INTER, qclist, NULL,
655 naco_pipe_id, filename));
658 if (naco_img_twflat_config.errmap_flag) {
661 filename = cpl_sprintf(RECIPE_STRING
"_set%02d_errmap"
662 CPL_DFS_FITS, set_nb);
663 skip_if (irplib_dfs_save_image(set_tot, parlist, rawframes,
664 cpl_imagelist_get_const(flat, nflats - 1),
665 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
666 NACO_IMG_TWFLAT_ERRMAP, qclist, NULL,
667 naco_pipe_id, filename));
673 cpl_frameset_delete(rawframes);
675 return cpl_error_get_code();
692 static char * naco_img_twflat_make_tag(
const cpl_frame*
self,
693 const cpl_propertylist* plist,
int dummy)
703 bug_if (cpl_error_get_code());
705 bug_if(
self == NULL);
706 bug_if(plist == NULL);
712 skip_if(cpl_error_get_code());
716 skip_if(cpl_error_get_code());
720 skip_if(cpl_error_get_code());
724 skip_if(cpl_error_get_code());
726 tag = cpl_sprintf(
"%s:%s:%s:%.5f", filter,
732 if (cpl_error_get_code()) {
755 static char * naco_img_twflat_make_dark_tag(
const cpl_frame *
self,
756 const cpl_propertylist * plist,
765 bug_if (cpl_error_get_code());
767 bug_if(
self == NULL);
768 bug_if(plist == NULL);
774 skip_if(cpl_error_get_code());
778 skip_if(cpl_error_get_code());
782 skip_if(cpl_error_get_code());
784 tag = cpl_sprintf(
"%s:%s:%.5f", name, mode, dit);
789 if (cpl_error_get_code()) {
cpl_error_code irplib_pfits_set_airmass(cpl_propertylist *self, const irplib_framelist *rawframes)
Update/Set the AIRMASS property.
int naco_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
const char * naco_parameterlist_get_string(const cpl_parameterlist *self, const char *recipe, naco_parameter bitmask)
Retrieve the value of a NACO string parameter.
cpl_boolean naco_parameterlist_get_bool(const cpl_parameterlist *self, const char *recipe, naco_parameter bitmask)
Retrieve the value of a NACO boolean parameter.
double naco_pfits_get_dit(const cpl_propertylist *self)
find out the DIT
const char * naco_pfits_get_mode(const cpl_propertylist *self)
find out the mode name
const char * naco_pfits_get_rom_name(const cpl_propertylist *self)
find out the read out mode name
const char * naco_pfits_get_templateid(const cpl_propertylist *self)
find out the template ID
const char * naco_pfits_get_filter(const cpl_propertylist *self)
find out the filter
const char ** naco_framelist_set_tag(irplib_framelist *self, char *(*pftag)(const cpl_frame *, const cpl_propertylist *, int), int *pntags)
Retag a framelist according to the given tagging function.