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 #include <cpl.h>
00030 #include <math.h>
00031 #include <string.h>
00032
00033 #include "muse_datacube.h"
00034
00035 #include "muse_flux.h"
00036 #include "muse_pfits.h"
00037 #include "muse_quality.h"
00038 #include "muse_utils.h"
00039 #include "muse_wcs.h"
00040
00041
00048
00049
00052
00069
00070 static double *
00071 muse_datacube_collapse_filter_buffer(cpl_table *aFilter,
00072 double aCRVAL, double aCRPIX, double aCDELT,
00073 cpl_boolean aIsLog, int *aL1, int *aL2)
00074 {
00075 if (!aFilter || !aL1 || !aL2) {
00076 return NULL;
00077 }
00078 double *fdata = (double *)cpl_calloc(*aL2, sizeof(double));
00079
00080 int l;
00081 for (l = 0; l < *aL2; l++) {
00082 double lambda = (l + 1. - aCRPIX) * aCDELT + aCRVAL;
00083 if (aIsLog) {
00084 lambda = aCRVAL * exp((l + 1. - aCRPIX) * aCDELT / aCRVAL);
00085 }
00086 fdata[l] = muse_flux_response_interpolate(aFilter, lambda, NULL,
00087 MUSE_FLUX_RESP_FILTER);
00088 }
00089
00090
00091 l = 0;
00092 while (l < *aL2 && fabs(fdata[l]) < DBL_EPSILON) {
00093 *aL1 = l++;
00094 }
00095 l = *aL2 - 1;
00096 while (l > *aL1 && fabs(fdata[l]) < DBL_EPSILON) {
00097 *aL2 = l--;
00098 }
00099 cpl_msg_debug(__func__, "filter wavelength range %.1f..%.1fA (planes %d..%d)",
00100 (*aL1 + 1. - aCRPIX) * aCDELT + aCRVAL,
00101 (*aL2 + 1. - aCRPIX) * aCDELT + aCRVAL,
00102 *aL1, *aL2);
00103
00104 return fdata;
00105 }
00106
00107
00128
00129 muse_image *
00130 muse_euro3dcube_collapse(muse_euro3dcube *aEuro3D, cpl_table *aFilter)
00131 {
00132 cpl_ensure(aEuro3D && aEuro3D->dtable && aEuro3D->hdata, CPL_ERROR_NULL_INPUT,
00133 NULL);
00134
00135
00136 muse_wcs *wcs = muse_wcs_new(aEuro3D->header);
00137
00138 wcs->iscelsph = CPL_FALSE;
00139 const char *unitx = cpl_table_get_column_unit(aEuro3D->dtable, "XPOS"),
00140 *unity = cpl_table_get_column_unit(aEuro3D->dtable, "YPOS");
00141 cpl_ensure(unitx && unity, CPL_ERROR_DATA_NOT_FOUND, NULL);
00142
00143 if (!strncmp(unitx, unity, 4) && !strncmp(unitx, "deg", 4)) {
00144 wcs->iscelsph = CPL_TRUE;
00145 }
00146
00147 double xmin = cpl_table_get_column_min(aEuro3D->dtable, "XPOS"),
00148 xmax = cpl_table_get_column_max(aEuro3D->dtable, "XPOS"),
00149 ymin = cpl_table_get_column_min(aEuro3D->dtable, "YPOS"),
00150 ymax = cpl_table_get_column_max(aEuro3D->dtable, "YPOS");
00151 double x1, x2, y1, y2;
00152 if (wcs->iscelsph) {
00153 wcs->crval1 /= CPL_MATH_DEG_RAD;
00154 wcs->crval2 /= CPL_MATH_DEG_RAD;
00155 muse_wcs_pixel_from_celestial_fast(wcs, xmin / CPL_MATH_DEG_RAD,
00156 ymin / CPL_MATH_DEG_RAD, &x1, &y1);
00157 muse_wcs_pixel_from_celestial_fast(wcs, xmax / CPL_MATH_DEG_RAD,
00158 ymax / CPL_MATH_DEG_RAD, &x2, &y2);
00159 } else {
00160 x1 = xmin;
00161 x2 = xmax;
00162 y1 = ymin;
00163 y2 = ymax;
00164 }
00165 int zmin = cpl_table_get_column_min(aEuro3D->dtable, "SPEC_STA"),
00166 zmax = cpl_table_get_column_max(aEuro3D->dtable, "SPEC_STA"),
00167 nx = lround(fabs(x2 - x1)) + 1,
00168 ny = lround(fabs(y2 - y1)) + 1,
00169 nz = zmax - zmin + 1;
00170
00171
00172 cpl_size zmaxpos = -1;
00173 cpl_table_get_column_maxpos(aEuro3D->dtable, "SPEC_STA", &zmaxpos);
00174 const cpl_array *amax = cpl_table_get_array(aEuro3D->dtable, "DATA_SPE",
00175 zmaxpos);
00176 int l, nsize = cpl_array_get_size(amax);
00177 for (l = nsize - 1; l > 0; l--) {
00178
00179 if (cpl_array_is_valid(amax, l) == 1) {
00180 break;
00181 }
00182 }
00183 nz += l + 1;
00184 int nspec = cpl_table_get_nrow(aEuro3D->dtable);
00185 cpl_msg_debug(__func__, "Euro3D dimensions: %dx%dx%d (z = %d - %d, valid %d),"
00186 " %d spectra", nx, ny, nz, zmax, zmin, l + 1, nspec);
00187
00188
00189 double crvals = cpl_propertylist_get_double(aEuro3D->hdata, "CRVALS"),
00190 cdelts = cpl_propertylist_get_double(aEuro3D->hdata, "CDELTS");
00191 const char *ctypes = cpl_propertylist_get_string(aEuro3D->hdata, "CTYPES");
00192 cpl_boolean loglambda = ctypes && (!strncmp(ctypes, "AWAV-LOG", 9) ||
00193 !strncmp(ctypes, "WAVE-LOG", 9));
00194 cpl_msg_debug(__func__, "spectral WCS: %f / %f %s", crvals, cdelts,
00195 loglambda ? "log" : "linear");
00196 int l1 = 0, l2 = nz;
00197 double *fdata = muse_datacube_collapse_filter_buffer(aFilter, crvals, zmin,
00198 cdelts, loglambda, &l1, &l2);
00199
00200
00201 muse_image *image = muse_image_new();
00202 image->header = cpl_propertylist_duplicate(aEuro3D->header);
00203
00204 image->data = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00205 float *outdata = cpl_image_get_data_float(image->data);
00206 image->dq = cpl_image_new(nx, ny, CPL_TYPE_INT);
00207
00208 cpl_image_add_scalar(image->dq, EURO3D_MISSDATA);
00209 int *outdq = cpl_image_get_data_int(image->dq);
00210
00211
00212
00213 cpl_boolean usevariance = CPL_FALSE;
00214 if (getenv("MUSE_COLLAPSE_USE_VARIANCE") &&
00215 atoi(getenv("MUSE_COLLAPSE_USE_VARIANCE")) > 0) {
00216 usevariance = CPL_TRUE;
00217 }
00218
00219
00220 int k, noutside = 0;
00221 #pragma omp parallel for default(none) private(l) \
00222 shared(aEuro3D, fdata, l1, l2, noutside, nspec, nx, ny, outdata, \
00223 outdq, usevariance, wcs)
00224 for (k = 0; k < nspec; k++) {
00225 int err;
00226 double xpos = cpl_table_get(aEuro3D->dtable, "XPOS", k, &err),
00227 ypos = cpl_table_get(aEuro3D->dtable, "YPOS", k, &err);
00228 if (err) {
00229 cpl_msg_warning(__func__, "spectrum %d in Euro3D table does not have "
00230 "position information!", k + 1);
00231 continue;
00232 }
00233
00234 double xpx, ypx;
00235 if (wcs->iscelsph) {
00236 muse_wcs_pixel_from_celestial_fast(wcs, xpos * CPL_MATH_RAD_DEG,
00237 ypos * CPL_MATH_RAD_DEG, &xpx, &ypx);
00238 } else {
00239 muse_wcs_pixel_from_projplane_fast(wcs, xpos, ypos, &xpx, &ypx);
00240 }
00241 int i = lround(xpx) - 1,
00242 j = lround(ypx) - 1;
00243 if (i >= nx || j >= ny) {
00244
00245 noutside++;
00246 continue;
00247 }
00248
00249 int nstart = cpl_table_get_int(aEuro3D->dtable, "SPEC_STA", k, &err);
00250 const cpl_array *adata = cpl_table_get_array(aEuro3D->dtable, "DATA_SPE", k),
00251 *adq = cpl_table_get_array(aEuro3D->dtable, "QUAL_SPE", k),
00252 *astat = NULL;
00253 if (usevariance) {
00254 astat = cpl_table_get_array(aEuro3D->dtable, "STAT_SPE", k);
00255 }
00256
00257 double sumdata = 0., sumweight = 0.;
00258 for (l = l1; l < l2; l++) {
00259
00260 int idx = l - nstart + 1;
00261
00262
00263 double fweight = fdata ? fdata[l] : 1.;
00264 cpl_errorstate prestate = cpl_errorstate_get();
00265 int dq = cpl_array_get_int(adq, idx, &err);
00266 if (dq || err) {
00267 cpl_errorstate_set(prestate);
00268 continue;
00269 }
00270
00271 double variance = 1.;
00272 if (usevariance) {
00273 variance = astat ? cpl_array_get(astat, idx, &err) : 1.;
00274
00275 variance *= variance;
00276 if (err > 0) {
00277 variance = DBL_MAX;
00278 }
00279 if (err || !isnormal(variance)) {
00280 continue;
00281 }
00282 }
00283 double data = cpl_array_get(adata, idx, &err);
00284
00285 sumdata += data * fweight / variance;
00286 sumweight += fweight / variance;
00287 }
00288 if (isnormal(sumweight)) {
00289 outdata[i + j*nx] = sumdata / sumweight;
00290 outdq[i + j*nx] = EURO3D_GOODPIXEL;
00291 } else {
00292 outdq[i + j*nx] = EURO3D_MISSDATA;
00293 }
00294 }
00295 cpl_free(wcs);
00296 cpl_free(fdata);
00297 if (noutside > 0) {
00298 cpl_msg_warning(__func__, "Skipped %d spaxels, due to their location "
00299 "outside the recostructed image!", noutside);
00300 }
00301
00302 return image;
00303 }
00304
00305
00326
00327 muse_image *
00328 muse_datacube_collapse(muse_datacube *aCube, cpl_table *aFilter)
00329 {
00330 cpl_ensure(aCube && aCube->data && aCube->header, CPL_ERROR_NULL_INPUT, NULL);
00331 cpl_ensure(cpl_image_get_type(cpl_imagelist_get(aCube->data, 0)) == CPL_TYPE_FLOAT,
00332 CPL_ERROR_INCOMPATIBLE_INPUT, NULL);
00333 if (aCube->dq) {
00334 cpl_ensure(cpl_image_get_type(cpl_imagelist_get(aCube->dq, 0)) == CPL_TYPE_INT,
00335 CPL_ERROR_INCOMPATIBLE_INPUT, NULL);
00336 }
00337 if (aCube->stat) {
00338 cpl_ensure(cpl_image_get_type(cpl_imagelist_get(aCube->stat, 0)) == CPL_TYPE_FLOAT,
00339 CPL_ERROR_INCOMPATIBLE_INPUT, NULL);
00340 }
00341
00342
00343 int nx = cpl_image_get_size_x(cpl_imagelist_get(aCube->data, 0)),
00344 ny = cpl_image_get_size_y(cpl_imagelist_get(aCube->data, 0)),
00345 nz = cpl_imagelist_get_size(aCube->data);
00346
00347 double crpix3 = muse_pfits_get_crpix(aCube->header, 3),
00348 crval3 = muse_pfits_get_crval(aCube->header, 3),
00349 cd33 = muse_pfits_get_cd(aCube->header, 3, 3);
00350 const char *ctype3 = muse_pfits_get_ctype(aCube->header, 3);
00351 cpl_boolean loglambda = ctype3 && (!strncmp(ctype3, "AWAV-LOG", 9) ||
00352 !strncmp(ctype3, "WAVE-LOG", 9));
00353 int l1 = 0, l2 = nz;
00354 double *fdata = muse_datacube_collapse_filter_buffer(aFilter, crval3, crpix3,
00355 cd33, loglambda, &l1, &l2);
00356
00357
00358 muse_image *image = muse_image_new();
00359 image->header = cpl_propertylist_duplicate(aCube->header);
00360 cpl_propertylist_erase_regexp(image->header, "^C...*3$|^CD3_.$", 0);
00361 image->data = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00362 float *outdata = cpl_image_get_data_float(image->data);
00363 image->dq = cpl_image_new(nx, ny, CPL_TYPE_INT);
00364 int *outdq = cpl_image_get_data_int(image->dq);
00365
00366
00367
00368 cpl_boolean usevariance = CPL_FALSE;
00369 if (getenv("MUSE_COLLAPSE_USE_VARIANCE") &&
00370 atoi(getenv("MUSE_COLLAPSE_USE_VARIANCE")) > 0) {
00371 usevariance = CPL_TRUE;
00372 }
00373
00374
00375 int i;
00376 #pragma omp parallel for default(none) \
00377 shared(aCube, nx, ny, l1, l2, fdata, outdata, outdq, usevariance)
00378 for (i = 0; i < nx; i++) {
00379 int j;
00380 for (j = 0; j < ny; j++) {
00381 double sumdata = 0., sumweight = 0.;
00382 int l;
00383 for (l = l1; l < l2; l++) {
00384
00385 double fweight = fdata ? fdata[l] : 1.;
00386 float *pdata = cpl_image_get_data_float(cpl_imagelist_get(aCube->data, l)),
00387 *pstat = NULL;
00388 if (!isfinite(pdata[i + j*nx])) {
00389 continue;
00390 }
00391 if (aCube->dq) {
00392 int *pdq = cpl_image_get_data_int(cpl_imagelist_get(aCube->dq, l));
00393 if (pdq && pdq[i + j*nx]) {
00394 continue;
00395 }
00396 }
00397
00398 double variance = 1.;
00399 if (usevariance) {
00400 pstat = cpl_image_get_data_float(cpl_imagelist_get(aCube->stat, l));
00401 variance = pstat ? pstat[i + j*nx] : 1.;
00402 if (!isnormal(variance)) {
00403 continue;
00404 }
00405 }
00406
00407 sumdata += pdata[i + j*nx] * fweight / variance;
00408 sumweight += fweight / variance;
00409 }
00410 if (isnormal(sumweight)) {
00411 outdata[i + j*nx] = sumdata / sumweight;
00412 outdq[i + j*nx] = EURO3D_GOODPIXEL;
00413 } else {
00414 outdq[i + j*nx] = EURO3D_MISSDATA;
00415 }
00416 }
00417 }
00418
00419 cpl_free(fdata);
00420
00421 return image;
00422 }
00423
00424
00439
00440 cpl_error_code
00441 muse_datacube_save_recimages(const char *aFilename, muse_imagelist *aImages,
00442 cpl_array *aNames)
00443 {
00444 cpl_ensure_code(aFilename, CPL_ERROR_NULL_INPUT);
00445 cpl_error_code rc = CPL_ERROR_NONE;
00446 if (!aImages || !aNames) {
00447 return rc;
00448 }
00449 unsigned int i, nimages = muse_imagelist_get_size(aImages);
00450 for (i = 0; i < nimages; i++) {
00451 muse_image *image = muse_imagelist_get(aImages, i);
00452
00453
00454 cpl_propertylist *header = cpl_propertylist_new();
00455 cpl_errorstate es = cpl_errorstate_get();
00456 const char *unit = muse_pfits_get_bunit(image->header),
00457 *ucomment = cpl_propertylist_get_comment(image->header, "BUNIT");
00458 if (!cpl_errorstate_is_equal(es) && !unit) {
00459 cpl_errorstate_set(es);
00460 }
00461 char dataext[KEYWORD_LENGTH], obj[KEYWORD_LENGTH],
00462 *dqext = NULL, *statext = NULL;
00463 snprintf(dataext, KEYWORD_LENGTH, "%s", cpl_array_get_string(aNames, i));
00464 if (image->dq) {
00465 dqext = cpl_sprintf("%s_%s", cpl_array_get_string(aNames, i), EXTNAME_DQ);
00466 }
00467 if (image->stat) {
00468 statext = cpl_sprintf("%s_%s", cpl_array_get_string(aNames, i), EXTNAME_STAT);
00469 }
00470 snprintf(obj, KEYWORD_LENGTH, "%s", cpl_array_get_string(aNames, i));
00471 cpl_propertylist_append_string(header, "EXTNAME", dataext);
00472 cpl_propertylist_set_comment(header, "EXTNAME", "reconstructed image (data values)");
00473
00474 if (unit) {
00475 cpl_propertylist_append_string(header, "BUNIT", unit);
00476 cpl_propertylist_set_comment(header, "BUNIT", ucomment);
00477 }
00478
00479 muse_utils_copy_modified_header(image->header, header, "OBJECT", obj);
00480 cpl_propertylist_update_string(header, MUSE_HDR_FILTER,
00481 cpl_array_get_string(aNames, i));
00482 cpl_propertylist_copy_property_regexp(header, image->header,
00483 MUSE_WCS_KEYS, 0);
00484 muse_utils_set_hduclass(header, "DATA", dataext, dqext, statext);
00485 rc = cpl_image_save(image->data, aFilename, CPL_TYPE_UNSPECIFIED, header,
00486 CPL_IO_EXTEND);
00487
00488 if (image->dq) {
00489 cpl_propertylist_update_string(header, "EXTNAME", dqext);
00490 cpl_propertylist_set_comment(header, "EXTNAME", "reconstructed image (bad pixel status values)");
00491 cpl_propertylist_erase(header, "BUNIT");
00492 snprintf(obj, KEYWORD_LENGTH, "%s, %s", cpl_array_get_string(aNames, i),
00493 EXTNAME_DQ);
00494 muse_utils_copy_modified_header(image->header, header, "OBJECT", obj);
00495 muse_utils_set_hduclass(header, "QUALITY", dataext, dqext, statext);
00496 rc = cpl_image_save(image->dq, aFilename, CPL_TYPE_INT, header,
00497 CPL_IO_EXTEND);
00498 }
00499 if (image->stat) {
00500 cpl_propertylist_update_string(header, "EXTNAME", statext);
00501 cpl_propertylist_set_comment(header, "EXTNAME", "reconstructed image (variance)");
00502 if (unit) {
00503 char *ustat = cpl_sprintf("(%s)**2", unit);
00504 cpl_propertylist_append_string(header, "BUNIT", ustat);
00505 cpl_free(ustat);
00506 }
00507 snprintf(obj, KEYWORD_LENGTH, "%s, %s", cpl_array_get_string(aNames, i),
00508 EXTNAME_STAT);
00509 muse_utils_copy_modified_header(image->header, header, "OBJECT", obj);
00510 muse_utils_set_hduclass(header, "ERROR", dataext, dqext, statext);
00511 rc = cpl_image_save(image->stat, aFilename, CPL_TYPE_UNSPECIFIED, header,
00512 CPL_IO_EXTEND);
00513 }
00514
00515 cpl_propertylist_delete(header);
00516 cpl_free(dqext);
00517 cpl_free(statext);
00518 }
00519
00520 return rc;
00521 }
00522
00523
00538
00539 cpl_error_code
00540 muse_euro3dcube_save(muse_euro3dcube *aEuro3D, const char *aFilename)
00541 {
00542 cpl_ensure_code(aEuro3D && aFilename, CPL_ERROR_NULL_INPUT);
00543
00544
00545 cpl_error_code rc = cpl_table_save(aEuro3D->dtable, aEuro3D->header,
00546 aEuro3D->hdata, aFilename, CPL_IO_CREATE);
00547 if (rc != CPL_ERROR_NONE) {
00548 cpl_msg_warning(__func__, "failed to save data part of the Euro3D table: "
00549 "%s", cpl_error_get_message());
00550 }
00551
00552 rc = cpl_table_save(aEuro3D->gtable, NULL, aEuro3D->hgroup, aFilename,
00553 CPL_IO_EXTEND);
00554 if (rc != CPL_ERROR_NONE) {
00555 cpl_msg_warning(__func__, "failed to save group part of the Euro3D table: "
00556 "%s", cpl_error_get_message());
00557 }
00558
00559 rc = muse_datacube_save_recimages(aFilename, aEuro3D->recimages,
00560 aEuro3D->recnames);
00561 return rc;
00562 }
00563
00564
00574
00575 void
00576 muse_euro3dcube_delete(muse_euro3dcube *aEuro3D)
00577 {
00578
00579 if (!aEuro3D) {
00580 return;
00581 }
00582
00583
00584
00585 cpl_table_delete(aEuro3D->dtable);
00586 cpl_table_delete(aEuro3D->gtable);
00587 cpl_propertylist_delete(aEuro3D->header);
00588 cpl_propertylist_delete(aEuro3D->hdata);
00589 cpl_propertylist_delete(aEuro3D->hgroup);
00590 muse_imagelist_delete(aEuro3D->recimages);
00591 cpl_array_delete(aEuro3D->recnames);
00592 cpl_free(aEuro3D);
00593 }
00594
00595
00605
00606 static cpl_error_code
00607 muse_datacube_convert_dq_recimages(muse_datacube *aCube)
00608 {
00609 cpl_ensure_code(aCube, CPL_ERROR_NULL_INPUT);
00610 if (!aCube->recimages) {
00611 return CPL_ERROR_NONE;
00612 }
00613 unsigned int k, nimages = muse_imagelist_get_size(aCube->recimages);
00614 for (k = 0; k < nimages; k++) {
00615 muse_image *image = muse_imagelist_get(aCube->recimages, k);
00616 if (!image->dq) {
00617 continue;
00618 }
00619 muse_image_dq_to_nan(image);
00620 }
00621
00622 return CPL_ERROR_NONE;
00623 }
00624
00625
00638
00639 cpl_error_code
00640 muse_datacube_convert_dq(muse_datacube *aCube)
00641 {
00642 cpl_ensure_code(aCube && aCube->data && aCube->stat && aCube->dq,
00643 CPL_ERROR_NULL_INPUT);
00644
00645
00646 int l, nx = cpl_image_get_size_x(cpl_imagelist_get(aCube->data, 0)),
00647 ny = cpl_image_get_size_y(cpl_imagelist_get(aCube->data, 0)),
00648 nz = cpl_imagelist_get_size(aCube->data);
00649 #pragma omp parallel for default(none) \
00650 shared(aCube, nx, ny, nz)
00651 for (l = 0; l < nz; l++) {
00652 int i;
00653 for (i = 0; i < nx; i++) {
00654 int j;
00655 for (j = 0; j < ny; j++) {
00656 float *pdata = cpl_image_get_data_float(cpl_imagelist_get(aCube->data, l)),
00657 *pstat = cpl_image_get_data_float(cpl_imagelist_get(aCube->stat, l));
00658 int *pdq = cpl_image_get_data_int(cpl_imagelist_get(aCube->dq, l));
00659 if (pdq[i + j*nx] == EURO3D_GOODPIXEL) {
00660 continue;
00661 }
00662
00663 pdata[i + j*nx] = NAN;
00664 pstat[i + j*nx] = NAN;
00665 }
00666 }
00667 }
00668
00669
00670 cpl_imagelist_delete(aCube->dq);
00671 aCube->dq = NULL;
00672
00673
00674 muse_datacube_convert_dq_recimages(aCube);
00675
00676 return CPL_ERROR_NONE;
00677 }
00678
00679
00708
00709 cpl_error_code
00710 muse_datacube_save(muse_datacube *aCube, const char *aFilename)
00711 {
00712 cpl_ensure_code(aCube && aCube->header && aFilename, CPL_ERROR_NULL_INPUT);
00713
00714
00715 cpl_propertylist *header = cpl_propertylist_new();
00716
00717 cpl_propertylist_copy_property_regexp(header, aCube->header,
00718 MUSE_WCS_KEYS, 1);
00719 cpl_error_code rc = cpl_propertylist_save(header, aFilename, CPL_IO_CREATE);
00720 cpl_propertylist_delete(header);
00721
00722
00723 header = cpl_propertylist_new();
00724 cpl_propertylist_append_string(header, "EXTNAME", EXTNAME_DATA);
00725 cpl_propertylist_set_comment(header, "EXTNAME", EXTNAME_DATA_COMMENT);
00726 muse_utils_copy_modified_header(aCube->header, header, "OBJECT",
00727 EXTNAME_DATA);
00728 cpl_propertylist_copy_property_regexp(header, aCube->header,
00729 MUSE_WCS_KEYS"|^BUNIT", 0);
00730 muse_utils_set_hduclass(header, "DATA", "DATA",
00731 aCube->dq ? "DQ" : NULL, aCube->stat ? "STAT" : NULL);
00732 rc = cpl_imagelist_save(aCube->data, aFilename, CPL_TYPE_FLOAT, header,
00733 CPL_IO_EXTEND);
00734 cpl_propertylist_delete(header);
00735
00736 if (rc == CPL_ERROR_NONE && aCube->dq) {
00737 header = cpl_propertylist_new();
00738 cpl_propertylist_append_string(header, "EXTNAME", EXTNAME_DQ);
00739 cpl_propertylist_set_comment(header, "EXTNAME", EXTNAME_DQ_COMMENT);
00740 muse_utils_copy_modified_header(aCube->header, header, "OBJECT",
00741 EXTNAME_DQ);
00742 cpl_propertylist_copy_property_regexp(header, aCube->header,
00743 MUSE_WCS_KEYS, 0);
00744 muse_utils_set_hduclass(header, "QUALITY", "DATA", "DQ",
00745 aCube->stat ? "STAT" : NULL);
00746 rc = cpl_imagelist_save(aCube->dq, aFilename, CPL_TYPE_INT, header,
00747 CPL_IO_EXTEND);
00748 cpl_propertylist_delete(header);
00749 }
00750
00751 if (rc == CPL_ERROR_NONE && aCube->stat) {
00752 header = cpl_propertylist_new();
00753 cpl_propertylist_append_string(header, "EXTNAME", EXTNAME_STAT);
00754 cpl_propertylist_set_comment(header, "EXTNAME", EXTNAME_STAT_COMMENT);
00755
00756 if (!strncmp(muse_pfits_get_bunit(aCube->header),
00757 kMuseFluxUnitString, strlen(kMuseFluxUnitString) + 1)) {
00758
00759 cpl_propertylist_append_string(header, "BUNIT", kMuseFluxStatString);
00760 }
00761 muse_utils_copy_modified_header(aCube->header, header, "OBJECT",
00762 EXTNAME_STAT);
00763 cpl_propertylist_copy_property_regexp(header, aCube->header,
00764 MUSE_WCS_KEYS, 0);
00765 muse_utils_set_hduclass(header, "ERROR", "DATA", aCube->dq ? "DQ" : NULL,
00766 "STAT");
00767 rc = cpl_imagelist_save(aCube->stat, aFilename, CPL_TYPE_FLOAT, header,
00768 CPL_IO_EXTEND);
00769 cpl_propertylist_delete(header);
00770 }
00771
00772 rc = muse_datacube_save_recimages(aFilename, aCube->recimages, aCube->recnames);
00773 return rc;
00774 }
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785 static cpl_propertylist *
00786 muse_datacube_load_header(const char *aFilename)
00787 {
00788 cpl_ensure(aFilename, CPL_ERROR_NULL_INPUT, NULL);
00789 int extdata = cpl_fits_find_extension(aFilename, "DATA");
00790 cpl_ensure(extdata >= 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
00791 cpl_ensure(extdata > 0, CPL_ERROR_DATA_NOT_FOUND, NULL);
00792
00793 cpl_propertylist *header = cpl_propertylist_load(aFilename, 0);
00794 cpl_propertylist *hdata = cpl_propertylist_load(aFilename, extdata);
00795 cpl_propertylist_copy_property_regexp(header, hdata,
00796 MUSE_WCS_KEYS"|BUNIT", 0);
00797 cpl_propertylist_delete(hdata);
00798 return header;
00799 }
00800
00801
00831
00832 muse_datacube *
00833 muse_datacube_load(const char *aFilename)
00834 {
00835 cpl_ensure(aFilename, CPL_ERROR_NULL_INPUT, NULL);
00836 muse_datacube *cube = cpl_calloc(1, sizeof(muse_datacube));
00837
00838 cpl_errorstate state = cpl_errorstate_get();
00839 cube->header = muse_datacube_load_header(aFilename);
00840 if (!cpl_errorstate_is_equal(state) || !cube->header) {
00841 cpl_msg_error(__func__, "Loading cube-like headers from \"%s\" failed!",
00842 aFilename);
00843 cpl_free(cube);
00844 return NULL;
00845 }
00846 int ext = cpl_fits_find_extension(aFilename, "DATA");
00847 cube->data = cpl_imagelist_load(aFilename, CPL_TYPE_FLOAT, ext);
00848
00849 ext = cpl_fits_find_extension(aFilename, "DQ");
00850 if (ext > 0) {
00851 cube->stat = cpl_imagelist_load(aFilename, CPL_TYPE_INT, ext);
00852 }
00853 ext = cpl_fits_find_extension(aFilename, "STAT");
00854 if (ext > 0) {
00855 cube->stat = cpl_imagelist_load(aFilename, CPL_TYPE_FLOAT, ext);
00856 }
00857 int next = cpl_fits_count_extensions(aFilename);
00858 while (++ext <= next) {
00859
00860 muse_image *image = muse_image_new();
00861 image->header = cpl_propertylist_load(aFilename, ext);
00862 image->data = cpl_image_load(aFilename, CPL_TYPE_UNSPECIFIED, 0, ext);
00863
00864 const char *extname = muse_pfits_get_extname(image->header);
00865 char *extname2 = cpl_sprintf("%s_DQ", extname);
00866 int ext2 = cpl_fits_find_extension(aFilename, extname2);
00867 cpl_free(extname2);
00868 if (ext2 > 0) {
00869 image->dq = cpl_image_load(aFilename, CPL_TYPE_INT, 0, ext2);
00870 ext = ext2;
00871 }
00872 extname2 = cpl_sprintf("%s_STAT", extname);
00873 ext2 = cpl_fits_find_extension(aFilename, extname2);
00874 cpl_free(extname2);
00875 if (ext2 > 0) {
00876 image->stat = cpl_image_load(aFilename, CPL_TYPE_UNSPECIFIED, 0, ext2);
00877 ext = ext2;
00878 }
00879
00880 if (!cube->recnames) {
00881 cube->recnames = cpl_array_new(1, CPL_TYPE_STRING);
00882 } else {
00883 cpl_array_set_size(cube->recnames, cpl_array_get_size(cube->recnames) + 1);
00884 }
00885
00886 cpl_array_set_string(cube->recnames, cpl_array_get_size(cube->recnames) - 1,
00887 extname);
00888 if (!cube->recimages) {
00889 cube->recimages = muse_imagelist_new();
00890 }
00891
00892 muse_imagelist_set(cube->recimages, image,
00893 muse_imagelist_get_size(cube->recimages));
00894 }
00895 return cube;
00896 }
00897
00898
00918
00919 cpl_error_code
00920 muse_datacube_concat(muse_datacube *aCube, const muse_datacube *aAppend)
00921 {
00922 cpl_ensure_code(aCube && aAppend, CPL_ERROR_NULL_INPUT);
00923
00924 cpl_size ndata = cpl_imagelist_get_size(aCube->data),
00925 nstat = cpl_imagelist_get_size(aCube->stat);
00926 cpl_ensure_code(ndata == nstat, CPL_ERROR_ILLEGAL_INPUT);
00927 cpl_size i, n = cpl_imagelist_get_size(aAppend->data);
00928 cpl_ensure_code(n == cpl_imagelist_get_size(aAppend->stat),
00929 CPL_ERROR_ILLEGAL_INPUT);
00930
00931
00932 cpl_size nx1 = cpl_image_get_size_x(cpl_imagelist_get(aCube->data, ndata - 1)),
00933 ny1 = cpl_image_get_size_y(cpl_imagelist_get(aCube->data, ndata - 1)),
00934 nx2 = cpl_image_get_size_x(cpl_imagelist_get(aAppend->data, 0)),
00935 ny2 = cpl_image_get_size_y(cpl_imagelist_get(aAppend->data, 0));
00936 cpl_ensure_code(nx1 == nx2 && ny1 == ny2, CPL_ERROR_ILLEGAL_INPUT);
00937 const char *ctype1 = muse_pfits_get_ctype(aCube->header, 3),
00938 *ctype2 = muse_pfits_get_ctype(aCube->header, 3);
00939 cpl_ensure_code(ctype1 && ctype2, CPL_ERROR_UNSUPPORTED_MODE);
00940 cpl_ensure_code((!strncmp(ctype1, "AWAV", 5) && !strncmp(ctype2, "AWAV", 5)) ||
00941 (!strncmp(ctype1, "WAVE", 5) && !strncmp(ctype2, "WAVE", 5)),
00942 CPL_ERROR_UNSUPPORTED_MODE);
00943
00944
00945 double pix1 = muse_pfits_get_crpix(aCube->header, 3),
00946 val1 = muse_pfits_get_crval(aCube->header, 3),
00947 cd1 = muse_pfits_get_cd(aCube->header, 3, 3),
00948 pix2 = muse_pfits_get_crpix(aAppend->header, 3),
00949 val2 = muse_pfits_get_crval(aAppend->header, 3),
00950 cd2 = muse_pfits_get_cd(aAppend->header, 3, 3),
00951 lbda1 = ((ndata - 1) + 1. - pix1) * cd1 + val1,
00952 lbda2 = (0 + 1. - pix2) * cd2 + val2;
00953
00954 cpl_msg_debug(__func__, "lambdas: %f %f (%f %f)", lbda1, lbda2, cd1, cd2);
00955 cpl_ensure_code(fabs(cd1 - cd2) < DBL_EPSILON &&
00956 fabs(lbda2 - cd2 - lbda1) < DBL_EPSILON,
00957 CPL_ERROR_ILLEGAL_INPUT);
00958
00959
00960 cpl_array_delete(aCube->recnames);
00961 aCube->recnames = NULL;
00962 muse_imagelist_delete(aCube->recimages);
00963 aCube->recimages = NULL;
00964
00965
00966
00967
00968 cpl_boolean usedq = CPL_FALSE;
00969 if (aCube->dq && cpl_imagelist_get_size(aCube->dq) == ndata &&
00970 aAppend->dq && cpl_imagelist_get_size(aAppend->dq) == n) {
00971 usedq = CPL_TRUE;
00972 } else {
00973 cpl_imagelist_delete(aCube->dq);
00974 aCube->dq = NULL;
00975 }
00976
00977
00978 for (i = 0; i < n; i++) {
00979 cpl_imagelist_set(aCube->data,
00980 cpl_image_duplicate(cpl_imagelist_get(aAppend->data, i)),
00981 cpl_imagelist_get_size(aCube->data));
00982 if (usedq) {
00983 cpl_imagelist_set(aCube->dq,
00984 cpl_image_duplicate(cpl_imagelist_get(aAppend->dq, i)),
00985 cpl_imagelist_get_size(aCube->dq));
00986 }
00987 cpl_imagelist_set(aCube->stat,
00988 cpl_image_duplicate(cpl_imagelist_get(aAppend->stat, i)),
00989 cpl_imagelist_get_size(aCube->stat));
00990 }
00991 return CPL_ERROR_NONE;
00992 }
00993
00994
01004
01005 void
01006 muse_datacube_delete(muse_datacube *aCube)
01007 {
01008
01009 if (!aCube) {
01010 return;
01011 }
01012
01013
01014
01015 cpl_imagelist_delete(aCube->data);
01016 aCube->data = NULL;
01017 cpl_imagelist_delete(aCube->dq);
01018 aCube->dq = NULL;
01019 cpl_imagelist_delete(aCube->stat);
01020 aCube->stat = NULL;
01021
01022
01023 cpl_propertylist_delete(aCube->header);
01024 aCube->header = NULL;
01025
01026
01027 muse_imagelist_delete(aCube->recimages);
01028 cpl_array_delete(aCube->recnames);
01029 cpl_free(aCube);
01030 }
01031