27 #define STORE_SLIT_WIDTH
28 #define STORE_BIN_WIDTH
40 #include "muse_resampling.h"
41 #include "muse_pfits.h"
42 #include "muse_quality.h"
43 #include "muse_instrument.h"
44 #include "muse_optimize.h"
45 #include "muse_tracing.h"
46 #include "muse_utils.h"
78 res->refraction = 1.0;
85 for (i = 0; i < MAX_HERMIT_ORDER; i++) {
86 res->
hermit[i] = cpl_array_new(n_hermit, CPL_TYPE_DOUBLE);
87 cpl_array_fill_window_double(res->
hermit[i], 0, n_hermit, 0.0);
90 res->
lsf_width = cpl_array_new(n_lsf_width, CPL_TYPE_DOUBLE);
91 if (n_lsf_width > 0) {
92 cpl_array_fill_window_double(res->
lsf_width, 0, n_lsf_width, 0.0);
93 cpl_array_set_double(res->
lsf_width, 0, 1.0);
95 res->
sensitivity = cpl_array_new(n_sensit, CPL_TYPE_DOUBLE);
97 cpl_array_fill_window_double(res->
sensitivity, 0, n_sensit, 0.0);
112 if (aParams == NULL) {
116 for (i = 0; *aParams != NULL; i++) {
130 if (aParams != NULL) {
133 for (i = 0; i < MAX_HERMIT_ORDER; i++) {
134 cpl_array_delete(aParams->
hermit[i]);
149 if (aParams != NULL) {
151 for (det = aParams; *det != NULL; det++) {
174 {
"ifu", CPL_TYPE_INT, NULL,
"%i",
"IFU number", CPL_TRUE},
175 {
"slice", CPL_TYPE_INT, NULL,
"%i",
"slice number within the IFU", CPL_TRUE},
176 {
"sensitivity", CPL_TYPE_DOUBLE | CPL_TYPE_POINTER, NULL,
"%e",
177 "detector sensitivity, relative to the reference", CPL_TRUE},
178 {
"offset", CPL_TYPE_DOUBLE, NULL,
"%e",
"wavelength calibration offset", CPL_TRUE},
179 {
"refraction", CPL_TYPE_DOUBLE, NULL,
"%e",
"relative refraction index", CPL_TRUE},
180 #ifdef STORE_SLIT_WIDTH
181 {
"slit_width", CPL_TYPE_DOUBLE,
"Angstrom",
"%e",
"slit width", CPL_TRUE},
183 #ifdef STORE_BIN_WIDTH
184 {
"bin_width", CPL_TYPE_DOUBLE,
"Angstrom",
"%e",
"bin width", CPL_TRUE},
186 {
"lsf_width", CPL_TYPE_DOUBLE | CPL_TYPE_POINTER,
"Angstrom",
"%e",
187 " LSF gauss-hermitean width", CPL_TRUE},
188 {
"hermit3", CPL_TYPE_DOUBLE | CPL_TYPE_POINTER, NULL,
"%e",
189 "3rd order hermitean coefficient", CPL_TRUE},
190 {
"hermit4", CPL_TYPE_DOUBLE | CPL_TYPE_POINTER, NULL,
"%e",
191 "4th order hermitean coefficient", CPL_TRUE},
192 {
"hermit5", CPL_TYPE_DOUBLE | CPL_TYPE_POINTER, NULL,
"%e",
193 "5th order hermitean coefficient", CPL_TRUE},
194 {
"hermit6", CPL_TYPE_DOUBLE | CPL_TYPE_POINTER, NULL,
"%e",
195 "6th order hermitean coefficient", CPL_TRUE},
196 { NULL, 0, NULL, NULL, NULL, CPL_FALSE }
216 cpl_ensure_code(aLsf != NULL, CPL_ERROR_NULL_INPUT);
217 cpl_ensure_code(*aLsf != NULL, CPL_ERROR_DATA_NOT_FOUND);
218 cpl_ensure_code(aFile != NULL, CPL_ERROR_NULL_INPUT);
222 cpl_size sensitivity_order = 1;
223 cpl_size lsf_order = 1;
224 cpl_size hermit_order[MAX_HERMIT_ORDER];
226 for (i = 0; i < MAX_HERMIT_ORDER; i++) {
229 for (det = aLsf; *det != NULL; det++, nrows++) {
230 sensitivity_order = fmax(sensitivity_order,
231 cpl_array_get_size((*det)->sensitivity));
232 lsf_order = fmax(lsf_order, cpl_array_get_size((*det)->lsf_width));
233 for (i = 0; i < MAX_HERMIT_ORDER; i++) {
234 hermit_order[i] = fmax(hermit_order[i],
235 cpl_array_get_size((*det)->hermit[i]));
239 cpl_table *slice_param = cpl_table_new(nrows);
240 cpl_table_new_column(slice_param,
"ifu", CPL_TYPE_INT);
241 cpl_table_new_column(slice_param,
"slice", CPL_TYPE_INT);
242 cpl_table_new_column_array(slice_param,
"sensitivity",
243 cpl_array_get_type(aLsf[0]->sensitivity),
245 cpl_table_new_column(slice_param,
"offset", CPL_TYPE_DOUBLE);
246 cpl_table_new_column(slice_param,
"refraction", CPL_TYPE_DOUBLE);
247 #ifdef STORE_SLIT_WIDTH
248 cpl_table_new_column(slice_param,
"slit_width", CPL_TYPE_DOUBLE);
250 #ifdef STORE_BIN_WIDTH
251 cpl_table_new_column(slice_param,
"bin_width", CPL_TYPE_DOUBLE);
253 cpl_table_new_column_array(slice_param,
"lsf_width",
254 cpl_array_get_type(aLsf[0]->lsf_width),
256 cpl_table_new_column_array(slice_param,
"hermit3",
257 cpl_array_get_type(aLsf[0]->hermit[0]),
259 cpl_table_new_column_array(slice_param,
"hermit4",
260 cpl_array_get_type(aLsf[0]->hermit[1]),
262 cpl_table_new_column_array(slice_param,
"hermit5",
263 cpl_array_get_type(aLsf[0]->hermit[2]),
265 cpl_table_new_column_array(slice_param,
"hermit6",
266 cpl_array_get_type(aLsf[0]->hermit[3]),
270 for (det = aLsf; *det != NULL; det++, iRow++) {
271 cpl_table_set(slice_param,
"ifu", iRow, (*det)->ifu);
272 cpl_table_set(slice_param,
"slice", iRow, (*det)->slice);
273 cpl_table_set_array(slice_param,
"sensitivity", iRow, (*det)->sensitivity);
274 cpl_table_set(slice_param,
"offset", iRow, (*det)->offset);
275 cpl_table_set(slice_param,
"refraction", iRow, (*det)->refraction);
276 #ifdef STORE_SLIT_WIDTH
277 cpl_table_set(slice_param,
"slit_width", iRow, (*det)->slit_width);
279 #ifdef STORE_BIN_WIDTH
280 cpl_table_set(slice_param,
"bin_width", iRow, (*det)->bin_width);
282 cpl_table_set_array(slice_param,
"lsf_width", iRow, (*det)->lsf_width);
283 cpl_table_set_array(slice_param,
"hermit3", iRow, (*det)->hermit[0]);
284 cpl_table_set_array(slice_param,
"hermit4", iRow, (*det)->hermit[1]);
285 cpl_table_set_array(slice_param,
"hermit5", iRow, (*det)->hermit[2]);
286 cpl_table_set_array(slice_param,
"hermit6", iRow, (*det)->hermit[3]);
291 cpl_table_delete(slice_param);
315 char *extname = cpl_sprintf(
"CHAN%02d.SLICE_PARAM", aIFU);
320 cpl_error_set_message(__func__, cpl_error_get_code(),
"Loading LSF data from "
321 "\"%s[SLICE_PARAMS]\" and \"%s[CHAH%02d.SLICE_PARAMS]\" "
322 "failed", aFile, aFile, aIFU);
327 cpl_size n_rows = cpl_table_get_nrow(lsfTable);
330 = cpl_realloc(aParams, (n_rows + n_rows_old + 1) *
sizeof(
muse_lsf_params *));
331 lsfParams[n_rows + n_rows_old] = NULL;
332 cpl_size i_row_new = n_rows_old;
334 for (i_row = 0; i_row < n_rows; i_row++) {
335 int ifu = cpl_table_get(lsfTable,
"ifu", i_row, NULL);
336 lsfParams[i_row + n_rows_old] = NULL;
337 if ((aIFU <= 0) || (ifu == aIFU)) {
339 lsfParams[i_row_new] = det;
342 det->slice = cpl_table_get(lsfTable,
"slice", i_row, NULL);
346 det->offset = cpl_table_get(lsfTable,
"offset", i_row, NULL);
347 det->refraction = cpl_table_get(lsfTable,
"refraction", i_row, NULL);
348 #ifdef STORE_SLIT_WIDTH
349 det->
slit_width = cpl_table_get(lsfTable,
"slit_width", i_row, NULL);
351 #ifdef STORE_BIN_WIDTH
352 det->
bin_width = cpl_table_get(lsfTable,
"bin_width", i_row, NULL);
357 cpl_array_delete(det->
hermit[0]);
360 cpl_array_delete(det->
hermit[1]);
363 cpl_array_delete(det->
hermit[2]);
366 cpl_array_delete(det->
hermit[3]);
371 cpl_table_delete(lsfTable);
395 cpl_ensure(aProcessing, CPL_ERROR_NULL_INPUT, NULL);
397 MUSE_TAG_LSF_PROFILE, aIFU,
399 if (frames == NULL) {
403 cpl_errorstate state = cpl_errorstate_get();
404 cpl_size iframe, nframes = cpl_frameset_get_size(frames);
406 for (iframe = 0; iframe < nframes; iframe++) {
407 cpl_frame *frame = cpl_frameset_get_position(frames, iframe);
411 cpl_msg_info(__func__,
"Loaded slice LSF params from \"%s\"",
412 cpl_frame_get_filename(frame));
417 if (!cpl_errorstate_is_equal(state)) {
418 errmsg = cpl_strdup(cpl_error_get_message());
420 cpl_errorstate_set(state);
423 if (!lsfParams && aIFU == 0 && nframes == 1) {
424 cpl_msg_debug(__func__,
"No LSF parameters loaded yet, trying merged table "
427 cpl_frame *frame = cpl_frameset_get_position(frames, 0);
428 const char *fname = cpl_frame_get_filename(frame);
429 state = cpl_errorstate_get();
431 for (ifu = 1; ifu <= kMuseNumIFUs; ifu++) {
434 cpl_errorstate_set(state);
436 cpl_msg_info(__func__,
"Loaded (merged) slice LSF params from \"%s\"", fname);
440 cpl_frameset_delete(frames);
444 cpl_msg_debug(__func__,
"Loading %ss from input frameset did not succeed: "
445 "%s", MUSE_TAG_LSF_PROFILE, errmsg);
459 if (aParams == NULL) {
463 for (i_det = 0; aParams[i_det] != NULL; i_det++) {
464 if (aParams[i_det]->ifu == aIFU && aParams[i_det]->slice == aSlice) {
465 return aParams[i_det];
491 cpl_ensure(aX != NULL, CPL_ERROR_NULL_INPUT, NULL);
492 cpl_ensure(aCoeffs != NULL, CPL_ERROR_NULL_INPUT, NULL);
494 cpl_array *y = cpl_array_duplicate(aX);
495 cpl_array_multiply(y, y);
496 cpl_array_multiply_scalar(y, -1);
498 cpl_array *y2 = cpl_array_duplicate(y);
500 cpl_array_multiply_scalar(y2, 1.0/60);
502 cpl_array_multiply_scalar(y, 0.5);
505 cpl_array *R = cpl_array_duplicate(aX);
507 cpl_array_multiply(y2, R);
509 cpl_array_add(y, y2);
511 cpl_array_copy_data_double(y2, cpl_array_get_data_double(aX));
512 cpl_array_multiply_scalar(y2, sqrt(0.5));
514 cpl_array_multiply_scalar(y2, sqrt(CPL_MATH_PI / 2));
515 cpl_array_multiply(y2, aX);
516 cpl_array_add(y, y2);
517 cpl_array_delete(y2);
548 static cpl_error_code
551 double aLineLambda,
double aLineFlux) {
552 cpl_ensure_code(aSpectrum != NULL, CPL_ERROR_NULL_INPUT);
553 cpl_ensure_code(aLambda != NULL, CPL_ERROR_NULL_INPUT);
554 cpl_ensure_code(aLsf != NULL, CPL_ERROR_NULL_INPUT);
556 aLineLambda *= aLsf->refraction;
557 aLineLambda += aLsf->offset;
572 cpl_array *coeff = cpl_array_new(5, CPL_TYPE_DOUBLE);
573 cpl_array_set(coeff, 4, 2 * sqrt(5) * h6);
574 cpl_array_set(coeff, 3, 2 * sqrt(15) * h5);
575 cpl_array_set(coeff, 2, 5 * sqrt(6) * h4 - 6 * sqrt(5) * h6);
576 cpl_array_set(coeff, 1, 10 * sqrt(3) * h3 - 3 * sqrt(15) * h5);
577 cpl_array_set(coeff, 0, -2.5 * sqrt(6) * h4 + 1.5 * sqrt(5) * h6);
580 aLineLambda - (5 * width +
581 0.6*(bin_width + slit_width)));
583 aLineLambda + (5 * width +
584 0.6*(bin_width + slit_width)));
586 cpl_array_delete(coeff);
587 return CPL_ERROR_NONE;
590 cpl_array *l0 = cpl_array_extract(aLambda, imin, imax-imin+1);
592 cpl_array_subtract_scalar(l0, aLineLambda);
593 cpl_array_divide_scalar(l0, width);
594 bin_width /= 2 * width;
595 slit_width /= 2 * width;
597 cpl_array *x = cpl_array_duplicate(l0);
600 cpl_array_add_scalar(x, slit_width + bin_width);
603 cpl_array_copy_data_double(x, cpl_array_get_data_double(l0));
604 cpl_array_add_scalar(x, slit_width - bin_width);
606 cpl_array_subtract(y, y1);
607 cpl_array_delete(y1);
609 cpl_array_copy_data_double(x, cpl_array_get_data_double(l0));
610 cpl_array_add_scalar(x, -slit_width + bin_width);
612 cpl_array_subtract(y, y1);
613 cpl_array_delete(y1);
615 cpl_array_copy_data_double(x, cpl_array_get_data_double(l0));
616 cpl_array_add_scalar(x, -slit_width - bin_width);
619 cpl_array_add(y, y1);
620 cpl_array_delete(y1);
623 cpl_array_multiply_scalar(y, width);
624 cpl_array_multiply_scalar(y, aLineFlux);
628 cpl_array_delete(l0);
629 cpl_array_delete(coeff);
631 return CPL_ERROR_NONE;
656 const cpl_array *aLinesLambda,
657 const cpl_array *aLinesFlux,
659 cpl_ensure(aLambda != NULL, CPL_ERROR_NULL_INPUT, NULL);
660 cpl_ensure(aLinesLambda != NULL, CPL_ERROR_NULL_INPUT, NULL);
661 cpl_ensure(aLinesFlux != NULL, CPL_ERROR_NULL_INPUT, NULL);
662 cpl_ensure(aLsf != NULL, CPL_ERROR_NULL_INPUT, NULL);
664 int nrows = cpl_array_get_size(aLambda);
665 cpl_array *spectrum = cpl_array_new(nrows, CPL_TYPE_DOUBLE);
666 cpl_array_fill_window_double(spectrum, 0, nrows, 0.0);
668 int linescount = cpl_array_get_size(aLinesLambda);
670 feclearexcept(FE_UNDERFLOW);
671 for (i = 0; i < linescount; i++) {
672 double lambda = cpl_array_get(aLinesLambda, i, NULL);
673 double flux = cpl_array_get(aLinesFlux, i, NULL);
676 if (fetestexcept(FE_UNDERFLOW)) {
678 feclearexcept(FE_UNDERFLOW);
711 double aFlux,
double aSampling,
unsigned int aLength,
714 cpl_ensure(aDP, CPL_ERROR_NULL_INPUT, 0.);
716 cpl_ensure(cpl_array_get(aDP->
lsf_width, 0, NULL) != 1 &&
717 cpl_array_get(aDP->
lsf_width, 0, NULL) != 0,
718 CPL_ERROR_ILLEGAL_INPUT, 0.);
720 cpl_array *llambda = cpl_array_new(1, CPL_TYPE_DOUBLE),
721 *lflux = cpl_array_new(1, CPL_TYPE_DOUBLE);
722 cpl_array_set_double(llambda, 0, aLambda);
723 cpl_array_set_double(lflux, 0, aFlux);
725 cpl_array *lambda = cpl_array_new(aLength, CPL_TYPE_DOUBLE);
727 for (i = 0; i < aLength; i++) {
728 cpl_array_set_double(lambda, i, (i + 1. - aLength/2) * aSampling + aLambda);
733 cpl_array_get_maxpos(spec, &imax);
734 double max = cpl_array_get_max(spec),
738 (vl = cpl_array_get_double(spec, i, NULL)) > max/2.) ;
741 while (++i < aLength &&
742 (vr = cpl_array_get_double(spec, i, NULL)) > max/2.) ;
746 double fwhm = (ir - il) * aSampling;
748 fprintf(aOutstream,
" %.1f: %02d.%02d\t%f %f %f\t%f +/- %f (%f) %f..%f "
749 "(%"CPL_SIZE_FORMAT
")\t%f (%"CPL_SIZE_FORMAT
") %f (%"CPL_SIZE_FORMAT
750 ") ==> %f\n", aLambda, aDP->ifu, aDP->slice, aDP->
lambda_ref,
752 cpl_array_get_stdev(spec), cpl_array_get_median(spec),
753 cpl_array_get_min(spec), max, imax, vl, il, vr, ir, fwhm);
756 cpl_array_dump(spec, 0, aLength, stdout);
759 cpl_vector *vspec = cpl_vector_wrap(aLength, cpl_array_get_data_double(spec));
760 cpl_vector_save(vspec,
"vspec.fits", CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
761 cpl_vector_unwrap(vspec);
763 cpl_array_delete(spec);
764 cpl_array_delete(lambda);
765 cpl_array_delete(llambda);
766 cpl_array_delete(lflux);
767 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
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)