40 #include "irplib_utils.h"
42 #include "isaac_utils.h"
43 #include "isaac_pfits.h"
44 #include "isaac_dfs.h"
50 #define MEDIAN_XSIZE 200
51 #define MEDIAN_YSIZE 200
57 static int isaac_spc_flat_create(cpl_plugin *);
58 static int isaac_spc_flat_exec(cpl_plugin *);
59 static int isaac_spc_flat_destroy(cpl_plugin *);
60 static int isaac_spc_flat(cpl_parameterlist *, cpl_frameset *);
61 static cpl_image * isaac_spc_flat_reduce(cpl_frameset *);
62 static cpl_imagelist * isaac_spc_flat_diffs(cpl_frameset *);
63 static cpl_image * isaac_spc_flat_divide_fit(cpl_image *,
int,
int,
int);
64 static int isaac_spc_flat_save(cpl_image *,
int, cpl_frameset *,
65 cpl_parameterlist *, cpl_frameset *);
66 static int isaac_spc_flat_compare(
const cpl_frame *,
const cpl_frame *);
86 } isaac_spc_flat_config;
88 static char isaac_spc_flat_description[] =
89 "isaac_spc_flat -- ISAAC spectro flat-field creation.\n"
90 "The files listed in the Set Of Frames (sof-file) must be tagged:\n"
91 "raw-file.fits "ISAAC_SPC_FLAT_RAW
"\n";
106 int cpl_plugin_get_info(cpl_pluginlist * list)
108 cpl_recipe * recipe = cpl_calloc(1,
sizeof(*recipe));
109 cpl_plugin * plugin = &recipe->interface;
111 cpl_plugin_init(plugin,
113 ISAAC_BINARY_VERSION,
114 CPL_PLUGIN_TYPE_RECIPE,
116 "Spectro flat recipe",
117 isaac_spc_flat_description,
121 isaac_spc_flat_create,
123 isaac_spc_flat_destroy);
125 cpl_pluginlist_append(list, plugin);
140 static int isaac_spc_flat_create(cpl_plugin * plugin)
146 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
147 recipe = (cpl_recipe *)plugin;
148 else return CPL_ERROR_UNSPECIFIED;
151 recipe->parameters = cpl_parameterlist_new();
155 p = cpl_parameter_new_value(
"isaac.isaac_spc_flat.thresholds",
156 CPL_TYPE_STRING,
"Low and high thresholds",
"isaac.isaac_spc_flat",
158 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"thresholds");
159 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
160 cpl_parameterlist_append(recipe->parameters, p);
162 p = cpl_parameter_new_value(
"isaac.isaac_spc_flat.fit_order", CPL_TYPE_INT,
163 "Order for the fit",
"isaac.isaac_spc_flat", 3);
164 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"fit_order");
165 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
166 cpl_parameterlist_append(recipe->parameters, p);
168 p = cpl_parameter_new_value(
"isaac.isaac_spc_flat.fit_size", CPL_TYPE_INT,
169 "Size for the fit",
"isaac.isaac_spc_flat", 200);
170 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"fit_size");
171 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
172 cpl_parameterlist_append(recipe->parameters, p);
174 p = cpl_parameter_new_value(
"isaac.isaac_spc_flat.offset", CPL_TYPE_INT,
175 "Offset",
"isaac.isaac_spc_flat", 40);
176 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"offset");
177 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
178 cpl_parameterlist_append(recipe->parameters, p);
180 p = cpl_parameter_new_value(
"isaac.isaac_spc_flat.zone",
181 CPL_TYPE_STRING,
"Zone to consider",
"isaac.isaac_spc_flat",
183 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"zone");
184 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
185 cpl_parameterlist_append(recipe->parameters, p);
197 static int isaac_spc_flat_exec(cpl_plugin * plugin)
202 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
203 recipe = (cpl_recipe *)plugin;
204 else return CPL_ERROR_UNSPECIFIED;
206 return isaac_spc_flat(recipe->parameters, recipe->frames);
216 static int isaac_spc_flat_destroy(cpl_plugin * plugin)
221 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
222 recipe = (cpl_recipe *)plugin;
223 else return CPL_ERROR_UNSPECIFIED;
225 cpl_parameterlist_delete(recipe->parameters);
237 static int isaac_spc_flat(
238 cpl_parameterlist * parlist,
239 cpl_frameset * framelist)
245 cpl_frameset * flatframes;
246 cpl_frameset * flat_one;
249 cpl_boolean did_reduce = CPL_FALSE;
253 isaac_spc_flat_config.med_stdev = 0.0;
254 isaac_spc_flat_config.med_avg = 0.0;
258 par = cpl_parameterlist_find(parlist,
"isaac.isaac_spc_flat.thresholds");
259 sval = cpl_parameter_get_string(par);
260 if (sscanf(sval,
"%lg,%lg",
261 &isaac_spc_flat_config.low_thresh,
262 &isaac_spc_flat_config.high_thresh)!=2) {
263 return CPL_ERROR_UNSPECIFIED;
266 par = cpl_parameterlist_find(parlist,
"isaac.isaac_spc_flat.fit_order");
267 isaac_spc_flat_config.fit_order = cpl_parameter_get_int(par);
269 par = cpl_parameterlist_find(parlist,
"isaac.isaac_spc_flat.fit_size");
270 isaac_spc_flat_config.fit_size = cpl_parameter_get_int(par);
272 par = cpl_parameterlist_find(parlist,
"isaac.isaac_spc_flat.offset");
273 isaac_spc_flat_config.offset = cpl_parameter_get_int(par);
275 par = cpl_parameterlist_find(parlist,
"isaac.isaac_spc_flat.zone");
276 sval = cpl_parameter_get_string(par);
277 if (sscanf(sval,
"%d,%d,%d,%d",
278 &isaac_spc_flat_config.llx,
279 &isaac_spc_flat_config.lly,
280 &isaac_spc_flat_config.urx,
281 &isaac_spc_flat_config.ury)!=4) {
282 return CPL_ERROR_UNSPECIFIED;
287 cpl_msg_error(cpl_func,
"Cannot identify RAW and CALIB frames");
288 return CPL_ERROR_UNSPECIFIED;
293 ISAAC_SPC_FLAT_RAW)) == NULL) {
294 cpl_msg_error(cpl_func,
"Cannot find flat frames in the input list");
295 return CPL_ERROR_UNSPECIFIED;
299 if (cpl_frameset_get_size(flatframes) % 2) {
300 cpl_msg_error(cpl_func,
"An even nb of frames expected in input");
301 cpl_frameset_delete(flatframes);
302 return CPL_ERROR_UNSPECIFIED;
306 if ((labels = cpl_frameset_labelise(flatframes, isaac_spc_flat_compare,
307 &nlabels)) == NULL) {
308 cpl_msg_error(cpl_func,
"Cannot labelise input frames");
309 cpl_frameset_delete(flatframes);
310 return CPL_ERROR_UNSPECIFIED;
314 for (i=0; i<nlabels; i++) {
315 cpl_errorstate prestate = cpl_errorstate_get();
318 cpl_msg_info(cpl_func,
"Reduce data set no %d out of %d", i+1,
320 cpl_msg_indent_more();
321 flat_one = cpl_frameset_extract(flatframes, labels, i);
322 spflat = isaac_spc_flat_reduce(flat_one);
323 cpl_msg_indent_less();
326 cpl_msg_info(cpl_func,
"Save the products");
327 cpl_msg_indent_more();
328 if (!cpl_errorstate_is_equal(prestate)) {
329 cpl_image_delete(spflat);
330 irplib_error_recover(prestate,
"Could not reduce set %d/%d", 1+i,
332 }
else if (spflat == NULL) {
333 cpl_msg_warning(cpl_func,
"Cannot reduce set nb %d", i+1);
335 isaac_spc_flat_save(spflat, i+1, flat_one, parlist, framelist);
336 cpl_image_delete(spflat);
337 did_reduce = CPL_TRUE;
339 cpl_msg_indent_less();
340 cpl_frameset_delete(flat_one);
344 cpl_frameset_delete(flatframes);
347 cpl_ensure_code(did_reduce, CPL_ERROR_ILLEGAL_INPUT);
349 return cpl_error_set_where(cpl_func);
360 static cpl_image * isaac_spc_flat_reduce(cpl_frameset * flatframes)
362 cpl_imagelist * diffs;
363 cpl_vector * medians;
371 if (flatframes == NULL)
return NULL;
374 cpl_msg_info(cpl_func,
"Compute the difference images");
375 if ((diffs = isaac_spc_flat_diffs(flatframes)) == NULL) {
376 cpl_msg_error(cpl_func,
"Cannot create the difference images");
379 nima = cpl_imagelist_get_size(diffs);
380 nx = cpl_image_get_size_x(cpl_imagelist_get(diffs, 0));
381 ny = cpl_image_get_size_y(cpl_imagelist_get(diffs, 0));
384 cpl_msg_info(cpl_func,
"Compute statistics on images");
385 cpl_msg_indent_more();
386 medians = cpl_vector_new(nima);
389 for (i=0; i<nima; i++) {
390 med = cpl_image_get_median_window(cpl_imagelist_get(diffs, i),
391 (nx-MEDIAN_XSIZE)/2.0, (ny-MEDIAN_YSIZE)/2.0,
392 (nx+MEDIAN_XSIZE)/2.0, (ny+MEDIAN_YSIZE)/2.0);
393 if (cpl_vector_set(medians, i, med) != CPL_ERROR_NONE) {
394 cpl_msg_error(cpl_func,
"Cannot compute the medians");
395 cpl_vector_delete(medians);
396 cpl_imagelist_delete(diffs);
397 cpl_msg_indent_less();
403 isaac_spc_flat_config.med_avg = cpl_vector_get_mean(medians);
405 isaac_spc_flat_config.med_stdev=cpl_vector_get_stdev(medians);
406 cpl_vector_delete(medians);
407 cpl_msg_info(cpl_func,
"Average of the medians: %g",
408 isaac_spc_flat_config.med_avg);
409 cpl_msg_info(cpl_func,
"Standard deviation of the medians: %g",
410 isaac_spc_flat_config.med_stdev);
411 cpl_msg_indent_less();
414 cpl_msg_info(cpl_func,
"Normalise the images");
415 for (i=0; i<nima; i++) {
418 if ((nx != 1024) || (ny != 1024)) {
419 mean = cpl_image_get_mean(cpl_imagelist_get(diffs, i));
421 mean = cpl_image_get_mean_window(cpl_imagelist_get(diffs, i),
422 isaac_spc_flat_config.llx, isaac_spc_flat_config.lly,
423 isaac_spc_flat_config.urx, isaac_spc_flat_config.ury);
425 if (cpl_image_divide_scalar(cpl_imagelist_get(diffs, i), mean) !=
427 cpl_msg_error(cpl_func,
"Cannot normalise the image");
428 cpl_imagelist_delete(diffs);
434 for (i=0; i<nima; i++) {
435 if (cpl_image_threshold(cpl_imagelist_get(diffs, i),
436 isaac_spc_flat_config.low_thresh,
437 isaac_spc_flat_config.high_thresh,
438 0.0, 0.0) != CPL_ERROR_NONE) {
439 cpl_msg_error(cpl_func,
"Cannot threshold the image");
440 cpl_imagelist_delete(diffs);
446 cpl_msg_info(cpl_func,
"Stack the images");
447 if ((avg_ima = cpl_imagelist_collapse_create(diffs)) == NULL) {
448 cpl_msg_error(cpl_func,
"Cannot collapse the image list");
449 cpl_imagelist_delete(diffs);
452 cpl_imagelist_delete(diffs);
455 cpl_msg_info(cpl_func,
"Divide by a fit");
456 if ((fitted = isaac_spc_flat_divide_fit(avg_ima,
457 isaac_spc_flat_config.fit_order,
458 isaac_spc_flat_config.fit_size,
459 isaac_spc_flat_config.offset)) == NULL) {
460 cpl_msg_error(cpl_func,
"Cannot collapse the image list");
461 cpl_image_delete(avg_ima);
464 cpl_image_delete(avg_ima);
476 static cpl_imagelist * isaac_spc_flat_diffs(cpl_frameset * in)
482 cpl_frame * cur_frame;
486 nima = cpl_frameset_get_size(in);
490 cpl_msg_error(cpl_func,
"Odd nb of frames");
495 out = cpl_imagelist_new();
498 for (i=0; i<nima/2; i++) {
499 cur_frame = cpl_frameset_get_position(in, 2*i);
500 if ((in1 = cpl_image_load(cpl_frame_get_filename(cur_frame),
501 CPL_TYPE_FLOAT, 0, 0)) == NULL) {
502 cpl_msg_error(cpl_func,
"Cannot load the image %d", 2*i);
503 cpl_imagelist_delete(out);
506 cur_frame = cpl_frameset_get_position(in, 2*i+1);
507 if ((in2 = cpl_image_load(cpl_frame_get_filename(cur_frame),
508 CPL_TYPE_FLOAT, 0, 0)) == NULL) {
509 cpl_msg_error(cpl_func,
"Cannot load the image %d", 2*i+1);
510 cpl_image_delete(in1);
511 cpl_imagelist_delete(out);
514 cpl_image_subtract(in1, in2);
515 cpl_image_delete(in2);
516 cpl_imagelist_set(out, in1, i);
528 static cpl_image * isaac_spc_flat_divide_fit(
535 int xstart, xend, ystart, yend;
536 cpl_image * collapsed;
538 cpl_image * extracted;
543 cpl_polynomial * poly_fit;
544 cpl_polynomial * poly_2d;
545 cpl_image * fit_image;
549 const cpl_size maxdeg1d = order - 1;
550 const cpl_boolean sampsym = CPL_TRUE;
553 if (in == NULL)
return NULL;
556 nx = cpl_image_get_size_x(in);
557 ny = cpl_image_get_size_y(in);
560 xstart = (int)((nx - xsize)/2) + 1;
561 xend = xstart + xsize - 1;
562 if ((xstart<1) || (xend>nx)) {
563 cpl_msg_error(cpl_func,
"bad X size specified");
568 if ((collapsed = cpl_image_collapse_window_create(in, xstart, 1, xend, ny,
570 cpl_msg_error(cpl_func,
"Cannot collpase a part of the image");
573 pcollapsed = cpl_image_get_data_float(collapsed);
577 while ((fabs(pcollapsed[ystart-1]) < 1e-4) && (ystart < nx)) ystart++;
581 while ((fabs(pcollapsed[yend-1]) <1e-4) && (yend > 1)) yend--;
585 cpl_msg_error(cpl_func,
"invalid coordinates of the zone to extract");
586 cpl_image_delete(collapsed);
591 if ((extracted = cpl_image_extract(collapsed, 1, ystart, 1, yend))==NULL) {
592 cpl_msg_error(cpl_func,
"cannot extract 1D image");
593 cpl_image_delete(collapsed);
596 cpl_image_delete(collapsed);
597 pextracted = cpl_image_get_data_float(extracted);
600 nb_samples = cpl_image_get_size_y(extracted);
601 xvec = cpl_matrix_new(1, nb_samples);
602 yvec = cpl_vector_new(nb_samples);
603 for (i=0; i<nb_samples; i++) {
604 cpl_matrix_set(xvec, 0, i, (
double)(ystart + i));
605 cpl_vector_set(yvec, i, (
double)(pextracted[i] / xsize));
607 cpl_image_delete(extracted);
608 poly_fit = cpl_polynomial_new(1);
609 if (cpl_polynomial_fit(poly_fit, xvec, &sampsym, yvec, NULL, CPL_FALSE,
611 cpl_msg_error(cpl_func,
"cannot fit the 1D signal");
612 cpl_matrix_delete(xvec);
613 cpl_vector_delete(yvec);
614 cpl_polynomial_delete(poly_fit);
617 cpl_matrix_delete(xvec);
618 cpl_vector_delete(yvec);
621 poly_2d = cpl_polynomial_new(2);
622 power[0] = 0; power[1] = 0;
623 cpl_polynomial_set_coeff(poly_2d, power,
624 cpl_polynomial_get_coeff(poly_fit, power + 1));
625 power[0] = 0; power[1] = 1;
626 cpl_polynomial_set_coeff(poly_2d, power,
627 cpl_polynomial_get_coeff(poly_fit, power + 1));
628 power[0] = 0; power[1] = 2;
629 cpl_polynomial_set_coeff(poly_2d, power,
630 cpl_polynomial_get_coeff(poly_fit, power + 1));
631 cpl_polynomial_delete(poly_fit);
634 fit_image = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
635 cpl_image_fill_polynomial(fit_image, poly_2d, 1.0, 1.0, 1.0, 1.0);
636 cpl_polynomial_delete(poly_2d);
639 if ((out = cpl_image_divide_create(in, fit_image)) == NULL) {
640 cpl_msg_error(cpl_func,
"cannot divide the images");
641 cpl_image_delete(fit_image);
644 cpl_image_delete(fit_image);
660 static int isaac_spc_flat_save(
664 cpl_parameterlist * parlist,
665 cpl_frameset * set_tot)
667 cpl_propertylist * plist;
668 cpl_propertylist * qclist;
669 cpl_propertylist * paflist;
670 const cpl_frame * ref_frame;
677 qclist = cpl_propertylist_new();
680 ref_frame = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW);
681 if ((plist=cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
683 cpl_msg_error(cpl_func,
"getting header from reference frame");
684 cpl_propertylist_delete(qclist);
685 return CPL_ERROR_UNSPECIFIED;
688 if (cpl_error_get_code()) {
689 cpl_propertylist_delete(qclist);
690 cpl_propertylist_delete(plist);
691 return CPL_ERROR_UNSPECIFIED;
696 cpl_msg_error(cpl_func,
"Cannot get the arm used");
697 cpl_propertylist_delete(plist);
698 cpl_propertylist_delete(qclist);
699 return CPL_ERROR_UNSPECIFIED;
701 if (sval[0] ==
'S') arm = 1;
702 else if (sval[0] ==
'L') arm = 2;
704 cpl_msg_error(cpl_func,
"Unsupported arm");
705 cpl_propertylist_delete(plist);
706 cpl_propertylist_delete(qclist);
707 return CPL_ERROR_UNSPECIFIED;
710 if (cpl_error_get_code()) cpl_error_reset();
711 else cpl_propertylist_append_string(qclist,
"ESO QC FILTER OBS", sval);
712 cpl_propertylist_delete(plist);
713 cpl_propertylist_append_double(qclist,
"ESO QC SPECFLAT NCOUNTS",
714 isaac_spc_flat_config.med_avg);
715 cpl_propertylist_append_double(qclist,
"ESO QC SPECFLAT STDEV",
716 isaac_spc_flat_config.med_stdev);
719 procat = arm == 1 ? ISAAC_SPC_FLAT_SW_RES : ISAAC_SPC_FLAT_LW_RES;
720 filename = cpl_sprintf(
"isaac_spc_flat_set%02d.fits", set_nb);
721 irplib_dfs_save_image(set_tot,
730 PACKAGE
"/" PACKAGE_VERSION,
735 ref_frame = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW);
738 if ((plist=cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
740 cpl_msg_error(cpl_func,
"getting header from reference frame");
741 cpl_propertylist_delete(qclist);
742 return CPL_ERROR_UNSPECIFIED;
746 paflist = cpl_propertylist_new();
747 cpl_propertylist_copy_property_regexp(paflist, plist,
748 "^(ARCFILE|MJD-OBS|INSTRUME|ESO TPL ID|ESO TPL NEXP|ESO DPR CATG|"
749 "ESO DPR TECH|ESO DPR TYPE|DATE-OBS|ESO INS GRAT NAME|"
750 "ESO INS GRAT WLEN|ESO INS OPTI1 ID|ESO DET DIT|ESO INS LAMP3 SET)$",0);
751 cpl_propertylist_delete(plist);
754 cpl_propertylist_copy_property_regexp(paflist, qclist,
".", 0);
755 cpl_propertylist_delete(qclist);
758 cpl_propertylist_update_string(paflist, CPL_DFS_PRO_CATG, procat);
761 filename = cpl_sprintf(
"isaac_spc_flat_set%02d.paf", set_nb);
762 cpl_dfs_save_paf(
"ISAAC",
767 cpl_propertylist_delete(paflist);
779 static int isaac_spc_flat_compare(
780 const cpl_frame * frame1,
781 const cpl_frame * frame2)
784 cpl_propertylist * plist1;
785 cpl_propertylist * plist2;
791 if (frame1==NULL || frame2==NULL)
return CPL_ERROR_UNSPECIFIED;
794 if ((plist1=cpl_propertylist_load(cpl_frame_get_filename(frame1),
796 cpl_msg_error(cpl_func,
"getting header from reference frame");
797 return CPL_ERROR_UNSPECIFIED;
799 if ((plist2=cpl_propertylist_load(cpl_frame_get_filename(frame2),
801 cpl_msg_error(cpl_func,
"getting header from reference frame");
802 cpl_propertylist_delete(plist1);
803 return CPL_ERROR_UNSPECIFIED;
807 if (cpl_error_get_code()) {
808 cpl_propertylist_delete(plist1);
809 cpl_propertylist_delete(plist2);
810 return CPL_ERROR_UNSPECIFIED;
818 if (cpl_error_get_code()) {
819 cpl_msg_error(cpl_func,
"cannot get the slit used");
820 cpl_propertylist_delete(plist1);
821 cpl_propertylist_delete(plist2);
822 return CPL_ERROR_UNSPECIFIED;
824 if (strcmp(sval1, sval2)) comparison = 0;
829 if (cpl_error_get_code()) {
830 cpl_msg_error(cpl_func,
"cannot get the resolution");
831 cpl_propertylist_delete(plist1);
832 cpl_propertylist_delete(plist2);
833 return CPL_ERROR_UNSPECIFIED;
835 if (strcmp(sval1, sval2)) comparison = 0;
840 if (cpl_error_get_code()) {
841 cpl_msg_error(cpl_func,
"cannot get the central wavelength");
842 cpl_propertylist_delete(plist1);
843 cpl_propertylist_delete(plist2);
844 return CPL_ERROR_UNSPECIFIED;
846 if (fabs(dval1-dval2) > 1e-4) comparison = 0;
848 cpl_propertylist_delete(plist1);
849 cpl_propertylist_delete(plist2);
int isaac_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
const char * isaac_pfits_get_opti1_id(const cpl_propertylist *plist)
find out the OPTI1.ID key
double isaac_pfits_get_wlen(const cpl_propertylist *plist)
find out the central wavelength
const char * isaac_pfits_get_arm(const cpl_propertylist *plist)
find out the arm which is active
const char * isaac_pfits_get_resolution(const cpl_propertylist *plist)
find out the resolution
const char * isaac_pfits_get_filter(const cpl_propertylist *plist)
find out the filter
cpl_frameset * isaac_extract_frameset(const cpl_frameset *self, const char *tag)
Extract the frames with the given tag from a frameset.
const char * isaac_get_license(void)
Get the pipeline copyright and license.