00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifdef HAVE_CONFIG_H
00023 #include <config.h>
00024 #endif
00025
00026
00027
00028
00029 #if HAVE_POPEN && HAVE_PCLOSE
00030 #define _BSD_SOURCE
00031 #endif
00032 #include <cpl.h>
00033 #include <string.h>
00034 #undef __USE_MISC
00035 #include <math.h>
00036
00037 #include "muse_tracing.h"
00038 #include "muse_instrument.h"
00039
00040 #include "muse_cplwrappers.h"
00041 #include "muse_pfits.h"
00042 #include "muse_quadrants.h"
00043 #include "muse_utils.h"
00044
00045
00049
00050
00053
00054 static const char *muse_trace_poly_strings[] = {
00055 "central",
00056 "left",
00057 "right"
00058 };
00059
00060 static void muse_trace_plot_located_slices(cpl_vector *, cpl_vector *, double, double, double, const unsigned char);
00061
00062
00076
00077 static cpl_vector *
00078 muse_trace_horizontal_cut(const muse_image *aImage, unsigned int aNRows)
00079 {
00080 cpl_ensure(aImage && aImage->data, CPL_ERROR_NULL_INPUT, NULL);
00081
00082
00083
00084 cpl_size ymid = cpl_image_get_size_y(aImage->data) / 2,
00085 *w = muse_quadrants_get_window(aImage, 1);
00086 if (w) {
00087 ymid = w[3];
00088 cpl_free(w);
00089 }
00090 int y1 = ymid - 1 - aNRows,
00091 y2 = ymid - 1,
00092 y3 = ymid + 1,
00093 y4 = ymid + 1 + aNRows;
00094 cpl_msg_debug(__func__, "IFU %hhu: ymid=%"CPL_SIZE_FORMAT", region=%d..%d, %d..%d",
00095 muse_utils_get_ifu(aImage->header), ymid, y1, y2, y3, y4);
00096
00097
00098 int nx = cpl_image_get_size_x(aImage->data);
00099 cpl_image *tmp1 = cpl_image_collapse_window_create(aImage->data, 1, y1, nx, y2, 0),
00100 *tmp2 = cpl_image_collapse_window_create(aImage->data, 1, y3, nx, y4, 0);
00101
00102 cpl_image_normalise(tmp1, CPL_NORM_MEAN);
00103 cpl_image_normalise(tmp2, CPL_NORM_MEAN);
00104
00105 cpl_image *tmax = cpl_image_new(nx, 1, CPL_TYPE_FLOAT);
00106 int i;
00107 for (i = 1; i <= nx; i++) {
00108 int err;
00109 cpl_image_set(tmax, i, 1,
00110 fmax(cpl_image_get(tmp1, i, 1, &err),
00111 cpl_image_get(tmp2, i, 1, &err)));
00112 }
00113 #if 0
00114 cpl_image_save(tmp1, "trace_tmp1.fits", CPL_TYPE_FLOAT, NULL, CPL_IO_CREATE);
00115 cpl_image_save(tmp2, "trace_tmp2.fits", CPL_TYPE_FLOAT, NULL, CPL_IO_CREATE);
00116 cpl_image_save(tmax, "trace_tmax.fits", CPL_TYPE_FLOAT, NULL, CPL_IO_CREATE);
00117 cpl_msg_debug(__func__, "Saved collapsed rows to trace_{tmp1,tmp2,tmax}.fits");
00118 #endif
00119 cpl_image_delete(tmp1);
00120 cpl_image_delete(tmp2);
00121
00122 cpl_vector *cut = cpl_vector_new_from_image_row(tmax, 1);
00123 cpl_image_delete(tmax);
00124 return cut;
00125 }
00126
00127
00160
00161 cpl_vector *
00162 muse_trace_locate_slices(cpl_vector *aRowVec, const unsigned short aNSlices,
00163 double aFrac, const unsigned char aIFU)
00164 {
00165 cpl_ensure(aRowVec, CPL_ERROR_NULL_INPUT, NULL);
00166 cpl_ensure(aFrac > 0. && aFrac < 1., CPL_ERROR_ILLEGAL_INPUT, NULL);
00167 cpl_vector *centers = cpl_vector_new(aNSlices),
00168 *widths = cpl_vector_new(aNSlices);
00169 double f = aFrac;
00170
00171
00172
00173 while (1) {
00174 double median = cpl_vector_get_median_const(aRowVec),
00175 mdev = muse_cplvector_get_adev_const(aRowVec, median),
00176 detlimit = f*median;
00177
00178 cpl_msg_debug(__func__, "median=%f, mdev=%f, fraction=%f --> edge detection"
00179 " limit=%f (IFU %hhu)", median, mdev, f, detlimit, aIFU);
00180
00181
00182
00183 double ledge = 0., redge = 0.;
00184 int i;
00185 for (i = 0; i <= kMuseSliceSearchRegion; i++) {
00186 if (cpl_vector_get(aRowVec, i) >= detlimit) {
00187 ledge = i - 0.5;
00188 break;
00189 }
00190 }
00191 if (i == kMuseSliceSearchRegion) {
00192 cpl_msg_error(__func__, "Search for first slice (left-edge) failed in IFU"
00193 " %hhu", aIFU);
00194 cpl_vector_delete(centers);
00195 centers = NULL;
00196 break;
00197 }
00198
00199
00200
00201 for (i = ledge + 1.5; i <= ledge + kMuseSliceMaxWidth; i++) {
00202 if (cpl_vector_get(aRowVec, i) <= detlimit) {
00203 redge = i - 0.5;
00204 break;
00205 }
00206 }
00207 if (i == ledge + kMuseSliceMaxWidth) {
00208 cpl_msg_error(__func__, "Search for first slice (right-edge) failed in "
00209 "IFU %hhu", aIFU);
00210 cpl_vector_delete(centers);
00211 centers = NULL;
00212 break;
00213 }
00214
00215 double width = redge - ledge;
00216 if (width < kMuseSliceLoLikelyWidth) {
00217 cpl_msg_error(__func__, "Initial slice is too narrow (%.2f pix, %.1f..%.1f)"
00218 " -> search failed in IFU %hhu", width, ledge, redge, aIFU);
00219 cpl_error_set(__func__, CPL_ERROR_ACCESS_OUT_OF_RANGE);
00220 cpl_vector_delete(centers);
00221 centers = NULL;
00222 break;
00223 }
00224 if (width > kMuseSliceHiLikelyWidth) {
00225 cpl_msg_error(__func__, "Initial slice is too wide (%.2f pix, %.1f..%.1f)"
00226 " -> search failed in IFU %hhu", width, ledge, redge, aIFU);
00227 cpl_error_set(__func__, CPL_ERROR_ACCESS_OUT_OF_RANGE);
00228 cpl_vector_delete(centers);
00229 centers = NULL;
00230 break;
00231 }
00232
00233
00234 cpl_vector_set(centers, 0, round((ledge + redge) / 2.) + 1);
00235 cpl_vector_set(widths, 0, width);
00236
00237
00238 unsigned short j;
00239 for (j = 1; j < aNSlices; j++) {
00240 for (i = redge + 1.5; i <= redge + kMuseSliceMaxWidth; i++) {
00241 if (cpl_vector_get(aRowVec, i) >= detlimit) {
00242 ledge = i - 0.5;
00243 break;
00244 }
00245 }
00246 if (i == redge + kMuseSliceMaxWidth) {
00247 cpl_msg_error(__func__, "Search for slice %hu (left-edge) failed in IFU"
00248 " %hhu", j, aIFU);
00249 cpl_vector_delete(centers);
00250 cpl_vector_delete(widths);
00251 return NULL;
00252 }
00253
00254 for (i = ledge + 1.5; i <= ledge + kMuseSliceMaxWidth; i++) {
00255 if (cpl_vector_get(aRowVec, i) <= detlimit) {
00256 redge = i - 0.5;
00257 break;
00258 }
00259 }
00260 if (i == ledge + kMuseSliceMaxWidth) {
00261 cpl_msg_error(__func__, "Search for slice %hu (right-edge) failed in"
00262 " IFU %hhu", j, aIFU);
00263 cpl_vector_delete(centers);
00264 cpl_vector_delete(widths);
00265 return NULL;
00266 }
00267
00268
00269 width = redge - ledge;
00270 cpl_vector_set(widths, j, width);
00271 #if 0
00272 cpl_msg_debug(__func__, "slice %hu: left=%f, right=%f --> width %f, center %f",
00273 j+1, ledge, redge, width, (ledge + redge) / 2.);
00274 #endif
00275
00276 cpl_vector_set(centers, j, round((ledge + redge) / 2.) + 1);
00277 }
00278
00279
00280 char *doplot = getenv("MUSE_PLOT_TRACE");
00281 if (doplot && (atoi(doplot) & 0x1)) {
00282 muse_trace_plot_located_slices(aRowVec, centers, median, mdev, detlimit,
00283 aIFU);
00284 }
00285
00286 int failures = 0;
00287 for (i = 1; i < cpl_vector_get_size(centers); i++) {
00288 double step = cpl_vector_get(centers, i) - cpl_vector_get(centers, i-1);
00289 if (step < kMuseSliceLoLikelyWidth) {
00290 failures++;
00291 }
00292 }
00293
00294
00295 if (!failures) {
00296 break;
00297 }
00298
00299
00300 f /= 1.2;
00301
00302 if (f < DBL_EPSILON) {
00303 cpl_msg_error(__func__, "Still detected %d unlikely slice locations, but "
00304 "the cut-off fraction has become unrealistically small in "
00305 "IFU %hhu (initial %f, now %f)", failures, aIFU, aFrac, f);
00306 break;
00307 }
00308 }
00309
00310
00311 int i, n = !centers ? -1 : cpl_vector_get_size(widths);
00312 for (i = 0; i < n; i++) {
00313 float width = cpl_vector_get(widths, i);
00314 if (width < kMuseSliceLoLikelyWidth) {
00315 cpl_msg_warning(__func__, "From the initial guess, slice %d appears to be"
00316 " only %f pix wide in IFU %hhu, please cross-check!", i+1,
00317 width, aIFU);
00318 }
00319 if (width > kMuseSliceHiLikelyWidth) {
00320 cpl_msg_warning(__func__, "From the initial guess, slice %d appears to be"
00321 " very wide in IFU %hhu (%f pix), please cross-check!",
00322 i+1, aIFU, width);
00323 }
00324 if (i >= 1) {
00325 double step = cpl_vector_get(centers, i) - cpl_vector_get(centers, i-1);
00326 if (step < kMuseSliceLoLikelyWidth) {
00327 cpl_msg_warning(__func__, "Slice %d is only %.2f pix farther than the "
00328 "previous one in IFU %hhu!", i + 1, step, aIFU);
00329 }
00330 }
00331 }
00332 cpl_vector_delete(widths);
00333
00334 return centers;
00335 }
00336
00337
00370
00371 double
00372 muse_trace_edgefinder(const cpl_vector *aDataVec, double aFrac,
00373 double *aLeft, double *aRight, cpl_boolean *aHighSN,
00374 const unsigned char aIFU)
00375 {
00376 int size = cpl_vector_get_size(aDataVec);
00377
00378 cpl_ensure(size > 5, CPL_ERROR_ILLEGAL_INPUT, -3);
00379 cpl_ensure(aFrac > 0. && aFrac < 1., CPL_ERROR_ILLEGAL_INPUT, -4);
00380 cpl_ensure(aLeft && aRight, CPL_ERROR_NULL_INPUT, -5);
00381
00382
00383
00384 double median = cpl_vector_get_median_const(aDataVec),
00385 mdev = muse_cplvector_get_adev_const(aDataVec, median),
00386 mean = cpl_vector_get_mean(aDataVec),
00387 stdev = cpl_vector_get_stdev(aDataVec),
00388 detlimit = aFrac * median;
00389
00390
00391
00392 cpl_boolean significant = median > mdev && mean > stdev;
00393 if (aHighSN) {
00394 *aHighSN = significant;
00395 }
00396 #if 0
00397 cpl_msg_debug(__func__, "median=%f+/-%f, mean=%f+/-%f, aFrac=%f --> edge "
00398 "detection limit=%f (%ssignificant), IFU %hhu", median, mdev,
00399 mean, stdev, aFrac, detlimit, significant ? "" : "NOT ", aIFU);
00400 #endif
00401
00402
00403 *aRight = 0;
00404 *aLeft = 0;
00405
00406 const double *ydata = cpl_vector_get_data_const(aDataVec);
00407
00408
00409 int i;
00410 for (i = size/2; i < size; i++) {
00411 if (ydata[i] < detlimit) {
00412
00413
00414
00415 *aRight = i-1 + (detlimit - ydata[i-1]) / (ydata[i] - ydata[i-1]);
00416 #if 0
00417 cpl_msg_debug(__func__, "r: %d..._%d_, %f/_%f_ ===> %f", i-1, i,
00418 ydata[i-1], ydata[i], *aRight);
00419 #endif
00420
00421
00422 if (fabs(*aRight - i) > 1.) {
00423
00424
00425
00426
00427 if (significant && i - size/2 > 2) {
00428 cpl_msg_debug(__func__, "Faulty interpolation of right-hand edge in "
00429 "IFU %hhu: i=%d (start %d), *aRight=%f (%f..%f > %f > "
00430 "%f)", aIFU, i, size/2, *aRight, ydata[i-2], ydata[i-1],
00431 detlimit, ydata[i]);
00432 return -11;
00433 }
00434 continue;
00435 }
00436 break;
00437 }
00438 }
00439
00440 if (i == size) {
00441 return -1;
00442 }
00443
00444
00445 for (i = size/2; i >= 0; i--) {
00446 if (ydata[i] < detlimit) {
00447
00448 *aLeft = i + (detlimit - ydata[i]) / (ydata[i+1] - ydata[i]);
00449 #if 0
00450 cpl_msg_debug(__func__, "l: %d..._%d_, %f/_%f_ ===> %f", i+1, i,
00451 ydata[i+1], ydata[i], *aLeft);
00452 #endif
00453 if (fabs(*aLeft - i) > 1.) {
00454 if (significant && size/2 - i > 2) {
00455
00456 cpl_msg_debug(__func__, "Faulty interpolation of left-hand edge in "
00457 "IFU %hhu: i=%d (start %d), *aLeft=%f (%f < %f < %f..%f"
00458 ")", aIFU, i, size/2, *aLeft, ydata[i], detlimit,
00459 ydata[i+1], ydata[i+2]);
00460 return -12;
00461 }
00462 continue;
00463 }
00464 break;
00465 }
00466 }
00467
00468 if (i == -1) {
00469 return -2;
00470 }
00471
00472 #if 0
00473 cpl_msg_debug(__func__, "result in IFU %hhu: %f %f --> %f", aIFU, *aLeft,
00474 *aRight, (*aLeft + *aRight)/2.);
00475 #endif
00476 return (*aLeft + *aRight)/2.;
00477 }
00478
00479
00508
00509 static double
00510 muse_trace_refine_edge(cpl_vector *aDiffVec, double *aLeft, double *aRight,
00511 int aOffset, double aY, const unsigned short aSlice,
00512 const unsigned char aIFU)
00513 {
00514 #define TRACE_REFINE_MAX_SHIFT 0.25
00515 #define TRACE_REFINE_RANGE 5
00516 int size = cpl_vector_get_size(aDiffVec);
00517 cpl_ensure(size > 5, CPL_ERROR_ILLEGAL_INPUT, -3);
00518 cpl_ensure(aLeft && aRight, CPL_ERROR_NULL_INPUT, -5);
00519 cpl_ensure(*aLeft > 0 && *aLeft < size &&
00520 *aRight > 0 && *aRight < size && *aRight > *aLeft,
00521 CPL_ERROR_ILLEGAL_INPUT, -6);
00522
00523
00524 double left = *aLeft,
00525 right = *aRight,
00526 mid = (*aLeft + *aRight) / 2.;
00527
00528
00529
00530 int nel = 2 * TRACE_REFINE_RANGE + 1;
00531 cpl_vector *vl = cpl_vector_new(nel),
00532 *vr = cpl_vector_new(nel),
00533 *pl = cpl_vector_new(nel),
00534 *pr = cpl_vector_new(nel);
00535
00536 int loffset = (int)(left + 0.5)- TRACE_REFINE_RANGE + 1,
00537 roffset = (int)(right + 0.5) - TRACE_REFINE_RANGE + 1;
00538 #if 0
00539 cpl_msg_debug(__func__, "input: %f/%f -> %d/%d",
00540 left, right, loffset, roffset);
00541 #endif
00542 double *diff = cpl_vector_get_data(aDiffVec);
00543 int i;
00544 for (i = 0; i < nel; i++ ) {
00545 double d = diff[i + loffset - 1];
00546 #if 0
00547 cpl_msg_debug(__func__, "l i=%d / %d: %f", i, i + loffset, d);
00548 #endif
00549 cpl_vector_set(pl, i, i + loffset - 1);
00550
00551 cpl_vector_set(vl, i, d > 0 ? d : 0);
00552 }
00553 for (i = 0; i < nel; i++ ) {
00554
00555 double d = -diff[i + roffset - 1];
00556 #if 0
00557 cpl_msg_debug(__func__, "r i=%d / %d: %f", i, i + roffset, d);
00558 #endif
00559 cpl_vector_set(pr, i, i + roffset - 1);
00560
00561 cpl_vector_set(vr, i, d > 0 ? d : 0);
00562 }
00563
00564
00565 cpl_errorstate state = cpl_errorstate_get();
00566
00567
00568 double center, sigma, area, bglevel = 0, mse;
00569 cpl_fit_mode fitmode = CPL_FIT_CENTROID | CPL_FIT_STDEV | CPL_FIT_AREA;
00570 cpl_error_code rc1 = cpl_vector_fit_gaussian(pl, NULL, vl, NULL, fitmode,
00571 ¢er, &sigma, &area, &bglevel,
00572 &mse, NULL, NULL);
00573
00574 center -= 0.5;
00575 if (rc1 == CPL_ERROR_CONTINUE || rc1 == CPL_ERROR_SINGULAR_MATRIX) {
00576
00577
00578 if (fabs(center - *aLeft) < TRACE_REFINE_MAX_SHIFT) {
00579 *aLeft = center;
00580 }
00581 }
00582 if (rc1 != CPL_ERROR_NONE) {
00583
00584 cpl_errorstate_set(state);
00585 } else {
00586 *aLeft = center;
00587 }
00588 #if 0
00589 cpl_msg_debug(__func__, "fit l: %f %f %f (%f)", center, sigma, area, sqrt(mse));
00590 #endif
00591 cpl_error_code rc2 = cpl_vector_fit_gaussian(pr, NULL, vr, NULL, fitmode,
00592 ¢er, &sigma, &area, &bglevel,
00593 &mse, NULL, NULL);
00594 center -= 0.5;
00595 if (rc2 == CPL_ERROR_CONTINUE || rc2 == CPL_ERROR_SINGULAR_MATRIX) {
00596
00597
00598 if (fabs(center - *aRight) < TRACE_REFINE_MAX_SHIFT) {
00599 *aRight = center;
00600 }
00601 }
00602 if (rc2 != CPL_ERROR_NONE) {
00603
00604 cpl_errorstate_set(state);
00605 } else {
00606 *aRight = center;
00607 }
00608 #if 0
00609 cpl_msg_debug(__func__, "fit r: %f %f %f (%f)", center, sigma, area, sqrt(mse));
00610 #endif
00611
00612 #if 0
00613 cpl_vector_dump(aDiffVec, stdout);
00614 printf("left\n");
00615 cpl_bivector *biv = cpl_bivector_wrap_vectors(pl, vl);
00616 cpl_bivector_dump(biv, stdout);
00617 cpl_bivector_unwrap_vectors(biv);
00618 printf("right\n");
00619 biv = cpl_bivector_wrap_vectors(pr, vr);
00620 cpl_bivector_dump(biv, stdout);
00621 cpl_bivector_unwrap_vectors(biv);
00622 fflush(stdout);
00623 #endif
00624 cpl_vector_delete(vl);
00625 cpl_vector_delete(vr);
00626 cpl_vector_delete(pl);
00627 cpl_vector_delete(pr);
00628
00629 double midpoint = (*aLeft + *aRight)/2.;
00630 #if 0
00631 cpl_msg_debug(__func__, "refine: %f %f %f %f %f %f",
00632 *aLeft, midpoint, *aRight,
00633 left - *aLeft, mid - midpoint, right - *aRight);
00634 #endif
00635
00636
00637 if (fabs(mid - midpoint) > TRACE_REFINE_MAX_SHIFT) {
00638 cpl_msg_debug(__func__, "large refined shift around y=%.1f in slice %hu of "
00639 "IFU %hhu: %f %f %f (%f %f %f) trace point will not be used",
00640 aY, aSlice, aIFU, left + aOffset, midpoint + aOffset,
00641 right + aOffset, left - *aLeft, mid - midpoint, right - *aRight);
00642 midpoint = -1.;
00643 } else {
00644 midpoint += aOffset;
00645 }
00646
00647 *aLeft += aOffset;
00648 *aRight += aOffset;
00649 return midpoint;
00650 }
00651
00652
00682
00683 static cpl_polynomial **
00684 muse_trace_iterate_fit(cpl_matrix *aX, cpl_vector *aY, cpl_vector *aWidths,
00685 const unsigned short aSlice, const unsigned char aIFU,
00686 const unsigned int aFitorder, const float aWSigma,
00687 const float aRSigma, cpl_vector *aMSE)
00688 {
00689 cpl_ensure(cpl_vector_get_size(aWidths) >= 3, CPL_ERROR_ILLEGAL_INPUT, NULL);
00690
00691 cpl_ensure(aSlice >= 1 && aSlice <= kMuseSlicesPerCCD,
00692 CPL_ERROR_ILLEGAL_INPUT, NULL);
00693
00694
00695 double wmean = cpl_vector_get_mean(aWidths),
00696 wmedian = cpl_vector_get_median_const(aWidths),
00697 wstdev = cpl_vector_get_stdev(aWidths),
00698 wmdev = muse_cplvector_get_adev_const(aWidths, wmedian);
00699 #if 0
00700 cpl_msg_debug(__func__, "width (1st): mean %6.3f +/- %5.3f, median %6.3f +/- "
00701 "%5.3f (%"CPL_SIZE_FORMAT" points)", wmean, wstdev, wmedian, wmdev,
00702 cpl_vector_get_size(aWidths));
00703 #endif
00704 if ((wmean - wstdev < kMuseSliceLoLikelyWidth ||
00705 wmedian - wmdev < kMuseSliceLoLikelyWidth) &&
00706 (wmean < kMuseSliceLoLikelyWidth || wmedian < kMuseSliceLoLikelyWidth)) {
00707 cpl_msg_debug(__func__, "slice %hu of IFU %hhu seems to be very narrow "
00708 "initially (widths: mean %6.3f +/- %5.3f, median %6.3f +/- "
00709 "%5.3f)!", aSlice, aIFU, wmean, wstdev, wmedian, wmdev);
00710 }
00711 if ((wmean + wstdev > kMuseSliceHiLikelyWidth ||
00712 wmedian + wmdev > kMuseSliceHiLikelyWidth) &&
00713 (wmean > kMuseSliceHiLikelyWidth || wmedian > kMuseSliceHiLikelyWidth)) {
00714 cpl_msg_debug(__func__, "slice %hu of IFU %hhu seems to be very wide "
00715 "initially (widths: mean %6.3f +/- %5.3f, median %6.3f +/- "
00716 "%5.3f)!", aSlice, aIFU, wmean, wstdev, wmedian, wmdev);
00717 }
00718
00719
00720
00721 int i;
00722 for (i = 0; i < cpl_vector_get_size(aWidths); i++) {
00723 double width = cpl_vector_get(aWidths, i);
00724 if (width > kMuseSliceLoLikelyWidth && width < kMuseSliceHiLikelyWidth) {
00725
00726 continue;
00727 }
00728
00729 if (cpl_vector_get_size(aWidths) == 1) {
00730 cpl_msg_warning(__func__, "trying to remove the last vector/matrix "
00731 "element in slice %hu of IFU %hhu when checking widths",
00732 aSlice, aIFU);
00733 break;
00734 }
00735
00736 cpl_matrix_erase_columns(aX, i, 1);
00737 muse_cplvector_erase_element(aY, i);
00738 muse_cplvector_erase_element(aWidths, i);
00739 i--;
00740 }
00741
00742 wmean = cpl_vector_get_mean(aWidths);
00743 wmedian = cpl_vector_get_median_const(aWidths);
00744 wstdev = cpl_vector_get_stdev(aWidths);
00745 wmdev = muse_cplvector_get_adev_const(aWidths, wmedian);
00746 #if 0
00747 cpl_msg_debug(__func__, "width (2nd): mean %6.3f+/-%5.3f, median %6.3f+/-%5.3f (%d points)",
00748 wmean, wstdev, wmedian, wmdev, cpl_vector_get_size(aWidths));
00749 #endif
00750 if ((wmean - wstdev < kMuseSliceLoLikelyWidth ||
00751 wmedian - wmdev < kMuseSliceLoLikelyWidth) &&
00752 (wmean < kMuseSliceLoLikelyWidth || wmedian < kMuseSliceLoLikelyWidth)) {
00753 cpl_msg_warning(__func__, "slice %hu of IFU %hhu seems to be very narrow "
00754 "after iteration (widths: mean %6.3f +/- %5.3f, median %6.3f"
00755 " +/- %5.3f)!", aSlice, aIFU, wmean, wstdev, wmedian, wmdev);
00756 }
00757 if ((wmean + wstdev > kMuseSliceHiLikelyWidth ||
00758 wmedian + wmdev > kMuseSliceHiLikelyWidth) &&
00759 (wmean > kMuseSliceHiLikelyWidth || wmedian > kMuseSliceHiLikelyWidth)) {
00760 cpl_msg_warning(__func__, "slice %hu of IFU %hhu seems to be very wide "
00761 "after iteration (widths: mean %6.3f +/- %5.3f, median %6.3f"
00762 " +/- %5.3f)!", aSlice, aIFU, wmean, wstdev, wmedian, wmdev);
00763 }
00764
00765
00766 for (i = 0; i < cpl_vector_get_size(aWidths); i++) {
00767 double width = cpl_vector_get(aWidths, i);
00768 #if 0
00769 cpl_msg_debug(__func__, "i=%d: %f <? %f <? %f", i,
00770 wmedian - aWSigma * wmdev, width, wmedian + aWSigma * wmdev);
00771 #endif
00772 if (width > (wmedian - aWSigma * wmdev) &&
00773 width < (wmedian + aWSigma * wmdev)) {
00774
00775 continue;
00776 }
00777
00778 if (cpl_vector_get_size(aWidths) == 1) {
00779 cpl_msg_warning(__func__, "trying to remove the last vector/matrix "
00780 "element in slice %hu of IFU %hhu when checking fit "
00781 "sigma", aSlice, aIFU);
00782 break;
00783 }
00784
00785 cpl_matrix_erase_columns(aX, i, 1);
00786 muse_cplvector_erase_element(aY, i);
00787 muse_cplvector_erase_element(aWidths, i);
00788 i--;
00789 }
00790
00791
00792 cpl_table *wtable = cpl_table_new(cpl_vector_get_size(aWidths));
00793 cpl_table_new_column(wtable, "widths", CPL_TYPE_DOUBLE);
00794 memcpy(cpl_table_get_data_double(wtable, "widths"),
00795 cpl_vector_get_data(aWidths), cpl_vector_get_size(aWidths));
00796 double mse, chisq;
00797 cpl_polynomial *tracefit = muse_utils_iterate_fit_polynomial(aX, aY, NULL, wtable,
00798 aFitorder, aRSigma,
00799 &mse, &chisq);
00800
00801 cpl_vector_set_size(aWidths, cpl_vector_get_size(aY));
00802 memcpy(cpl_vector_get_data(aWidths), cpl_table_get_data_double(wtable, "widths"),
00803 cpl_vector_get_size(aWidths));
00804 cpl_table_delete(wtable);
00805 if (!tracefit) {
00806 cpl_vector_fill(aMSE, FLT_MAX);
00807 return NULL;
00808 }
00809
00810 cpl_vector_set(aMSE, MUSE_TRACE_CENTER, mse);
00811
00812 char *dodebug = getenv("MUSE_DEBUG_TRACE");
00813 if (dodebug && atoi(dodebug) > 0) {
00814 printf("Polynomial trace fit for slice %hu of IFU %hhu (mse=%g, "
00815 "chi**2=%g):\n", aSlice, aIFU, mse, chisq);
00816 cpl_polynomial_dump(tracefit, stdout);
00817 fflush(stdout);
00818 }
00819
00820
00821
00822
00823 cpl_vector *edge[MUSE_TRACE_NPOLY - 1] = {
00824 cpl_vector_new(cpl_vector_get_size(aY)),
00825 cpl_vector_new(cpl_vector_get_size(aY))
00826 };
00827 for (i = 0; i < cpl_vector_get_size(aWidths); i++) {
00828 double x = cpl_vector_get(aY, i),
00829 halfwidth = cpl_vector_get(aWidths, i) / 2.;
00830 #if 0
00831 cpl_msg_debug(__func__, "x=%f (%f...%f)", x, x - halfwidth, x + halfwidth);
00832 #endif
00833 cpl_vector_set(edge[MUSE_TRACE_LEFT - 1], i, x - halfwidth);
00834 cpl_vector_set(edge[MUSE_TRACE_RIGHT - 1], i, x + halfwidth);
00835 }
00836 #if 0
00837 printf("left:\n");
00838 cpl_vector_dump(edge[0], stdout);
00839 printf("right:\n");
00840 cpl_vector_dump(edge[1], stdout);
00841 fflush(stdout);
00842 #endif
00843
00844 cpl_polynomial **fit = cpl_calloc(MUSE_TRACE_NPOLY, sizeof(cpl_polynomial *));
00845 fit[MUSE_TRACE_CENTER] = tracefit;
00846
00847 int ipoly;
00848 for (ipoly = 1; ipoly < MUSE_TRACE_NPOLY; ipoly++) {
00849
00850 fit[ipoly] = muse_utils_iterate_fit_polynomial(aX, edge[ipoly - 1], NULL,
00851 NULL, aFitorder, FLT_MAX,
00852 &mse, &chisq);
00853 cpl_vector_set(aMSE, ipoly, mse);
00854
00855 cpl_vector_delete(edge[ipoly - 1]);
00856 }
00857
00858 #if 0
00859 printf("resulting polynomials (center, left, and right):\n");
00860 cpl_polynomial_dump(fit[MUSE_TRACE_CENTER], stdout);
00861 cpl_polynomial_dump(fit[MUSE_TRACE_LEFT], stdout);
00862 cpl_polynomial_dump(fit[MUSE_TRACE_RIGHT], stdout);
00863 printf("MSEs:\n");
00864 cpl_vector_dump(aMSE, stdout);
00865 fflush(stdout);
00866 #endif
00867
00868 return fit;
00869 }
00870
00871
00875
00876 const muse_cpltable_def muse_tracesamples_def[] = {
00877 { "slice", CPL_TYPE_INT, "", "%02d", "slice number", CPL_TRUE},
00878 { "y", CPL_TYPE_FLOAT, "pix", "%6.1f", "y position on CCD", CPL_TRUE},
00879 { "mid", CPL_TYPE_FLOAT, "pix", "%8.3f",
00880 "midpoint of the slice at this y position", CPL_TRUE},
00881 { "left", CPL_TYPE_FLOAT, "pix", "%8.3f",
00882 "left edge of the slice at this y position", CPL_TRUE},
00883 { "right", CPL_TYPE_FLOAT, "pix", "%8.3f",
00884 "right edge of the slice at this y position", CPL_TRUE},
00885 { NULL, 0, NULL, NULL, NULL, CPL_FALSE }
00886 };
00887
00888
00934
00935 cpl_table *
00936 muse_trace(const muse_image *aImage, int aNSum, double aEdgeFrac, int aFitorder,
00937 cpl_table **aSamples)
00938 {
00939 cpl_ensure(aImage && aImage->data, CPL_ERROR_NULL_INPUT, NULL);
00940 cpl_ensure(aNSum > 0 && aEdgeFrac > 0. && aEdgeFrac < 1. && aFitorder > 0,
00941 CPL_ERROR_ILLEGAL_INPUT, NULL);
00942
00943
00944 int ny = cpl_image_get_size_y(aImage->data),
00945 npoints = (ny - 1) / aNSum;
00946 unsigned short nsearchslices = kMuseSlicesPerCCD;
00947 cpl_boolean slice_number_hack = getenv("MUSE_AIT_HACK_SLICE_NUMBER")
00948 && atoi(getenv("MUSE_AIT_HACK_SLICE_NUMBER")) > 0
00949 && atoi(getenv("MUSE_AIT_HACK_SLICE_NUMBER")) < 49;
00950 unsigned char ifu = muse_utils_get_ifu(aImage->header);
00951 if (slice_number_hack) {
00952 nsearchslices = atoi(getenv("MUSE_AIT_HACK_SLICE_NUMBER"));
00953 cpl_msg_warning(__func__, "Overriding number of slices to search in IFU "
00954 "%hhu to %hu!", ifu, nsearchslices);
00955 }
00956 cpl_msg_info(__func__, "Working with %hu slices, %d image rows, and %d "
00957 "tracepoints in IFU %hhu", nsearchslices, ny, npoints, ifu);
00958
00959
00960
00961 cpl_boolean chan24paranal = (ifu == 24);
00962 const char *dateobs = muse_pfits_get_dateobs(aImage->header);
00963 if (chan24paranal && dateobs) {
00964 chan24paranal = atoi(dateobs) >= 2014;
00965 }
00966 if (chan24paranal) {
00967 cpl_msg_info(__func__, "Using overrides for IFU 24 since 2014: due to field"
00968 " vignetting, left-hand edges (as seen on the CCD) of slices "
00969 "37 to 48 may be only approximate!");
00970 }
00971
00972
00973 muse_image *image = muse_image_new();
00974 image->data = cpl_image_duplicate(aImage->data);
00975 if (aImage->dq) {
00976 image->dq = cpl_image_duplicate(aImage->dq);
00977 } else {
00978 image->dq = cpl_image_new(cpl_image_get_size_x(aImage->data), ny, CPL_TYPE_INT);
00979 }
00980 if (aImage->header) {
00981 image->header = cpl_propertylist_duplicate(aImage->header);
00982 }
00983
00984 muse_image_reject_from_dq(image);
00985 cpl_detector_interpolate_rejected(image->data);
00986
00987
00988 #define NROWCOLLAPSE 15
00989 cpl_vector *cut = muse_trace_horizontal_cut(image, NROWCOLLAPSE);
00990 cpl_vector *centers = muse_trace_locate_slices(cut, nsearchslices, aEdgeFrac,
00991 ifu);
00992 cpl_vector_delete(cut);
00993 if (!centers) {
00994 cpl_msg_error(__func__, "Could not carry out first guess of slice positions "
00995 "in IFU %hhu!", ifu);
00996 muse_image_delete(image);
00997 return NULL;
00998 }
00999
01000
01001 cpl_table *tracetable = cpl_table_new(kMuseSlicesPerCCD);
01002 if (!tracetable) {
01003 cpl_msg_error(__func__, "Could not create output trace table for IFU %hhu: "
01004 "%s", ifu, cpl_error_get_message());
01005 muse_image_delete(image);
01006 return NULL;
01007 }
01008
01009
01010 cpl_table_new_column(tracetable, MUSE_TRACE_TABLE_COL_SLICE_NO, CPL_TYPE_INT);
01011 cpl_table_set_column_unit(tracetable, MUSE_TRACE_TABLE_COL_SLICE_NO, "No");
01012 cpl_table_set_column_format(tracetable, MUSE_TRACE_TABLE_COL_SLICE_NO, "%2d");
01013 cpl_table_new_column(tracetable, MUSE_TRACE_TABLE_COL_WIDTH, CPL_TYPE_FLOAT);
01014 cpl_table_set_column_unit(tracetable, MUSE_TRACE_TABLE_COL_WIDTH, "pix");
01015 cpl_table_set_column_format(tracetable, MUSE_TRACE_TABLE_COL_WIDTH, "%6.3f");
01016 int ipoly;
01017 for (ipoly = 0; ipoly < MUSE_TRACE_NPOLY; ipoly++) {
01018 char *colname;
01019 int j;
01020 for (j = 0; j <= aFitorder; j++) {
01021
01022 colname = cpl_sprintf(MUSE_TRACE_TABLE_COL_COEFF, ipoly, j);
01023 cpl_table_new_column(tracetable, colname, CPL_TYPE_DOUBLE);
01024
01025 cpl_table_set_column_unit(tracetable, colname, "pix");
01026 cpl_table_set_column_format(tracetable, colname, "%12.5e");
01027 cpl_free(colname);
01028 }
01029 colname = cpl_sprintf(MUSE_TRACE_TABLE_COL_MSE, ipoly);
01030 cpl_table_new_column(tracetable, colname, CPL_TYPE_DOUBLE);
01031 cpl_table_set_column_unit(tracetable, colname, "pix");
01032 cpl_table_set_column_format(tracetable, colname, "%12.5e");
01033 cpl_free(colname);
01034 }
01035
01036 int isamplesrow = -1;
01037 if (aSamples) {
01038
01039 *aSamples = muse_cpltable_new(muse_tracesamples_def,
01040 kMuseSlicesPerCCD * npoints);
01041 }
01042
01043
01044
01045 cpl_image *shiftdiff = cpl_image_duplicate(image->data);
01046 cpl_image_shift(shiftdiff, 1, 0);
01047
01048 cpl_image_multiply_scalar(shiftdiff, -1);
01049 cpl_image_add(shiftdiff, image->data);
01050
01051
01052 unsigned short islice;
01053 for (islice = 0; islice < kMuseSlicesPerCCD; islice++) {
01054 int nfailed = 0;
01055 cpl_matrix *xtrace = cpl_matrix_new(1, npoints);
01056 cpl_vector *ytrace = cpl_vector_new(npoints);
01057
01058 cpl_vector *widths = cpl_vector_new(npoints);
01059
01060
01061 int j, k, knum;
01062 for (j = 1, k = 0, knum = 1; j <= ny - aNSum; j += aNSum, k++, knum++) {
01063
01064
01065 int noffset = (int)cpl_vector_get(centers, islice) - TRACE_BINSIZE,
01066 ilo = noffset,
01067 ihi = (int)cpl_vector_get(centers, islice) + TRACE_BINSIZE,
01068 jlo = j,
01069 jhi = j + aNSum - 1;
01070 #if 0
01071 cpl_msg_debug(__func__, "slice=%d, center=%f, cut region: %d,%d,%d,%d",
01072 (int)islice + 1, cpl_vector_get(centers, islice), ilo, ihi, jlo, jhi);
01073 #endif
01074 cpl_image *tmp = cpl_image_collapse_window_create(image->data,
01075 ilo, jlo, ihi, jhi,
01076 0);
01077 cpl_image_divide_scalar(tmp, aNSum);
01078 cut = cpl_vector_new_from_image_row(tmp, 1);
01079 cpl_image_delete(tmp);
01080
01081
01082 double left, right;
01083 cpl_boolean highSN = CPL_TRUE;
01084 double midpoint = muse_trace_edgefinder(cut, aEdgeFrac, &left, &right,
01085 &highSN, ifu);
01086 cpl_vector_delete(cut);
01087
01088
01089 double left1 = left + noffset;
01090
01091 cpl_errorstate state = cpl_errorstate_get();
01092
01093
01094 tmp = cpl_image_collapse_window_create(shiftdiff, ilo, jlo, ihi, jhi,
01095 0);
01096 cpl_image_divide_scalar(tmp, aNSum);
01097 cut = cpl_vector_new_from_image_row(tmp, 1);
01098 cpl_image_delete(tmp);
01099 midpoint = muse_trace_refine_edge(cut, &left, &right, noffset,
01100 (jlo + jhi) / 2., islice + 1, ifu);
01101 cpl_vector_delete(cut);
01102
01103
01104 if (midpoint < 0 && midpoint > -2 && islice+1 >= 37 && chan24paranal) {
01105 cpl_msg_debug(__func__, "IFU24 problem? slice %d, y = %f: refined "
01106 "%f < %f < %f", islice+1, ((double)jlo + jhi) / 2.,
01107 left, midpoint, right);
01108 if (left1 < left) {
01109
01110
01111 left = left1;
01112 cpl_msg_debug(__func__, "IFU24 problem! slice %d y = %f: corrected "
01113 "%f < %f < %f", islice+1, ((double)jlo + jhi) / 2.,
01114 left, (left + right) / 2., right);
01115 }
01116
01117 midpoint = (left + right) / 2.;
01118 }
01119
01120 if (midpoint > 0) {
01121 cpl_matrix_set(xtrace, 0, k, (jlo + jhi) / 2.);
01122 cpl_vector_set(ytrace, k, midpoint);
01123 cpl_vector_set(widths, k, right - left);
01124
01125 if (aSamples) {
01126
01127 if (++isamplesrow+1 > cpl_table_get_nrow(*aSamples)) {
01128 cpl_table_set_size(*aSamples, isamplesrow+1);
01129 }
01130 cpl_table_set_int(*aSamples, "slice", isamplesrow, islice + 1);
01131 cpl_table_set_float(*aSamples, "y", isamplesrow, (jlo + jhi) / 2.);
01132 cpl_table_set_float(*aSamples, "mid", isamplesrow, midpoint);
01133 cpl_table_set_float(*aSamples, "left", isamplesrow, left);
01134 cpl_table_set_float(*aSamples, "right", isamplesrow, right);
01135 }
01136
01137
01138 continue;
01139 }
01140
01141
01142
01143
01144 cpl_errorstate_set(state);
01145 if (highSN) {
01146 nfailed++;
01147 }
01148 #if 0
01149 cpl_msg_debug(__func__, "slice=%d, nfailed=%d, tracepoint=%d, midpoint="
01150 "%f, y=%d", (int)islice + 1, nfailed, knum, midpoint, j);
01151 #endif
01152 if (nfailed > 0.1*npoints && midpoint == -1.) {
01153 cpl_msg_warning(__func__, "failure %d in slice %d of IFU %hhu: lost "
01154 "trace at y=%d (tracepoint %d of %d)", nfailed,
01155 (int)islice + 1, ifu, j, knum, npoints);
01156 }
01157
01158
01159 int oldsize = cpl_vector_get_size(ytrace);
01160 cpl_vector_set_size(ytrace, oldsize - 1);
01161 cpl_matrix_resize(xtrace, 0, 0, 0, -1);
01162 cpl_vector_set_size(widths, oldsize - 1);
01163 k--;
01164 }
01165 #if 0
01166
01167
01168 printf("k=%d tracepoints (should be equal to %d)\n", k, npoints);
01169 cpl_matrix_dump(xtrace, stdout), fflush(stdout);
01170 cpl_vector_dump(ytrace, stdout), fflush(stdout);
01171 #endif
01172
01173
01174 const float kWSigma = 5, kRSigma = 5;
01175 cpl_msg_debug(__func__, "Working on slice %d of IFU %hhu (kWSigma=%f, "
01176 "kRSigma=%f)", (int)islice + 1, ifu, kWSigma, kRSigma);
01177 cpl_vector *mse = cpl_vector_new(MUSE_TRACE_NPOLY);
01178 cpl_vector_fill(mse, -1.);
01179 cpl_polynomial **tracefits = muse_trace_iterate_fit(xtrace, ytrace, widths,
01180 islice + 1, ifu, aFitorder,
01181 kWSigma, kRSigma, mse);
01182
01183 double wmean = cpl_vector_get_mean(widths);
01184
01185
01186 cpl_matrix_delete(xtrace);
01187 cpl_vector_delete(ytrace);
01188 cpl_vector_delete(widths);
01189
01190 if (!tracefits) {
01191
01192 cpl_msg_error(__func__, "The trace fit in slice %d of IFU %hhu failed",
01193 (int)islice + 1, ifu);
01194 cpl_vector_delete(mse);
01195 continue;
01196 }
01197
01198
01199 cpl_table_set_int(tracetable, MUSE_TRACE_TABLE_COL_SLICE_NO, islice,
01200 islice + 1);
01201 cpl_table_set_float(tracetable, MUSE_TRACE_TABLE_COL_WIDTH, islice, wmean);
01202 for (ipoly = 0; ipoly < MUSE_TRACE_NPOLY; ipoly++) {
01203 if (!tracefits[ipoly]) {
01204 cpl_msg_error(__func__, "The fit %d in slice %d of IFU %hhu failed",
01205 ipoly, (int)islice + 1, ifu);
01206 continue;
01207 }
01208 char *colname = cpl_sprintf(MUSE_TRACE_TABLE_COL_MSE, ipoly);
01209 cpl_table_set_double(tracetable, colname, islice,
01210 cpl_vector_get(mse, ipoly));
01211 cpl_free(colname);
01212
01213 for (j = 0; j <= aFitorder; j++) {
01214 cpl_size pows[1] = { j };
01215
01216 colname = cpl_sprintf(MUSE_TRACE_TABLE_COL_COEFF, ipoly, j);
01217 cpl_errorstate prestate = cpl_errorstate_get();
01218 double coeff = cpl_polynomial_get_coeff(tracefits[ipoly], pows);
01219 #define SLOPE_WARN_LIMIT 0.015
01220 if (j == 1 && fabs(coeff) > SLOPE_WARN_LIMIT) {
01221 cpl_msg_warning(__func__, "1st order coefficient of the %s tracing "
01222 "polynomial is unexpectedly large in slice %d of IFU"
01223 " %hhu: |%f| > %f", muse_trace_poly_strings[ipoly],
01224 (int)islice + 1, ifu, coeff, SLOPE_WARN_LIMIT);
01225 }
01226 cpl_table_set_double(tracetable, colname, islice, coeff);
01227 if (!cpl_errorstate_is_equal(prestate)) {
01228 cpl_msg_warning(__func__, "Problem writing to field %s in trace table"
01229 " for IFU %hhu: %s", colname, ifu,
01230 cpl_error_get_message());
01231 }
01232 cpl_free(colname);
01233 }
01234 }
01235 cpl_vector_delete(mse);
01236 muse_trace_polys_delete(tracefits);
01237 }
01238 cpl_vector_delete(centers);
01239 cpl_image_delete(shiftdiff);
01240 if (aSamples) {
01241
01242 cpl_table_set_size(*aSamples, ++isamplesrow);
01243 }
01244
01245 if (slice_number_hack) {
01246 cpl_msg_warning(__func__, "Will try to fix the slices in IFU %hhu, %"
01247 CPL_SIZE_FORMAT" seem to be bad!", ifu,
01248 cpl_table_count_invalid(tracetable, MUSE_TRACE_TABLE_COL_WIDTH));
01249 cpl_table_dump(tracetable, 0, 100, stdout);
01250 fflush(stdout);
01251
01252 for (islice = 0; islice < cpl_table_get_nrow(tracetable); islice++) {
01253 double width = cpl_table_get(tracetable, MUSE_TRACE_TABLE_COL_WIDTH, islice, NULL);
01254 if (width < 40.) {
01255 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_OUTPUT, "slice %d of "
01256 "IFU %hhu was narrow (%f), erased it", (int)islice + 1,
01257 ifu, width);
01258 cpl_table_erase_window(tracetable, islice--, 1);
01259 }
01260 }
01261 double last = 0;
01262 for (islice = 0; islice < cpl_table_get_nrow(tracetable); islice++) {
01263 double cen = cpl_table_get(tracetable, "tc0_00", islice, NULL);
01264 if (cen - last > 100) {
01265 unsigned short iref = islice - 1;
01266 cpl_table *row = cpl_table_extract(tracetable, iref, 1);
01267
01268 double offset = 84.5;
01269 cpl_table_add_scalar(row, MUSE_TRACE_TABLE_COL_SLICE_NO, 1);
01270 cpl_table_add_scalar(row, "tc0_00", offset);
01271 cpl_table_add_scalar(row, "tc1_00", offset);
01272 cpl_table_add_scalar(row, "tc2_00", offset);
01273 cpl_table_add_scalar(row, "MSE0", 1.);
01274 cpl_table_add_scalar(row, "MSE1", 1.);
01275 cpl_table_add_scalar(row, "MSE2", 1.);
01276 cpl_table_insert(tracetable, row, islice);
01277 #if 0
01278 printf("rowtable (islice=%hu):\n", islice);
01279 cpl_table_dump(row, 0, 100, stdout);
01280 fflush(stdout);
01281 printf("tracetable (islice=%hu):\n", islice);
01282 cpl_table_dump(tracetable, islice - 2, 10, stdout);
01283 fflush(stdout);
01284 #endif
01285 cen = cpl_table_get(row, "tc0_00", 0, NULL);
01286 cpl_table_delete(row);
01287 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_OUTPUT, "slice was "
01288 "missing before slice %d of IFU %hhu, copied "
01289 "from slice %d", (int)islice + 1, ifu, (int)iref + 1);
01290 }
01291 last = cen;
01292 }
01293 for (islice = 0; islice < cpl_table_get_nrow(tracetable); islice++) {
01294 unsigned short sliceno = cpl_table_get_int(tracetable,
01295 MUSE_TRACE_TABLE_COL_SLICE_NO,
01296 islice, NULL);
01297 if (sliceno != islice + 1) {
01298 cpl_msg_warning(__func__, "Resetting entry at table row index %hu to "
01299 "correct slice number in IFU %hhu (%d instead of %hu)",
01300 islice, ifu, (int)islice + 1, sliceno);
01301 cpl_table_set_int(tracetable, MUSE_TRACE_TABLE_COL_SLICE_NO, islice,
01302 islice + 1);
01303 }
01304 }
01305 }
01306
01307
01308 cpl_msg_info(__func__, "Found %"CPL_SIZE_FORMAT" slices of width %4.1f+/-%3.1f"
01309 " pix (%4.1f pix...%4.1f pix) in IFU %hhu",
01310 cpl_table_get_nrow(tracetable),
01311 cpl_table_get_column_mean(tracetable, MUSE_TRACE_TABLE_COL_WIDTH),
01312 cpl_table_get_column_stdev(tracetable, MUSE_TRACE_TABLE_COL_WIDTH),
01313 cpl_table_get_column_min(tracetable, MUSE_TRACE_TABLE_COL_WIDTH),
01314 cpl_table_get_column_max(tracetable, MUSE_TRACE_TABLE_COL_WIDTH),
01315 ifu);
01316 muse_image_delete(image);
01317
01318 return tracetable;
01319 }
01320
01321
01330
01331 int
01332 muse_trace_table_get_order(const cpl_table *aTable)
01333 {
01334
01335
01336
01337
01338 return (cpl_table_get_ncol(aTable) - 2) / MUSE_TRACE_NPOLY - 2;
01339 }
01340
01341
01360
01361 cpl_polynomial **
01362 muse_trace_table_get_polys_for_slice(const cpl_table *aTable,
01363 const unsigned short aSlice)
01364 {
01365 cpl_ensure(aTable, CPL_ERROR_NULL_INPUT, NULL);
01366 cpl_ensure(aSlice >= 1 && aSlice <= kMuseSlicesPerCCD,
01367 CPL_ERROR_ILLEGAL_INPUT, NULL);
01368
01369
01370 int irow, nrow = cpl_table_get_nrow(aTable);
01371 for (irow = 0; irow < nrow; irow++) {
01372 int err;
01373 unsigned short slice = cpl_table_get_int(aTable,
01374 MUSE_TRACE_TABLE_COL_SLICE_NO,
01375 irow, &err);
01376 if (slice == aSlice && !err) {
01377 break;
01378 }
01379 }
01380 cpl_ensure(irow < nrow, CPL_ERROR_DATA_NOT_FOUND, NULL);
01381
01382 cpl_polynomial **ptrace = cpl_calloc(MUSE_TRACE_NPOLY,
01383 sizeof(cpl_polynomial *));
01384 char colname[7];
01385 int ipoly;
01386 for (ipoly = 0; ipoly < MUSE_TRACE_NPOLY; ipoly++) {
01387 int traceorder = muse_trace_table_get_order(aTable);
01388 ptrace[ipoly] = cpl_polynomial_new(1);
01389
01390
01391 int k;
01392 for (k = 0; k <= traceorder; k++) {
01393 cpl_size pows[1] = { k };
01394 sprintf(colname, MUSE_TRACE_TABLE_COL_COEFF, ipoly, k);
01395 int err;
01396 cpl_polynomial_set_coeff(ptrace[ipoly], pows,
01397 cpl_table_get(aTable, colname, irow, &err));
01398 if (err != 0) {
01399 cpl_polynomial_delete(ptrace[MUSE_TRACE_CENTER]);
01400 cpl_polynomial_delete(ptrace[MUSE_TRACE_LEFT]);
01401 cpl_polynomial_delete(ptrace[MUSE_TRACE_RIGHT]);
01402 cpl_free(ptrace);
01403 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_OUTPUT, "Trace table "
01404 "broken in slice %hu (row index %d) column %s",
01405 aSlice, irow, colname);
01406 return NULL;
01407 }
01408 }
01409 }
01410
01411 return ptrace;
01412 }
01413
01414
01419
01420 void
01421 muse_trace_polys_delete(cpl_polynomial *aPolys[])
01422 {
01423 if (!aPolys) {
01424 return;
01425 }
01426 cpl_polynomial_delete(aPolys[MUSE_TRACE_CENTER]);
01427 cpl_polynomial_delete(aPolys[MUSE_TRACE_LEFT]);
01428 cpl_polynomial_delete(aPolys[MUSE_TRACE_RIGHT]);
01429 cpl_free(aPolys);
01430 }
01431
01432
01433 static void
01434 muse_trace_plot_located_slices(cpl_vector *aRowVec, cpl_vector *aCenters,
01435 double aMedian, double aMDev, double aLimit,
01436 const unsigned char aIFU)
01437 {
01438 #if HAVE_POPEN && HAVE_PCLOSE
01439 FILE *gp = popen("gnuplot -persist", "w");
01440 if (!gp) {
01441 cpl_msg_error(__func__, "could not open gnuplot for plotting");
01442 return;
01443 }
01444
01445 #if HAVE_MKDTEMP
01446 char dirtemplate[] = "/tmp/muse_trace_plot_located_slices_XXXXXX";
01447 char *dirname = mkdtemp(dirtemplate);
01448 if (!dirname) {
01449 return;
01450 }
01451 #else
01452 char dirname[] = "/tmp";
01453 #endif
01454 char *out1 = cpl_sprintf("%s/row.dat", dirname);
01455 FILE *fp = fopen(out1, "w");
01456 cpl_vector_dump(aRowVec, fp);
01457 fclose(fp);
01458 char *out2 = cpl_sprintf("%s/centers.dat", dirname);
01459 fp = fopen(out2, "w");
01460 cpl_vector_dump(aCenters, fp);
01461 fclose(fp);
01462
01463 fprintf(gp, "set title \"located slices (IFU %hhu): median %.2f+/-%.2f, limit"
01464 " %.2f\"\nunset key\nset style fill solid 0.5\n", aIFU, aMedian, aMDev,
01465 aLimit);
01466 fprintf(gp, "median(x)=%e\nlimit(x)=%e\nlo(x)=%e\n",
01467 aMedian, aLimit, aMedian - aMDev);
01468 fprintf(gp, "set xrange [%d:%"CPL_SIZE_FORMAT"]\n", 1, cpl_vector_get_size(aRowVec));
01469 fprintf(gp, "set yrange [%e:%e]\n", aLimit - 0.5*aMDev, aMedian + 1.3*aMDev);
01470 fprintf(gp, "plot lo(x) w filledcu y1=%e, "
01471 " median(x) t \"median\", limit(x) t \"limit\" w l lw 2, "
01472 " \"%s\" w l lt 7, \"%s\" u 2:(%e):1 w p lt -1, "
01473 " \"%s\" u 2:(%e):1 w labels\n",
01474 aMedian+aMDev, out1, out2, aMedian, out2, aMedian+200);
01475
01476 pclose(gp);
01477 remove(out1);
01478 remove(out2);
01479 cpl_free(out1);
01480 cpl_free(out2);
01481 #if HAVE_MKDTEMP && HAVE_UNISTD_H
01482 int rc = rmdir(dirname);
01483 if (rc < 0) {
01484 cpl_msg_warning(__func__, "Used %s for plotting, please clean it manually!",
01485 dirname);
01486 }
01487 #endif
01488 #endif
01489 }
01490
01491
01513
01514 cpl_error_code
01515 muse_trace_plot_samples(cpl_table *aSamples, cpl_table *aTrace,
01516 unsigned short aSlice1, unsigned short aSlice2,
01517 unsigned char aIFU, muse_image *aImage)
01518 {
01519 #if HAVE_POPEN && HAVE_PCLOSE
01520 cpl_ensure_code(aSamples, CPL_ERROR_NULL_INPUT);
01521 cpl_error_code rc = muse_cpltable_check(aSamples, muse_tracesamples_def);
01522 cpl_ensure_code(rc == CPL_ERROR_NONE, rc);
01523
01524 if (aSlice1 < 1 || aSlice1 > kMuseSlicesPerCCD || aSlice1 > aSlice2 ||
01525 aSlice2 < 1 || aSlice2 > kMuseSlicesPerCCD) {
01526 fprintf(stderr, "Warning: resetting slice numbers (%hu to %hu does not make"
01527 " sense)!\n", aSlice1, aSlice2);
01528 aSlice1 = kMuseSlicesPerCCD / 2;
01529 aSlice2 = kMuseSlicesPerCCD / 2 + 1;
01530 }
01531 if (aSlice2 - aSlice1 > 10) {
01532 fprintf(stderr, "Warning: plotting %d slices may take a long time and "
01533 "RAM/disk space!\n", (int)aSlice2 - (int)aSlice1 + 1);
01534 }
01535 printf("Plotting ");;
01536 if (aIFU > 0) {
01537 printf("IFU %hhu, ", aIFU);
01538 }
01539 printf("slices %hu to %hu\n", aSlice1, aSlice2);
01540
01541 FILE *gp = popen("gnuplot", "w");
01542 if (!gp) {
01543 return CPL_ERROR_ASSIGNING_STREAM;
01544 }
01545
01546 int nx = -1, ny = kMuseOutputYTop;
01547 const float *data = NULL;
01548 if (aImage) {
01549 nx = cpl_image_get_size_x(aImage->data);
01550 ny = cpl_image_get_size_x(aImage->data);
01551 data = cpl_image_get_data_float_const(aImage->data);
01552 }
01553
01554
01555
01556 #if HAVE_MKDTEMP
01557 char dirtemplate[] = "/tmp/muse_trace_plot_samples_XXXXXX";
01558 char *dirname = mkdtemp(dirtemplate);
01559 if (!dirname) {
01560 return CPL_ERROR_FILE_NOT_CREATED;
01561 }
01562 #else
01563 char dirname[] = "/tmp";
01564 #endif
01565 FILE *tf = NULL, *sf = NULL;
01566 char *t_out = NULL;
01567 if (aImage) {
01568 t_out = cpl_sprintf("%s/muse_trace_plot_flatimage.dat", dirname);
01569 tf = fopen(t_out, "w+");
01570 if (!tf) {
01571 cpl_error_set_message(__func__, CPL_ERROR_FILE_NOT_CREATED, "\"%s\"",
01572 t_out);
01573 cpl_free(t_out);
01574 return CPL_ERROR_FILE_NOT_CREATED;
01575 }
01576 }
01577 char *s_out = cpl_sprintf("%s/muse_trace_plot_samples.dat", dirname);
01578 sf = fopen(s_out, "w+");
01579 if (!sf) {
01580 cpl_error_set_message(__func__, CPL_ERROR_FILE_NOT_CREATED, "%s", s_out);
01581 cpl_free(t_out);
01582 cpl_free(s_out);
01583 return CPL_ERROR_FILE_NOT_CREATED;
01584 }
01585
01586
01587 int i, lplot = INT_MAX, rplot = INT_MIN;
01588 unsigned short nslice;
01589 for (nslice = aSlice1; nslice <= aSlice2; nslice++) {
01590
01591 for (i = 0; i < cpl_table_get_nrow(aSamples); i++) {
01592 if (nslice != cpl_table_get_int(aSamples, "slice", i, NULL)) {
01593
01594 continue;
01595 }
01596 float l = cpl_table_get_float(aSamples, "left", i, NULL),
01597 r = cpl_table_get_float(aSamples, "right", i, NULL);
01598 fprintf(sf, "%g %g %g %g\n",
01599 cpl_table_get_float(aSamples, "y", i, NULL),
01600 cpl_table_get_float(aSamples, "mid", i, NULL), l, r);
01601 if ((int)floor(l) < lplot) {
01602 lplot = floor(l);
01603 }
01604 if ((int)floor(r) > rplot) {
01605 rplot = floor(r);
01606 }
01607 }
01608
01609 lplot -= 5;
01610 rplot += 5;
01611
01612 if (aTrace) {
01613 int order = muse_trace_table_get_order(aTrace);
01614 double *c = (double *)cpl_calloc(order + 1, sizeof(double));
01615
01616 int ipoly;
01617 for (ipoly = 0; ipoly < MUSE_TRACE_NPOLY; ipoly++) {
01618 for (i = 0; i <= order; i++) {
01619 char *colname = cpl_sprintf(MUSE_TRACE_TABLE_COL_COEFF, ipoly, i);
01620 c[i] = cpl_table_get_double(aTrace, colname, nslice-1, NULL);
01621 cpl_free(colname);
01622 }
01623
01624
01625 fprintf(gp, "p%02hu%1d(x) = (%g)", nslice, ipoly, c[0]);
01626 for (i = 1; i <= order; i++) {
01627 fprintf(gp, " + (%g) * x**(%d)", c[i], i);
01628 }
01629 fprintf(gp, "\n");
01630 }
01631 cpl_free(c);
01632 }
01633 }
01634 if (aImage) {
01635
01636 for (i = lplot - 1; i < rplot; i++) {
01637 int j;
01638 for (j = 0; j < ny; j++) {
01639 if (i < 0 || i >= nx || j < 0 || j >= ny) {
01640 continue;
01641 }
01642 fprintf(tf, "%d %d %f\n", i+1, j+1, data[i + j*nx]);
01643 }
01644 }
01645 printf("Written \"%s\".\n", t_out);
01646 fclose(tf);
01647 }
01648 printf("Written \"%s\".\n", s_out);
01649 fclose(sf);
01650
01651
01652 fprintf(gp, "set title \"trace result, ");
01653 if (aIFU > 0) {
01654 fprintf(gp, "IFU %hhu, ", aIFU);
01655 }
01656 fprintf(gp, "slices %hu to %hu\"\n", aSlice1, aSlice2);
01657 fprintf(gp, "set palette gray\n");
01658 fprintf(gp, "unset key\n");
01659
01660
01661 fprintf(gp, "set samples %d\n", ny);
01662
01663 fprintf(gp, "set parametric\n");
01664
01665 fprintf(gp, "set xrange [%d:%d]\n", lplot, rplot);
01666 fprintf(gp, "set yrange [%d:%d]\n", 1, ny);
01667 fprintf(gp, "set trange [%d:%d]\n", 1, ny);
01668
01669 fprintf(gp, "set cbrange [1e-4:1.5]\n");
01670
01671
01672 fprintf(gp, "plot ");
01673 if (aImage) {
01674 fprintf(gp, "\"%s\" w image, ", t_out);
01675 }
01676 fprintf(gp, "\"%s\" u 2:1 t \"center points\" w p pt 2 lt rgb \"blue\" ps 1.2, "
01677 "\"%s\" u 3:1 t \"edge points left\" w p pt 2 lt rgb \"red\" ps 0.8, "
01678 "\"%s\" u 4:1 t \"edge points right\" w p pt 2 lt rgb \"green\" ps 0.8",
01679 s_out, s_out, s_out);
01680 if (aTrace) {
01681
01682 for (nslice = aSlice1; nslice <= aSlice2; nslice++) {
01683 fprintf(gp, ", p%02hu0(t),t t \"center\" w l lt rgb \"dark-blue\" lw 2, "
01684 "p%02hu1(t),t t \"left\" w l lt rgb \"dark-red\" lw 1, "
01685 "p%02hu2(t),t t \"right\" w l lt rgb \"forest-green\" lw 1",
01686 nslice, nslice, nslice);
01687 }
01688 }
01689 fprintf(gp, "\n");
01690 fflush(gp);
01691
01692
01693
01694 printf("Press ENTER to end program and close plot\n");
01695 getchar();
01696 remove(s_out);
01697 if (aImage) {
01698 remove(t_out);
01699 cpl_free(t_out);
01700 }
01701 rmdir(dirname);
01702 cpl_free(s_out);
01703 pclose(gp);
01704 return CPL_ERROR_NONE;
01705 #else
01706 return CPL_ERROR_UNSUPPORTED_MODE;
01707 #endif
01708 }
01709
01710
01733
01734 cpl_error_code
01735 muse_trace_plot_widths(cpl_table *aSamples, unsigned short aSlice1,
01736 unsigned short aSlice2, unsigned char aIFU)
01737 {
01738 #if HAVE_POPEN && HAVE_PCLOSE
01739 cpl_ensure_code(aSamples, CPL_ERROR_NULL_INPUT);
01740 cpl_error_code rc = muse_cpltable_check(aSamples, muse_tracesamples_def);
01741 cpl_ensure_code(rc == CPL_ERROR_NONE, rc);
01742
01743 if (aSlice1 < 1 || aSlice1 > kMuseSlicesPerCCD || aSlice1 > aSlice2 ||
01744 aSlice2 < 1 || aSlice2 > kMuseSlicesPerCCD) {
01745 fprintf(stderr, "Warning: resetting slice numbers (%hu to %hu does not make"
01746 " sense)!\n", aSlice1, aSlice2);
01747 aSlice1 = kMuseSlicesPerCCD / 2;
01748 aSlice2 = kMuseSlicesPerCCD / 2 + 1;
01749 }
01750 printf("Plotting ");;
01751 if (aIFU > 0) {
01752 printf("IFU %hhu, ", aIFU);
01753 }
01754 printf("slices %hu to %hu\n", aSlice1, aSlice2);
01755
01756 FILE *gp = popen("gnuplot", "w");
01757 if (!gp) {
01758 return CPL_ERROR_ASSIGNING_STREAM;
01759 }
01760
01761 int nrow = cpl_table_get_nrow(aSamples);
01762 const int *sdata = cpl_table_get_data_int_const(aSamples, "slice");
01763 const float *ydata = cpl_table_get_data_float_const(aSamples, "y"),
01764 *ldata = cpl_table_get_data_float_const(aSamples, "left"),
01765 *rdata = cpl_table_get_data_float_const(aSamples, "right");
01766
01767
01768 fprintf(gp, "set title \"trace slice widths, ");
01769 if (aIFU > 0) {
01770 fprintf(gp, "IFU %hhu, ", aIFU);
01771 }
01772 fprintf(gp, "slices %hu to %hu\"\n", aSlice1, aSlice2);
01773 fprintf(gp, "set key outside below\n");
01774
01775 fprintf(gp, "set xrange [%d:%d]\n", 1, kMuseOutputYTop);
01776 fprintf(gp, "set yrange [%f:%f]\n", kMuseSliceLoLikelyWidth,
01777 kMuseSliceHiLikelyWidth);
01778 fprintf(gp, "set xlabel \"y position on CCD [pix]\"\n");
01779 fprintf(gp, "set ylabel \"slice width at y position [pix]\"\n");
01780
01781
01782 double dslice = (aSlice2 - aSlice1) / 255.;
01783 if (dslice == 0.) {
01784 dslice = 1.;
01785 }
01786
01787 fprintf(gp, "plot ");
01788 unsigned short nslice;
01789 for (nslice = aSlice1; nslice <= aSlice2; nslice++) {
01790
01791
01792 fprintf(gp, "\"-\" t \"slice %02hu\" w lp ps 0.8 lt rgb \"#%02x%02x%02x\"",
01793 nslice,
01794 (int)((nslice - aSlice1) / dslice),
01795 (int)((aSlice2 - nslice) / dslice),
01796 0);
01797 if (nslice == aSlice2) {
01798 fprintf(gp, "\n");
01799 } else {
01800 fprintf(gp, ", ");
01801 }
01802 }
01803 fflush(gp);
01804 for (nslice = aSlice1; nslice <= aSlice2; nslice++) {
01805 int i;
01806 for (i = 0; i < nrow; i++) {
01807 if (nslice == sdata[i]) {
01808 fprintf(gp, "%f %f\n", ydata[i], rdata[i]-ldata[i]);
01809 }
01810 }
01811 fprintf(gp, "EOF\n");
01812 }
01813 fprintf(gp, "\n");
01814 fflush(gp);
01815
01816
01817
01818 printf("Press ENTER to end program and close plot\n");
01819 getchar();
01820 pclose(gp);
01821 return CPL_ERROR_NONE;
01822 #else
01823 return CPL_ERROR_UNSUPPORTED_MODE;
01824 #endif
01825 }
01826