36 #include "omega_recipe.h"
63 static int omega_mbias_create(cpl_plugin *) ;
64 static int omega_mbias_exec(cpl_plugin *) ;
65 static int omega_mbias_destroy(cpl_plugin *) ;
66 static int omega_mbias(cpl_frameset *,cpl_parameterlist *) ;
72 static void omega_mbias_init(
void);
73 static void omega_mbias_tidy(
void);
99 const cpl_frame *rnframe;
100 cpl_frameset *biaslist;
102 omega_fits *firstbias;
103 cpl_propertylist *ph;
104 cpl_propertylist *eh;
117 #define RECIPE "omega_mbias"
136 cpl_recipe * recipe = cpl_calloc(1,
sizeof(*recipe)) ;
137 cpl_plugin * plugin = &recipe->interface ;
139 cpl_plugin_init(plugin,
141 OMEGA_BINARY_VERSION,
142 CPL_PLUGIN_TYPE_RECIPE,
144 "OMEGA - Create Master Bias for each chip.",
145 "Trims and applies overscan correction to the raw input bias \n"
146 "frames. Averages these frames to derive the master bias frame. \n"
147 "Calculates the image statistics on the resulting frame. Creates \n"
148 "the FITS header and saves it together with the FITS image.",
154 omega_mbias_destroy) ;
156 cpl_pluginlist_append(list, plugin) ;
171 static int omega_mbias_create(cpl_plugin * plugin)
177 if (cpl_error_get_code() != CPL_ERROR_NONE) {
178 cpl_msg_error(cpl_func,
"%s():%d: An error is already set: %s",
179 cpl_func, __LINE__, cpl_error_get_where());
180 return (
int)cpl_error_get_code();
183 if (plugin == NULL) {
184 cpl_msg_error(cpl_func,
"Null plugin");
185 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
189 if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
190 cpl_msg_error(cpl_func,
"Plugin is not a recipe");
191 cpl_ensure_code(0, (
int)CPL_ERROR_TYPE_MISMATCH);
195 recipe = (cpl_recipe *)plugin;
198 recipe->parameters = cpl_parameterlist_new() ;
199 if (recipe->parameters == NULL) {
200 cpl_msg_error(cpl_func,
"Parameter list allocation failed");
201 cpl_ensure_code(0, (
int)CPL_ERROR_ILLEGAL_OUTPUT);
205 p = cpl_parameter_new_value(
"omega.omega_mbias.ExtensionNumber",
207 "FITS extension number to load (1 to 32). (-1 = all)",
211 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ext") ;
212 cpl_parameterlist_append(recipe->parameters, p) ;
215 p = cpl_parameter_new_range(
"omega.omega_mbias.OverscanMethod",
217 "Overscan Correction Method",
220 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"oc-meth") ;
221 cpl_parameterlist_append(recipe->parameters, p) ;
223 p = cpl_parameter_new_value(
"omega.omega_mbias.PAF",
225 "Boolean value to create PAF files. 1(Yes), 0(No)",
229 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,
"paf") ;
230 cpl_parameterlist_append(recipe->parameters, p) ;
232 p = cpl_parameter_new_value(
"omega.omega_mbias.SigmaClip",
234 "Sigma Clipping Threshold for image",
238 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sig-clip") ;
239 cpl_parameterlist_append(recipe->parameters, p) ;
241 p = cpl_parameter_new_range(
"omega.omega_mbias.RejSigma",
243 "Rejection threshold for outlying pixels in Hot Pixels Map",
247 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,
"rej-sigma") ;
248 cpl_parameterlist_append(recipe->parameters, p) ;
262 static int omega_mbias_exec(cpl_plugin * plugin)
269 if (cpl_error_get_code() != CPL_ERROR_NONE) {
270 cpl_msg_error(cpl_func,
"%s():%d: An error is already set: %s",
271 cpl_func, __LINE__, cpl_error_get_where());
272 return (
int)cpl_error_get_code();
275 if (plugin == NULL) {
276 cpl_msg_error(cpl_func,
"Null plugin");
277 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
281 if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
282 cpl_msg_error(cpl_func,
"Plugin is not a recipe");
283 cpl_ensure_code(0, (
int)CPL_ERROR_TYPE_MISMATCH);
287 recipe = (cpl_recipe *)plugin;
290 if (recipe->parameters == NULL) {
291 cpl_msg_error(cpl_func,
"Recipe invoked with NULL parameter list");
292 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
294 if (recipe->frames == NULL) {
295 cpl_msg_error(cpl_func,
"Recipe invoked with NULL frame set");
296 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
300 recipe_status = omega_mbias(recipe->frames, recipe->parameters);
303 if (cpl_dfs_update_product_header(recipe->frames)) {
304 if (!recipe_status) recipe_status = (int)cpl_error_get_code();
308 return recipe_status;
318 static int omega_mbias_destroy(cpl_plugin * plugin)
322 if (plugin == NULL) {
323 cpl_msg_error(cpl_func,
"Null plugin");
324 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
328 if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
329 cpl_msg_error(cpl_func,
"Plugin is not a recipe");
330 cpl_ensure_code(0, (
int)CPL_ERROR_TYPE_MISMATCH);
334 recipe = (cpl_recipe *)plugin;
336 cpl_parameterlist_delete(recipe->parameters);
349 static int omega_mbias(cpl_frameset *
set, cpl_parameterlist *pars)
352 int j,jst,jfn,status;
356 char *outmbias = NULL;
358 const char *_id =
"omega_mbias";
361 cpl_frame *firstframe;
362 cpl_frame *prframe_mbias = NULL;
363 cpl_frame *prframe_hpm = NULL;
364 const cpl_frame *refframe = NULL;
365 cpl_propertylist *qclist;
366 cpl_propertylist *alist;
367 cpl_stats *diffstats = NULL;
373 cpl_msg_error (_id,
"Parameters list not found");
377 if (cpl_frameset_is_empty(
set) == 1) {
378 cpl_msg_error (_id,
"Frameset not found");
384 par = cpl_parameterlist_find(pars,
"omega.omega_mbias.ExtensionNumber") ;
385 omega_mbias_config.extnum = cpl_parameter_get_int(par) ;
387 par = cpl_parameterlist_find(pars,
"omega.omega_mbias.OverscanMethod") ;
388 omega_mbias_config.oc = cpl_parameter_get_int(par) ;
390 par = cpl_parameterlist_find(pars,
"omega.omega_mbias.SigmaClip") ;
391 omega_mbias_config.sigma = cpl_parameter_get_double(par) ;
393 par = cpl_parameterlist_find(pars,
"omega.omega_mbias.RejSigma") ;
394 omega_mbias_config.rejsig = cpl_parameter_get_double(par) ;
396 par = cpl_parameterlist_find(pars,
"omega.omega_mbias.PAF");
397 omega_mbias_config.paf = cpl_parameter_get_bool(par);
402 if (oc_dfs_set_groups(
set)) {
403 cpl_msg_error(_id,
"Cannot identify RAW and CALIB frames") ;
415 cpl_msg_error(_id,
"Cannot labelise the input frameset");
420 MBIAS_RAW)) == NULL) {
421 cpl_msg_error(_id,
"Cannot find bias frames in input frameset");
426 nbias = cpl_frameset_get_size(ps.biaslist);
428 cpl_msg_error(_id,
"Need at least 2 (%s) frames to run this recipe",MBIAS_RAW);
433 cpl_msg_info (_id,
"There are %d %s in frame set",nbias, MBIAS_RAW);
437 ps.rnframe = cpl_frameset_find_const(
set, OMEGA_CALIB_RDNOISE);
438 if (ps.rnframe == NULL) {
439 cpl_msg_info(_id,
"A Readnoise table is not present in frame set. Using header values");
442 cpl_msg_info(_id,
"Using %s %s",OMEGA_CALIB_RDNOISE, cpl_frame_get_filename(ps.rnframe));
446 firstframe = cpl_frameset_get_first(ps.biaslist);
449 refframe = cpl_frameset_find_const(
set, REFBIAS);
450 if (refframe != NULL)
451 cpl_msg_info(cpl_func,
"Using %s for comparison",cpl_frame_get_filename(refframe));
456 if(omega_mbias_config.extnum == 0){
457 cpl_msg_error(cpl_func,
"Unsupported extension request, %d",omega_mbias_config.extnum);
465 sprintf(INSTRUME,
"wfi");
468 omega_mbias_config.extnum == 0 && jfn == 32){
472 for (j = jst; j <= jfn; j++) {
474 isfirst = (j == jst);
475 cpl_msg_info(_id,
"Beginning work on extension %d",j);
476 omega_mbias_config.CountHotPixels = 0;
477 omega_mbias_config.Mean = 0.0;
478 omega_mbias_config.Median = 0.0;
479 omega_mbias_config.Stdev = 0.0;
487 cpl_msg_warning(_id,
"Image detector is not live");
489 freefits(ps.firstbias);
493 else if(status == -1){
494 cpl_msg_error(_id,
"Cannot combine images");
503 qclist = cpl_propertylist_new();
506 if(refframe != NULL){
508 cpl_msg_warning(cpl_func,
"Cannot compare with reference frame");
511 cpl_propertylist_append_double(qclist,
"ESO QC DIFF REFBIAS MEAN",
512 cpl_stats_get_mean(diffstats));
513 cpl_propertylist_set_comment(qclist,
"ESO QC DIFF REFBIAS MEAN",
514 "Mean of difference with reference");
515 cpl_propertylist_append_double(qclist,
"ESO QC DIFF REFBIAS MEDIAN",
516 cpl_stats_get_median(diffstats));
517 cpl_propertylist_set_comment(qclist,
"ESO QC DIFF REFBIAS MEDIAN",
518 "Median of difference with reference");
519 cpl_propertylist_append_double(qclist,
"ESO QC DIFF REFBIAS STDEV",
520 cpl_stats_get_stdev(diffstats));
521 cpl_propertylist_set_comment(qclist,
"ESO QC DIFF REFBIAS STDEV",
522 "Stdev of difference with reference");
524 freestats(diffstats);
530 cpl_propertylist_append_double(qclist,
"ESO QC MASTER BIAS MEAN",
531 omega_mbias_config.Mean) ;
532 cpl_propertylist_set_comment (qclist,
"ESO QC MASTER BIAS MEAN",
533 "Mean value of master bias");
535 cpl_propertylist_append_double(qclist,
"ESO QC MASTER BIAS MEDIAN",
536 omega_mbias_config.Median) ;
537 cpl_propertylist_set_comment (qclist,
"ESO QC MASTER BIAS MEDIAN",
538 "Median value of master bias");
540 cpl_propertylist_append_double(qclist,
"ESO QC MASTER BIAS STDEV",
541 omega_mbias_config.Stdev) ;
542 cpl_propertylist_set_comment (qclist,
"ESO QC MASTER BIAS STDEV",
543 "Standard Deviation of master bias");
546 outmbias = cpl_sprintf(
"%s_%s.fits", INSTRUME,MBIAS_PROCATG);
550 alist = cpl_propertylist_new();
551 cpl_propertylist_append_string(alist,
"EXTNAME",
552 cpl_propertylist_get_string(ps.eh,
"EXTNAME"));
553 cpl_propertylist_set_comment(alist,
"EXTNAME",
"Extension name");
556 cpl_propertylist_update_int(alist,
"ESO DRS OVERSCAN METHOD", omega_mbias_config.oc);
557 cpl_propertylist_set_comment(alist,
"ESO DRS OVERSCAN METHOD",
"overscan correction method");
559 cpl_propertylist_copy_property_regexp(alist, ps.eh, WCS_KEYS, 0);
562 if(
omega_save_image(ps.mbias,
set,pars,alist,qclist,CPL_BPP_IEEE_FLOAT,outmbias,
563 RECIPE,prframe_mbias,NULL,isfirst) == -1){
564 cpl_msg_error(_id,
"Cannot save product %s", MBIAS_PROCATG);
577 qclist = cpl_propertylist_new();
578 cpl_propertylist_append_int(qclist,
"ESO QC NUMBER HOT PIXELS",
579 omega_mbias_config.CountHotPixels);
580 cpl_propertylist_set_comment(qclist,
"ESO QC NUMBER HOT PIXELS",
581 "Number of hot pixels");
583 outhpm = cpl_sprintf(
"%s_%s.fits", INSTRUME,HPM_PROCATG);
587 if(
omega_save_image(ps.hpixels,
set,pars,alist,qclist,CPL_BPP_16_SIGNED,outhpm,
588 RECIPE,prframe_hpm,NULL,isfirst) == -1){
589 cpl_msg_error(_id,
"Cannot save product %s", HPM_PROCATG);
600 freeimage(ps.hpixels);
603 freefits(ps.firstbias);
628 int i, nbias, live, naxis1, naxis2;
629 double read_noise, threshold;
630 double cutoff = 200.0;
631 const char *_id =
"omega_mbias_combine";
633 const cpl_frame *biasfr;
634 cpl_image *trim_raw,*median_all,*dev,*good_int,*good_float;
635 cpl_image *sum_data,*sum_good,*image;
636 cpl_imagelist *ilist;
637 cpl_mask *good,*pixelmap;
641 nbias = cpl_frameset_get_size(ps.biaslist);
642 biasfr = cpl_frameset_get_first_const(ps.biaslist);
651 cpl_msg_info (_id,
"Doing trim and overscan correction on images");
653 for (i=0; i< nbias; i++){
656 if(trim_raw == NULL){
661 naxis1 = cpl_image_get_size_x (trim_raw);
662 naxis2 = cpl_image_get_size_y (trim_raw);
663 ilist = cpl_imagelist_new ();
666 cpl_imagelist_set (ilist, trim_raw, i);
668 biasfr = cpl_frameset_get_next_const(ps.biaslist);
675 cpl_msg_error(_id,
"Error in imagelist <%s>",cpl_error_get_message());
685 if(ps.rnframe != NULL){
686 rntable = cpl_table_load(cpl_frame_get_filename(ps.rnframe), xn, 0);
688 read_noise = cpl_table_get_double(rntable,
"READNOISE",0, NULL);
693 cpl_msg_warning(cpl_func,
"Cannot load READNOISE_ADU table. %s",cpl_error_get_message());
700 if (read_noise == 0.0){
701 cpl_msg_info(_id,
"Using default value for read noise");
705 cpl_msg_info(_id,
"Using read noise = %g", read_noise);
709 threshold = read_noise * omega_mbias_config.sigma;
710 cpl_msg_info (_id,
"Discarding outliers using threshold %g", threshold);
714 cpl_msg_info (_id,
"Computing the median of all images...");
715 median_all = cpl_imagelist_collapse_median_create (ilist);
717 if (median_all == NULL) {
718 cpl_msg_error (_id,
"Cannot take median of imagelist <%s>",cpl_error_get_message());
724 trim_raw = cpl_imagelist_get (ilist, 0);
725 dev = cpl_image_subtract_create(median_all, trim_raw);
727 good = cpl_mask_threshold_image_create(dev, -threshold, threshold);
730 good_int = cpl_image_new_from_mask(good) ;
732 good_float = cpl_image_cast(good_int, CPL_TYPE_FLOAT);
735 sum_data = cpl_image_multiply_create(trim_raw, good_float);
736 sum_good = cpl_image_duplicate(good_float);
738 freeimage(good_float);
741 for (i=1; i< nbias; i++){
743 trim_raw = cpl_imagelist_get(ilist, i);
747 dev = cpl_image_subtract_create(median_all, trim_raw);
750 cpl_msg_error(_id,
"Error in subtraction <%s>",cpl_error_get_function());
752 freeimage(median_all);
758 good = cpl_mask_threshold_image_create (dev, -threshold, threshold);
762 good_int = cpl_image_new_from_mask(good) ;
764 good_float = cpl_image_cast(good_int, CPL_TYPE_FLOAT);
767 image = cpl_image_multiply_create(trim_raw, good_float);
768 cpl_image_add(sum_data, image);
770 cpl_image_add(sum_good, good_float);
773 freeimage(good_float);
776 freeimage(median_all);
779 ps.mbias = cpl_image_divide_create(sum_data, sum_good);
781 if (ps.mbias == NULL) {
782 cpl_msg_error(_id,
"Cannot create product. Error in division");
792 ps.stats = cpl_stats_new_from_image(ps.mbias, CPL_STATS_ALL);
793 if(ps.stats != NULL) {
794 omega_mbias_config.Mean = cpl_stats_get_mean(ps.stats);
795 omega_mbias_config.Median = cpl_stats_get_median(ps.stats);
796 omega_mbias_config.Stdev = cpl_stats_get_stdev(ps.stats);
797 cutoff = omega_mbias_config.Mean + omega_mbias_config.rejsig * omega_mbias_config.Stdev;
798 cpl_msg_info(_id,
"Using cutoff %g for Hot Pixels Map creation", cutoff);
804 pixelmap = cpl_mask_threshold_image_create(ps.mbias, -1e20, cutoff);
807 cpl_mask_not(pixelmap);
808 omega_mbias_config.CountHotPixels = cpl_mask_count(pixelmap);
815 ps.hpixels = cpl_image_new_from_mask(pixelmap);
822 static void omega_mbias_init(
void) {
835 static void omega_mbias_tidy(
void) {
836 freespace(ps.labels);
837 freeframeset(ps.biaslist);
839 freeimage(ps.hpixels);
841 freefits(ps.firstbias);