26 #define STORE_SLIT_WIDTH
27 #define STORE_BIN_WIDTH
39 #include "muse_resampling.h"
40 #include "muse_pfits.h"
41 #include "muse_quality.h"
42 #include "muse_instrument.h"
43 #include "muse_optimize.h"
44 #include "muse_tracing.h"
45 #include "muse_utils.h"
77 res->refraction = 1.0;
84 for (i = 0; i < MAX_HERMIT_ORDER; i++) {
85 res->
hermit[i] = cpl_array_new(n_hermit, CPL_TYPE_DOUBLE);
86 cpl_array_fill_window_double(res->
hermit[i], 0, n_hermit, 0.0);
89 res->
lsf_width = cpl_array_new(n_lsf_width, CPL_TYPE_DOUBLE);
90 if (n_lsf_width > 0) {
91 cpl_array_fill_window_double(res->
lsf_width, 0, n_lsf_width, 0.0);
92 cpl_array_set_double(res->
lsf_width, 0, 1.0);
94 res->
sensitivity = cpl_array_new(n_sensit, CPL_TYPE_DOUBLE);
96 cpl_array_fill_window_double(res->
sensitivity, 0, n_sensit, 0.0);
111 if (aParams == NULL) {
115 for (i = 0; *aParams != NULL; i++) {
129 if (aParams != NULL) {
132 for (i = 0; i < MAX_HERMIT_ORDER; i++) {
133 cpl_array_delete(aParams->
hermit[i]);
148 if (aParams != NULL) {
150 for (det = aParams; *det != NULL; det++) {
173 {
"ifu", CPL_TYPE_INT, NULL,
"%i",
"IFU number", CPL_TRUE},
174 {
"slice", CPL_TYPE_INT, NULL,
"%i",
"slice number within the IFU", CPL_TRUE},
175 {
"sensitivity", CPL_TYPE_DOUBLE | CPL_TYPE_POINTER, NULL,
"%e",
176 "detector sensitivity, relative to the reference", CPL_TRUE},
177 {
"offset", CPL_TYPE_DOUBLE, NULL,
"%e",
"wavelength calibration offset", CPL_TRUE},
178 {
"refraction", CPL_TYPE_DOUBLE, NULL,
"%e",
"relative refraction index", CPL_TRUE},
179 #ifdef STORE_SLIT_WIDTH
180 {
"slit_width", CPL_TYPE_DOUBLE,
"Angstrom",
"%e",
"slit width", CPL_TRUE},
182 #ifdef STORE_BIN_WIDTH
183 {
"bin_width", CPL_TYPE_DOUBLE,
"Angstrom",
"%e",
"bin width", CPL_TRUE},
185 {
"lsf_width", CPL_TYPE_DOUBLE | CPL_TYPE_POINTER,
"Angstrom",
"%e",
186 " LSF gauss-hermitean width", CPL_TRUE},
187 {
"hermit3", CPL_TYPE_DOUBLE | CPL_TYPE_POINTER, NULL,
"%e",
188 "3rd order hermitean coefficient", CPL_TRUE},
189 {
"hermit4", CPL_TYPE_DOUBLE | CPL_TYPE_POINTER, NULL,
"%e",
190 "4th order hermitean coefficient", CPL_TRUE},
191 {
"hermit5", CPL_TYPE_DOUBLE | CPL_TYPE_POINTER, NULL,
"%e",
192 "5th order hermitean coefficient", CPL_TRUE},
193 {
"hermit6", CPL_TYPE_DOUBLE | CPL_TYPE_POINTER, NULL,
"%e",
194 "6th order hermitean coefficient", CPL_TRUE},
195 { NULL, 0, NULL, NULL, NULL, CPL_FALSE }
215 cpl_ensure_code(aLsf != NULL, CPL_ERROR_NULL_INPUT);
216 cpl_ensure_code(*aLsf != NULL, CPL_ERROR_DATA_NOT_FOUND);
217 cpl_ensure_code(aFile != NULL, CPL_ERROR_NULL_INPUT);
221 cpl_size sensitivity_order = 1;
222 cpl_size lsf_order = 1;
223 cpl_size hermit_order[MAX_HERMIT_ORDER];
225 for (i = 0; i < MAX_HERMIT_ORDER; i++) {
228 for (det = aLsf; *det != NULL; det++, nrows++) {
229 sensitivity_order = fmax(sensitivity_order,
230 cpl_array_get_size((*det)->sensitivity));
231 lsf_order = fmax(lsf_order, cpl_array_get_size((*det)->lsf_width));
232 for (i = 0; i < MAX_HERMIT_ORDER; i++) {
233 hermit_order[i] = fmax(hermit_order[i],
234 cpl_array_get_size((*det)->hermit[i]));
238 cpl_table *slice_param = cpl_table_new(nrows);
239 cpl_table_new_column(slice_param,
"ifu", CPL_TYPE_INT);
240 cpl_table_new_column(slice_param,
"slice", CPL_TYPE_INT);
241 cpl_table_new_column_array(slice_param,
"sensitivity",
242 cpl_array_get_type(aLsf[0]->sensitivity),
244 cpl_table_new_column(slice_param,
"offset", CPL_TYPE_DOUBLE);
245 cpl_table_new_column(slice_param,
"refraction", CPL_TYPE_DOUBLE);
246 #ifdef STORE_SLIT_WIDTH
247 cpl_table_new_column(slice_param,
"slit_width", CPL_TYPE_DOUBLE);
249 #ifdef STORE_BIN_WIDTH
250 cpl_table_new_column(slice_param,
"bin_width", CPL_TYPE_DOUBLE);
252 cpl_table_new_column_array(slice_param,
"lsf_width",
253 cpl_array_get_type(aLsf[0]->lsf_width),
255 cpl_table_new_column_array(slice_param,
"hermit3",
256 cpl_array_get_type(aLsf[0]->hermit[0]),
258 cpl_table_new_column_array(slice_param,
"hermit4",
259 cpl_array_get_type(aLsf[0]->hermit[1]),
261 cpl_table_new_column_array(slice_param,
"hermit5",
262 cpl_array_get_type(aLsf[0]->hermit[2]),
264 cpl_table_new_column_array(slice_param,
"hermit6",
265 cpl_array_get_type(aLsf[0]->hermit[3]),
269 for (det = aLsf; *det != NULL; det++, iRow++) {
270 cpl_table_set(slice_param,
"ifu", iRow, (*det)->ifu);
271 cpl_table_set(slice_param,
"slice", iRow, (*det)->slice);
272 cpl_table_set_array(slice_param,
"sensitivity", iRow, (*det)->sensitivity);
273 cpl_table_set(slice_param,
"offset", iRow, (*det)->offset);
274 cpl_table_set(slice_param,
"refraction", iRow, (*det)->refraction);
275 #ifdef STORE_SLIT_WIDTH
276 cpl_table_set(slice_param,
"slit_width", iRow, (*det)->slit_width);
278 #ifdef STORE_BIN_WIDTH
279 cpl_table_set(slice_param,
"bin_width", iRow, (*det)->bin_width);
281 cpl_table_set_array(slice_param,
"lsf_width", iRow, (*det)->lsf_width);
282 cpl_table_set_array(slice_param,
"hermit3", iRow, (*det)->hermit[0]);
283 cpl_table_set_array(slice_param,
"hermit4", iRow, (*det)->hermit[1]);
284 cpl_table_set_array(slice_param,
"hermit5", iRow, (*det)->hermit[2]);
285 cpl_table_set_array(slice_param,
"hermit6", iRow, (*det)->hermit[3]);
290 cpl_table_delete(slice_param);
314 char *extname = cpl_sprintf(
"CHAN%02d.SLICE_PARAM", aIFU);
319 cpl_error_set_message(__func__, cpl_error_get_code(),
"Loading LSF data from "
320 "\"%s[SLICE_PARAMS]\" and \"%s[CHAH%02d.SLICE_PARAMS]\" "
321 "failed", aFile, aFile, aIFU);
326 cpl_size n_rows = cpl_table_get_nrow(lsfTable);
329 = cpl_realloc(aParams, (n_rows + n_rows_old + 1) *
sizeof(
muse_lsf_params *));
330 lsfParams[n_rows + n_rows_old] = NULL;
331 cpl_size i_row_new = n_rows_old;
333 for (i_row = 0; i_row < n_rows; i_row++) {
334 int ifu = cpl_table_get(lsfTable,
"ifu", i_row, NULL);
335 lsfParams[i_row + n_rows_old] = NULL;
336 if ((aIFU <= 0) || (ifu == aIFU)) {
338 lsfParams[i_row_new] = det;
341 det->slice = cpl_table_get(lsfTable,
"slice", i_row, NULL);
345 det->offset = cpl_table_get(lsfTable,
"offset", i_row, NULL);
346 det->refraction = cpl_table_get(lsfTable,
"refraction", i_row, NULL);
347 #ifdef STORE_SLIT_WIDTH
348 det->
slit_width = cpl_table_get(lsfTable,
"slit_width", i_row, NULL);
350 #ifdef STORE_BIN_WIDTH
351 det->
bin_width = cpl_table_get(lsfTable,
"bin_width", i_row, NULL);
356 cpl_array_delete(det->
hermit[0]);
359 cpl_array_delete(det->
hermit[1]);
362 cpl_array_delete(det->
hermit[2]);
365 cpl_array_delete(det->
hermit[3]);
370 cpl_table_delete(lsfTable);
394 cpl_ensure(aProcessing, CPL_ERROR_NULL_INPUT, NULL);
396 "LSF_TABLE", aIFU, CPL_FALSE);
397 if (frames == NULL) {
401 cpl_errorstate state = cpl_errorstate_get();
402 cpl_size iframe, nframes = cpl_frameset_get_size(frames);
404 for (iframe = 0; iframe < nframes; iframe++) {
405 cpl_frame *frame = cpl_frameset_get_position(frames, iframe);
409 cpl_msg_info(__func__,
"Loaded slice LSF params from \"%s\"",
410 cpl_frame_get_filename(frame));
415 if (!cpl_errorstate_is_equal(state)) {
416 errmsg = cpl_strdup(cpl_error_get_message());
418 cpl_errorstate_set(state);
421 if (!lsfParams && aIFU == 0 && nframes == 1) {
422 cpl_msg_debug(__func__,
"No LSF parameters loaded yet, trying merged table "
425 cpl_frame *frame = cpl_frameset_get_position(frames, 0);
426 const char *fname = cpl_frame_get_filename(frame);
427 state = cpl_errorstate_get();
429 for (ifu = 1; ifu <= kMuseNumIFUs; ifu++) {
432 cpl_errorstate_set(state);
434 cpl_msg_info(__func__,
"Loaded (merged) slice LSF params from \"%s\"", fname);
438 cpl_frameset_delete(frames);
442 cpl_msg_debug(__func__,
"Loading LSF_TABLEs from input frameset did not "
443 "succeed: %s", errmsg);
457 if (aParams == NULL) {
461 for (i_det = 0; aParams[i_det] != NULL; i_det++) {
462 if (aParams[i_det]->ifu == aIFU && aParams[i_det]->slice == aSlice) {
463 return aParams[i_det];
489 cpl_ensure(aX != NULL, CPL_ERROR_NULL_INPUT, NULL);
490 cpl_ensure(aCoeffs != NULL, CPL_ERROR_NULL_INPUT, NULL);
492 cpl_array *y = cpl_array_duplicate(aX);
493 cpl_array_multiply(y, y);
494 cpl_array_multiply_scalar(y, -1);
496 cpl_array *y2 = cpl_array_duplicate(y);
498 cpl_array_multiply_scalar(y2, 1.0/60);
500 cpl_array_multiply_scalar(y, 0.5);
503 cpl_array *R = cpl_array_duplicate(aX);
505 cpl_array_multiply(y2, R);
507 cpl_array_add(y, y2);
509 cpl_array_copy_data_double(y2, cpl_array_get_data_double(aX));
510 cpl_array_multiply_scalar(y2, sqrt(0.5));
512 cpl_array_multiply_scalar(y2, sqrt(CPL_MATH_PI / 2));
513 cpl_array_multiply(y2, aX);
514 cpl_array_add(y, y2);
515 cpl_array_delete(y2);
546 static cpl_error_code
549 double aLineLambda,
double aLineFlux) {
550 cpl_ensure_code(aSpectrum != NULL, CPL_ERROR_NULL_INPUT);
551 cpl_ensure_code(aLambda != NULL, CPL_ERROR_NULL_INPUT);
552 cpl_ensure_code(aLsf != NULL, CPL_ERROR_NULL_INPUT);
554 aLineLambda *= aLsf->refraction;
555 aLineLambda += aLsf->offset;
570 cpl_array *coeff = cpl_array_new(5, CPL_TYPE_DOUBLE);
571 cpl_array_set(coeff, 4, 2 * sqrt(5) * h6);
572 cpl_array_set(coeff, 3, 2 * sqrt(15) * h5);
573 cpl_array_set(coeff, 2, 5 * sqrt(6) * h4 - 6 * sqrt(5) * h6);
574 cpl_array_set(coeff, 1, 10 * sqrt(3) * h3 - 3 * sqrt(15) * h5);
575 cpl_array_set(coeff, 0, -2.5 * sqrt(6) * h4 + 1.5 * sqrt(5) * h6);
578 aLineLambda - (5 * width +
579 0.6*(bin_width + slit_width)));
581 aLineLambda + (5 * width +
582 0.6*(bin_width + slit_width)));
584 cpl_array_delete(coeff);
585 return CPL_ERROR_NONE;
588 cpl_array *l0 = cpl_array_extract(aLambda, imin, imax-imin+1);
590 cpl_array_subtract_scalar(l0, aLineLambda);
591 cpl_array_divide_scalar(l0, width);
592 bin_width /= 2 * width;
593 slit_width /= 2 * width;
595 cpl_array *x = cpl_array_duplicate(l0);
598 cpl_array_add_scalar(x, slit_width + bin_width);
601 cpl_array_copy_data_double(x, cpl_array_get_data_double(l0));
602 cpl_array_add_scalar(x, slit_width - bin_width);
604 cpl_array_subtract(y, y1);
605 cpl_array_delete(y1);
607 cpl_array_copy_data_double(x, cpl_array_get_data_double(l0));
608 cpl_array_add_scalar(x, -slit_width + bin_width);
610 cpl_array_subtract(y, y1);
611 cpl_array_delete(y1);
613 cpl_array_copy_data_double(x, cpl_array_get_data_double(l0));
614 cpl_array_add_scalar(x, -slit_width - bin_width);
617 cpl_array_add(y, y1);
618 cpl_array_delete(y1);
621 cpl_array_multiply_scalar(y, width);
622 cpl_array_multiply_scalar(y, aLineFlux);
626 cpl_array_delete(l0);
627 cpl_array_delete(coeff);
629 return CPL_ERROR_NONE;
654 const cpl_array *aLinesLambda,
655 const cpl_array *aLinesFlux,
657 cpl_ensure(aLambda != NULL, CPL_ERROR_NULL_INPUT, NULL);
658 cpl_ensure(aLinesLambda != NULL, CPL_ERROR_NULL_INPUT, NULL);
659 cpl_ensure(aLinesFlux != NULL, CPL_ERROR_NULL_INPUT, NULL);
660 cpl_ensure(aLsf != NULL, CPL_ERROR_NULL_INPUT, NULL);
662 int nrows = cpl_array_get_size(aLambda);
663 cpl_array *spectrum = cpl_array_new(nrows, CPL_TYPE_DOUBLE);
664 cpl_array_fill_window_double(spectrum, 0, nrows, 0.0);
666 int linescount = cpl_array_get_size(aLinesLambda);
668 feclearexcept(FE_UNDERFLOW);
669 for (i = 0; i < linescount; i++) {
670 double lambda = cpl_array_get(aLinesLambda, i, NULL);
671 double flux = cpl_array_get(aLinesFlux, i, NULL);
674 if (fetestexcept(FE_UNDERFLOW)) {
676 feclearexcept(FE_UNDERFLOW);
709 double aFlux,
double aSampling,
unsigned int aLength,
712 cpl_ensure(aDP, CPL_ERROR_NULL_INPUT, 0.);
714 cpl_ensure(cpl_array_get(aDP->
lsf_width, 0, NULL) != 1 &&
715 cpl_array_get(aDP->
lsf_width, 0, NULL) != 0,
716 CPL_ERROR_ILLEGAL_INPUT, 0.);
718 cpl_array *llambda = cpl_array_new(1, CPL_TYPE_DOUBLE),
719 *lflux = cpl_array_new(1, CPL_TYPE_DOUBLE);
720 cpl_array_set_double(llambda, 0, aLambda);
721 cpl_array_set_double(lflux, 0, aFlux);
723 cpl_array *lambda = cpl_array_new(aLength, CPL_TYPE_DOUBLE);
725 for (i = 0; i < aLength; i++) {
726 cpl_array_set_double(lambda, i, (i + 1. - aLength/2) * aSampling + aLambda);
731 cpl_array_get_maxpos(spec, &imax);
732 double max = cpl_array_get_max(spec),
736 (vl = cpl_array_get_double(spec, i, NULL)) > max/2.) ;
739 while (++i < aLength &&
740 (vr = cpl_array_get_double(spec, i, NULL)) > max/2.) ;
744 double fwhm = (ir - il) * aSampling;
746 fprintf(aOutstream,
" %.1f: %02d.%02d\t%f %f %f\t%f +/- %f (%f) %f..%f "
747 "(%"CPL_SIZE_FORMAT
")\t%f (%"CPL_SIZE_FORMAT
") %f (%"CPL_SIZE_FORMAT
748 ") ==> %f\n", aLambda, aDP->ifu, aDP->slice, aDP->
lambda_ref,
750 cpl_array_get_stdev(spec), cpl_array_get_median(spec),
751 cpl_array_get_min(spec), max, imax, vl, il, vr, ir, fwhm);
754 cpl_array_dump(spec, 0, aLength, stdout);
757 cpl_vector *vspec = cpl_vector_wrap(aLength, cpl_array_get_data_double(spec));
758 cpl_vector_save(vspec,
"vspec.fits", CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
759 cpl_vector_unwrap(vspec);
761 cpl_array_delete(spec);
762 cpl_array_delete(lambda);
763 cpl_array_delete(llambda);
764 cpl_array_delete(lflux);
765 cpl_ensure(il > 0 && ir < aLength, CPL_ERROR_ILLEGAL_OUTPUT, 0.);
void muse_lsf_params_delete_one(muse_lsf_params *aParams)
Delete an allocated muse_lsf_params structure.
cpl_error_code muse_lsf_params_save(const muse_lsf_params **aLsf, const char *aFile)
Save slice LSF parameters to the extension "slice" on disk.
muse_lsf_params * muse_lsf_params_get(muse_lsf_params **aParams, int aIFU, int aSlice)
Get the slice LSF parameters for one slice.
cpl_error_code muse_cplarray_poly1d(cpl_array *aArray, const cpl_array *aCoeff)
Apply a polynomial to an array.
cpl_table * muse_cpltable_load(const char *aFile, const char *aExtension, const muse_cpltable_def aDefinition[])
Load a table from disk (and check against definition).
cpl_array * muse_lsf_spectrum_get_lines(const cpl_array *aLambda, const cpl_array *aLinesLambda, const cpl_array *aLinesFlux, const muse_lsf_params *aLsf)
Set the lines spectrum from the lines table and the detector LSF.
double bin_width
Bin width.
cpl_array * hermit[MAX_HERMIT_ORDER]
coefficients for the damped gauss-hermitean parametrization
muse_lsf_params * muse_lsf_params_new(cpl_size n_sensit, cpl_size n_lsf_width, cpl_size n_hermit)
Create a new lsf_params structure.
cpl_array * sensitivity
Relative detector sensitivity parametrization.
cpl_error_code muse_cplarray_exp(cpl_array *aArray)
Compute the exponential function of array elements.
double muse_lsf_fwhm_lambda(const muse_lsf_params *aDP, double aLambda, double aFlux, double aSampling, unsigned int aLength, FILE *aOutstream)
Measure the FWHM of an LSF at a given wavelength.
double slit_width
Slit width.
cpl_array * muse_cpltable_get_array_copy(cpl_table *aTable, const char *aColumn, cpl_size aRow)
Return the copy of an array of a table cell.
cpl_array * lsf_width
LSF width.
static cpl_error_code muse_lsf_line_apply(const cpl_array *, cpl_array *, const muse_lsf_params *, double, double)
Apply the MUSE LSF function to a single line.
void muse_processing_append_used(muse_processing *aProcessing, cpl_frame *aFrame, cpl_frame_group aGroup, int aDuplicate)
Add a frame to the set of used frames.
cpl_error_code muse_cplarray_erf(cpl_array *aArray)
Compute the error function of array elements.
cpl_size muse_lsf_params_get_size(muse_lsf_params **aParams)
Count the number of entries in the array.
cpl_error_code muse_cplarray_add_window(cpl_array *aDest, cpl_size aStart, const cpl_array *aArray)
Add the value of an array to a window of a table column.
const muse_cpltable_def muse_lsfparams_def[]
Definition of a lsf parameters table.
muse_lsf_params ** muse_lsf_params_load(const char *aFile, muse_lsf_params **aParams, int aIFU)
Load slice LSF parameters from the extension "SLICE_PARAM".
double lambda_ref
Reference wavelength for polynomial parametrizations.
static cpl_array * muse_lsf_G(cpl_array *aX, cpl_array *aCoeffs)
Helper function "G" for integrated damped gauss-hermitean function.
Definition of a cpl table structure.
muse_lsf_params ** muse_processing_lsf_params_load(muse_processing *aProcessing, int aIFU)
Load slice LSF parameters.
cpl_frameset * muse_frameset_find(const cpl_frameset *aFrames, const char *aTag, unsigned char aIFU, cpl_boolean aInvert)
return frameset containing data from an IFU/channel with a certain tag
cpl_frameset * inputFrames
Structure definition of detector (slice) parameters.
double muse_cplarray_poly1d_double(double aDouble, const cpl_array *aCoeff)
Apply a polynomial to a double value.
cpl_size muse_cplarray_find_sorted(const cpl_array *aArray, double aValue)
Find a row in an array.
void muse_lsf_params_delete(muse_lsf_params **aParams)
Delete an allocated array of muse_lsf_params structure.
cpl_error_code muse_cpltable_append_file(const cpl_table *aTable, const char *aFile, const char *aExtension, const muse_cpltable_def aDefinition[])
Save a table to disk (into a FITS extension)