29 #if HAVE_POPEN && HAVE_PCLOSE
37 #include "muse_tracing.h"
38 #include "muse_instrument.h"
40 #include "muse_cplwrappers.h"
41 #include "muse_pfits.h"
42 #include "muse_quadrants.h"
43 #include "muse_utils.h"
54 static const char *muse_trace_poly_strings[] = {
60 static void muse_trace_plot_located_slices(cpl_vector *, cpl_vector *,
double,
double,
double,
const unsigned char);
80 cpl_ensure(aImage && aImage->
data, CPL_ERROR_NULL_INPUT, NULL);
84 cpl_size ymid = cpl_image_get_size_y(aImage->
data) / 2,
90 int y1 = ymid - 1 - aNRows,
93 y4 = ymid + 1 + aNRows;
94 cpl_msg_debug(__func__,
"IFU %hhu: ymid=%"CPL_SIZE_FORMAT
", region=%d..%d, %d..%d",
98 int nx = cpl_image_get_size_x(aImage->
data);
99 cpl_image *tmp1 = cpl_image_collapse_window_create(aImage->
data, 1, y1, nx, y2, 0),
100 *tmp2 = cpl_image_collapse_window_create(aImage->
data, 1, y3, nx, y4, 0);
102 cpl_image_normalise(tmp1, CPL_NORM_MEAN);
103 cpl_image_normalise(tmp2, CPL_NORM_MEAN);
105 cpl_image *tmax = cpl_image_new(nx, 1, CPL_TYPE_FLOAT);
107 for (i = 1; i <= nx; i++) {
109 cpl_image_set(tmax, i, 1,
110 fmax(cpl_image_get(tmp1, i, 1, &err),
111 cpl_image_get(tmp2, i, 1, &err)));
114 cpl_image_save(tmp1,
"trace_tmp1.fits", CPL_TYPE_FLOAT, NULL, CPL_IO_CREATE);
115 cpl_image_save(tmp2,
"trace_tmp2.fits", CPL_TYPE_FLOAT, NULL, CPL_IO_CREATE);
116 cpl_image_save(tmax,
"trace_tmax.fits", CPL_TYPE_FLOAT, NULL, CPL_IO_CREATE);
117 cpl_msg_debug(__func__,
"Saved collapsed rows to trace_{tmp1,tmp2,tmax}.fits");
119 cpl_image_delete(tmp1);
120 cpl_image_delete(tmp2);
122 cpl_vector *cut = cpl_vector_new_from_image_row(tmax, 1);
123 cpl_image_delete(tmax);
163 double aFrac,
const unsigned char aIFU)
165 cpl_ensure(aRowVec, CPL_ERROR_NULL_INPUT, NULL);
166 cpl_ensure(aFrac > 0. && aFrac < 1., CPL_ERROR_ILLEGAL_INPUT, NULL);
167 cpl_vector *centers = cpl_vector_new(aNSlices),
168 *widths = cpl_vector_new(aNSlices);
174 double median = cpl_vector_get_median_const(aRowVec),
178 cpl_msg_debug(__func__,
"median=%f, mdev=%f, fraction=%f --> edge detection"
179 " limit=%f (IFU %hhu)", median, mdev, f, detlimit, aIFU);
183 double ledge = 0., redge = 0.;
185 for (i = 0; i <= kMuseSliceSearchRegion; i++) {
186 if (cpl_vector_get(aRowVec, i) >= detlimit) {
191 if (i == kMuseSliceSearchRegion) {
192 cpl_msg_error(__func__,
"Search for first slice (left-edge) failed in IFU"
194 cpl_vector_delete(centers);
201 for (i = ledge + 1.5; i <= ledge + kMuseSliceMaxWidth; i++) {
202 if (cpl_vector_get(aRowVec, i) <= detlimit) {
207 if (i == ledge + kMuseSliceMaxWidth) {
208 cpl_msg_error(__func__,
"Search for first slice (right-edge) failed in "
210 cpl_vector_delete(centers);
215 double width = redge - ledge;
216 if (width < kMuseSliceLoLikelyWidth) {
217 cpl_msg_error(__func__,
"Initial slice is too narrow (%.2f pix, %.1f..%.1f)"
218 " -> search failed in IFU %hhu", width, ledge, redge, aIFU);
219 cpl_error_set(__func__, CPL_ERROR_ACCESS_OUT_OF_RANGE);
220 cpl_vector_delete(centers);
224 if (width > kMuseSliceHiLikelyWidth) {
225 cpl_msg_error(__func__,
"Initial slice is too wide (%.2f pix, %.1f..%.1f)"
226 " -> search failed in IFU %hhu", width, ledge, redge, aIFU);
227 cpl_error_set(__func__, CPL_ERROR_ACCESS_OUT_OF_RANGE);
228 cpl_vector_delete(centers);
234 cpl_vector_set(centers, 0, round((ledge + redge) / 2.) + 1);
235 cpl_vector_set(widths, 0, width);
239 for (j = 1; j < aNSlices; j++) {
240 for (i = redge + 1.5; i <= redge + kMuseSliceMaxWidth; i++) {
241 if (cpl_vector_get(aRowVec, i) >= detlimit) {
246 if (i == redge + kMuseSliceMaxWidth) {
247 cpl_msg_error(__func__,
"Search for slice %hu (left-edge) failed in IFU"
249 cpl_vector_delete(centers);
250 cpl_vector_delete(widths);
254 for (i = ledge + 1.5; i <= ledge + kMuseSliceMaxWidth; i++) {
255 if (cpl_vector_get(aRowVec, i) <= detlimit) {
260 if (i == ledge + kMuseSliceMaxWidth) {
261 cpl_msg_error(__func__,
"Search for slice %hu (right-edge) failed in"
262 " IFU %hhu", j, aIFU);
263 cpl_vector_delete(centers);
264 cpl_vector_delete(widths);
269 width = redge - ledge;
270 cpl_vector_set(widths, j, width);
272 cpl_msg_debug(__func__,
"slice %hu: left=%f, right=%f --> width %f, center %f",
273 j+1, ledge, redge, width, (ledge + redge) / 2.);
276 cpl_vector_set(centers, j, round((ledge + redge) / 2.) + 1);
280 char *doplot = getenv(
"MUSE_PLOT_TRACE");
281 if (doplot && atoi(doplot) & 0x1) {
282 muse_trace_plot_located_slices(aRowVec, centers, median, mdev, detlimit,
287 for (i = 1; i < cpl_vector_get_size(centers); i++) {
288 double step = cpl_vector_get(centers, i) - cpl_vector_get(centers, i-1);
289 if (step < kMuseSliceLoLikelyWidth) {
302 if (f < DBL_EPSILON) {
303 cpl_msg_error(__func__,
"Still detected %d unlikely slice locations, but "
304 "the cut-off fraction has become unrealistically small in "
305 "IFU %hhu (initial %f, now %f)", failures, aIFU, aFrac, f);
311 int i, n = !centers ? -1 : cpl_vector_get_size(widths);
312 for (i = 0; i < n; i++) {
313 float width = cpl_vector_get(widths, i);
314 if (width < kMuseSliceLoLikelyWidth) {
315 cpl_msg_warning(__func__,
"From the initial guess, slice %d appears to be"
316 " only %f pix wide in IFU %hhu, please cross-check!", i+1,
319 if (width > kMuseSliceHiLikelyWidth) {
320 cpl_msg_warning(__func__,
"From the initial guess, slice %d appears to be"
321 " very wide in IFU %hhu (%f pix), please cross-check!",
325 double step = cpl_vector_get(centers, i) - cpl_vector_get(centers, i-1);
326 if (step < kMuseSliceLoLikelyWidth) {
327 cpl_msg_warning(__func__,
"Slice %d is only %.2f pix farther than the "
328 "previous one in IFU %hhu!", i + 1, step, aIFU);
332 cpl_vector_delete(widths);
373 double *aLeft,
double *aRight, cpl_boolean *aHighSN,
374 const unsigned char aIFU)
376 int size = cpl_vector_get_size(aDataVec);
378 cpl_ensure(size > 5, CPL_ERROR_ILLEGAL_INPUT, -3);
379 cpl_ensure(aFrac > 0. && aFrac < 1., CPL_ERROR_ILLEGAL_INPUT, -4);
380 cpl_ensure(aLeft && aRight, CPL_ERROR_NULL_INPUT, -5);
384 double median = cpl_vector_get_median_const(aDataVec),
386 mean = cpl_vector_get_mean(aDataVec),
387 stdev = cpl_vector_get_stdev(aDataVec),
388 detlimit = aFrac * median;
392 cpl_boolean significant = median > mdev && mean > stdev;
394 *aHighSN = significant;
397 cpl_msg_debug(__func__,
"median=%f+/-%f, mean=%f+/-%f, aFrac=%f --> edge "
398 "detection limit=%f (%ssignificant), IFU %hhu", median, mdev,
399 mean, stdev, aFrac, detlimit, significant ?
"" :
"NOT ", aIFU);
406 const double *ydata = cpl_vector_get_data_const(aDataVec);
410 for (i = size/2; i < size; i++) {
411 if (ydata[i] < detlimit) {
415 *aRight = i-1 + (detlimit - ydata[i-1]) / (ydata[i] - ydata[i-1]);
417 cpl_msg_debug(__func__,
"r: %d..._%d_, %f/_%f_ ===> %f", i-1, i,
418 ydata[i-1], ydata[i], *aRight);
422 if (fabs(*aRight - i) > 1.) {
427 if (significant && i - size/2 > 2) {
428 cpl_msg_debug(__func__,
"Faulty interpolation of right-hand edge in "
429 "IFU %hhu: i=%d (start %d), *aRight=%f (%f..%f > %f > "
430 "%f)", aIFU, i, size/2, *aRight, ydata[i-2], ydata[i-1],
445 for (i = size/2; i >= 0; i--) {
446 if (ydata[i] < detlimit) {
448 *aLeft = i + (detlimit - ydata[i]) / (ydata[i+1] - ydata[i]);
450 cpl_msg_debug(__func__,
"l: %d..._%d_, %f/_%f_ ===> %f", i+1, i,
451 ydata[i+1], ydata[i], *aLeft);
453 if (fabs(*aLeft - i) > 1.) {
454 if (significant && size/2 - i > 2) {
456 cpl_msg_debug(__func__,
"Faulty interpolation of left-hand edge in "
457 "IFU %hhu: i=%d (start %d), *aLeft=%f (%f < %f < %f..%f"
458 ")", aIFU, i, size/2, *aLeft, ydata[i], detlimit,
459 ydata[i+1], ydata[i+2]);
473 cpl_msg_debug(__func__,
"result in IFU %hhu: %f %f --> %f", aIFU, *aLeft,
474 *aRight, (*aLeft + *aRight)/2.);
476 return (*aLeft + *aRight)/2.;
511 int aOffset,
double aY,
const unsigned short aSlice,
512 const unsigned char aIFU)
514 #define TRACE_REFINE_MAX_SHIFT 0.25
515 #define TRACE_REFINE_RANGE 5
516 int size = cpl_vector_get_size(aDiffVec);
517 cpl_ensure(size > 5, CPL_ERROR_ILLEGAL_INPUT, -3);
518 cpl_ensure(aLeft && aRight, CPL_ERROR_NULL_INPUT, -5);
519 cpl_ensure(*aLeft > 0 && *aLeft < size &&
520 *aRight > 0 && *aRight < size && *aRight > *aLeft,
521 CPL_ERROR_ILLEGAL_INPUT, -6);
524 double left = *aLeft,
526 mid = (*aLeft + *aRight) / 2.;
530 int nel = 2 * TRACE_REFINE_RANGE + 1;
531 cpl_vector *vl = cpl_vector_new(nel),
532 *vr = cpl_vector_new(nel),
533 *pl = cpl_vector_new(nel),
534 *pr = cpl_vector_new(nel);
536 int loffset = (int)(left + 0.5)- TRACE_REFINE_RANGE + 1,
537 roffset = (int)(right + 0.5) - TRACE_REFINE_RANGE + 1;
539 cpl_msg_debug(__func__,
"input: %f/%f -> %d/%d",
540 left, right, loffset, roffset);
542 double *diff = cpl_vector_get_data(aDiffVec);
544 for (i = 0; i < nel; i++ ) {
545 double d = diff[i + loffset - 1];
547 cpl_msg_debug(__func__,
"l i=%d / %d: %f", i, i + loffset, d);
549 cpl_vector_set(pl, i, i + loffset - 1);
551 cpl_vector_set(vl, i, d > 0 ? d : 0);
553 for (i = 0; i < nel; i++ ) {
555 double d = -diff[i + roffset - 1];
557 cpl_msg_debug(__func__,
"r i=%d / %d: %f", i, i + roffset, d);
559 cpl_vector_set(pr, i, i + roffset - 1);
561 cpl_vector_set(vr, i, d > 0 ? d : 0);
565 cpl_errorstate state = cpl_errorstate_get();
568 double center, sigma, area, bglevel = 0, mse;
569 cpl_fit_mode fitmode = CPL_FIT_CENTROID | CPL_FIT_STDEV | CPL_FIT_AREA;
570 cpl_error_code rc1 = cpl_vector_fit_gaussian(pl, NULL, vl, NULL, fitmode,
571 ¢er, &sigma, &area, &bglevel,
575 if (rc1 == CPL_ERROR_CONTINUE || rc1 == CPL_ERROR_SINGULAR_MATRIX) {
578 if (fabs(center - *aLeft) < TRACE_REFINE_MAX_SHIFT) {
582 if (rc1 != CPL_ERROR_NONE) {
584 cpl_errorstate_set(state);
589 cpl_msg_debug(__func__,
"fit l: %f %f %f (%f)", center, sigma, area, sqrt(mse));
591 cpl_error_code rc2 = cpl_vector_fit_gaussian(pr, NULL, vr, NULL, fitmode,
592 ¢er, &sigma, &area, &bglevel,
595 if (rc2 == CPL_ERROR_CONTINUE || rc2 == CPL_ERROR_SINGULAR_MATRIX) {
598 if (fabs(center - *aRight) < TRACE_REFINE_MAX_SHIFT) {
602 if (rc2 != CPL_ERROR_NONE) {
604 cpl_errorstate_set(state);
609 cpl_msg_debug(__func__,
"fit r: %f %f %f (%f)", center, sigma, area, sqrt(mse));
613 cpl_vector_dump(aDiffVec, stdout);
615 cpl_bivector *biv = cpl_bivector_wrap_vectors(pl, vl);
616 cpl_bivector_dump(biv, stdout);
617 cpl_bivector_unwrap_vectors(biv);
619 biv = cpl_bivector_wrap_vectors(pr, vr);
620 cpl_bivector_dump(biv, stdout);
621 cpl_bivector_unwrap_vectors(biv);
624 cpl_vector_delete(vl);
625 cpl_vector_delete(vr);
626 cpl_vector_delete(pl);
627 cpl_vector_delete(pr);
629 double midpoint = (*aLeft + *aRight)/2.;
631 cpl_msg_debug(__func__,
"refine: %f %f %f %f %f %f",
632 *aLeft, midpoint, *aRight,
633 left - *aLeft, mid - midpoint, right - *aRight);
637 if (fabs(mid - midpoint) > TRACE_REFINE_MAX_SHIFT) {
638 cpl_msg_debug(__func__,
"large refined shift around y=%.1f in slice %hu of "
639 "IFU %hhu: %f %f %f (%f %f %f) trace point will not be used",
640 aY, aIFU, aSlice, left + aOffset, midpoint + aOffset,
641 right + aOffset, left - *aLeft, mid - midpoint, right - *aRight);
683 static cpl_polynomial **
685 const unsigned short aSlice,
const unsigned char aIFU,
686 const unsigned int aFitorder,
const float aWSigma,
687 const float aRSigma, cpl_vector *aMSE)
689 cpl_ensure(cpl_vector_get_size(aWidths) >= 3, CPL_ERROR_ILLEGAL_INPUT, NULL);
691 cpl_ensure(aSlice >= 1 && aSlice <= kMuseSlicesPerCCD,
692 CPL_ERROR_ILLEGAL_INPUT, NULL);
695 double wmean = cpl_vector_get_mean(aWidths),
696 wmedian = cpl_vector_get_median_const(aWidths),
697 wstdev = cpl_vector_get_stdev(aWidths),
700 cpl_msg_debug(__func__,
"width (1st): mean %6.3f +/- %5.3f, median %6.3f +/- "
701 "%5.3f (%"CPL_SIZE_FORMAT
" points)", wmean, wstdev, wmedian, wmdev,
702 cpl_vector_get_size(aWidths));
704 if ((wmean - wstdev < kMuseSliceLoLikelyWidth ||
705 wmedian - wmdev < kMuseSliceLoLikelyWidth) &&
706 (wmean < kMuseSliceLoLikelyWidth || wmedian < kMuseSliceLoLikelyWidth)) {
707 cpl_msg_debug(__func__,
"slice %hu of IFU %hhu seems to be very narrow "
708 "initially (widths: mean %6.3f +/- %5.3f, median %6.3f +/- "
709 "%5.3f)!", aSlice, aIFU, wmean, wstdev, wmedian, wmdev);
711 if ((wmean + wstdev > kMuseSliceHiLikelyWidth ||
712 wmedian + wmdev > kMuseSliceHiLikelyWidth) &&
713 (wmean > kMuseSliceHiLikelyWidth || wmedian > kMuseSliceHiLikelyWidth)) {
714 cpl_msg_debug(__func__,
"slice %hu of IFU %hhu seems to be very wide "
715 "initially (widths: mean %6.3f +/- %5.3f, median %6.3f +/- "
716 "%5.3f)!", aSlice, aIFU, wmean, wstdev, wmedian, wmdev);
722 for (i = 0; i < cpl_vector_get_size(aWidths); i++) {
723 double width = cpl_vector_get(aWidths, i);
724 if (width > kMuseSliceLoLikelyWidth && width < kMuseSliceHiLikelyWidth) {
729 if (cpl_vector_get_size(aWidths) == 1) {
730 cpl_msg_warning(__func__,
"trying to remove the last vector/matrix "
731 "element in slice %hu of IFU %hhu when checking widths",
736 cpl_matrix_erase_columns(aX, i, 1);
742 wmean = cpl_vector_get_mean(aWidths);
743 wmedian = cpl_vector_get_median_const(aWidths);
744 wstdev = cpl_vector_get_stdev(aWidths);
747 cpl_msg_debug(__func__,
"width (2nd): mean %6.3f+/-%5.3f, median %6.3f+/-%5.3f (%d points)",
748 wmean, wstdev, wmedian, wmdev, cpl_vector_get_size(aWidths));
750 if ((wmean - wstdev < kMuseSliceLoLikelyWidth ||
751 wmedian - wmdev < kMuseSliceLoLikelyWidth) &&
752 (wmean < kMuseSliceLoLikelyWidth || wmedian < kMuseSliceLoLikelyWidth)) {
753 cpl_msg_warning(__func__,
"slice %hu of IFU %hhu seems to be very narrow "
754 "after iteration (widths: mean %6.3f +/- %5.3f, median %6.3f"
755 " +/- %5.3f)!", aSlice, aIFU, wmean, wstdev, wmedian, wmdev);
757 if ((wmean + wstdev > kMuseSliceHiLikelyWidth ||
758 wmedian + wmdev > kMuseSliceHiLikelyWidth) &&
759 (wmean > kMuseSliceHiLikelyWidth || wmedian > kMuseSliceHiLikelyWidth)) {
760 cpl_msg_warning(__func__,
"slice %hu of IFU %hhu seems to be very wide "
761 "after iteration (widths: mean %6.3f +/- %5.3f, median %6.3f"
762 " +/- %5.3f)!", aSlice, aIFU, wmean, wstdev, wmedian, wmdev);
766 for (i = 0; i < cpl_vector_get_size(aWidths); i++) {
767 double width = cpl_vector_get(aWidths, i);
769 cpl_msg_debug(__func__,
"i=%d: %f <? %f <? %f", i,
770 wmedian - aWSigma * wmdev, width, wmedian + aWSigma * wmdev);
772 if (width > (wmedian - aWSigma * wmdev) &&
773 width < (wmedian + aWSigma * wmdev)) {
778 if (cpl_vector_get_size(aWidths) == 1) {
779 cpl_msg_warning(__func__,
"trying to remove the last vector/matrix "
780 "element in slice %hu of IFU %hhu when checking fit "
781 "sigma", aSlice, aIFU);
785 cpl_matrix_erase_columns(aX, i, 1);
792 cpl_table *wtable = cpl_table_new(cpl_vector_get_size(aWidths));
793 cpl_table_new_column(wtable,
"widths", CPL_TYPE_DOUBLE);
794 memcpy(cpl_table_get_data_double(wtable,
"widths"),
795 cpl_vector_get_data(aWidths), cpl_vector_get_size(aWidths));
801 cpl_vector_set_size(aWidths, cpl_vector_get_size(aY));
802 memcpy(cpl_vector_get_data(aWidths), cpl_table_get_data_double(wtable,
"widths"),
803 cpl_vector_get_size(aWidths));
804 cpl_table_delete(wtable);
806 cpl_vector_fill(aMSE, FLT_MAX);
810 cpl_vector_set(aMSE, MUSE_TRACE_CENTER, mse);
812 char *dodebug = getenv(
"MUSE_DEBUG_TRACE");
813 if (dodebug && atoi(dodebug) > 0) {
814 printf(
"Polynomial trace fit for slice %hu of IFU %hhu (mse=%g, "
815 "chi**2=%g):\n", aSlice, aIFU, mse, chisq);
816 cpl_polynomial_dump(tracefit, stdout);
823 cpl_vector *edge[MUSE_TRACE_NPOLY - 1] = {
824 cpl_vector_new(cpl_vector_get_size(aY)),
825 cpl_vector_new(cpl_vector_get_size(aY))
827 for (i = 0; i < cpl_vector_get_size(aWidths); i++) {
828 double x = cpl_vector_get(aY, i),
829 halfwidth = cpl_vector_get(aWidths, i) / 2.;
831 cpl_msg_debug(__func__,
"x=%f (%f...%f)", x, x - halfwidth, x + halfwidth);
833 cpl_vector_set(edge[MUSE_TRACE_LEFT - 1], i, x - halfwidth);
834 cpl_vector_set(edge[MUSE_TRACE_RIGHT - 1], i, x + halfwidth);
838 cpl_vector_dump(edge[0], stdout);
840 cpl_vector_dump(edge[1], stdout);
844 cpl_polynomial **fit = cpl_calloc(MUSE_TRACE_NPOLY,
sizeof(cpl_polynomial *));
845 fit[MUSE_TRACE_CENTER] = tracefit;
848 for (ipoly = 1; ipoly < MUSE_TRACE_NPOLY; ipoly++) {
851 NULL, aFitorder, FLT_MAX,
853 cpl_vector_set(aMSE, ipoly, mse);
855 cpl_vector_delete(edge[ipoly - 1]);
859 printf(
"resulting polynomials (center, left, and right):\n");
860 cpl_polynomial_dump(fit[MUSE_TRACE_CENTER], stdout);
861 cpl_polynomial_dump(fit[MUSE_TRACE_LEFT], stdout);
862 cpl_polynomial_dump(fit[MUSE_TRACE_RIGHT], stdout);
864 cpl_vector_dump(aMSE, stdout);
877 {
"slice", CPL_TYPE_INT,
"",
"%02d",
"slice number", CPL_TRUE},
878 {
"y", CPL_TYPE_FLOAT,
"pix",
"%6.1f",
"y position on CCD", CPL_TRUE},
879 {
"mid", CPL_TYPE_FLOAT,
"pix",
"%8.3f",
880 "midpoint of the slice at this y position", CPL_TRUE},
881 {
"left", CPL_TYPE_FLOAT,
"pix",
"%8.3f",
882 "left edge of the slice at this y position", CPL_TRUE},
883 {
"right", CPL_TYPE_FLOAT,
"pix",
"%8.3f",
884 "right edge of the slice at this y position", CPL_TRUE},
885 { NULL, 0, NULL, NULL, NULL, CPL_FALSE }
937 cpl_table **aSamples)
939 cpl_ensure(aImage && aImage->
data, CPL_ERROR_NULL_INPUT, NULL);
940 cpl_ensure(aNSum > 0 && aEdgeFrac > 0. && aEdgeFrac < 1. && aFitorder > 0,
941 CPL_ERROR_ILLEGAL_INPUT, NULL);
944 int ny = cpl_image_get_size_y(aImage->
data),
945 npoints = (ny - 1) / aNSum;
946 unsigned short nsearchslices = kMuseSlicesPerCCD;
947 cpl_boolean slice_number_hack = getenv(
"MUSE_AIT_HACK_SLICE_NUMBER")
948 && atoi(getenv(
"MUSE_AIT_HACK_SLICE_NUMBER")) > 0
949 && atoi(getenv(
"MUSE_AIT_HACK_SLICE_NUMBER")) < 49;
951 if (slice_number_hack) {
952 nsearchslices = atoi(getenv(
"MUSE_AIT_HACK_SLICE_NUMBER"));
953 cpl_msg_warning(__func__,
"Overriding number of slices to search in IFU "
954 "%hhu to %hu!", ifu, nsearchslices);
956 cpl_msg_info(__func__,
"Working with %hu slices, %d image rows, and %d "
957 "tracepoints in IFU %hhu", nsearchslices, ny, npoints, ifu);
959 cpl_boolean chan24in2014 = (ifu == 24)
963 cpl_msg_info(__func__,
"Using overrides for IFU 24 in 2014/5: due to field "
964 "vignetting, left-hand edges of slices 37 to 48 may be only "
970 image->
data = cpl_image_duplicate(aImage->
data);
972 image->
dq = cpl_image_duplicate(aImage->
dq);
974 image->
dq = cpl_image_new(cpl_image_get_size_x(aImage->
data), ny, CPL_TYPE_INT);
977 image->
header = cpl_propertylist_duplicate(aImage->
header);
981 cpl_detector_interpolate_rejected(image->
data);
984 #define NROWCOLLAPSE 15
988 cpl_vector_delete(cut);
990 cpl_msg_error(__func__,
"Could not carry out first guess of slice positions "
991 "in IFU %hhu!", ifu);
997 cpl_table *tracetable = cpl_table_new(kMuseSlicesPerCCD);
999 cpl_msg_error(__func__,
"Could not create output trace table for IFU %hhu: "
1000 "%s", ifu, cpl_error_get_message());
1006 cpl_table_new_column(tracetable, MUSE_TRACE_TABLE_COL_SLICE_NO, CPL_TYPE_INT);
1007 cpl_table_set_column_unit(tracetable, MUSE_TRACE_TABLE_COL_SLICE_NO,
"No");
1008 cpl_table_set_column_format(tracetable, MUSE_TRACE_TABLE_COL_SLICE_NO,
"%2d");
1009 cpl_table_new_column(tracetable, MUSE_TRACE_TABLE_COL_WIDTH, CPL_TYPE_FLOAT);
1010 cpl_table_set_column_unit(tracetable, MUSE_TRACE_TABLE_COL_WIDTH,
"pix");
1011 cpl_table_set_column_format(tracetable, MUSE_TRACE_TABLE_COL_WIDTH,
"%6.3f");
1013 for (ipoly = 0; ipoly < MUSE_TRACE_NPOLY; ipoly++) {
1016 for (j = 0; j <= aFitorder; j++) {
1018 colname = cpl_sprintf(MUSE_TRACE_TABLE_COL_COEFF, ipoly, j);
1019 cpl_table_new_column(tracetable, colname, CPL_TYPE_DOUBLE);
1021 cpl_table_set_column_unit(tracetable, colname,
"pix");
1022 cpl_table_set_column_format(tracetable, colname,
"%12.5e");
1025 colname = cpl_sprintf(MUSE_TRACE_TABLE_COL_MSE, ipoly);
1026 cpl_table_new_column(tracetable, colname, CPL_TYPE_DOUBLE);
1027 cpl_table_set_column_unit(tracetable, colname,
"pix");
1028 cpl_table_set_column_format(tracetable, colname,
"%12.5e");
1032 int isamplesrow = -1;
1036 kMuseSlicesPerCCD * npoints);
1041 cpl_image *shiftdiff = cpl_image_duplicate(image->
data);
1042 cpl_image_shift(shiftdiff, 1, 0);
1044 cpl_image_multiply_scalar(shiftdiff, -1);
1045 cpl_image_add(shiftdiff, image->
data);
1048 unsigned short islice;
1049 for (islice = 0; islice < kMuseSlicesPerCCD; islice++) {
1051 cpl_matrix *xtrace = cpl_matrix_new(1, npoints);
1052 cpl_vector *ytrace = cpl_vector_new(npoints);
1054 cpl_vector *widths = cpl_vector_new(npoints);
1058 for (j = 1, k = 0, knum = 1; j <= ny - aNSum; j += aNSum, k++, knum++) {
1061 int noffset = (int)cpl_vector_get(centers, islice) - TRACE_BINSIZE,
1063 ihi = (int)cpl_vector_get(centers, islice) + TRACE_BINSIZE,
1065 jhi = j + aNSum - 1;
1067 cpl_msg_debug(__func__,
"slice=%hu, center=%f, cut region: %d,%d,%d,%d",
1068 islice + 1, cpl_vector_get(centers, islice), ilo, ihi, jlo, jhi);
1070 cpl_image *tmp = cpl_image_collapse_window_create(image->
data,
1073 cpl_image_divide_scalar(tmp, aNSum);
1074 cut = cpl_vector_new_from_image_row(tmp, 1);
1075 cpl_image_delete(tmp);
1079 cpl_boolean highSN = CPL_TRUE;
1082 cpl_vector_delete(cut);
1085 double left1 = left + noffset;
1087 cpl_errorstate state = cpl_errorstate_get();
1090 tmp = cpl_image_collapse_window_create(shiftdiff, ilo, jlo, ihi, jhi,
1092 cpl_image_divide_scalar(tmp, aNSum);
1093 cut = cpl_vector_new_from_image_row(tmp, 1);
1094 cpl_image_delete(tmp);
1096 (jlo + jhi) / 2., islice + 1, ifu);
1097 cpl_vector_delete(cut);
1100 if (midpoint < 0 && midpoint > -2 && islice+1 >= 37 && chan24in2014) {
1101 cpl_msg_debug(__func__,
"IFU24 problem? slice %d, y = %f: refined "
1102 "%f < %f < %f", islice+1, ((
double)jlo + jhi) / 2.,
1103 left, midpoint, right);
1108 cpl_msg_debug(__func__,
"IFU24 problem! slice %d y = %f: corrected "
1109 "%f < %f < %f", islice+1, ((
double)jlo + jhi) / 2.,
1110 left, (left + right) / 2., right);
1113 midpoint = (left + right) / 2.;
1117 cpl_matrix_set(xtrace, 0, k, (jlo + jhi) / 2.);
1118 cpl_vector_set(ytrace, k, midpoint);
1119 cpl_vector_set(widths, k, right - left);
1123 if (++isamplesrow+1 > cpl_table_get_nrow(*aSamples)) {
1124 cpl_table_set_size(*aSamples, isamplesrow+1);
1126 cpl_table_set_int(*aSamples,
"slice", isamplesrow, islice + 1);
1127 cpl_table_set_float(*aSamples,
"y", isamplesrow, (jlo + jhi) / 2.);
1128 cpl_table_set_float(*aSamples,
"mid", isamplesrow, midpoint);
1129 cpl_table_set_float(*aSamples,
"left", isamplesrow, left);
1130 cpl_table_set_float(*aSamples,
"right", isamplesrow, right);
1140 cpl_errorstate_set(state);
1145 cpl_msg_debug(__func__,
"slice=%hu, nfailed=%d, tracepoint=%d, midpoint="
1146 "%f, y=%d", islice + 1, nfailed, knum, midpoint, j);
1148 if (nfailed > 0.1*npoints && midpoint == -1.) {
1149 cpl_msg_warning(__func__,
"failure %d in slice %hu of IFU %hhu: lost "
1150 "trace at y=%d (tracepoint %d of %d)", nfailed,
1151 islice + 1, ifu, j, knum, npoints);
1155 int oldsize = cpl_vector_get_size(ytrace);
1156 cpl_vector_set_size(ytrace, oldsize - 1);
1157 cpl_matrix_resize(xtrace, 0, 0, 0, -1);
1158 cpl_vector_set_size(widths, oldsize - 1);
1164 printf(
"k=%d tracepoints (should be equal to %d)\n", k, npoints);
1165 cpl_matrix_dump(xtrace, stdout), fflush(stdout);
1166 cpl_vector_dump(ytrace, stdout), fflush(stdout);
1170 const float kWSigma = 5, kRSigma = 5;
1171 cpl_msg_debug(__func__,
"Working on slice %hu of IFU %hhu (kWSigma=%f, "
1172 "kRSigma=%f)", islice + 1, ifu, kWSigma, kRSigma);
1173 cpl_vector *mse = cpl_vector_new(MUSE_TRACE_NPOLY);
1174 cpl_vector_fill(mse, -1.);
1176 islice + 1, ifu, aFitorder,
1177 kWSigma, kRSigma, mse);
1179 double wmean = cpl_vector_get_mean(widths);
1182 cpl_matrix_delete(xtrace);
1183 cpl_vector_delete(ytrace);
1184 cpl_vector_delete(widths);
1188 cpl_msg_error(__func__,
"The trace fit in slice %hu of IFU %hhu failed",
1190 cpl_vector_delete(mse);
1195 cpl_table_set_int(tracetable, MUSE_TRACE_TABLE_COL_SLICE_NO, islice,
1197 cpl_table_set_float(tracetable, MUSE_TRACE_TABLE_COL_WIDTH, islice, wmean);
1198 for (ipoly = 0; ipoly < MUSE_TRACE_NPOLY; ipoly++) {
1199 if (!tracefits[ipoly]) {
1200 cpl_msg_error(__func__,
"The fit %d in slice %hu of IFU %hhu failed",
1201 ipoly, islice + 1, ifu);
1204 char *colname = cpl_sprintf(MUSE_TRACE_TABLE_COL_MSE, ipoly);
1205 cpl_table_set_double(tracetable, colname, islice,
1206 cpl_vector_get(mse, ipoly));
1209 for (j = 0; j <= aFitorder; j++) {
1210 cpl_size pows[1] = { j };
1212 colname = cpl_sprintf(MUSE_TRACE_TABLE_COL_COEFF, ipoly, j);
1213 cpl_errorstate prestate = cpl_errorstate_get();
1214 double coeff = cpl_polynomial_get_coeff(tracefits[ipoly], pows);
1215 #define SLOPE_WARN_LIMIT 0.015
1216 if (j == 1 && fabs(coeff) > SLOPE_WARN_LIMIT) {
1217 cpl_msg_warning(__func__,
"1st order coefficient of the %s tracing "
1218 "polynomial is unexpectedly large in slice %hu of IFU"
1219 " %hhu: |%f| > %f", muse_trace_poly_strings[ipoly],
1220 islice + 1, ifu, coeff, SLOPE_WARN_LIMIT);
1222 cpl_table_set_double(tracetable, colname, islice, coeff);
1223 if (!cpl_errorstate_is_equal(prestate)) {
1224 cpl_msg_warning(__func__,
"Problem writing to field %s in trace table"
1225 " for IFU %hhu: %s", colname, ifu,
1226 cpl_error_get_message());
1231 cpl_vector_delete(mse);
1234 cpl_vector_delete(centers);
1235 cpl_image_delete(shiftdiff);
1238 cpl_table_set_size(*aSamples, ++isamplesrow);
1241 if (slice_number_hack) {
1242 cpl_msg_warning(__func__,
"Will try to fix the slices in IFU %hhu, %"
1243 CPL_SIZE_FORMAT
" seem to be bad!", ifu,
1244 cpl_table_count_invalid(tracetable, MUSE_TRACE_TABLE_COL_WIDTH));
1245 cpl_table_dump(tracetable, 0, 100, stdout);
1248 for (islice = 0; islice < cpl_table_get_nrow(tracetable); islice++) {
1249 double width = cpl_table_get(tracetable, MUSE_TRACE_TABLE_COL_WIDTH, islice, NULL);
1251 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_OUTPUT,
"slice %hu of "
1252 "IFU %hhu was narrow (%f), erased it", islice + 1,
1254 cpl_table_erase_window(tracetable, islice--, 1);
1258 for (islice = 0; islice < cpl_table_get_nrow(tracetable); islice++) {
1259 double cen = cpl_table_get(tracetable,
"tc0_00", islice, NULL);
1260 if (cen - last > 100) {
1261 unsigned short iref = islice - 1;
1262 cpl_table *row = cpl_table_extract(tracetable, iref, 1);
1264 double offset = 84.5;
1265 cpl_table_add_scalar(row, MUSE_TRACE_TABLE_COL_SLICE_NO, 1);
1266 cpl_table_add_scalar(row,
"tc0_00", offset);
1267 cpl_table_add_scalar(row,
"tc1_00", offset);
1268 cpl_table_add_scalar(row,
"tc2_00", offset);
1269 cpl_table_add_scalar(row,
"MSE0", 1.);
1270 cpl_table_add_scalar(row,
"MSE1", 1.);
1271 cpl_table_add_scalar(row,
"MSE2", 1.);
1272 cpl_table_insert(tracetable, row, islice);
1274 printf(
"rowtable (islice=%hu):\n", islice);
1275 cpl_table_dump(row, 0, 100, stdout);
1277 printf(
"tracetable (islice=%hu):\n", islice);
1278 cpl_table_dump(tracetable, islice - 2, 10, stdout);
1281 cen = cpl_table_get(row,
"tc0_00", 0, NULL);
1282 cpl_table_delete(row);
1283 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_OUTPUT,
"slice was "
1284 "missing before slice %hu of IFU %hhu, copied "
1285 "from slice %hu", islice + 1, ifu, iref + 1);
1289 for (islice = 0; islice < cpl_table_get_nrow(tracetable); islice++) {
1290 unsigned short sliceno = cpl_table_get_int(tracetable,
1291 MUSE_TRACE_TABLE_COL_SLICE_NO,
1293 if (sliceno != islice + 1) {
1294 cpl_msg_warning(__func__,
"Resetting entry at table row index %hu to "
1295 "correct slice number in IFU %hhu (%hu instead of %hu)",
1296 islice, ifu, islice + 1, sliceno);
1297 cpl_table_set_int(tracetable, MUSE_TRACE_TABLE_COL_SLICE_NO, islice,
1304 cpl_msg_info(__func__,
"Found %"CPL_SIZE_FORMAT
" slices of width %4.1f+/-%3.1f"
1305 " pix (%4.1f pix...%4.1f pix) in IFU %hhu",
1306 cpl_table_get_nrow(tracetable),
1307 cpl_table_get_column_mean(tracetable, MUSE_TRACE_TABLE_COL_WIDTH),
1308 cpl_table_get_column_stdev(tracetable, MUSE_TRACE_TABLE_COL_WIDTH),
1309 cpl_table_get_column_min(tracetable, MUSE_TRACE_TABLE_COL_WIDTH),
1310 cpl_table_get_column_max(tracetable, MUSE_TRACE_TABLE_COL_WIDTH),
1334 return (cpl_table_get_ncol(aTable) - 2) / MUSE_TRACE_NPOLY - 2;
1359 const unsigned short aSlice)
1361 cpl_ensure(aTable, CPL_ERROR_NULL_INPUT, NULL);
1362 cpl_ensure(aSlice >= 1 && aSlice <= kMuseSlicesPerCCD,
1363 CPL_ERROR_ILLEGAL_INPUT, NULL);
1366 int irow, nrow = cpl_table_get_nrow(aTable);
1367 for (irow = 0; irow < nrow; irow++) {
1369 unsigned short slice = cpl_table_get_int(aTable,
1370 MUSE_TRACE_TABLE_COL_SLICE_NO,
1372 if (slice == aSlice && !err) {
1376 cpl_ensure(irow < nrow, CPL_ERROR_DATA_NOT_FOUND, NULL);
1378 cpl_polynomial **ptrace = cpl_calloc(MUSE_TRACE_NPOLY,
1379 sizeof(cpl_polynomial *));
1382 for (ipoly = 0; ipoly < MUSE_TRACE_NPOLY; ipoly++) {
1384 ptrace[ipoly] = cpl_polynomial_new(1);
1388 for (k = 0; k <= traceorder; k++) {
1389 cpl_size pows[1] = { k };
1390 sprintf(colname, MUSE_TRACE_TABLE_COL_COEFF, ipoly, k);
1392 cpl_polynomial_set_coeff(ptrace[ipoly], pows,
1393 cpl_table_get(aTable, colname, irow, &err));
1395 cpl_polynomial_delete(ptrace[MUSE_TRACE_CENTER]);
1396 cpl_polynomial_delete(ptrace[MUSE_TRACE_LEFT]);
1397 cpl_polynomial_delete(ptrace[MUSE_TRACE_RIGHT]);
1399 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_OUTPUT,
"Trace table "
1400 "broken in slice %hu (row index %d) column %s",
1401 aSlice, irow, colname);
1422 cpl_polynomial_delete(aPolys[MUSE_TRACE_CENTER]);
1423 cpl_polynomial_delete(aPolys[MUSE_TRACE_LEFT]);
1424 cpl_polynomial_delete(aPolys[MUSE_TRACE_RIGHT]);
1430 muse_trace_plot_located_slices(cpl_vector *aRowVec, cpl_vector *aCenters,
1431 double aMedian,
double aMDev,
double aLimit,
1432 const unsigned char aIFU)
1434 #if HAVE_POPEN && HAVE_PCLOSE
1435 FILE *gp = popen(
"gnuplot -persist",
"w");
1437 cpl_msg_error(__func__,
"could not open gnuplot for plotting");
1442 char dirtemplate[] =
"/tmp/muse_trace_plot_located_slices_XXXXXX";
1443 char *dirname = mkdtemp(dirtemplate);
1448 char dirname[] =
"/tmp";
1450 char *out1 = cpl_sprintf(
"%s/row.dat", dirname);
1451 FILE *fp = fopen(out1,
"w");
1452 cpl_vector_dump(aRowVec, fp);
1454 char *out2 = cpl_sprintf(
"%s/centers.dat", dirname);
1455 fp = fopen(out2,
"w");
1456 cpl_vector_dump(aCenters, fp);
1459 fprintf(gp,
"set title \"located slices (IFU %hhu): median %.2f+/-%.2f, limit"
1460 " %.2f\"\nunset key\nset style fill solid 0.5\n", aIFU, aMedian, aMDev,
1462 fprintf(gp,
"median(x)=%e\nlimit(x)=%e\nlo(x)=%e\n",
1463 aMedian, aLimit, aMedian - aMDev);
1464 fprintf(gp,
"set xrange [%d:%"CPL_SIZE_FORMAT
"]\n", 1, cpl_vector_get_size(aRowVec));
1465 fprintf(gp,
"set yrange [%e:%e]\n", aLimit - 0.5*aMDev, aMedian + 1.3*aMDev);
1466 fprintf(gp,
"plot lo(x) w filledcu y1=%e, "
1467 " median(x) t \"median\", limit(x) t \"limit\" w l lw 2, "
1468 " \"%s\" w l lt 7, \"%s\" u 2:(%e):1 w p lt -1, "
1469 " \"%s\" u 2:(%e):1 w labels\n",
1470 aMedian+aMDev, out1, out2, aMedian, out2, aMedian+200);
1477 #if HAVE_MKDTEMP && HAVE_UNISTD_H
1478 int rc = rmdir(dirname);
1480 cpl_msg_warning(__func__,
"Used %s for plotting, please clean it manually!",
1511 unsigned short aSlice1,
unsigned short aSlice2,
1514 #if HAVE_POPEN && HAVE_PCLOSE
1515 cpl_ensure_code(aSamples, CPL_ERROR_NULL_INPUT);
1517 cpl_ensure_code(rc == CPL_ERROR_NONE, rc);
1519 if (aSlice1 < 1 || aSlice1 > kMuseSlicesPerCCD || aSlice1 > aSlice2 ||
1520 aSlice2 < 1 || aSlice2 > kMuseSlicesPerCCD) {
1521 fprintf(stderr,
"Warning: resetting slice numbers (%hu to %hu does not make"
1522 " sense)!\n", aSlice1, aSlice2);
1523 aSlice1 = kMuseSlicesPerCCD / 2;
1524 aSlice2 = kMuseSlicesPerCCD / 2 + 1;
1526 if (aSlice2 - aSlice1 > 10) {
1527 fprintf(stderr,
"Warning: plotting %hu slices may take a long time and "
1528 "RAM/disk space!\n", aSlice2 - aSlice1 + 1);
1530 printf(
"Plotting slices %hu to %hu\n", aSlice1, aSlice2);
1532 FILE *gp = popen(
"gnuplot",
"w");
1534 return CPL_ERROR_ASSIGNING_STREAM;
1537 int nx = -1, ny = kMuseOutputYTop;
1538 const float *data = NULL;
1540 nx = cpl_image_get_size_x(aImage->
data);
1541 ny = cpl_image_get_size_x(aImage->
data);
1542 data = cpl_image_get_data_float_const(aImage->
data);
1548 char dirtemplate[] =
"/tmp/muse_trace_plot_samples_XXXXXX";
1549 char *dirname = mkdtemp(dirtemplate);
1551 return CPL_ERROR_FILE_NOT_CREATED;
1554 char dirname[] =
"/tmp";
1556 FILE *tf = NULL, *sf = NULL;
1559 t_out = cpl_sprintf(
"%s/muse_trace_plot_flatimage.dat", dirname);
1560 tf = fopen(t_out,
"w+");
1562 cpl_error_set_message(__func__, CPL_ERROR_FILE_NOT_CREATED,
"\"%s\"",
1565 return CPL_ERROR_FILE_NOT_CREATED;
1568 char *s_out = cpl_sprintf(
"%s/muse_trace_plot_samples.dat", dirname);
1569 sf = fopen(s_out,
"w+");
1571 cpl_error_set_message(__func__, CPL_ERROR_FILE_NOT_CREATED,
"%s", s_out);
1574 return CPL_ERROR_FILE_NOT_CREATED;
1578 int i, lplot = INT_MAX, rplot = INT_MIN;
1579 unsigned short nslice;
1580 for (nslice = aSlice1; nslice <= aSlice2; nslice++) {
1582 for (i = 0; i < cpl_table_get_nrow(aSamples); i++) {
1583 if (nslice != cpl_table_get_int(aSamples,
"slice", i, NULL)) {
1587 float l = cpl_table_get_float(aSamples,
"left", i, NULL),
1588 r = cpl_table_get_float(aSamples,
"right", i, NULL);
1589 fprintf(sf,
"%g %g %g %g\n",
1590 cpl_table_get_float(aSamples,
"y", i, NULL),
1591 cpl_table_get_float(aSamples,
"mid", i, NULL), l, r);
1592 if ((
int)floor(l) < lplot) {
1595 if ((
int)floor(r) > rplot) {
1605 double *c = (
double *)cpl_calloc(order + 1,
sizeof(
double));
1608 for (ipoly = 0; ipoly < MUSE_TRACE_NPOLY; ipoly++) {
1609 for (i = 0; i <= order; i++) {
1610 char *colname = cpl_sprintf(MUSE_TRACE_TABLE_COL_COEFF, ipoly, i);
1611 c[i] = cpl_table_get_double(aTrace, colname, nslice-1, NULL);
1616 fprintf(gp,
"p%02hu%1d(x) = (%g)", nslice, ipoly, c[0]);
1617 for (i = 1; i <= order; i++) {
1618 fprintf(gp,
" + (%g) * x**(%d)", c[i], i);
1627 for (i = lplot - 1; i < rplot; i++) {
1629 for (j = 0; j < ny; j++) {
1630 if (i < 0 || i >= nx || j < 0 || j >= ny) {
1633 fprintf(tf,
"%d %d %f\n", i+1, j+1, data[i + j*nx]);
1636 printf(
"Written \"%s\".\n", t_out);
1639 printf(
"Written \"%s\".\n", s_out);
1643 fprintf(gp,
"set title \"trace result, slices %hu to %hu\"\n", aSlice1, aSlice2);
1644 fprintf(gp,
"set palette gray\n");
1645 fprintf(gp,
"unset key\n");
1648 fprintf(gp,
"set samples %d\n", ny);
1650 fprintf(gp,
"set parametric\n");
1652 fprintf(gp,
"set xrange [%d:%d]\n", lplot, rplot);
1653 fprintf(gp,
"set yrange [%d:%d]\n", 1, ny);
1654 fprintf(gp,
"set trange [%d:%d]\n", 1, ny);
1656 fprintf(gp,
"set cbrange [1e-4:1.5]\n");
1659 fprintf(gp,
"plot ");
1661 fprintf(gp,
"\"%s\" w image, ", t_out);
1663 fprintf(gp,
"\"%s\" u 2:1 t \"center points\" w p pt 2 lt rgb \"blue\" ps 1.2, "
1664 "\"%s\" u 3:1 t \"edge points left\" w p pt 2 lt rgb \"red\" ps 0.8, "
1665 "\"%s\" u 4:1 t \"edge points right\" w p pt 2 lt rgb \"green\" ps 0.8",
1666 s_out, s_out, s_out);
1669 for (nslice = aSlice1; nslice <= aSlice2; nslice++) {
1670 fprintf(gp,
", p%02hu0(t),t t \"center\" w l lt rgb \"dark-blue\" lw 2, "
1671 "p%02hu1(t),t t \"left\" w l lt rgb \"dark-red\" lw 1, "
1672 "p%02hu2(t),t t \"right\" w l lt rgb \"forest-green\" lw 1",
1673 nslice, nslice, nslice);
1681 printf(
"Press ENTER to end program and close plot\n");
1691 return CPL_ERROR_NONE;
1693 return CPL_ERROR_UNSUPPORTED_MODE;
1722 unsigned short aSlice2)
1724 #if HAVE_POPEN && HAVE_PCLOSE
1725 cpl_ensure_code(aSamples, CPL_ERROR_NULL_INPUT);
1727 cpl_ensure_code(rc == CPL_ERROR_NONE, rc);
1729 if (aSlice1 < 1 || aSlice1 > kMuseSlicesPerCCD || aSlice1 > aSlice2 ||
1730 aSlice2 < 1 || aSlice2 > kMuseSlicesPerCCD) {
1731 fprintf(stderr,
"Warning: resetting slice numbers (%hu to %hu does not make"
1732 " sense)!\n", aSlice1, aSlice2);
1733 aSlice1 = kMuseSlicesPerCCD / 2;
1734 aSlice2 = kMuseSlicesPerCCD / 2 + 1;
1736 printf(
"Plotting slices %hu to %hu\n", aSlice1, aSlice2);
1738 FILE *gp = popen(
"gnuplot",
"w");
1740 return CPL_ERROR_ASSIGNING_STREAM;
1743 int nrow = cpl_table_get_nrow(aSamples);
1744 const int *sdata = cpl_table_get_data_int_const(aSamples,
"slice");
1745 const float *ydata = cpl_table_get_data_float_const(aSamples,
"y"),
1746 *ldata = cpl_table_get_data_float_const(aSamples,
"left"),
1747 *rdata = cpl_table_get_data_float_const(aSamples,
"right");
1750 fprintf(gp,
"set title \"trace slice widths, slices %hu to %hu\"\n",
1752 fprintf(gp,
"set key outside below\n");
1754 fprintf(gp,
"set xrange [%d:%d]\n", 1, kMuseOutputYTop);
1755 fprintf(gp,
"set yrange [%f:%f]\n", kMuseSliceLoLikelyWidth,
1756 kMuseSliceHiLikelyWidth);
1757 fprintf(gp,
"set xlabel \"y position on CCD [pix]\"\n");
1758 fprintf(gp,
"set ylabel \"slice width at y position [pix]\"\n");
1761 double dslice = (aSlice2 - aSlice1) / 255.;
1766 fprintf(gp,
"plot ");
1767 unsigned short nslice;
1768 for (nslice = aSlice1; nslice <= aSlice2; nslice++) {
1771 fprintf(gp,
"\"-\" t \"slice %02hu\" w lp ps 0.8 lt rgb \"#%02x%02x%02x\"",
1773 (
int)((nslice - aSlice1) / dslice),
1774 (
int)((aSlice2 - nslice) / dslice),
1776 if (nslice == aSlice2) {
1783 for (nslice = aSlice1; nslice <= aSlice2; nslice++) {
1785 for (i = 0; i < nrow; i++) {
1786 if (nslice == sdata[i]) {
1787 fprintf(gp,
"%f %f\n", ydata[i], rdata[i]-ldata[i]);
1790 fprintf(gp,
"EOF\n");
1797 printf(
"Press ENTER to end program and close plot\n");
1800 return CPL_ERROR_NONE;
1802 return CPL_ERROR_UNSUPPORTED_MODE;
cpl_polynomial ** muse_trace_table_get_polys_for_slice(const cpl_table *aTable, const unsigned short aSlice)
construct polynomial from the trace table entry for the given slice
static cpl_polynomial ** muse_trace_iterate_fit(cpl_matrix *aX, cpl_vector *aY, cpl_vector *aWidths, const unsigned short aSlice, const unsigned char aIFU, const unsigned int aFitorder, const float aWSigma, const float aRSigma, cpl_vector *aMSE)
iterate the tracing solution to remove outliers
int muse_trace_table_get_order(const cpl_table *aTable)
determine order of tracing polynomial from table
void muse_image_delete(muse_image *aImage)
Deallocate memory associated to a muse_image object.
cpl_size * muse_quadrants_get_window(const muse_image *aImage, unsigned char aQuadrant)
Determine the data window of a given quadrant on the CCD.
cpl_error_code muse_trace_plot_samples(cpl_table *aSamples, cpl_table *aTrace, unsigned short aSlice1, unsigned short aSlice2, muse_image *aImage)
Plotting of trace sample points and solution using gnuplot.
cpl_table * muse_trace(const muse_image *aImage, int aNSum, double aEdgeFrac, int aFitorder, cpl_table **aSamples)
carry out the tracing of the slices on CCD, save parameters in table
unsigned char muse_utils_get_ifu(const cpl_propertylist *aHeaders)
Find out the IFU/channel from which this header originated.
cpl_image * data
the data extension
static cpl_vector * muse_trace_horizontal_cut(const muse_image *aImage, unsigned int aNRows)
Create a vector containing a representative horizontal image cut.
const char * muse_pfits_get_dateobs(const cpl_propertylist *aHeaders)
find out the date of observations
Structure definition of MUSE three extension FITS file.
cpl_propertylist * header
the FITS header
double muse_trace_edgefinder(const cpl_vector *aDataVec, double aFrac, double *aLeft, double *aRight, cpl_boolean *aHighSN, const unsigned char aIFU)
Find the midpoint and edges of a cut through a slice.
cpl_error_code muse_cpltable_check(const cpl_table *aTable, const muse_cpltable_def *aDef)
Check whether the table contains the fields of the definition.
static double muse_trace_refine_edge(cpl_vector *aDiffVec, double *aLeft, double *aRight, int aOffset, double aY, const unsigned short aSlice, const unsigned char aIFU)
Find more exact midpoint and edge positions using a difference vector of the input data...
void muse_trace_polys_delete(cpl_polynomial *aPolys[])
Delete the multi-polynomial array created in relation to tracing.
cpl_image * dq
the data quality extension
cpl_table * muse_cpltable_new(const muse_cpltable_def *aDef, cpl_size aLength)
Create an empty table according to the specified definition.
cpl_error_code muse_cplvector_erase_element(cpl_vector *aVector, int aElement)
delete the given element from the input vector
cpl_polynomial * muse_utils_iterate_fit_polynomial(cpl_matrix *aPos, cpl_vector *aVal, cpl_vector *aErr, cpl_table *aExtra, const unsigned int aOrder, const double aRSigma, double *aMSE, double *aChiSq)
Iterate a polynomial fit.
const muse_cpltable_def muse_tracesamples_def[]
MUSE tracing sample points table definition.
cpl_error_code muse_image_reject_from_dq(muse_image *aImage)
Reject pixels of a muse_image depending on its DQ data.
Definition of a cpl table structure.
double muse_cplvector_get_adev_const(const cpl_vector *aVector, double aCenter)
Compute the average absolute deviation of a (constant) vector.
muse_image * muse_image_new(void)
Allocate memory for a new muse_image object.
cpl_error_code muse_trace_plot_widths(cpl_table *aSamples, unsigned short aSlice1, unsigned short aSlice2)
Plotting the width from trace sample points using gnuplot.
cpl_vector * muse_trace_locate_slices(cpl_vector *aRowVec, const unsigned short aNSlices, double aFrac, const unsigned char aIFU)
Find all slice midpoints across a CCD.