MOONS Pipeline Reference Manual 0.13.1
moo_skycorr.c
1/*
2 * This file is part of the MOONS Pipeline
3 * Copyright (C) 2002-2016 European Southern Observatory
4 *
5 * This program 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 program 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 program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24/*-----------------------------------------------------------------------------
25 Includes
26 -----------------------------------------------------------------------------*/
27
28#include "math.h"
29#include <cpl.h>
30#include "moo_skycorr.h"
31#include "sc_skycorr.h"
32#include "hdrl_types.h"
33#include "moo_params.h"
34#include "moo_pfits.h"
35#include "moo_utils.h"
36/*----------------------------------------------------------------------------*/
40/*----------------------------------------------------------------------------*/
41
44static cpl_table *
45_moo_spectrum_to_table(hdrl_image *himg,
46 int index,
47 double crpix1,
48 double crval1,
49 double cd1_1,
50 cpl_parameterlist *parlist)
51{
52 cpl_table *result = NULL;
53 cpl_parameter *p;
54 char errtxt[SC_MAXLEN];
55 double meanlam = 0.;
56
57 cpl_ensure(himg != NULL, CPL_ERROR_NULL_INPUT, NULL);
58
59 int nrow = hdrl_image_get_size_x(himg);
60
61 result = cpl_table_new(nrow);
62
63 /* Get wavelength unit conversion factor */
64 p = cpl_parameterlist_find(parlist, "wlgtomicron");
65 double wlgtomicron = cpl_parameter_get_double(p);
66
67 cpl_table_new_column(result, "lambda", CPL_TYPE_DOUBLE);
68 cpl_table_new_column(result, "flux", CPL_TYPE_DOUBLE);
69 cpl_table_new_column(result, "dflux", CPL_TYPE_DOUBLE);
70 cpl_table_new_column(result, "mask", CPL_TYPE_INT);
71 cpl_table_new_column(result, "weight", CPL_TYPE_DOUBLE);
72
73 for (int i = 1; i <= nrow; i++) {
74 int rej;
75
76 double wave = crval1 + (i - crpix1) * cd1_1;
77 wave = wave * wlgtomicron;
78 hdrl_value val = hdrl_image_get_pixel(himg, i, index, &rej);
79
80 int rejected = rej != 0 || isnan(val.data);
81 cpl_table_set(result, "lambda", i - 1, wave);
82 cpl_table_set(result, "flux", i - 1, val.data);
83 cpl_table_set(result, "dflux", i - 1, val.error);
84 cpl_table_set(result, "mask", i - 1, !rejected);
85 if (val.error <= 0. || rejected) {
86 cpl_table_set(result, "weight", i - 1, 0.);
87 cpl_table_set(result, "flux", i - 1, 0.);
88 cpl_table_set(result, "dflux", i - 1, 0.);
89 }
90 else {
91 cpl_table_set(result, "weight", i - 1, 1. / val.error);
92 }
93 }
94
95 if (cpl_table_get_nrow(result) == 0) {
96 sprintf(errtxt, "%s: cpl_table *spec", SC_ERROR_NDA_TXT);
97 cpl_error_set_message(cpl_func, SC_ERROR_NDA, "%s", errtxt);
98 return NULL;
99 }
100
101 /* All weights = 0? */
102 if (cpl_table_get_column_max(result, "weight") == 0) {
103 sprintf(errtxt, "%s: cpl_table *spec (all weights = 0)",
104 SC_ERROR_IOV_TXT);
105 cpl_error_set_message(cpl_func, SC_ERROR_IOV, "%s", errtxt);
106 return NULL;
107 }
108
109 /* Set mean wavelength */
110 meanlam = 0.5 * (cpl_table_get(result, "lambda", 0, NULL) +
111 cpl_table_get(result, "lambda",
112 cpl_table_get_nrow(result) - 1, NULL));
113 p = cpl_parameterlist_find(parlist, "meanlam");
114 cpl_parameter_set_double(p, meanlam);
115
116
117 return result;
118}
119
120static cpl_error_code
121__mo_sc_readspec_header(cpl_parameterlist *parlist, cpl_propertylist *header)
122{
147 cpl_parameter *p;
148 cpl_property *prop;
149 cpl_type type;
150 char key[SC_NKEY][SC_LENLINE + 1] = { "", "", "" }, errtxt[SC_MAXLEN];
151 int i = 0, nerr = 0;
152 double val = 0.;
153
154 /* Parameter names related to FITS keywords */
155 char keypar[SC_NKEY][SC_LENLINE + 1] = { "date_key", "time_key",
156 "telalt_key" };
157 char valpar[SC_NKEY][SC_LENLINE + 1] = { "date_val", "time_val",
158 "telalt_val" };
159
160 for (i = 0; i < SC_NKEY; i++) {
161 /* Get value from parameter list */
162 p = cpl_parameterlist_find(parlist, valpar[i]);
163 val = cpl_parameter_get_double(p);
164
165 /* Get name of required FITS keyword */
166 p = cpl_parameterlist_find(parlist, keypar[i]);
167 strncpy(key[i], cpl_parameter_get_string(p), SC_LENLINE + 1);
168
169 /* Write info message */
170 //cpl_msg_info(cpl_func, "Read keyword %s", key[i]);
171
172 /* Get FITS keyword */
173 prop = cpl_propertylist_get_property(header, key[i]);
174
175 if (prop == NULL && val == -1.) {
176 /* Set error message in the case of missing keyword */
177 nerr++;
178 sprintf(errtxt, "%s: (keyword %s not found)", SC_ERROR_UFS_TXT,
179 key[i]);
180 cpl_error_set_message(cpl_func, SC_ERROR_UFS, "%s", errtxt);
181 }
182 else {
183 /* Take FITS keyword only if parameter value was not given
184 manually */
185 if (val == -1.) {
186 /* Check for type */
187 type = cpl_property_get_type(prop);
188 if (type == CPL_TYPE_DOUBLE) {
189 val = cpl_property_get_double(prop);
190 }
191 else if (type == CPL_TYPE_FLOAT) {
192 val = (double)cpl_property_get_float(prop);
193 }
194 else if (type == CPL_TYPE_INT) {
195 val = (double)cpl_property_get_int(prop);
196 }
197 else {
198 nerr++;
199 sprintf(errtxt, "%s: (non-numerical keyword %s)",
200 SC_ERROR_UFS_TXT, key[i]);
201 cpl_error_set_message(cpl_func, SC_ERROR_UFS, "%s", errtxt);
202 continue;
203 }
204 }
205
206 /* MJD -> date in years (if required; save MJD before) */
207 if (i == 0 && val > 3000.) {
208 p = cpl_parameterlist_find(parlist, "mjd");
209 cpl_parameter_set_double(p, val);
210 val = sc_basic_mjd2fracyear(val);
211 }
212
213 /* Write new value into parameter list */
214 p = cpl_parameterlist_find(parlist, valpar[i]);
215 cpl_parameter_set_double(p, val);
216 }
217 }
218
219 /* Return SC_ERROR_UFS in the case of keyword mismatch */
220 if (nerr > 0) {
221 return SC_ERROR_UFS;
222 }
223
224 return CPL_ERROR_NONE;
225}
226
227static cpl_error_code
228_moo_sc_lines_readlist(cpl_table *groups, const char *linetabfile)
229{
246 FILE *stream;
247 char errtxt[SC_MAXLEN], str[SC_LENLINE + 2];
248 cpl_boolean isoutrange = CPL_FALSE;
249 int nhead = 0, nrec = 0, feat = 0, syst = 0, agroup = 0, bgroup = 0;
250 int ncol0 = 0, ncolmin = 7, i = 0, ncol = 0;
251 double lam = 0., flux = 0., trans = 0.;
252
253 /* Create CPL table columns */
254 cpl_table_new_column(groups, "lambda", CPL_TYPE_DOUBLE);
255 cpl_table_new_column(groups, "flux", CPL_TYPE_DOUBLE);
256 cpl_table_new_column(groups, "trans", CPL_TYPE_DOUBLE);
257 cpl_table_new_column(groups, "feat", CPL_TYPE_INT);
258 cpl_table_new_column(groups, "system", CPL_TYPE_INT);
259 cpl_table_new_column(groups, "groupA", CPL_TYPE_INT);
260 cpl_table_new_column(groups, "groupB", CPL_TYPE_INT);
261
262 if ((stream = fopen(linetabfile, "r")) == NULL) {
263 sprintf(errtxt, "%s: %s", SC_ERROR_FOF_TXT, linetabfile);
264 return cpl_error_set_message(cpl_func, SC_ERROR_FOF, "%s", errtxt);
265 }
266
267 /* Write info message */
268 //cpl_msg_info(cpl_func, "Read line list %s", linetabfile);
269
270 /* Find number of header and data lines */
271 while (fgets(str, SC_LENLINE + 2, stream) != NULL) {
272 if (str[0] == '#') {
273 nhead++;
274 if (nrec != 0) {
275 fclose(stream);
276 sprintf(errtxt, "%s: %s (comment line in data part)",
277 SC_ERROR_UFS_TXT, linetabfile);
278 return cpl_error_set_message(cpl_func, SC_ERROR_UFS, "%s",
279 errtxt);
280 }
281 }
282 else if (isdigit(str[0]) || isspace(str[0]) || str[0] == '-') {
283 if (nrec == 0) {
284 /* Number of values per line */
285 ncol0 = sscanf(str, "%le %le %le %d %d %d %d", &lam, &flux,
286 &trans, &feat, &syst, &agroup, &bgroup);
287 if (ncol0 == 0) {
288 fclose(stream);
289 sprintf(errtxt, "%s: %s (empty line)", SC_ERROR_UFS_TXT,
290 linetabfile);
291 return cpl_error_set_message(cpl_func, SC_ERROR_UFS, "%s",
292 errtxt);
293 }
294 else if (ncol0 < ncolmin) {
295 fclose(stream);
296 sprintf(errtxt, "%s: %s (too low number of columns)",
297 SC_ERROR_UFS_TXT, linetabfile);
298 return cpl_error_set_message(cpl_func, SC_ERROR_UFS, "%s",
299 errtxt);
300 }
301 }
302 nrec++;
303 }
304 else {
305 fclose(stream);
306 sprintf(errtxt, "%s: %s (unexpected first character at line)",
307 SC_ERROR_UFS_TXT, linetabfile);
308 return cpl_error_set_message(cpl_func, SC_ERROR_UFS, "%s", errtxt);
309 }
310 }
311 rewind(stream);
312
313 /* No data points */
314 if (nrec == 0) {
315 fclose(stream);
316 sprintf(errtxt, "%s: %s (no data)", SC_ERROR_UFS_TXT, linetabfile);
317 return cpl_error_set_message(cpl_func, SC_ERROR_UFS, "%s", errtxt);
318 }
319
320 /* Resize output table */
321 cpl_table_set_size(groups, nrec);
322
323 /* Skip header */
324 for (i = 0; i < nhead; i++) {
325 if (fgets(str, SC_LENLINE + 2, stream)) {
326 };
327 }
328
329 /* Read line data from file and write it to CPL table */
330
331 for (i = 0; i < nrec; i++) {
332 ncol = fscanf(stream, "%le %le %le %d %d %d %d", &lam, &flux, &trans,
333 &feat, &syst, &agroup, &bgroup);
334
335 if (ncol != ncol0) {
336 cpl_table_set_size(groups, 0);
337 fclose(stream);
338 sprintf(errtxt, "%s: %s (unexpected number of values at line)",
339 SC_ERROR_UFS_TXT, linetabfile);
340 return cpl_error_set_message(cpl_func, SC_ERROR_UFS, "%s", errtxt);
341 }
342
343 cpl_table_set(groups, "lambda", i, lam);
344 cpl_table_set(groups, "flux", i, flux);
345 cpl_table_set(groups, "trans", i, trans);
346 cpl_table_set(groups, "feat", i, feat);
347 cpl_table_set(groups, "system", i, syst);
348 cpl_table_set(groups, "groupA", i, agroup);
349 if (syst > 0 && bgroup == 0) {
350 /* Negative numbers for molecular lines without B group number */
351 cpl_table_set(groups, "groupB", i, -syst);
352 }
353 else {
354 cpl_table_set(groups, "groupB", i, bgroup);
355 }
356
357 if (flux < 0.) {
358 flux = 0.;
359 isoutrange = CPL_TRUE;
360 }
361
362 if (trans < 0.) {
363 trans = 0.;
364 isoutrange = CPL_TRUE;
365 }
366
367 if (trans > 1.) {
368 trans = 1.;
369 isoutrange = CPL_TRUE;
370 }
371
372 if (feat < 1) {
373 feat = 1;
374 isoutrange = CPL_TRUE;
375 }
376
377 if (agroup < 0) {
378 agroup = 0;
379 isoutrange = CPL_TRUE;
380 }
381
382 if (bgroup < 0) {
383 bgroup = 0;
384 isoutrange = CPL_TRUE;
385 }
386 }
387
388 fclose(stream);
389
390 if (isoutrange == CPL_TRUE) {
391 cpl_msg_warning(cpl_func,
392 "%s: Input value(s) out of range -> "
393 "Take lowest/highest allowed value(s)",
394 linetabfile);
395 }
396
397 return CPL_ERROR_NONE;
398}
399
400static cpl_error_code
401_moo_sc_lines_readsolflux(cpl_parameterlist *parlist, const char *soldatfile)
402{
423 FILE *stream;
424 cpl_parameter *p;
425 char soldatsource[SC_MAXLEN];
426 char errtxt[SC_MAXLEN], str[SC_LENLINE + 2];
427 int year = 0, month = 0, i = 0, y = 0, m = 0, ncol = 0, ncolmin = 5;
428 double obsflux = 0., adjflux = 0., absflux = 0., solflux = -1.;
429
430 /* Get year and month from parameter list */
431 p = cpl_parameterlist_find(parlist, "year");
432 year = cpl_parameter_get_int(p);
433 p = cpl_parameterlist_find(parlist, "month");
434 month = cpl_parameter_get_int(p);
435
436 /* Set solar radio flux to -1 to indicate if month is not found */
437 p = cpl_parameterlist_find(parlist, "solflux");
438 cpl_parameter_set_double(p, -1.);
439
440 /* Get source of the solar radio flux data from parameter list */
441 p = cpl_parameterlist_find(parlist, "soldatsource");
442 strncpy(soldatsource, cpl_parameter_get_string(p), SC_MAXLEN);
443
444 /* Take average solar radio flux if no data source */
445 if ((strcmp(soldatsource, "LOCAL") != 0 &&
446 strcmp(soldatsource, "WEB") != 0) ||
447 (strcmp(soldatsource, "WEB") == 0 &&
448 ((year == 1947 && month == 1) || year < 1947))) {
449 p = cpl_parameterlist_find(parlist, "solflux");
450 cpl_parameter_set_double(p, 130.);
451 /*cpl_msg_warning(cpl_func, "No source for solar radio flux available"
452 " -> Take average of 130 sfu");*/
453 return CPL_ERROR_NONE;
454 }
455
456 /* Write info message */
457 /*cpl_msg_info(cpl_func, "Get solar radio flux for %d/%d from %s", month,
458 year, soldatfile);*/
459
460 /* Open file with sky line data */
461 if ((stream = fopen(soldatfile, "r")) == NULL) {
462 sprintf(errtxt, "%s: %s", SC_ERROR_FOF_TXT, soldatfile);
463 return cpl_error_set_message(cpl_func, SC_ERROR_FOF, "%s", errtxt);
464 }
465
466 /* Skip header */
467 for (i = 0; i < 2; i++) {
468 if (fgets(str, SC_LENLINE + 2, stream)) {
469 };
470 }
471
472 /* Read file and find solar radio flux for given year and month */
473
474 while (fgets(str, SC_LENLINE + 2, stream) != NULL) {
475 if (isdigit(str[0]) || isspace(str[0])) {
476 /* Read values */
477 ncol = sscanf(str, "%d %d %le %le %le", &y, &m, &obsflux, &adjflux,
478 &absflux);
479
480 /* Check number of values per line */
481 if (ncol == 0) {
482 fclose(stream);
483 sprintf(errtxt, "%s: %s (empty line)", SC_ERROR_UFS_TXT,
484 soldatfile);
485 return cpl_error_set_message(cpl_func, SC_ERROR_UFS, "%s",
486 errtxt);
487 }
488 else if (ncol < ncolmin) {
489 fclose(stream);
490 sprintf(errtxt, "%s: %s (too low number of columns)",
491 SC_ERROR_UFS_TXT, soldatfile);
492 return cpl_error_set_message(cpl_func, SC_ERROR_UFS, "%s",
493 errtxt);
494 }
495
496 /* Check validity of values */
497 if (y < 1947 || m < 1 || m > 12 || obsflux < 0.) {
498 fclose(stream);
499 sprintf(errtxt, "%s: %s (invalid value(s))", SC_ERROR_UFS_TXT,
500 soldatfile);
501 return cpl_error_set_message(cpl_func, SC_ERROR_UFS, "%s",
502 errtxt);
503 }
504
505 /* Find solar radio flux for given year and month */
506 if (y == year && m == month) {
507 solflux = obsflux;
508 break;
509 }
510 }
511 else {
512 /* No digit or space at the beginning of the line */
513 fclose(stream);
514 sprintf(errtxt, "%s: %s (unexpected first character at line)",
515 SC_ERROR_UFS_TXT, soldatfile);
516 return cpl_error_set_message(cpl_func, SC_ERROR_UFS, "%s", errtxt);
517 }
518 }
519
520 fclose(stream);
521
522 /* If the required month is not in the file on the web server, take the
523 last entry */
524 if (strcmp(soldatsource, "WEB") == 0) {
525 if ((month != 1 && m < month - 1 && y == year) ||
526 (month != 1 && y < year) ||
527 (month == 1 && m < 12 && y == year - 1) ||
528 (month == 1 && y < year - 1)) {
529 /* Warning message if last file entry is outdated */
530 cpl_msg_warning(cpl_func, "Solar radio fluxes until %d/%d only", m,
531 y);
532 }
533 if (obsflux != solflux) {
534 solflux = obsflux;
535 }
536 }
537
538 /* Write solar radio flux into parameter list */
539 p = cpl_parameterlist_find(parlist, "solflux");
540 cpl_parameter_set_double(p, floor(solflux + 0.5));
541
542 return CPL_ERROR_NONE;
543}
544
545static cpl_error_code
546_moo_sc_lines_getmodelbins(cpl_parameterlist *parlist,
547 const cpl_frame *solflux_frame)
548{
573 cpl_error_code status = CPL_ERROR_NONE;
574 cpl_parameter *p, *q;
575 char errtxt[SC_MAXLEN];
576 int year = 0, month = 0, day = 0, hh = 0, mm = 0;
577 int season = 0, timebin = 0;
578 double ss = 0., fracyear = 0., ut = 0., nlen = 0.;
579 double tlim1 = 0., tlim2 = 0.;
580 double nstart[6] = { 0.98, 0.48, -0.44, -0.57, -0.23, 0.29 };
581 double nend[6] = { 8.50, 9.29, 9.77, 10.07, 9.61, 8.60 };
582
583 /* Get date in years and UT time in s from parameter list */
584 p = cpl_parameterlist_find(parlist, "date_val");
585 fracyear = cpl_parameter_get_double(p);
586 p = cpl_parameterlist_find(parlist, "time_val");
587 ut = cpl_parameter_get_double(p) / 3600.;
588
589 /* Check for existence of date and time information */
590 if (fracyear < 0 || ut < 0) {
591 sprintf(errtxt,
592 "%s: cpl_parameterlist *parlist (invalid date_val "
593 "and/or time_val)",
594 SC_ERROR_IOV_TXT);
595 return cpl_error_set_message(cpl_func, SC_ERROR_IOV, "%s", errtxt);
596 }
597
598 /* Derive season bin */
599 sc_basic_fracyear2date(&year, &month, &day, &hh, &mm, &ss, &fracyear);
600 if (month == 12) {
601 season = 1;
602 }
603 else {
604 season = floor((float)month / 2) + 1;
605 }
606
607 /* Derive time bin */
608 if (ut > 16.) {
609 ut -= 24.;
610 }
611 nlen = nend[season - 1] - nstart[season - 1];
612 tlim1 = nstart[season - 1] + nlen / 3;
613 tlim2 = nend[season - 1] - nlen / 3;
614 if (ut < tlim1) {
615 timebin = 1;
616 }
617 else if (ut >= tlim2) {
618 timebin = 3;
619 }
620 else {
621 timebin = 2;
622 }
623
624 /* Write season and time bins into parameter list */
625 p = cpl_parameter_new_value("season", CPL_TYPE_INT, "", "", season);
626 cpl_parameterlist_append(parlist, p);
627 p = cpl_parameter_new_value("timebin", CPL_TYPE_INT, "", "", timebin);
628 cpl_parameterlist_append(parlist, p);
629
630 /* Write year and month into parameter list */
631 p = cpl_parameter_new_value("year", CPL_TYPE_INT, "", "", year);
632 cpl_parameterlist_append(parlist, p);
633 p = cpl_parameter_new_value("month", CPL_TYPE_INT, "", "", month);
634 cpl_parameterlist_append(parlist, p);
635
636 /* Take solar radio flux from parameter list if given */
637 q = cpl_parameterlist_find(parlist, "solflux");
638
639 if (cpl_parameter_get_double(q) >= 0) {
640 /*cpl_msg_info(cpl_func, "SOLFLUX = %g sfu",
641 cpl_parameter_get_double(q));*/
642 return CPL_ERROR_NONE;
643 }
644
645 /* Get solar radio flux for year and month from file in sysdata/ */
646 p = cpl_parameterlist_find(parlist, "soldatsource");
647 cpl_parameter_set_string(p, "LOCAL");
648 const char *solflux_filename = cpl_frame_get_filename(solflux_frame);
649 status = _moo_sc_lines_readsolflux(parlist, solflux_filename);
650
651 /* If reading fails, take flux from file on web server */
652 q = cpl_parameterlist_find(parlist, "solflux");
653
654 /* If the procedure fails, take average value of 130 sfu */
655 if (cpl_parameter_get_double(q) < 0) {
656 cpl_parameter_set_string(p, "NONE");
657 _moo_sc_lines_readsolflux(parlist, NULL);
658 }
659
660 /* Write info message */
661 q = cpl_parameterlist_find(parlist, "solflux");
662 //cpl_msg_info(cpl_func, "SOLFLUX = %g sfu", cpl_parameter_get_double(q));
663
664 return status;
665}
666
667static cpl_error_code
668_moo_sc_lines_readvarpar(cpl_array *varpar,
669 cpl_parameterlist *parlist,
670 const char *vardatfile)
671{
693 FILE *stream;
694 cpl_parameter *p;
695 scpar x[SC_MAXPAR], m[SC_MAXPAR];
696 char errtxt[SC_MAXLEN];
697 int n = SC_MAXPAR, nfeat = 0, nseason = 0, ntime = 0, season = 0;
698 int timebin = 0, i = 0, j = 0;
699 double alt = 0., solflux = 0., height = 0., scale = 0., cons = 0.;
700 double slope = 0., mean = 0., z = 0., cvr = 0., csol = 0.;
701
702 if ((stream = fopen(vardatfile, "r")) == NULL) {
703 sprintf(errtxt, "%s: %s", SC_ERROR_FOF_TXT, vardatfile);
704 return cpl_error_set_message(cpl_func, SC_ERROR_FOF, "%s", errtxt);
705 }
706
707 /* Write info message */
708 //cpl_msg_info(cpl_func, "Read line variability model file %s", vardatfile);
709
710 /* Read airglow scaling parameter file */
711
712 /* Read numbers for data set size */
713 sc_basic_readline(stream, x, &n);
714 nfeat = x[0].i;
715 sc_basic_readline(stream, x, &n);
716 nseason = x[0].i;
717 ntime = x[1].i;
718 //nbin = (nseason + 1) * (ntime + 1);
719
720 /* Return NULL vectors in the case of one or more zero for the data set
721 size */
722 if (nfeat == 0 || nseason == 0 || ntime == 0) {
723 fclose(stream);
724 sprintf(errtxt, "%s: %s (nfeat == 0 || nseason == 0 || ntime == 0)",
725 SC_ERROR_UFS_TXT, vardatfile);
726 return cpl_error_set_message(cpl_func, SC_ERROR_UFS, "%s", errtxt);
727 }
728
729 /* Get and check airglow model parameters */
730 p = cpl_parameterlist_find(parlist, "telalt_val");
731 alt = cpl_parameter_get_double(p);
732 p = cpl_parameterlist_find(parlist, "solflux");
733 solflux = cpl_parameter_get_double(p);
734 p = cpl_parameterlist_find(parlist, "season");
735 season = cpl_parameter_get_int(p);
736 p = cpl_parameterlist_find(parlist, "timebin");
737 timebin = cpl_parameter_get_int(p);
738 if (alt < 0. || alt > 90. || solflux < 0. || season < 0 ||
739 season > nseason || timebin < 0 || timebin > ntime) {
740 fclose(stream);
741 sprintf(errtxt,
742 "%s: cpl_parameterlist *parlist (telalt, solflux, "
743 "season, and/or timebin out of range) ",
744 SC_ERROR_IOV_TXT);
745 return cpl_error_set_message(cpl_func, SC_ERROR_IOV, "%s", errtxt);
746 }
747
748 /* Set size of varpar array */
749 cpl_array_set_size(varpar, nfeat);
750
751 /* Read data for each feature, extract bin data for selected time, and
752 fill CPL array with feature-specific flux correction factors */
753
754 for (i = 0; i < nfeat; i++) {
755 /* Time-independent parameters */
756 sc_basic_readline(stream, x, &n); // skip molmass
757 sc_basic_readline(stream, x, &n); // skip temp
758 sc_basic_readline(stream, x, &n);
759 height = x[0].d;
760 sc_basic_readline(stream, x, &n);
761 scale = x[0].d;
762 sc_basic_readline(stream, x, &n);
763 cons = x[0].d;
764 slope = x[1].d;
765
766 /* Mean value for selected time */
767 for (j = 0; j < ntime + 1; j++) {
768 sc_basic_readline(stream, m, &n);
769 if (j == timebin) {
770 mean = m[season].d;
771 }
772 }
773
774 /* Standard deviation for selected time (skipped) */
775 for (j = 0; j < ntime + 1; j++) {
776 sc_basic_readline(stream, m, &n);
777 }
778
779 /* Emission line brightness depending on airmass and layer height
780 (van Rhijn 1921) */
781 z = (90. - alt) * CPL_MATH_RAD_DEG;
782 cvr = 1 / sqrt(1 - pow((SC_ERAD / (SC_ERAD + height)) * sin(z), 2));
783
784 /* Influence of solar radio flux [sfu] */
785 csol = slope * solflux + cons;
786
787 /* Set feature-specific correction factors */
788 cpl_array_set(varpar, i, scale * cvr * csol * mean);
789 }
790
791 /* Close file */
792 fclose(stream);
793
794 return CPL_ERROR_NONE;
795}
796
797static cpl_error_code
798_moo_sc_lines(cpl_table *groups,
799 cpl_parameterlist *parlist,
800 const cpl_frame *solflux_frame,
801 const cpl_frame *airglow_group_frame,
802 const cpl_frame *airglow_var_frame)
803{
824 cpl_error_code status = CPL_ERROR_NONE;
825 cpl_array *varpar;
826
827 const char *airglow_group_filename =
828 cpl_frame_get_filename(airglow_group_frame);
829 const char *airglow_var_filename =
830 cpl_frame_get_filename(airglow_var_frame);
831
832 /* Read line groups from ASCII file */
833 if ((status = _moo_sc_lines_readlist(groups, airglow_group_filename)) !=
834 CPL_ERROR_NONE) {
835 return status;
836 }
837 /* Get season and time bins for airglow model from time of observation */
838 if ((status = _moo_sc_lines_getmodelbins(parlist, solflux_frame)) !=
839 CPL_ERROR_NONE) {
840 return status;
841 }
842
843 /* Read scaling factors of line variability classes from ASCII file */
844 varpar = cpl_array_new(0, CPL_TYPE_DOUBLE);
845 if ((status =
846 _moo_sc_lines_readvarpar(varpar, parlist, airglow_var_filename)) !=
847 CPL_ERROR_NONE) {
848 cpl_array_delete(varpar);
849 return status;
850 }
851
852 /* Modify line fluxes by multiplying factors depending on the variability
853 class and the airmass */
854
855 sc_lines_scalelines(groups, varpar, parlist);
856
857
858 /* Convert vacuum to air wavelengths in line group list if required */
859 if ((status = sc_lines_vactoair(groups, parlist)) != CPL_ERROR_NONE) {
860 cpl_array_delete(varpar);
861 return status;
862 }
863
864 /* Free allocated memory */
865 cpl_array_delete(varpar);
866
867 return CPL_ERROR_NONE;
868}
869
870static cpl_error_code
871_moo_table_to_spectrum(cpl_table *scispec,
872 hdrl_image *himg,
873 cpl_image *sky,
874 int index)
875{
890 cpl_ensure_code(himg != NULL, CPL_ERROR_NULL_INPUT);
891 cpl_ensure_code(sky != NULL, CPL_ERROR_NULL_INPUT);
892
893 int nrow = hdrl_image_get_size_x(himg);
894
895 for (int i = 1; i <= nrow; i++) {
896 int mask = cpl_table_get_int(scispec, "mask", i - 1, NULL);
897 double flux = NAN;
898 double err = NAN;
899 double sky_flux = cpl_table_get_double(scispec, "mflux", i - 1, NULL);
900 cpl_image_set(sky, i, index, sky_flux);
901
902 if (mask == 1) {
903 flux = cpl_table_get_double(scispec, "scflux", i - 1, NULL);
904 err = cpl_table_get_double(scispec, "scdflux", i - 1, NULL);
905 }
906 hdrl_value val;
907 val.data = flux;
908 val.error = err;
909 hdrl_image_set_pixel(himg, i, index, val);
910 }
911
912 return CPL_ERROR_NONE;
913}
914
915/*----------------------------------------------------------------------------*/
938cpl_error_code
939moo_skycorr(hdrl_image *rbn,
940 hdrl_image *sky,
941 int indextarg,
942 int indexrbn,
943 double crpix1,
944 double crval1,
945 double cd1_1,
946 cpl_propertylist *header,
947 const cpl_frame *solflux_frame,
948 const cpl_frame *airglow_group_frame,
949 const cpl_frame *airglow_var_frame,
950 moo_skycorr_params *params,
951 hdrl_image *sci,
952 cpl_image *sci_sky)
953{
954 cpl_error_code status = CPL_ERROR_NONE;
955 char errtxt[SC_MAXLEN];
956 cpl_table *scispec = NULL;
957 cpl_table *skyspec = NULL;
958 cpl_table *groups = NULL;
959 cpl_table *skylinetab = NULL;
960 cpl_table *scilinetab = NULL;
961 cpl_parameterlist *parlist = NULL;
962 cpl_parameter *p = NULL;
963
964 cpl_ensure_code(header != NULL, CPL_ERROR_NULL_INPUT);
965 cpl_ensure_code(airglow_var_frame != NULL, CPL_ERROR_NULL_INPUT);
966 double ltol = params->ltol;
967 double min_line_dist_fac = params->min_line_dist_fac;
968 double min_line_flux_fac = params->min_line_flux_fac;
969
970 double fluxlim = params->fluxlim;
971
972 double ftol = params->ftol;
973 double xtol = params->xtol;
974 double wtol = params->wtol;
975 int cheby_max = params->cheby_max;
976 int cheby_min = params->cheby_min;
977 double cheby_const = params->cheby_const;
978 int rebintype = params->rebintype;
979 double weightlim = params->weightlim;
980 double siglim = params->siglim;
981 double fitlim = params->fitlim;
982
983 cpl_msg_info("test", "call SC with indextarg %d indexrbn %d", indextarg,
984 indexrbn);
985 parlist = cpl_parameterlist_new();
986
987 p = cpl_parameter_new_value("col_dflux", CPL_TYPE_STRING, "", "", "dflux");
988 cpl_parameterlist_append(parlist, p);
989
990 p = cpl_parameter_new_value("vac_air", CPL_TYPE_STRING, "", "", "air");
991 cpl_parameterlist_append(parlist, p);
992 p = cpl_parameter_new_value("wlgtomicron", CPL_TYPE_DOUBLE, "", "", 1e-03);
993 cpl_parameterlist_append(parlist, p);
994 p = cpl_parameter_new_value("date_key", CPL_TYPE_STRING, "", "", "MJD-OBS");
995 cpl_parameterlist_append(parlist, p);
996 p = cpl_parameter_new_value("date_val", CPL_TYPE_DOUBLE, "", "", -1.);
997 cpl_parameterlist_append(parlist, p);
998 p = cpl_parameter_new_value("mjd", CPL_TYPE_DOUBLE, "", "", -1.);
999 cpl_parameterlist_append(parlist, p);
1000 p = cpl_parameter_new_value("time_key", CPL_TYPE_STRING, "", "",
1001 MOO_PFITS_UTC);
1002 cpl_parameterlist_append(parlist, p);
1003 p = cpl_parameter_new_value("time_val", CPL_TYPE_DOUBLE, "", "", -1.);
1004 cpl_parameterlist_append(parlist, p);
1005 p = cpl_parameter_new_value("telalt_key", CPL_TYPE_STRING, "", "",
1006 "ESO TEL ALT");
1007 cpl_parameterlist_append(parlist, p);
1008 p = cpl_parameter_new_value("telalt_val", CPL_TYPE_DOUBLE, "", "", -1.);
1009 cpl_parameterlist_append(parlist, p);
1010
1011 /* Required input data */
1012 p = cpl_parameter_new_value("linetabname", CPL_TYPE_STRING, "", "",
1013 "skylinegroups");
1014 cpl_parameterlist_append(parlist, p);
1015 p = cpl_parameter_new_value("vardatname", CPL_TYPE_STRING, "", "",
1016 "sky_featvar");
1017 cpl_parameterlist_append(parlist, p);
1018 p = cpl_parameter_new_value(
1019 "soldaturl", CPL_TYPE_STRING, "", "",
1020 "ftp.geolab.nrcan.gc.ca/data/solar_flux/monthly_averages");
1021 cpl_parameterlist_append(parlist, p);
1022 p = cpl_parameter_new_value("soldatname", CPL_TYPE_STRING, "", "",
1023 "solflux_monthly_average.txt");
1024 cpl_parameterlist_append(parlist, p);
1025 p = cpl_parameter_new_value("soldatsource", CPL_TYPE_STRING, "", "",
1026 "NONE");
1027 cpl_parameterlist_append(parlist, p);
1028 p = cpl_parameter_new_value("solflux", CPL_TYPE_DOUBLE, "", "", -1.);
1029 cpl_parameterlist_append(parlist, p);
1030
1031 /* Line identification */
1032 p = cpl_parameter_new_value("fwhm", CPL_TYPE_DOUBLE, "", "", MOO_SC_FWHM);
1033 cpl_parameterlist_append(parlist, p);
1034 p = cpl_parameter_new_range("varfwhm", CPL_TYPE_INT, "", "", MOO_SC_VARFWHM,
1035 0, 1);
1036 cpl_parameterlist_append(parlist, p);
1037 p = cpl_parameter_new_value("meanlam", CPL_TYPE_DOUBLE, "", "", 1.);
1038 cpl_parameterlist_append(parlist, p);
1039 p = cpl_parameter_new_value("ltol", CPL_TYPE_DOUBLE, "", "", ltol);
1040 cpl_parameterlist_append(parlist, p);
1041 p = cpl_parameter_new_value("min_line_dist_fac", CPL_TYPE_DOUBLE, "", "",
1042 min_line_dist_fac);
1043 cpl_parameterlist_append(parlist, p);
1044 p = cpl_parameter_new_value("min_line_flux_fac", CPL_TYPE_DOUBLE, "", "",
1045 min_line_flux_fac);
1046 cpl_parameterlist_append(parlist, p);
1047 p = cpl_parameter_new_value("fluxlim", CPL_TYPE_DOUBLE, "", "", fluxlim);
1048 cpl_parameterlist_append(parlist, p);
1049 p = cpl_parameter_new_value("iteration", CPL_TYPE_INT, "", "", 0);
1050 cpl_parameterlist_append(parlist, p);
1051
1052 /* Fitting of sky lines */
1053 p = cpl_parameter_new_value("ftol", CPL_TYPE_DOUBLE, "", "", ftol);
1054 cpl_parameterlist_append(parlist, p);
1055 p = cpl_parameter_new_value("xtol", CPL_TYPE_DOUBLE, "", "", xtol);
1056 cpl_parameterlist_append(parlist, p);
1057 p = cpl_parameter_new_value("wtol", CPL_TYPE_DOUBLE, "", "", wtol);
1058 cpl_parameterlist_append(parlist, p);
1059 p = cpl_parameter_new_value("cheby_max", CPL_TYPE_INT, "", "", cheby_max);
1060 cpl_parameterlist_append(parlist, p);
1061 p = cpl_parameter_new_value("cheby_min", CPL_TYPE_INT, "", "", cheby_min);
1062 cpl_parameterlist_append(parlist, p);
1063 p = cpl_parameter_new_value("cheby_const", CPL_TYPE_DOUBLE, "", "",
1064 cheby_const);
1065 cpl_parameterlist_append(parlist, p);
1066 p = cpl_parameter_new_value("rebintype", CPL_TYPE_INT, "", "", rebintype);
1067 cpl_parameterlist_append(parlist, p);
1068 p = cpl_parameter_new_value("weightlim", CPL_TYPE_DOUBLE, "", "",
1069 weightlim);
1070 cpl_parameterlist_append(parlist, p);
1071 p = cpl_parameter_new_value("siglim", CPL_TYPE_DOUBLE, "", "", siglim);
1072 cpl_parameterlist_append(parlist, p);
1073 p = cpl_parameter_new_value("fitlim", CPL_TYPE_DOUBLE, "", "", fitlim);
1074 cpl_parameterlist_append(parlist, p);
1075
1076 /* Plotting */
1077 p = cpl_parameter_new_value("plot_type", CPL_TYPE_STRING, "", "", "N");
1078 cpl_parameterlist_append(parlist, p);
1079
1080 scispec =
1081 _moo_spectrum_to_table(rbn, indexrbn, crpix1, crval1, cd1_1, parlist);
1082
1083 skyspec = _moo_spectrum_to_table(sky, 1, crpix1, crval1, cd1_1, parlist);
1084
1085 moo_try_check(status = __mo_sc_readspec_header(parlist, header),
1086 "error initialising SKYCORR");
1087 groups = cpl_table_new(0);
1088 _moo_sc_lines(groups, parlist, solflux_frame, airglow_group_frame,
1089 airglow_var_frame);
1090
1091 scilinetab = cpl_table_new(0);
1092 sc_specdiss_init_linetab(scilinetab);
1093 /* Subtraction of continuum from science and sky spectrum and estimation
1094 of line FWHM in sky spectrum */
1095
1096 /* Prepare science spectrum */
1097 //cpl_msg_info(cpl_func, "Science spectrum:");
1098 sc_skycorr_subcont(scispec, scilinetab, parlist, groups);
1099
1100 if ((status = cpl_error_get_code()) != CPL_ERROR_NONE) {
1101 sprintf(errtxt,
1102 "%s: error while separating lines and continuum of "
1103 "science spectrum",
1104 SC_ERROR_EIS_TXT);
1105 cpl_error_set_message(cpl_func, SC_ERROR_EIS, "%s", errtxt);
1106 }
1107
1108 /* Prepare sky spectrum */
1109 skylinetab = cpl_table_new(0);
1110 sc_specdiss_init_linetab(skylinetab);
1111
1112 sc_skycorr_subcont(skyspec, skylinetab, parlist, groups);
1113
1114 if ((status = cpl_error_get_code()) != CPL_ERROR_NONE) {
1115 sprintf(errtxt,
1116 "%s: error while separating lines and continuum of "
1117 "sky spectrum",
1118 SC_ERROR_EIS_TXT);
1119 cpl_error_set_message(cpl_func, SC_ERROR_EIS, "%s", errtxt);
1120 }
1121
1122 /* CMPFIT-based fitting procedure to adapt the sky line spectrum to the
1123 science line spectrum */
1124 //cpl_table_save(scispec,NULL,NULL,"moo_scipec.fits",CPL_IO_CREATE);
1125 //cpl_table_save(skyspec,NULL,NULL,"moo_skyspec.fits",CPL_IO_CREATE);
1126 sc_skycorr_fit(scispec, skyspec, groups, parlist);
1127
1128 //cpl_table_save(skyspec,NULL,NULL,"moo_skyspec.fits",CPL_IO_CREATE);
1129 /* Perform sky subtraction */
1130 sc_skycorr_subsky(scispec);
1131//cpl_table_save(scispec,NULL,NULL,"moo_skyspec_subsky.fits",CPL_IO_CREATE);
1132#if MOO_DEBUG_SKYCORR
1133 {
1134 char *namesci = cpl_sprintf("SKYCORR_SCI_%d.fits", indextarg);
1135 cpl_table_save(scispec, header, NULL, namesci, CPL_IO_CREATE);
1136 cpl_free(namesci);
1137
1138 char *namesky = cpl_sprintf("SKYCORR_SKY_%d.fits", indextarg);
1139 cpl_table_save(skyspec, header, NULL, namesky, CPL_IO_CREATE);
1140 cpl_free(namesky);
1141 }
1142#endif
1143 _moo_table_to_spectrum(scispec, sci, sci_sky, indextarg);
1144
1145moo_try_cleanup:
1146 cpl_table_delete(skylinetab);
1147 cpl_table_delete(scilinetab);
1148 cpl_table_delete(scispec);
1149 cpl_table_delete(skyspec);
1150 cpl_table_delete(groups);
1151 cpl_parameterlist_delete(parlist);
1152
1153 return status;
1154}
cpl_error_code moo_skycorr(hdrl_image *rbn, hdrl_image *sky, int indextarg, int indexrbn, double crpix1, double crval1, double cd1_1, cpl_propertylist *header, const cpl_frame *solflux_frame, const cpl_frame *airglow_group_frame, const cpl_frame *airglow_var_frame, moo_skycorr_params *params, hdrl_image *sci, cpl_image *sci_sky)
call the skycorr subtract sky function
Definition: moo_skycorr.c:939