MUSE Pipeline Reference Manual  1.0.2
muse_sky_master.c
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set sw=2 sts=2 et cin: */
3 /*
4  * This file is part of the MUSE Instrument Pipeline
5  * Copyright (C) 2008-2014 European Southern Observatory
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #include <math.h>
27 #include <string.h>
28 
29 #include "muse_sky.h"
30 #include "muse_instrument.h"
31 #include "muse_lsf.h"
32 #include "muse_optimize.h"
33 #include "muse_utils.h"
34 #include "muse_data_format_z.h"
35 
39 /*----------------------------------------------------------------------------*/
44 /*----------------------------------------------------------------------------*/
47  return cpl_calloc(1, sizeof(muse_sky_master));
48 }
49 
50 /*----------------------------------------------------------------------------*/
56 /*----------------------------------------------------------------------------*/
57 void
59  if (aMaster != NULL) {
60  cpl_table_delete(aMaster->lines);
61  cpl_table_delete(aMaster->continuum);
62  muse_lsf_params_delete(aMaster->lsf);
63  cpl_free(aMaster);
64  }
65 }
66 
67 /*----------------------------------------------------------------------------*/
74 /*----------------------------------------------------------------------------*/
75 typedef struct {
77  cpl_array *line_strength;
79  cpl_array *continuum;
81  muse_lsf_params *lsf;
82 } muse_sky_master_params;
83 
84 /*----------------------------------------------------------------------------*/
92 /*----------------------------------------------------------------------------*/
93 static muse_sky_master_params *
94 muse_sky_master_params_new(cpl_size n_groups, cpl_size n_continuum) {
95  muse_sky_master_params *res = cpl_calloc(1, sizeof(muse_sky_master_params));
96  res->line_strength = cpl_array_new(n_groups, CPL_TYPE_DOUBLE);
97  cpl_array_fill_window_double(res->line_strength, 0, n_groups, 1.0);
98  res->continuum = cpl_array_new(n_continuum, CPL_TYPE_DOUBLE);
99  cpl_array_fill_window_double(res->continuum, 0, n_continuum, 0.0);
100  return res;
101 }
102 
103 /*----------------------------------------------------------------------------*/
109 /*----------------------------------------------------------------------------*/
110 static void
111 muse_sky_master_params_delete(muse_sky_master_params *aParams) {
112  if (aParams != NULL) {
113  cpl_array_delete(aParams->line_strength);
114  cpl_array_delete(aParams->continuum);
115  muse_lsf_params_delete_one(aParams->lsf);
116  cpl_free(aParams);
117  }
118 }
119 
120 /*----------------------------------------------------------------------------*/
132 /*----------------------------------------------------------------------------*/
133 static muse_sky_master_params *
134 muse_sky_master_apply_sky_parametrization(const cpl_array *aPar,
135  cpl_size *offset,
136  int ngroups) {
137  muse_sky_master_params *p = muse_sky_master_params_new(ngroups, 0);
138 
139  int i;
140  for (i = 0; i < ngroups; i++) {
141  double s = (cpl_array_get(aPar, (*offset)++, NULL));
142  cpl_array_set(p->line_strength, i, s*s);
143  }
144  return p;
145 }
146 
147 /*----------------------------------------------------------------------------*/
157 /*----------------------------------------------------------------------------*/
158 static cpl_array *
159 muse_sky_master_sky_firstguess(int ngroups) {
160  cpl_array *pars = cpl_array_new(0 + ngroups, CPL_TYPE_DOUBLE);
161  cpl_size offset = 0;
162 
163  // Line strengths
164  int i;
165  for (i = 0; i < ngroups; i++) {
166  cpl_array_set(pars, offset++, 1e-1);
167  }
168 
169  if (offset != cpl_array_get_size(pars)) {
170  cpl_msg_error(__func__,
171  "inconsistent array: size %li; filled with %li values",
172  (long)cpl_array_get_size(pars), (long)offset);
173  }
174  return pars;
175 }
176 
177 /*----------------------------------------------------------------------------*/
188 /*----------------------------------------------------------------------------*/
189 static muse_lsf_params *
190 muse_sky_master_apply_lsf_parametrization(const cpl_array *aPar,
191  cpl_size *offset)
192 {
193  muse_lsf_params *lsf = muse_lsf_params_new(1, 3, 1);
194  cpl_array_set(lsf->sensitivity, 0, 1.0);
195  lsf->offset = cpl_array_get(aPar, (*offset)++, NULL);
196  lsf->refraction = 1.0 + cpl_array_get(aPar, (*offset)++, NULL);
197  cpl_array_set(lsf->lsf_width, 0,
198  cpl_array_get(aPar, (*offset)++, NULL));
199 #if 1
200  cpl_array_set(lsf->lsf_width, 1,
201  cpl_array_get(aPar, (*offset)++, NULL));
202  cpl_array_set(lsf->lsf_width, 2,
203  cpl_array_get(aPar, (*offset)++, NULL));
204 #endif
205  cpl_size i;
206  for (i = 0; i < MAX_HERMIT_ORDER; i++) {
207  cpl_array_set(lsf->hermit[i], 0,
208  cpl_array_get(aPar, (*offset)++, NULL));
209  }
210  return lsf;
211 }
212 
213 /*----------------------------------------------------------------------------*/
222 /*----------------------------------------------------------------------------*/
223 static cpl_array *
224 muse_sky_master_lsf_firstguess(void) {
225  cpl_array *pars = cpl_array_new(5 + MAX_HERMIT_ORDER, CPL_TYPE_DOUBLE);
226  cpl_size offset = 0;
227 
228  // wavelength calibration offset
229  cpl_array_set(pars, offset++, 0.0);
230  // Relative refraction - 1
231  cpl_array_set(pars, offset++, 0.0);
232 
233  // LSF width
234  cpl_array_set(pars, offset++, 1.0);
235 #if 1
236  cpl_array_set(pars, offset++, 0);
237  cpl_array_set(pars, offset++, 0);
238 #endif
239  // Hermitean coefficients
240  cpl_size i;
241  for (i = 0; i < MAX_HERMIT_ORDER; i++) {
242  cpl_array_set(pars, offset++, 0.0);
243  }
244  if (offset != cpl_array_get_size(pars)) {
245  cpl_msg_error(__func__,
246  "inconsistent array: size %ld, filled with %ld values",
247  (long)cpl_array_get_size(pars), (long)offset);
248  }
249  return pars;
250 }
251 
252 /*----------------------------------------------------------------------------*/
263 /*----------------------------------------------------------------------------*/
264 static muse_sky_master_params *
265 muse_sky_master_apply_parametrization(const cpl_array *aPar, int ngroups) {
266  cpl_size offset = 0;
267  muse_sky_master_params *p = muse_sky_master_apply_sky_parametrization(aPar, &offset,
268  ngroups);
269  p->lsf = muse_sky_master_apply_lsf_parametrization(aPar, &offset);
270 
271  if (offset != cpl_array_get_size(aPar)) {
272  cpl_msg_error(__func__,
273  "inconsistent array: size %ld, read with %ld values",
274  (long)cpl_array_get_size(aPar), (long)offset);
275  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
276  muse_sky_master_params_delete(p);
277  return NULL;
278  }
279  return p;
280 }
281 
282 /*----------------------------------------------------------------------------*/
293 /*----------------------------------------------------------------------------*/
294 
295 static cpl_array *
296 simulate_master_sky_parameters(const cpl_table *aLines,
297  cpl_size aNgroups,
298  const cpl_array *aLambda,
299  const cpl_array *aPar) {
300  muse_sky_master_params *p
301  = muse_sky_master_apply_parametrization(aPar, aNgroups);
302 
303  cpl_array *continuum = cpl_array_duplicate(aLambda);
304  muse_cplarray_poly1d(continuum, p->continuum);
305 
306  cpl_table *lines = cpl_table_duplicate(aLines);
307  muse_sky_lines_apply_strength(lines, p->line_strength);
308  double maxflux = cpl_table_get_column_max(lines, "flux");
309  muse_sky_lines_cut(lines, 1e-4 * maxflux);
310 
311  cpl_array *simulated = muse_sky_apply_lsf(aLambda, lines, p->lsf);
312  cpl_array_add(simulated, continuum);
313 
314  cpl_array_delete(continuum);
315  cpl_table_delete(lines);
316  muse_sky_master_params_delete(p);
317  return simulated;
318 
319 }
320 
321 typedef struct {
322  const cpl_array *lambda; // wavelength
323  const cpl_array *values; // data values
324  const cpl_array *stat; // data statistics
325  const cpl_table *sky; // constant sky physics data
326  const cpl_size ngroups; // number of groups in the data
327 } muse_master_fit_struct;
328 
329 
330 /*----------------------------------------------------------------------------*/
339 /*----------------------------------------------------------------------------*/
340 static cpl_error_code
341 muse_sky_master_eval(void *aData, cpl_array *aPar, cpl_array *aRetval) {
342  cpl_size size = cpl_array_get_size(aRetval);
343  muse_master_fit_struct *data = aData;
344  cpl_array *simulated
345  = simulate_master_sky_parameters(data->sky, data->ngroups,
346  data->lambda, aPar);
347 
348  cpl_array_subtract(simulated, data->values);
349  cpl_array *dsimulated = muse_cplarray_diff(simulated, 1);
350  cpl_array_divide(dsimulated, data->stat);
351 
352  cpl_array_fill_window_double(aRetval, 0, size, 0.0);
353  memcpy(cpl_array_get_data_double(aRetval),
354  cpl_array_get_data_double_const(dsimulated),
355  size * sizeof(double));
356 
357  cpl_array_delete(simulated);
358  cpl_array_delete(dsimulated);
359 
360  return CPL_ERROR_NONE;
361 }
362 
363 /*----------------------------------------------------------------------------*/
380 /*----------------------------------------------------------------------------*/
381 
382 static cpl_error_code
383 muse_sky_master_correct_firstguess(const cpl_table *aLines,
384  cpl_size aNgroups,
385  const cpl_array *aLambda,
386  const cpl_array *aData,
387  cpl_array *aPars) {
388 
389  // evaluate the first guess
390  cpl_array *simulated
391  = simulate_master_sky_parameters(aLines, aNgroups, aLambda, aPars);
392 
393  cpl_size offset = 0;
394  muse_sky_master_params *msp
395  = muse_sky_master_apply_sky_parametrization(aPars, &offset, aNgroups);
396  cpl_table *lines = cpl_table_duplicate(aLines);
397  muse_sky_lines_apply_strength(lines, msp->line_strength);
398  muse_sky_master_params_delete(msp);
399  cpl_size i_group;
400  double delta = 0.0;
401  for (i_group = 0; i_group < aNgroups; i_group++) {
402  // take the strongest line of each group
403  cpl_table_unselect_all(lines);
404  cpl_table_or_selected_int(lines, "group", CPL_EQUAL_TO, i_group);
405  cpl_table *gtable = cpl_table_extract_selected(lines);
406  cpl_size row;
407  cpl_table_get_column_maxpos(gtable, "flux", &row);
408  double wavelength = cpl_table_get_double(gtable, "lambda", row, NULL);
409  cpl_table_delete(gtable);
410 
411  // divide measured data and first guess result
412  cpl_size i_lbda1 = muse_cplarray_find_sorted(aLambda, wavelength - 2.0);
413  cpl_size i_lbda2 = muse_cplarray_find_sorted(aLambda, wavelength + 2.0);
414  double y_data = 0;
415  double y_sim = 0;
416  double avg_data = 0;
417  double avg_sim = 0;
418  cpl_size i_lbda;
419  for (i_lbda = i_lbda1; i_lbda <= i_lbda2; i_lbda++) {
420  double lbda = cpl_array_get(aLambda, i_lbda, NULL);
421  double wy_data = cpl_array_get(aData, i_lbda, NULL);
422  double wy_sim = cpl_array_get(simulated, i_lbda, NULL);
423  y_data += wy_data;
424  avg_data += wy_data * lbda;
425  y_sim += wy_sim;
426  avg_sim += wy_sim * lbda;
427  }
428 
429  // take this as correction factor
430  if (y_sim > 0) {
431  cpl_array_set(aPars, i_group,
432  cpl_array_get(aPars, i_group, NULL)*sqrt(y_data/y_sim));
433  avg_data /= y_data;
434  avg_sim /= y_sim;
435  delta += avg_data - avg_sim;
436  }
437  }
438  cpl_array_set(aPars, aNgroups,
439  cpl_array_get(aPars, aNgroups, NULL) + delta/aNgroups);
440  cpl_table_delete(lines);
441  cpl_array_delete(simulated);
442 
443  return CPL_ERROR_NONE;
444 }
445 
446 /*----------------------------------------------------------------------------*/
461 /*----------------------------------------------------------------------------*/
463 muse_sky_master_fit(const cpl_array *aLambda, const cpl_array *aData,
464  const cpl_array *aStat, const cpl_table *aLines)
465 {
466  cpl_ensure(aLambda, CPL_ERROR_NULL_INPUT, NULL);
467  cpl_ensure(aData, CPL_ERROR_NULL_INPUT, NULL);
468  cpl_ensure(aStat, CPL_ERROR_NULL_INPUT, NULL);
469  cpl_ensure(aLines, CPL_ERROR_NULL_INPUT, NULL);
470 
471  cpl_size nstat = cpl_array_get_size(aStat);
472  cpl_ensure(nstat > 0, CPL_ERROR_DATA_NOT_FOUND, NULL);
473  cpl_array *stat = cpl_array_extract(aStat, 0, nstat - 1);
474  cpl_array *s2 = cpl_array_extract(aStat, 1, nstat);
475  cpl_array_add(stat, s2);
476  cpl_array_delete(s2);
477  cpl_array_power(stat, 0.5);
478 
479  muse_master_fit_struct data = {
480  aLambda,
481  aData,
482  stat,
483  aLines,
484  cpl_table_get_column_max(aLines, "group") + 1
485  };
486 
487  cpl_array *pars = muse_sky_master_sky_firstguess(data.ngroups);
488  cpl_array *dpars = muse_sky_master_lsf_firstguess();
489  cpl_array_insert(pars, dpars, cpl_array_get_size(pars));
490  cpl_array_delete(dpars);
491 
492  // run the correction twice: in the first run, mainly the offset for
493  // the wavelength is calculated. In the second step, the lines strengts
494  // are corrected with a better guess of the window (with the offset from
495  // the first step). Also the wavelength offset is corrected.
496  muse_sky_master_correct_firstguess(aLines, data.ngroups, aLambda, aData, pars);
497  muse_sky_master_correct_firstguess(aLines, data.ngroups, aLambda, aData, pars);
498  muse_sky_master_correct_firstguess(aLines, data.ngroups, aLambda, aData, pars);
499 
500  cpl_size size = cpl_array_get_size(aLambda);
501  // do the fit, ignoring possible errors
502  int debug = getenv("MUSE_DEBUG_LSF_FIT")
503  && atoi(getenv("MUSE_DEBUG_LSF_FIT")) > 0;
505  -1, -1, -1, -1, // default ftol, xtol, gtol, maxiter
506  debug
507  };
508  /* this potentially takes a long time, better output something */
509  cpl_msg_info(__func__, "Starting master sky fit");
510  cpl_error_code r = muse_cpl_optimize_lvmq(&data, pars, size-1,
511  muse_sky_master_eval, &ctrl);
512  if (r != CPL_ERROR_NONE) {
513  cpl_msg_error(__func__, "Master sky fit failed with error code %i: %s",
514  r, cpl_error_get_message());
515  } else {
516  cpl_msg_info(__func__, "Master sky fit finished successfully.");
517  }
518 
519  muse_sky_master_params *p = muse_sky_master_apply_parametrization(pars, data.ngroups);
520 
521  cpl_array_delete(pars);
522 
524  res->lines = cpl_table_duplicate(aLines);
525  muse_sky_lines_apply_strength(res->lines, p->line_strength);
526  cpl_propertylist *order = cpl_propertylist_new();
527 // cpl_propertylist_append_bool(order, "lambda", FALSE);
528  cpl_propertylist_append_bool(order, "flux", TRUE);
529  cpl_table_sort(res->lines, order);
530  cpl_propertylist_delete(order);
531 
532  cpl_array *continuum = muse_sky_apply_lsf(aLambda, res->lines, p->lsf);
533  cpl_msg_info(__func__, "refraction index=1%s%g, offset=%f Angstrom",
534  p->lsf->refraction < 1?"-":"+",
535  fabs(p->lsf->refraction-1), p->lsf->offset);
536 
537  cpl_array_subtract(continuum, aData);
538  cpl_array_multiply_scalar(continuum, -1);
539 
540  /*
541  * ::TODO::
542  * In the moment, the continuum is just calculated by subtracting
543  * the fitted line spectrum from the original spectrum. This is a
544  * source of errors since the original spectrum is created by many
545  * slices with different LSF parameters and also rebinned; so the
546  * subtraction contains a residual from rebinning artefacts.
547  *
548  * It would be much better if we would use the pixel table of the sky
549  * regions (created in muse_create_sky) and the slice-dependent LSF
550  * parameters to create a subtracted sky pixel table first, and then
551  * rebin this into the continuum spectrum.
552 
553  * This also makes the resolution of the continuum independent of
554  * the resolution for the fit; the later one could be largely
555  * reduced and optimized in a way that we have clear bins with lines
556  * and other bins that don't contain (many) lines, without edge
557  * problems. This would also eliminate the LSF parameter fit here
558  * Also we don't suffer from (small) wavelength calibration errors
559  * here. This all would make this fit faster and more stable.
560  */
562  cpl_array_get_size(aLambda));
563  muse_cpltable_copy_array(res->continuum, "lambda", aLambda);
564  muse_cpltable_copy_array(res->continuum, "flux", continuum);
565  cpl_array_delete(continuum);
566 
567  res->lsf = cpl_calloc(2, sizeof(muse_lsf_params));
568  res->lsf[0] = p->lsf;
569  p->lsf = NULL;
570 
571  cpl_array_delete(stat);
572  muse_sky_master_params_delete(p);
573 
574  return res;
575 }
576 
577 /*----------------------------------------------------------------------------*/
583 /*----------------------------------------------------------------------------*/
584 cpl_table *
586 {
587  cpl_ensure(aProcessing, CPL_ERROR_NULL_INPUT, NULL);
588 
589  /* search for frames with the SKY_CONTINUUM tag set */
590  cpl_frameset *frames_c = muse_frameset_find(aProcessing->inframes,
591  "SKY_CONTINUUM", 0, CPL_FALSE);
592  if (frames_c == NULL || cpl_frameset_get_size(frames_c) < 1) {
593  cpl_frameset_delete(frames_c);
594  return NULL;
595  }
596  cpl_frame *frame_c = cpl_frameset_get_position(frames_c, 0);
597  const char *fn = cpl_frame_get_filename(frame_c);
598  cpl_table *continuum = muse_cpltable_load(fn, "CONTINUUM",
600 
601  if (continuum == NULL) {
602  cpl_frameset_delete(frames_c);
603  return NULL;
604  }
605 
606  muse_processing_append_used(aProcessing, frame_c, CPL_FRAME_GROUP_CALIB, 1);
607  cpl_frameset_delete(frames_c);
608  return continuum;
609 } /* muse_processing_sky_continuum_load() */
610 
611 /*----------------------------------------------------------------------------*/
622 /*----------------------------------------------------------------------------*/
625 {
626  cpl_ensure(aProcessing, CPL_ERROR_NULL_INPUT, NULL);
627 
628  /* load the three different sky properties from the corresponding file */
630 
631  /* search for frames with the SKY_LINES tag set */
632  cpl_frameset *frames_l = muse_frameset_find(aProcessing->inframes,
633  "SKY_LINES", 0, CPL_FALSE);
634  if (cpl_frameset_get_size(frames_l) < 1) {
635  cpl_frameset_delete(frames_l);
637  return NULL;
638  }
639  cpl_frame *frame_l = cpl_frameset_get_position(frames_l, 0);
640  const char *fn = cpl_frame_get_filename(frame_l);
642 
643  /* search for frames with the SKY_CONTINUUM tag set */
644  cpl_frameset *frames_c = muse_frameset_find(aProcessing->inframes,
645  "SKY_CONTINUUM", 0, CPL_FALSE);
646  if (cpl_frameset_get_size(frames_c) < 1) {
647  cpl_frameset_delete(frames_c);
648  cpl_frameset_delete(frames_l);
650  return NULL;
651  }
652  cpl_frame *frame_c = cpl_frameset_get_position(frames_c, 0);
653  fn = cpl_frame_get_filename(frame_c);
654  sky->continuum = muse_cpltable_load(fn, "CONTINUUM", muse_fluxspectrum_def);
655 
656  /* search for frames with the LSF tag set */
657  cpl_frameset *frames_d = muse_frameset_find(aProcessing->inframes,
658  MUSE_TAG_LSF_PROFILE, 0, CPL_FALSE);
659  cpl_size iframe, nframes = cpl_frameset_get_size(frames_d);
660  for (iframe = 0; iframe < nframes; iframe++) {
661  cpl_frame *frame_d = cpl_frameset_get_position(frames_d, iframe);
662  fn = cpl_frame_get_filename(frame_d);
663  sky->lsf = muse_lsf_params_load(fn, sky->lsf, 0);
664  } /* for iframe (all frames) */
665 
666  /* if not all could be loaded, clean up and return now */
667  if (!sky->lines || !sky->continuum || !sky->lsf) {
669  cpl_frameset_delete(frames_d);
670  cpl_frameset_delete(frames_c);
671  cpl_frameset_delete(frames_l);
672  return NULL;
673  }
674 
675  muse_processing_append_used(aProcessing, frame_l, CPL_FRAME_GROUP_CALIB, 1);
676  muse_processing_append_used(aProcessing, frame_c, CPL_FRAME_GROUP_CALIB, 1);
677  for (iframe = 0; iframe < nframes; iframe++) {
678  cpl_frame *frame_d = cpl_frameset_get_position(frames_d, iframe);
679  muse_processing_append_used(aProcessing, frame_d,
680  CPL_FRAME_GROUP_CALIB, 1);
681  } /* for iframe (all frames) */
682  cpl_frameset_delete(frames_l);
683  cpl_frameset_delete(frames_c);
684  cpl_frameset_delete(frames_d);
685 
686  return sky;
687 } /* muse_sky_master_load() */
688 
void muse_lsf_params_delete_one(muse_lsf_params *aParams)
Delete an allocated muse_lsf_params structure.
cpl_error_code muse_sky_lines_apply_strength(cpl_table *, const cpl_array *)
Apply the line strengths to the lines.
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.
Structure to hold the MASTER SKY result.
Definition: muse_sky.h:57
const muse_cpltable_def muse_sky_lines_lines_def[]
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_table * muse_cpltable_new(const muse_cpltable_def *aDef, cpl_size aLength)
Create an empty table according to the specified definition.
cpl_array * hermit[MAX_HERMIT_ORDER]
coefficients for the damped gauss-hermitean parametrization
Definition: muse_lsf.h:66
cpl_table * muse_sky_continuum_load(muse_processing *aProcessing)
Load the SKY_CONTINUUM spectrum.
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.
Definition: muse/muse_lsf.c:75
cpl_array * sensitivity
Relative detector sensitivity parametrization.
Definition: muse_lsf.h:58
cpl_array * lsf_width
LSF width.
Definition: muse_lsf.h:64
cpl_table * lines
Table of Atmospheric emission lines and their intensities.
Definition: muse_sky.h:61
Optimization control parameters.
Definition: muse_optimize.h:32
const muse_cpltable_def muse_fluxspectrum_def[]
Definition of the flux spectrum table structure.
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.
void muse_sky_master_delete(muse_sky_master *)
Delete a MASTER SKY structure.
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".
muse_sky_master * muse_sky_master_fit(const cpl_array *aLambda, const cpl_array *aData, const cpl_array *aStat, const cpl_table *aLines)
Fit all entries of the pixel table to the master sky.
cpl_error_code muse_cpltable_copy_array(cpl_table *aTable, const char *aColumn, const cpl_array *aArray)
Copy an array into a table.
cpl_array * muse_cplarray_diff(const cpl_array *aArray, int aOffset)
Build the difference of any element and one of the next elements.
cpl_error_code muse_sky_lines_cut(cpl_table *, double)
Remove all lines below a certain flux limit.
cpl_frameset * inframes
muse_sky_master * muse_sky_master_load(muse_processing *aProcessing)
Load SKY_LINES, SKY_CONTINUUM, and LSF_PROFILE into a structure.
cpl_array * muse_sky_apply_lsf(const cpl_array *, const cpl_table *, const muse_lsf_params *)
Apply the LSF parameters to a spectrum.
cpl_table * continuum
Continuum flux table
Definition: muse_sky.h:63
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
Definition: muse_utils.c:158
Structure definition of detector (slice) parameters.
Definition: muse_lsf.h:50
cpl_size muse_cplarray_find_sorted(const cpl_array *aArray, double aValue)
Find a row in an array.
muse_lsf_params ** lsf
LSF parameter for the resampled spectrum.
Definition: muse_sky.h:65
void muse_lsf_params_delete(muse_lsf_params **aParams)
Delete an allocated array of muse_lsf_params structure.
muse_sky_master * muse_sky_master_new(void)
Create a muse_sky_master structure.