ERIS Pipeline Reference Manual 1.9.2
sc_skycorr.c
Go to the documentation of this file.
1/*
2 * This file is part of the SKYCORR software package.
3 * Copyright (C) 2009-2013 European Southern Observatory
4 *
5 * This programme is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This programme is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this programme. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19
37/*****************************************************************************
38 * INCLUDES *
39 ****************************************************************************/
40
41#include <sc_skycorr.h>
42
43
44/*****************************************************************************
45 * CODE *
46 ****************************************************************************/
47
48cpl_error_code sc_skycorr(cpl_parameterlist *parlist,
49 cpl_table *scispec,
50 cpl_table *skyspec,
51 int product_depth)
52{
74 cpl_error_code status = CPL_ERROR_NONE;
75 cpl_table *groups, *linetab;
76 char errtxt[SC_MAXLEN];
77
78 /* Read line groups from ASCII file and adapt it to observing
79 conditions */
80 groups = cpl_table_new(0);
81 if ((status = sc_lines(groups, parlist)) != CPL_ERROR_NONE) {
82 cpl_table_delete(groups);
83 return status;
84 }
85
86 /* Subtraction of continuum from science and sky spectrum and estimation
87 of line FWHM in sky spectrum */
88
89 /* Prepare science spectrum */
90// cpl_msg_debug(cpl_func, "Science spectrum:");
91 linetab = cpl_table_new(0);
93 sc_skycorr_subcont(scispec, linetab, parlist, groups);
94 cpl_table_delete(linetab);
95 status = cpl_error_get_code();
96 if (status != CPL_ERROR_NONE) {
97 sprintf(errtxt, "%s: error while separating lines and continuum of "
98 "science spectrum", SC_ERROR_EIS_TXT);
99 cpl_error_set_message(cpl_func, (cpl_error_code)SC_ERROR_EIS, "%s", errtxt);
100 return status; // agudo
101 }
102
103 /* Prepare sky spectrum */
104// cpl_msg_debug(cpl_func, "Sky spectrum:");
105 linetab = cpl_table_new(0);
107 status = sc_skycorr_subcont(skyspec, linetab, parlist, groups);
108 cpl_table_delete(linetab); linetab = NULL;
109 if (status != CPL_ERROR_NONE) {
110 sprintf(errtxt, "%s: error while separating lines and continuum of "
111 "sky spectrum", SC_ERROR_EIS_TXT);
112 cpl_error_set_message(cpl_func, (cpl_error_code)SC_ERROR_EIS, "%s", errtxt);
113 cpl_table_delete(groups);
114 return status; // agudo
115 }
116
117 /* CMPFIT-based fitting procedure to adapt the sky line spectrum to the
118 science line spectrum */
119 status = sc_skycorr_fit(scispec, skyspec, groups, parlist, product_depth);
120 if (status != CPL_ERROR_NONE) {
121 cpl_table_delete(groups);
122 return status;
123 }
124
125 /* Free allocated memory */
126 cpl_table_delete(groups);
127
128 /* Perform sky subtraction */
129 status = sc_skycorr_subsky(scispec);
130
131 return status;
132}
133
134cpl_error_code sc_skycorr_subcont(cpl_table *spec, cpl_table *linetab,
135 cpl_parameterlist *parlist,
136 const cpl_table *groups)
137{
179 cpl_error_code status = CPL_ERROR_NONE;
180 cpl_parameter *p;
181 //cpl_parameterlist *plottags;
182 cpl_array *mask;
183 int it = 0, i = 0, n = 10, nrow = 0, j = 0, niso = 0, search = 0;
184 double fwhm0 = 0., fwhm = 1000., eps = 1e-2, tmp = 0., rms = 0.;
185 double fluxlim = 0., minfluxlim = 0.005, maxfluxlim = 0.1;
186
187 /* Print info message */
188// cpl_msg_debug(cpl_func, "Identify lines, estimate FWHM, "
189// "and subtract continuum");
190
191 /* Get FWHM from parameter list */
192 p = cpl_parameterlist_find(parlist, "fwhm");
193 fwhm0 = cpl_parameter_get_double(p);
194
195 /* Take FWHM from parameter list as start value if already fitted */
196 p = cpl_parameterlist_find(parlist, "iteration");
197 it = cpl_parameter_get_int(p);
198 if (it > 0) {
199 fwhm = fwhm0;
200 }
201if (cpl_error_get_code() != CPL_ERROR_NONE) {
202 return cpl_error_get_code();
203}
204 /* Get convergence criterion for line width */
205 p = cpl_parameterlist_find(parlist, "ltol");
206 eps = cpl_parameter_get_double(p);
207
208 /* Iterative line identification and FWHM estimation */
209 for (tmp = fwhm, i = 0; i < n; i++, tmp = fwhm) {
210 /* Find emission lines in spectrum */
211 status = sc_specdiss_find_emissionlines(spec, linetab, parlist, groups);
212 if (status != CPL_ERROR_NONE) {
213 return status;
214 }
215
216 /* Subtract continuum in spectrum */
217 status = sc_contsub(spec);
218 if (status != CPL_ERROR_NONE) {
219 return status;
220 }
221
222 /* Count isolated lines */
223 nrow = cpl_table_get_nrow(linetab);
224 for (j = 0, niso = 0; j < nrow; j++) {
225 if (cpl_table_get_int(linetab, "isol_flag", j, NULL) != 0) {
226 niso++;
227 }
228 }
229
230 /* No isolated lines -> break */
231 if (niso == 0) {
232 if (it == 0) {
233 fwhm = fwhm0;
234 }
235 cpl_msg_warning(cpl_func, "No isolated lines found -> "
236 "Take initial FWHM");
237 break;
238 }
239
240 /* Estimate FWHM of lines in spectrum */
241 status = sc_fwhmest(&fwhm, &rms, spec, linetab, parlist);
242 if (status != CPL_ERROR_NONE) {
243 return status;
244 }
245
246 /* Update FWHM in parlist */
247 p = cpl_parameterlist_find(parlist, "fwhm");
248 cpl_parameter_set_double(p, fwhm);
249
250 /* Check convergence */
251 if (fabs((fwhm - tmp) / tmp) < eps) {
252 break;
253 }
254 }
255
256 /* Save pixel class column */
257 mask = cpl_array_new(0, CPL_TYPE_INT);
258 status = sc_basic_col2arr(mask, spec, "class");
259 if (status != CPL_ERROR_NONE) {
260 return status;
261 }
262
263 /* Get relative peak flux limit from parameter list */
264 p = cpl_parameterlist_find(parlist, "fluxlim");
265 fluxlim = cpl_parameter_get_double(p);
266
267 /* Check whether automatic search is desired */
268 if (fluxlim < 0) {
269 fluxlim = minfluxlim;
270 search = 1;
271 }
272
273 /* Get line and continuum pixels (iterative approach if desired) */
274 do {
275 /* Get initial pixel class column */
276 status = sc_basic_arr2col(spec, "class", mask);
277 if (status != CPL_ERROR_NONE) {
278 cpl_array_delete(mask);
279 return status;
280 }
281
282 /* Identify continuum windows by means of airglow line list */
283 status = sc_contsub_identcont(spec, groups, linetab, fluxlim,
284 parlist);
285 if (status != CPL_ERROR_NONE) {
286 cpl_array_delete(mask);
287 return status;
288 }
289
290 /* Modify lower flux limit for line peaks */
291 fluxlim *= 2;
292 } while (sc_contsub_check(spec) != 0 && fluxlim <= maxfluxlim && search == 1);
293
294 status = cpl_error_get_code();
295 if (status != CPL_ERROR_NONE) {
296 return status;
297 }
298
299 /* Info message on fluxlim parameter */
300// if (search == 1) {
301// cpl_msg_debug(cpl_func, "Search for line threshold: FLUXLIM = %g",
302// fluxlim / 2);
303// }
304
305 /* Avoid identification of lines in the thermal IR */
306 status = sc_contsub_skipthermir(spec);
307 if (status != CPL_ERROR_NONE) {
308 return status;
309 }
310
311 /* Cleanup */
312 cpl_array_delete(mask); mask = NULL;
313
314 /* Plotting spectrum with identified line peaks */
315 //plottags=cpl_parameterlist_new();
316 //sc_setplottags_single_spec(plottags, "lambda", "cflux", "CFLUX before",
317 // "lambda", "cflux", parlist);
318 //sc_plot_single_spec(spec, plottags);
319 //cpl_parameterlist_delete(plottags);
320
321 /* Subtract continuum in spectrum */
322 status = sc_contsub(spec);
323 if (status != CPL_ERROR_NONE) {
324 return status;
325 }
326
327 return status;
328}
329
330cpl_error_code sc_skycorr_fit(cpl_table *scispec, cpl_table *skyspec,
331 cpl_table *groups, cpl_parameterlist *parlist,
332 int product_depth)
333{
356 cpl_error_code status = CPL_ERROR_NONE;
357 cpl_table *fitpar;
358 mp_result result;
359 int nsci = 0;
360// double ts = 0., te = 0., runtime = 0.;
361
362 /* Create columns for modification of sky spectrum */
363 cpl_table_new_column(skyspec, "mlambda", CPL_TYPE_DOUBLE);
364 cpl_table_new_column(skyspec, "mlflux", CPL_TYPE_DOUBLE);
365 if (cpl_table_has_column(skyspec, "dflux") == 1) {
366 cpl_table_new_column(skyspec, "mdflux", CPL_TYPE_DOUBLE);
367 }
368 cpl_table_new_column(skyspec, "mweight", CPL_TYPE_DOUBLE);
369 cpl_table_new_column(skyspec, "mpix", CPL_TYPE_INT);
370 cpl_table_new_column(skyspec, "dpix", CPL_TYPE_DOUBLE);
371 cpl_table_new_column(skyspec, "frat", CPL_TYPE_DOUBLE);
372
373 /* Create columns for comparison of science and sky spectrum */
374 cpl_table_new_column(scispec, "mcflux", CPL_TYPE_DOUBLE);
375 cpl_table_new_column(scispec, "mlflux", CPL_TYPE_DOUBLE);
376 cpl_table_new_column(scispec, "mflux", CPL_TYPE_DOUBLE);
377 if (cpl_table_has_column(skyspec, "dflux") == 1) {
378 cpl_table_new_column(scispec, "mdflux", CPL_TYPE_DOUBLE);
379 }
380 if (cpl_table_has_column(skyspec, "mask") == 1) {
381 cpl_table_new_column(scispec, "mmask", CPL_TYPE_INT);
382 }
383 cpl_table_new_column(scispec, "mweight", CPL_TYPE_DOUBLE);
384 cpl_table_new_column(scispec, "sigclip", CPL_TYPE_INT);
385 cpl_table_new_column(scispec, "cweight", CPL_TYPE_DOUBLE);
386 cpl_table_new_column(scispec, "dev", CPL_TYPE_DOUBLE);
387
388 /* Initialise sigclip column with 1 (= ejected) */
389 nsci = cpl_table_get_nrow(scispec);
390 cpl_table_fill_column_window(scispec, "sigclip", 0, nsci, 1);
391
392 /* Initialise fit parameter table */
393 fitpar = cpl_table_new(0);
394
395 /* Prepare the line group weights of each pixel of the input sky
396 spectrum */
397 if ((status = sc_weights(skyspec, fitpar, groups, parlist)) !=
398 CPL_ERROR_NONE) {
399 cpl_table_delete(fitpar);
400 return status;
401 }
402
403 /* Start run time measurement */
404// ts = cpl_test_get_walltime();
405
406 /* Start CMPFIT and compare resulting deviations */
407 status = sc_mpfit(&result, scispec, skyspec, fitpar, parlist);
408
409 /* Get CMPFIT run time in s */
410// te = cpl_test_get_walltime();
411// runtime = te - ts;
412
413 /* Print fit results */
414// cpl_msg_debug(cpl_func, "FIT RESULTS:");
415// cpl_msg_debug(cpl_func, "status: %d", result.status);
416// if (status == CPL_ERROR_NONE) {
417// cpl_msg_debug(cpl_func, "npar: %d", result.npar);
418// cpl_msg_debug(cpl_func, "npix: %d", result.nfunc);
419// cpl_msg_debug(cpl_func, "niter: %d", result.niter);
420// cpl_msg_debug(cpl_func, "nfev: %d", result.nfev);
421// cpl_msg_debug(cpl_func, "fittime: %.2f s", runtime);
422// cpl_msg_debug(cpl_func, "orignorm: %.3e", result.orignorm);
423// cpl_msg_debug(cpl_func, "bestnorm: %.3e", result.bestnorm);
424// }
425 if ((product_depth == 3) && (result.status != 1)) {
426 cpl_msg_debug(cpl_func, ">>>>> skycorr fit result: %d", result.status);
427 }
428// if (result.status == MP_OK_DIR) {
429// cpl_msg_info(cpl_func, "############# got status = MP_OK_DIR -> should be fixed");
430// cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_OUTPUT);
431// status = CPL_ERROR_ILLEGAL_OUTPUT;
432// } else if (result.status <= 0) {
433// cpl_msg_info(cpl_func, "############# got status <= 0 -> bad, not fixed");
434// cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_OUTPUT);
435// status = CPL_ERROR_ILLEGAL_OUTPUT;
436// } else if (result.status > 1) {
437// cpl_msg_info(cpl_func, "############# got status > 1 -> what? bad? ok?");
440// }
441
442 /* Free allocated memory */
443 cpl_table_delete(fitpar);
444 sc_mpfit_freememresult(&result);
445
446 return status;
447}
448
449
450cpl_error_code sc_skycorr_subsky(cpl_table *scispec)
451{
472 cpl_error_code status = CPL_ERROR_NONE;
473 int nrow = 0, i = 0;
474 int *mmask = NULL, *mask = NULL, *scmask = NULL;
475 double *mweight = NULL, *dflux = NULL, *mdflux = NULL, *scdflux = NULL;
476
477 /* Get number of rows in science spectrum table */
478 nrow = cpl_table_get_nrow(scispec);
479
480 /* Calculate combined sky line and continuum flux */
481 cpl_table_fill_column_window(scispec, "mflux", 0, nrow, 0.);
482 cpl_table_add_columns(scispec, "mflux", "mcflux");
483 cpl_table_add_columns(scispec, "mflux", "mlflux");
484
485 /* Derive mask for sky spectrum if present */
486 if (cpl_table_has_column(scispec, "mask") == 1) {
487 cpl_table_fill_column_window(scispec, "mmask", 0, nrow, 0);
488 mweight = cpl_table_get_data_double(scispec, "mweight");
489 mmask = cpl_table_get_data_int(scispec, "mmask");
490 for (i = 0; i < nrow; i++) {
491 if (mweight[i] == 0.) {
492 mmask[i] = 0;
493 } else {
494 mmask[i] = 1;
495 }
496 }
497 }
498
499 /* Create column for sky-subtracted flux and initialise it with
500 uncorrected flux */
501 cpl_table_duplicate_column(scispec, "scflux", scispec, "flux");
502
503 /* Create column for flux errors after sky subtraction and initialise it
504 with input flux errors if present */
505 if (cpl_table_has_column(scispec, "dflux") == 1) {
506 cpl_table_duplicate_column(scispec, "scdflux", scispec, "dflux");
507 }
508
509 /* Create column for mask after sky subtraction and initialise it with
510 input mask if present */
511 if (cpl_table_has_column(scispec, "mask") == 1) {
512 cpl_table_duplicate_column(scispec, "scmask", scispec, "mask");
513 }
514
515 /* Leave routine in the case of errors */
516 if ((status = cpl_error_get_code()) != CPL_ERROR_NONE) {
517 return status;
518 }
519
520 /* Subtract sky continuum and best-fit sky line flux */
521 cpl_table_subtract_columns(scispec, "scflux", "mflux");
522
523 /* Derive errors for sky-subtracted flux if errors are present in the
524 input data */
525 if (cpl_table_has_column(scispec, "dflux") == 1) {
526 dflux = cpl_table_get_data_double(scispec, "dflux");
527 mdflux = cpl_table_get_data_double(scispec, "mdflux");
528 scdflux = cpl_table_get_data_double(scispec, "scdflux");
529 for (i = 0; i < nrow; i++) {
530 scdflux[i] = sqrt(dflux[i] * dflux[i] + mdflux[i] * mdflux[i]);
531 }
532 }
533
534 /* Derive combined mask if masks are present in the input data */
535 if (cpl_table_has_column(scispec, "mask") == 1) {
536 mask = cpl_table_get_data_int(scispec, "mask");
537 mmask = cpl_table_get_data_int(scispec, "mmask");
538 scmask = cpl_table_get_data_int(scispec, "scmask");
539 for (i = 0; i < nrow; i++) {
540 if (mask[i] == 1 && mmask[i] == 1) {
541 scmask[i] = 1;
542 } else {
543 scmask[i] = 0;
544 }
545 }
546 }
547
548 return cpl_error_get_code();
549}
550
#define SC_MAXLEN
Definition: sc_basic.h:94
cpl_error_code sc_basic_col2arr(cpl_array *arr, const cpl_table *tab, const char *colname)
Definition: sc_basic.c:1652
cpl_error_code sc_basic_arr2col(cpl_table *tab, const char *colname, const cpl_array *arr)
Definition: sc_basic.c:1757
int sc_contsub_check(cpl_table *spec)
Definition: sc_contsub.c:422
cpl_error_code sc_contsub_skipthermir(cpl_table *spec)
Definition: sc_contsub.c:497
cpl_error_code sc_contsub_identcont(cpl_table *spec, const cpl_table *groups, const cpl_table *linetab, const double fluxlim, const cpl_parameterlist *parlist)
Definition: sc_contsub.c:171
cpl_error_code sc_contsub(cpl_table *spec)
Definition: sc_contsub.c:50
cpl_error_code sc_fwhmest(double *fwhm, double *rms, cpl_table *spec, cpl_table *lines, const cpl_parameterlist *parlist)
Definition: sc_fwhmest.c:49
cpl_error_code sc_lines(cpl_table *groups, cpl_parameterlist *parlist)
Definition: sc_lines.c:48
cpl_error_code sc_mpfit(mp_result *result, cpl_table *scispec, cpl_table *skyspec, cpl_table *fitpar, const cpl_parameterlist *parlist)
Definition: sc_mpfit.c:60
cpl_error_code sc_mpfit_freememresult(mp_result *result)
Definition: sc_mpfit.c:1502
cpl_error_code sc_skycorr(cpl_parameterlist *parlist, cpl_table *scispec, cpl_table *skyspec, int product_depth)
Definition: sc_skycorr.c:48
cpl_error_code sc_skycorr_subcont(cpl_table *spec, cpl_table *linetab, cpl_parameterlist *parlist, const cpl_table *groups)
Definition: sc_skycorr.c:134
cpl_error_code sc_skycorr_fit(cpl_table *scispec, cpl_table *skyspec, cpl_table *groups, cpl_parameterlist *parlist, int product_depth)
Definition: sc_skycorr.c:330
cpl_error_code sc_skycorr_subsky(cpl_table *scispec)
Definition: sc_skycorr.c:450
void sc_specdiss_init_linetab(cpl_table *linetab)
Definition: sc_specdiss.c:974
cpl_error_code sc_specdiss_find_emissionlines(cpl_table *input_spectrum, cpl_table *linetab, cpl_parameterlist *parlist, const cpl_table *groups)
Definition: sc_specdiss.c:59
cpl_error_code sc_weights(cpl_table *skyspec, cpl_table *fitpar, cpl_table *groups, cpl_parameterlist *parlist)
Definition: sc_weights.c:49