00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <muse.h>
00023 #include <string.h>
00024
00025
00056
00057
00060 #define PRINT_USAGE(rc) \
00061 fprintf(stderr, "Usage: %s CUBE_OUT CUBE_IN_1 CUBE_IN_2 [ CUBE_IN_3 ... ]\n",\
00062 argv[0]); \
00063 cpl_end(); return (rc);
00064
00065 int main(int argc, char **argv)
00066 {
00067 const char *idstring = "muse_cube_combine";
00068 cpl_init(CPL_INIT_DEFAULT);
00069 cpl_msg_set_time_on();
00070 muse_processing_recipeinfo(NULL);
00071 cpl_msg_set_level(CPL_MSG_DEBUG);
00072 cpl_msg_set_component_on();
00073 cpl_errorstate state = cpl_errorstate_get();
00074
00075 if (argc < 4) {
00076
00077 PRINT_USAGE(1);
00078 }
00079
00080 char *oname = NULL;
00081 int i, noverlap = 1;
00082
00083
00084 for (i = 1; i < argc; i++) {
00085 if (strncmp(argv[i], "-xxx", 5) == 0) {
00086
00087 i++;
00088
00089
00090
00091
00092
00093 } else if (strncmp(argv[i], "-", 1) == 0) {
00094 PRINT_USAGE(9);
00095 } else {
00096 if (oname) {
00097 break;
00098 }
00099 oname = argv[i];
00100 }
00101 }
00102 if (!oname) {
00103 PRINT_USAGE(10);
00104 }
00105 FILE *fp = fopen(oname, "r");
00106 if (fp) {
00107 cpl_msg_error(idstring, "Output cube \"%s\" is already present!", oname);
00108 cpl_msg_error(idstring, "Please specify another output name or rename the "
00109 "existing file with this name.");
00110 fclose(fp);
00111 PRINT_USAGE(11);
00112 }
00113
00114 int ncubes = argc - i;
00115 cpl_msg_info(idstring, "Will write combination of %d cubes to \"%s\".",
00116 ncubes, oname);
00117
00118
00119 cpl_table *table = cpl_table_new(ncubes);
00120 cpl_table_new_column(table, "FILENAME", CPL_TYPE_STRING);
00121 cpl_table_new_column(table, "LMIN", CPL_TYPE_DOUBLE);
00122 cpl_table_new_column(table, "LMAX", CPL_TYPE_DOUBLE);
00123 cpl_table_new_column(table, "P1", CPL_TYPE_INT);
00124 cpl_table_new_column(table, "P2", CPL_TYPE_INT);
00125
00126
00127 int irecout = -1,
00128 iparout1 = -1,
00129 iparout2 = -1;
00130 double lminout = 99999.,
00131 lmaxout = -99999.;
00132 char *ctype1ref = NULL, *ctype2ref = NULL,
00133 *cunit1ref = NULL, *cunit2ref = NULL;
00134 double crpix1ref = NAN, crpix2ref = NAN, crval1ref = NAN, crval2ref = NAN,
00135 cd11ref = NAN, cd12ref = NAN, cd21ref = NAN, cd22ref = NAN;
00136 char *ctype3ref = NULL;
00137 cpl_boolean loglambda = CPL_FALSE;
00138 double crpix3ref = NAN,
00139 crval3ref = NAN,
00140 cd33ref = NAN;
00141 int ic;
00142 for (ic = 0; ic < ncubes; ic++) {
00143 int argidx = ic + 2;
00144 char *iname = argv[argidx];
00145
00146 int iext = cpl_fits_find_extension(iname, "DATA");
00147 if (iext < 0) {
00148 cpl_msg_warning(idstring, "Could not open cube \"%s\"", iname);
00149 continue;
00150 }
00151
00152
00153 cpl_propertylist *header = cpl_propertylist_load(iname, 0);
00154 double lmin = -FLT_MAX,
00155 lmax = FLT_MAX;
00156
00157 cpl_errorstate es = cpl_errorstate_get();
00158 int irec = 0;
00159 do {
00160 irec++;
00161 char *hname = cpl_sprintf("ESO PRO REC%d ID", irec);
00162
00163 const char *name = cpl_propertylist_get_string(header, hname);
00164 cpl_free(hname);
00165 if (!name) {
00166 break;
00167 }
00168 cpl_msg_debug(idstring, "REC = %d, ID = %s", irec, name);
00169 } while (cpl_errorstate_is_equal(es));
00170 cpl_errorstate_set(es);
00171 cpl_msg_info(idstring, "Using recipe parameters ESO PRO REC%d to determine "
00172 "wavelength ranges", --irec);
00173 if (irecout < 0) {
00174 irecout = irec;
00175 }
00176
00177
00178 int ipar = 0;
00179 do {
00180 ipar++;
00181 char *hname = cpl_sprintf("ESO PRO REC%d PARAM%d NAME", irec, ipar);
00182 const char *name = cpl_propertylist_get_string(header, hname);
00183 cpl_free(hname);
00184 cpl_boolean islmin = name && !strncmp(name, "lambdamin", 10),
00185 islmax = name && !strncmp(name, "lambdamax", 10);
00186 if (islmin || islmax) {
00187 char *hval = cpl_sprintf("ESO PRO REC%d PARAM%d VALUE", irec, ipar);
00188 if (islmin) {
00189 if (iparout1 < 0) {
00190 iparout1 = ipar;
00191 }
00192 lmin = atof(cpl_propertylist_get_string(header, hval));
00193 cpl_msg_debug(idstring, "lmin = %f", lmin);
00194 if (lmin < lminout) {
00195 lminout = lmin;
00196 }
00197 } else {
00198 if (iparout2 < 0) {
00199 iparout2 = ipar;
00200 }
00201 lmax = atof(cpl_propertylist_get_string(header, hval));
00202 cpl_msg_debug(idstring, "lmax = %f", lmax);
00203 if (lmax > lmaxout) {
00204 lmaxout = lmax;
00205 }
00206 }
00207 cpl_free(hval);
00208 }
00209 } while (cpl_errorstate_is_equal(es));
00210 cpl_errorstate_set(es);
00211 cpl_propertylist_delete(header);
00212
00213
00214 header = cpl_propertylist_load(iname, iext);
00215 double crpix3 = muse_pfits_get_crpix(header, 3),
00216 crval3 = muse_pfits_get_crval(header, 3),
00217 cd33 = muse_pfits_get_cd(header, 3, 3);
00218 int naxis3 = cpl_propertylist_get_int(header, "NAXIS3");
00219
00220 const char *cunit3 = muse_pfits_get_cunit(header, 3),
00221 *lunit = cpl_table_get_column_unit(table, "LMIN");
00222 if (!lunit) {
00223 cpl_table_set_column_unit(table, "LMIN", cunit3);
00224 cpl_table_set_column_unit(table, "LMAX", cunit3);
00225 } else if (strncmp(lunit, cunit3, strlen(lunit) + 1)) {
00226 cpl_msg_warning(idstring, "Cube %d does not contain wavelengths in "
00227 "%s (%s), skipping it", ic + 1, lunit, cunit3);
00228 cpl_propertylist_delete(header);
00229 continue;
00230 }
00231 const char *ctype3 = muse_pfits_get_ctype(header, 3);
00232 if (!ctype3ref) {
00233 ctype3ref = cpl_strdup(ctype3);
00234 crpix3ref = crpix3;
00235 crval3ref = crval3;
00236 cd33ref = cd33;
00237 loglambda = ctype3ref && (!strncmp(ctype3ref, "AWAV-LOG", 9) ||
00238 !strncmp(ctype3ref, "WAVE-LOG", 9));
00239 } else if (strncmp(ctype3ref, ctype3, strlen(ctype3ref)) ||
00240 fabs(crpix3 - crpix3ref) > DBL_EPSILON ||
00241 fabs(crval3 - crval3ref) > DBL_EPSILON ||
00242 fabs(cd33 - cd33ref) > DBL_EPSILON) {
00243 cpl_msg_warning(idstring, "Cube %d does not match in spectral WCS, "
00244 "skipping it", ic + 1);
00245 cpl_propertylist_delete(header);
00246 continue;
00247 }
00248 double lpx1 = (1. - crpix3) * cd33 + crval3,
00249 lpx2 = (naxis3 - crpix3) * cd33 + crval3;
00250 if (loglambda) {
00251 lpx1 = crval3 * exp((1 - crpix3) * cd33 / crval3);
00252 lpx2 = crval3 * exp((naxis3 - crpix3) * cd33 / crval3);
00253 }
00254 cpl_msg_debug(idstring, "Cube %d, axis 3 WCS: %f %f %f (%s, %d pixels, "
00255 "%f..%f %s)", ic + 1, crpix3, crval3, cd33, ctype3, naxis3,
00256 lpx1, lpx2, cunit3);
00257
00258 if (lmin < lpx1) {
00259 lmin = lpx1;
00260 }
00261 if (lmax > lpx2) {
00262 lmax = lpx2;
00263 }
00264
00265
00266 const char *ctype1 = muse_pfits_get_ctype(header, 1),
00267 *ctype2 = muse_pfits_get_ctype(header, 2),
00268 *cunit1 = muse_pfits_get_cunit(header, 1),
00269 *cunit2 = muse_pfits_get_cunit(header, 2);
00270 double crpix1 = muse_pfits_get_crpix(header, 1),
00271 crpix2 = muse_pfits_get_crval(header, 2),
00272 crval1 = muse_pfits_get_crval(header, 1),
00273 crval2 = muse_pfits_get_crval(header, 2),
00274 cd11 = muse_pfits_get_cd(header, 1, 1),
00275 cd12 = muse_pfits_get_cd(header, 1, 2),
00276 cd21 = muse_pfits_get_cd(header, 2, 1),
00277 cd22 = muse_pfits_get_cd(header, 2, 2);
00278 if (!ctype1ref) {
00279 ctype1ref = cpl_strdup(ctype1);
00280 ctype2ref = cpl_strdup(ctype2);
00281 cunit1ref = cpl_strdup(cunit1);
00282 cunit2ref = cpl_strdup(cunit2);
00283 crpix1ref = crpix1;
00284 crval1ref = crval1;
00285 crpix2ref = crpix2;
00286 crval2ref = crval2;
00287 cd11ref = cd11;
00288 cd12ref = cd12;
00289 cd21ref = cd21;
00290 cd22ref = cd22;
00291 } else if (strncmp(ctype1ref, ctype1, strlen(ctype1ref)) ||
00292 strncmp(ctype2ref, ctype2, strlen(ctype2ref)) ||
00293 strncmp(cunit1ref, cunit1, strlen(cunit1ref)) ||
00294 strncmp(cunit2ref, cunit2, strlen(cunit2ref)) ||
00295 fabs(crpix1 - crpix1ref) > DBL_EPSILON ||
00296 fabs(crval1 - crval1ref) > DBL_EPSILON ||
00297 fabs(crpix2 - crpix2ref) > DBL_EPSILON ||
00298 fabs(crval2 - crval2ref) > DBL_EPSILON ||
00299 fabs(cd11 - cd11ref) > DBL_EPSILON ||
00300 fabs(cd12 - cd12ref) > DBL_EPSILON ||
00301 fabs(cd21 - cd21ref) > DBL_EPSILON ||
00302 fabs(cd22 - cd22ref) > DBL_EPSILON) {
00303 cpl_msg_warning(idstring, "Cube %d does not match in spatial WCS, "
00304 "skipping it", ic + 1);
00305 cpl_propertylist_delete(header);
00306 continue;
00307 }
00308 cpl_propertylist_delete(header);
00309
00310
00311 int l1 = lround((lmin - crval3) / cd33 + crpix3),
00312 l2 = lround((lmax - crval3) / cd33 + crpix3);
00313 if (loglambda) {
00314 l1 = lround(crval3 / cd33 * log(lmin / crval3)) + crpix3;
00315 l2 = lround(crval3 / cd33 * log(lmax / crval3)) + crpix3;
00316 }
00317 cpl_msg_debug(idstring, "Cube %d: %d..%d (%f..%f Angstrom)", ic + 1,
00318 l1, l2, lmin, lmax);
00319 if (l1 <= 1) {
00320 l1 = 1;
00321 } else if (l1 >= naxis3) {
00322 cpl_msg_warning(idstring, "Something is wrong with cube %d: l1 = %d!",
00323 ic + 1, l1);
00324 continue;
00325 } else {
00326
00327 l1 += noverlap;
00328 }
00329 if (l2 >= naxis3) {
00330 l2 = naxis3;
00331 } else if (l2 <= 1) {
00332 cpl_msg_warning(idstring, "Something is wrong with cube %d: l2 = %d!",
00333 ic + 1, l2);
00334 continue;
00335 } else {
00336 l2 -= noverlap;
00337 }
00338 cpl_msg_debug(idstring, "Cube %d: ---> %d..%d", ic + 1, l1, l2);
00339
00340
00341 cpl_table_set_string(table, "FILENAME", ic, iname);
00342 cpl_table_set(table, "LMIN", ic, lmin);
00343 cpl_table_set(table, "LMAX", ic, lmax);
00344 cpl_table_set(table, "P1", ic, l1);
00345 cpl_table_set(table, "P2", ic, l2);
00346 }
00347 cpl_free(ctype1ref);
00348 cpl_free(ctype2ref);
00349 cpl_free(cunit1ref);
00350 cpl_free(cunit2ref);
00351 cpl_free(ctype3ref);
00352
00353
00354 cpl_table_select_all(table);
00355 cpl_table_and_selected_invalid(table, "FILENAME");
00356 cpl_table_erase_selected(table);
00357 ncubes = cpl_table_get_nrow(table);
00358 if (ncubes < 2) {
00359 cpl_msg_error(idstring, "Only %d cube%s with valid info %s found!", ncubes,
00360 ncubes ? "" : "s", ncubes ? "was" : "were");
00361 cpl_end();
00362 return 12;
00363 }
00364
00365
00366 cpl_propertylist *order = cpl_propertylist_new();
00367 cpl_propertylist_append_bool(order, "P1", CPL_FALSE);
00368 cpl_table_sort(table, order);
00369 cpl_propertylist_delete(order);
00370 #if 1
00371 printf("Stored and sorted %d cubes:\n", ncubes);
00372 cpl_table_dump(table, 0, ncubes, stdout);
00373 fflush(stdout);
00374 #endif
00375
00376
00377
00378
00379
00380
00381 int nover = 0, ngaps = 0;
00382 for (ic = 1; ic < cpl_table_get_nrow(table); ic++) {
00383 int p2a = cpl_table_get_int(table, "P2", ic - 1, NULL),
00384 p1b = cpl_table_get_int(table, "P1", ic, NULL);
00385 double lmaxa = cpl_table_get_double(table, "LMAX", ic - 1, NULL);
00386 int pdiff = p1b - p2a;
00387 if (pdiff == 1) {
00388 continue;
00389 }
00390 if (pdiff < 1) {
00391 p2a += pdiff - 1;
00392 lmaxa += cd33ref * (pdiff - 1);
00393 nover++;
00394 }
00395 if (pdiff > 1) {
00396 p2a += pdiff - 1;
00397 lmaxa += cd33ref * (pdiff - 1);
00398 ngaps++;
00399 }
00400 cpl_table_set_int(table, "P2", ic - 1, p2a);
00401 cpl_table_set_double(table, "LMAX", ic - 1, lmaxa);
00402 }
00403 #if 1
00404 printf("Cleaned up %d overlaps and %d gaps.\n", nover, ngaps);
00405 cpl_table_dump(table, 0, ncubes, stdout);
00406 fflush(stdout);
00407 #endif
00408
00409
00410 muse_datacube *cube = cpl_calloc(1, sizeof(muse_datacube));
00411 const char *fn = cpl_table_get_string(table, "FILENAME", 0);
00412 cpl_msg_info(idstring, "Loading cube from \"%s\"", fn);
00413 cube->header = cpl_propertylist_load(fn, 0);
00414
00415 int iext = cpl_fits_find_extension(fn, "DATA");
00416
00417
00418 cpl_propertylist *wcs = cpl_propertylist_load(fn, iext);
00419 cpl_propertylist_erase_regexp(wcs, MUSE_WCS_KEYS, 1);
00420 cpl_propertylist_append(cube->header, wcs);
00421 cpl_propertylist_delete(wcs);
00422
00423 cube->data = cpl_imagelist_load(fn, CPL_TYPE_FLOAT, iext);
00424 iext = cpl_fits_find_extension(fn, "STAT");
00425 cube->stat = cpl_imagelist_load(fn, CPL_TYPE_FLOAT, iext);
00426
00427
00428 int nplanes = cpl_imagelist_get_size(cube->data),
00429 l1 = cpl_table_get_int(table, "P1", 0, NULL),
00430 l2 = cpl_table_get_int(table, "P2", 0, NULL);
00431 cpl_array *aflags = cpl_array_new(nplanes, CPL_TYPE_DOUBLE);
00432 cpl_array_fill_window_double(aflags, 0, nplanes, -1.);
00433 cpl_array_fill_window_double(aflags, l1 - 1, l2 - l1 + 1, 1.);
00434 #if 0
00435 cpl_array_dump(aflags, 0, 5, stdout);
00436 cpl_array_dump(aflags, l1 - 4, 10, stdout);
00437 cpl_array_dump(aflags, l2 - 4, 10, stdout);
00438 cpl_array_dump(aflags, nplanes - 5, 6, stdout);
00439 fflush(stdout);
00440 #endif
00441 cpl_vector *vflags = cpl_vector_wrap(nplanes, cpl_array_unwrap(aflags));
00442 cpl_imagelist_erase(cube->data, vflags);
00443 cpl_imagelist_erase(cube->stat, vflags);
00444 cpl_vector_delete(vflags);
00445 cpl_msg_debug(idstring, "%d of %d planes left in first cube",
00446 (int)cpl_imagelist_get_size(cube->data), nplanes);
00447 nplanes = cpl_imagelist_get_size(cube->data);
00448
00449
00450 cpl_propertylist_update_double(cube->header, "CRPIX3", crpix3ref - (l1 - 1));
00451
00452
00453
00454 for (ic = 1; ic < cpl_table_get_nrow(table); ic++) {
00455 fn = cpl_table_get_string(table, "FILENAME", ic);
00456 cpl_msg_info(idstring, "Loading cube from \"%s\"", fn);
00457 iext = cpl_fits_find_extension(fn, "DATA");
00458 cpl_imagelist *cubedata = cpl_imagelist_load(fn, CPL_TYPE_FLOAT, iext);
00459 iext = cpl_fits_find_extension(fn, "STAT");
00460 cpl_imagelist *cubestat = cpl_imagelist_load(fn, CPL_TYPE_FLOAT, iext);
00461
00462
00463 l1 = cpl_table_get_int(table, "P1", ic, NULL);
00464 l2 = cpl_table_get_int(table, "P2", ic, NULL);
00465 int l;
00466 for (l = l1 - 1; l < l2; l++, nplanes = cpl_imagelist_get_size(cube->data)) {
00467 cpl_error_code rc1, rc2;
00468 rc1 = cpl_imagelist_set(cube->data,
00469 cpl_image_duplicate(cpl_imagelist_get(cubedata, l)),
00470 nplanes);
00471 rc2 = cpl_imagelist_set(cube->stat,
00472 cpl_image_duplicate(cpl_imagelist_get(cubestat, l)),
00473 nplanes);
00474 if (rc1 != rc2 || rc1 != CPL_ERROR_NONE || rc2 != CPL_ERROR_NONE) {
00475 cpl_msg_warning(idstring, "Could not append plane %d of cube %d to output cube",
00476 l, ic + 1);
00477 }
00478 }
00479 cpl_imagelist_delete(cubedata);
00480 cpl_imagelist_delete(cubestat);
00481 cpl_msg_debug(idstring, "output cube now has %d/%d planes after copying %d "
00482 "planes from cube %d", nplanes,
00483 (int)cpl_imagelist_get_size(cube->data), l2 - l1 + 1, ic + 1);
00484 }
00485 cpl_table_delete(table);
00486
00487
00488 cpl_msg_info(idstring, "Resetting recipe parameters ESO PRO REC%d to determine "
00489 "wavelength ranges", irecout);
00490 char *hname = cpl_sprintf("ESO PRO REC%d PARAM%d VALUE", irecout, iparout1),
00491 *hvalue = cpl_sprintf("%g", lminout),
00492 *hcomment = cpl_sprintf("set with %s!", idstring);
00493 cpl_propertylist_update_string(cube->header, hname, hvalue);
00494 cpl_propertylist_set_comment(cube->header, hname, hcomment);
00495 cpl_free(hname);
00496 cpl_free(hvalue);
00497 hname = cpl_sprintf("ESO PRO REC%d PARAM%d VALUE", irecout, iparout2),
00498 hvalue = cpl_sprintf("%g", lmaxout),
00499 cpl_propertylist_update_string(cube->header, hname, hvalue);
00500 cpl_propertylist_set_comment(cube->header, hname, hcomment);
00501 cpl_free(hname);
00502 cpl_free(hvalue);
00503 cpl_free(hcomment);
00504
00505
00506 int rc = muse_datacube_save(cube, oname);
00507 muse_datacube_delete(cube);
00508 if (rc == CPL_ERROR_NONE) {
00509 cpl_msg_info(idstring, "Saved cube to \"%s\".", oname);
00510 } else {
00511 cpl_msg_error(idstring, "Error while saving cube to \"%s\": %s (%d)", oname,
00512 cpl_error_get_message(), rc);
00513 rc = 20;
00514 }
00515
00516 if (!cpl_errorstate_is_equal(state)) {
00517 cpl_errorstate_dump(state, CPL_FALSE, muse_cplerrorstate_dump_some);
00518 rc = 50;
00519 }
00520 cpl_memory_dump();
00521 cpl_end();
00522 return rc;
00523 }
00524