40 #include "irplib_plugin.h"
41 #include "irplib_utils.h"
43 #include "sofi_utils.h"
44 #include "sofi_pfits.h"
51 #define RECIPE_STRING "sofi_spc_flat"
53 #define MEDIAN_XSIZE 200
54 #define MEDIAN_YSIZE 200
60 static cpl_image * sofi_spc_flat_reduce(cpl_frameset *);
61 static cpl_imagelist * sofi_spc_flat_diffs(cpl_frameset *);
62 static cpl_image * sofi_spc_flat_divide_fit(cpl_image *,
int,
int,
int);
63 static cpl_error_code sofi_spc_flat_save(cpl_frameset *,
int,
const cpl_image *,
65 const cpl_parameterlist *);
66 static int sofi_spc_flat_compare(
const cpl_frame *,
const cpl_frame *);
68 cpl_recipe_define(sofi_spc_flat, SOFI_BINARY_VERSION,
69 "Lars Lundin", PACKAGE_BUGREPORT,
"2002,2003,2009",
70 "SOFI spectro flat-field creation",
71 RECIPE_STRING
" -- SOFI spectro flat-field creation.\n"
72 "The files listed in the Set Of Frames (sof-file) "
74 "raw-file.fits "SOFI_SPC_FLAT_RAW
"\n");
94 } sofi_spc_flat_config;
111 cpl_error_code sofi_spc_flat_fill_parameterlist(cpl_parameterlist *
self)
113 const char * context = PACKAGE
"." RECIPE_STRING;
116 cpl_ensure_code(
self, CPL_ERROR_NULL_INPUT);
121 err = irplib_parameterlist_set_string(
self, PACKAGE, RECIPE_STRING,
122 "thresholds",
"0.01,3.0", NULL,
123 context,
"Low and high thresholds");
124 cpl_ensure_code(!err, err);
127 err = irplib_parameterlist_set_int(
self, PACKAGE, RECIPE_STRING,
"fit_order",
128 3, NULL, context,
"Order of the fit");
129 cpl_ensure_code(!err, err);
132 err = irplib_parameterlist_set_int(
self, PACKAGE, RECIPE_STRING,
"fit_size",
133 200, NULL, context,
"Size of the fit");
134 cpl_ensure_code(!err, err);
137 err = irplib_parameterlist_set_int(
self, PACKAGE, RECIPE_STRING,
"offset",
138 40, NULL, context,
"Offset");
139 cpl_ensure_code(!err, err);
142 err = irplib_parameterlist_set_string(
self, PACKAGE, RECIPE_STRING,
143 "zone",
"256,256,768,768", NULL,
144 context,
"Zone to process [pixel]");
145 cpl_ensure_code(!err, err);
147 return CPL_ERROR_NONE;
160 static int sofi_spc_flat(cpl_frameset * framelist,
161 const cpl_parameterlist * parlist)
163 const int nframes = cpl_frameset_get_size(framelist);
165 cpl_frameset * flatframes = NULL;
166 cpl_size * labels = NULL;
172 sofi_spc_flat_config.med_stdev = 0.0;
173 sofi_spc_flat_config.med_avg = 0.0;
177 sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
179 bug_if(sval == NULL);
180 skip_if (sscanf(sval,
"%lg,%lg",
181 &sofi_spc_flat_config.low_thresh,
182 &sofi_spc_flat_config.high_thresh) != 2);
185 sofi_spc_flat_config.fit_order
186 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
189 sofi_spc_flat_config.fit_size
190 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
193 sofi_spc_flat_config.offset
194 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
197 sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
199 bug_if(sval == NULL);
200 skip_if (sscanf(sval,
"%d,%d,%d,%d",
201 &sofi_spc_flat_config.llx,
202 &sofi_spc_flat_config.lly,
203 &sofi_spc_flat_config.urx,
204 &sofi_spc_flat_config.ury) != 4);
212 error_if (flatframes == NULL, CPL_ERROR_DATA_NOT_FOUND,
213 "Cannot find flat frames in the input frame list");
215 nflats = cpl_frameset_get_size(flatframes);
218 error_if (cpl_frameset_get_size(flatframes) % 2, CPL_ERROR_ILLEGAL_INPUT,
219 "The number of flat frames must be even, not %d", nflats);
222 labels = cpl_frameset_labelise(flatframes, sofi_spc_flat_compare, &nlabels);
223 error_if (labels == NULL, cpl_error_get_code(),
224 "Cannot labelise input frames");
227 for (i=0; i < nlabels; i++) {
229 cpl_errorstate prestate = cpl_errorstate_get();
230 cpl_frameset * flat_one = cpl_frameset_extract(flatframes, labels, i);
233 cpl_msg_info(cpl_func,
"Reducing set %d/%d", i+1, (
int)nlabels);
235 spflat = sofi_spc_flat_reduce(flat_one);
237 if (spflat == NULL) {
238 cpl_msg_warning(cpl_func,
"Could not reduce set %d:", i+1);
239 cpl_errorstate_dump(prestate, CPL_FALSE,
240 irplib_errorstate_dump_warning);
241 cpl_errorstate_set(prestate);
243 sofi_spc_flat_save(framelist, i+1, spflat, flat_one, parlist);
244 cpl_image_delete(spflat);
246 cpl_frameset_delete(flat_one);
247 if (!cpl_errorstate_is_equal(prestate))
break;
249 skip_if(i != nlabels);
251 error_if (cpl_frameset_get_size(framelist) == nframes,
252 CPL_ERROR_ILLEGAL_INPUT,
"No products produced from %d flat "
253 "frames grouped into %d set(s)", nflats, (
int)nlabels);
257 cpl_frameset_delete(flatframes);
259 return cpl_error_get_code();
270 static cpl_image * sofi_spc_flat_reduce(cpl_frameset * flatframes)
272 cpl_imagelist * diffs;
273 cpl_vector * medians;
282 if (flatframes == NULL)
return NULL;
283 nframes = cpl_frameset_get_size(flatframes);
285 cpl_msg_error(cpl_func,
"Expect 4 frames in input, not %d", nframes);
290 cpl_msg_info(cpl_func,
"Compute the difference images");
291 if ((diffs = sofi_spc_flat_diffs(flatframes)) == NULL) {
292 cpl_msg_error(cpl_func,
"Cannot create the difference images");
295 nima = cpl_imagelist_get_size(diffs);
296 nx = cpl_image_get_size_x(cpl_imagelist_get(diffs, 0));
297 ny = cpl_image_get_size_y(cpl_imagelist_get(diffs, 0));
300 cpl_msg_info(cpl_func,
"Compute statistics on images");
301 cpl_msg_indent_more();
302 medians = cpl_vector_new(nima);
305 for (i=0; i<nima; i++) {
306 med = cpl_image_get_median_window(cpl_imagelist_get(diffs, i),
307 (nx-MEDIAN_XSIZE)/2.0, (ny-MEDIAN_YSIZE)/2.0,
308 (nx+MEDIAN_XSIZE)/2.0, (ny+MEDIAN_YSIZE)/2.0);
309 if (cpl_vector_set(medians, i, med) != CPL_ERROR_NONE) {
310 cpl_msg_error(cpl_func,
"Cannot compute the medians");
311 cpl_vector_delete(medians);
312 cpl_imagelist_delete(diffs);
313 cpl_msg_indent_less();
319 sofi_spc_flat_config.med_avg = cpl_vector_get_mean(medians);
321 sofi_spc_flat_config.med_stdev=cpl_vector_get_stdev(medians);
322 cpl_vector_delete(medians);
323 cpl_msg_info(cpl_func,
"Average of the medians: %g",
324 sofi_spc_flat_config.med_avg);
325 cpl_msg_info(cpl_func,
"Standard deviation of the medians: %g",
326 sofi_spc_flat_config.med_stdev);
327 cpl_msg_indent_less();
330 cpl_msg_info(cpl_func,
"Normalise the images");
331 for (i=0; i<nima; i++) {
332 mean = cpl_image_get_mean_window(cpl_imagelist_get(diffs, i),
333 sofi_spc_flat_config.llx, sofi_spc_flat_config.lly,
334 sofi_spc_flat_config.urx, sofi_spc_flat_config.ury);
335 if (cpl_image_divide_scalar(cpl_imagelist_get(diffs, i), mean) !=
337 cpl_msg_error(cpl_func,
"Cannot normalise the image");
338 cpl_imagelist_delete(diffs);
344 for (i=0; i<nima; i++) {
345 if (cpl_image_threshold(cpl_imagelist_get(diffs, i),
346 sofi_spc_flat_config.low_thresh,
347 sofi_spc_flat_config.high_thresh,
348 0.0, 0.0) != CPL_ERROR_NONE) {
349 cpl_msg_error(cpl_func,
"Cannot threshold the image");
350 cpl_imagelist_delete(diffs);
356 cpl_msg_info(cpl_func,
"Stack the images");
357 if ((avg_ima = cpl_imagelist_collapse_create(diffs)) == NULL) {
358 cpl_msg_error(cpl_func,
"Cannot collapse the image list");
359 cpl_imagelist_delete(diffs);
362 cpl_imagelist_delete(diffs);
365 cpl_msg_info(cpl_func,
"Divide by a fit");
366 if ((fitted = sofi_spc_flat_divide_fit(avg_ima,
367 sofi_spc_flat_config.fit_order,
368 sofi_spc_flat_config.fit_size,
369 sofi_spc_flat_config.offset)) == NULL) {
370 cpl_msg_error(cpl_func,
"Cannot collapse the image list");
371 cpl_image_delete(avg_ima);
374 cpl_image_delete(avg_ima);
386 static cpl_imagelist * sofi_spc_flat_diffs(cpl_frameset * in)
392 cpl_frame * cur_frame;
396 nima = cpl_frameset_get_size(in);
399 if ((nima % 2) || (nima != 4)) {
400 cpl_msg_error(cpl_func,
"Wrong nb of frames");
405 out = cpl_imagelist_new();
408 for (i=0; i<nima/2; i++) {
409 cur_frame = cpl_frameset_get_position(in, 2*i);
410 if ((in1 = cpl_image_load(cpl_frame_get_filename(cur_frame),
411 CPL_TYPE_FLOAT, 0, 0)) == NULL) {
412 cpl_msg_error(cpl_func,
"Cannot load the image %d", 2*i);
413 cpl_imagelist_delete(out);
416 cur_frame = cpl_frameset_get_position(in, 2*i+1);
417 if ((in2 = cpl_image_load(cpl_frame_get_filename(cur_frame),
418 CPL_TYPE_FLOAT, 0, 0)) == NULL) {
419 cpl_msg_error(cpl_func,
"Cannot load the image %d", 2*i+1);
420 cpl_image_delete(in1);
421 cpl_imagelist_delete(out);
427 cpl_image_subtract(in2, in1);
428 cpl_image_delete(in1);
429 cpl_imagelist_set(out, in2, i);
431 cpl_image_subtract(in1, in2);
432 cpl_image_delete(in2);
433 cpl_imagelist_set(out, in1, i);
446 static cpl_image * sofi_spc_flat_divide_fit(
452 const cpl_size degree = order - 1;
454 int xstart, xend, ystart, yend;
455 cpl_image * collapsed;
457 cpl_image * extracted;
462 cpl_polynomial * poly_fit;
463 cpl_polynomial * poly_2d;
464 cpl_image * fit_image;
470 if (in == NULL)
return NULL;
473 nx = cpl_image_get_size_x(in);
474 ny = cpl_image_get_size_y(in);
477 xstart = (int)((nx - xsize)/2) + 1;
478 xend = xstart + xsize - 1;
479 if ((xstart<1) || (xend>nx)) {
480 cpl_msg_error(cpl_func,
"bad X size specified");
485 if ((collapsed = cpl_image_collapse_window_create(in, xstart, 1, xend, ny,
487 cpl_msg_error(cpl_func,
"Cannot collpase a part of the image");
490 pcollapsed = cpl_image_get_data_float(collapsed);
494 while ((fabs(pcollapsed[ystart-1]) < 1e-4) && (ystart < nx)) ystart++;
498 while ((fabs(pcollapsed[yend-1]) <1e-4) && (yend > 1)) yend--;
502 cpl_msg_error(cpl_func,
"invalid coordinates of the zone to extract");
503 cpl_image_delete(collapsed);
508 if ((extracted = cpl_image_extract(collapsed, 1, ystart, 1, yend))==NULL) {
509 cpl_msg_error(cpl_func,
"cannot extract 1D image");
510 cpl_image_delete(collapsed);
513 cpl_image_delete(collapsed);
514 pextracted = cpl_image_get_data_float(extracted);
517 nb_samples = cpl_image_get_size_y(extracted);
518 xvec = cpl_matrix_new(1, nb_samples);
519 yvec = cpl_vector_new(nb_samples);
520 for (i=0; i<nb_samples; i++) {
521 cpl_matrix_set(xvec, 0, i, (
double)(ystart + i));
522 cpl_vector_set(yvec, i, (
double)(pextracted[i] / xsize));
524 cpl_image_delete(extracted);
525 poly_fit = cpl_polynomial_new(1);
526 if (cpl_polynomial_fit(poly_fit, xvec, NULL, yvec, NULL, CPL_FALSE,
528 cpl_msg_error(cpl_func,
"cannot fit the 1D signal");
529 cpl_polynomial_delete(poly_fit);
530 cpl_matrix_delete(xvec);
531 cpl_vector_delete(yvec);
534 cpl_matrix_delete(xvec);
535 cpl_vector_delete(yvec);
538 poly_2d = cpl_polynomial_new(2);
539 power[0] = 0; power[1] = 0;
540 cpl_polynomial_set_coeff(poly_2d, power,
541 cpl_polynomial_get_coeff(poly_fit, power + 1));
542 power[0] = 0; power[1] = 1;
543 cpl_polynomial_set_coeff(poly_2d, power,
544 cpl_polynomial_get_coeff(poly_fit, power + 1));
545 power[0] = 0; power[1] = 2;
546 cpl_polynomial_set_coeff(poly_2d, power,
547 cpl_polynomial_get_coeff(poly_fit, power + 1));
548 cpl_polynomial_delete(poly_fit);
551 fit_image = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
552 cpl_image_fill_polynomial(fit_image, poly_2d, 1.0, 1.0, 1.0, 1.0);
553 cpl_polynomial_delete(poly_2d);
556 if ((out = cpl_image_divide_create(in, fit_image)) == NULL) {
557 cpl_msg_error(cpl_func,
"cannot divide the images");
558 cpl_image_delete(fit_image);
561 cpl_image_delete(fit_image);
577 static cpl_error_code sofi_spc_flat_save(cpl_frameset * set_tot,
579 const cpl_image * flat,
580 const cpl_frameset * set,
581 const cpl_parameterlist * parlist)
583 #define SOFI_SPC_FLAT_PAF \
584 "^(ARCFILE|MJD-OBS|INSTRUME|ESO TPL ID|ESO TPL NEXP|ESO DPR CATG" \
585 "|ESO DPR TECH|ESO DPR TYPE|DATE-OBS|ESO INS GRAT NAME" \
586 "|ESO INS GRAT WLEN|ESO INS OPTI1 ID|ESO DET DIT|ESO INS LAMP3 SET)$"
588 cpl_errorstate prestate = cpl_errorstate_get();
590 const cpl_frame * ref_frame
591 = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW);
593 cpl_propertylist * qclist = cpl_propertylist_new();
594 cpl_propertylist * plist = cpl_propertylist_load_regexp
595 (cpl_frame_get_filename(ref_frame), 0, SOFI_SPC_FLAT_PAF
596 "|^ESO INS FILT[12] ID$", 0);
604 cpl_msg_warning(cpl_func,
"Could not get filter for set %d:", set_nb);
605 cpl_errorstate_dump(prestate, CPL_FALSE,
606 irplib_errorstate_dump_warning);
607 cpl_errorstate_set(prestate);
609 cpl_propertylist_append_string(qclist,
"ESO QC FILTER OBS", sval);
612 cpl_propertylist_append_double(qclist,
"ESO QC SPECFLAT NCOUNTS",
613 sofi_spc_flat_config.med_avg);
614 cpl_propertylist_append_double(qclist,
"ESO QC SPECFLAT STDEV",
615 sofi_spc_flat_config.med_stdev);
618 filename = cpl_sprintf(RECIPE_STRING
"_set%02d" CPL_DFS_FITS, set_nb);
619 irplib_dfs_save_image(set_tot, parlist, set, flat, CPL_BPP_IEEE_FLOAT,
620 RECIPE_STRING, SOFI_SPC_FLAT_RES, qclist, NULL,
621 PACKAGE
"/" PACKAGE_VERSION, filename);
625 cpl_propertylist_copy_property_regexp(qclist, plist,
626 SOFI_SPC_FLAT_PAF, 0);
627 cpl_propertylist_empty(plist);
630 filename = cpl_sprintf(RECIPE_STRING
"_set%02d" CPL_DFS_PAF, set_nb);
631 cpl_dfs_save_paf(
"SOFI", RECIPE_STRING, qclist, filename);
638 cpl_propertylist_delete(qclist);
639 cpl_propertylist_delete(plist);
641 return cpl_error_get_code();
652 static int sofi_spc_flat_compare(
653 const cpl_frame * frame1,
654 const cpl_frame * frame2)
657 cpl_propertylist * plist1;
658 cpl_propertylist * plist2;
663 if (frame1==NULL || frame2==NULL)
return CPL_ERROR_UNSPECIFIED;
666 if ((plist1=cpl_propertylist_load(cpl_frame_get_filename(frame1),
668 cpl_msg_error(cpl_func,
"getting header from reference frame");
669 return CPL_ERROR_UNSPECIFIED;
671 if ((plist2=cpl_propertylist_load(cpl_frame_get_filename(frame2),
673 cpl_msg_error(cpl_func,
"getting header from reference frame");
674 cpl_propertylist_delete(plist1);
675 return CPL_ERROR_UNSPECIFIED;
679 if (cpl_error_get_code()) {
680 cpl_propertylist_delete(plist1);
681 cpl_propertylist_delete(plist2);
682 return CPL_ERROR_UNSPECIFIED;
690 if (cpl_error_get_code()) {
691 cpl_msg_error(cpl_func,
"cannot get the slit used");
692 cpl_propertylist_delete(plist1);
693 cpl_propertylist_delete(plist2);
694 return CPL_ERROR_UNSPECIFIED;
696 if (strcmp(sval1, sval2)) comparison = 0;
701 if (cpl_error_get_code()) {
702 cpl_msg_error(cpl_func,
"cannot get the filter");
703 cpl_propertylist_delete(plist1);
704 cpl_propertylist_delete(plist2);
705 return CPL_ERROR_UNSPECIFIED;
707 if (strcmp(sval1, sval2)) comparison = 0;
709 cpl_propertylist_delete(plist1);
710 cpl_propertylist_delete(plist2);