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 <string.h>
00030
00031 #include "muse_dfs.h"
00032 #include "muse_pfits.h"
00033 #include "muse_pixtable.h"
00034 #include "muse_cplwrappers.h"
00035 #include "muse_wcs.h"
00036 #include "muse_flux.h"
00037 #include "muse_utils.h"
00038 #include "muse_idp.h"
00039
00040
00041
00042
00043
00044 #define KEY_ASSON "ASSON"
00045 #define KEY_ASSON_COMMENT "Associated file name"
00046 #define KEY_DEC "DEC"
00047 #define KEY_DEC_COMMENT "[deg] Image center (J2000)"
00048 #define KEY_EXPTIME "EXPTIME"
00049 #define KEY_EXPTIME_COMMENT "[s] Total integration time per pixel"
00050 #define KEY_FLUXCAL "FLUXCAL"
00051 #define KEY_FLUXCAL_COMMENT "Type of flux calibration (ABSOLUTE or UNCALIBRATED)"
00052 #define KEY_FLUXCAL_VALUE_FALSE "UNCALIBRATED"
00053 #define KEY_FLUXCAL_VALUE_TRUE "ABSOLUTE"
00054 #define KEY_MJDOBS "MJD-OBS"
00055 #define KEY_MJDOBS_COMMENT "[d] Start of observations (days)"
00056 #define KEY_MJDEND "MJD-END"
00057 #define KEY_MJDEND_COMMENT "[d] End of observations (days)"
00058 #define KEY_OBID "OBID"
00059 #define KEY_OBID_COMMENT "Observation block ID"
00060 #define KEY_OBSTECH "OBSTECH"
00061 #define KEY_OBSTECH_COMMENT "Technique for observation"
00062 #define KEY_PROCSOFT "PROCSOFT"
00063 #define KEY_PROCSOFT_COMMENT "ESO pipeline version"
00064 #define KEY_PRODCATG "PRODCATG"
00065 #define KEY_PRODCATG_COMMENT "Data product category"
00066 #define KEY_PRODCATG_VALUE_IFS_CUBE "SCIENCE.CUBE.IFS"
00067 #define KEY_PRODCATG_VALUE_FOV_IMAGE "ANCILLARY.IMAGE"
00068 #define KEY_PROG_ID "PROG_ID"
00069 #define KEY_PROG_ID_COMMENT "ESO programme identification"
00070 #define KEY_PROG_ID_VALUE_MULTIPLE "MULTI"
00071 #define KEY_PROGID "PROGID"
00072 #define KEY_PROGID_COMMENT KEY_PROG_ID_COMMENT
00073 #define KEY_PROV "PROV"
00074 #define KEY_PROV_COMMENT "Originating raw science file"
00075 #define KEY_RA "RA"
00076 #define KEY_RA_COMMENT "[deg] Image center (J2000)"
00077 #define KEY_REFERENC "REFERENC"
00078 #define KEY_REFERENC_COMMENT "Reference publication"
00079 #define KEY_TEXPTIME "TEXPTIME"
00080 #define KEY_TEXPTIME_COMMENT "[s] Total integration time of all exposures"
00081 #define KEY_WAVELMIN "WAVELMIN"
00082 #define KEY_WAVELMIN_COMMENT "[nm] Minimum wavelength"
00083 #define KEY_WAVELMAX "WAVELMAX"
00084 #define KEY_WAVELMAX_COMMENT "[nm] Maximum wavelength"
00085 #define KEY_SKY_RES "SKY_RES"
00086 #define KEY_SKY_RES_COMMENT "[arcsec] FWHM effective spatial resolution (measured)"
00087 #define KEY_SKY_RERR "SKY_RERR"
00088 #define KEY_SKY_RERR_COMMENT "[arcsec] Error of SKY_RES (estimated)"
00089 #define KEY_SPEC_RES "SPEC_RES"
00090 #define KEY_SPEC_RES_COMMENT "Spectral resolving power at central wavelength"
00091 #define KEY_SPEC_ERR "CRDER3"
00092 #define KEY_SPEC_ERR_COMMENT "[Angstrom] Random error in spectral coordinate"
00093 #define KEY_PIXNOISE "PIXNOISE"
00094 #define KEY_PIXNOISE_COMMENT "[erg/s/cm**2/Angstrom] pixel-to-pixel noise"
00095 #define KEY_ABMAGLIM "ABMAGLIM"
00096 #define KEY_ABMAGLIM_COMMENT "5-sigma magnitude limit for point sources"
00097 #define KEY_NCOMBINE "NCOMBINE"
00098 #define KEY_NCOMBINE_COMMENT "No. of combined raw science data files"
00099
00100
00101 #define CLEAN_KEYS_REGEXP \
00102 "^(" KEY_MJDEND "|" \
00103 KEY_PROCSOFT "|" \
00104 KEY_PRODCATG "|" \
00105 KEY_PROG_ID "|" \
00106 KEY_PROGID "[0-9]+|" \
00107 KEY_OBID "[0-9]+|" \
00108 KEY_OBSTECH "|" \
00109 KEY_FLUXCAL "|" \
00110 KEY_TEXPTIME "|" \
00111 KEY_WAVELMIN "|" \
00112 KEY_WAVELMAX "|" \
00113 KEY_SKY_RES "|" \
00114 KEY_SKY_RERR "|" \
00115 KEY_SPEC_RES "|" \
00116 KEY_PIXNOISE "|" \
00117 KEY_ABMAGLIM "|" \
00118 KEY_REFERENC "|" \
00119 KEY_NCOMBINE "|" \
00120 KEY_PROV "[0-9]+|" \
00121 KEY_ASSON "[0-9]+" ")$"
00122
00123
00127
00128
00131
00132
00133 typedef struct {
00134
00135 double lambda;
00136
00137 double R;
00138 } muse_specres_lut_entry;
00139
00140
00141
00142 static const muse_specres_lut_entry
00143 muse_specres_data_wfm[] =
00144 {
00145 {4650.0000, 1674.77},
00146 {4810.3448, 1769.45},
00147 {4970.6897, 1864.50},
00148 {5131.0345, 1959.52},
00149 {5291.3793, 2054.19},
00150 {5451.7242, 2148.34},
00151 {5612.0690, 2241.81},
00152 {5772.4138, 2334.46},
00153 {5932.7587, 2426.18},
00154 {6093.1035, 2516.84},
00155 {6253.4483, 2606.28},
00156 {6413.7932, 2694.36},
00157 {6574.1380, 2780.89},
00158 {6734.4828, 2865.70},
00159 {6894.8277, 2948.59},
00160 {7055.1725, 3029.32},
00161 {7215.5173, 3107.70},
00162 {7375.8622, 3183.46},
00163 {7536.2070, 3256.36},
00164 {7696.5518, 3326.12},
00165 {7856.8967, 3392.45},
00166 {8017.2415, 3455.01},
00167 {8177.5863, 3513.44},
00168 {8337.9312, 3567.37},
00169 {8498.2760, 3616.34},
00170 {8658.6208, 3659.87},
00171 {8818.9657, 3697.42},
00172 {8979.3105, 3728.38},
00173 {9139.6553, 3752.11},
00174 {9300.0002, 3767.93},
00175 { 0.0000 , 0.00}
00176 };
00177
00178
00179 static const muse_specres_lut_entry
00180 muse_specres_data_nfm[] =
00181 {
00182 {4800.0000, 1740.00},
00183 {9300.0000, 3450.00},
00184 { 0.0000 , 0.00}
00185 };
00186
00187
00188
00189
00190 static const unsigned int kMuseNumQuadrants = 4;
00191
00192
00193 static const double kMuseFovSizeWFM = 60.00;
00194 static const double kMuseFovSizeNFM = 7.43;
00195
00196
00197 static const double kMusePixscaleWFM = 0.2;
00198 static const double kMusePixscaleNFM = 0.025;
00199
00200
00201 static const double kMuseLambdaRef = 7000.;
00202
00203
00204 static const double kMuseResponseRef = 41.2;
00205
00206
00207 static const double kMuseExtraErrorIQE = 0.3;
00208
00209
00210
00211
00212 static const double kMuseSkyRes = 0.853823;
00213 static const double kMuseSkyResError = 0.495547;
00214
00215
00216
00217
00218 static const double day2sec = 86400.0;
00219 static const double m2nm = 1.e9;
00220 static const double nm2Angstrom = 10.;
00221 static const double deg2as = 3600.;
00222
00223
00224
00225
00226
00227
00228
00237
00238 static cpl_boolean
00239 muse_pfits_get_fluxcal(const cpl_propertylist *aHeaders)
00240 {
00241 cpl_ensure(aHeaders, CPL_ERROR_NULL_INPUT, CPL_FALSE);
00242 cpl_errorstate prestate = cpl_errorstate_get();
00243 cpl_boolean value = cpl_propertylist_get_bool(aHeaders,
00244 MUSE_HDR_PT_FLUXCAL);
00245 cpl_errorstate_set(prestate);
00246 return value;
00247 }
00248
00249
00266
00267 static int
00268 muse_idp_get_scales(const cpl_propertylist *aHeader, double *xscale, double *yscale)
00269 {
00270
00271 int flag = 0;
00272
00273 double _xscale = 0.;
00274 double _yscale = 0.;
00275
00276 cpl_errorstate status = cpl_errorstate_get();
00277
00278 if (muse_wcs_get_scales((cpl_propertylist *)aHeader, &_xscale, &_yscale) != CPL_ERROR_NONE) {
00279 const char *insmode = muse_pfits_get_insmode(aHeader);
00280 if (insmode) {
00281 if (strncmp(insmode, "NFM", 3) == 0) {
00282 _xscale = kMusePixscaleNFM;
00283 _yscale = kMusePixscaleNFM;
00284 } else {
00285 _xscale = kMusePixscaleWFM;
00286 _yscale = kMusePixscaleWFM;
00287 }
00288 flag = 1;
00289 } else {
00290 *xscale = _xscale;
00291 *yscale = _yscale;
00292 flag = -1;
00293 }
00294 } else {
00295 _xscale *= deg2as;
00296 _yscale *= deg2as;
00297 }
00298
00299 cpl_errorstate_set(status);
00300
00301 if (flag == -1) {
00302 cpl_msg_debug(__func__, "Keyword \"INS.MODE\" is missing!");
00303 cpl_error_set(__func__, CPL_ERROR_DATA_NOT_FOUND);
00304 } else {
00305 *xscale = _xscale;
00306 *yscale = _yscale;
00307 }
00308
00309 return flag;
00310 }
00311
00312
00313
00326
00327 static double
00328 muse_idp_compute_specres(double aLambda, const muse_specres_lut_entry *aSpecresLut)
00329 {
00330
00331
00332
00333
00334 cpl_size i = 0;
00335 while ((aSpecresLut[i].lambda > 0.) && (aLambda > aSpecresLut[i].lambda)) {
00336 ++i;
00337 }
00338
00339 if (i == 0) {
00340 return aSpecresLut[0].R;
00341 }
00342 else if (aSpecresLut[i].lambda == 0.) {
00343 return aSpecresLut[i - 1].R;
00344 }
00345
00346 double t = (aLambda - aSpecresLut[i - 1].lambda) /
00347 (aSpecresLut[i].lambda - aSpecresLut[i - 1].lambda);
00348
00349 return (1 - t) * aSpecresLut[i - 1].R + t * aSpecresLut[i].R;
00350 }
00351
00352
00366
00367 static double
00368 muse_idp_compute_iqe(double aLambda, double aSeeing, double aAirmass)
00369 {
00370
00371 const double rad2as = 180. / CPL_MATH_PI * 3600.;
00372
00373
00374
00375 const double L0 = 23.;
00376
00377
00378 const double D = 8.1175365721399437;
00379
00380
00381 const double Fkolb = 1. / (1. + 300. * D / L0) - 1.;
00382
00383
00384
00385 double lambda = aLambda / 5000.;
00386
00387
00388 double r0 = 0.976 * 5.e-7 / aSeeing * rad2as *
00389 pow(lambda, 1.2) * pow(aAirmass, -0.6);
00390
00391 double iqe = aSeeing * pow(lambda, -0.2) * pow(aAirmass, 0.6);
00392 iqe *= sqrt(1. + Fkolb * 2.183 * pow(r0 / L0, 0.356));
00393
00394 return iqe;
00395 }
00396
00397
00412
00413 static double
00414 muse_idp_compute_pixnoise(const muse_datacube *aCube,
00415 double aVarianceMin, double aVarianceMax,
00416 double aVarianceBin)
00417 {
00418 cpl_ensure(aCube != NULL, CPL_ERROR_NULL_INPUT, 0.);
00419 cpl_ensure(aCube->stat, CPL_ERROR_DATA_NOT_FOUND, 0.);
00420 cpl_ensure((aVarianceMin >= 0.) && (aVarianceMax > aVarianceMin),
00421 CPL_ERROR_ILLEGAL_INPUT, 0.);
00422 cpl_ensure(aVarianceBin > 0., CPL_ERROR_ILLEGAL_INPUT, 0.);
00423
00424 cpl_size nbins = (cpl_size)((aVarianceMax - aVarianceMin) / aVarianceBin) + 1;
00425 if (nbins < 2) {
00426 cpl_error_set(__func__, CPL_ERROR_INCOMPATIBLE_INPUT);
00427 return 0.;
00428 }
00429
00430 const cpl_imagelist *data = aCube->stat;
00431 cpl_matrix *histogram = cpl_matrix_new(1, nbins);
00432 double *hdata = cpl_matrix_get_data(histogram);
00433
00434 cpl_size iplane;
00435 for (iplane = 0; iplane < cpl_imagelist_get_size(data); ++iplane) {
00436 const cpl_image *plane = cpl_imagelist_get_const(data, iplane);
00437 const float *_data = cpl_image_get_data_float_const(plane);
00438 cpl_size ndata = cpl_image_get_size_x(plane) * cpl_image_get_size_y(plane);
00439 cpl_size idata;
00440 for (idata = 0; idata < ndata; ++idata) {
00441 register double v = _data[idata];
00442 if ((isnan(v) == 0) && (v >= aVarianceMin) && (v <= aVarianceMax)) {
00443 cpl_size ibin = (cpl_size)((v + aVarianceMin) / aVarianceBin);
00444 hdata[ibin] += 1.;
00445 }
00446 }
00447 }
00448
00449
00450
00451 cpl_size irow = 0.;
00452 cpl_size icol = 0.;
00453 cpl_matrix_get_maxpos(histogram, &irow, &icol);
00454
00455
00456 double mode = aVarianceMin + (icol + 0.5) * aVarianceBin;
00457 cpl_matrix_delete(histogram);
00458
00459 return mode;
00460 }
00461
00462
00472
00473 static double
00474 muse_idp_compute_abmaglimit(const muse_datacube *aCube, double aWlenMin,
00475 double aWlenMax, double aFwhm)
00476 {
00477 cpl_ensure(aCube != NULL, CPL_ERROR_NULL_INPUT, 0.);
00478 cpl_ensure(aWlenMax > aWlenMin, CPL_ERROR_ILLEGAL_INPUT, 0.);
00479 cpl_ensure(aFwhm > 0., CPL_ERROR_ILLEGAL_INPUT, 0.);
00480
00481
00482
00483
00484 const cpl_size min_valid = 2;
00485
00486
00487
00488 muse_image *fov = muse_datacube_collapse((muse_datacube *)aCube, NULL);
00489 muse_image_dq_to_nan(fov);
00490
00491 cpl_size nx = cpl_image_get_size_x(fov->data);
00492 cpl_size ny = cpl_image_get_size_y(fov->data);
00493
00494
00495 cpl_image_reject_value(fov->data, CPL_VALUE_NOTFINITE);
00496 #undef USE_HISTOGRAM
00497 #ifndef USE_HISTOGRAM
00498 double median = cpl_image_get_median(fov->data);
00499 #else
00500 double sigma = 0;
00501 double median = cpl_image_get_mad(fov->data, &sigma);
00502 #endif
00503
00504
00505
00506
00507
00508
00509
00510 cpl_size _nx = (nx % 2) == 0 ? nx : nx - 1;
00511 cpl_size _ny = (ny % 2) == 0 ? ny : ny - 1;
00512 cpl_size npixel = _nx * _ny;
00513
00514 cpl_image *fov_clean = cpl_image_new(_nx, _ny, CPL_TYPE_DOUBLE);
00515 cpl_image_fill_window(fov_clean, 1, 1, _nx, _ny, median);
00516
00517 cpl_mask *fov_invalid = cpl_mask_new(_nx, _ny);
00518 cpl_binary *_fov_invalid = cpl_mask_get_data(fov_invalid);
00519
00520 const float *_fov_data = cpl_image_get_data_float(fov->data);
00521 double *_fov_clean = cpl_image_get_data_double(fov_clean);
00522
00523 cpl_size iy;
00524 for (iy = 0; iy < _ny; ++iy) {
00525 cpl_size ix;
00526 for (ix = 0; ix < _nx; ++ix) {
00527 cpl_size _ipixel = nx * iy + ix;
00528 if ((isnan(_fov_data[_ipixel]) == 0) &&
00529 (_fov_data[_ipixel] < median)) {
00530 _fov_clean[_nx * iy + ix] = _fov_data[_ipixel];
00531 } else {
00532 _fov_invalid[_nx * iy + ix] = CPL_BINARY_1;
00533 }
00534
00535 }
00536 }
00537 muse_image_delete(fov);
00538
00539
00540
00541
00542
00543
00544 const double csigma = aFwhm / (2. * sqrt(2. * log(2.)));
00545 const double radius = CPL_MAX(3. * csigma, 2.001);
00546 const int nhalf = (int)(radius + 0.5);
00547 cpl_matrix *ckernel = muse_matrix_new_gaussian_2d(nhalf, nhalf, csigma);
00548 cpl_matrix_divide_scalar(ckernel, cpl_matrix_get_max(ckernel));
00549
00550 cpl_image *fov_smooth = muse_convolve_image(fov_clean, ckernel);
00551
00552 cpl_matrix_delete(ckernel);
00553 cpl_image_delete(fov_clean);
00554
00555
00556
00557
00558
00559
00560 cpl_size nmask = 2 * nhalf + 1;
00561 cpl_mask *mkernel = cpl_mask_new(nmask, nmask);
00562 cpl_binary *_mkernel = cpl_mask_get_data(mkernel);
00563 double rsquare = radius * radius;
00564
00565 for (iy = 0; iy < nmask; ++iy) {
00566 cpl_size ix;
00567 double y = (double)iy - radius;
00568 for (ix = 0; ix < nmask; ++ix) {
00569 double x = (double)ix - radius;
00570 _mkernel[nmask * iy + ix] = ((x * x + y * y) > rsquare) ?
00571 CPL_BINARY_0 : CPL_BINARY_1;
00572 }
00573 }
00574
00575 cpl_mask *fov_mask = cpl_mask_new(_nx, _ny);
00576 cpl_mask_filter(fov_mask, fov_invalid, mkernel,
00577 CPL_FILTER_DILATION, CPL_BORDER_ZERO);
00578 cpl_mask_delete(mkernel);
00579
00580
00581
00582
00583
00584 cpl_binary *_fov_mask = cpl_mask_get_data(fov_mask);
00585
00586 cpl_size ipixel;
00587 for (ipixel = 0; ipixel < npixel; ++ipixel) {
00588 cpl_size _x = ipixel % _nx;
00589 cpl_size _y = ipixel / _nx;
00590 if (((_x < nhalf) ||(_x > (_nx - nhalf - 1))) ||
00591 ((_y < nhalf) ||(_y > (_ny - nhalf - 1)))) {
00592 _fov_mask[_y * _nx + _x] = CPL_BINARY_1;
00593 }
00594 }
00595
00596
00597
00598
00599 if (npixel - cpl_mask_count(fov_mask) < min_valid) {
00600 cpl_msg_debug(__func__, "Number of valid pixels in the dilated mask is"
00601 "less than 2! Falling back to the original mask!");
00602 cpl_mask_delete(fov_mask);
00603 fov_mask = fov_invalid;
00604 fov_invalid = NULL;
00605 } else {
00606 cpl_mask_delete(fov_invalid);
00607 }
00608
00609 #ifndef USE_HISTOGRAM
00610 const double *_fov_smooth = cpl_image_get_data_double_const(fov_smooth);
00611
00612 double *_fov_valid = cpl_calloc(npixel, sizeof *_fov_valid);
00613
00614 cpl_size nvalid = 0;
00615 for (ipixel = 0; ipixel < npixel; ++ipixel) {
00616 if (_fov_mask[ipixel] == CPL_BINARY_0) {
00617 _fov_valid[nvalid] = _fov_smooth[ipixel];
00618 ++nvalid;
00619 }
00620 }
00621 cpl_mask_delete(fov_mask);
00622 cpl_image_delete(fov_smooth);
00623
00624 cpl_vector *fov_valid = cpl_vector_wrap(nvalid, _fov_valid);
00625 double sdev = cpl_vector_get_stdev(fov_valid);
00626
00627 cpl_vector_unwrap(fov_valid);
00628 cpl_free(_fov_valid);
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639 double zeropoint = -2.5 * log10(5. * (3.34e4 * aWlenMin * aWlenMax / 3631.));
00640 double abmaglimit = -2.5 * log10(2. * sdev / kMuseFluxUnitFactor) + zeropoint;
00641 #else
00642
00643
00644
00645 const double hstep = 0.1 * sigma;
00646 double hmin = cpl_image_get_min(fov_smooth);
00647 double hmax = cpl_image_get_max(fov_smooth);
00648
00649 cpl_size nbins = (hmax - hmin) / hstep + 1;
00650 cpl_vector *bins = cpl_vector_new(nbins);
00651
00652
00653
00654 cpl_size ibin;
00655 for (ibin = 0; ibin < nbins; ++ ibin) {
00656 cpl_vector_set(bins, ibin, hmin + (ibin + 0.5) * hstep);
00657 }
00658
00659 cpl_vector *histogram = cpl_vector_new(nbins);
00660 cpl_vector_fill(histogram, 0.);
00661 double *hdata = cpl_vector_get_data(histogram);
00662
00663 const double *_fov_smooth = cpl_image_get_data_double_const(fov_smooth);
00664
00665 for (ipixel = 0; ipixel < npixel; ++ipixel) {
00666 if ((_fov_mask[ipixel] == CPL_BINARY_0) &&
00667 (_fov_smooth[ipixel] >= hmin) && (_fov_smooth[ipixel] <= hmax)) {
00668 cpl_size jbin = (cpl_size)((_fov_smooth[ipixel] + fabs(hmin)) / hstep);
00669 hdata[jbin] += 1.;
00670 }
00671 }
00672
00673 cpl_mask_delete(fov_mask);
00674 cpl_image_delete(fov_smooth);
00675
00676
00677 double center = 0.;
00678 double sdev = 0.;
00679 double area = 0.;
00680 double bckgrnd = 0.;
00681
00682 cpl_fit_mode mode = CPL_FIT_CENTROID | CPL_FIT_STDEV | CPL_FIT_AREA;
00683 cpl_errorstate status = cpl_errorstate_get();
00684 cpl_error_code ecode = cpl_vector_fit_gaussian(bins, NULL, histogram, NULL,
00685 mode,
00686 ¢er, &sdev, &area, &bckgrnd,
00687 NULL, NULL, NULL);
00688 cpl_vector_delete(histogram);
00689 cpl_vector_delete(bins);
00690
00691 double abmaglimit = 0.;
00692 if (!cpl_errorstate_is_equal(status) && (ecode != CPL_ERROR_CONTINUE)) {
00693 cpl_msg_debug(__func__, "Fit of a Gaussian to the histogram peak failed!");
00694 cpl_errorstate_set(status);
00695 } else {
00696 if (ecode == CPL_ERROR_CONTINUE) {
00697 cpl_msg_debug(__func__, "Fit of a Gaussian to the histogram peak did "
00698 "not converge!");
00699 cpl_errorstate_set(status);
00700 }
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711 double zeropoint = -2.5 *
00712 log10(5. * (3.34e4 * aWlenMin * aWlenMax / 3631.));
00713 abmaglimit = -2.5 * log10(2. * sdev / kMuseFluxUnitFactor) + zeropoint;
00714 }
00715 #endif
00716
00717 return abmaglimit;
00718 }
00719
00720
00721
00722 muse_idp_properties *
00723 muse_idp_properties_new(void) {
00724 muse_idp_properties *properties = cpl_calloc(1, sizeof *properties);
00725 return properties;
00726 }
00727
00728 void
00729 muse_idp_properties_delete(muse_idp_properties *aProperties)
00730 {
00731 if (aProperties) {
00732 cpl_array_delete(aProperties->obid);
00733 cpl_array_delete(aProperties->progid);
00734 cpl_propertylist_delete(aProperties->prov);
00735 cpl_array_delete(aProperties->asson);
00736
00737
00738
00739 cpl_array_delete(aProperties->assoc);
00740 cpl_free((char *)aProperties->prodcatg);
00741 cpl_free((char *)aProperties->procsoft);
00742 cpl_free((char *)aProperties->obstech);
00743 cpl_free((char *)aProperties->referenc);
00744 }
00745 cpl_free(aProperties);
00746 return;
00747 }
00748
00749
00750 muse_idp_properties *
00751 muse_idp_properties_collect(muse_processing *aProcessing,
00752 const muse_datacube *aCube,
00753 const char *aTag)
00754 {
00755 cpl_ensure(aProcessing, CPL_ERROR_NULL_INPUT, NULL);
00756 cpl_table *exposures = muse_processing_sort_exposures(aProcessing);
00757 cpl_ensure(exposures, CPL_ERROR_DATA_NOT_FOUND, NULL);
00758 cpl_size nexposures = cpl_table_get_nrow(exposures);
00759
00760 muse_idp_properties *properties = muse_idp_properties_new();
00761 properties->obid = cpl_array_new(nexposures, CPL_TYPE_LONG);
00762 properties->progid = cpl_array_new(nexposures, CPL_TYPE_STRING);
00763 properties->prov = cpl_propertylist_new();
00764 properties->fluxcal = CPL_TRUE;
00765 properties->wlerror = 0.026;
00766
00767
00768
00769 cpl_errorstate status = cpl_errorstate_get();
00770
00771 cpl_size kexposure = 0;
00772 cpl_size iexposure;
00773 double fwhmmin = DBL_MAX;
00774 double fwhmmax = -DBL_MAX;
00775
00776 for (iexposure = 0; iexposure < nexposures; ++iexposure) {
00777 const char *filename = NULL;
00778 if (cpl_table_has_column(exposures, "00")) {
00779 filename = cpl_table_get_string(exposures, "00", iexposure);
00780 }
00781 if (!filename) {
00782 int ifu=1;
00783 while (!filename && (ifu <= kMuseNumIFUs)) {
00784 char *column = cpl_sprintf("%02d", ifu);
00785 filename = cpl_table_get_string(exposures, column, iexposure);
00786 cpl_free(column);
00787 ++ifu;
00788 }
00789 }
00790 if (!filename) {
00791 cpl_msg_error(__func__, "No pixel table is available for exposure %"
00792 CPL_SIZE_FORMAT " of %" CPL_SIZE_FORMAT "!",
00793 iexposure + 1, nexposures);
00794 cpl_error_set(__func__, CPL_ERROR_DATA_NOT_FOUND);
00795 break;
00796 } else {
00797
00798 cpl_msg_debug(__func__, "Collecting IDP data from exposure '%s'",
00799 filename);
00800 cpl_propertylist *_header = cpl_propertylist_load(filename, 0);
00801
00802 const char *progid = muse_pfits_get_progid(_header);
00803 long obid = muse_pfits_get_obsid(_header);
00804 double mjd = muse_pfits_get_mjdobs(_header);
00805 double exptime = muse_pfits_get_exptime(_header);
00806 double endtime = mjd + exptime / day2sec;
00807
00808
00809
00810 double npixel = 0.;
00811
00812 cpl_errorstate _status = cpl_errorstate_get();
00813
00814 const char *_insmode = muse_pfits_get_insmode(_header);
00815 if (_insmode) {
00816 if (strncmp(_insmode, "NFM", 3) == 0) {
00817 npixel = (kMuseFovSizeNFM * kMuseFovSizeNFM) /
00818 (kMusePixscaleNFM * kMusePixscaleNFM);
00819 } else {
00820 npixel = (kMuseFovSizeWFM * kMuseFovSizeWFM) /
00821 (kMusePixscaleWFM * kMusePixscaleWFM);
00822 }
00823 }
00824
00825 if (!cpl_errorstate_is_equal(_status)) {
00826 if (cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) {
00827 cpl_msg_debug(__func__, "Keyword \"INS.MODE\" is missing in '%s'!",
00828 filename);
00829 }
00830 cpl_msg_error(__func__, "Cannot determine pixel scales of exposure '%s'",
00831 filename);
00832 break;
00833 }
00834
00835 properties->exptime += exptime * npixel;
00836 properties->texptime += exptime;
00837 properties->mjd_end = CPL_MAX(endtime, properties->mjd_end);
00838
00839
00840
00841 double zstart = muse_pfits_get_airmass_start(_header);
00842 double zend = muse_pfits_get_airmass_end(_header);
00843
00844 _status = cpl_errorstate_get();
00845 double fwhmstart = muse_pfits_get_fwhm_start(_header);
00846 double fwhmend = muse_pfits_get_fwhm_end(_header);
00847
00848 if (!cpl_errorstate_is_equal(_status)) {
00849 cpl_msg_debug(__func__, "Missing or invalid seeing information "
00850 "(\"TEL.AMBI.FWHM.START\", \"TEL.AMBI.FWHM.END\") in "
00851 "exposure '%s'", filename);
00852 cpl_errorstate_set(_status);
00853 }
00854
00855 double iqe = kMuseSkyRes;
00856 double fwhmIA = muse_pfits_get_ia_fwhmlin(_header);
00857
00858 if (cpl_errorstate_is_equal(_status)) {
00859 iqe = muse_idp_compute_iqe(kMuseLambdaRef, fwhmIA,
00860 0.5 * (zstart + zend));
00861 }
00862 else {
00863
00864
00865
00866
00867 cpl_msg_debug(__func__, "Missing or invalid seeing information "
00868 "(\"TEL.IA.FWHMLIN\") in exposure '%s'", filename);
00869 cpl_errorstate_set(_status);
00870 fwhmstart = 0.;
00871 fwhmend = 0.;
00872 }
00873
00874 properties->skyres += exptime * iqe;
00875
00876 fwhmmin = CPL_MIN(fwhmmin, CPL_MIN(fwhmstart, fwhmend));
00877 fwhmmax = CPL_MAX(fwhmmax, CPL_MAX(fwhmstart, fwhmend));
00878
00879
00880 cpl_array_set_long(properties->obid, kexposure, obid);
00881 if (progid) {
00882 cpl_array_set_string(properties->progid, kexposure, progid);
00883 }
00884
00885 if ((muse_pfits_get_fluxcal(_header) == CPL_FALSE) &&
00886 (cpl_frameset_find(aProcessing->usedframes, MUSE_TAG_STD_RESPONSE) == NULL)) {
00887 properties->fluxcal = CPL_FALSE;
00888 }
00889
00890 unsigned int nraw = cpl_propertylist_get_size(properties->prov);
00891 const char *prov = muse_pfits_get_ancestor(_header);
00892 if (!prov) {
00893 prov = muse_pfits_get_arcfile(_header);
00894 if (!prov) {
00895 prov = muse_pfits_get_origfile(_header);
00896 }
00897 }
00898
00899 if (prov) {
00900 char *name = cpl_sprintf("PROV%-u", ++nraw);
00901 cpl_propertylist_append_string(properties->prov, name, prov);
00902 cpl_free(name);
00903 } else {
00904 unsigned int iraw = 1;
00905 prov = muse_pfits_get_raw_filename(_header, iraw);
00906 while (prov) {
00907 char *name = cpl_sprintf("PROV%-u", ++nraw);
00908 cpl_propertylist_append_string(properties->prov, name, prov);
00909 prov = muse_pfits_get_raw_filename(_header, ++iraw);
00910 cpl_free(name);
00911 }
00912 }
00913
00914 cpl_propertylist_delete(_header);
00915 ++kexposure;
00916 }
00917 }
00918 cpl_table_delete(exposures);
00919
00920 if (!cpl_errorstate_is_equal(status)) {
00921 muse_idp_properties_delete(properties);
00922 return NULL;
00923 }
00924
00925 if (kexposure != nexposures) {
00926 cpl_msg_warning(__func__, "Could not collect raw data information of all "
00927 "exposures. Got %" CPL_SIZE_FORMAT " of %" CPL_SIZE_FORMAT
00928 "!", kexposure, nexposures);
00929 }
00930
00931 properties->ncombine = kexposure;
00932 cpl_array_set_size(properties->obid, kexposure);
00933 cpl_array_set_size(properties->progid, kexposure);
00934
00935
00936
00937 cpl_msg_debug(__func__, "Collecting IDP ancillary products information");
00938
00939 cpl_size nframes = cpl_frameset_get_size(aProcessing->outframes);
00940 properties->asson = cpl_array_new(nframes, CPL_TYPE_STRING);
00941
00942 cpl_size iancillary = 0;
00943 cpl_size nptotal = 0;
00944 cpl_size iframe;
00945 for (iframe = 0; iframe < nframes; ++iframe) {
00946 const cpl_frame *frame = cpl_frameset_get_position(aProcessing->outframes,
00947 iframe);
00948 const char *tag = cpl_frame_get_tag(frame);
00949
00950 if (strcmp(tag, MUSE_TAG_IMAGE_FOV) == 0) {
00951 cpl_array_set_string(properties->asson, iancillary,
00952 cpl_frame_get_filename(frame));
00953
00954
00955
00956
00957
00958 muse_image *_fov = muse_fov_load(cpl_frame_get_filename(frame));
00959
00960 if (_fov) {
00961 float *pixels = cpl_image_get_data_float(_fov->data);
00962 cpl_size npix = cpl_image_get_size_x(_fov->data) * cpl_image_get_size_y(_fov->data) ;
00963
00964 cpl_size _nptotal = 0;
00965 cpl_size ipix;
00966 for (ipix = 0; ipix < npix; ++ipix) {
00967 if (isnan(pixels[ipix]) == 0) {
00968 ++_nptotal;
00969 }
00970 }
00971 nptotal = CPL_MAX(nptotal, _nptotal);
00972
00973 muse_image_delete(_fov);
00974 }
00975 ++iancillary;
00976 }
00977 }
00978 cpl_array_set_size(properties->asson, iancillary);
00979
00980
00981
00982
00983
00984 if (nptotal == 0) {
00985 properties->exptime = 0.;
00986 } else {
00987 properties->exptime /= nptotal;
00988 }
00989
00990
00991 properties->skyres /= properties->texptime;
00992 if ((fwhmmin > 0.) && (fwhmmax > 0.)) {
00993 properties->skyrerr = 0.5 * fabs(fwhmmax - fwhmmin);
00994 properties->skyrerr = sqrt(properties->skyrerr * properties->skyrerr +
00995 kMuseExtraErrorIQE * kMuseExtraErrorIQE);
00996 } else {
00997 cpl_msg_warning(__func__, "Got invalid seeing information! Using an "
00998 "estimate for \"SKY_RERR\"!");
00999 properties->skyrerr = kMuseSkyResError;
01000 }
01001
01002
01003
01004
01005 cpl_msg_debug(__func__, "Collecting IDP data from products");
01006
01007 const cpl_propertylist *header = aCube->header;
01008
01009
01010 cpl_wcs *wcs = cpl_wcs_new_from_propertylist(header);
01011 int naxes = cpl_wcs_get_image_naxis(wcs);
01012 const cpl_array *naxis = cpl_wcs_get_image_dims(wcs);
01013
01014 cpl_matrix *position = cpl_matrix_new(2, naxes);
01015 cpl_matrix_fill_column(position, 0.5 * cpl_array_get_int(naxis, 0, NULL), 0);
01016 cpl_matrix_fill_column(position, 0.5 * cpl_array_get_int(naxis, 1, NULL), 1);
01017 cpl_matrix_set(position, 0, 2, 1.);
01018 cpl_matrix_set(position, 1, 2, cpl_array_get_int(naxis, 2, NULL));
01019
01020 cpl_matrix *world;
01021 cpl_array *flags;
01022 cpl_error_code _status = cpl_wcs_convert(wcs, position, &world, &flags,
01023 CPL_WCS_PHYS2WORLD);
01024
01025 cpl_array_delete(flags);
01026 cpl_matrix_delete(position);
01027
01028 if (_status != CPL_ERROR_NONE) {
01029 cpl_matrix_delete(world);
01030 cpl_wcs_delete(wcs);
01031 muse_idp_properties_delete(properties);
01032 return NULL;
01033 }
01034
01035 properties->fovcenter[0] = cpl_matrix_get(world, 0, 0);
01036 properties->fovcenter[1] = cpl_matrix_get(world, 0, 1);
01037
01038
01039
01040 properties->wlenrange[0] = cpl_matrix_get(world, 0, 2) * m2nm;
01041 properties->wlenrange[1] = cpl_matrix_get(world, 1, 2) * m2nm;
01042 cpl_matrix_delete(world);
01043 cpl_wcs_delete(wcs);
01044
01045
01046 const muse_specres_lut_entry *specres_data = muse_specres_data_wfm;
01047
01048 const char *insmode = muse_pfits_get_insmode(header);
01049 if (strncmp(insmode, "NFM", 3) == 0) {
01050 specres_data = muse_specres_data_nfm;
01051 }
01052
01053 double wlencenter = 0.5 * (properties->wlenrange[0] + properties->wlenrange[1]);
01054 properties->specres = muse_idp_compute_specres(wlencenter * nm2Angstrom,
01055 specres_data);
01056
01057
01058
01059
01060 status = cpl_errorstate_get();
01061
01062
01063
01064
01065
01066 double pixnoise = muse_idp_compute_pixnoise(aCube, 0, 25., 0.04);
01067 if (!cpl_errorstate_is_equal(status)) {
01068 double ron = 0.;
01069 double gain = 0.;
01070
01071 unsigned int iquadrant;
01072 for (iquadrant = 1; iquadrant <= kMuseNumQuadrants; ++iquadrant) {
01073 ron += muse_pfits_get_ron(header, iquadrant);
01074 gain += muse_pfits_get_gain(header, iquadrant);
01075 }
01076
01077
01078 properties->pixnoise = ron * gain * pow(10., -0.4 * kMuseResponseRef) /
01079 (double)(kMuseNumQuadrants * kMuseNumQuadrants);
01080 cpl_errorstate_set(status);
01081 } else {
01082 const char *bunit = muse_pfits_get_bunit(header);
01083
01084 properties->pixnoise = sqrt(pixnoise);
01085
01086 if (bunit &&
01087 !strncmp(bunit, kMuseFluxUnitString, strlen(kMuseFluxUnitString) + 1)) {
01088 properties->pixnoise /= kMuseFluxUnitFactor;
01089 } else {
01090 if (!bunit) {
01091 cpl_msg_warning(__func__,
01092 "No BUNIT data units are present in the data cube!");
01093 } else {
01094 cpl_msg_warning(__func__,
01095 "Data cube has unsupported data unit in BUNIT!");
01096 }
01097 cpl_msg_warning(__func__, "No scale factor has been applied to PIXNOISE!");
01098 }
01099 }
01100
01101
01102 double xscale = 0.;
01103 double yscale = 0.;
01104
01105 if (muse_idp_get_scales(header, &xscale, &yscale) == -1) {
01106 cpl_msg_error(__func__, "Cannot determine pixel scales of the data cube");
01107 muse_idp_properties_delete(properties);
01108 return NULL;
01109 }
01110
01111 status = cpl_errorstate_get();
01112 double abmaglimit =
01113 muse_idp_compute_abmaglimit(aCube,
01114 properties->wlenrange[0] * nm2Angstrom,
01115 properties->wlenrange[1] * nm2Angstrom,
01116 properties->skyres / CPL_MAX(xscale, yscale));
01117 if (!cpl_errorstate_is_equal(status)) {
01118 properties->abmaglimit = -99.;
01119 cpl_errorstate_set(status);
01120 } else {
01121 properties->abmaglimit = abmaglimit;
01122 }
01123
01124
01125
01126 if (!aTag) {
01127 aTag = muse_pfits_get_pro_catg(header);
01128 }
01129 if (!aTag || (strcmp(aTag, MUSE_TAG_CUBE_FINAL) != 0)) {
01130 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
01131 muse_idp_properties_delete(properties);
01132 return NULL;
01133 } else {
01134 properties->prodcatg = cpl_strdup(KEY_PRODCATG_VALUE_IFS_CUBE);
01135 }
01136
01137
01138 unsigned int recid = 0;
01139 const char *procsoft = NULL;
01140 const char *pipeid;
01141 while ((pipeid = muse_pfits_get_pipe_id(header, ++recid)) != NULL) {
01142 procsoft = pipeid;
01143 }
01144
01145 if (!procsoft) {
01146 properties->procsoft = cpl_strdup(PACKAGE "/" PACKAGE_VERSION);
01147 } else {
01148 properties->procsoft = cpl_strdup(procsoft);
01149 }
01150
01151
01152
01153 properties->obstech = cpl_strdup("IFU");
01154 properties->referenc = NULL;
01155
01156 return properties;
01157 }
01158
01159 cpl_error_code
01160 muse_idp_properties_update(cpl_propertylist *aHeader,
01161 const muse_idp_properties *aProperties)
01162 {
01163 cpl_ensure(aHeader && aProperties, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
01164 cpl_ensure(cpl_array_get_size(aProperties->obid) == aProperties->ncombine,
01165 CPL_ERROR_ILLEGAL_INPUT, CPL_ERROR_ILLEGAL_INPUT);
01166 cpl_ensure(cpl_array_get_size(aProperties->progid) == aProperties->ncombine,
01167 CPL_ERROR_ILLEGAL_INPUT, CPL_ERROR_ILLEGAL_INPUT);
01168 cpl_ensure(cpl_propertylist_get_size(aProperties->prov) >= aProperties->ncombine,
01169 CPL_ERROR_ILLEGAL_INPUT, CPL_ERROR_ILLEGAL_INPUT);
01170
01171 cpl_propertylist_erase_regexp(aHeader, CLEAN_KEYS_REGEXP, 0);
01172
01173 cpl_propertylist_update_double(aHeader, KEY_RA, aProperties->fovcenter[0]);
01174 cpl_propertylist_set_comment(aHeader, KEY_RA, KEY_RA_COMMENT);
01175 cpl_propertylist_update_double(aHeader, KEY_DEC, aProperties->fovcenter[1]);
01176 cpl_propertylist_set_comment(aHeader, KEY_DEC, KEY_DEC_COMMENT);
01177 cpl_propertylist_update_double(aHeader, KEY_EXPTIME, aProperties->exptime);
01178 cpl_propertylist_set_comment(aHeader, KEY_EXPTIME, KEY_EXPTIME_COMMENT);
01179 cpl_propertylist_insert_after_double(aHeader, KEY_EXPTIME,
01180 KEY_TEXPTIME, aProperties->texptime);
01181 cpl_propertylist_set_comment(aHeader, KEY_TEXPTIME, KEY_TEXPTIME_COMMENT);
01182
01183 cpl_propertylist_insert_after_int(aHeader, KEY_TEXPTIME,
01184 KEY_NCOMBINE, aProperties->ncombine);
01185 cpl_propertylist_set_comment(aHeader, KEY_NCOMBINE, KEY_NCOMBINE_COMMENT);
01186
01187 cpl_propertylist_set_comment(aHeader, KEY_MJDOBS, KEY_MJDOBS_COMMENT);
01188 cpl_propertylist_insert_after_double(aHeader, KEY_MJDOBS,
01189 KEY_MJDEND, aProperties->mjd_end);
01190 cpl_propertylist_set_comment(aHeader, KEY_MJDEND, KEY_MJDEND_COMMENT);
01191
01192 cpl_array *obids = cpl_array_duplicate(aProperties->obid);
01193 muse_cplarray_sort(obids, CPL_TRUE);
01194
01195
01196 long obid = cpl_array_get_long(obids, 0, NULL);
01197 cpl_propertylist_update_long(aHeader, KEY_OBID "1", obid);
01198 cpl_propertylist_set_comment(aHeader, KEY_OBID "1", KEY_OBID_COMMENT);
01199
01200 if (aProperties->ncombine > 1) {
01201 unsigned int ik = 1;
01202 cpl_size idx;
01203 for (idx = 1; idx < aProperties->ncombine; ++idx) {
01204 long _obid = cpl_array_get_long(aProperties->obid, idx, NULL);
01205 if (obid != _obid) {
01206 char *key = cpl_sprintf(KEY_OBID "%-u", ++ik);
01207 cpl_propertylist_update_long(aHeader, key, _obid);
01208 cpl_propertylist_set_comment(aHeader, key, KEY_OBID_COMMENT);
01209 cpl_free(key);
01210 obid = _obid;
01211 }
01212 }
01213 }
01214 cpl_array_delete(obids);
01215
01216
01217
01218
01219 cpl_array *progids = cpl_array_duplicate(aProperties->progid);
01220 muse_cplarray_sort(progids, CPL_TRUE);
01221 const char *progid = cpl_array_get_string(progids, 0);
01222
01223 if (aProperties->ncombine > 1) {
01224 unsigned int nprogid = 1;
01225 cpl_size idx;
01226 for (idx = 1; idx < aProperties->ncombine; ++idx) {
01227 const char *_progid = cpl_array_get_string(aProperties->progid, idx);
01228 if (strcmp(progid, _progid) != 0) {
01229 progid = _progid;
01230 ++nprogid;
01231 }
01232 }
01233
01234 progid = cpl_array_get_string(progids, 0);
01235 if (nprogid == 1) {
01236 cpl_propertylist_update_string(aHeader, KEY_PROG_ID, progid);
01237 } else {
01238 cpl_propertylist_update_string(aHeader, KEY_PROG_ID,
01239 KEY_PROG_ID_VALUE_MULTIPLE);
01240 cpl_propertylist_update_string(aHeader, KEY_PROGID "1", progid);
01241 cpl_propertylist_set_comment(aHeader, KEY_PROGID "1", KEY_PROGID_COMMENT);
01242
01243 unsigned int ik = 1;
01244 for (idx = 1; idx < aProperties->ncombine; ++idx) {
01245 const char *_progid = cpl_array_get_string(aProperties->progid, idx);
01246 if (strcmp(progid, _progid) != 0) {
01247 char *key = cpl_sprintf(KEY_PROGID "%-u", ++ik);
01248 cpl_propertylist_update_string(aHeader, key, _progid);
01249 cpl_propertylist_set_comment(aHeader, key, KEY_PROGID_COMMENT);
01250 cpl_free(key);
01251 progid = _progid;
01252 }
01253 }
01254 }
01255 cpl_propertylist_set_comment(aHeader, KEY_PROG_ID, KEY_PROG_ID_COMMENT);
01256
01257 } else {
01258 cpl_propertylist_update_string(aHeader, KEY_PROG_ID, progid);
01259 cpl_propertylist_set_comment(aHeader, KEY_PROG_ID, KEY_PROG_ID_COMMENT);
01260 }
01261 cpl_array_delete(progids);
01262
01263
01264 cpl_propertylist_append(aHeader, aProperties->prov);
01265
01266
01267 cpl_size idx;
01268 for (idx = 0; idx < cpl_array_get_size(aProperties->asson); ++idx) {
01269 char *name = cpl_sprintf(KEY_ASSON "%-" CPL_SIZE_FORMAT, idx + 1);
01270 cpl_propertylist_update_string(aHeader, name,
01271 cpl_array_get_string(aProperties->asson, idx));
01272 cpl_free(name);
01273 }
01274
01275 cpl_propertylist_update_string(aHeader, KEY_PRODCATG, aProperties->prodcatg);
01276 cpl_propertylist_set_comment(aHeader, KEY_PRODCATG, KEY_PRODCATG_COMMENT);
01277
01278 cpl_propertylist_update_string(aHeader, KEY_PROCSOFT, aProperties->procsoft);
01279 cpl_propertylist_set_comment(aHeader, KEY_PROCSOFT, KEY_PROCSOFT_COMMENT);
01280
01281 cpl_propertylist_update_string(aHeader, KEY_OBSTECH, aProperties->obstech);
01282 cpl_propertylist_set_comment(aHeader, KEY_OBSTECH, KEY_OBSTECH_COMMENT);
01283
01284 const char *fluxcal = KEY_FLUXCAL_VALUE_TRUE;
01285 if (aProperties->fluxcal == CPL_FALSE) {
01286 fluxcal = KEY_FLUXCAL_VALUE_FALSE;
01287 }
01288 cpl_propertylist_update_string(aHeader, KEY_FLUXCAL, fluxcal);
01289 cpl_propertylist_set_comment(aHeader, KEY_FLUXCAL, KEY_FLUXCAL_COMMENT);
01290
01291 cpl_propertylist_insert_after_double(aHeader, KEY_FLUXCAL, KEY_WAVELMIN,
01292 aProperties->wlenrange[0]);
01293 cpl_propertylist_set_comment(aHeader, KEY_WAVELMIN, KEY_WAVELMIN_COMMENT);
01294 cpl_propertylist_insert_after_double(aHeader, KEY_WAVELMIN, KEY_WAVELMAX,
01295 aProperties->wlenrange[1]);
01296 cpl_propertylist_set_comment(aHeader, KEY_WAVELMAX, KEY_WAVELMAX_COMMENT);
01297 cpl_propertylist_insert_after_double(aHeader, KEY_WAVELMAX, KEY_SPEC_RES,
01298 aProperties->specres);
01299 cpl_propertylist_set_comment(aHeader, KEY_SPEC_RES, KEY_SPEC_RES_COMMENT);
01300 cpl_propertylist_insert_after_double(aHeader, KEY_SPEC_RES, KEY_SKY_RES,
01301 aProperties->skyres);
01302 cpl_propertylist_set_comment(aHeader, KEY_SKY_RES, KEY_SKY_RES_COMMENT);
01303 cpl_propertylist_insert_after_double(aHeader, KEY_SKY_RES, KEY_SKY_RERR,
01304 aProperties->skyrerr);
01305 cpl_propertylist_set_comment(aHeader, KEY_SKY_RERR, KEY_SKY_RERR_COMMENT);
01306 cpl_propertylist_insert_after_double(aHeader, KEY_SKY_RERR, KEY_PIXNOISE,
01307 aProperties->pixnoise);
01308 cpl_propertylist_set_comment(aHeader, KEY_PIXNOISE, KEY_PIXNOISE_COMMENT);
01309 cpl_propertylist_insert_after_double(aHeader, KEY_PIXNOISE, KEY_ABMAGLIM,
01310 aProperties->abmaglimit);
01311 cpl_propertylist_set_comment(aHeader, KEY_ABMAGLIM, KEY_ABMAGLIM_COMMENT);
01312
01313 const char *reference = "";
01314 if (aProperties->referenc) {
01315 reference = aProperties->referenc;
01316 }
01317 cpl_propertylist_update_string(aHeader, KEY_REFERENC, reference);
01318 cpl_propertylist_set_comment(aHeader, KEY_REFERENC, KEY_REFERENC_COMMENT);
01319
01320 cpl_propertylist_insert_after_double(aHeader, "CRVAL3", KEY_SPEC_ERR,
01321 aProperties->wlerror);
01322 cpl_propertylist_set_comment(aHeader, KEY_SPEC_ERR, KEY_SPEC_ERR_COMMENT);
01323
01324
01325
01326 if (!cpl_propertylist_has(aHeader, "CSYER1")) {
01327 cpl_propertylist_update_double(aHeader, "CSYER1", -1.);
01328 cpl_propertylist_set_comment(aHeader, "CSYER1",
01329 "[deg] Systematic error in coordinate");
01330 }
01331 if (!cpl_propertylist_has(aHeader, "CSYER2")) {
01332 cpl_propertylist_update_double(aHeader, "CSYER2", -1.);
01333 cpl_propertylist_set_comment(aHeader, "CSYER2",
01334 "[deg] Systematic error in coordinate");
01335 }
01336
01337 return CPL_ERROR_NONE;
01338 }
01339
01340 cpl_error_code
01341 muse_idp_properties_update_fov(muse_image *aFov)
01342 {
01343 cpl_error_code status = CPL_ERROR_NONE;
01344
01345 cpl_ensure(aFov, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
01346 cpl_ensure(aFov->header, CPL_ERROR_ILLEGAL_INPUT, CPL_ERROR_ILLEGAL_INPUT);
01347
01348 status = cpl_propertylist_update_string(aFov->header, KEY_PRODCATG,
01349 KEY_PRODCATG_VALUE_FOV_IMAGE);
01350 cpl_propertylist_set_comment(aFov->header, KEY_PRODCATG, KEY_PRODCATG_COMMENT);
01351
01352 return status;
01353 }
01354