39 #include <casu_utils.h>
40 #include <casu_mods.h>
41 #include <casu_mask.h>
42 #include <casu_stats.h>
44 #include "vircam_utils.h"
45 #include "vircam_dfs.h"
46 #include "vircam_pfits.h"
47 #include "vircam_paf.h"
51 static int vircam_detector_noise_create(cpl_plugin *) ;
52 static int vircam_detector_noise_exec(cpl_plugin *) ;
53 static int vircam_detector_noise_destroy(cpl_plugin *) ;
54 static int vircam_detector_noise(cpl_parameterlist *, cpl_frameset *) ;
55 static int vircam_detector_noise_save(cpl_frameset *framelist,
56 cpl_parameterlist *parlist);
57 static void vircam_detector_noise_init(
void);
58 static void vircam_detector_noise_tidy(
void);
75 } vircam_detector_noise_config ;
79 cpl_frameset *darklist;
80 cpl_frameset *domelist;
86 casu_mask *master_mask;
89 cpl_propertylist *phupaf;
92 static cpl_frame *product_frame = NULL;
96 #define BUZZ_OFF {vircam_detector_noise_tidy(); return(-1);}
98 static char vircam_detector_noise_description[] =
99 "vircam_detector_noise -- VIRCAM readnoise and gain recipe.\n\n"
100 "Measures the read noise and gain of a chip using two dome flat exposures\n"
101 "and two dark exposures. The flats should have the same illumination.\n"
102 "All four frames should have the same exposure time. If the SOF\n"
103 "contains more than two files of a given type, the others are ignored.\n\n"
104 "The program requires the following files in the SOF:\n\n"
106 " -----------------------------------------------------------------------\n"
107 " %-21s A list of two raw dark images\n"
108 " %-21s A list of two raw dome flat image\n"
109 " %-21s Optional master bad pixel map or\n"
110 " %-21s Optional master confidence map\n"
190 int cpl_plugin_get_info(cpl_pluginlist *list) {
191 cpl_recipe *recipe = cpl_calloc(1,
sizeof(*recipe));
192 cpl_plugin *plugin = &recipe->interface;
193 char alldesc[SZ_ALLDESC];
194 (void)snprintf(alldesc,SZ_ALLDESC,vircam_detector_noise_description,
195 VIRCAM_NOISE_DARK_RAW,VIRCAM_NOISE_FLAT_RAW,VIRCAM_CAL_BPM,
198 cpl_plugin_init(plugin,
200 VIRCAM_BINARY_VERSION,
201 CPL_PLUGIN_TYPE_RECIPE,
202 "vircam_detector_noise",
203 "VIRCAM recipe to determine readout noise and gain",
208 vircam_detector_noise_create,
209 vircam_detector_noise_exec,
210 vircam_detector_noise_destroy);
212 cpl_pluginlist_append(list,plugin);
229 static int vircam_detector_noise_create(cpl_plugin *plugin) {
235 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
236 recipe = (cpl_recipe *)plugin;
242 recipe->parameters = cpl_parameterlist_new();
246 p = cpl_parameter_new_value(
"vircam.vircam_detector_noise.thresh",
248 "Rejection threshold in sigma above background",
"vircam.vircam_detector_noise",5.0);
249 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,
"thresh");
250 cpl_parameterlist_append(recipe->parameters,p);
254 p = cpl_parameter_new_range(
"vircam.vircam_detector_noise.extenum",
256 "Extension number to be done, 0 == all",
257 "vircam.vircam_detector_noise",
259 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,
"ext");
260 cpl_parameterlist_append(recipe->parameters,p);
275 static int vircam_detector_noise_destroy(cpl_plugin *plugin) {
280 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
281 recipe = (cpl_recipe *)plugin;
285 cpl_parameterlist_delete(recipe->parameters);
297 static int vircam_detector_noise_exec(cpl_plugin *plugin) {
302 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
303 recipe = (cpl_recipe *)plugin;
307 return(vircam_detector_noise(recipe->parameters,recipe->frames));
319 static int vircam_detector_noise(cpl_parameterlist *parlist,
320 cpl_frameset *framelist) {
321 const char *fctid=
"vircam_detector_noise";
323 int j,jst,jfn,retval,nx,ny,live;
326 float meandark1,meandome1,meandark2,meandome2,sigdark,lcut,hcut;
327 float meandarkdiff,sigdarkdiff,counts;
328 float meandomediff,sigdomediff,gain,readnoise,exptime;
329 cpl_frame *dark1,*dark2,*dome1,*dome2;
330 cpl_propertylist *plist;
335 if (framelist == NULL || cpl_frameset_get_size(framelist) <= 0) {
336 cpl_msg_error(fctid,
"Input framelist NULL or has no input data");
342 vircam_detector_noise_init();
346 p = cpl_parameterlist_find(parlist,
"vircam.vircam_detector_noise.thresh");
347 vircam_detector_noise_config.thresh = (float)cpl_parameter_get_double(p);
348 p = cpl_parameterlist_find(parlist,
"vircam.vircam_detector_noise.extenum");
349 vircam_detector_noise_config.extenum = cpl_parameter_get_int(p);
354 cpl_msg_error(fctid,
"Cannot identify RAW and CALIB frames");
355 vircam_detector_noise_tidy();
363 cpl_msg_error(fctid,
"Cannot labelise the input frameset");
367 VIRCAM_NOISE_DARK_RAW)) == NULL) {
368 cpl_msg_error(fctid,
"Cannot find dark frames in input frameset");
371 if (cpl_frameset_get_size(ps.darklist) < 2) {
372 cpl_msg_error(fctid,
"Dark frameset doesn't have enough frames");
376 VIRCAM_NOISE_FLAT_RAW)) == NULL) {
377 cpl_msg_error(fctid,
"Cannot find dome flat frames in input frameset");
380 if (cpl_frameset_get_size(ps.domelist) < 2) {
381 cpl_msg_error(fctid,
"Dome flat frameset doesn't have enough frames");
393 dark1 = cpl_frameset_get_position(ps.darklist,0);
394 dark2 = cpl_frameset_get_position(ps.darklist,1);
395 dome1 = cpl_frameset_get_position(ps.domelist,0);
396 dome2 = cpl_frameset_get_position(ps.domelist,1);
401 ps.ph = cpl_propertylist_load(cpl_frame_get_filename(dome1),0);
407 (
const cpl_frame *)dark1,&jst,&jfn);
408 if (jst == -1 || jfn == -1) {
409 cpl_msg_error(fctid,
"Unable to continue");
410 vircam_detector_noise_tidy();
413 for (j = jst; j <= jfn; j++) {
414 cpl_msg_info(fctid,
"Beginning work on extension %" CPL_SIZE_FORMAT,
416 isfirst = (j == jst);
417 vircam_detector_noise_config.readnoise = 0.0;
418 vircam_detector_noise_config.gain = 0.0;
419 vircam_detector_noise_config.counts = 0.0;
420 vircam_detector_noise_config.lampflux = 0.0;
425 ps.darkim1 = cpl_image_load(cpl_frame_get_filename(dark1),
426 CPL_TYPE_FLOAT,0,(cpl_size)j);
427 ps.darkim2 = cpl_image_load(cpl_frame_get_filename(dark2),
428 CPL_TYPE_FLOAT,0,(cpl_size)j);
429 ps.domeim1 = cpl_image_load(cpl_frame_get_filename(dome1),
430 CPL_TYPE_FLOAT,0,(cpl_size)j);
431 ps.domeim2 = cpl_image_load(cpl_frame_get_filename(dome2),
432 CPL_TYPE_FLOAT,0,(cpl_size)j);
433 if (ps.darkim1 == NULL || ps.darkim2 == NULL || ps.domeim1 == NULL ||
434 ps.domeim2 == NULL) {
437 "NULL image input for extension %" CPL_SIZE_FORMAT,
439 retval = vircam_detector_noise_save(framelist,parlist);
440 freeimage(ps.darkim1);
441 freeimage(ps.darkim2);
442 freeimage(ps.domeim1);
443 freeimage(ps.domeim2);
449 ps.eh = cpl_propertylist_load(cpl_frame_get_filename(dome1),
454 plist = cpl_propertylist_load(cpl_frame_get_filename(dark1),
458 cpl_msg_warning(fctid,
"First dark image detector not live");
459 retval = vircam_detector_noise_save(framelist,parlist);
460 cpl_propertylist_delete(plist);
461 freeimage(ps.darkim1);
462 freeimage(ps.darkim2);
463 freeimage(ps.domeim1);
464 freeimage(ps.domeim2);
465 freepropertylist(ps.eh);
468 cpl_propertylist_delete(plist);
469 plist = cpl_propertylist_load(cpl_frame_get_filename(dark2),
473 cpl_msg_warning(fctid,
"Second dark image detector not live");
474 retval = vircam_detector_noise_save(framelist,parlist);
475 cpl_propertylist_delete(plist);
476 freeimage(ps.darkim1);
477 freeimage(ps.darkim2);
478 freeimage(ps.domeim1);
479 freeimage(ps.domeim2);
480 freepropertylist(ps.eh);
483 cpl_propertylist_delete(plist);
484 plist = cpl_propertylist_load(cpl_frame_get_filename(dome1),
488 cpl_msg_warning(fctid,
"First dome image detector not live");
489 retval = vircam_detector_noise_save(framelist,parlist);
490 cpl_propertylist_delete(plist);
491 freeimage(ps.darkim1);
492 freeimage(ps.darkim2);
493 freeimage(ps.domeim1);
494 freeimage(ps.domeim2);
495 freepropertylist(ps.eh);
498 cpl_propertylist_delete(plist);
499 plist = cpl_propertylist_load(cpl_frame_get_filename(dome2),
503 cpl_msg_warning(fctid,
"Second dome image detector not live");
504 retval = vircam_detector_noise_save(framelist,parlist);
505 cpl_propertylist_delete(plist);
506 freeimage(ps.darkim1);
507 freeimage(ps.darkim2);
508 freeimage(ps.domeim1);
509 freeimage(ps.domeim2);
510 freepropertylist(ps.eh);
513 cpl_propertylist_delete(plist);
517 nx = (int)cpl_image_get_size_x(ps.darkim1);
518 ny = (int)cpl_image_get_size_y(ps.darkim1);
519 nptsdark = (long)(nx*ny);
525 "Unable to load mask image %s[%" CPL_SIZE_FORMAT
"]",
527 cpl_msg_info(fctid,
"Forcing all pixels to be good from now on");
534 casu_medmad((
float *)cpl_image_get_data(ps.darkim1),bpm,
535 nptsdark,&meandark1,&sigdark);
537 lcut = meandark1 - vircam_detector_noise_config.thresh*sigdark;
538 hcut = meandark1 + vircam_detector_noise_config.thresh*sigdark;
540 nptsdark,lcut,hcut,&meandark1,&sigdark);
541 casu_medmad((
float *)cpl_image_get_data(ps.domeim1),bpm,
542 nptsdark,&meandome1,&sigdark);
544 lcut = meandome1 - vircam_detector_noise_config.thresh*sigdark;
545 hcut = meandome1 + vircam_detector_noise_config.thresh*sigdark;
547 nptsdark,lcut,hcut,&meandome1,&sigdark);
551 casu_medmad((
float *)cpl_image_get_data(ps.darkim2),bpm,
552 nptsdark,&meandark2,&sigdark);
554 lcut = meandark2 - vircam_detector_noise_config.thresh*sigdark;
555 hcut = meandark2 + vircam_detector_noise_config.thresh*sigdark;
557 nptsdark,lcut,hcut,&meandark2,&sigdark);
558 casu_medmad((
float *)cpl_image_get_data(ps.domeim2),bpm,
559 nptsdark,&meandome2,&sigdark);
561 lcut = meandome2 - vircam_detector_noise_config.thresh*sigdark;
562 hcut = meandome2 + vircam_detector_noise_config.thresh*sigdark;
564 nptsdark,lcut,hcut,&meandome2,&sigdark);
568 cpl_image_subtract(ps.darkim1,ps.darkim2);
569 cpl_image_subtract(ps.domeim1,ps.domeim2);
573 casu_medmad((
float *)cpl_image_get_data(ps.darkim1),bpm,
574 nptsdark,&meandarkdiff,&sigdarkdiff);
576 lcut = meandarkdiff - vircam_detector_noise_config.thresh*sigdarkdiff;
577 hcut = meandarkdiff + vircam_detector_noise_config.thresh*sigdarkdiff;
579 nptsdark,lcut,hcut,&meandarkdiff,&sigdarkdiff);
581 casu_medmad((
float *)cpl_image_get_data(ps.domeim1),bpm,
582 nptsdark,&meandomediff,&sigdomediff);
584 lcut = meandomediff - vircam_detector_noise_config.thresh*sigdomediff;
585 hcut = meandomediff + vircam_detector_noise_config.thresh*sigdomediff;
587 nptsdark,lcut,hcut,&meandomediff,&sigdomediff);
592 counts = (meandome1 + meandome2) - (meandark1 + meandark2);
593 vircam_detector_noise_config.counts = 0.5*counts;
594 vircam_detector_noise_config.lampflux = 0.5*counts/exptime;
595 gain = counts/(sigdomediff*sigdomediff - sigdarkdiff*sigdarkdiff);
596 vircam_detector_noise_config.gain = gain;
600 readnoise = gain*sigdarkdiff/sqrt(2.0);
601 vircam_detector_noise_config.readnoise = readnoise;
606 retval = vircam_detector_noise_save(framelist,parlist);
608 cpl_msg_error(fctid,
"Error saving results");
614 freeimage(ps.darkim1);
615 freeimage(ps.darkim2);
616 freeimage(ps.domeim1);
617 freeimage(ps.domeim2);
619 freepropertylist(ps.eh);
621 vircam_detector_noise_tidy();
634 static int vircam_detector_noise_save(cpl_frameset *framelist,
635 cpl_parameterlist *parlist) {
636 const char *fctid =
"vircam_detector_noise_save";
637 const char *outpaf =
"vircam_detector_noise";
638 const char *outfile =
"detector_noise.fits";
639 const char *recipeid =
"vircam_detector_noise";
640 cpl_propertylist *plist,*p;
649 product_frame = cpl_frame_new();
650 cpl_frame_set_filename(product_frame,outfile);
651 cpl_frame_set_tag(product_frame,VIRCAM_PRO_READGAINFILE);
652 cpl_frame_set_type(product_frame,CPL_FRAME_TYPE_IMAGE);
653 cpl_frame_set_group(product_frame,CPL_FRAME_GROUP_PRODUCT);
654 cpl_frame_set_level(product_frame,CPL_FRAME_LEVEL_FINAL);
658 plist = cpl_propertylist_duplicate(ps.ph);
659 ps.phupaf = vircam_paf_phu_items(plist);
661 parlist,(
char *)recipeid,
662 "PRO-1.15",ps.inherit,0);
663 vircam_paf_append(ps.phupaf,plist,
"ESO PRO CATG");
664 vircam_paf_append(ps.phupaf,plist,
"ESO INS FILT1 NAME");
668 if (cpl_image_save(NULL,outfile,CPL_TYPE_UCHAR,plist,
669 CPL_IO_DEFAULT) != CPL_ERROR_NONE) {
670 cpl_msg_error(fctid,
"Cannot save product PHU");
671 cpl_frame_delete(product_frame);
672 cpl_propertylist_delete(plist);
675 cpl_propertylist_delete(plist);
676 cpl_frameset_insert(framelist,product_frame);
681 plist = cpl_propertylist_duplicate(ps.eh);
685 cpl_propertylist_update_float(plist,
"ESO QC READNOISE",
686 vircam_detector_noise_config.readnoise);
687 cpl_propertylist_set_comment(plist,
"ESO QC READNOISE",
688 "[e-] Calculated detector readnoise");
689 cpl_propertylist_update_float(plist,
"ESO QC CONAD",
690 vircam_detector_noise_config.gain);
691 cpl_propertylist_set_comment(plist,
"ESO QC CONAD",
692 "[e-/ADU] Calculated detector gain");
693 cpl_propertylist_update_float(plist,
"ESO QC COUNTS",
694 vircam_detector_noise_config.counts);
695 cpl_propertylist_set_comment(plist,
"ESO QC COUNTS",
696 "[ADU] Dark corrected dome counts");
697 cpl_propertylist_update_float(plist,
"ESO QC LAMPFLUX",
698 vircam_detector_noise_config.lampflux);
699 cpl_propertylist_set_comment(plist,
"ESO QC LAMPFLUX",
700 "[ADU/sec] Dark corrected flux level");
705 parlist,(
char *)recipeid,
706 "PRO-1.15",ps.inherit);
712 o = cpl_table_new(1);
713 cpl_table_new_column(o,
"EXTNAME",CPL_TYPE_STRING);
714 cpl_table_new_column(o,
"READNOISE",CPL_TYPE_FLOAT);
715 cpl_table_new_column(o,
"GAIN",CPL_TYPE_FLOAT);
719 cpl_table_set_string(o,
"EXTNAME",0,
720 cpl_propertylist_get_string(plist,
"EXTNAME"));
721 cpl_table_set_float(o,
"READNOISE",0,
722 vircam_detector_noise_config.readnoise);
723 cpl_table_set_float(o,
"GAIN",0,vircam_detector_noise_config.gain);
727 if (cpl_table_save(o,NULL,plist,outfile,CPL_IO_EXTEND) != CPL_ERROR_NONE) {
728 cpl_msg_error(fctid,
"Cannot save product");
729 cpl_propertylist_delete(plist);
730 cpl_frame_delete(product_frame);
738 p = vircam_paf_req_items(plist);
740 if (vircam_paf_print((
char *)outpaf,
"VIRCAM/vircam_detector_noise",
741 "QC file",p) != CASU_OK)
742 cpl_msg_warning(fctid,
"Unable to write PAF");
743 cpl_propertylist_delete(p);
747 freepropertylist(plist);
757 static void vircam_detector_noise_init(
void) {
765 ps.master_mask = NULL;
779 static void vircam_detector_noise_tidy(
void) {
780 freespace(ps.labels);
781 freeframeset(ps.darklist);
782 freeframeset(ps.domelist);
783 freeimage(ps.darkim1);
784 freeimage(ps.darkim2);
785 freeimage(ps.domeim1);
786 freeimage(ps.domeim2);
787 freemask(ps.master_mask);
788 freepropertylist(ps.ph);
789 freepropertylist(ps.eh);
790 freepropertylist(ps.phupaf);
void casu_mask_force(casu_mask *m, int nx, int ny)
unsigned char * casu_mask_get_data(casu_mask *m)
const char * casu_mask_get_filename(casu_mask *m)
int casu_mask_load(casu_mask *m, int nexten, int nx, int ny)
casu_mask * casu_mask_define(cpl_frameset *framelist, cpl_size *labels, cpl_size nlab, const char *conftag, const char *bpmtag)
void casu_mask_clear(casu_mask *m)
void casu_medmad(float *data, unsigned char *bpm, long np, float *med, float *mad)
void casu_medmadcut(float *data, unsigned char *bpm, long np, float lcut, float hcut, float *med, float *mad)
int casu_compare_tags(const cpl_frame *frame1, const cpl_frame *frame2)
Compare input tags.
void casu_merge_propertylists(cpl_propertylist *p1, cpl_propertylist *p2)
Merge two propertylists.
void casu_dummy_property(cpl_propertylist *p)
Set dummy property keyword.
cpl_frameset * casu_frameset_subgroup(cpl_frameset *frameset, cpl_size *labels, cpl_size nlab, const char *tag)
Extract a frameset from another frameset.
int vircam_dfs_set_groups(cpl_frameset *set)
void vircam_dfs_set_product_primary_header(cpl_propertylist *plist, cpl_frame *frame, cpl_frameset *frameset, cpl_parameterlist *parlist, char *recipeid, const char *dict, cpl_frame *inherit, int synch)
void vircam_dfs_set_product_exten_header(cpl_propertylist *plist, cpl_frame *frame, cpl_frameset *frameset, cpl_parameterlist *parlist, char *recipeid, const char *dict, cpl_frame *inherit)
int vircam_pfits_get_detlive(const cpl_propertylist *plist, int *detlive)
Get the value of DET_LIVE.
int vircam_pfits_get_exptime(const cpl_propertylist *plist, float *exptime)
Get the value of exposure time.
const char * vircam_get_license(void)
void vircam_exten_range(int inexten, const cpl_frame *fr, int *out1, int *out2)