32 #include "muse_sky_old.h" 33 #include "muse_instrument.h" 34 #include "muse_lsf_params.h" 35 #include "muse_optimize.h" 36 #include "muse_utils.h" 37 #include "muse_data_format_z.h" 53 cpl_array *line_strength;
58 } muse_sky_master_params;
70 static muse_sky_master_params *
71 muse_sky_master_params_new(cpl_size n_groups, cpl_size n_continuum) {
72 muse_sky_master_params *res = cpl_calloc(1,
sizeof(muse_sky_master_params));
73 res->line_strength = cpl_array_new(n_groups, CPL_TYPE_DOUBLE);
74 cpl_array_fill_window_double(res->line_strength, 0, n_groups, 1.0);
75 res->continuum = cpl_array_new(n_continuum, CPL_TYPE_DOUBLE);
76 cpl_array_fill_window_double(res->continuum, 0, n_continuum, 0.0);
88 muse_sky_master_params_delete(muse_sky_master_params *aParams) {
89 if (aParams != NULL) {
90 cpl_array_delete(aParams->line_strength);
91 cpl_array_delete(aParams->continuum);
110 static muse_sky_master_params *
111 muse_sky_master_apply_sky_parametrization(
const cpl_array *aPar,
114 muse_sky_master_params *p = muse_sky_master_params_new(ngroups, 0);
117 for (i = 0; i < ngroups; i++) {
118 double s = (cpl_array_get(aPar, (*offset)++, NULL));
119 cpl_array_set(p->line_strength, i, s*s);
136 muse_sky_master_sky_firstguess(
int ngroups) {
137 cpl_array *pars = cpl_array_new(0 + ngroups, CPL_TYPE_DOUBLE);
142 for (i = 0; i < ngroups; i++) {
143 cpl_array_set(pars, offset++, 1e-1);
146 if (offset != cpl_array_get_size(pars)) {
147 cpl_msg_error(__func__,
148 "inconsistent array: size %li; filled with %li values",
149 (
long)cpl_array_get_size(pars), (
long)offset);
167 muse_sky_master_apply_lsf_parametrization(
const cpl_array *aPar,
172 lsf->offset = cpl_array_get(aPar, (*offset)++, NULL);
173 lsf->refraction = 1.0 + cpl_array_get(aPar, (*offset)++, NULL);
175 cpl_array_get(aPar, (*offset)++, NULL));
178 cpl_array_get(aPar, (*offset)++, NULL));
180 cpl_array_get(aPar, (*offset)++, NULL));
183 for (i = 0; i < MAX_HERMIT_ORDER; i++) {
184 cpl_array_set(lsf->
hermit[i], 0,
185 cpl_array_get(aPar, (*offset)++, NULL));
201 muse_sky_master_lsf_firstguess(
void) {
202 cpl_array *pars = cpl_array_new(5 + MAX_HERMIT_ORDER, CPL_TYPE_DOUBLE);
206 cpl_array_set(pars, offset++, 0.0);
208 cpl_array_set(pars, offset++, 0.0);
211 cpl_array_set(pars, offset++, 1.0);
213 cpl_array_set(pars, offset++, 0);
214 cpl_array_set(pars, offset++, 0);
218 for (i = 0; i < MAX_HERMIT_ORDER; i++) {
219 cpl_array_set(pars, offset++, 0.0);
221 if (offset != cpl_array_get_size(pars)) {
222 cpl_msg_error(__func__,
223 "inconsistent array: size %ld, filled with %ld values",
224 (
long)cpl_array_get_size(pars), (
long)offset);
241 static muse_sky_master_params *
242 muse_sky_master_apply_parametrization(
const cpl_array *aPar,
int ngroups) {
244 muse_sky_master_params *p = muse_sky_master_apply_sky_parametrization(aPar, &offset,
246 p->lsf = muse_sky_master_apply_lsf_parametrization(aPar, &offset);
248 if (offset != cpl_array_get_size(aPar)) {
249 cpl_msg_error(__func__,
250 "inconsistent array: size %ld, read with %ld values",
251 (
long)cpl_array_get_size(aPar), (
long)offset);
252 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
253 muse_sky_master_params_delete(p);
273 simulate_master_sky_parameters(
const cpl_table *aLines,
275 const cpl_array *aLambda,
276 const cpl_array *aPar) {
277 muse_sky_master_params *p
278 = muse_sky_master_apply_parametrization(aPar, aNgroups);
280 cpl_array *continuum = cpl_array_duplicate(aLambda);
283 cpl_table *lines = cpl_table_duplicate(aLines);
285 double maxflux = cpl_table_get_column_max(lines,
"flux");
289 cpl_array_add(simulated, continuum);
291 cpl_array_delete(continuum);
292 cpl_table_delete(lines);
293 muse_sky_master_params_delete(p);
299 const cpl_array *lambda;
300 const cpl_array *values;
301 const cpl_array *stat;
302 const cpl_table *sky;
303 const cpl_size ngroups;
304 } muse_master_fit_struct;
317 static cpl_error_code
318 muse_sky_master_eval(
void *aData, cpl_array *aPar, cpl_array *aRetval) {
319 cpl_size size = cpl_array_get_size(aRetval);
320 muse_master_fit_struct *data = aData;
322 = simulate_master_sky_parameters(data->sky, data->ngroups,
325 cpl_array_subtract(simulated, data->values);
327 cpl_array_divide(dsimulated, data->stat);
329 cpl_array_fill_window_double(aRetval, 0, size, 0.0);
330 memcpy(cpl_array_get_data_double(aRetval),
331 cpl_array_get_data_double_const(dsimulated),
332 size *
sizeof(
double));
334 cpl_array_delete(simulated);
335 cpl_array_delete(dsimulated);
337 return CPL_ERROR_NONE;
359 static cpl_error_code
360 muse_sky_master_correct_firstguess(
const cpl_table *aLines,
362 const cpl_array *aLambda,
363 const cpl_array *aData,
368 = simulate_master_sky_parameters(aLines, aNgroups, aLambda, aPars);
371 muse_sky_master_params *msp
372 = muse_sky_master_apply_sky_parametrization(aPars, &offset, aNgroups);
373 cpl_table *lines = cpl_table_duplicate(aLines);
375 muse_sky_master_params_delete(msp);
378 for (i_group = 0; i_group < aNgroups; i_group++) {
380 cpl_table_unselect_all(lines);
381 cpl_table_or_selected_int(lines,
"group", CPL_EQUAL_TO, i_group);
382 cpl_table *gtable = cpl_table_extract_selected(lines);
384 cpl_table_get_column_maxpos(gtable,
"flux", &row);
385 double wavelength = cpl_table_get_double(gtable,
"lambda", row, NULL);
386 cpl_table_delete(gtable);
396 for (i_lbda = i_lbda1; i_lbda <= i_lbda2; i_lbda++) {
397 double lbda = cpl_array_get(aLambda, i_lbda, NULL);
398 double wy_data = cpl_array_get(aData, i_lbda, NULL);
399 double wy_sim = cpl_array_get(simulated, i_lbda, NULL);
401 avg_data += wy_data * lbda;
403 avg_sim += wy_sim * lbda;
408 cpl_array_set(aPars, i_group,
409 cpl_array_get(aPars, i_group, NULL)*sqrt(y_data/y_sim));
412 delta += avg_data - avg_sim;
415 cpl_array_set(aPars, aNgroups,
416 cpl_array_get(aPars, aNgroups, NULL) + delta/aNgroups);
417 cpl_table_delete(lines);
418 cpl_array_delete(simulated);
420 return CPL_ERROR_NONE;
438 cpl_ensure_code(aSpectrum, CPL_ERROR_NULL_INPUT);
439 cpl_ensure_code(aLines, CPL_ERROR_NULL_INPUT);
445 cpl_size nstat = cpl_array_get_size(stat2);
446 cpl_ensure_code(nstat > 0, CPL_ERROR_DATA_NOT_FOUND);
447 cpl_array *stat = cpl_array_extract(stat2, 0, nstat - 1);
448 cpl_array *s2 = cpl_array_extract(stat2, 1, nstat);
449 cpl_array_add(stat, s2);
450 cpl_array_delete(s2);
451 cpl_array_power(stat, 0.5);
453 muse_master_fit_struct fit_data = {
458 cpl_table_get_column_max(aLines,
"group") + 1
461 cpl_array *pars = muse_sky_master_sky_firstguess(fit_data.ngroups);
462 cpl_array *dpars = muse_sky_master_lsf_firstguess();
463 cpl_array_insert(pars, dpars, cpl_array_get_size(pars));
464 cpl_array_delete(dpars);
470 muse_sky_master_correct_firstguess(aLines, fit_data.ngroups, lambda, data, pars);
471 muse_sky_master_correct_firstguess(aLines, fit_data.ngroups, lambda, data, pars);
472 muse_sky_master_correct_firstguess(aLines, fit_data.ngroups, lambda, data, pars);
474 cpl_size size = cpl_array_get_size(lambda);
476 int debug = getenv(
"MUSE_DEBUG_LSF_FIT")
477 && atoi(getenv(
"MUSE_DEBUG_LSF_FIT")) > 0;
483 cpl_msg_info(__func__,
"Starting master sky fit");
485 muse_sky_master_eval, &ctrl);
486 if (r != CPL_ERROR_NONE) {
487 cpl_msg_error(__func__,
"Master sky fit failed with error code %i: %s",
488 r, cpl_error_get_message());
490 cpl_msg_info(__func__,
"Master sky fit finished successfully.");
493 muse_sky_master_params *p = muse_sky_master_apply_parametrization(pars, fit_data.ngroups);
495 cpl_array_delete(pars);
498 cpl_propertylist *order = cpl_propertylist_new();
500 cpl_propertylist_append_bool(order,
"flux", TRUE);
501 cpl_table_sort(aLines, order);
502 cpl_propertylist_delete(order);
504 cpl_msg_info(__func__,
"refraction index=1%s%g, offset=%f Angstrom",
505 p->lsf->refraction < 1?
"-":
"+",
506 fabs(p->lsf->refraction-1), p->lsf->offset);
508 cpl_array_delete(stat);
509 muse_sky_master_params_delete(p);
511 cpl_array_unwrap(lambda);
512 cpl_array_unwrap(data);
513 cpl_array_unwrap(stat2);
515 return CPL_ERROR_NONE;
535 cpl_ensure_code(aPixtable != NULL, CPL_ERROR_NULL_INPUT);
536 cpl_ensure_code(aPixtable->
table != NULL, CPL_ERROR_NULL_INPUT);
537 cpl_ensure_code(aLines != NULL, CPL_ERROR_NULL_INPUT);
542 cpl_msg_info(__func__,
"Starting sky subtraction of %"CPL_SIZE_FORMAT
" slices",
544 cpl_boolean debug = getenv(
"MUSE_DEBUG_SKY")
545 && atoi(getenv(
"MUSE_DEBUG_SKY")) > 0;
546 #pragma omp parallel for default(none) \ 547 shared(aLsfParams, aLines, debug, n_slices, slice_pixtable) 548 for (i_slice = 0; i_slice < n_slices; i_slice++) {
550 = (uint32_t)cpl_table_get_int(slice_pixtable[i_slice]->table,
555 if ((slice_params == NULL) && (aLines != NULL)){
556 cpl_msg_warning(__func__,
"No LSF params for slice #%i.%i." 557 " Ignoring lines in sky subtraction for this slice.",
563 cpl_msg_debug(__func__,
"Sky subtraction of %li pixels for slice #%i.%i",
564 (
long)nrows, ifu, slice);
566 cpl_errorstate prestate = cpl_errorstate_get();
568 cpl_propertylist *order = cpl_propertylist_new();
570 cpl_table_sort(slice_pt->
table, order);
571 cpl_propertylist_delete(order);
574 "lambda_double", CPL_TYPE_DOUBLE);
576 cpl_table_unwrap(slice_pt->
table,
"lambda_double");
581 cpl_array_subtract(data, spectrum);
584 for (ii = 0; ii < cpl_array_get_size(data); ii++) {
585 if (!cpl_array_is_valid(spectrum, ii)) {
589 cpl_array_unwrap(data);
590 cpl_array_delete(spectrum);
591 cpl_array_delete(lambda);
593 if (!cpl_errorstate_is_equal(prestate)) {
594 cpl_errorstate_dump(prestate, CPL_FALSE, NULL);
595 cpl_errorstate_set(prestate);
605 MUSE_HDR_PT_SKYSUB_COMMENT);
607 return CPL_ERROR_NONE;
cpl_array * muse_lsf_params_spectrum(const cpl_array *aLambda, cpl_table *aLines, const muse_lsf_params *aLsfParams)
Create spectrum for a single slice.
void muse_pixtable_extracted_delete(muse_pixtable **aPixtables)
Delete a pixel table array.
unsigned short muse_pixtable_origin_get_slice(uint32_t aOrigin)
Get the slice number from the encoded 32bit origin number.
cpl_size muse_pixtable_extracted_get_size(muse_pixtable **aPixtables)
Get the size of an array of extracted pixel tables.
cpl_error_code muse_sky_lines_apply_strength(cpl_table *, const cpl_array *)
Apply the line strengths to the lines.
void muse_lsf_params_delete(muse_lsf_params *aParams)
Delete an allocated muse_lsf_params structure.
muse_pixtable ** muse_pixtable_extracted_get_slices(muse_pixtable *aPixtable)
Extract one pixel table per IFU and slice.
cpl_size muse_pixtable_get_nrow(const muse_pixtable *aPixtable)
get the number of rows within the pixel table
cpl_error_code muse_cpl_optimize_lvmq(void *aData, cpl_array *aPar, int aSize, muse_cpl_evaluate_func *aFunction, muse_cpl_optimize_control_t *aCtrl)
Minimize a function with the Levenberg-Marquardt algorithm.
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 * table
The pixel table.
#define MUSE_PIXTABLE_DATA
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.
Structure definition of MUSE pixel table.
cpl_error_code muse_sky_subtract_lines_old(muse_pixtable *aPixtable, cpl_table *aLines, muse_lsf_params **aLsfParams)
Subtract sky lines from a pixtable.
cpl_array * lsf_width
LSF width.
cpl_array * muse_cpltable_extract_column(cpl_table *aTable, const char *aColumn)
Create an array from a section of a column.
#define MUSE_HDR_PT_SKYSUB
Optimization control parameters.
#define MUSE_PIXTABLE_ORIGIN
cpl_array * muse_cplarray_diff(const cpl_array *aArray, int aOffset)
Build the difference of any element and one of the next elements.
unsigned short muse_pixtable_origin_get_ifu(uint32_t aOrigin)
Get the IFU number from the encoded 32bit origin number.
cpl_error_code muse_sky_lines_cut(cpl_table *, double)
Remove all lines below a certain flux limit.
#define MUSE_PIXTABLE_LAMBDA
cpl_error_code muse_sky_lines_fit_old(cpl_table *aSpectrum, cpl_table *aLines)
Fit all entries of the pixel table to the master sky.
Structure definition of detector (slice) parameters.
cpl_size muse_cplarray_find_sorted(const cpl_array *aArray, double aValue)
Find a row in an array.
cpl_propertylist * header
The FITS header.