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 #define STORE_SLIT_WIDTH
00028 #define STORE_BIN_WIDTH
00029
00030
00031
00032
00033 #include <math.h>
00034 #include <string.h>
00035 #include <fenv.h>
00036
00037 #include <cpl.h>
00038
00039 #include "muse_lsf_params.h"
00040 #include "muse_resampling.h"
00041 #include "muse_pfits.h"
00042 #include "muse_quality.h"
00043 #include "muse_instrument.h"
00044 #include "muse_optimize.h"
00045 #include "muse_tracing.h"
00046 #include "muse_utils.h"
00047
00048
00052
00053
00056
00066
00067 muse_lsf_params *
00068 muse_lsf_params_new(cpl_size n_sensit, cpl_size n_lsf_width, cpl_size n_hermit)
00069 {
00070 muse_lsf_params *res = cpl_calloc(1, sizeof(muse_lsf_params));
00071 res->refraction = 1.0;
00072 res->offset = 0.0;
00073 res->slit_width = kMuseSliceSlitWidthA;
00074 res->bin_width = kMuseSpectralSamplingA;
00075 res->lambda_ref = 7000;
00076 int i;
00077 if (n_hermit > 0) {
00078 for (i = 0; i < MAX_HERMIT_ORDER; i++) {
00079 res->hermit[i] = cpl_array_new(n_hermit, CPL_TYPE_DOUBLE);
00080 cpl_array_fill_window_double(res->hermit[i], 0, n_hermit, 0.0);
00081 }
00082 }
00083 res->lsf_width = cpl_array_new(n_lsf_width, CPL_TYPE_DOUBLE);
00084 if (n_lsf_width > 0) {
00085 cpl_array_fill_window_double(res->lsf_width, 0, n_lsf_width, 0.0);
00086 cpl_array_set_double(res->lsf_width, 0, 1.0);
00087 }
00088 res->sensitivity = cpl_array_new(n_sensit, CPL_TYPE_DOUBLE);
00089 if (n_sensit > 0) {
00090 cpl_array_fill_window_double(res->sensitivity, 0, n_sensit, 0.0);
00091 cpl_array_set_double(res->sensitivity, 0, 1.0);
00092 }
00093 return res;
00094 }
00095
00096
00102
00103 cpl_size
00104 muse_lsf_params_get_size(muse_lsf_params **aParams) {
00105 if (aParams == NULL) {
00106 return 0;
00107 }
00108 cpl_size i;
00109 for (i = 0; *aParams != NULL; i++) {
00110 aParams++;
00111 }
00112 return i;
00113 }
00114
00115
00120
00121 void
00122 muse_lsf_params_delete(muse_lsf_params *aParams) {
00123 if (aParams != NULL) {
00124 cpl_array_delete(aParams->sensitivity);
00125 int i;
00126 for (i = 0; i < MAX_HERMIT_ORDER; i++) {
00127 cpl_array_delete(aParams->hermit[i]);
00128 }
00129 cpl_array_delete(aParams->lsf_width);
00130 cpl_free(aParams);
00131 }
00132 }
00133
00134
00139
00140 void
00141 muse_lsf_params_delete_all(muse_lsf_params **aParams) {
00142 if (aParams != NULL) {
00143 muse_lsf_params **det;
00144 for (det = aParams; *det != NULL; det++) {
00145 muse_lsf_params_delete(*det);
00146 }
00147 cpl_free(aParams);
00148 }
00149 }
00150
00151
00165
00166 const muse_cpltable_def muse_lsfparams_def[] = {
00167 {"ifu", CPL_TYPE_INT, NULL, "%i", "IFU number", CPL_TRUE},
00168 {"slice", CPL_TYPE_INT, NULL, "%i", "slice number within the IFU", CPL_TRUE},
00169 {"sensitivity", CPL_TYPE_DOUBLE | CPL_TYPE_POINTER, NULL, "%e",
00170 "detector sensitivity, relative to the reference", CPL_TRUE},
00171 {"offset", CPL_TYPE_DOUBLE, NULL, "%e", "wavelength calibration offset", CPL_TRUE},
00172 {"refraction", CPL_TYPE_DOUBLE, NULL, "%e", "relative refraction index", CPL_TRUE},
00173 #ifdef STORE_SLIT_WIDTH
00174 {"slit_width", CPL_TYPE_DOUBLE, "Angstrom", "%e", "slit width", CPL_TRUE},
00175 #endif
00176 #ifdef STORE_BIN_WIDTH
00177 {"bin_width", CPL_TYPE_DOUBLE, "Angstrom", "%e", "bin width", CPL_TRUE},
00178 #endif
00179 {"lsf_width", CPL_TYPE_DOUBLE | CPL_TYPE_POINTER, "Angstrom", "%e",
00180 " LSF gauss-hermitean width", CPL_TRUE},
00181 {"hermit3", CPL_TYPE_DOUBLE | CPL_TYPE_POINTER, NULL, "%e",
00182 "3rd order hermitean coefficient", CPL_TRUE},
00183 {"hermit4", CPL_TYPE_DOUBLE | CPL_TYPE_POINTER, NULL, "%e",
00184 "4th order hermitean coefficient", CPL_TRUE},
00185 {"hermit5", CPL_TYPE_DOUBLE | CPL_TYPE_POINTER, NULL, "%e",
00186 "5th order hermitean coefficient", CPL_TRUE},
00187 {"hermit6", CPL_TYPE_DOUBLE | CPL_TYPE_POINTER, NULL, "%e",
00188 "6th order hermitean coefficient", CPL_TRUE},
00189 { NULL, 0, NULL, NULL, NULL, CPL_FALSE }
00190 };
00191
00192
00206
00207 cpl_error_code
00208 muse_lsf_params_save(const muse_lsf_params **aLsfParams, const char *aFile) {
00209 cpl_ensure_code(aLsfParams != NULL, CPL_ERROR_NULL_INPUT);
00210 cpl_ensure_code(*aLsfParams != NULL, CPL_ERROR_DATA_NOT_FOUND);
00211 cpl_ensure_code(aFile != NULL, CPL_ERROR_NULL_INPUT);
00212
00213 cpl_size nrows = 0;
00214 const muse_lsf_params **det;
00215 cpl_size sensitivity_order = 1;
00216 cpl_size lsf_order = 1;
00217 cpl_size hermit_order[MAX_HERMIT_ORDER];
00218 int i;
00219 for (i = 0; i < MAX_HERMIT_ORDER; i++) {
00220 hermit_order[i] = 1;
00221 }
00222 for (det = aLsfParams; *det != NULL; det++, nrows++) {
00223 sensitivity_order = fmax(sensitivity_order,
00224 cpl_array_get_size((*det)->sensitivity));
00225 lsf_order = fmax(lsf_order, cpl_array_get_size((*det)->lsf_width));
00226 for (i = 0; i < MAX_HERMIT_ORDER; i++) {
00227 hermit_order[i] = fmax(hermit_order[i],
00228 cpl_array_get_size((*det)->hermit[i]));
00229 }
00230 }
00231
00232 cpl_table *slice_param = cpl_table_new(nrows);
00233 cpl_table_new_column(slice_param, "ifu", CPL_TYPE_INT);
00234 cpl_table_new_column(slice_param, "slice", CPL_TYPE_INT);
00235 cpl_table_new_column_array(slice_param, "sensitivity",
00236 cpl_array_get_type(aLsfParams[0]->sensitivity),
00237 sensitivity_order);
00238 cpl_table_new_column(slice_param, "offset", CPL_TYPE_DOUBLE);
00239 cpl_table_new_column(slice_param, "refraction", CPL_TYPE_DOUBLE);
00240 #ifdef STORE_SLIT_WIDTH
00241 cpl_table_new_column(slice_param, "slit_width", CPL_TYPE_DOUBLE);
00242 #endif
00243 #ifdef STORE_BIN_WIDTH
00244 cpl_table_new_column(slice_param, "bin_width", CPL_TYPE_DOUBLE);
00245 #endif
00246 cpl_table_new_column_array(slice_param, "lsf_width",
00247 cpl_array_get_type(aLsfParams[0]->lsf_width),
00248 lsf_order);
00249 cpl_table_new_column_array(slice_param, "hermit3",
00250 cpl_array_get_type(aLsfParams[0]->hermit[0]),
00251 hermit_order[0]);
00252 cpl_table_new_column_array(slice_param, "hermit4",
00253 cpl_array_get_type(aLsfParams[0]->hermit[1]),
00254 hermit_order[1]);
00255 cpl_table_new_column_array(slice_param, "hermit5",
00256 cpl_array_get_type(aLsfParams[0]->hermit[2]),
00257 hermit_order[2]);
00258 cpl_table_new_column_array(slice_param, "hermit6",
00259 cpl_array_get_type(aLsfParams[0]->hermit[3]),
00260 hermit_order[3]);
00261
00262 cpl_size iRow = 0;
00263 for (det = aLsfParams; *det != NULL; det++, iRow++) {
00264 cpl_table_set(slice_param, "ifu", iRow, (*det)->ifu);
00265 cpl_table_set(slice_param, "slice", iRow, (*det)->slice);
00266 cpl_table_set_array(slice_param, "sensitivity", iRow, (*det)->sensitivity);
00267 cpl_table_set(slice_param, "offset", iRow, (*det)->offset);
00268 cpl_table_set(slice_param, "refraction", iRow, (*det)->refraction);
00269 #ifdef STORE_SLIT_WIDTH
00270 cpl_table_set(slice_param, "slit_width", iRow, (*det)->slit_width);
00271 #endif
00272 #ifdef STORE_BIN_WIDTH
00273 cpl_table_set(slice_param, "bin_width", iRow, (*det)->bin_width);
00274 #endif
00275 cpl_table_set_array(slice_param, "lsf_width", iRow, (*det)->lsf_width);
00276 cpl_table_set_array(slice_param, "hermit3", iRow, (*det)->hermit[0]);
00277 cpl_table_set_array(slice_param, "hermit4", iRow, (*det)->hermit[1]);
00278 cpl_table_set_array(slice_param, "hermit5", iRow, (*det)->hermit[2]);
00279 cpl_table_set_array(slice_param, "hermit6", iRow, (*det)->hermit[3]);
00280 }
00281
00282 int r = muse_cpltable_append_file(slice_param, aFile, "SLICE_PARAM",
00283 muse_lsfparams_def);
00284 cpl_table_delete(slice_param);
00285 return r;
00286 }
00287
00288
00300
00301 muse_lsf_params **
00302 muse_lsf_params_load(const char *aFile, muse_lsf_params **aParams, int aIFU)
00303 {
00304 cpl_errorstate prestate = cpl_errorstate_get();
00305 cpl_table *lsfTable = muse_cpltable_load(aFile, "SLICE_PARAM",
00306 muse_lsfparams_def);
00307 if (!lsfTable) {
00308
00309 char *extname = cpl_sprintf("CHAN%02d.SLICE_PARAM", aIFU);
00310 lsfTable = muse_cpltable_load(aFile, extname, muse_lsfparams_def);
00311 cpl_free(extname);
00312 if (!lsfTable) {
00313 if (aParams == NULL) {
00314
00315 cpl_errorstate_set(prestate);
00316 return NULL;
00317 }
00318
00319 cpl_error_set_message(__func__, cpl_error_get_code(), "Loading LSF data from "
00320 "\"%s[SLICE_PARAMS]\" and \"%s[CHAH%02d.SLICE_PARAMS]\" "
00321 "failed", aFile, aFile, aIFU);
00322 return aParams;
00323 }
00324 }
00325
00326 cpl_size n_rows = cpl_table_get_nrow(lsfTable);
00327 cpl_size n_rows_old = muse_lsf_params_get_size(aParams);
00328 muse_lsf_params **lsfParams
00329 = cpl_realloc(aParams, (n_rows + n_rows_old + 1) * sizeof(muse_lsf_params *));
00330 lsfParams[n_rows + n_rows_old] = NULL;
00331 cpl_size i_row_new = n_rows_old;
00332 cpl_size i_row;
00333 for (i_row = 0; i_row < n_rows; i_row++) {
00334 int ifu = cpl_table_get(lsfTable, "ifu", i_row, NULL);
00335 lsfParams[i_row + n_rows_old] = NULL;
00336 if ((aIFU <= 0) || (ifu == aIFU)) {
00337 muse_lsf_params *det = muse_lsf_params_new(0,0,0);
00338 lsfParams[i_row_new] = det;
00339 i_row_new++;
00340 det->ifu = ifu;
00341 det->slice = cpl_table_get(lsfTable, "slice", i_row, NULL);
00342 cpl_array_delete(det->sensitivity);
00343 det->sensitivity
00344 = muse_cpltable_get_array_copy(lsfTable, "sensitivity",i_row);
00345 det->offset = cpl_table_get(lsfTable, "offset", i_row, NULL);
00346 det->refraction = cpl_table_get(lsfTable, "refraction", i_row, NULL);
00347 #ifdef STORE_SLIT_WIDTH
00348 det->slit_width = cpl_table_get(lsfTable, "slit_width", i_row, NULL);
00349 #endif
00350 #ifdef STORE_BIN_WIDTH
00351 det->bin_width = cpl_table_get(lsfTable, "bin_width", i_row, NULL);
00352 #endif
00353 cpl_array_delete(det->lsf_width);
00354 det->lsf_width
00355 = muse_cpltable_get_array_copy(lsfTable, "lsf_width", i_row);
00356 cpl_array_delete(det->hermit[0]);
00357 det->hermit[0]
00358 = muse_cpltable_get_array_copy(lsfTable, "hermit3", i_row);
00359 cpl_array_delete(det->hermit[1]);
00360 det->hermit[1]
00361 = muse_cpltable_get_array_copy(lsfTable, "hermit4", i_row);
00362 cpl_array_delete(det->hermit[2]);
00363 det->hermit[2]
00364 = muse_cpltable_get_array_copy(lsfTable, "hermit5", i_row);
00365 cpl_array_delete(det->hermit[3]);
00366 det->hermit[3]
00367 = muse_cpltable_get_array_copy(lsfTable, "hermit6", i_row);
00368 }
00369 }
00370 cpl_table_delete(lsfTable);
00371
00372 return lsfParams;
00373 }
00374
00375
00390
00391 muse_lsf_params **
00392 muse_processing_lsf_params_load(muse_processing *aProcessing, int aIFU)
00393 {
00394 cpl_ensure(aProcessing, CPL_ERROR_NULL_INPUT, NULL);
00395 cpl_frameset *frames = muse_frameset_find(aProcessing->inframes,
00396 MUSE_TAG_LSF_PROFILE, aIFU,
00397 CPL_FALSE);
00398 if (frames == NULL) {
00399 return NULL;
00400 }
00401
00402 cpl_errorstate state = cpl_errorstate_get();
00403 cpl_size iframe, nframes = cpl_frameset_get_size(frames);
00404 muse_lsf_params **lsfParams = NULL;
00405 for (iframe = 0; iframe < nframes; iframe++) {
00406 cpl_frame *frame = cpl_frameset_get_position(frames, iframe);
00407 lsfParams = muse_lsf_params_load(cpl_frame_get_filename(frame),
00408 lsfParams, aIFU);
00409 if (lsfParams) {
00410 cpl_msg_info(__func__, "Loaded slice LSF params from \"%s\"",
00411 cpl_frame_get_filename(frame));
00412 muse_processing_append_used(aProcessing, frame, CPL_FRAME_GROUP_CALIB, 1);
00413 }
00414 }
00415 char *errmsg = NULL;
00416 if (!cpl_errorstate_is_equal(state)) {
00417 errmsg = cpl_strdup(cpl_error_get_message());
00418 }
00419 cpl_errorstate_set(state);
00420
00421
00422 if (!lsfParams && aIFU == 0 && nframes == 1) {
00423 cpl_msg_debug(__func__, "No LSF parameters loaded yet, trying merged table "
00424 "format.");
00425
00426 cpl_frame *frame = cpl_frameset_get_position(frames, 0);
00427 const char *fname = cpl_frame_get_filename(frame);
00428 state = cpl_errorstate_get();
00429 unsigned char ifu;
00430 for (ifu = 1; ifu <= kMuseNumIFUs; ifu++) {
00431 lsfParams = muse_lsf_params_load(fname, lsfParams, ifu);
00432 }
00433 cpl_errorstate_set(state);
00434 if (lsfParams) {
00435 cpl_msg_info(__func__, "Loaded (merged) slice LSF params from \"%s\"", fname);
00436 muse_processing_append_used(aProcessing, frame, CPL_FRAME_GROUP_CALIB, 1);
00437 }
00438 }
00439 cpl_frameset_delete(frames);
00440
00441
00442 if (errmsg) {
00443 cpl_msg_debug(__func__, "Loading %ss from input frameset did not succeed: "
00444 "%s", MUSE_TAG_LSF_PROFILE, errmsg);
00445 }
00446 cpl_free(errmsg);
00447 return lsfParams;
00448 }
00449
00450
00455
00456 muse_lsf_params *
00457 muse_lsf_params_get(muse_lsf_params **aParams, int aIFU, int aSlice) {
00458 if (aParams == NULL) {
00459 return NULL;
00460 }
00461 int i_det;
00462 for (i_det = 0; aParams[i_det] != NULL; i_det++) {
00463 if (aParams[i_det]->ifu == aIFU && aParams[i_det]->slice == aSlice) {
00464 return aParams[i_det];
00465 }
00466 }
00467 return NULL;
00468 }
00469
00470
00487
00488 static cpl_array *
00489 muse_lsf_G(cpl_array *aX, cpl_array *aCoeffs) {
00490 cpl_ensure(aX != NULL, CPL_ERROR_NULL_INPUT, NULL);
00491 cpl_ensure(aCoeffs != NULL, CPL_ERROR_NULL_INPUT, NULL);
00492
00493 cpl_array *y = cpl_array_duplicate(aX);
00494 cpl_array_multiply(y, y);
00495 cpl_array_multiply_scalar(y, -1);
00496
00497 cpl_array *y2 = cpl_array_duplicate(y);
00498 muse_cplarray_exp(y2);
00499 cpl_array_multiply_scalar(y2, 1.0/60);
00500
00501 cpl_array_multiply_scalar(y, 0.5);
00502 muse_cplarray_exp(y);
00503
00504 cpl_array *R = cpl_array_duplicate(aX);
00505 muse_cplarray_poly1d(R, aCoeffs);
00506 cpl_array_multiply(y2, R);
00507 cpl_array_delete(R);
00508 cpl_array_add(y, y2);
00509
00510 cpl_array_copy_data_double(y2, cpl_array_get_data_double(aX));
00511 cpl_array_multiply_scalar(y2, sqrt(0.5));
00512 muse_cplarray_erf(y2);
00513 cpl_array_multiply_scalar(y2, sqrt(CPL_MATH_PI / 2));
00514 cpl_array_multiply(y2, aX);
00515 cpl_array_add(y, y2);
00516 cpl_array_delete(y2);
00517
00518 return y;
00519 }
00520
00521
00542
00543 cpl_error_code
00544 muse_lsf_params_apply(const muse_lsf_params *aLsfParams,
00545 cpl_array *aVal, double aLambda)
00546 {
00547
00548 cpl_ensure_code(aVal != NULL, CPL_ERROR_NULL_INPUT);
00549 cpl_ensure_code(aLsfParams != NULL, CPL_ERROR_NULL_INPUT);
00550
00551 double slit_width = aLsfParams->slit_width;
00552 double bin_width = aLsfParams->bin_width;
00553 double width = muse_cplarray_poly1d_double(aLambda - aLsfParams->lambda_ref,
00554 aLsfParams->lsf_width);
00555 double h3 = muse_cplarray_poly1d_double(aLambda - aLsfParams->lambda_ref,
00556 aLsfParams->hermit[0]);
00557 double h4 = muse_cplarray_poly1d_double(aLambda - aLsfParams->lambda_ref,
00558 aLsfParams->hermit[1]);
00559 double h5 = muse_cplarray_poly1d_double(aLambda - aLsfParams->lambda_ref,
00560 aLsfParams->hermit[2]);
00561 double h6 = muse_cplarray_poly1d_double(aLambda - aLsfParams->lambda_ref,
00562 aLsfParams->hermit[3]);
00563
00564 cpl_array *coeff = cpl_array_new(5, CPL_TYPE_DOUBLE);
00565 cpl_array_set(coeff, 4, 2 * sqrt(5) * h6);
00566 cpl_array_set(coeff, 3, 2 * sqrt(15) * h5);
00567 cpl_array_set(coeff, 2, 5 * sqrt(6) * h4 - 6 * sqrt(5) * h6);
00568 cpl_array_set(coeff, 1, 10 * sqrt(3) * h3 - 3 * sqrt(15) * h5);
00569 cpl_array_set(coeff, 0, -2.5 * sqrt(6) * h4 + 1.5 * sqrt(5) * h6);
00570
00571 cpl_array_divide_scalar(aVal, width);
00572 bin_width /= 2 * width;
00573 slit_width /= 2 * width;
00574
00575 cpl_array *x = cpl_array_duplicate(aVal);
00576 cpl_array *y;
00577 cpl_array *y1;
00578 cpl_array_add_scalar(x, slit_width + bin_width);
00579 y = muse_lsf_G(x, coeff);
00580
00581 cpl_array_copy_data_double(x, cpl_array_get_data_double(aVal));
00582 cpl_array_add_scalar(x, slit_width - bin_width);
00583 y1 = muse_lsf_G(x, coeff);
00584 cpl_array_subtract(y, y1);
00585 cpl_array_delete(y1);
00586
00587 cpl_array_copy_data_double(x, cpl_array_get_data_double(aVal));
00588 cpl_array_add_scalar(x, -slit_width + bin_width);
00589 y1 = muse_lsf_G(x, coeff);
00590 cpl_array_subtract(y, y1);
00591 cpl_array_delete(y1);
00592
00593 cpl_array_copy_data_double(x, cpl_array_get_data_double(aVal));
00594 cpl_array_add_scalar(x, -slit_width - bin_width);
00595 y1 = muse_lsf_G(x, coeff);
00596 cpl_array_delete(x);
00597 cpl_array_add(y, y1);
00598 cpl_array_delete(y1);
00599
00600 cpl_array_divide_scalar(y, sqrt(CPL_MATH_PI * 32)
00601 * bin_width * slit_width * width * width);
00602 cpl_array_multiply_scalar(y, width);
00603 cpl_array_copy_data_double(aVal, cpl_array_get_data_double(y));
00604 cpl_array_delete(y);
00605 cpl_array_delete(coeff);
00606
00607 return CPL_ERROR_NONE;
00608 }
00609
00610
00626
00627 cpl_array *
00628 muse_lsf_params_spectrum(const cpl_array *aLambda, cpl_table *aLines,
00629 const muse_lsf_params *aLsfParams)
00630 {
00631 cpl_size n_lines = cpl_table_get_nrow(aLines);
00632 cpl_size i_line;
00633 cpl_array *spectrum = cpl_array_new(cpl_array_get_size(aLambda),
00634 CPL_TYPE_DOUBLE);
00635 cpl_array_fill_window(spectrum, 0, cpl_array_get_size(aLambda), 0.0);
00636 int errold = errno;
00637 feclearexcept(FE_UNDERFLOW);
00638 for (i_line = 0; i_line < n_lines; i_line++) {
00639 double l_lambda = cpl_table_get(aLines, "lambda", i_line, NULL);
00640 double l_flux = cpl_table_get(aLines, "flux", i_line, NULL);
00641 double l_min = -7;
00642 double l_max = 7;
00643 cpl_size imin = muse_cplarray_find_sorted(aLambda, l_lambda + l_min);
00644 cpl_size imax = muse_cplarray_find_sorted(aLambda, l_lambda + l_max);
00645 if (imax <= imin) {
00646 continue;
00647 }
00648 cpl_array *l0 = cpl_array_extract(aLambda, imin, imax-imin+1);
00649 cpl_array_subtract_scalar(l0, l_lambda);
00650 muse_lsf_params_apply(aLsfParams, l0, l_lambda);
00651 cpl_array_multiply_scalar(l0, l_flux);
00652 muse_cplarray_add_window(spectrum, imin, l0);
00653 cpl_array_delete(l0);
00654 }
00655 if (fetestexcept(FE_UNDERFLOW)) {
00656 errno = errold;
00657 feclearexcept(FE_UNDERFLOW);
00658 }
00659 return spectrum;
00660 }
00661
00662
00679
00680
00681 muse_lsf_fit_params *
00682 muse_lsf_fit_params_new(cpl_boolean aOffset, cpl_boolean aRefraction,
00683 cpl_size aSensitivity, cpl_size aSlitWidth,
00684 cpl_size aBinWidth, cpl_size aLSFWidth,
00685 cpl_size aHermit3, cpl_size aHermit4,
00686 cpl_size aHermit5, cpl_size aHermit6)
00687 {
00688 muse_lsf_fit_params *params = cpl_malloc(sizeof(muse_lsf_fit_params));
00689 params->offset = aOffset;
00690 params->refraction = aRefraction;
00691 params->sensitivity = aSensitivity;
00692 params->slit_width = aSlitWidth;
00693 params->bin_width = aBinWidth;
00694 params->lsf_width = aLSFWidth;
00695 params->hermit[0] = aHermit3;
00696 params->hermit[1] = aHermit4;
00697 params->hermit[2] = aHermit5;
00698 params->hermit[3] = aHermit6;
00699
00700 params->n_param = params->offset + params->refraction + params->sensitivity +
00701 params->slit_width + params->bin_width + params->lsf_width;
00702 cpl_size i;
00703 for (i = 0; i < MAX_HERMIT_ORDER; i++) {
00704 params->n_param += params->hermit[i];
00705 }
00706
00707 return params;
00708 }
00709
00710
00715
00716 void
00717 muse_lsf_fit_params_delete(muse_lsf_fit_params *params) {
00718 cpl_free(params);
00719 }
00720
00721
00722
00732
00733 static cpl_array *
00734 muse_lsf_firstguess(const muse_lsf_fit_params *aFitParams) {
00735 cpl_array *pars = cpl_array_new(aFitParams->n_param, CPL_TYPE_DOUBLE);
00736 cpl_size offset = 0;
00737
00738
00739 if (aFitParams->offset > 0) {
00740 cpl_array_set(pars, offset++, 0.0);
00741 }
00742
00743
00744 if (aFitParams->refraction > 0) {
00745 cpl_array_set(pars, offset++, 0.0);
00746 }
00747
00748
00749 cpl_size j;
00750 for (j = 0; j < aFitParams->sensitivity; j++) {
00751 cpl_array_set(pars, offset++, (j == 0)?1.0:0.0);
00752 }
00753
00754
00755 if (aFitParams->slit_width > 0) {
00756 cpl_array_set(pars, offset++, kMuseSliceSlitWidthA);
00757 }
00758
00759
00760 if (aFitParams->bin_width > 0) {
00761 cpl_array_set(pars, offset++, kMuseSpectralSamplingA);
00762 }
00763
00764
00765 for (j = 0; j < aFitParams->lsf_width; j++) {
00766 cpl_array_set(pars, offset++, (j == 0)?0.5:0.0);
00767 }
00768
00769
00770 cpl_size i;
00771 for (i = 0; i < MAX_HERMIT_ORDER; i++) {
00772 for (j = 0; j < aFitParams->hermit[i]; j++) {
00773 cpl_array_set(pars, offset++, 0.0);
00774 }
00775 }
00776
00777 if (offset > cpl_array_get_size(pars)) {
00778 cpl_msg_error(__func__,
00779 "inconsistent array: size %ld, filled with %ld values",
00780 (long)cpl_array_get_size(pars), (long)offset);
00781 }
00782 return pars;
00783 }
00784
00785
00793
00794 static cpl_array *
00795 muse_lsf_set_param(muse_lsf_params *aLsfParams,
00796 const muse_lsf_fit_params *aFitParams) {
00797 cpl_array *pars = cpl_array_new(aFitParams->n_param, CPL_TYPE_DOUBLE);
00798 cpl_size offset = 0;
00799
00800
00801 if (aFitParams->offset > 0) {
00802 cpl_array_set(pars, offset++, aLsfParams->offset);
00803 }
00804 if (aFitParams->refraction > 0) {
00805 cpl_array_set(pars, offset++, aLsfParams->refraction -1);
00806 }
00807
00808 cpl_size j;
00809 cpl_size n = cpl_array_get_size(aLsfParams->sensitivity);
00810 for (j = 0; j < aFitParams->sensitivity; j++) {
00811 if (j < n) {
00812 cpl_msg_debug(__func__, "S[%li]=%f", (long)j,
00813 cpl_array_get(aLsfParams->sensitivity, j, NULL));
00814 cpl_array_set(pars, offset++,
00815 cpl_array_get(aLsfParams->sensitivity, j, NULL));
00816 } else {
00817 cpl_array_set(pars, offset++, (j == 0)?1.0:0.0);
00818 }
00819 }
00820
00821 if (aFitParams->slit_width > 0) {
00822 cpl_array_set(pars, offset++, aLsfParams->slit_width);
00823 }
00824
00825 if (aFitParams->bin_width > 0) {
00826 cpl_array_set(pars, offset++, aLsfParams->bin_width);
00827 }
00828
00829
00830 n = cpl_array_get_size(aLsfParams->lsf_width);
00831 for (j = 0; j < aFitParams->lsf_width; j++) {
00832 if (j < n) {
00833 cpl_array_set(pars, offset++,
00834 cpl_array_get(aLsfParams->lsf_width, j, NULL));
00835 } else {
00836 cpl_array_set(pars, offset++, (j == 0)?1.0:0.0);
00837 }
00838 }
00839
00840
00841 cpl_size i;
00842 for (i = 0; i < MAX_HERMIT_ORDER; i++) {
00843 n = cpl_array_get_size(aLsfParams->hermit[i]);
00844 for (j = 0; j < aFitParams->hermit[i]; j++) {
00845 if (j < n) {
00846 cpl_array_set(pars, offset++,
00847 cpl_array_get(aLsfParams->hermit[i], j, NULL));
00848 } else {
00849 cpl_array_set(pars, offset++, 0.0);
00850 }
00851 }
00852 }
00853
00854 if (offset > cpl_array_get_size(pars)) {
00855 cpl_msg_error(__func__,
00856 "inconsistent array: size %ld, filled with %ld values",
00857 (long)cpl_array_get_size(pars), (long)offset);
00858 }
00859 return pars;
00860 }
00861
00862
00873
00874 static muse_lsf_params *
00875 muse_lsf_apply_parametrization(const muse_lsf_params *aTemplate,
00876 const cpl_array *aPar,
00877 const muse_lsf_fit_params *aFitParams)
00878 {
00879 cpl_size offset = 0;
00880 cpl_size j;
00881
00882 cpl_size max_hermit = 0;
00883 for (j = 0; j < MAX_HERMIT_ORDER; j++) {
00884 if (max_hermit < aFitParams->hermit[j]) {
00885 max_hermit = aFitParams->hermit[j];
00886 }
00887 }
00888 muse_lsf_params *lsf
00889 = muse_lsf_params_new((aFitParams->sensitivity > 0)?
00890 aFitParams->sensitivity:
00891 cpl_array_get_size(aTemplate->sensitivity),
00892 (aFitParams->lsf_width > 0)?
00893 aFitParams->lsf_width:
00894 cpl_array_get_size(aTemplate->lsf_width),
00895 (max_hermit > 0)?
00896 max_hermit:
00897 cpl_array_get_size(aTemplate->hermit[0]));
00898 cpl_array_set(lsf->sensitivity, 0, 1.0);
00899
00900 if (aFitParams->offset > 0) {
00901 lsf->offset = cpl_array_get(aPar, offset++, NULL);
00902 } else {
00903 lsf->offset = aTemplate->offset;
00904 }
00905
00906 if (aFitParams->refraction > 0) {
00907 lsf->refraction = 1.0 + cpl_array_get(aPar, offset++, NULL);
00908 } else {
00909 lsf->refraction = aTemplate->refraction;
00910 }
00911
00912 cpl_size n = cpl_array_get_size(lsf->sensitivity);
00913 if (aFitParams->sensitivity > 0) {
00914 for (j = 0; j < n; j++) {
00915 if (j < aFitParams->sensitivity) {
00916 cpl_array_set(lsf->sensitivity, j,
00917 cpl_array_get(aPar, offset++, NULL));
00918 } else {
00919 cpl_array_set(lsf->sensitivity, j, 0.0);
00920 }
00921 }
00922 } else {
00923 for (j = 0; j < n; j++) {
00924 cpl_array_set(lsf->sensitivity, j,
00925 cpl_array_get(aTemplate->sensitivity, j, NULL));
00926 }
00927 }
00928
00929 if (aFitParams->slit_width > 0) {
00930 lsf->slit_width = cpl_array_get(aPar, offset++, NULL);
00931 } else {
00932 lsf->slit_width = aTemplate->slit_width;
00933 }
00934
00935 if (aFitParams->bin_width > 0) {
00936 lsf->bin_width = cpl_array_get(aPar, offset++, NULL);
00937 } else {
00938 lsf->bin_width = aTemplate->bin_width;
00939 }
00940
00941 n = cpl_array_get_size(lsf->lsf_width);
00942 if (aFitParams->lsf_width > 0) {
00943 for (j = 0; j < n; j++) {
00944 if (j < aFitParams->lsf_width) {
00945 cpl_array_set(lsf->lsf_width, j,
00946 cpl_array_get(aPar, offset++, NULL));
00947 } else {
00948 cpl_array_set(lsf->lsf_width, j, 0.0);
00949 }
00950 }
00951 } else {
00952 for (j = 0; j < n; j++) {
00953 cpl_array_set(lsf->lsf_width, j,
00954 cpl_array_get(aTemplate->lsf_width, j, NULL));
00955 }
00956 }
00957
00958 int i;
00959 for (i = 0; i < MAX_HERMIT_ORDER; i++) {
00960 n = cpl_array_get_size(lsf->hermit[i]);
00961 if (aFitParams->hermit[i] > 0) {
00962 for (j = 0; j < n; j++) {
00963 if (j < aFitParams->hermit[i]) {
00964 cpl_array_set(lsf->hermit[i], j,
00965 cpl_array_get(aPar, offset++, NULL));
00966 } else {
00967 cpl_array_set(lsf->hermit[i], j, 0.0);
00968 }
00969 }
00970 } else {
00971 for (j = 0; j < n; j++) {
00972 cpl_array_set(lsf->hermit[i], j,
00973
00974 0.0);
00975 }
00976 }
00977 }
00978
00979 if (offset > cpl_array_get_size(aPar)) {
00980 cpl_msg_error(__func__,
00981 "inconsistent array: size %ld, read with %ld values",
00982 (long)cpl_array_get_size(aPar), (long)offset);
00983 muse_lsf_params_delete(lsf);
00984 return NULL;
00985 }
00986
00987 return lsf;
00988 }
00989
00990
00991
00992
00993 typedef struct {
00994 cpl_array *lambda;
00995 cpl_array *values;
00996 cpl_array *stat;
00997 const cpl_table *lines;
00998 const muse_lsf_fit_params *fit_params;
00999 muse_lsf_params *firstGuess;
01000 } muse_lsf_fit_struct;
01001
01002
01011
01012 static cpl_error_code
01013 muse_lsf_eval(void *aData, cpl_array *aPar, cpl_array *aRetval) {
01014
01015 muse_lsf_fit_struct *data = aData;
01016 cpl_size size = cpl_array_get_size(aRetval);
01017
01018 muse_lsf_params *lsfParam
01019 = muse_lsf_apply_parametrization(data->firstGuess, aPar, data->fit_params);
01020
01021 cpl_table *lines = cpl_table_duplicate(data->lines);
01022
01023 if (!cpl_table_has_column(lines, "flux")) {
01024 cpl_array *linesFlux = cpl_array_extract(aPar, cpl_array_get_size(aPar)
01025 - cpl_table_get_nrow(data->lines),
01026 cpl_table_get_nrow(data->lines));
01027 cpl_table_wrap_double(lines, cpl_array_unwrap(linesFlux), "flux");
01028 }
01029
01030 cpl_array *simulated
01031 = muse_lsf_params_spectrum(data->lambda, lines, lsfParam);
01032
01033 cpl_table_delete(lines);
01034
01035 muse_lsf_params_delete(lsfParam);
01036 cpl_array_subtract(simulated, data->values);
01037 cpl_array_divide(simulated, data->stat);
01038
01039 cpl_array_fill_window_double(aRetval, 0, size, 0.0);
01040 memcpy(cpl_array_get_data_double(aRetval),
01041 cpl_array_get_data_double_const(simulated),
01042 size * sizeof(double));
01043
01044
01045 cpl_size i;
01046 double *d = cpl_array_get_data_double(aRetval);
01047 for (i = 0; i < size; i++) {
01048 if (isnan(d[i])) {
01049 d[i] = 0.0;
01050 }
01051 }
01052
01053 cpl_array_delete(simulated);
01054 return CPL_ERROR_NONE;
01055 }
01056
01057
01070
01071 muse_lsf_params *
01072 muse_lsf_params_fit(muse_pixtable *aPixtable, cpl_table *aLines, int aMaxIter)
01073 {
01074 cpl_ensure(aPixtable, CPL_ERROR_NULL_INPUT, NULL);
01075 uint32_t origin = (uint32_t)cpl_table_get_int(aPixtable->table,
01076 MUSE_PIXTABLE_ORIGIN,
01077 0, NULL);
01078 int i_ifu = muse_pixtable_origin_get_ifu(origin);
01079 int i_slice = muse_pixtable_origin_get_slice(origin);
01080
01081 cpl_propertylist *order = cpl_propertylist_new();
01082 cpl_propertylist_append_bool(order, MUSE_PIXTABLE_LAMBDA, CPL_FALSE);
01083 cpl_table_sort(aPixtable->table, order);
01084 cpl_propertylist_delete(order);
01085
01086
01087
01088 cpl_table *lines = cpl_table_duplicate(aLines);
01089
01090
01091
01092
01093
01094 cpl_size reduction = 1;
01095 cpl_size size = cpl_table_get_nrow(aPixtable->table)/reduction;
01096 cpl_array *lambda = cpl_array_new(size, CPL_TYPE_DOUBLE);
01097 cpl_array *data = cpl_array_new(size, CPL_TYPE_DOUBLE);
01098 cpl_array *stat = cpl_array_new(size, CPL_TYPE_DOUBLE);
01099
01100 cpl_msg_info(__func__, "processing slice %2i.%02i"
01101 " with %"CPL_SIZE_FORMAT" entries",
01102 i_ifu, i_slice, size);
01103
01104 cpl_size i;
01105 for (i = 0; i < size; i++) {
01106 int iflg = 0;
01107 cpl_array_set(lambda, i, cpl_table_get(aPixtable->table,
01108 MUSE_PIXTABLE_LAMBDA,
01109 reduction * i, &iflg));
01110 cpl_array_set(data, i, cpl_table_get(aPixtable->table,
01111 MUSE_PIXTABLE_DATA,
01112 reduction * i, &iflg));
01113 cpl_array_set(stat, i, sqrt(cpl_table_get(aPixtable->table,
01114 MUSE_PIXTABLE_STAT,
01115 reduction * i, &iflg)));
01116 }
01117
01118 muse_lsf_params *firstGuess = muse_lsf_params_new(1, 3, 1);
01119
01120 int debug = getenv("MUSE_DEBUG_LSF_FIT")
01121 && atoi(getenv("MUSE_DEBUG_LSF_FIT")) > 0;
01122 muse_cpl_optimize_control_t ctrl = {
01123 -1, -1, -1,
01124 aMaxIter, debug
01125 };
01126
01127
01128
01129
01130 muse_lsf_fit_params *slice_fit_params0 = muse_lsf_fit_params_new
01131 (
01132 0,
01133 0,
01134 0,
01135 0,
01136 0,
01137 3,
01138 0,
01139 0,
01140 0,
01141 0
01142 );
01143
01144 muse_lsf_fit_struct fit_data = {
01145 lambda,
01146 data,
01147 stat,
01148 lines,
01149 slice_fit_params0,
01150 firstGuess
01151 };
01152
01153 cpl_array *pars = muse_lsf_firstguess(slice_fit_params0);
01154
01155
01156 cpl_array *lf = muse_cpltable_extract_column(lines, "flux");
01157 cpl_array *linesFlux = cpl_array_cast(lf, CPL_TYPE_DOUBLE);
01158 cpl_array_unwrap(lf);
01159 cpl_array_insert(pars, linesFlux, cpl_array_get_size(pars));
01160 cpl_table_erase_column(lines, "flux");
01161
01162 cpl_error_code r
01163 = muse_cpl_optimize_lvmq(&fit_data, pars, size, muse_lsf_eval, &ctrl);
01164
01165 if (r != CPL_ERROR_NONE) {
01166 cpl_array_delete(pars);
01167 pars = muse_lsf_firstguess(slice_fit_params0);
01168 cpl_array_insert(pars, linesFlux, cpl_array_get_size(pars));
01169 }
01170
01171
01172
01173
01174
01175 muse_lsf_fit_params *slice_fit_params = muse_lsf_fit_params_new
01176 (
01177 0,
01178 0,
01179 0,
01180 1,
01181 1,
01182 3,
01183 1,
01184 2,
01185 1,
01186 2
01187 );
01188
01189 fit_data.fit_params = slice_fit_params;
01190
01191 cpl_array_delete(linesFlux);
01192 linesFlux = cpl_array_extract(pars, cpl_array_get_size(pars)
01193 - cpl_table_get_nrow(lines),
01194 cpl_table_get_nrow(lines));
01195 cpl_table_wrap_double(lines, cpl_array_unwrap(linesFlux), "flux");
01196
01197 fit_data.firstGuess = muse_lsf_apply_parametrization(firstGuess, pars,
01198 slice_fit_params0);
01199 muse_lsf_fit_params_delete(slice_fit_params0);
01200 cpl_array_delete(pars);
01201 pars = muse_lsf_set_param(fit_data.firstGuess, slice_fit_params);
01202
01203 r = muse_cpl_optimize_lvmq(&fit_data, pars, size, muse_lsf_eval, &ctrl);
01204 if (r != CPL_ERROR_NONE) {
01205 cpl_array_delete(pars);
01206 pars = muse_lsf_firstguess(slice_fit_params);
01207 }
01208
01209 muse_lsf_params *lsfParam
01210 = muse_lsf_apply_parametrization(firstGuess, pars, slice_fit_params);
01211 lsfParam->ifu = i_ifu;
01212 lsfParam->slice = i_slice;
01213
01214 cpl_msg_debug(__func__, "Slice %2i.%02i: Slit width: %f (%s), bin width: %f (%s)",
01215 i_ifu, i_slice,
01216 lsfParam->slit_width, slice_fit_params->slit_width?"fit":"fixed",
01217 lsfParam->bin_width, slice_fit_params->bin_width?"fit":"fixed");
01218
01219 cpl_array *simulated = muse_lsf_params_spectrum(lambda, lines, lsfParam);
01220 cpl_table_wrap_double(aPixtable->table, cpl_array_unwrap(simulated),
01221 "simulated");
01222 cpl_table_subtract_columns(aPixtable->table, MUSE_PIXTABLE_DATA,
01223 "simulated");
01224 cpl_table_erase_column(aPixtable->table, "simulated");
01225
01226
01227 cpl_array_delete(pars);
01228 if (cpl_table_has_column(aPixtable->table, "lambda_double")) {
01229 cpl_table_erase_column(aPixtable->table, "lambda_double");
01230 }
01231 cpl_array_delete(fit_data.lambda);
01232 cpl_array_delete(fit_data.values);
01233 cpl_array_delete(fit_data.stat);
01234 muse_lsf_params_delete(fit_data.firstGuess);
01235 muse_lsf_params_delete(firstGuess);
01236 muse_lsf_fit_params_delete(slice_fit_params);
01237 cpl_table_delete(lines);
01238
01239 return lsfParam;
01240 }
01241
01242
01263
01264 double
01265 muse_lsf_fwhm_lambda(const muse_lsf_params *aDP, double aLambda,
01266 double aSampling, unsigned int aLength)
01267 {
01268 cpl_ensure(aDP, CPL_ERROR_NULL_INPUT, 0.);
01269
01270 cpl_ensure(cpl_array_get(aDP->lsf_width, 0, NULL) != 1 &&
01271 cpl_array_get(aDP->lsf_width, 0, NULL) != 0,
01272 CPL_ERROR_ILLEGAL_INPUT, 0.);
01273
01274 cpl_table *line = cpl_table_new(1);
01275 cpl_table_new_column(line, "lambda", CPL_TYPE_DOUBLE);
01276 cpl_table_new_column(line, "flux", CPL_TYPE_FLOAT);
01277 cpl_table_set_double(line, "lambda", 0, aLambda);
01278 cpl_table_set_float(line, "flux", 0, 1.0);
01279
01280 cpl_array *lambda = cpl_array_new(aLength, CPL_TYPE_DOUBLE);
01281 cpl_size i;
01282 for (i = 0; i < aLength; i++) {
01283 cpl_array_set_double(lambda, i, (i + 1. - aLength/2) * aSampling + aLambda);
01284 }
01285
01286 cpl_array *spec = muse_lsf_params_spectrum(lambda, line, aDP);
01287 cpl_size imax;
01288 cpl_array_get_maxpos(spec, &imax);
01289 double max = cpl_array_get_max(spec),
01290 vl = 0., vr = 0.;
01291 i = imax;
01292 while (--i >= 0 &&
01293 (vl = cpl_array_get_double(spec, i, NULL)) > max/2.) ;
01294 cpl_size il = i;
01295 i = imax;
01296 while (++i < aLength &&
01297 (vr = cpl_array_get_double(spec, i, NULL)) > max/2.) ;
01298 cpl_size ir = i;
01299
01300
01301 double fwhm = (ir - il) * aSampling;
01302 cpl_array_delete(spec);
01303 cpl_array_delete(lambda);
01304 cpl_table_delete(line);
01305 cpl_ensure(il > 0 && ir < aLength, CPL_ERROR_ILLEGAL_OUTPUT, 0.);
01306 return fwhm;
01307 }
01308