39 #include "vircam_utils.h"
40 #include "vircam_mask.h"
41 #include "vircam_dfs.h"
42 #include "vircam_stats.h"
43 #include "vircam_pfits.h"
44 #include "vircam_paf.h"
48 static int vircam_detector_noise_create(cpl_plugin *) ;
49 static int vircam_detector_noise_exec(cpl_plugin *) ;
50 static int vircam_detector_noise_destroy(cpl_plugin *) ;
51 static int vircam_detector_noise(cpl_parameterlist *, cpl_frameset *) ;
52 static int vircam_detector_noise_save(cpl_frameset *framelist,
53 cpl_parameterlist *parlist);
54 static void vircam_detector_noise_init(
void);
55 static void vircam_detector_noise_tidy(
void);
72 } vircam_detector_noise_config ;
76 cpl_frameset *darklist;
77 cpl_frameset *domelist;
83 vir_mask *master_mask;
86 cpl_propertylist *phupaf;
89 static cpl_frame *product_frame = NULL;
93 #define BUZZ_OFF {vircam_detector_noise_tidy(); return(-1);}
95 static char vircam_detector_noise_description[] =
96 "vircam_detector_noise -- VIRCAM readnoise and gain recipe.\n\n"
97 "Measures the read noise and gain of a chip using two dome flat exposures\n"
98 "and two dark exposures. The flats should have the same illumination.\n"
99 "All four frames should have the same exposure time. If the SOF\n"
100 "contains more than two files of a given type, the others are ignored.\n\n"
101 "The program requires the following files in the SOF:\n\n"
103 " -----------------------------------------------------------------------\n"
104 " %-21s A list of two raw dark images\n"
105 " %-21s A list of two raw dome flat image\n"
106 " %-21s Optional master bad pixel map or\n"
107 " %-21s Optional master confidence map\n"
187 int cpl_plugin_get_info(cpl_pluginlist *list) {
188 cpl_recipe *recipe = cpl_calloc(1,
sizeof(*recipe));
189 cpl_plugin *plugin = &recipe->interface;
190 char alldesc[SZ_ALLDESC];
191 (void)snprintf(alldesc,SZ_ALLDESC,vircam_detector_noise_description,
192 VIRCAM_NOISE_DARK_RAW,VIRCAM_NOISE_FLAT_RAW,VIRCAM_CAL_BPM,
195 cpl_plugin_init(plugin,
197 VIRCAM_BINARY_VERSION,
198 CPL_PLUGIN_TYPE_RECIPE,
199 "vircam_detector_noise",
200 "VIRCAM recipe to determine readout noise and gain",
205 vircam_detector_noise_create,
206 vircam_detector_noise_exec,
207 vircam_detector_noise_destroy);
209 cpl_pluginlist_append(list,plugin);
226 static int vircam_detector_noise_create(cpl_plugin *plugin) {
232 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
233 recipe = (cpl_recipe *)plugin;
239 recipe->parameters = cpl_parameterlist_new();
243 p = cpl_parameter_new_value(
"vircam.vircam_detector_noise.thresh",
245 "Rejection threshold in sigma above background",
"vircam.vircam_detector_noise",5.0);
246 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,
"thresh");
247 cpl_parameterlist_append(recipe->parameters,p);
251 p = cpl_parameter_new_range(
"vircam.vircam_detector_noise.extenum",
253 "Extension number to be done, 0 == all",
254 "vircam.vircam_detector_noise",
256 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,
"ext");
257 cpl_parameterlist_append(recipe->parameters,p);
272 static int vircam_detector_noise_destroy(cpl_plugin *plugin) {
277 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
278 recipe = (cpl_recipe *)plugin;
282 cpl_parameterlist_delete(recipe->parameters);
294 static int vircam_detector_noise_exec(cpl_plugin *plugin) {
299 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
300 recipe = (cpl_recipe *)plugin;
304 return(vircam_detector_noise(recipe->parameters,recipe->frames));
316 static int vircam_detector_noise(cpl_parameterlist *parlist,
317 cpl_frameset *framelist) {
318 const char *fctid=
"vircam_detector_noise";
320 int j,jst,jfn,retval,nx,ny,live;
323 float meandark1,meandome1,meandark2,meandome2,sigdark,lcut,hcut;
324 float meandarkdiff,sigdarkdiff,counts;
325 float meandomediff,sigdomediff,gain,readnoise,exptime;
326 cpl_frame *dark1,*dark2,*dome1,*dome2;
327 cpl_propertylist *plist;
332 if (framelist == NULL || cpl_frameset_get_size(framelist) <= 0) {
333 cpl_msg_error(fctid,
"Input framelist NULL or has no input data");
340 cpl_msg_error(fctid,
"Input frameset is missing files. Check SOF");
346 vircam_detector_noise_init();
350 p = cpl_parameterlist_find(parlist,
"vircam.vircam_detector_noise.thresh");
351 vircam_detector_noise_config.thresh = (float)cpl_parameter_get_double(p);
352 p = cpl_parameterlist_find(parlist,
"vircam.vircam_detector_noise.extenum");
353 vircam_detector_noise_config.extenum = cpl_parameter_get_int(p);
358 cpl_msg_error(fctid,
"Cannot identify RAW and CALIB frames");
359 vircam_detector_noise_tidy();
367 cpl_msg_error(fctid,
"Cannot labelise the input frameset");
371 VIRCAM_NOISE_DARK_RAW)) == NULL) {
372 cpl_msg_error(fctid,
"Cannot find dark frames in input frameset");
375 if (cpl_frameset_get_size(ps.darklist) < 2) {
376 cpl_msg_error(fctid,
"Dark frameset doesn't have enough frames");
380 VIRCAM_NOISE_FLAT_RAW)) == NULL) {
381 cpl_msg_error(fctid,
"Cannot find dome flat frames in input frameset");
384 if (cpl_frameset_get_size(ps.domelist) < 2) {
385 cpl_msg_error(fctid,
"Dome flat frameset doesn't have enough frames");
396 dark1 = cpl_frameset_get_frame(ps.darklist,0);
397 dark2 = cpl_frameset_get_frame(ps.darklist,1);
398 dome1 = cpl_frameset_get_frame(ps.domelist,0);
399 dome2 = cpl_frameset_get_frame(ps.domelist,1);
404 ps.ph = cpl_propertylist_load(cpl_frame_get_filename(dome1),0);
410 (
const cpl_frame *)dark1,&jst,&jfn);
411 if (jst == -1 || jfn == -1) {
412 cpl_msg_error(fctid,
"Unable to continue");
413 vircam_detector_noise_tidy();
416 for (j = jst; j <= jfn; j++) {
417 cpl_msg_info(fctid,
"Beginning work on extension %" CPL_SIZE_FORMAT,
419 isfirst = (j == jst);
420 vircam_detector_noise_config.readnoise = 0.0;
421 vircam_detector_noise_config.gain = 0.0;
422 vircam_detector_noise_config.counts = 0.0;
423 vircam_detector_noise_config.lampflux = 0.0;
428 ps.darkim1 = cpl_image_load(cpl_frame_get_filename(dark1),
429 CPL_TYPE_FLOAT,0,(cpl_size)j);
430 ps.darkim2 = cpl_image_load(cpl_frame_get_filename(dark2),
431 CPL_TYPE_FLOAT,0,(cpl_size)j);
432 ps.domeim1 = cpl_image_load(cpl_frame_get_filename(dome1),
433 CPL_TYPE_FLOAT,0,(cpl_size)j);
434 ps.domeim2 = cpl_image_load(cpl_frame_get_filename(dome2),
435 CPL_TYPE_FLOAT,0,(cpl_size)j);
436 if (ps.darkim1 == NULL || ps.darkim2 == NULL || ps.domeim1 == NULL ||
437 ps.domeim2 == NULL) {
440 "NULL image input for extension %" CPL_SIZE_FORMAT,
442 retval = vircam_detector_noise_save(framelist,parlist);
443 freeimage(ps.darkim1);
444 freeimage(ps.darkim2);
445 freeimage(ps.domeim1);
446 freeimage(ps.domeim2);
452 ps.eh = cpl_propertylist_load(cpl_frame_get_filename(dome1),
457 plist = cpl_propertylist_load(cpl_frame_get_filename(dark1),
461 cpl_msg_warning(fctid,
"First dark image detector not live");
462 retval = vircam_detector_noise_save(framelist,parlist);
463 cpl_propertylist_delete(plist);
464 freeimage(ps.darkim1);
465 freeimage(ps.darkim2);
466 freeimage(ps.domeim1);
467 freeimage(ps.domeim2);
468 freepropertylist(ps.eh);
471 cpl_propertylist_delete(plist);
472 plist = cpl_propertylist_load(cpl_frame_get_filename(dark2),
476 cpl_msg_warning(fctid,
"Second dark image detector not live");
477 retval = vircam_detector_noise_save(framelist,parlist);
478 cpl_propertylist_delete(plist);
479 freeimage(ps.darkim1);
480 freeimage(ps.darkim2);
481 freeimage(ps.domeim1);
482 freeimage(ps.domeim2);
483 freepropertylist(ps.eh);
486 cpl_propertylist_delete(plist);
487 plist = cpl_propertylist_load(cpl_frame_get_filename(dome1),
491 cpl_msg_warning(fctid,
"First dome image detector not live");
492 retval = vircam_detector_noise_save(framelist,parlist);
493 cpl_propertylist_delete(plist);
494 freeimage(ps.darkim1);
495 freeimage(ps.darkim2);
496 freeimage(ps.domeim1);
497 freeimage(ps.domeim2);
498 freepropertylist(ps.eh);
501 cpl_propertylist_delete(plist);
502 plist = cpl_propertylist_load(cpl_frame_get_filename(dome2),
506 cpl_msg_warning(fctid,
"Second dome image detector not live");
507 retval = vircam_detector_noise_save(framelist,parlist);
508 cpl_propertylist_delete(plist);
509 freeimage(ps.darkim1);
510 freeimage(ps.darkim2);
511 freeimage(ps.domeim1);
512 freeimage(ps.domeim2);
513 freepropertylist(ps.eh);
516 cpl_propertylist_delete(plist);
520 nx = (int)cpl_image_get_size_x(ps.darkim1);
521 ny = (int)cpl_image_get_size_y(ps.darkim1);
522 nptsdark = (long)(nx*ny);
528 "Unable to load mask image %s[%" CPL_SIZE_FORMAT
"]",
530 cpl_msg_info(fctid,
"Forcing all pixels to be good from now on");
538 nptsdark,&meandark1,&sigdark);
540 lcut = meandark1 - vircam_detector_noise_config.thresh*sigdark;
541 hcut = meandark1 + vircam_detector_noise_config.thresh*sigdark;
543 nptsdark,lcut,hcut,&meandark1,&sigdark);
545 nptsdark,&meandome1,&sigdark);
547 lcut = meandome1 - vircam_detector_noise_config.thresh*sigdark;
548 hcut = meandome1 + vircam_detector_noise_config.thresh*sigdark;
550 nptsdark,lcut,hcut,&meandome1,&sigdark);
555 nptsdark,&meandark2,&sigdark);
557 lcut = meandark2 - vircam_detector_noise_config.thresh*sigdark;
558 hcut = meandark2 + vircam_detector_noise_config.thresh*sigdark;
560 nptsdark,lcut,hcut,&meandark2,&sigdark);
562 nptsdark,&meandome2,&sigdark);
564 lcut = meandome2 - vircam_detector_noise_config.thresh*sigdark;
565 hcut = meandome2 + vircam_detector_noise_config.thresh*sigdark;
567 nptsdark,lcut,hcut,&meandome2,&sigdark);
571 cpl_image_subtract(ps.darkim1,ps.darkim2);
572 cpl_image_subtract(ps.domeim1,ps.domeim2);
577 nptsdark,&meandarkdiff,&sigdarkdiff);
579 lcut = meandarkdiff - vircam_detector_noise_config.thresh*sigdarkdiff;
580 hcut = meandarkdiff + vircam_detector_noise_config.thresh*sigdarkdiff;
582 nptsdark,lcut,hcut,&meandarkdiff,&sigdarkdiff);
585 nptsdark,&meandomediff,&sigdomediff);
587 lcut = meandomediff - vircam_detector_noise_config.thresh*sigdomediff;
588 hcut = meandomediff + vircam_detector_noise_config.thresh*sigdomediff;
590 nptsdark,lcut,hcut,&meandomediff,&sigdomediff);
595 counts = (meandome1 + meandome2) - (meandark1 + meandark2);
596 vircam_detector_noise_config.counts = 0.5*counts;
597 vircam_detector_noise_config.lampflux = 0.5*counts/exptime;
598 gain = counts/(sigdomediff*sigdomediff - sigdarkdiff*sigdarkdiff);
599 vircam_detector_noise_config.gain = gain;
603 readnoise = gain*sigdarkdiff/sqrt(2.0);
604 vircam_detector_noise_config.readnoise = readnoise;
609 retval = vircam_detector_noise_save(framelist,parlist);
611 cpl_msg_error(fctid,
"Error saving results");
617 freeimage(ps.darkim1);
618 freeimage(ps.darkim2);
619 freeimage(ps.domeim1);
620 freeimage(ps.domeim2);
622 freepropertylist(ps.eh);
624 vircam_detector_noise_tidy();
637 static int vircam_detector_noise_save(cpl_frameset *framelist,
638 cpl_parameterlist *parlist) {
639 const char *fctid =
"vircam_detector_noise_save";
640 const char *outpaf =
"vircam_detector_noise";
641 const char *outfile =
"detector_noise.fits";
642 const char *recipeid =
"vircam_detector_noise";
643 cpl_propertylist *plist,*p;
652 product_frame = cpl_frame_new();
653 cpl_frame_set_filename(product_frame,outfile);
654 cpl_frame_set_tag(product_frame,VIRCAM_PRO_READGAINFILE);
655 cpl_frame_set_type(product_frame,CPL_FRAME_TYPE_IMAGE);
656 cpl_frame_set_group(product_frame,CPL_FRAME_GROUP_PRODUCT);
657 cpl_frame_set_level(product_frame,CPL_FRAME_LEVEL_FINAL);
661 plist = cpl_propertylist_duplicate(ps.ph);
662 ps.phupaf = vircam_paf_phu_items(plist);
664 parlist,(
char *)recipeid,
665 "PRO-1.15",ps.inherit,0);
666 vircam_paf_append(ps.phupaf,plist,
"ESO PRO CATG");
667 vircam_paf_append(ps.phupaf,plist,
"ESO INS FILT1 NAME");
671 if (cpl_image_save(NULL,outfile,CPL_TYPE_UCHAR,plist,
672 CPL_IO_DEFAULT) != CPL_ERROR_NONE) {
673 cpl_msg_error(fctid,
"Cannot save product PHU");
674 cpl_frame_delete(product_frame);
675 cpl_propertylist_delete(plist);
678 cpl_propertylist_delete(plist);
679 cpl_frameset_insert(framelist,product_frame);
684 plist = cpl_propertylist_duplicate(ps.eh);
688 cpl_propertylist_update_float(plist,
"ESO QC READNOISE",
689 vircam_detector_noise_config.readnoise);
690 cpl_propertylist_set_comment(plist,
"ESO QC READNOISE",
691 "[e-] Calculated detector readnoise");
692 cpl_propertylist_update_float(plist,
"ESO QC CONAD",
693 vircam_detector_noise_config.gain);
694 cpl_propertylist_set_comment(plist,
"ESO QC CONAD",
695 "[e-/ADU] Calculated detector gain");
696 cpl_propertylist_update_float(plist,
"ESO QC COUNTS",
697 vircam_detector_noise_config.counts);
698 cpl_propertylist_set_comment(plist,
"ESO QC COUNTS",
699 "[ADU] Dark corrected dome counts");
700 cpl_propertylist_update_float(plist,
"ESO QC LAMPFLUX",
701 vircam_detector_noise_config.lampflux);
702 cpl_propertylist_set_comment(plist,
"ESO QC LAMPFLUX",
703 "[ADU/sec] Dark corrected flux level");
708 parlist,(
char *)recipeid,
709 "PRO-1.15",ps.inherit);
715 o = cpl_table_new(1);
716 cpl_table_new_column(o,
"EXTNAME",CPL_TYPE_STRING);
717 cpl_table_new_column(o,
"READNOISE",CPL_TYPE_FLOAT);
718 cpl_table_new_column(o,
"GAIN",CPL_TYPE_FLOAT);
722 cpl_table_set_string(o,
"EXTNAME",0,
723 cpl_propertylist_get_string(plist,
"EXTNAME"));
724 cpl_table_set_float(o,
"READNOISE",0,
725 vircam_detector_noise_config.readnoise);
726 cpl_table_set_float(o,
"GAIN",0,vircam_detector_noise_config.gain);
730 if (cpl_table_save(o,NULL,plist,outfile,CPL_IO_EXTEND) != CPL_ERROR_NONE) {
731 cpl_msg_error(fctid,
"Cannot save product");
732 cpl_propertylist_delete(plist);
733 cpl_frame_delete(product_frame);
741 p = vircam_paf_req_items(plist);
743 if (vircam_paf_print((
char *)outpaf,
"VIRCAM/vircam_detector_noise",
744 "QC file",p) != VIR_OK)
745 cpl_msg_warning(fctid,
"Unable to write PAF");
746 cpl_propertylist_delete(p);
750 freepropertylist(plist);
760 static void vircam_detector_noise_init(
void) {
768 ps.master_mask = NULL;
782 static void vircam_detector_noise_tidy(
void) {
783 freespace(ps.labels);
784 freeframeset(ps.darklist);
785 freeframeset(ps.domelist);
786 freeimage(ps.darkim1);
787 freeimage(ps.darkim2);
788 freeimage(ps.domeim1);
789 freeimage(ps.domeim2);
790 freemask(ps.master_mask);
791 freepropertylist(ps.ph);
792 freepropertylist(ps.eh);
793 freepropertylist(ps.phupaf);