30#include <eris_ifu_strehl.h>
31#include <eris_ifu_jitter_interface.h>
32#include <eris_ifu_wavecal_static.h>
33#include <eris_utils.h>
34#include <eris_pfits.h>
35#include <eris_ifu_utils.h>
42#define ERIS_IFU_RAW_BPM "RAW_BPM"
43#define ERIS_IFU_RAW_ERROR "RAW_ERROR"
110#define HDRL_PARAMETER_HEAD void * base
118} hdrl_rect_region_parameter;
137static cpl_error_code eris_ifu_propertylist_save(
138 const char * procatg,
139 const char * filename,
140 const cpl_propertylist * header,
141 const cpl_parameterlist * parlist,
142 cpl_frameset * frameset)
145 cpl_propertylist * applist = cpl_propertylist_new();
148 cpl_propertylist_update_string(applist, CPL_DFS_PRO_CATG, procatg);
150 cpl_dfs_save_propertylist(frameset, NULL, parlist, frameset, NULL,
151 "ERIS_IFU_STREHL", header, NULL, PACKAGE
"/" PACKAGE_VERSION,
153 cpl_propertylist_delete(applist);
155 return cpl_error_get_code();
186 hdrl_parameter * rect_region,
190 hdrl_rect_region_parameter * rr_loc =
191 (hdrl_rect_region_parameter *)rect_region ;
193 cpl_error_ensure(rect_region != 0, CPL_ERROR_NULL_INPUT,
194 return CPL_ERROR_NULL_INPUT,
"region input must not be NULL");
196 CPL_ERROR_ILLEGAL_INPUT,
return CPL_ERROR_ILLEGAL_INPUT,
197 "Expected Rect Region parameter") ;
199 if (nx > 0 && rr_loc->llx < 1) rr_loc->llx += nx;
200 if (ny > 0 && rr_loc->lly < 1) rr_loc->lly += ny;
201 if (nx > 0 && rr_loc->urx < 1) rr_loc->urx += nx;
202 if (ny > 0 && rr_loc->ury < 1) rr_loc->ury += ny;
241eris_ifu_detector_shotnoise_model(
const cpl_image* ima_data,
const double gain,
242 const double ron, cpl_image ** ima_errs)
244 cpl_ensure_code(ima_data, CPL_ERROR_NULL_INPUT);
245 cpl_ensure_code(ima_errs, CPL_ERROR_NULL_INPUT);
246 cpl_ensure_code(gain > 0., CPL_ERROR_ILLEGAL_INPUT);
247 cpl_ensure_code(ron > 0., CPL_ERROR_ILLEGAL_INPUT);
249 *ima_errs = cpl_image_duplicate(ima_data);
251 cpl_image_threshold(*ima_errs, 0., INFINITY, ron, ron);
255 cpl_image_divide_scalar(*ima_errs, gain);
256 cpl_image_add_scalar(*ima_errs, ron * ron);
257 cpl_image_power(*ima_errs, 0.5);
259 return cpl_error_get_code();
281eris_ifu_fix_neg_region(
const cpl_frame * frm, cpl_size extnum,
282 hdrl_parameter * par)
284 cpl_propertylist * plist =
285 cpl_propertylist_load(cpl_frame_get_filename(frm), extnum);
287 return cpl_error_get_code();
292 cpl_propertylist_delete(plist);
294 return cpl_error_get_code();
314static cpl_image * eris_ifu_image_mef_load_region(
317 hdrl_parameter * region_params)
319 cpl_image * out = NULL ;
321 if (region_params == NULL) {
322 out = cpl_image_load(cpl_frame_get_filename(frm),
323 CPL_TYPE_DOUBLE, 0, eidx);
325 eris_ifu_fix_neg_region(frm, eidx, region_params);
326 out = cpl_image_load_window(cpl_frame_get_filename(frm),
327 CPL_TYPE_DOUBLE, 0, eidx,
374static cpl_error_code eris_ifu_hdrl_image_load(
378 cpl_size ext_num_err,
380 cpl_size ext_num_bpm,
381 hdrl_parameter * region_params,
384 hdrl_image ** out_hdrl_ima)
389 cpl_ensure_code(in, CPL_ERROR_NULL_INPUT);
390 cpl_ensure_code(out_hdrl_ima, CPL_ERROR_NULL_INPUT);
393 img = eris_ifu_image_mef_load_region(in, ext_num, region_params);
394 if (img == NULL)
return CPL_ERROR_ILLEGAL_INPUT ;
397 if (in_bpm != NULL) {
398 cpl_image * bpm = eris_ifu_image_mef_load_region(in_bpm, ext_num_bpm, region_params);
399 cpl_mask * bpm_mask = cpl_mask_threshold_image_create(bpm,
401 cpl_image_delete(bpm) ;
402 cpl_mask_not(bpm_mask) ;
403 cpl_image_reject_from_mask(img, bpm_mask);
404 cpl_mask_delete(bpm_mask) ;
408 cpl_image * err =NULL;
409 if (in_err != NULL) {
410 err = eris_ifu_image_mef_load_region(in_err, ext_num_err, region_params);
411 }
else if (ron < 0. && gain < 0.) {
416 eris_ifu_detector_shotnoise_model(img, gain, ron, &err);
423 cpl_image_delete(img);
424 cpl_image_delete(err);
426 return cpl_error_get_code();
503eris_ifu_strehl_compute(cpl_frameset * frameset,
const cpl_parameterlist * parlist,
504 const char* recipe_name)
510 hdrl_strehl_result res;
513 cpl_frame * err_frm ;
514 cpl_frame * bpm_frm ;
516 hdrl_parameter * region_params = NULL;
518 cpl_ensure_code(frameset, CPL_ERROR_NULL_INPUT);
519 cpl_ensure_code(parlist, CPL_ERROR_NULL_INPUT);
520 cpl_ensure_code(recipe_name, CPL_ERROR_NULL_INPUT);
523 return cpl_error_get_code();
551 return cpl_error_set_message(cpl_func, CPL_ERROR_UNSPECIFIED,
552 "Parsing of the strehl parameters failed");
567 if ((in_frm = cpl_frameset_find(frameset, ERIS_IFU_PRO_JITTER_CUBE))==NULL) {
570 return cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
577 const char* fname = cpl_frame_get_filename(in_frm);
578 cpl_image* in_ima = cpl_image_load(fname,CPL_TYPE_FLOAT, 0, 0);
579 sx = cpl_image_get_size_x(in_ima);
580 sy = cpl_image_get_size_y(in_ima);
583 cpl_propertylist* plist = cpl_propertylist_load(fname,0);
584 double ron = cpl_propertylist_get_double(plist,
"ESO DET CHIP RON");
585 double gain = cpl_propertylist_get_double(plist,
"ESO DET CHIP GAIN");
586 cpl_propertylist_delete(plist);
587 cpl_image_delete(in_ima);
590 if (eris_ifu_hdrl_image_load(in_frm, extnum_raw, err_frm, extnum_err,
591 bpm_frm, extnum_bpm, region_params, ron, gain,
592 &hima) != CPL_ERROR_NONE) {
595 return cpl_error_set_message(cpl_func, CPL_ERROR_FILE_NOT_FOUND,
596 "Cannot load RAW image");
616 cpl_msg_info(cpl_func,
"Handles NANs");
621 cpl_msg_info(cpl_func,
"strehl=%g+-%g", res.strehl_value.data,
622 res.strehl_value.error);
624 cpl_msg_info(cpl_func,
"star peak at %g/%g: %g +- %g", res.star_x,
625 res.star_y, res.star_peak.data, res.star_peak.error);
626 cpl_msg_info(cpl_func,
"star flux %g+-%g", res.star_flux.data,
627 res.star_flux.error);
628 cpl_msg_info(cpl_func,
"median estimated background=%g+-%g "
629 "(computed error %g)",
630 res.star_background.data, res.star_background.error,
631 res.computed_background_error);
632 cpl_propertylist* header=cpl_propertylist_new();
633 cpl_propertylist_update_double(header,
"ESO QC STREHL",
634 res.strehl_value.data);
635 cpl_propertylist_update_double(header,
"ESO QC STREHL ERROR",
636 res.strehl_value.error);
637 cpl_propertylist_update_string(header, CPL_DFS_PRO_CATG,
"ERIS_IFU_STREHL");
639 eris_ifu_propertylist_save(
"ERIS_IFU_STREHL",
"eris_ifu_strehl.fits", header,
644 cpl_propertylist_delete(header);
648 return cpl_error_get_code();
737eris_ifu_stdstar_strehl_compute(cpl_frameset * frameset,
738 const cpl_parameterlist * parlist,
746 hdrl_strehl_result res;
748 cpl_frame * in_frm = NULL ;
749 cpl_frame * err_frm ;
750 cpl_frame * bpm_frm ;
752 hdrl_parameter * region_params = NULL;
753 char* param_name = NULL;
755 double wavelength = 0;
757 double pixel_scale_x = 0;
758 double pixel_scale_y = 0;
759 double flux_radius_pix = 1;
760 double bkg_radius_low = 1;
761 double bkg_radius_high = 1.5;
763 cpl_ensure_code(frameset,CPL_ERROR_NULL_INPUT);
764 cpl_ensure_code(parlist,CPL_ERROR_NULL_INPUT);
765 cpl_ensure_code(context,CPL_ERROR_NULL_INPUT);
767 param_name = cpl_sprintf(
"%s.strehl_flux_radius", context);
768 flux_radius_pix = cpl_parameter_get_double(
769 cpl_parameterlist_find_const(parlist, param_name));
770 cpl_free(param_name);
773 param_name = cpl_sprintf(
"%s.strehl_bkg-radius-low", context);
774 bkg_radius_low = cpl_parameter_get_double(
775 cpl_parameterlist_find_const(parlist, param_name));
776 cpl_free(param_name);
779 param_name = cpl_sprintf(
"%s.strehl_bkg-radius-high", context);
780 bkg_radius_high = cpl_parameter_get_double(
781 cpl_parameterlist_find_const(parlist, param_name));
782 cpl_free(param_name);
785 ifsBand band = UNDEFINED_BAND;
786 ifsPreopticsScale scale = UNDEFINED_SCALE;
787 ifsInstrument instrument = UNSET_INSTRUMENT;
792 pixel_scale_x = 0.250;
796 pixel_scale_x = 0.100;
800 pixel_scale_x = 0.025;
803 case UNDEFINED_SCALE:
804 pixel_scale_x = 0.025;
808 pixel_scale_x = 0.100;
811 eris_ifu_get_central_lambda(band, &wavelength);
813 pixel_scale_y = pixel_scale_x;
814 cpl_msg_info(cpl_func,
"pixel_scale: %g [arcsec]",pixel_scale_x);
818 cpl_frame* std_flux_frm;
821 std_frm = cpl_frameset_find(frameset, ERIS_IFU_PRO_JITTER_STD_CUBE_COADD_MEDIAN);
822 std_flux_frm = cpl_frameset_find(frameset, ERIS_IFU_PRO_JITTER_STD_FLUX_CUBE_COADD_MEDIAN);
823 psf_frm = cpl_frameset_find(frameset, ERIS_IFU_PRO_JITTER_PSF_CUBE_COADD_MEDIAN);
824 if ( (std_frm == NULL) && (psf_frm == NULL) && (std_flux_frm == NULL)) {
825 return cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
826 "Missing ERIS_IFU_PRO_JITTER_PSF_CUBE_COADD_MEDIAN file, Cannot compute Strehl,");
828 if(std_frm != NULL) {
830 }
else if(psf_frm != NULL) {
832 }
else if(std_flux_frm != NULL) {
833 in_frm = std_flux_frm;
837 cpl_propertylist* plist = cpl_propertylist_load(cpl_frame_get_filename(in_frm),0);
841 if(cpl_propertylist_has(plist,
"ESO QC FWHM MAJ")) {
842 fwhm_maj = cpl_propertylist_get_double(plist,
"ESO QC FWHM MAJ");
844 if(cpl_propertylist_has(plist,
"ESO QC FWHMX")) {
845 fwhm_maj = cpl_propertylist_get_double(plist,
"ESO QC FWHMX");
850 if(cpl_propertylist_has(plist,
"ESO QC FWHM MIN")) {
851 fwhm_min = cpl_propertylist_get_double(plist,
"ESO QC FWHM MIN");
853 if(cpl_propertylist_has(plist,
"ESO QC FWHMY")) {
854 fwhm_min = cpl_propertylist_get_double(plist,
"ESO QC FWHMY");
859 cpl_propertylist_delete(plist);
862 double fwhm_sup = (fwhm_maj > fwhm_min) ? fwhm_maj : fwhm_min;
863 if(flux_radius_pix == -1) {
864 cpl_msg_info(cpl_func,
"pipeline setting flux_radius_pix: 3 * PSF sigmas");
865 flux_radius_pix = 3. * fwhm_sup / CPL_MATH_FWHM_SIG;
867 cpl_msg_info(cpl_func,
"flux_radius_pix: %g",flux_radius_pix);
868 double flux_radius_arc = flux_radius_pix * pixel_scale_x;
870 if(bkg_radius_low == -1) {
871 cpl_msg_info(cpl_func,
"pipeline setting bkg_radius_low: 1.5 * flux_radius");
872 bkg_radius_low = 1.5 * flux_radius_arc;
874 bkg_radius_low *= pixel_scale_x;
877 if(bkg_radius_high == -1) {
878 cpl_msg_info(cpl_func,
"pipeline setting bkg_radius_high: 2.0 * flux_radius");
879 bkg_radius_high = 2.0 * flux_radius_arc;
881 bkg_radius_high *= pixel_scale_x;
884 cpl_msg_info(cpl_func,
"flux_radius: %g [arcsec] bkg_radius_low: %g [arcsec] bkg_radius_high: %g [arcsec]",
885 flux_radius_arc, bkg_radius_low,bkg_radius_high);
887 cpl_msg_info(cpl_func,
"flux_radius: %g [pix] bkg_radius_low: %g [pix] bkg_radius_high: %g [pix]",
888 flux_radius_arc / pixel_scale_x,bkg_radius_low / pixel_scale_x,bkg_radius_high / pixel_scale_x);
892 std_frm = cpl_frameset_find(frameset, ERIS_IFU_PRO_JITTER_STD_CUBE_MEAN);
893 psf_frm = cpl_frameset_find(frameset, ERIS_IFU_PRO_JITTER_PSF_CUBE_MEAN);
894 std_flux_frm = cpl_frameset_find(frameset, ERIS_IFU_PRO_JITTER_STD_FLUX_CUBE_MEAN);
895 if ( (std_frm == NULL) && (std_flux_frm == NULL) && (psf_frm == NULL) ) {
897 return cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
898 "Missing ERIS_IFU_PRO_JITTER_PSF_CUBE_MEAN file, Cannot compute Strehl,");
900 if(std_frm != NULL) {
902 }
else if(psf_frm != NULL) {
909 const char* fname = cpl_frame_get_filename(in_frm);
910 cpl_msg_info(cpl_func,
"strehl computed on: %s",fname);
911 cpl_image* in_ima = cpl_image_load(fname,CPL_TYPE_FLOAT, 0, 1);
913 sx = cpl_image_get_size_x(in_ima);
914 sy = cpl_image_get_size_y(in_ima);
918 plist = cpl_propertylist_load(fname,0);
919 double ron = cpl_propertylist_get_double(plist,
"ESO DET CHIP RON");
920 double gain = cpl_propertylist_get_double(plist,
"ESO DET CHIP GAIN");
923 cpl_image_delete(in_ima);
927 if (eris_ifu_hdrl_image_load(in_frm, extnum_raw, err_frm, extnum_err,
928 bpm_frm, extnum_bpm, region_params, ron, gain,
929 &hima) != CPL_ERROR_NONE) {
932 return cpl_error_set_message(cpl_func, CPL_ERROR_FILE_NOT_FOUND,
933 "Cannot load RAW image");
943 cpl_size margin_x = 4;
944 cpl_size margin_y = 4;
945 cpl_size llx = margin_x;
946 cpl_size lly = margin_y;
947 cpl_size urx = sx - margin_x;
948 cpl_size ury = sy - margin_y;
951 cpl_msg_info(cpl_func,
"Image max detected at cx: %lld, cy: %lld",cx, cy);
956 cpl_msg_info(cpl_func,
"check Strehl parameters");
961 res.strehl_value.data = 0;
962 res.strehl_value.error = 0;
964 cpl_msg_info(cpl_func,
"wavelength: %g M1: %g M2: %g",wavelength, M1_RADIUS,M2_RADIUS);
965 cpl_msg_info(cpl_func,
"flux_radius_pix: %g cx: %lld cy: %lld sx: %d sy:%d",flux_radius_pix, cx, cy, sx, sy);
968 if( (flux_radius_pix + cx) > (sx -2) ||
969 (flux_radius_pix + cy) > (sy -2) ||
970 (cx-flux_radius_pix) < 2 ||
971 (cy-flux_radius_pix) < 2){
973 cpl_msg_info(cpl_func,
"correct Strehl parameters");
974 flux_radius_pix = ( (flux_radius_pix + cx) > (sx -2) ) ? flux_radius_pix : sx -2;
975 flux_radius_pix = ( (flux_radius_pix + cy) > (sy -2) ) ? flux_radius_pix : sy -2;
976 flux_radius_pix = ( (cx - flux_radius_pix) < 2 ) ? cx -2 : flux_radius_pix;
977 flux_radius_pix = ( (cy - flux_radius_pix) < 2 ) ? cy -2 : flux_radius_pix;
979 flux_radius_arc = flux_radius_pix * pixel_scale_x;
980 bkg_radius_low = flux_radius_arc;
981 bkg_radius_high = (flux_radius_pix + 1) * pixel_scale_x;
982 cpl_msg_info(cpl_func,
"flux_radius: %g bkg_radius_low: %g bkg_radius_high: %g",
983 flux_radius_arc ,bkg_radius_low ,bkg_radius_high );
985 if(bkg_radius_low > 0) {
987 M1_RADIUS, M2_RADIUS, pixel_scale_x, pixel_scale_y,
988 flux_radius_arc, bkg_radius_low, bkg_radius_high) ;
993 cpl_msg_warning(cpl_func,
"bkg_radius_low: %g. Skip Strehl computation.", bkg_radius_low);
1000 flux_radius_arc = flux_radius_pix * pixel_scale_x;
1001 cpl_msg_info(cpl_func,
"flux_radius_pix: %g",flux_radius_pix);
1002 if(bkg_radius_low > 0) {
1004 M1_RADIUS, M2_RADIUS, pixel_scale_x, pixel_scale_y,
1005 flux_radius_arc, bkg_radius_low, bkg_radius_high) ;
1009 cpl_msg_info(cpl_func,
"strehl=%g+-%g", res.strehl_value.data,
1010 res.strehl_value.error);
1012 cpl_msg_warning(cpl_func,
"bkg_radius_low: %g. Skip Strehl computation.", bkg_radius_low);
1020 if(cpl_error_get_code() != CPL_ERROR_NONE) {
1021 cpl_msg_error(cpl_func,
"Error computing Strehl. Temporarily suppress it.");
1022 cpl_error_set(cpl_func,CPL_ERROR_NONE);
1024 return CPL_ERROR_NONE;
1026 if (res.strehl_value.data > 0) {
1028 cpl_msg_info(cpl_func,
"strehl=%g+-%g", res.strehl_value.data,
1029 res.strehl_value.error);
1031 cpl_msg_info(cpl_func,
"star peak at %g/%g: %g +- %g", res.star_x,
1032 res.star_y, res.star_peak.data, res.star_peak.error);
1033 cpl_msg_info(cpl_func,
"star flux %g+-%g", res.star_flux.data,
1034 res.star_flux.error);
1035 cpl_msg_info(cpl_func,
"median estimated background=%g+-%g "
1036 "(computed error %g)",
1037 res.star_background.data, res.star_background.error,
1038 res.computed_background_error);
1040 double qc_strehl = 0;
1041 double qc_strehl_err = 0;
1042 if(isnan(res.strehl_value.data)){
1046 qc_strehl=res.strehl_value.data;
1047 qc_strehl_err=res.strehl_value.error;
1050 cpl_image* data = cpl_image_load(fname, CPL_TYPE_DOUBLE, 0, extnum_raw);
1052 cpl_image* errs = cpl_image_load(fname, CPL_TYPE_DOUBLE, 0, extnum_err);
1053 cpl_propertylist* eheader = cpl_propertylist_load(fname, extnum_err);
1056 cpl_image* qual = cpl_image_load(fname, CPL_TYPE_INT, 0, extnum_bpm);
1057 cpl_propertylist* qheader = cpl_propertylist_load(fname, extnum_bpm);
1061 cpl_propertylist_append_double(plist,
"ESO QC STREHL", qc_strehl);
1062 cpl_propertylist_append_double(plist,
"ESO QC STREHL ERROR", qc_strehl_err);
1063 cpl_image_save(data, fname, CPL_TYPE_DOUBLE, plist, CPL_IO_DEFAULT);
1071 cpl_image_save(errs, fname, CPL_TYPE_DOUBLE, eheader, CPL_IO_EXTEND);
1072 cpl_image_save(qual, fname, CPL_TYPE_INT, qheader, CPL_IO_EXTEND);
1073 cpl_image_delete(data);
1074 cpl_image_delete(errs);
1075 cpl_image_delete(qual);
1077 cpl_propertylist_delete(eheader);
1078 cpl_propertylist_delete(qheader);
1082 cpl_propertylist_delete(plist);
1088 return cpl_error_get_code();
cpl_error_code eris_ifu_dfs_set_groups(cpl_frameset *self)
Set the frame group (RAW, CALIB, or PRODUCT) for all frames in a frameset.
cpl_error_code eris_ifu_jitter_get_instrument_settings(cpl_frameset *frames, ifsInstrument *instrument, ifsBand *band, ifsPreopticsScale *scale)
Extract instrument configuration from frameset.
cpl_error_code eris_ifu_mask_nans_in_hdrlimage(hdrl_image **hima)
Flag NaNs in HDRL image.
int eris_pfits_get_naxis2(const cpl_propertylist *plist)
find out the character string associated to the NAXIS2 keyword
int eris_pfits_get_naxis1(const cpl_propertylist *plist)
find out the character string associated to the NAXIS1 keyword
cpl_error_code eris_check_error_code(const char *func_id)
handle CPL errors
hdrl_image * hdrl_image_create(const cpl_image *image, const cpl_image *error)
create a new hdrl_image from to existing images by copying them
cpl_image * hdrl_image_get_image(hdrl_image *himg)
get data as cpl image
void hdrl_image_delete(hdrl_image *himg)
delete hdrl_image
void hdrl_parameter_delete(hdrl_parameter *obj)
shallow delete of a parameter
hdrl_strehl_result hdrl_strehl_compute(const hdrl_image *himg, hdrl_parameter *params)
This function computes the Strehl ratio.
hdrl_parameter * hdrl_strehl_parameter_create(double wavelength, double m1_radius, double m2_radius, double pixel_scale_x, double pixel_scale_y, double flux_radius, double bkg_radius_low, double bkg_radius_high)
Creates Strehl Parameters object.
hdrl_parameter * hdrl_strehl_parameter_parse_parlist(const cpl_parameterlist *parlist, const char *prefix)
Parse parameter list to create input parameters for the Strehl.
cpl_error_code hdrl_rect_region_parameter_verify(const hdrl_parameter *param, const cpl_size max_x, const cpl_size max_y)
Verify basic correctness of the parameters.
cpl_error_code hdrl_rect_region_fix_negatives(hdrl_parameter *rect_region, const cpl_size nx, const cpl_size ny)
wrap negative or zero coordinates around full image size
hdrl_parameter * hdrl_rect_region_parameter_create(cpl_size llx, cpl_size lly, cpl_size urx, cpl_size ury)
Creates Rect Region Parameters object.
cpl_size hdrl_rect_region_get_llx(const hdrl_parameter *p)
get lower left x coordinate of rectangual region
cpl_size hdrl_rect_region_get_urx(const hdrl_parameter *p)
get upper right x coordinate of rectangular region
cpl_size hdrl_rect_region_get_lly(const hdrl_parameter *p)
get lower left y coordinate of rectangual region
cpl_size hdrl_rect_region_get_ury(const hdrl_parameter *p)
get upper right y coordinate of rectangual region
cpl_boolean hdrl_rect_region_parameter_check(const hdrl_parameter *self)
Check that the parameter is hdrl_rect_region parameter.