00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026
00027
00028
00029
00030 #include <string.h>
00031 #include <math.h>
00032
00033 #include <muse.h>
00034 #include <muse_data_format_z.h>
00035 #include <muse_instrument.h>
00036 #include <muse_lsf.h>
00037 #include "muse_lsf_z.h"
00038
00039 #ifndef USE_LSF_PARAMS
00040 #ifdef MUSE_LSF_PARAM_METHOD_HERMIT
00041 #error Please remove the "method" parameter from muse_lsf_params.xml
00042 #endif
00043 #endif
00044
00045
00046
00047
00048
00057 static muse_lsf_cube *
00058 muse_lsf_compute_slices(muse_pixtable *aPixtable, muse_lsf_params_t *aParams)
00059 {
00060 cpl_ensure(aPixtable, CPL_ERROR_NULL_INPUT, NULL);
00061 muse_lsf_cube *lsfCube = muse_lsf_cube_new(aParams->lsf_range,
00062 aParams->lsf_size,
00063 aParams->lambda_size,
00064 aPixtable->header);
00065 muse_pixtable **slice_pixtable = muse_pixtable_extracted_get_slices(aPixtable);
00066
00067 int i_slice, n_slices = muse_pixtable_extracted_get_size(slice_pixtable);
00068 #pragma omp parallel for default(none) \
00069 shared(lsfCube, n_slices, slice_pixtable, aParams)
00070 for (i_slice = 0; i_slice < n_slices; i_slice++) {
00071 cpl_image *img = cpl_imagelist_get(lsfCube->img, i_slice);
00072 muse_lsf_fit_slice(slice_pixtable[i_slice], img,
00073 lsfCube->wcs, aParams->lsf_regression_window);
00074 }
00075 muse_pixtable_extracted_delete(slice_pixtable);
00076 return lsfCube;
00077 }
00078
00088 static cpl_error_code
00089 muse_lsf_subtract_arcs(muse_lsf_cube *aLsfCube, cpl_table *aPixtable) {
00090 cpl_size n_rows = cpl_table_get_nrow(aPixtable);
00091 cpl_size i_row;
00092 for (i_row = 0; i_row < n_rows; i_row++) {
00093 uint32_t origin = (uint32_t)cpl_table_get_int(aPixtable, MUSE_PIXTABLE_ORIGIN,
00094 i_row, NULL);
00095 int i_slice = muse_pixtable_origin_get_slice(origin);
00096 double lambda = cpl_table_get(aPixtable, "line_lambda", i_row, NULL);
00097 double flux = cpl_table_get(aPixtable, "line_flux", i_row, NULL);
00098 double v = cpl_table_get(aPixtable, MUSE_PIXTABLE_LAMBDA, i_row, NULL)
00099 - lambda;
00100 cpl_array *val = cpl_array_wrap_double(&v, 1);
00101 muse_lsf_apply(cpl_imagelist_get(aLsfCube->img, i_slice - 1),
00102 aLsfCube->wcs, val, lambda);
00103 cpl_array_unwrap(val);
00104 cpl_table_set(aPixtable, MUSE_PIXTABLE_DATA, i_row,
00105 cpl_table_get(aPixtable, MUSE_PIXTABLE_DATA, i_row, NULL)
00106 - v * flux);
00107 }
00108 return CPL_ERROR_NONE;
00109 }
00110
00126 static cpl_error_code
00127 muse_lsf_qc(muse_lsf_cube *aLsfCube)
00128 {
00129 cpl_ensure_code(aLsfCube, CPL_ERROR_NULL_INPUT);
00130
00131 cpl_size i_slice, n_slices = cpl_imagelist_get_size(aLsfCube->img);
00132 for (i_slice = 0; i_slice < n_slices; i_slice++) {
00133 cpl_image *img = cpl_imagelist_get(aLsfCube->img, i_slice);
00134 cpl_size n_lsf = cpl_image_get_size_x(img);
00135 cpl_size n_lambda = cpl_image_get_size_y(img);
00136 cpl_array *fwhm = cpl_array_new(n_lambda, CPL_TYPE_DOUBLE);
00137 cpl_size i_lambda;
00138 for (i_lambda = 0; i_lambda < n_lambda; i_lambda++) {
00139 int res;
00140 double ref = cpl_image_get(img, n_lsf/2, i_lambda+1, &res);
00141 cpl_size i_min;
00142 for (i_min = n_lsf/2; i_min > 0; i_min--) {
00143 if (cpl_image_get(img, i_min, i_lambda+1, &res) < ref/2) {
00144 break;
00145 }
00146 }
00147 double f_min = (ref/2 - cpl_image_get(img, i_min, i_lambda+1, &res))
00148 / (cpl_image_get(img, i_min+1, i_lambda+1, &res)
00149 - cpl_image_get(img, i_min, i_lambda+1, &res));
00150
00151 cpl_size i_max;
00152 for (i_max = n_lsf/2; i_max <= n_lsf; i_max++) {
00153 if (cpl_image_get(img, i_max, i_lambda+1, &res) < ref/2) {
00154 break;
00155 }
00156 }
00157 double f_max = (ref/2 - cpl_image_get(img, i_max, i_lambda+1, &res))
00158 / (cpl_image_get(img, i_max-1, i_lambda+1, &res)
00159 - cpl_image_get(img, i_max, i_lambda+1, &res));
00160
00161 double f = (i_max - f_max - i_min - f_min) * aLsfCube->wcs->cd11;
00162 cpl_array_set(fwhm, i_lambda, f);
00163 }
00164 char keyword[KEYWORD_LENGTH];
00165 snprintf(keyword, KEYWORD_LENGTH, "ESO QC LSF SLICE%i FWHM MEAN",
00166 (int)i_slice+1);
00167 cpl_propertylist_append_float(aLsfCube->header, keyword, cpl_array_get_mean(fwhm));
00168 snprintf(keyword, KEYWORD_LENGTH, "ESO QC LSF SLICE%i FWHM STDEV",
00169 (int)i_slice+1);
00170 cpl_propertylist_append_float(aLsfCube->header, keyword, cpl_array_get_stdev(fwhm));
00171 snprintf(keyword, KEYWORD_LENGTH, "ESO QC LSF SLICE%i FWHM MIN",
00172 (int)i_slice+1);
00173 cpl_propertylist_append_float(aLsfCube->header, keyword, cpl_array_get_min(fwhm));
00174 snprintf(keyword, KEYWORD_LENGTH, "ESO QC LSF SLICE%i FWHM MAX",
00175 (int)i_slice+1);
00176 cpl_propertylist_append_float(aLsfCube->header, keyword, cpl_array_get_max(fwhm));
00177 cpl_array_delete(fwhm);
00178 }
00179
00180 return CPL_ERROR_NONE;
00181 }
00182
00183 #ifdef USE_LSF_PARAMS
00184 muse_lsf_params **
00185 muse_lsf_params_compute(cpl_table *aLines,
00186 muse_pixtable *aPixtable,
00187 int max_iterations)
00188 {
00189 muse_pixtable **slice_pixtable = muse_pixtable_extracted_get_slices(aPixtable);
00190 int n_slices = muse_pixtable_extracted_get_size(slice_pixtable);
00191 int i_slice;
00192
00193 muse_lsf_params **lsfParams
00194 = cpl_calloc(n_slices+1, sizeof(muse_lsf_params *));
00195 #pragma omp parallel for default(none) num_threads(2) \
00196 shared(aLines, n_slices, i_slice, lsfParams, slice_pixtable, \
00197 max_iterations)
00198 for (i_slice = 0; i_slice < n_slices; i_slice++) {
00199 uint32_t origin
00200 = (uint32_t)cpl_table_get_int(slice_pixtable[i_slice]->table,
00201 MUSE_PIXTABLE_ORIGIN, 0, NULL);
00202 unsigned short ifu = muse_pixtable_origin_get_ifu(origin);
00203 unsigned short slice = muse_pixtable_origin_get_slice(origin);
00204
00205 cpl_errorstate prestate = cpl_errorstate_get();
00206 lsfParams[i_slice]
00207 = muse_lsf_params_fit(slice_pixtable[i_slice], aLines, max_iterations);
00208 if (!cpl_errorstate_is_equal(prestate)) {
00209 cpl_msg_error(__func__, "While processing slice %hu.%hu:", ifu, slice);
00210 cpl_errorstate_dump(prestate, CPL_FALSE, NULL);
00211 cpl_errorstate_set(prestate);
00212 }
00213 }
00214 muse_pixtable_extracted_delete(slice_pixtable);
00215 return lsfParams;
00216 }
00217
00218
00224
00225 static cpl_error_code
00226 muse_lsf_params_qc(cpl_propertylist *aHeader, const muse_lsf_params **aSlicePars)
00227 {
00228 cpl_ensure_code(aHeader != NULL, CPL_ERROR_NULL_INPUT);
00229 cpl_ensure_code(aSlicePars != NULL, CPL_ERROR_NULL_INPUT);
00230
00231 const muse_lsf_params **det;
00232 for (det = aSlicePars; *det != NULL; det++) {
00233 cpl_size n_lambda = 30;
00234 double lambda_step = (kMuseNominalLambdaMax - kMuseNominalLambdaMin)
00235 / (n_lambda - 1);
00236 cpl_array *fwhm = cpl_array_new(n_lambda, CPL_TYPE_DOUBLE);
00237 cpl_size i_lambda;
00238 for (i_lambda = 0; i_lambda < n_lambda; i_lambda++) {
00239 double lambda = kMuseNominalLambdaMin + i_lambda * lambda_step;
00240 double f = muse_lsf_fwhm_lambda(*det, lambda, 0.04, 150);
00241 cpl_array_set(fwhm, i_lambda, f);
00242 }
00243 char keyword[KEYWORD_LENGTH];
00244 snprintf(keyword, KEYWORD_LENGTH, "ESO QC LSF SLICE%i FWHM MEAN",
00245 (int)(*det)->slice);
00246 cpl_propertylist_append_float(aHeader, keyword, cpl_array_get_mean(fwhm));
00247 snprintf(keyword, KEYWORD_LENGTH, "ESO QC LSF SLICE%i FWHM STDEV",
00248 (int)(*det)->slice);
00249 cpl_propertylist_append_float(aHeader, keyword, cpl_array_get_stdev(fwhm));
00250 snprintf(keyword, KEYWORD_LENGTH, "ESO QC LSF SLICE%i FWHM MIN",
00251 (int)(*det)->slice);
00252 cpl_propertylist_append_float(aHeader, keyword, cpl_array_get_min(fwhm));
00253 snprintf(keyword, KEYWORD_LENGTH, "ESO QC LSF SLICE%i FWHM MAX",
00254 (int)(*det)->slice);
00255 cpl_propertylist_append_float(aHeader, keyword, cpl_array_get_max(fwhm));
00256 cpl_array_delete(fwhm);
00257 }
00258
00259 return CPL_ERROR_NONE;
00260 }
00261
00262 static cpl_error_code
00263 muse_lsf_params_save_table(cpl_propertylist *aHeader,
00264 const muse_lsf_params **aSlicePars,
00265 muse_processing *aProcessing, int aIFU)
00266 {
00267 cpl_error_code r = CPL_ERROR_NONE;
00268 if (aSlicePars != NULL) {
00269 cpl_frame *frame
00270 = muse_processing_new_frame(aProcessing, aIFU, aHeader,
00271 "LSF_PROFILE", CPL_FRAME_TYPE_TABLE);
00272 if (frame != NULL) {
00273 const char *filename = cpl_frame_get_filename(frame);
00274 cpl_msg_info(__func__, "Saving LSF table as %s", filename);
00275 char *channel = cpl_sprintf("CHAN%02d", aIFU);
00276 cpl_propertylist_update_string(aHeader, "EXTNAME", channel);
00277 cpl_free(channel);
00278 r = cpl_propertylist_save(aHeader, filename, CPL_IO_CREATE);
00279 r = muse_lsf_params_save(aSlicePars, filename);
00280 if (r == CPL_ERROR_NONE) {
00281 #pragma omp critical(muse_processing_output_frames)
00282 cpl_frameset_insert(aProcessing->outframes, frame);
00283 } else {
00284 cpl_frame_delete(frame);
00285 }
00286 }
00287 }
00288 return r;
00289 }
00290 #endif // defined(USE_LSF_PARAMS)
00291
00292
00299
00300 int
00301 muse_lsf_compute(muse_processing *aProcessing, muse_lsf_params_t *aParams)
00302 {
00303 muse_basicproc_params *bpars = muse_basicproc_params_new(aProcessing->parameters,
00304 "muse.muse_lsf");
00305 muse_imagelist *images = muse_basicproc_combine_images_lampwise(aProcessing,
00306 aParams->nifu,
00307 bpars, NULL);
00308 muse_basicproc_params_delete(bpars);
00309 cpl_ensure(images, cpl_error_get_code(), -1);
00310
00311 cpl_table *arclines = muse_table_load(aProcessing, MUSE_TAG_LINE_CATALOG, 0);
00312 cpl_table *tracetable = muse_table_load(aProcessing, MUSE_TAG_TRACE_TABLE,
00313 aParams->nifu);
00314 cpl_table *wavecaltable = muse_table_load(aProcessing, MUSE_TAG_WAVECAL_TABLE,
00315 aParams->nifu);
00316 if (!arclines || !tracetable || !wavecaltable) {
00317 cpl_msg_error(__func__, "Calibration could not be loaded:%s%s%s",
00318 !arclines ? " " : "",
00319 !tracetable ? " "MUSE_TAG_TRACE_TABLE : "",
00320 !wavecaltable ? " "MUSE_TAG_WAVECAL_TABLE : "");
00321 muse_imagelist_delete(images);
00322 cpl_table_delete(arclines);
00323 cpl_table_delete(tracetable);
00324 cpl_table_delete(wavecaltable);
00325 return -1;
00326 }
00327
00328
00329 cpl_errorstate prestate = cpl_errorstate_get();
00330
00331 if (aParams->method == MUSE_LSF_PARAM_METHOD_INTERPOLATE) {
00332
00333 muse_pixtable *arcpixtable = muse_lsf_create_arcpixtable(
00334 images, tracetable, wavecaltable, arclines,
00335 aParams->line_quality,
00336 aParams->lsf_range + aParams->lsf_regression_window);
00337
00338 cpl_table_delete(arclines);
00339 cpl_table_delete(tracetable);
00340 cpl_table_delete(wavecaltable);
00341 muse_imagelist_delete(images);
00342 if (arcpixtable == NULL) {
00343 cpl_msg_error(__func__, "Could not create pixel table of arc lines for "
00344 "IFU %d", aParams->nifu);
00345 return -1;
00346 }
00347
00348 muse_lsf_cube *lsfcube = muse_lsf_compute_slices(arcpixtable, aParams);
00349 if (lsfcube == NULL) {
00350 cpl_msg_error(__func__, "Could not create LSF cube for IFU %d",
00351 aParams->nifu);
00352 if (aParams->save_subtracted) {
00353 muse_processing_save_table(aProcessing, aParams->nifu, arcpixtable, NULL,
00354 MUSE_TAG_PT_SUB, MUSE_TABLE_TYPE_PIXTABLE);
00355 }
00356 muse_pixtable_delete(arcpixtable);
00357 return -1;
00358 }
00359
00360
00361 muse_lsf_qc(lsfcube);
00362 muse_processing_save_cube(aProcessing, aParams->nifu, lsfcube,
00363 MUSE_TAG_LSF_PROFILE, MUSE_CUBE_TYPE_LSF);
00364 if (aParams->save_subtracted) {
00365 cpl_table_duplicate_column(arcpixtable->table, "orig", arcpixtable->table,
00366 MUSE_PIXTABLE_DATA);
00367 muse_lsf_subtract_arcs(lsfcube, arcpixtable->table);
00368 muse_processing_save_table(aProcessing, aParams->nifu, arcpixtable, NULL,
00369 MUSE_TAG_PT_SUB, MUSE_TABLE_TYPE_PIXTABLE);
00370 }
00371 muse_pixtable_delete(arcpixtable);
00372 muse_lsf_cube_delete(lsfcube);
00373
00374 }
00375 #ifdef USE_LSF_PARAMS
00376 else if (aParams->method == MUSE_LSF_PARAM_METHOD_HERMIT) {
00377 muse_combinepar *cpars = muse_combinepar_new(aProcessing->parameters,
00378 "muse.muse_lsf");
00379 muse_image *masterimage = muse_combine_images(cpars, images);
00380 muse_combinepar_delete(cpars);
00381 muse_imagelist_delete(images);
00382
00383 muse_pixtable *arcpixtable = muse_pixtable_create(masterimage, tracetable,
00384 wavecaltable, NULL);
00385 cpl_table_delete(tracetable);
00386 cpl_table_delete(wavecaltable);
00387 if (!arcpixtable) {
00388 cpl_msg_error(__func__, "ARC pixel table creation failed");
00389 cpl_table_delete(arclines);
00390 muse_image_delete(masterimage);
00391 return -1;
00392 }
00393
00394
00395 cpl_table_unselect_all(arclines);
00396 cpl_table_or_selected_int(arclines, MUSE_LINE_CATALOG_QUALITY,
00397 CPL_LESS_THAN, aParams->line_quality);
00398 cpl_table_or_selected_float(arclines, "flux", CPL_NOT_GREATER_THAN, 0.);
00399 cpl_table_erase_selected(arclines);
00400
00401 cpl_propertylist *flux_sort = cpl_propertylist_new();
00402 cpl_propertylist_append_bool(flux_sort, "flux", CPL_TRUE);
00403 cpl_table_sort(arclines, flux_sort);
00404 cpl_propertylist_delete(flux_sort);
00405 cpl_size nrows = 40;
00406 if (nrows < cpl_table_get_nrow(arclines)) {
00407 cpl_table_erase_window(arclines, nrows, cpl_table_get_nrow(arclines));
00408 }
00409
00410 if (aParams->save_subtracted) {
00411 cpl_table_duplicate_column(arcpixtable->table, "orig", arcpixtable->table,
00412 MUSE_PIXTABLE_DATA);
00413 }
00414 muse_lsf_params **lsf = muse_lsf_params_compute(arclines, arcpixtable, 40);
00415
00416 cpl_propertylist *qc_header = cpl_propertylist_new();
00417 muse_lsf_params_qc(qc_header, (const muse_lsf_params **)lsf);
00418 muse_lsf_params_save_table(qc_header, (const muse_lsf_params **)lsf,
00419 aProcessing, aParams->nifu);
00420 muse_lsf_params_delete_all(lsf);
00421 cpl_propertylist_delete(qc_header);
00422
00423 if (aParams->save_subtracted) {
00424 muse_processing_save_table(aProcessing, aParams->nifu, arcpixtable, NULL,
00425 MUSE_TAG_PT_SUB, MUSE_TABLE_TYPE_PIXTABLE);
00426 }
00427
00428 muse_pixtable_delete(arcpixtable);
00429 cpl_table_delete(arclines);
00430 muse_image_delete(masterimage);
00431 }
00432 #endif // defined(USE_LSF_PARAMS)
00433 else {
00434 cpl_msg_error(__func__, "Unknown LSF method %s", aParams->method_s);
00435 }
00436 return (cpl_errorstate_is_equal(prestate))?0:-1;
00437 }