33 #define omp_get_max_threads() 1
38 #include "muse_resampling.h"
39 #include "muse_instrument.h"
41 #include "muse_astro.h"
42 #include "muse_cplwrappers.h"
45 #include "muse_flux.h"
46 #include "muse_pfits.h"
47 #include "muse_pixgrid.h"
48 #include "muse_pixtable.h"
49 #include "muse_quality.h"
50 #include "muse_utils.h"
52 #include "muse_data_format_z.h"
120 const cpl_propertylist *aWCS)
122 cpl_ensure_code(aParams, CPL_ERROR_NULL_INPUT);
125 cpl_wcs_delete(aParams->
wcs);
127 return CPL_ERROR_NONE;
129 if (cpl_propertylist_has(aWCS,
"CTYPE3") &&
130 !strncmp(cpl_propertylist_get_string(aWCS,
"CTYPE3"),
"AWAV-LOG", 9)) {
135 cpl_errorstate state = cpl_errorstate_get();
136 cpl_error_code rc = CPL_ERROR_NONE;
137 aParams->
wcs = cpl_wcs_new_from_propertylist(aWCS);
138 if (!cpl_errorstate_is_equal(state)) {
139 cpl_wcs_delete(aParams->
wcs);
141 rc = cpl_error_get_code();
144 printf(
"CDi_j matrix:\n");
145 cpl_matrix_dump(cpl_wcs_get_cd(aParams->
wcs), stdout);
166 cpl_wcs_delete(aParams->
wcs);
183 muse_resampling_weight_function_linear(
double r)
185 return r == 0 ? FLT_MAX : 1. / r;
201 muse_resampling_weight_function_quadratic(
double r2)
203 return r2 == 0 ? FLT_MAX : 1. / r2;
221 muse_resampling_weight_function_renka(
double r,
double r_c)
225 }
else if (r >= r_c) {
228 double p = (r_c - r) / (r_c * r);
242 muse_resampling_weight_function_sinc(
double r)
244 return fabs(r) < DBL_EPSILON ? 1. : sin(CPL_MATH_PI * r) / (CPL_MATH_PI * r);
259 muse_resampling_weight_function_lanczos(
double dx,
double dy,
double dz,
unsigned int n)
261 return (fabs(dx) >= n || fabs(dy) >= n || fabs(dz) > n) ? 0.
262 : muse_resampling_weight_function_sinc(dx) * muse_resampling_weight_function_sinc(dx / n)
263 * muse_resampling_weight_function_sinc(dy) * muse_resampling_weight_function_sinc(dy / n)
264 * muse_resampling_weight_function_sinc(dz) * muse_resampling_weight_function_sinc(dz / n);
288 muse_resampling_weight_function_drizzle(
double xin,
double yin,
double zin,
289 double xout,
double yout,
double zout,
290 double dx,
double dy,
double dz)
295 double x = (dx + xout / 2.) <= xin / 2. ? xout : (xin + xout) / 2. - dx,
296 y = (dy + yout / 2.) <= yin / 2. ? yout : (yin + yout) / 2. - dy,
297 z = (dz + zout / 2.) <= zin / 2. ? zout : (zin + zout) / 2. - dz;
300 if (x <= 0 || y <= 0 || z <= 0) {
305 return (x > xin ? xin : x) * (y > yin ? yin : y) * (z > zin ? zin : z)
326 static cpl_error_code
330 cpl_ensure_code(aCube && aPixtable && aPixgrid, CPL_ERROR_NULL_INPUT);
333 crval3 = cpl_propertylist_get_double(aCube->
header,
"CRVAL3"),
334 crpix3 = cpl_propertylist_get_double(aCube->
header,
"CRPIX3"),
335 cd33 = cpl_propertylist_get_double(aCube->
header,
"CD3_3");
338 cpl_boolean loglambda = !strncmp(cpl_propertylist_get_string(aCube->
header,
341 float *xpos = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_XPOS),
342 *ypos = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_YPOS),
343 *lbda = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_LAMBDA),
344 *data = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_DATA),
345 *stat = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_STAT);
346 int *dq = cpl_table_get_data_int(aPixtable->
table, MUSE_PIXTABLE_DQ);
352 double xnorm = 1., ynorm = 1., znorm = 1. / kMuseSpectralSamplingA;
358 ptxoff = cpl_propertylist_get_double(aPixtable->
header,
"CRVAL1");
359 ptyoff = cpl_propertylist_get_double(aPixtable->
header,
"CRVAL2");
362 #ifdef ESO_ENABLE_DEBUG
364 if (getenv(
"MUSE_DEBUG_NEAREST")) {
365 debug = atoi(getenv(
"MUSE_DEBUG_NEAREST"));
370 #ifdef ESO_ENABLE_DEBUG
371 #pragma omp parallel for default(none) \
372 shared(aCube, aPixgrid, cd33, crpix3, crval3, data, debug, dq, lbda, \
373 loglambda, ptxoff, ptyoff, stat, stdout, wcs, xnorm, xpos, \
376 #pragma omp parallel for default(none) \
377 shared(aCube, aPixgrid, cd33, crpix3, crval3, data, dq, lbda, \
378 loglambda, ptxoff, ptyoff, stat, stdout, wcs, xnorm, xpos, \
381 for (l = 0; l < aPixgrid->size_z; l++) {
382 float *pdata = cpl_image_get_data_float(cpl_imagelist_get(aCube->
data, l)),
383 *pstat = cpl_image_get_data_float(cpl_imagelist_get(aCube->
stat, l));
384 int *pdq = cpl_image_get_data_int(cpl_imagelist_get(aCube->
dq, l));
386 double lambda = (l + 1. - crpix3) * cd33 + crval3;
388 lambda = crval3 * exp((l + 1. - crpix3) * cd33 / crval3);
392 for (i = 0; i < aPixgrid->size_x; i++) {
394 for (j = 0; j < aPixgrid->size_y; j++) {
409 pdata[i + j * aPixgrid->size_x] = data[rows[0]];
410 pstat[i + j * aPixgrid->size_x] = stat[rows[0]];
411 pdq[i + j * aPixgrid->size_x] = dq[rows[0]];
413 #ifdef ESO_ENABLE_DEBUG
415 printf(
"only: %f,%f\n", data[rows[0]], stat[rows[0]]);
419 }
else if (n_rows >= 2) {
421 cpl_size n, nbest = -1;
422 double dbest = FLT_MAX;
423 for (n = 0; n < n_rows; n++) {
425 double dx = fabs(x - xpos[rows[n]] + ptxoff) * xnorm,
426 dy = fabs(y - ypos[rows[n]] + ptyoff) * ynorm,
427 dlambda = fabs(lambda - lbda[rows[n]]) * znorm,
428 dthis = sqrt(dx*dx + dy*dy + dlambda*dlambda);
432 dx *= cos(y * CPL_MATH_RAD_DEG);
434 #ifdef ESO_ENABLE_DEBUG
436 printf(
"%f %f %f, %f %f %f, d: %f %f %f -> %f best: %f (%f,%f)\n",
437 x, y, lambda, xpos[rows[n]] + ptxoff, ypos[rows[n]] + ptyoff,
438 lbda[rows[n]], dx, dy, dlambda, dthis, dbest, data[rows[n]],
447 pdata[i + j * aPixgrid->size_x] = data[rows[nbest]];
448 pstat[i + j * aPixgrid->size_x] = stat[rows[nbest]];
449 pdq[i + j * aPixgrid->size_x] = dq[rows[nbest]];
450 #ifdef ESO_ENABLE_DEBUG
452 printf(
"closest: %f,%f\n", data[rows[nbest]], stat[rows[nbest]]);
458 pdq[i + j * aPixgrid->size_x] = EURO3D_MISSDATA;
465 return CPL_ERROR_NONE;
490 static cpl_error_code
495 cpl_ensure_code(aCube && aPixtable && aPixgrid && aParams,
496 CPL_ERROR_NULL_INPUT);
499 crval3 = cpl_propertylist_get_double(aCube->
header,
"CRVAL3"),
500 crpix3 = cpl_propertylist_get_double(aCube->
header,
"CRPIX3"),
501 cd33 = cpl_propertylist_get_double(aCube->
header,
"CD3_3");
504 cpl_boolean loglambda = !strncmp(cpl_propertylist_get_string(aCube->
header,
507 cpl_errorstate prestate = cpl_errorstate_get();
508 float *xpos = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_XPOS),
509 *ypos = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_YPOS),
510 *lbda = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_LAMBDA),
511 *data = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_DATA),
512 *stat = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_STAT),
513 *wght = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_WEIGHT);
514 if (!cpl_errorstate_is_equal(prestate)) {
515 cpl_errorstate_set(prestate);
517 int *dq = cpl_table_get_data_int(aPixtable->
table, MUSE_PIXTABLE_DQ);
523 double xnorm = 1., ynorm = 1., znorm = 1. / kMuseSpectralSamplingA;
529 ptxoff = cpl_propertylist_get_double(aPixtable->
header,
"CRVAL1");
530 ptyoff = cpl_propertylist_get_double(aPixtable->
header,
"CRVAL2");
534 double zoutefac = exp(1.5 * cd33 / crval3) - exp(0.5 * cd33 / crval3);
536 double renka_rc = aParams->
rc
537 * sqrt((wcs->cd11*xnorm)*(wcs->cd11*xnorm) + (wcs->
cd22*ynorm)*(wcs->
cd22*ynorm)
538 + (cd33*znorm)*(cd33*znorm));
540 int ld = aParams->
ld;
543 cpl_msg_info(__func__,
"Overriding loop distance ld=%d", ld);
548 double xsz = aParams->
pfx / xnorm,
549 ysz = aParams->pfy / ynorm,
550 zsz = aParams->pfl / znorm,
551 xout = fabs(wcs->cd11), yout = fabs(wcs->
cd22), zout = fabs(cd33);
553 #ifdef ESO_ENABLE_DEBUG
554 int debug = 0, debugx = 0, debugy = 0, debugz = 0;
555 if (getenv(
"MUSE_DEBUG_WEIGHTED")) {
556 debug = atoi(getenv(
"MUSE_DEBUG_WEIGHTED"));
559 if (getenv(
"MUSE_DEBUG_WEIGHTED_X")) {
560 debugx = atoi(getenv(
"MUSE_DEBUG_WEIGHTED_X"));
561 if (debugx < 1 || debugx > aPixgrid->size_x) {
565 if (getenv(
"MUSE_DEBUG_WEIGHTED_Y")) {
566 debugy = atoi(getenv(
"MUSE_DEBUG_WEIGHTED_Y"));
567 if (debugy < 1 || debugy > aPixgrid->size_y) {
571 if (getenv(
"MUSE_DEBUG_WEIGHTED_Z")) {
572 debugz = atoi(getenv(
"MUSE_DEBUG_WEIGHTED_Z"));
573 if (debugz < 1 || debugz > aPixgrid->size_z) {
579 printf(
"parameters:\n cd=%e %e %e\n"
580 " corrected crpix3=%e\n norm=%e %e %e\n",
581 wcs->cd11, wcs->
cd22, cd33, crpix3, xnorm, ynorm, znorm);
583 printf(
" drop sizes %e %e %e (pixfrac %f,%f,%f)\n"
584 " output sizes %e %e %e\n",
585 xsz, ysz, zsz, aParams->
pfx, aParams->pfy, aParams->pfl,
588 printf(
" resulting renka_rc: %e %e %e / %e %e %e --> %e\n",
589 pow(wcs->cd11, 2), pow(wcs->
cd22, 2), cd33*cd33,
590 pow(wcs->cd11*xnorm, 2), pow(wcs->
cd22*ynorm, 2),
591 pow(cd33*znorm, 2), renka_rc);
596 cpl_imagelist *wcube = NULL;
597 if (getenv(
"MUSE_DEBUG_WEIGHT_CUBE")) {
598 cpl_msg_debug(__func__,
"Weighted resampling: creating weight cube");
599 wcube = cpl_imagelist_new();
601 for (i = 0; i < aPixgrid->size_z; i++) {
602 cpl_image *image = cpl_image_new(aPixgrid->size_x, aPixgrid->size_y,
604 cpl_imagelist_set(wcube, image, i);
608 if (getenv(
"MUSE_DEBUG_WEIGHTED_GRID")) {
609 char *fn = getenv(
"MUSE_DEBUG_WEIGHTED_GRID");
610 FILE *grid = fopen(fn,
"w");
612 cpl_msg_info(__func__,
"Writing grid to \"%s\"", fn);
613 fprintf(grid,
"# i j l x y lambda\n");
615 for (l = 0; l < aPixgrid->size_z; l++) {
616 double lambda = (l + 1. - crpix3) * cd33 + crval3;
618 for (i = 0; i < aPixgrid->size_x; i++) {
620 for (j = 0; j < aPixgrid->size_y; j++) {
628 fprintf(grid,
"%03d %03d %04d %.10f %.10f %8.3f\n", i+1, j+1, l+1,
635 cpl_msg_warning(__func__,
"Writing grid to \"%s\" failed!", fn);
640 #ifdef ESO_ENABLE_DEBUG
641 #pragma omp parallel for default(none) \
642 shared(aCube, aParams, aPixgrid, aPixtable, cd33, crpix3, crval3, \
643 data, debug, debugx, debugy, debugz, dq, lbda, ld, loglambda, \
644 ptxoff, ptyoff, renka_rc, stat, stdout, wcs, wcube, wght, \
645 xnorm, xout, xpos, xsz, ynorm, yout, ypos, ysz, znorm, zout, \
648 #pragma omp parallel for default(none) \
649 shared(aCube, aParams, aPixgrid, aPixtable, cd33, crpix3, crval3, \
650 data, dq, lbda, ld, loglambda, ptxoff, ptyoff, renka_rc, stat,\
651 stdout, wcs, wcube, wght, xnorm, xout, xpos, xsz, ynorm, yout,\
652 ypos, ysz, znorm, zout, zoutefac, zsz)
654 for (l = 0; l < aPixgrid->size_z; l++) {
655 float *pdata = cpl_image_get_data_float(cpl_imagelist_get(aCube->
data, l)),
656 *pstat = cpl_image_get_data_float(cpl_imagelist_get(aCube->
stat, l));
657 int *pdq = cpl_image_get_data_int(cpl_imagelist_get(aCube->
dq, l));
659 double lambda = (l + 1. - crpix3) * cd33 + crval3;
662 lambda = crval3 * exp((l + 1. - crpix3) * cd33 / crval3);
663 zout2 = crval3 * exp((l - crpix3) * cd33 / crval3) * zoutefac;
665 float *pwcube = NULL;
667 pwcube = cpl_image_get_data_float(cpl_imagelist_get(wcube, l));
671 for (i = 0; i < aPixgrid->size_x; i++) {
673 for (j = 0; j < aPixgrid->size_y; j++) {
681 double sumdata = 0, sumstat = 0, sumweight = 0;
683 #ifdef ESO_ENABLE_DEBUG
684 cpl_size *pointlist = NULL;
685 double *pointweights = NULL;
687 if (debug & 2 && i+1 == debugx && j+1 == debugy && l+1 == debugz) {
688 pointlist = cpl_calloc(100,
sizeof(cpl_size));
689 pointweights = cpl_malloc(100 *
sizeof(
double));
694 #ifdef ESO_ENABLE_DEBUG
696 printf(
"cell %d %d %d:\n", i, j, l);
701 for (i2 = i - ld; i2 <= i + ld; i2++) {
703 for (j2 = j - ld; j2 <= j + ld; j2++) {
705 for (l2 = l - ld; l2 <= l + ld; l2++) {
708 #ifdef ESO_ENABLE_DEBUG
709 if (debug & 8 && n_rows2 < 1) {
710 printf(
"%d %d %d / %d %d %d (%"CPL_SIZE_FORMAT
"): no rows!\n",
711 i+1, j+1, l+1, i2+1, j2+1, l2+1, idx2);
716 for (n = 0; n < n_rows2; n++) {
718 #ifdef ESO_ENABLE_DEBUG
720 printf(
"%d %d %d / %d %d %d (%"CPL_SIZE_FORMAT
", "
721 "%"CPL_SIZE_FORMAT
"): bad!\n",
722 i+1, j+1, l+1, i2+1, j2+1, l2+1, idx2, n);
729 double dx = fabs(x - (xpos[rows2[n]] + ptxoff)),
730 dy = fabs(y - (ypos[rows2[n]] + ptyoff)),
731 dlambda = fabs(lambda - lbda[rows2[n]]),
739 dx *= cos(y * CPL_MATH_RAD_DEG);
745 r2 = dx*dx + dy*dy + dlambda*dlambda;
749 weight = muse_resampling_weight_function_renka(sqrt(r2), renka_rc);
751 weight = muse_resampling_weight_function_drizzle(xsz, ysz, zsz,
755 weight = muse_resampling_weight_function_linear(sqrt(r2));
757 weight = muse_resampling_weight_function_quadratic(r2);
759 weight = muse_resampling_weight_function_lanczos(dx, dy, dlambda, ld);
764 weight *= wght[rows2[n]];
766 #ifdef ESO_ENABLE_DEBUG
768 printf(
"%d %d %d / %d %d %d (%"CPL_SIZE_FORMAT
", %"CPL_SIZE_FORMAT
"):"
769 " x %e %e %e %e y %e %e %e %e l %e %e %e %e --> %e %e %e\n",
770 i+1, j+1, l+1, i2+1, j2+1, l2+1, idx2, n,
771 x, xpos[rows2[n]]+ptxoff, fabs(x - (xpos[rows2[n]]+ptxoff)), dx,
772 y, ypos[rows2[n]]+ptyoff, fabs(y - (ypos[rows2[n]]+ptyoff)), dy,
773 lambda, lbda[rows2[n]], fabs(lambda - lbda[rows2[n]]), dlambda,
774 r2, sqrt(r2), weight);
779 sumdata += data[rows2[n]] * weight;
780 sumstat += stat[rows2[n]] * weight*weight;
782 #ifdef ESO_ENABLE_DEBUG
783 if (debug & 2 && i+1 == debugx && j+1 == debugy && l+1 == debugz) {
784 if (npoints > npointlist) {
785 pointlist = cpl_realloc(pointlist,
786 (npointlist + 100) *
sizeof(cpl_size));
787 memset(pointlist + npointlist, 0, 100 *
sizeof(cpl_size));
788 pointweights = cpl_realloc(pointweights,
789 (npointlist + 100) *
sizeof(
double));
793 pointlist[npoints-1] = rows2[n] + 1;
794 pointweights[npoints-1] = weight;
801 printf(
" pixel %4d,%4d,%4d (%8"CPL_SIZE_FORMAT
"): "
802 "%2"CPL_SIZE_FORMAT
" %2"CPL_SIZE_FORMAT
" %f %f %f, "
803 " %e -> %e ==> %e %e (%d)\n", i+1, j+1, l+1, idx,
804 n, count, dx, dy, dlambda,
806 weight, sumweight, sumdata, npoints);
815 #ifdef ESO_ENABLE_DEBUG
816 if (debug & 2 && i+1 == debugx && j+1 == debugy && l+1 == debugz) {
817 printf(
"cell center (%d, %d, %d): %14.7e %14.7e %9.3f\npixelnumber "
818 "weight ", debugx, debugy, debugz, x, y, lambda);
821 while (++m < npointlist && pointlist[m] != 0) {
823 printf(
"%12"CPL_SIZE_FORMAT
" %8.5f ", pointlist[m] - 1,
827 printf(
"sums: %g %g %g --> %g %g\n", sumdata, sumstat, sumweight,
828 sumdata / sumweight, sumstat / pow(sumweight, 2));
830 cpl_free(pointweights);
833 if (debug & 1 && npoints) {
834 printf(
" sumdata: %e %e (%d)", sumdata, sumweight, npoints);
841 if (!npoints || !isnormal(sumweight)) {
842 pdq[i + j * aPixgrid->size_x] = EURO3D_MISSDATA;
843 #ifdef ESO_ENABLE_DEBUG
845 printf(
" -> no points or weird weight\n");
852 sumdata /= sumweight;
853 sumstat /= sumweight*sumweight;
854 #ifdef ESO_ENABLE_DEBUG
856 printf(
" -> %e (%e)\n", sumdata, sumstat);
862 pdata[i + j * aPixgrid->size_x] = sumdata;
863 pstat[i + j * aPixgrid->size_x] = sumstat;
864 pdq[i + j * aPixgrid->size_x] = EURO3D_GOODPIXEL;
866 pwcube[i + j * aPixgrid->size_x] = sumweight;
874 const char *fn = getenv(
"MUSE_DEBUG_WEIGHT_CUBE");
875 cpl_error_code rc = cpl_imagelist_save(wcube, fn, CPL_TYPE_UNSPECIFIED,
876 NULL, CPL_IO_CREATE);
877 if (rc != CPL_ERROR_NONE) {
878 cpl_msg_warning(__func__,
"Failure to save weight cube as \"%s\": %s", fn,
879 cpl_error_get_message());
881 cpl_msg_info(__func__,
"Saved weight cube as \"%s\"", fn);
883 cpl_imagelist_delete(wcube);
886 return CPL_ERROR_NONE;
900 static cpl_error_code
904 cpl_ensure_code(aPixtable && aParams, CPL_ERROR_NULL_INPUT);
905 const char func[] =
"muse_resampling_cube";
908 if (aParams->dlambda == 0.0) {
909 aParams->dlambda = kMuseSpectralSamplingA;
911 aParams->dlambda /= 1.6;
917 if (aParams->
dx == 0.0) {
920 if (aParams->dy == 0.0) {
923 cpl_msg_debug(func,
"steps from parameters: %.2f pix, %.2f pix, %.3f Angstrom",
924 aParams->
dx, aParams->dy, aParams->dlambda);
925 return CPL_ERROR_NONE;
927 if (aParams->
dx == 0.0) {
928 aParams->
dx = kMuseSpaxelSizeX_WFM / 3600.;
930 aParams->
dx = kMuseSpaxelSizeX_NFM / 3600.;
934 aParams->
dx /= 3600.;
936 if (aParams->dy == 0.0) {
937 aParams->dy = kMuseSpaxelSizeY_WFM / 3600.;
939 aParams->dy = kMuseSpaxelSizeY_NFM / 3600.;
943 aParams->dy /= 3600.;
945 cpl_msg_debug(func,
"steps from parameters: %f arcsec, %f arcsec, %.3f Angstrom",
946 aParams->
dx * 3600., aParams->dy * 3600., aParams->dlambda);
947 return CPL_ERROR_NONE;
965 static cpl_error_code
968 int *aX,
int *aY,
int *aZ)
970 cpl_ensure_code(aPixtable && aParams && aX && aY && aZ, CPL_ERROR_NULL_INPUT);
971 const char func[] =
"muse_resampling_cube";
972 double x1, y1, x2, y2;
985 *aX = lround(fabs(x2 - x1) / aParams->
dx) + 1;
986 *aY = lround(fabs(y2 - y1) / aParams->dy) + 1;
989 *aZ = (int)ceil((lmax - lmin) / aParams->dlambda) + 1;
991 *aZ = (int)ceil(lmin / aParams->dlambda * log(lmax / lmin)) + 1;
993 cpl_msg_info(func,
"Output cube size %d x %d x %d (fit to data)",
995 return CPL_ERROR_NONE;
1010 muse_resampling_override_size_int(
int *aV,
const char *aKeyword,
int aValue)
1012 if (aValue <= 0 || !aV) {
1015 const char func[] =
"muse_resampling_cube";
1016 cpl_msg_info(func,
"Overriding %s=%d (was %d)", aKeyword, aValue, *aV);
1035 static cpl_error_code
1036 muse_resampling_override_size(
int *aX,
int *aY,
int *aZ,
1039 cpl_ensure_code(aX && aY && aZ && aParams, CPL_ERROR_NULL_INPUT);
1040 if (!aParams->
wcs) {
1041 return CPL_ERROR_NONE;
1043 const char func[] =
"muse_resampling_cube";
1045 const cpl_array *dims = cpl_wcs_get_image_dims(aParams->
wcs);
1047 cpl_msg_debug(func,
"No dimensions to override were specified");
1048 return CPL_ERROR_NONE;
1050 muse_resampling_override_size_int(aX,
"NAXIS1", cpl_array_get_int(dims, 0, NULL));
1051 muse_resampling_override_size_int(aY,
"NAXIS2", cpl_array_get_int(dims, 1, NULL));
1052 if (cpl_wcs_get_image_naxis(aParams->
wcs) >= 3) {
1053 muse_resampling_override_size_int(aZ,
"NAXIS3",
1054 cpl_array_get_int(dims, 2, NULL));
1056 return CPL_ERROR_NONE;
1072 muse_resampling_override_wcs_double(
muse_datacube *aCube,
const char *aKeyword,
1073 double aValue,
int aError)
1075 if (aError || !aCube) {
1076 cpl_msg_debug(
"double",
"%s=%#g (%d)", aKeyword, aValue, aError);
1079 const char func[] =
"muse_resampling_cube";
1080 double old = cpl_propertylist_has(aCube->
header, aKeyword)
1081 ? cpl_propertylist_get_double(aCube->
header, aKeyword) : NAN;
1082 cpl_msg_info(func,
"Overriding %s=%#g (was %#g)", aKeyword, aValue, old);
1083 cpl_propertylist_update_double(aCube->
header, aKeyword, aValue);
1086 cpl_propertylist_update_bool(aCube->
header,
"MUSE_RESAMPLING_WCS_OVERRIDDEN",
1103 static cpl_error_code
1107 cpl_ensure_code(aCube && aCube->
header && aParams, CPL_ERROR_NULL_INPUT);
1108 if (!aParams->
wcs) {
1109 return CPL_ERROR_NONE;
1111 const char func[] =
"muse_resampling_cube";
1112 const cpl_array *crval = cpl_wcs_get_crval(aParams->
wcs),
1113 *crpix = cpl_wcs_get_crpix(aParams->
wcs);
1114 const cpl_matrix *cd = cpl_wcs_get_cd(aParams->
wcs);
1118 muse_resampling_override_wcs_double(aCube,
"CRVAL1", cpl_array_get_double(crval, 0, &err), err);
1119 muse_resampling_override_wcs_double(aCube,
"CRVAL2", cpl_array_get_double(crval, 1, &err), err);
1121 cpl_msg_debug(func,
"No CRVALj to override were specified");
1124 muse_resampling_override_wcs_double(aCube,
"CRPIX1", cpl_array_get_double(crpix, 0, &err), err);
1125 muse_resampling_override_wcs_double(aCube,
"CRPIX2", cpl_array_get_double(crpix, 1, &err), err);
1127 cpl_msg_debug(func,
"No CRPIXi to override were specified");
1130 int naxes = cpl_matrix_get_ncol(cd);
1131 if (cpl_matrix_get_determinant(cd) == 0.) {
1132 cpl_msg_warning(func,
"det(CDi_j) = 0, not overriding CDi_j!");
1134 }
else if (naxes > 2 && (cpl_matrix_get(cd, 0, 2) != 0. ||
1135 cpl_matrix_get(cd, 2, 0) != 0. ||
1136 cpl_matrix_get(cd, 2, 1) != 0. ||
1137 cpl_matrix_get(cd, 1, 2) != 0.)) {
1138 cpl_msg_warning(func,
"Axis 3 (dispersion) is not cleanly separated from "
1139 "axes 1 and 2, not overriding CDi_j!");
1142 cpl_errorstate es = cpl_errorstate_get();
1143 muse_resampling_override_wcs_double(aCube,
"CD1_1", cpl_matrix_get(cd, 0, 0),
1144 !cpl_errorstate_is_equal(es));
1145 es = cpl_errorstate_get();
1146 muse_resampling_override_wcs_double(aCube,
"CD1_2", cpl_matrix_get(cd, 0, 1),
1147 !cpl_errorstate_is_equal(es));
1148 es = cpl_errorstate_get();
1149 muse_resampling_override_wcs_double(aCube,
"CD2_1", cpl_matrix_get(cd, 1, 0),
1150 !cpl_errorstate_is_equal(es));
1151 es = cpl_errorstate_get();
1152 muse_resampling_override_wcs_double(aCube,
"CD2_2", cpl_matrix_get(cd, 1, 1),
1153 !cpl_errorstate_is_equal(es));
1156 cpl_msg_debug(func,
"No CDi_j to override were specified");
1161 if (cpl_array_get_size(crval) > 2) {
1163 muse_resampling_override_wcs_double(aCube,
"CRVAL3",
1164 cpl_array_get_double(crval, 2, &err) * 1e10, err);
1167 muse_resampling_override_wcs_double(aCube,
"CRPIX3", cpl_array_get_double(crpix, 2, &err), err);
1170 cpl_errorstate es = cpl_errorstate_get();
1171 muse_resampling_override_wcs_double(aCube,
"CD3_3", cpl_matrix_get(cd, 2, 2) * 1e10,
1172 !cpl_errorstate_is_equal(es));
1175 return CPL_ERROR_NONE;
1189 static cpl_error_code
1192 cpl_ensure_code(aCube && aPixtable, CPL_ERROR_NULL_INPUT);
1193 const char func[] =
"muse_resampling_cube";
1197 if (cpl_propertylist_has(aCube->
header,
"MUSE_RESAMPLING_WCS_OVERRIDDEN") &&
1198 cpl_propertylist_get_bool(aCube->
header,
"MUSE_RESAMPLING_WCS_OVERRIDDEN")) {
1199 cpl_msg_debug(func,
"Output WCS was forced, won't update CRPIX[12]!");
1200 cpl_propertylist_erase(aCube->
header,
"MUSE_RESAMPLING_WCS_OVERRIDDEN");
1201 return CPL_ERROR_NONE;
1204 double xoff1, yoff1, xoff2, yoff2;
1219 double xoff = fmin(xoff1, xoff2) - 1,
1220 yoff = fmin(yoff1, yoff2) - 1;
1221 if (xoff != 0. || yoff != 0.) {
1222 double crpix1 = cpl_propertylist_get_double(aCube->
header,
"CRPIX1"),
1223 crpix2 = cpl_propertylist_get_double(aCube->
header,
"CRPIX2");
1224 cpl_msg_debug(func,
"Updating CRPIX[12]=%#g,%#g (were %#g,%#g)",
1225 crpix1 - xoff, crpix2 - yoff, crpix1, crpix2);
1228 cpl_propertylist_update_double(aCube->
header,
"CRPIX1", crpix1);
1229 cpl_propertylist_update_double(aCube->
header,
"CRPIX2", crpix2);
1231 return CPL_ERROR_NONE;
1236 const char *crtypestring[] = {
1242 #define MUSE_RESAMPLING_CRREJECT_COMPUTE_STATS_START \
1243 cpl_size idx = muse_pixgrid_get_index(aPixgrid, i2, j2, l2, CPL_FALSE),\
1244 nrow = muse_pixgrid_get_count(aPixgrid, idx), \
1246 const cpl_size *rows = muse_pixgrid_get_rows(aPixgrid, idx); \
1247 for (irow = 0; irow < nrow; irow++) { \
1248 if (muse_quality_is_usable(dq[rows[irow]], badinclude)) { \
1250 } else if (dq[rows[irow]]) { \
1253 #define MUSE_RESAMPLING_CRREJECT_COMPUTE_STATS_DEBUG \
1254 if (debug & 4 && i+1 == debugx && j+1 == debugy && l+1 == debugz) { \
1255 printf("%s: data / stat (%"CPL_SIZE_FORMAT") = %e / %e\n", \
1256 __func__, npixels+1, data[rows[irow]], stat[rows[irow]]); \
1258 #define MUSE_RESAMPLING_CRREJECT_COMPUTE_STATS_END \
1259 if (aType == MUSE_RESAMPLING_CRSTATS_IRAF) { \
1261 level += data[rows[irow]]; \
1262 dev += stat[rows[irow]]; \
1265 if (npixels >= sxsize) { \
1267 sxsize += MUSE_CRREJECT_MAX_NPIX; \
1268 cpl_image *tmp = cpl_image_new(sxsize, 2, CPL_TYPE_DOUBLE); \
1269 cpl_image_copy(tmp, sdata, 1, 1); \
1270 cpl_image_delete(sdata); \
1272 vdata = cpl_image_get_data_double(sdata); \
1274 vdata[npixels] = data[rows[irow]]; \
1275 vdata[npixels + sxsize] = stat[rows[irow]]; \
1309 const char *
id =
"muse_resampling_cube";
1311 cpl_msg_warning(
id,
"Unknown type (%u) for cosmic-ray rejection statistics,"
1312 " resetting to \"%s\"", aType,
1316 cpl_msg_info(
id,
"Using %s statistics (%.3f sigma level) for cosmic-ray"
1317 " rejection", crtypestring[aType], aSigma);
1319 #ifdef ESO_ENABLE_DEBUG
1320 int debug = 0, debugx = 0, debugy = 0, debugz = 0;
1321 if (getenv(
"MUSE_DEBUG_CRREJECT")) {
1322 debug = atoi(getenv(
"MUSE_DEBUG_CRREJECT"));
1325 if (getenv(
"MUSE_DEBUG_CRREJECT_X")) {
1326 debugx = atoi(getenv(
"MUSE_DEBUG_CRREJECT_X"));
1327 if (debugx < 1 || debugx > aPixgrid->size_x) {
1331 if (getenv(
"MUSE_DEBUG_CRREJECT_Y")) {
1332 debugy = atoi(getenv(
"MUSE_DEBUG_CRREJECT_Y"));
1333 if (debugy < 1 || debugy > aPixgrid->size_y) {
1337 if (getenv(
"MUSE_DEBUG_CRREJECT_Z")) {
1338 debugz = atoi(getenv(
"MUSE_DEBUG_CRREJECT_Z"));
1339 if (debugz < 1 || debugz > aPixgrid->size_z) {
1351 enum dirtype dir = DIR_NONE;
1355 const double palimit = 5.;
1356 if (!haswcs || (fabs(posang) < palimit || fabs(fabs(posang) - 180.) < palimit ||
1357 fabs(fabs(posang) - 360.) < palimit)) {
1358 cpl_msg_debug(
id,
"CR rejection: posang = %f deg --> DIR_X "
1359 "(%s / %s / %s / %s)", posang, haswcs ?
"yes":
"no",
1360 fabs(posang) < palimit ?
"true" :
"false",
1361 fabs(fabs(posang) - 180.) < palimit ?
"true" :
"false",
1362 fabs(fabs(posang) - 360.) < palimit ?
"true" :
"false");
1364 }
else if (fabs(fabs(posang) - 90.) < palimit ||
1365 fabs(fabs(posang) - 270.) < palimit) {
1366 cpl_msg_debug(
id,
"CR rejection: posang = %f deg --> DIR_Y "
1367 "(%s / %s / %s)", posang, haswcs ?
"yes":
"no",
1368 fabs(fabs(posang) - 90.) < palimit ?
"true" :
"false",
1369 fabs(fabs(posang) - 270.) < palimit ?
"true" :
"false");
1372 cpl_msg_debug(
id,
"CR rejection: posang = %f deg --> DIR_NONE "
1373 "(%s / %s / %s / %s / %s / %s)", posang, haswcs ?
"yes":
"no",
1374 fabs(posang) < palimit ?
"true" :
"false",
1375 fabs(fabs(posang) - 90.) < palimit ?
"true" :
"false",
1376 fabs(fabs(posang) - 180.) < palimit ?
"true" :
"false",
1377 fabs(fabs(posang) - 270.) < palimit ?
"true" :
"false",
1378 fabs(fabs(posang) - 360.) < palimit ?
"true" :
"false");
1382 float *data = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_DATA),
1383 *stat = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_STAT);
1384 int *dq = cpl_table_get_data_int(aPixtable->
table, MUSE_PIXTABLE_DQ);
1387 uint32_t badinclude = EURO3D_COSMICRAY;
1389 #ifdef ESO_ENABLE_DEBUG
1390 #pragma omp parallel for default(none) \
1391 shared(aPixgrid, aPixtable, aSigma, badinclude, aType, crtypestring, \
1392 data, debug, debugx, debugy, debugz, dir, dq, id, stat, stdout)
1394 #pragma omp parallel for default(none) \
1395 shared(aPixgrid, aSigma, aType, badinclude, crtypestring, data, dir, \
1398 for (l = 0; l < aPixgrid->size_z; l++) {
1399 #define MUSE_CRREJECT_MAX_NPIX 1000
1400 int sxsize = MUSE_CRREJECT_MAX_NPIX;
1401 cpl_image *sdata = NULL;
1402 double *vdata = NULL;
1406 sdata = cpl_image_new(sxsize, 2, CPL_TYPE_DOUBLE);
1407 vdata = cpl_image_get_data_double(sdata);
1411 for (i = 0; i < aPixgrid->size_x; i++) {
1413 for (j = 0; j < aPixgrid->size_y; j++) {
1416 double level = 0., dev = 0;
1419 cpl_size npixels = 0;
1422 for (i2 = i - CR_LD; i2 <= i + CR_LD; i2++) {
1427 for (j2 = j - nwidth; j2 <= j + nwidth; j2++) {
1428 for (l2 = l - nwidth; l2 <= l + nwidth; l2++) {
1429 MUSE_RESAMPLING_CRREJECT_COMPUTE_STATS_START
1430 #ifdef ESO_ENABLE_DEBUG
1431 MUSE_RESAMPLING_CRREJECT_COMPUTE_STATS_DEBUG
1433 MUSE_RESAMPLING_CRREJECT_COMPUTE_STATS_END
1438 for (j2 = j - CR_LD; j2 <= j + CR_LD; j2++) {
1440 if (dir == DIR_X && j2 == j) {
1443 for (i2 = i - nwidth; i2 <= i + nwidth; i2++) {
1444 for (l2 = l - nwidth; l2 <= l + nwidth; l2++) {
1445 MUSE_RESAMPLING_CRREJECT_COMPUTE_STATS_START
1446 #ifdef ESO_ENABLE_DEBUG
1447 MUSE_RESAMPLING_CRREJECT_COMPUTE_STATS_DEBUG
1449 MUSE_RESAMPLING_CRREJECT_COMPUTE_STATS_END
1460 dev = sqrt(dev) / npixels;
1464 sflags = CPL_STATS_MEDIAN | CPL_STATS_MAD;
1466 sflags = CPL_STATS_MEAN | CPL_STATS_STDEV;
1468 cpl_stats *sstats = cpl_stats_new_from_image_window(sdata, sflags,
1471 level = cpl_stats_get_median(sstats);
1472 dev = cpl_stats_get_mad(sstats);
1474 level = cpl_stats_get_mean(sstats);
1475 dev = cpl_stats_get_stdev(sstats);
1477 cpl_stats_delete(sstats);
1479 double limit = level + aSigma * dev;
1480 #ifdef ESO_ENABLE_DEBUG
1481 if (debug & 2 && i+1 == debugx && j+1 == debugy && l+1 == debugz) {
1483 printf(
"%s: %03d,%03d,%04d: %.3f+/-%.3f (stats), %.3f (limit) (%"
1484 CPL_SIZE_FORMAT
" values)\n", __func__, i+1, j+1, l+1, level,
1485 dev, limit, npixels);
1487 cpl_stats *ssdata = cpl_stats_new_from_image_window(sdata, CPL_STATS_ALL,
1489 *ssstat = cpl_stats_new_from_image_window(sdata, CPL_STATS_ALL,
1491 printf(
"%s: %03d,%03d,%04d: %e +/- %e (%s), %e (limit) (%"CPL_SIZE_FORMAT
1492 " values); data stats:\n", __func__, i+1, j+1, l+1,
1493 level, dev, crtypestring[aType], limit, npixels);
1494 cpl_stats_dump(ssdata, CPL_STATS_ALL, stdout);
1495 printf(
"%s: variance stats:\n", __func__);
1496 cpl_stats_dump(ssstat, CPL_STATS_ALL, stdout);
1498 cpl_stats_delete(ssdata);
1499 cpl_stats_delete(ssstat);
1509 for (irow = 0; irow < nrow; irow++) {
1510 if (data[rows[irow]] > limit) {
1511 dq[rows[irow]] |= EURO3D_COSMICRAY;
1512 #ifdef ESO_ENABLE_DEBUG
1513 if (debug & 1 && i+1 == debugx && j+1 == debugy && l+1 == debugz) {
1514 printf(
"%s: %03d,%03d,%04d: rejected row %"CPL_SIZE_FORMAT
" (%"
1515 CPL_SIZE_FORMAT
" of %"CPL_SIZE_FORMAT
" in this gridcell):\t",
1516 __func__, i+1, j+1, l+1, rows[irow], irow+1, nrow);
1522 #ifdef ESO_ENABLE_DEBUG
1529 cpl_image_delete(sdata);
1561 cpl_ensure(aParams, CPL_ERROR_NULL_INPUT, NULL);
1573 e3d->
header = cpl_propertylist_duplicate(cube->
header);
1574 cpl_propertylist_erase_regexp(e3d->
header,
1575 "^SIMPLE$|^BITPIX$|^NAXIS|^EURO3D$|^E3D_",
1577 cpl_propertylist_append_char(e3d->
header,
"EURO3D",
'T');
1578 cpl_propertylist_set_comment(e3d->
header,
"EURO3D",
1579 "file conforms to Euro3D standard");
1581 cpl_propertylist_append_string(e3d->
header,
"E3D_VERS",
"1.0");
1582 cpl_propertylist_set_comment(e3d->
header,
"E3D_VERS",
1583 "version number of the Euro3D format");
1584 cpl_errorstate prestate = cpl_errorstate_get();
1585 double darlambdaref = cpl_propertylist_get_double(e3d->
header,
1587 if (!cpl_errorstate_is_equal(prestate)) {
1589 cpl_errorstate_set(prestate);
1591 if (darlambdaref > 0.) {
1592 cpl_propertylist_append_char(e3d->
header,
"E3D_ADC",
'T');
1593 cpl_propertylist_set_comment(e3d->
header,
"E3D_ADC",
1594 "data was corrected for atmospheric dispersion");
1596 cpl_propertylist_append_char(e3d->
header,
"E3D_ADC",
'F');
1597 cpl_propertylist_set_comment(e3d->
header,
"E3D_ADC",
1598 "data not corrected for atmospheric dispersion");
1602 e3d->
hdata = cpl_propertylist_new();
1603 cpl_propertylist_append_string(e3d->
hdata,
"EXTNAME",
"E3D_DATA");
1604 cpl_propertylist_set_comment(e3d->
hdata,
"EXTNAME",
1605 "This is the Euro3D data table extension");
1606 cpl_propertylist_append_string(e3d->
hdata,
"CTYPES",
1607 cpl_propertylist_get_string(e3d->
header,
"CTYPE3"));
1608 cpl_propertylist_set_comment(e3d->
hdata,
"CTYPES",
1609 cpl_propertylist_get_comment(e3d->
header,
"CTYPE3"));
1610 cpl_propertylist_append_string(e3d->
hdata,
"CUNITS",
1611 cpl_propertylist_get_string(e3d->
header,
"CUNIT3"));
1612 cpl_propertylist_set_comment(e3d->
hdata,
"CUNITS",
1613 cpl_propertylist_get_comment(e3d->
header,
"CUNIT3"));
1614 cpl_propertylist_append_double(e3d->
hdata,
"CRVALS",
1615 cpl_propertylist_get_double(e3d->
header,
"CRVAL3"));
1616 cpl_propertylist_set_comment(e3d->
hdata,
"CRVALS",
1617 cpl_propertylist_get_comment(e3d->
header,
"CRVAL3"));
1618 cpl_propertylist_append_double(e3d->
hdata,
"CDELTS",
1619 cpl_propertylist_get_double(e3d->
header,
"CD3_3"));
1620 cpl_propertylist_set_comment(e3d->
hdata,
"CDELTS",
1621 cpl_propertylist_get_comment(e3d->
header,
"CD3_3"));
1623 cpl_propertylist_erase_regexp(e3d->
header,
"^C...*3$|^CD3_.$", 0);
1626 int nx = cpl_image_get_size_x(cpl_imagelist_get(cube->
data, 0)),
1627 ny = cpl_image_get_size_y(cpl_imagelist_get(cube->
data, 0)),
1628 nz = cpl_imagelist_get_size(cube->
data);
1633 cpl_table_set_column_depth(e3d->
dtable,
"DATA_SPE", nz);
1634 cpl_table_set_column_depth(e3d->
dtable,
"QUAL_SPE", nz);
1635 cpl_table_set_column_depth(e3d->
dtable,
"STAT_SPE", nz);
1637 cpl_table_set_column_unit(e3d->
dtable,
"DATA_SPE",
1638 cpl_table_get_column_unit(aPixtable->
table,
1639 MUSE_PIXTABLE_DATA));
1640 cpl_table_set_column_unit(e3d->
dtable,
"STAT_SPE",
1641 cpl_table_get_column_unit(aPixtable->
table,
1642 MUSE_PIXTABLE_STAT));
1644 cpl_table_set_column_savetype(e3d->
dtable,
"SELECTED", CPL_TYPE_BOOL);
1649 cpl_table_set_column_unit(e3d->
dtable,
"XPOS",
"deg");
1650 cpl_table_set_column_unit(e3d->
dtable,
"YPOS",
"deg");
1654 unsigned euro3d_ignore = EURO3D_OUTSDRANGE | EURO3D_MISSDATA;
1655 cpl_vector *vusable = cpl_vector_new(nx * ny);
1657 for (i = 1; i <= nx; i++) {
1659 for (j = 1; j <= ny; j++) {
1660 cpl_array *adata = cpl_array_new(nz, CPL_TYPE_FLOAT),
1661 *adq = cpl_array_new(nz, CPL_TYPE_INT),
1662 *astat = cpl_array_new(nz, CPL_TYPE_FLOAT);
1671 int l, nusable = 0, nstart = -1;
1672 for (l = 0; l < nz; l++) {
1674 unsigned dq = cpl_image_get(cpl_imagelist_get(cube->
dq, l), i, j, &err);
1676 if (nstart < 0 && (dq & euro3d_ignore)) {
1679 cpl_array_set_int(adq, nusable, dq);
1680 cpl_array_set_float(adata, nusable,
1681 cpl_image_get(cpl_imagelist_get(cube->
data, l),
1684 cpl_array_set_float(astat, nusable,
1685 sqrt(cpl_image_get(cpl_imagelist_get(cube->
stat, l),
1693 cpl_table_set_int(e3d->
dtable,
"SPEC_ID", itable, itable + 1);
1694 cpl_table_set_int(e3d->
dtable,
"SPEC_LEN", itable, nusable);
1695 cpl_table_set_int(e3d->
dtable,
"SPEC_STA", itable, nstart);
1696 cpl_table_set_double(e3d->
dtable,
"XPOS", itable, x);
1697 cpl_table_set_double(e3d->
dtable,
"YPOS", itable, y);
1700 cpl_table_set_array(e3d->
dtable,
"DATA_SPE", itable, adata);
1701 cpl_table_set_array(e3d->
dtable,
"QUAL_SPE", itable, adq);
1702 cpl_table_set_array(e3d->
dtable,
"STAT_SPE", itable, astat);
1704 cpl_array_delete(adata);
1705 cpl_array_delete(adq);
1706 cpl_array_delete(astat);
1708 cpl_vector_set(vusable, itable, nusable);
1709 if (nstart != -1 && nusable > 0) {
1711 cpl_table_unselect_row(e3d->
dtable, itable);
1718 cpl_vector_set_size(vusable, itable);
1719 int maxusable = cpl_vector_get_max(vusable);
1721 cpl_msg_debug(__func__,
"filled %d of %d spaxels, usable are "
1722 "%f..%f(%f)+/-%f..%d pixels per spectrum", itable, nx * ny,
1723 cpl_vector_get_min(vusable), cpl_vector_get_mean(vusable),
1724 cpl_vector_get_median(vusable), cpl_vector_get_stdev(vusable),
1727 cpl_msg_debug(__func__,
"filled %"CPL_SIZE_FORMAT
" of %d spaxels, usable "
1728 "are max. %d of %d pixels per spectrum%s",
1729 itable - cpl_table_count_selected(e3d->
dtable), nx * ny,
1730 maxusable, nz, maxusable == nz ?
"" :
", cutting table");
1731 if (maxusable != nz) {
1733 cpl_table_set_column_depth(e3d->
dtable,
"DATA_SPE", maxusable);
1734 cpl_table_set_column_depth(e3d->
dtable,
"QUAL_SPE", maxusable);
1735 cpl_table_set_column_depth(e3d->
dtable,
"STAT_SPE", maxusable);
1738 cpl_table_erase_selected(e3d->
dtable);
1739 cpl_vector_delete(vusable);
1743 cpl_table_fill_column_window_int(e3d->
dtable,
"SELECTED", 0, itable,
1746 cpl_table_fill_column_window_int(e3d->
dtable,
"NSPAX", 0, itable, 1);
1748 cpl_table_fill_column_window_int(e3d->
dtable,
"GROUP_N", 0, itable, 1);
1754 e3d->
hgroup = cpl_propertylist_new();
1755 cpl_propertylist_append_string(e3d->
hgroup,
"EXTNAME",
"E3D_GRP");
1756 cpl_propertylist_set_comment(e3d->
hgroup,
"EXTNAME",
1757 "This is the Euro3D group table extension");
1759 cpl_table_set_int(e3d->
gtable,
"GROUP_N", 0, 1);
1760 cpl_table_set_string(e3d->
gtable,
"G_SHAPE", 0,
"R");
1761 cpl_table_set_float(e3d->
gtable,
"G_SIZE1", 0, aParams->
dx);
1762 cpl_table_set_float(e3d->
gtable,
"G_ANGLE", 0, 0.);
1763 cpl_table_set_float(e3d->
gtable,
"G_SIZE2", 0, aParams->dy);
1764 if (darlambdaref > 0.) {
1766 cpl_table_set_float(e3d->
gtable,
"G_POSWAV", 0, NAN);
1767 cpl_table_set_float(e3d->
gtable,
"G_AIRMAS", 0, NAN);
1768 cpl_table_set_float(e3d->
gtable,
"G_PARANG", 0, NAN);
1769 cpl_table_set_float(e3d->
gtable,
"G_PRESSU", 0, NAN);
1770 cpl_table_set_float(e3d->
gtable,
"G_TEMPER", 0, NAN);
1771 cpl_table_set_float(e3d->
gtable,
"G_HUMID", 0, NAN);
1774 cpl_table_set_float(e3d->
gtable,
"G_POSWAV", 0,
1775 (kMuseNominalLambdaMin + kMuseNominalLambdaMax) / 2.);
1776 cpl_table_set_float(e3d->
gtable,
"G_AIRMAS", 0,
1778 cpl_table_set_float(e3d->
gtable,
"G_PARANG", 0,
1780 cpl_table_set_float(e3d->
gtable,
"G_PRESSU", 0,
1783 cpl_table_set_float(e3d->
gtable,
"G_TEMPER", 0,
1785 cpl_table_set_float(e3d->
gtable,
"G_HUMID", 0,
1848 cpl_ensure(aPixtable && aParams, CPL_ERROR_NULL_INPUT, NULL);
1850 CPL_ERROR_ILLEGAL_INPUT, NULL);
1858 muse_resampling_check_deltas(aPixtable, aParams);
1862 int xsize = 0, ysize = 0, zsize = 0;
1863 muse_resampling_compute_size(aPixtable, aParams, &xsize, &ysize, &zsize);
1864 muse_resampling_override_size(&xsize, &ysize, &zsize, aParams);
1865 cpl_ensure(xsize > 0 && ysize > 0 && zsize > 0, CPL_ERROR_ILLEGAL_OUTPUT,
1868 double time = cpl_test_get_walltime();
1874 cube->
header = cpl_propertylist_duplicate(aPixtable->
header);
1875 cpl_propertylist_erase_regexp(cube->
header,
1876 "^SIMPLE$|^BITPIX$|^NAXIS|^EXTEND$|^XTENSION$|"
1877 "^DATASUM$|^DATAMIN$|^DATAMAX$|^DATAMD5$|"
1878 "^PCOUNT$|^GCOUNT$|^HDUVERS$|^BLANK$|"
1879 "^BZERO$|^BSCALE$|^CHECKSUM$|^INHERIT$|"
1880 "^EXTNAME$|"MUSE_WCS_KEYS
"|"MUSE_HDR_PT_REGEXP,
1883 cpl_propertylist_update_string(cube->
header,
"BUNIT",
1884 cpl_table_get_column_unit(aPixtable->
table,
1885 MUSE_PIXTABLE_DATA));
1887 cpl_propertylist_update_int(cube->
header,
"NAXIS", 3);
1888 cpl_propertylist_update_int(cube->
header,
"NAXIS1", xsize);
1889 cpl_propertylist_update_int(cube->
header,
"NAXIS2", ysize);
1890 cpl_propertylist_update_int(cube->
header,
"NAXIS3", zsize);
1894 cpl_propertylist_copy_property_regexp(cube->
header, aPixtable->
header,
1896 cpl_propertylist_update_double(cube->
header,
"CD1_1", -aParams->
dx);
1897 cpl_propertylist_update_double(cube->
header,
"CD2_2", aParams->dy);
1898 cpl_propertylist_update_double(cube->
header,
"CD1_2", 0.);
1899 cpl_propertylist_update_double(cube->
header,
"CD2_1", 0.);
1901 cpl_propertylist_update_double(cube->
header,
"CRPIX1",
1902 cpl_propertylist_get_double(cube->
header,
"CRPIX1")
1903 + (1. + xsize) / 2.);
1904 cpl_propertylist_update_double(cube->
header,
"CRPIX2",
1905 cpl_propertylist_get_double(cube->
header,
"CRPIX2")
1906 + (1. + ysize) / 2.);
1908 cpl_propertylist_erase(cube->
header,
"WCSAXES");
1911 cpl_propertylist_append_double(cube->
header,
"CRPIX1", 1.);
1912 cpl_propertylist_append_double(cube->
header,
"CRVAL1",
1913 cpl_propertylist_get_float(aPixtable->
header,
1917 cpl_propertylist_append_string(cube->
header,
"CTYPE1",
"PIXEL");
1918 cpl_propertylist_append_string(cube->
header,
"CUNIT1",
"pixel");
1919 cpl_propertylist_append_double(cube->
header,
"CD1_1", aParams->
dx);
1920 cpl_propertylist_append_double(cube->
header,
"CRPIX2", 1.);
1921 cpl_propertylist_append_double(cube->
header,
"CRVAL2",
1922 cpl_propertylist_get_float(aPixtable->
header,
1924 cpl_propertylist_append_string(cube->
header,
"CTYPE2",
"PIXEL");
1925 cpl_propertylist_append_string(cube->
header,
"CUNIT2",
"pixel");
1926 cpl_propertylist_append_double(cube->
header,
"CD2_2", aParams->dy);
1928 cpl_propertylist_append_double(cube->
header,
"CD1_2", 0.);
1929 cpl_propertylist_append_double(cube->
header,
"CD2_1", 0.);
1932 cpl_propertylist_append_string(cube->
header,
"CTYPE3",
"AWAV-LOG");
1934 cpl_propertylist_append_string(cube->
header,
"CTYPE3",
"AWAV");
1936 cpl_propertylist_append_string(cube->
header,
"CUNIT3",
"Angstrom");
1937 cpl_propertylist_append_double(cube->
header,
"CD3_3", aParams->dlambda);
1938 cpl_propertylist_append_double(cube->
header,
"CRPIX3", 1.);
1939 cpl_propertylist_append_double(cube->
header,
"CRVAL3",
1940 cpl_propertylist_get_float(aPixtable->
header,
1943 cpl_propertylist_append_double(cube->
header,
"CD1_3", 0.);
1944 cpl_propertylist_append_double(cube->
header,
"CD2_3", 0.);
1945 cpl_propertylist_append_double(cube->
header,
"CD3_1", 0.);
1946 cpl_propertylist_append_double(cube->
header,
"CD3_2", 0.);
1949 muse_resampling_override_wcs(cube, aParams);
1951 muse_resampling_fit_data_to_grid(cube, aPixtable);
1955 cube->
data = cpl_imagelist_new();
1956 cube->
dq = cpl_imagelist_new();
1957 cube->
stat = cpl_imagelist_new();
1959 for (i = 0; i < zsize; i++) {
1960 cpl_image *image = cpl_image_new(xsize, ysize, CPL_TYPE_FLOAT);
1962 cpl_imagelist_set(cube->
data, image, i);
1964 cpl_imagelist_set(cube->
stat, cpl_image_duplicate(image), i);
1968 image = cpl_image_new(xsize, ysize, CPL_TYPE_INT);
1970 cpl_image_add_scalar(image, EURO3D_OUTSDRANGE);
1971 cpl_imagelist_set(cube->
dq, image, i);
1978 xsize, ysize, zsize);
1981 muse_resampling_crreject(aPixtable, pixgrid, aParams->
crtype,
1986 double timeinit = cpl_test_get_walltime(),
1987 cpuinit = cpl_test_get_cputime();
1990 cpl_error_code rc = CPL_ERROR_NONE;
1991 switch (aParams->
method) {
1993 cpl_msg_info(__func__,
"Starting resampling, using method \"nearest\"");
1994 rc = muse_resampling_cube_nearest(cube, aPixtable, pixgrid);
1997 cpl_msg_info(__func__,
"Starting resampling, using method \"renka\" "
1998 "(critical radius rc=%f, loop distance ld=%d)", aParams->
rc,
2000 rc = muse_resampling_cube_weighted(cube, aPixtable, pixgrid, aParams);
2005 cpl_msg_info(__func__,
"Starting resampling, using method \"%s\" (loop "
2013 rc = muse_resampling_cube_weighted(cube, aPixtable, pixgrid, aParams);
2016 cpl_msg_info(__func__,
"Starting resampling, using method \"drizzle\" "
2017 "(pixfrac f=%.3f,%.3f,%.3f, loop distance ld=%d)",
2018 aParams->
pfx, aParams->pfy, aParams->pfl, aParams->
ld);
2019 rc = muse_resampling_cube_weighted(cube, aPixtable, pixgrid, aParams);
2022 cpl_msg_debug(__func__,
"Method %d (no resampling)", aParams->
method);
2025 cpl_msg_error(__func__,
"Don't know this resampling method: %d",
2027 cpl_error_set(__func__, CPL_ERROR_UNSUPPORTED_MODE);
2028 rc = CPL_ERROR_UNSUPPORTED_MODE;
2032 double timefini = cpl_test_get_walltime(),
2033 cpufini = cpl_test_get_cputime();
2037 *aPixgrid = pixgrid;
2042 cpl_msg_debug(__func__,
"resampling took %.3fs (wall-clock) and %.3fs "
2043 "(%.3fs CPU, %d CPUs) for muse_resampling_cube*() alone",
2044 timefini - time, timefini - timeinit, cpufini - cpuinit,
2045 omp_get_max_threads());
2046 if (rc != CPL_ERROR_NONE) {
2047 cpl_msg_error(__func__,
"resampling failed: %s", cpl_error_get_message());
2092 cpl_ensure(aPixtable && aPixtable->
table && aPixgrid && aParams &&
2093 aCube && aCube->
header, CPL_ERROR_NULL_INPUT, NULL);
2100 cpl_errorstate prestate = cpl_errorstate_get();
2101 float *xpos = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_XPOS),
2102 *ypos = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_YPOS),
2103 *lbda = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_LAMBDA),
2104 *data = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_DATA),
2105 *stat = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_STAT),
2106 *wght = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_WEIGHT);
2107 if (!cpl_errorstate_is_equal(prestate)) {
2108 cpl_errorstate_set(prestate);
2110 int *dq = cpl_table_get_data_int(aPixtable->
table, MUSE_PIXTABLE_DQ);
2116 double xnorm = 1., ynorm = 1.,
2124 ptxoff = cpl_propertylist_get_double(aPixtable->
header,
"CRVAL1");
2125 ptyoff = cpl_propertylist_get_double(aPixtable->
header,
"CRVAL2");
2128 double renka_rc = aParams->
rc
2129 * sqrt(pow(wcs->cd11*xnorm, 2) + pow(wcs->
cd22*xnorm, 2));
2131 int ld = aParams->
ld;
2134 cpl_msg_info(__func__,
"Overriding loop distance ld=%d", ld);
2138 double xsz = aParams->
pfx / xnorm,
2139 ysz = aParams->pfy / ynorm,
2140 xout = fabs(wcs->cd11), yout = fabs(wcs->
cd22);
2143 image->
data = cpl_image_new(aPixgrid->size_x, aPixgrid->size_y, CPL_TYPE_FLOAT);
2144 image->
dq = cpl_image_new(aPixgrid->size_x, aPixgrid->size_y, CPL_TYPE_INT);
2145 image->
stat = cpl_image_new(aPixgrid->size_x, aPixgrid->size_y, CPL_TYPE_FLOAT);
2146 image->
header = cpl_propertylist_duplicate(aCube->
header);
2147 cpl_propertylist_erase_regexp(image->
header,
"^C...*3$|^CD3_.$", 0);
2148 float *pdata = cpl_image_get_data_float(image->
data),
2149 *pstat = cpl_image_get_data_float(image->
stat);
2150 int *pdq = cpl_image_get_data_int(image->
dq);
2153 cpl_boolean usevariance = CPL_FALSE;
2154 if (getenv(
"MUSE_COLLAPSE_USE_VARIANCE") &&
2155 atoi(getenv(
"MUSE_COLLAPSE_USE_VARIANCE")) > 0) {
2156 usevariance = CPL_TRUE;
2162 const double *flbda = cpl_table_get_data_double_const(aFilter,
"lambda"),
2163 *fresp = cpl_table_get_data_double_const(aFilter,
"throughput");
2164 int l = 0, nl = cpl_table_get_nrow(aFilter);
2165 while (l < nl && fabs(fresp[l]) < DBL_EPSILON) {
2169 while (l > 0 && fabs(fresp[l]) < DBL_EPSILON) {
2172 cpl_msg_debug(__func__,
"filter wavelength range %.1f..%.1fA", lmin, lmax);
2176 cpl_msg_debug(__func__,
"full wavelength range %.1f..%.1fA", lmin, lmax);
2180 #pragma omp parallel for default(none) \
2181 shared(aFilter, aParams, aPixgrid, data, dq, lbda, ld, lmax, lmin, \
2182 pdata, pdq, pstat, ptxoff, ptyoff, renka_rc, stat, usevariance,\
2183 wcs, wght, xnorm, xout, xpos, xsz, ynorm, yout, ypos, ysz)
2184 for (i = 0; i < aPixgrid->size_x; i++) {
2186 for (j = 0; j < aPixgrid->size_y; j++) {
2194 double sumdata = 0, sumstat = 0, sumweight = 0;
2195 cpl_size npoints = 0;
2199 for (i2 = i - ld; i2 <= i + ld; i2++) {
2201 for (j2 = j - ld; j2 <= j + ld; j2++) {
2204 for (l2 = 0; l2 < aPixgrid->size_z; l2++) {
2208 for (n = 0; n < n_rows2; n++) {
2212 if (usevariance && !isnormal(stat[rows2[n]])) {
2215 if (lbda[rows2[n]] > lmax || lbda[rows2[n]] < lmin) {
2219 double dx = fabs(x - (xpos[rows2[n]] + ptxoff)),
2220 dy = fabs(y - (ypos[rows2[n]] + ptyoff)),
2225 dx *= cos(y * CPL_MATH_RAD_DEG);
2234 weight = muse_resampling_weight_function_renka(sqrt(r2), renka_rc);
2236 weight = muse_resampling_weight_function_drizzle(xsz, ysz, 1.,
2240 weight = muse_resampling_weight_function_linear(sqrt(r2));
2242 weight = muse_resampling_weight_function_quadratic(r2);
2244 weight = muse_resampling_weight_function_lanczos(dx, dy, 0., ld);
2249 weight *= wght[rows2[n]];
2258 weight /= stat[rows2[n]];
2260 sumweight += weight;
2261 sumdata += data[rows2[n]] * weight;
2262 sumstat += stat[rows2[n]] * weight*weight;
2272 if (!npoints || !isnormal(sumweight)) {
2273 pdq[i + j * aPixgrid->size_x] = EURO3D_MISSDATA;
2278 sumdata /= sumweight;
2279 sumstat /= sumweight*sumweight;
2280 pdata[i + j * aPixgrid->size_x] = sumdata;
2281 pstat[i + j * aPixgrid->size_x] = sumstat;
2282 pdq[i + j * aPixgrid->size_x] = EURO3D_GOODPIXEL;
2311 static cpl_error_code
2315 cpl_ensure_code(aImage && aPixtable && aPixgrid, CPL_ERROR_NULL_INPUT);
2316 aImage->
data = cpl_image_new(aPixgrid->size_x, aPixgrid->size_z,
2319 double crval2 = cpl_propertylist_get_double(aImage->
header,
"CRVAL2"),
2320 cd22 = cpl_propertylist_get_double(aImage->
header,
"CD2_2");
2322 float *lbda = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_LAMBDA),
2323 *data = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_DATA);
2324 float *imagedata = cpl_image_get_data_float(aImage->
data);
2326 #ifdef ESO_ENABLE_DEBUG
2328 if (getenv(
"MUSE_DEBUG_NEAREST")) {
2329 debug = atoi(getenv(
"MUSE_DEBUG_NEAREST"));
2334 for (i = 0; i < aPixgrid->size_x; i++) {
2336 for (j = 0; j < aPixgrid->size_z; j++) {
2342 imagedata[i + j * aPixgrid->size_x] = data[rows[0]];
2343 #ifdef ESO_ENABLE_DEBUG
2345 printf(
"only: %f\n", data[rows[0]]);
2349 }
else if (n_rows >= 2) {
2351 cpl_size n, nbest = -1;
2352 double dbest = FLT_MAX;
2353 for (n = 0; n < n_rows; n++) {
2356 double dlambda = fabs(j * cd22 + crval2 - lbda[rows[n]]);
2357 #ifdef ESO_ENABLE_DEBUG
2359 printf(
"%f, %f, d: %f best: %f (%f)\n",
2360 j * cd22 + crval2, lbda[rows[n]],
2361 dlambda, dbest, data[rows[n]]);
2364 if (dlambda < dbest) {
2369 imagedata[i + j * aPixgrid->size_x] = data[rows[nbest]];
2370 #ifdef ESO_ENABLE_DEBUG
2372 printf(
"closest: %f\n", data[rows[nbest]]);
2382 return CPL_ERROR_NONE;
2402 static cpl_error_code
2406 cpl_ensure_code(aImage && aPixtable && aPixgrid, CPL_ERROR_NULL_INPUT);
2407 aImage->
data = cpl_image_new(aPixgrid->size_x, aPixgrid->size_z,
2410 double crval2 = cpl_propertylist_get_double(aImage->
header,
"CRVAL2"),
2411 cd22 = cpl_propertylist_get_double(aImage->
header,
"CD2_2");
2413 float *lbda = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_LAMBDA),
2414 *data = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_DATA);
2415 float *imagedata = cpl_image_get_data_float(aImage->
data);
2417 #ifdef ESO_ENABLE_DEBUG
2418 int debug = 0, debugx = 0, debugz = 0;
2419 if (getenv(
"MUSE_DEBUG_WEIGHTED")) {
2420 debug = atoi(getenv(
"MUSE_DEBUG_WEIGHTED"));
2423 if (getenv(
"MUSE_DEBUG_WEIGHTED_X")) {
2424 debugx = atoi(getenv(
"MUSE_DEBUG_WEIGHTED_X"));
2425 if (debugx < 1 || debugx > aPixgrid->size_x) {
2429 if (getenv(
"MUSE_DEBUG_WEIGHTED_Z")) {
2430 debugz = atoi(getenv(
"MUSE_DEBUG_WEIGHTED_Z"));
2431 if (debugz < 1 || debugz > aPixgrid->size_z) {
2441 double renka_rc = 1.25;
2446 for (i = 0; i < aPixgrid->size_x; i++) {
2448 for (j = 0; j < aPixgrid->size_z; j++) {
2449 double sumdata = 0, sumweight = 0,
2450 lambda = j * cd22 + crval2;
2452 #ifdef ESO_ENABLE_DEBUG
2453 #define MAX_NPIX_2D 50
2454 int *pointlist = NULL;
2455 double *pointweights = NULL;
2456 if (debug & 128 && i+1 == debugx && j+1 == debugz) {
2457 pointlist = cpl_calloc(MAX_NPIX_2D,
sizeof(
int));
2458 pointweights = cpl_malloc(MAX_NPIX_2D *
sizeof(
double));
2464 for (j2 = j - ld; j2 <= j + ld; j2++) {
2468 for (n = 0; n < n_rows; n++) {
2469 double dlambda = fabs(lambda - lbda[rows[n]]),
2470 weight = muse_resampling_weight_function_renka(dlambda,
2472 sumweight += weight;
2473 sumdata += data[rows[n]] * weight;
2475 #ifdef ESO_ENABLE_DEBUG
2476 if (debug & 128 && i+1 == debugx && j+1 == debugz &&
2477 npoints-1 < MAX_NPIX_2D) {
2479 pointlist[npoints-1] = rows[n] + 1;
2480 pointweights[npoints-1] = weight;
2484 printf(
" pixel %4d,%4d (%8"CPL_SIZE_FORMAT
"): %2"CPL_SIZE_FORMAT
2485 " %2"CPL_SIZE_FORMAT
" %f, %f -> %f ==> %f %f (%d)\n",
2488 weight, sumweight, sumdata, npoints);
2494 #ifdef ESO_ENABLE_DEBUG
2495 if (debug & 128 && i+1 == debugx && j+1 == debugz) {
2496 printf(
"pixelnumber weight ");
2499 while (++m < MAX_NPIX_2D && pointlist[m] != 0) {
2501 printf(
"%12d %8.5f ", pointlist[m] - 1, pointweights[m]);
2505 cpl_free(pointlist);
2506 cpl_free(pointweights);
2518 imagedata[i + j * aPixgrid->size_x] = sumdata / sumweight;
2522 return CPL_ERROR_NONE;
2546 double aDX,
double aLambdaMin,
2547 double aLambdaMax,
double aDLambda)
2549 double dlambda = aDLambda;
2552 aLambdaMin, aLambdaMax,
2558 image->
header = cpl_propertylist_new();
2559 const char *unit = cpl_table_get_column_unit(aPixtable->
table,
"data");
2560 cpl_propertylist_append_string(image->
header,
"BUNIT", unit);
2564 cpl_propertylist_copy_property_regexp(image->
header, aPixtable->
header,
2565 MUSE_HDR_PT_REGEXP
"|"MUSE_WCS_KEYS, 1);
2566 cpl_propertylist_append_double(image->
header,
"CRPIX1", 1.);
2567 cpl_propertylist_append_double(image->
header,
"CRPIX2", 1.);
2568 cpl_propertylist_append_double(image->
header,
"CRVAL1", 1.);
2569 cpl_propertylist_append_double(image->
header,
"CRVAL2", aLambdaMin);
2570 cpl_propertylist_append_double(image->
header,
"CD1_1", 1.);
2571 cpl_propertylist_append_double(image->
header,
"CD2_2", dlambda);
2573 cpl_propertylist_append_string(image->
header,
"CUNIT1",
"pixel");
2574 cpl_propertylist_append_string(image->
header,
"CUNIT2",
"Angstrom");
2577 cpl_propertylist_append_string(image->
header,
"CTYPE1",
"PIXEL");
2580 cpl_propertylist_append_string(image->
header,
"CTYPE2",
"AWAV");
2582 cpl_propertylist_append_double(image->
header,
"CD1_2", 0.);
2583 cpl_propertylist_append_double(image->
header,
"CD2_1", 0.);
2586 cpl_error_code rc = CPL_ERROR_NONE;
2589 rc = muse_resampling_image_nearest(image, aPixtable, pixgrid);
2593 rc = muse_resampling_image_weighted(image, aPixtable, pixgrid);
2597 if (rc != CPL_ERROR_NONE) {
2598 cpl_msg_error(__func__,
"resampling failed: %s", cpl_error_get_message());
2649 double aDX,
double aDLambda)
2651 cpl_ensure(aPixtable, CPL_ERROR_NULL_INPUT, NULL);
2652 if (aDLambda == 0.0) {
2653 aDLambda = kMuseSpectralSamplingA;
2663 cpl_msg_info(__func__,
"Using nearest neighbor sampling (%d) along "
2664 "wavelengths.", aMethod);
2667 cpl_msg_info(__func__,
"Using renka-weighted interpolation (%d) along "
2668 "wavelengths.", aMethod);
2671 cpl_msg_error(__func__,
"Don't know this resampling method: %d", aMethod);
2672 cpl_error_set(__func__, CPL_ERROR_UNSUPPORTED_MODE);
2685 return muse_resampling_image_selected(aPixtable, aMethod,
2686 aDX == 0.0 ? 1. : aDX,
2687 lmin, lmax, aDLambda);
2707 cpl_msg_debug(__func__,
"Resampling %d slices to a 2D image, using bins of"
2708 " %e %s x %.3f Angstrom", n_slices, dx,
2709 cpl_table_get_column_unit(aPixtable->
table, MUSE_PIXTABLE_XPOS),
2715 #pragma omp parallel for default(none) \
2716 shared(aDLambda, aMethod, dx, i_slice, lmax, lmin, n_slices, \
2717 slice_image, slice_pixtable)
2718 for (i_slice = 0; i_slice < n_slices; i_slice++) {
2720 cpl_msg_debug(__func__,
"slice pixel table %d", i_slice + 1);
2724 slice_image[i_slice] = NULL;
2727 slice_image[i_slice] = muse_resampling_image_selected(pt, aMethod, dx,
2728 lmin, lmax, aDLambda);
2733 for (i_slice = 0; i_slice < n_slices; i_slice++) {
2736 cpl_msg_debug(__func__,
"slice %d: %ldx%ld", i_slice + 1,
2737 cpl_image_get_size_x(slice->
data), cpl_image_get_size_y(slice->
data));
2739 if (slice == NULL) {
2744 image->
header = cpl_propertylist_duplicate(slice->
header);
2747 cpl_image_delete(image->
data);
2751 cpl_image_delete(image->
dq);
2756 cpl_image_delete(image->
stat);
2760 slice_image[i_slice] = NULL;
2784 cpl_ensure(aPixtable != NULL, CPL_ERROR_NULL_INPUT, NULL);
2789 cpl_size lsize = floor((lmax - lmin) / aBinwidth) + 2;
2793 cpl_table_fill_column_window(spectrum,
"lambda", 0, lsize, 0);
2794 cpl_table_fill_column_window(spectrum,
"data", 0, lsize, 0);
2795 cpl_table_fill_column_window(spectrum,
"stat", 0, lsize, 0);
2796 cpl_table_fill_column_window(spectrum,
"dq", 0, lsize, 0);
2797 double *spec_data = cpl_table_get_data_double(spectrum,
"data");
2798 double *spec_stat = cpl_table_get_data_double(spectrum,
"stat");
2799 double *spec_lbda = cpl_table_get_data_double(spectrum,
"lambda");
2801 cpl_table_set_column_unit(spectrum,
"data",
2802 cpl_table_get_column_unit(aPixtable->
table,
2803 MUSE_PIXTABLE_DATA));
2804 cpl_table_set_column_unit(spectrum,
"stat",
2805 cpl_table_get_column_unit(aPixtable->
table,
2806 MUSE_PIXTABLE_STAT));
2809 cpl_table_new_column(spectrum,
"weight", CPL_TYPE_DOUBLE);
2810 cpl_table_fill_column_window(spectrum,
"weight", 0, lsize, 0);
2811 double *spec_weight = cpl_table_get_data_double(spectrum,
"weight");
2814 float *lbda = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_LAMBDA);
2815 float *data = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_DATA);
2816 float *stat = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_STAT);
2818 if (cpl_table_has_column(aPixtable->
table, MUSE_PIXTABLE_WEIGHT)) {
2819 wght = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_WEIGHT);
2821 int *dq = cpl_table_get_data_int(aPixtable->
table, MUSE_PIXTABLE_DQ);
2825 cpl_array *asel = cpl_table_where_selected(aPixtable->
table);
2826 const cpl_size *sel = cpl_array_get_data_cplsize_const(asel);
2827 cpl_size isel, nsel = cpl_array_get_size(asel);
2828 cpl_msg_debug(__func__,
"Resample spectrum from %" CPL_SIZE_FORMAT
2830 for (isel = 0; isel < nsel; isel++) {
2831 cpl_size i_row = sel[isel];
2832 if ((dq[i_row] != EURO3D_GOODPIXEL)) {
2836 double l = (lbda[i_row] - lmin) / aBinwidth;
2838 cpl_size il = floor(l);
2847 spec_data[il] += w0 * data[i_row];
2848 spec_data[il+1] += w1 * data[i_row];
2849 spec_stat[il] += w0 * stat[i_row];
2850 spec_stat[il+1] += w1 * stat[i_row];
2851 spec_weight[il] += w0;
2852 spec_weight[il+1] += w1;
2854 cpl_array_delete(asel);
2858 for (ispec = 0; ispec < lsize; ispec++) {
2859 if (spec_weight[ispec] > 0) {
2860 spec_lbda[ispec] = ispec * aBinwidth + lmin;
2861 cpl_table_unselect_row(spectrum, ispec);
2864 cpl_table_erase_selected(spectrum);
2867 cpl_table_divide_columns(spectrum,
"data",
"weight");
2868 cpl_table_divide_columns(spectrum,
"stat",
"weight");
2869 cpl_table_erase_column(spectrum,
"weight");
muse_pixtable_wcs
State of the astrometric calibration of a MUSE pixel table.
Structure definition of a MUSE datacube.
muse_image * muse_resampling_image(muse_pixtable *aPixtable, muse_resampling_type aMethod, double aDX, double aDLambda)
Resample a pixel table onto a two-dimensional regular grid.
cpl_error_code muse_wcs_get_scales(cpl_propertylist *aHeader, double *aXScale, double *aYScale)
Compute the spatial scales (in degrees) from the FITS header WCS.
cpl_error_code muse_wcs_pixel_from_projplane(cpl_propertylist *aHeader, double aX, double aY, double *aXOut, double *aYOut)
Convert from projection plane coordinates to pixel coordinates.
void muse_image_delete(muse_image *aImage)
Deallocate memory associated to a muse_image object.
void muse_pixtable_extracted_delete(muse_pixtable **aPixtables)
Delete a pixel table array.
muse_pixgrid * muse_pixgrid_2d_create(cpl_table *aTable, double aDX, double aZMin, double aZMax, double aDZ, float *aXMin)
Convert selected rows of a pixel table into 2D pixgrid, linking the grid points to entries (=rows) in...
#define MUSE_HDR_PT_XLO
FITS header keyword contains the lower limit of the data in x-direction.
cpl_size muse_pixtable_extracted_get_size(muse_pixtable **aPixtables)
Get the size of an array of extracted pixel tables.
double muse_pfits_get_rhum(const cpl_propertylist *aHeaders)
find out the relavtive humidity (in %)
A structure containing a spatial two-axis WCS.
cpl_error_code muse_resampling_params_set_wcs(muse_resampling_params *aParams, const cpl_propertylist *aWCS)
Set an output WCS (and wavelength scale) in the resampling parameters.
muse_pixgrid * muse_pixgrid_create(muse_pixtable *aPixtable, cpl_propertylist *aHeader, cpl_size aXSize, cpl_size aYSize, cpl_size aZSize)
Convert selected rows of a pixel table into pixel grid, linking the grid points to entries (=rows) in...
muse_pixtable ** muse_pixtable_extracted_get_slices(muse_pixtable *aPixtable)
Extract one pixel table per IFU and slice.
cpl_image * data
the data extension
cpl_size muse_pixtable_get_nrow(const muse_pixtable *aPixtable)
get the number of rows within the pixel table
#define MUSE_HDR_PT_LHI
FITS header keyword contains the upper limit of the data in spectral direction.
int muse_pixtable_get_type(muse_pixtable *aPixtable)
Determine the type of pixel table.
void muse_utils_memory_dump(const char *aMarker)
Display the current memory usage of the given program.
cpl_error_code muse_pixtable_dump(muse_pixtable *aPixtable, cpl_size aStart, cpl_size aCount, unsigned char aDisplayHeader)
Dump a MUSE pixel table to the screen, resolving the origin column.
double muse_pfits_get_pres_start(const cpl_propertylist *aHeaders)
find out the ambient pressure at start of exposure (in mbar)
cpl_image * stat
the statistics extension
cpl_error_code muse_wcs_projplane_from_celestial(cpl_propertylist *aHeader, double aRA, double aDEC, double *aX, double *aY)
Convert from celestial spherical coordinates to projection plane coordinates.
void muse_datacube_delete(muse_datacube *aCube)
Deallocate memory associated to a muse_datacube object.
cpl_propertylist * hgroup
the group FITS header
cpl_propertylist * header
the primary FITS header
double muse_astro_parangle(const cpl_propertylist *aHeader)
Properly average parallactic angle values of one exposure.
Structure definition of MUSE three extension FITS file.
cpl_table * table
The pixel table.
cpl_propertylist * header
the FITS header
muse_resampling_crstats_type crtype
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.
double muse_flux_response_interpolate(const cpl_table *aResponse, double aLambda, double *aError, muse_flux_interpolation_type aType)
Compute linearly interpolated response of some kind at given wavelength.
muse_wcs * muse_wcs_new(cpl_propertylist *aHeader)
Create a new WCS structure from a given FITS header.
Structure definition of MUSE pixel table.
muse_pixtable_wcs muse_pixtable_wcs_check(muse_pixtable *aPixtable)
Check the state of the world coordinate system of a pixel table.
#define MUSE_HDR_PT_YLO
FITS header keyword contains the lower limit of the data in y-direction.
static void muse_wcs_celestial_from_pixel_fast(muse_wcs *aWCS, double aX, double aY, double *aRA, double *aDEC)
Convert from pixel coordinates to celestial spherical coordinates.
muse_resampling_crstats_type
Cosmic ray rejection statistics type.
muse_resampling_params * muse_resampling_params_new(muse_resampling_type aMethod)
Create the resampling parameters structure.
cpl_error_code muse_wcs_projplane_from_pixel(cpl_propertylist *aHeader, double aX, double aY, double *aXOut, double *aYOut)
Convert from pixel coordinates to projection plane coordinates.
cpl_imagelist * data
the cube containing the actual data values
cpl_error_code muse_wcs_pixel_from_celestial(cpl_propertylist *aHeader, double aRA, double aDEC, double *aX, double *aY)
Convert from celestial spherical coordinates to pixel coordinates.
Structure definition of a Euro3D datacube.
static const cpl_size * muse_pixgrid_get_rows(muse_pixgrid *aPixels, cpl_size aIndex)
Return a pointer to the rows stored in one pixel.
muse_datacube * muse_resampling_cube(muse_pixtable *aPixtable, muse_resampling_params *aParams, muse_pixgrid **aPixgrid)
Resample a pixel table onto a regular grid structure representing a FITS NAXIS=3 datacube.
cpl_imagelist * dq
the optional cube containing the bad pixel status
muse_resampling_dispersion_type tlambda
#define MUSE_HDR_PT_LLO
FITS header keyword contains the lower limit of the data in spectral direction.
cpl_table * dtable
the table containing the actual Euro3D data
cpl_image * muse_cplimage_concat_x(const cpl_image *aImage1, const cpl_image *aImage2)
Concatenate two images in x direction.
cpl_propertylist * hdata
the data FITS header
muse_image * muse_resampling_collapse_pixgrid(muse_pixtable *aPixtable, muse_pixgrid *aPixgrid, muse_datacube *aCube, cpl_table *aFilter, muse_resampling_params *aParams)
Integrate a pixel table / pixel grid along the wavelength direction.
void muse_pixgrid_delete(muse_pixgrid *aPixels)
Delete a pixgrid and remove its memory.
cpl_table * gtable
the table containing the Euro3D groups
cpl_propertylist * header
the FITS header
double muse_astro_posangle(const cpl_propertylist *aHeader)
Derive the position angle of an observation from information in a FITS header.
static void muse_wcs_projplane_from_pixel_fast(muse_wcs *aWCS, double aX, double aY, double *aXOut, double *aYOut)
Convert from pixel coordinates to projection plane coordinates.
#define MUSE_HDR_PT_DAR_NAME
muse_resampling_type
Resampling types.
double muse_pfits_get_temp(const cpl_propertylist *aHeaders)
find out the ambient temperature (in degrees Celsius)
muse_euro3dcube * muse_resampling_euro3d(muse_pixtable *aPixtable, muse_resampling_params *aParams)
Resample a pixel table onto a regular grid structure representing a Euro3D format file...
void muse_resampling_params_delete(muse_resampling_params *aParams)
Delete a resampling parameters structure.
muse_resampling_type method
muse_image * muse_image_new(void)
Allocate memory for a new muse_image object.
cpl_table * muse_resampling_spectrum(muse_pixtable *aPixtable, double aBinwidth)
Resample the selected pixels of a pixel table into a spectrum.
static cpl_size muse_pixgrid_get_index(muse_pixgrid *aPixels, cpl_size aX, cpl_size aY, cpl_size aZ, cpl_boolean aAllowOutside)
Get the grid index determined from all three coordinates.
#define MUSE_HDR_PT_YHI
FITS header keyword contains the upper limit of the data in y-direction.
static cpl_size muse_pixgrid_get_count(muse_pixgrid *aPixels, cpl_size aIndex)
Return the number of rows stored in one pixel.
muse_ins_mode muse_pfits_get_mode(const cpl_propertylist *aHeaders)
find out the observation mode
double muse_astro_airmass(cpl_propertylist *aHeader)
Derive the effective airmass of an observation from information in a FITS header. ...
cpl_imagelist * stat
the cube containing the data variance
cpl_propertylist * header
The FITS header.
#define MUSE_HDR_PT_XHI
FITS header keyword contains the upper limit of the data in x-ion.