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_quality.h"
00034 #include "muse_instrument.h"
00035
00036 #include "muse_cplwrappers.h"
00037 #include "muse_pfits.h"
00038 #include "muse_quadrants.h"
00039 #include "muse_tracing.h"
00040 #include "muse_utils.h"
00041 #include "muse_data_format_z.h"
00042
00043
00050
00051
00054
00078
00079 int
00080 muse_quality_dark_badpix(muse_image *aDark, double aSigmaLo, double aSigmaHi)
00081 {
00082 cpl_ensure(aDark, CPL_ERROR_NULL_INPUT, -1);
00083 float *data = cpl_image_get_data_float(aDark->data);
00084 int *dq = cpl_image_get_data_int(aDark->dq);
00085 cpl_ensure(data && dq, CPL_ERROR_ILLEGAL_INPUT, -2);
00086 #ifdef MUSE_DARK_PREPARE_TEST_DATA
00087 muse_image *x = muse_image_new();
00088 x->data = cpl_image_extract(aDark->data, 1780, 1922, 3000, 4112);
00089 x->dq = cpl_image_extract(aDark->dq, 1780, 1922, 3000, 4112);
00090 x->stat = cpl_image_extract(aDark->stat, 1780, 1922, 3000, 4112);
00091 x->header = cpl_propertylist_duplicate(aDark->header);
00092 cpl_propertylist_update_int(x->header, "ESO DET OUT1 NX", 269);
00093 cpl_propertylist_update_int(x->header, "ESO DET OUT1 NY", 135);
00094 cpl_propertylist_update_int(x->header, "ESO DET OUT2 NX", 952);
00095 cpl_propertylist_update_int(x->header, "ESO DET OUT2 NY", 135);
00096 cpl_propertylist_update_int(x->header, "ESO DET OUT3 NX", 269);
00097
00098 cpl_propertylist_update_int(x->header, "ESO DET OUT4 NX", 952);
00099
00100 const char *fn = "muse_test_quality_dark.fits";
00101 muse_image_save(x, fn);
00102 cpl_msg_debug(__func__, "saved as \"%s\"", fn);
00103 muse_image_delete(x);
00104 #endif
00105
00106
00107
00108 int nbad = muse_quality_image_reject_using_dq(aDark->data, aDark->dq,
00109 aDark->stat);
00110 cpl_msg_debug(__func__, "%d incoming bad pixels", nbad);
00111 cpl_binary *databpm = cpl_mask_get_data(cpl_image_get_bpm(aDark->data)),
00112 *statbpm = NULL;
00113 if (aDark->stat) {
00114 statbpm = cpl_mask_get_data(cpl_image_get_bpm(aDark->stat));
00115 }
00116
00117 int nlo = 0, nhi = 0;
00118 unsigned char n;
00119 for (n = 1; n <= 4; n++) {
00120 cpl_size *w = muse_quadrants_get_window(aDark, n);
00121 cpl_stats_mode smode = CPL_STATS_MEDIAN | CPL_STATS_MEDIAN_DEV
00122 | CPL_STATS_MIN | CPL_STATS_MAX;
00123 cpl_stats *s = cpl_stats_new_from_image_window(aDark->data, smode,
00124 w[0], w[2], w[1], w[3]);
00125 double median = cpl_stats_get_median(s),
00126 mdev = cpl_stats_get_median_dev(s),
00127 min = cpl_stats_get_min(s),
00128 max = cpl_stats_get_max(s),
00129 locut = aSigmaLo > 0 ? median - aSigmaLo * mdev : min,
00130 hicut = aSigmaHi > 0 ? median + aSigmaHi * mdev : max;
00131 cpl_msg_debug(__func__, "quadrant %d bad pixel limits: %g ... %g +/- %g ... %g",
00132 n, locut, median, mdev, hicut);
00133 #if 0
00134 cpl_stats_dump(s, smode, stdout);
00135 fflush(stdout);
00136 #endif
00137 cpl_stats_delete(s);
00138
00139 int i, nx = cpl_image_get_size_x(aDark->data);
00140 for (i = w[0] - 1; i < w[1]; i++) {
00141 int j;
00142 for (j = w[2] - 1; j < w[3]; j++) {
00143 cpl_size pos = i + j*nx;
00144 double value = data[pos];
00145 if (value < locut) {
00146 dq[pos] |= EURO3D_DEADPIXEL;
00147 databpm[pos] = CPL_BINARY_1;
00148 if (statbpm) {
00149 statbpm[pos] = CPL_BINARY_1;
00150 }
00151 nlo++;
00152 }
00153 if (value > hicut) {
00154 dq[pos] |= EURO3D_HOTPIXEL;
00155 databpm[pos] = CPL_BINARY_1;
00156 if (statbpm) {
00157 statbpm[pos] = CPL_BINARY_1;
00158 }
00159 nhi++;
00160 }
00161 }
00162 }
00163 cpl_free(w);
00164 }
00165 if (nlo || aSigmaLo > 0) {
00166 cpl_msg_info(__func__, "%d pixel%s lower than %.3f sigma marked as dark",
00167 nlo, nlo != 1 ? "s" : "", aSigmaLo);
00168 }
00169 if (nhi || aSigmaHi > 0) {
00170 cpl_msg_info(__func__, "%d pixel%s higher than %.3f sigma marked as hot",
00171 nhi, nhi != 1 ? "s" : "", aSigmaHi);
00172 }
00173 return nlo + nhi;
00174 }
00175
00176
00191
00192 int
00193 muse_quality_bad_columns(muse_image *aBias, double aLow, double aHigh)
00194 {
00195 cpl_ensure(aBias && aBias->data && aBias->dq && aBias->stat && aBias->header,
00196 CPL_ERROR_NULL_INPUT, -1);
00197
00198 int nx = cpl_image_get_size_x(aBias->data),
00199 nlo = 0, nhi = 0;
00200 unsigned char n;
00201 for (n = 1; n <= 4; n++) {
00202
00203 cpl_size *w = muse_quadrants_get_window(aBias, n);
00204 cpl_vector *vmean = cpl_vector_new(w[1] - w[0] + 1),
00205 *vstdev = cpl_vector_new(w[1] - w[0] + 1);
00206 int i;
00207 for (i = w[0]; i <= w[1]; i++) {
00208 double mean = cpl_image_get_mean_window(aBias->data, i, w[2], i, w[3]),
00209 stdev = cpl_image_get_stdev_window(aBias->data, i, w[2], i, w[3]);
00210 cpl_vector_set(vmean, i - w[0], mean);
00211 cpl_vector_set(vstdev, i - w[0], stdev);
00212 }
00213
00214
00215 double cmedian = cpl_vector_get_median_const(vmean),
00216 cmdev = muse_cplvector_get_adev_const(vmean, cmedian),
00217 hicut = cmedian + aHigh*cmdev,
00218 locut = cmedian - aLow*cmdev;
00219 char *keyword = cpl_sprintf(QC_BIAS_MASTER_RON, n);
00220 double ron = cpl_propertylist_get_double(aBias->header, keyword);
00221 cpl_free(keyword);
00222 cpl_msg_debug(__func__, "quadrant %1d: mean %f+/-%f(%f); valid range "
00223 "%f...(%f+/-%f)...%f RON=%f", n, cpl_vector_get_mean(vmean),
00224 cpl_vector_get_stdev(vmean), cpl_vector_get_mean(vstdev),
00225 locut, cmedian, cmdev, hicut, ron);
00226
00227 int j;
00228 float *data = cpl_image_get_data_float(aBias->data);
00229 int *dq = cpl_image_get_data_int(aBias->dq);
00230 for (i = w[0]; i <= w[1]; i++) {
00231 double cmean = cpl_vector_get(vmean, i - w[0]),
00232 cstdev = cpl_vector_get(vstdev, i - w[0]);
00233 if (cmean > hicut && cstdev > ron) {
00234 cpl_msg_debug(__func__, "hot column %d (%f+/-%f)", i, cmean, cstdev);
00235
00236 int jfirst = w[2], jlast = w[3];
00237 for (j = w[2]; j <= w[3]; j++) {
00238 if (data[(i-1) + (j-1)*nx] > hicut) {
00239 jfirst = j;
00240 break;
00241 }
00242 }
00243
00244 for (j = w[3]; j >= w[2]; j--) {
00245 if (data[(i-1) + (j-1)*nx] > hicut) {
00246 jlast = j;
00247 break;
00248 }
00249 }
00250
00251 for (j = jfirst; j <= jlast; j++) {
00252 dq[(i-1) + (j-1)*nx] |= EURO3D_DEADPIXEL;
00253 nhi++;
00254 }
00255 } else if (cmean < locut) {
00256 cpl_msg_debug(__func__, "dark column %d (%f+/-%f)", i, cmean, cstdev);
00257
00258 int jfirst = w[2], jlast = w[3];
00259 for (j = w[2]; j <= w[3]; j++) {
00260 if (data[(i-1) + (j-1)*nx] < locut) {
00261 jfirst = j;
00262 break;
00263 }
00264 }
00265
00266 for (j = w[3]; j >= w[2]; j--) {
00267 if (data[(i-1) + (j-1)*nx] < locut) {
00268 jlast = j;
00269 break;
00270 }
00271 }
00272
00273 for (j = jfirst; j <= jlast; j++) {
00274 dq[(i-1) + (j-1)*nx] |= EURO3D_DEADPIXEL;
00275 nhi++;
00276 }
00277 }
00278 }
00279
00280 cpl_vector_delete(vmean);
00281 cpl_vector_delete(vstdev);
00282 cpl_free(w);
00283 }
00284
00285 cpl_msg_info(__func__, "%d low and %d high pixels found", nlo, nhi);
00286
00287 return nlo + nhi;
00288 }
00289
00290
00313
00314 int
00315 muse_quality_flat_badpix(muse_image *aFlat, cpl_table *aTrace,
00316 double aSigmaLo, double aSigmaHi)
00317 {
00318 cpl_ensure(aFlat && aFlat->data && aFlat->dq && aFlat->stat && aTrace,
00319 CPL_ERROR_NULL_INPUT, -1);
00320
00321 cpl_msg_info(__func__, "Marking dark/bright pixels using sigmas %.2f/%.2f",
00322 aSigmaLo, aSigmaHi);
00323 int ndark = 0, nhot = 0, nlowqe = 0,
00324 nx = cpl_image_get_size_x(aFlat->data),
00325 ny = cpl_image_get_size_y(aFlat->data);
00326 float *data = cpl_image_get_data_float(aFlat->data);
00327 int *dq = cpl_image_get_data_int(aFlat->dq);
00328
00329
00330
00331 double mean = cpl_image_get_mean(aFlat->data);
00332 #if 0
00333 cpl_msg_debug(__func__, "mean flat value: %f", mean);
00334 #endif
00335 int nslice;
00336 for (nslice = 1; nslice <= kMuseSlicesPerCCD; nslice++) {
00337
00338 cpl_polynomial **ptrace = muse_trace_table_get_polys_for_slice(aTrace,
00339 nslice);
00340 if (!ptrace) {
00341 cpl_msg_warning(__func__, "slice %2d: tracing polynomials missing!",
00342 nslice);
00343 continue;
00344 }
00345
00346
00347 int j;
00348 for (j = 0; j < ny; j++) {
00349
00350
00351 cpl_errorstate prestate = cpl_errorstate_get();
00352 double x1 = cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_LEFT], j+1, NULL),
00353 x2 = cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_RIGHT], j+1, NULL);
00354 if (!cpl_errorstate_is_equal(prestate) || !isnormal(x1) || !isnormal(x2)
00355 || x1 < 1 || x2 > nx || x1 > x2) {
00356 cpl_msg_warning(__func__, "slice %2d: faulty polynomial detected at "
00357 "y=%d (borders: %f ... %f): %s", nslice, j+1, x1, x2,
00358 cpl_error_get_message());
00359 j = ny;
00360 continue;
00361 }
00362
00363
00364 int mleft = ceil(x1),
00365 mright = floor(x2);
00366
00367 #if 0
00368 double xc = cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_CENTER], j+1, NULL);
00369 cpl_msg_debug(__func__, "%02d %04d: %04d/%.3f...%.3f...%04d/%.3f "
00370 "(%02d/%.3f wide)", nslice, j+1, mleft,x1, xc, mright,x2,
00371 mright - mleft, x2 - x1);
00372 #endif
00373 unsigned statmask = CPL_STATS_MIN | CPL_STATS_MAX
00374 | CPL_STATS_MEAN | CPL_STATS_STDEV
00375 | CPL_STATS_MEDIAN | CPL_STATS_MEDIAN_DEV;
00376 cpl_stats *stats = cpl_stats_new_from_image_window(aFlat->data, statmask,
00377 mleft, j+1,
00378 mright, j+1);
00379 #if 0
00380 cpl_stats_dump(stats, statmask, stdout);
00381 fflush(stdout);
00382 #endif
00383 double median = cpl_stats_get_median(stats),
00384 llim = median - aSigmaLo * cpl_stats_get_median_dev(stats),
00385 hlim = median + aSigmaHi * cpl_stats_get_median_dev(stats);
00386 cpl_stats_delete(stats);
00387
00388
00389 llim = llim <= 0 ? 1.e-4 : llim;
00390 #if 0
00391 cpl_msg_debug(__func__, "limits: %f...%f (sigmas %.2f/%.2f)", llim, hlim,
00392 aSigmaLo, aSigmaHi);
00393 #endif
00394
00395
00396
00397 int i, i1 = mleft - 1, i2 = mright - 1;
00398 for (i = mleft - 1; i < mleft + kMuseSliceMaxEdgeWidth; i++) {
00399 if (data[i + j*nx] > llim) {
00400 i1 = i;
00401 break;
00402 }
00403 }
00404 for (i = mright - 1; i > mright - kMuseSliceMaxEdgeWidth; i--) {
00405 if (data[i + j*nx] > llim) {
00406 i2 = i;
00407 break;
00408 }
00409 }
00410
00411
00412
00413 for (i = i1; i <= i2; i++) {
00414 if (data[i + j*nx] < llim) {
00415 dq[i + j*nx] |= EURO3D_DARKPIXEL;
00416 if (data[i + j*nx] < 0.2 * mean) {
00417
00418
00419 dq[i + j*nx] |= EURO3D_LOWQEPIXEL;
00420 nlowqe++;
00421 }
00422 #if 0
00423 cpl_msg_debug(__func__, "%04d,%04d is DARK%s: %f", i+1, j+1,
00424 data[i + j*nx] < 0.2 * mean ? " and low QE" : "",
00425 data[i + j*nx]);
00426 #endif
00427 ndark++;
00428 } else if (data[i + j*nx] > hlim) {
00429 dq[i + j*nx] |= EURO3D_HOTPIXEL;
00430 #if 0
00431 cpl_msg_debug(__func__, "%04d,%04d is HOT: %f", i+1, j+1, data[i + j*nx]);
00432 #endif
00433 nhot++;
00434 }
00435 }
00436 }
00437
00438 muse_trace_polys_delete(ptrace);
00439 }
00440
00441
00442 int i, nnonpos = 0;
00443 for (i = 0; i < nx; i++) {
00444 int j;
00445 for (j = 0; j < ny; j++) {
00446 if (data[i + j*nx] <= 0) {
00447 dq[i + j*nx] |= EURO3D_BADOTHER;
00448 nnonpos++;
00449 }
00450 }
00451 }
00452
00453 cpl_msg_info(__func__, "Found %d dark (%d of them are also low QE), %d hot, "
00454 "and %d non-positive pixels", ndark, nlowqe, nhot, nnonpos);
00455 return ndark + nhot;
00456 }
00457
00458
00471
00472 int
00473 muse_quality_set_saturated(muse_image *aImage)
00474 {
00475 cpl_ensure(aImage && aImage->data && aImage->dq, CPL_ERROR_NULL_INPUT, -1);
00476
00477 float *data = cpl_image_get_data_float(aImage->data);
00478 int *dq = cpl_image_get_data_int(aImage->dq);
00479 int i, j, nsaturated = 0,
00480 nx = cpl_image_get_size_x(aImage->data),
00481 ny = cpl_image_get_size_y(aImage->data);
00482 for (i = 0; i < nx; i++) {
00483 for (j = 0; j < ny; j++) {
00484 if (data[i + j*nx] > kMuseSaturationLimit ||
00485 data[i + j*nx] < FLT_EPSILON) {
00486 dq[i + j*nx] |= EURO3D_SATURATED;
00487 nsaturated++;
00488 }
00489 }
00490 }
00491
00492 return nsaturated;
00493 }
00494
00495
00509
00510 cpl_table *
00511 muse_quality_convert_dq(cpl_image *aDQ)
00512 {
00513 cpl_ensure(aDQ, CPL_ERROR_NULL_INPUT, NULL);
00514 int nx = cpl_image_get_size_x(aDQ),
00515 ny = cpl_image_get_size_y(aDQ);
00516 const int *dq = cpl_image_get_data_int_const(aDQ);
00517 int i, j, nbad = 0;
00518 for (i = 0; i < nx; i++) {
00519 for (j = 0; j < ny; j++) {
00520 if (dq[i + j*nx] != EURO3D_GOODPIXEL) {
00521 nbad++;
00522 }
00523 }
00524 }
00525 cpl_table *table = muse_cpltable_new(muse_badpix_table_def, nbad);
00526
00527 if (!nbad) {
00528 return table;
00529 }
00530
00531 nbad = 0;
00532 for (i = 0; i < nx; i++) {
00533 for (j = 0; j < ny; j++) {
00534 if (dq[i + j*nx] == EURO3D_GOODPIXEL) {
00535 continue;
00536 }
00537 int xbad = i + 1,
00538 ybad = j + 1;
00539
00540 muse_quadrants_coords_to_raw(NULL, &xbad, &ybad);
00541 cpl_table_set_int(table, MUSE_BADPIX_X, nbad, xbad);
00542 cpl_table_set_int(table, MUSE_BADPIX_Y, nbad, ybad);
00543 cpl_table_set_int(table, MUSE_BADPIX_DQ, nbad, dq[i + j*nx]);
00544
00545 nbad++;
00546 }
00547 }
00548 return table;
00549 }
00550
00551
00565
00566 cpl_error_code
00567 muse_quality_merge_badpix(cpl_table *aTable, const cpl_table *aToMerge)
00568 {
00569 cpl_ensure_code(aTable && aToMerge, CPL_ERROR_NULL_INPUT);
00570 cpl_error_code rc = cpl_table_insert(aTable, aToMerge,
00571 cpl_table_get_nrow(aTable));
00572 cpl_ensure_code(rc == CPL_ERROR_NONE, rc);
00573
00574
00575 cpl_propertylist *order = cpl_propertylist_new();
00576 cpl_propertylist_append_bool(order, MUSE_BADPIX_X, FALSE);
00577 cpl_propertylist_append_bool(order, MUSE_BADPIX_Y, FALSE);
00578 cpl_table_sort(aTable, order);
00579 cpl_propertylist_delete(order);
00580
00581
00582 cpl_table_unselect_all(aTable);
00583 const int *x = cpl_table_get_data_int_const(aTable, MUSE_BADPIX_X),
00584 *y = cpl_table_get_data_int_const(aTable, MUSE_BADPIX_Y);
00585 int *dq = cpl_table_get_data_int(aTable, MUSE_BADPIX_DQ);
00586 float *value = cpl_table_get_data_float(aTable, MUSE_BADPIX_VALUE);
00587 int i, nrow = cpl_table_get_nrow(aTable);
00588 for (i = 1; i < nrow; i++) {
00589 if (x[i] == x[i-1] && y[i] == y[i-1]) {
00590 dq[i-1] |= dq[i];
00591 if (value) {
00592
00593 value[i-1] = fmax(value[i-1], value[i]);
00594 }
00595 cpl_table_select_row(aTable, i);
00596 }
00597 }
00598 rc = cpl_table_erase_selected(aTable);
00599
00600 return rc;
00601 }
00602
00603
00626
00627 int
00628 muse_quality_image_reject_using_dq(cpl_image *aData, cpl_image *aDQ,
00629 cpl_image *aStat)
00630 {
00631 cpl_ensure(aData && aDQ, CPL_ERROR_NULL_INPUT, -1);
00632 int nx = cpl_image_get_size_x(aData),
00633 ny = cpl_image_get_size_y(aData);
00634 cpl_ensure(nx == cpl_image_get_size_x(aDQ) &&
00635 ny == cpl_image_get_size_y(aDQ), CPL_ERROR_INCOMPATIBLE_INPUT, -2);
00636 if (aStat) {
00637 cpl_ensure(nx == cpl_image_get_size_x(aStat) &&
00638 ny == cpl_image_get_size_y(aStat), CPL_ERROR_INCOMPATIBLE_INPUT,
00639 -2);
00640 }
00641 const int *dq = cpl_image_get_data_int_const(aDQ);
00642 if (!dq) {
00643 return -3;
00644 }
00645 #if 0
00646 double cputime = cpl_test_get_cputime(),
00647 walltime = cpl_test_get_walltime();
00648 #endif
00649 cpl_binary *bpm = cpl_mask_get_data(cpl_image_get_bpm(aData)),
00650 *statbpm = NULL;
00651 if (aStat) {
00652 statbpm = cpl_mask_get_data(cpl_image_get_bpm(aStat));
00653 }
00654 int i, j, nbad = 0;
00655 for (i = 0; i < nx; i++) {
00656 for (j = 0; j < ny; j++) {
00657 if (dq[i + j*nx] == EURO3D_GOODPIXEL) {
00658 continue;
00659 }
00660 nbad++;
00661 bpm[i + j*nx] = CPL_BINARY_1;
00662 if (aStat) {
00663 statbpm[i + j*nx] = CPL_BINARY_1;
00664 }
00665 }
00666 }
00667 #if 0
00668 double cputime2 = cpl_test_get_cputime(),
00669 walltime2 = cpl_test_get_walltime();
00670 cpl_msg_debug(__func__, "reject_using_dq times new: cpu %f wall %f", cputime2 - cputime,
00671 walltime2 - walltime);
00672 #endif
00673 return nbad;
00674 }
00675
00676
00696
00697 cpl_table *
00698 muse_quality_merge_badpix_from_file(const cpl_table *aTable, const char *aInFile,
00699 const char *aExtname, int *aExt)
00700 {
00701 cpl_ensure(aTable && aInFile, CPL_ERROR_NULL_INPUT, NULL);
00702
00703 int extension = cpl_fits_find_extension(aInFile, aExtname);
00704 cpl_table *table = NULL;
00705 if (extension < 1) {
00706 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
00707 printf("Input table \"%s\" does not contain a table for EXTNAME=\"%s\""
00708 " yet\n", aInFile, aExtname);
00709 }
00710 } else {
00711 table = cpl_table_load(aInFile, extension, 1);
00712 if (!table) {
00713 printf("WARNING: could not load BADPIX_TABLE from EXTNAME=\"%s\" from "
00714 "table \"%s\" (the headers say that it should be extension %d)!\n",
00715 aExtname, aInFile, extension);
00716 }
00717 }
00718 cpl_ensure(table, CPL_ERROR_DATA_NOT_FOUND, NULL);
00719
00720 if (aExt) {
00721 *aExt = extension;
00722 }
00723
00724 cpl_size nold = cpl_table_get_nrow(table);
00725 cpl_error_code rc = muse_quality_merge_badpix(table, aTable);
00726 if (rc != CPL_ERROR_NONE) {
00727 printf("WARNING: Merging input and new table failed: %s\n",
00728 cpl_error_get_message());
00729 printf("Table still has %"CPL_SIZE_FORMAT" bad pixel%s\n", nold,
00730 nold != 1 ? "s" : "");
00731 } else {
00732 cpl_size nbad = cpl_table_get_nrow(table);
00733 printf("Merged %"CPL_SIZE_FORMAT" of %"CPL_SIZE_FORMAT" bad pixel%s into "
00734 "the input table (now %"CPL_SIZE_FORMAT" entries)\n", nbad - nold,
00735 cpl_table_get_nrow(table), (nbad - nold) != 1 ? "s" : "", nbad);
00736 }
00737
00738 return table;
00739 }
00740
00741
00762
00763 cpl_error_code
00764 muse_quality_copy_badpix_table(const char *aInFile, const char *aOutFile,
00765 int aExtension, const cpl_table *aTable)
00766 {
00767 cpl_ensure_code(aInFile && aOutFile && aTable, CPL_ERROR_NULL_INPUT);
00768
00769 cpl_errorstate state = cpl_errorstate_get();
00770 cpl_error_code rc = CPL_ERROR_NONE;
00771 cpl_size nextensions = cpl_fits_count_extensions(aInFile);
00772 if (!cpl_errorstate_is_equal(state)) {
00773 rc = cpl_error_get_code();
00774 }
00775 if (nextensions > 0) {
00776 printf("Saving primary header and %"CPL_SIZE_FORMAT" extensions to \"%s\"\n",
00777 nextensions, aOutFile);
00778 }
00779 cpl_size i;
00780 for (i = 0; i <= nextensions; i++) {
00781 cpl_propertylist *extheader = cpl_propertylist_load(aInFile, i);
00782 if (i == 0) {
00783
00784
00785 cpl_propertylist_update_string(extheader, "PIPEFILE", aOutFile);
00786 cpl_propertylist_set_comment(extheader, "PIPEFILE",
00787 "pretend to be a pipeline output file");
00788 cpl_propertylist_save(extheader, aOutFile, CPL_IO_CREATE);
00789 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
00790 printf("Saved primary header to \"%s\"\n", aOutFile);
00791 }
00792 cpl_propertylist_delete(extheader);
00793 continue;
00794 }
00795 if (aTable && i == aExtension) {
00796 unsigned char nifu = muse_utils_get_ifu(extheader);
00797 printf("Saving merged table of IFU %2hhu to extension %"CPL_SIZE_FORMAT
00798 "\n", nifu, i);
00799 cpl_table_save(aTable, NULL, extheader, aOutFile, CPL_IO_EXTEND);
00800 cpl_propertylist_delete(extheader);
00801 continue;
00802 }
00803
00804 cpl_table *tab = NULL;
00805 const char *xtension = cpl_propertylist_get_string(extheader, "XTENSION");
00806 if (xtension && strncmp(xtension, "BINTABLE", 8)) {
00807 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
00808 printf("WARNING: Not a binary table extension, skipping data section "
00809 "(extension %"CPL_SIZE_FORMAT")", i);
00810 }
00811 cpl_propertylist_save(extheader, aOutFile, CPL_IO_EXTEND);
00812 } else {
00813 tab = cpl_table_load(aInFile, i, 1);
00814 cpl_table_save(tab, NULL, extheader, aOutFile, CPL_IO_EXTEND);
00815 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
00816 printf("Saved table extension %"CPL_SIZE_FORMAT" to \"%s\"\n", i,
00817 aOutFile);
00818 }
00819 }
00820 cpl_table_delete(tab);
00821 cpl_propertylist_delete(extheader);
00822 }
00823
00824 return rc;
00825 }
00826