00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifdef HAVE_CONFIG_H
00023 #include <config.h>
00024 #endif
00025
00026 #include <string.h>
00027
00028 #include "muse_sky.h"
00029 #include "muse_utils.h"
00030 #include "muse_cplwrappers.h"
00031 #include "muse_data_format_z.h"
00032
00033
00034 #define MUSE_SKY_T_VIBR 200.0
00035
00039
00046
00047 static cpl_table *
00048 muse_sky_ohtransitions_load(const char *aFile)
00049 {
00050 if (!cpl_fits_find_extension(aFile, "OH_TRANSITIONS")) {
00051 return NULL;
00052 }
00053 return muse_cpltable_load(aFile, "OH_TRANSITIONS",
00054 muse_sky_lines_oh_transitions_def);
00055 }
00056
00057
00068
00069 static cpl_error_code
00070 muse_sky_lines_reindex_groups(cpl_table *aLines)
00071 {
00072 cpl_ensure_code(aLines, CPL_ERROR_NULL_INPUT);
00073 cpl_size n_rows = cpl_table_get_nrow(aLines);
00074 if (n_rows > 0) {
00075 int i;
00076 int i_max = cpl_table_get_column_max(aLines, "group");
00077 int new_ids[i_max + 1];
00078 for (i = 0; i <= i_max; i++) {
00079 new_ids[i] = -1;
00080 }
00081 i_max = 0;
00082 cpl_size i_row;
00083 for (i_row = 0; i_row < n_rows; i_row++) {
00084 int old_id = cpl_table_get_int(aLines, "group", i_row, NULL);
00085 if (new_ids[old_id] < 0) {
00086 new_ids[old_id] = i_max++;
00087 }
00088 cpl_table_set_int(aLines, "group", i_row, new_ids[old_id]);
00089 }
00090 }
00091 return CPL_ERROR_NONE;
00092 }
00093
00094
00106
00107 cpl_error_code
00108 muse_sky_lines_set_range(cpl_table *aLines, double aLow, double aHigh)
00109 {
00110 cpl_ensure_code(aLines, CPL_ERROR_NULL_INPUT);
00111 #pragma omp critical(cpl_table_select)
00112 cpl_table_unselect_all(aLines);
00113 cpl_table_or_selected_double(aLines, "lambda", CPL_LESS_THAN, aLow);
00114 cpl_table_or_selected_double(aLines, "lambda", CPL_GREATER_THAN, aHigh);
00115 cpl_table_erase_selected(aLines);
00116 muse_sky_lines_reindex_groups(aLines);
00117
00118 return CPL_ERROR_NONE;
00119 }
00120
00121
00134
00135 cpl_error_code
00136 muse_sky_lines_save(muse_processing *aProcessing, const cpl_table *aLines,
00137 cpl_propertylist *aHeader)
00138 {
00139 cpl_ensure_code(aProcessing && aLines && aHeader, CPL_ERROR_NULL_INPUT);
00140 cpl_frame *frame = muse_processing_new_frame(aProcessing, -1, aHeader,
00141 MUSE_TAG_SKY_LINES,
00142 CPL_FRAME_TYPE_TABLE);
00143 cpl_ensure_code(frame, CPL_ERROR_ILLEGAL_INPUT);
00144 const char *filename = cpl_frame_get_filename(frame);
00145 cpl_error_code rc = cpl_propertylist_save(aHeader, filename, CPL_IO_CREATE);
00146 rc = muse_cpltable_append_file(aLines, filename,
00147 "LINES", muse_sky_lines_lines_def);
00148 if (rc == CPL_ERROR_NONE) {
00149 #pragma omp critical(muse_processing_output_frames)
00150 cpl_frameset_insert(aProcessing->outframes, frame);
00151 } else {
00152 cpl_frame_delete(frame);
00153 }
00154 return rc;
00155 }
00156
00157
00167
00168 cpl_table *
00169 muse_sky_lines_load(muse_processing *aProcessing)
00170 {
00171 cpl_ensure(aProcessing, CPL_ERROR_NULL_INPUT, NULL);
00172 cpl_frameset *frames = muse_frameset_find(aProcessing->inframes,
00173 MUSE_TAG_SKY_LINES, 0, CPL_FALSE);
00174 cpl_errorstate es = cpl_errorstate_get();
00175 cpl_frame *frame = cpl_frameset_get_position(frames, 0);
00176 if (frame == NULL) {
00177 cpl_frameset_delete(frames);
00178 cpl_errorstate_set(es);
00179 cpl_msg_warning(__func__, "No sky lines found in input frameset!");
00180 return NULL;
00181 }
00182 const char *fn = cpl_frame_get_filename(frame);
00183 cpl_table *oh_transitions = muse_sky_ohtransitions_load(fn);
00184 cpl_table *lines = muse_cpltable_load(fn, "LINES", muse_sky_lines_lines_def);
00185 if (lines == NULL && oh_transitions == NULL) {
00186 cpl_msg_warning(__func__, "Could not load sky lines from \"%s\"", fn);
00187 cpl_frameset_delete(frames);
00188 return NULL;
00189 }
00190
00191
00192 if (lines != NULL) {
00193 if (strcmp(cpl_table_get_column_unit(lines, "flux"),
00194 "erg/(s cm^2 arcsec^2)") == 0) {
00195 cpl_msg_info(__func__, "Scaling flux by 1e20");
00196 cpl_table_multiply_scalar(lines, "flux", 1e20);
00197 cpl_table_set_column_unit(lines, "flux",
00198 "10**(-20)*erg/(s cm^2 arcsec^2)");
00199 }
00200 if (strcmp(cpl_table_get_column_unit(lines, "flux"),
00201 "10**(-20)*erg/(s cm^2 arcsec^2)") != 0) {
00202 cpl_msg_warning(__func__, "Unsupported flux unit %s",
00203 cpl_table_get_column_unit(lines, "flux"));
00204 }
00205 }
00206
00207 cpl_msg_info(__func__, "Loaded sky lines from \"%s\"", fn);
00208 muse_processing_append_used(aProcessing, frame, CPL_FRAME_GROUP_CALIB, 1);
00209 cpl_frameset_delete(frames);
00210
00211 cpl_table *sky_lines = muse_sky_lines_create(lines, oh_transitions,
00212 MUSE_SKY_T_VIBR);
00213 cpl_table_delete(oh_transitions);
00214 cpl_table_delete(lines);
00215 return sky_lines;
00216 }
00217
00218
00231
00232 cpl_error_code
00233 muse_sky_lines_apply_strength(cpl_table *aLines, const cpl_array *aStrength)
00234 {
00235 cpl_ensure_code(aLines != NULL, CPL_ERROR_NULL_INPUT);
00236 cpl_ensure_code(aStrength != NULL, CPL_ERROR_NULL_INPUT);
00237
00238 int *group = cpl_table_get_data_int(aLines, "group");
00239 cpl_ensure_code(group != NULL, CPL_ERROR_ILLEGAL_INPUT);
00240 double *flux = cpl_table_get_data_double(aLines, "flux");
00241 cpl_ensure_code(flux != NULL, CPL_ERROR_ILLEGAL_INPUT);
00242 cpl_size nRows = cpl_table_get_nrow(aLines);
00243 cpl_size i;
00244 for (i = 0; i < nRows; i++, group++, flux++) {
00245 *flux *= cpl_array_get(aStrength, *group, NULL);
00246 }
00247 return CPL_ERROR_NONE;
00248 }
00249
00250
00260
00261 cpl_error_code
00262 muse_sky_lines_cut(cpl_table *aLines, double aMinflux)
00263 {
00264 cpl_ensure_code(aLines != NULL, CPL_ERROR_NULL_INPUT);
00265 cpl_table_select_all(aLines);
00266 cpl_table_and_selected_double(aLines, "flux", CPL_LESS_THAN, aMinflux);
00267 cpl_table_erase_selected(aLines);
00268 return CPL_ERROR_NONE;
00269 }
00270
00271
00292
00293 static cpl_table *
00294 muse_sky_lines_create_oh(const cpl_table *aTransitions, double aTemperature)
00295 {
00296 if ((aTransitions == NULL) || (cpl_table_get_nrow(aTransitions) == 0)) {
00297 return muse_cpltable_new(muse_sky_lines_lines_def, 0);
00298 }
00299
00300 const int max_level = cpl_table_get_column_max(aTransitions, "v_u");
00301 const int min_level = cpl_table_get_column_min(aTransitions, "v_u");
00302 cpl_ensure(max_level-min_level < 100, CPL_ERROR_UNSUPPORTED_MODE, NULL);
00303 const int n_transitions = cpl_table_get_nrow(aTransitions);
00304
00305 cpl_table *lines = muse_cpltable_new(muse_sky_lines_lines_def, n_transitions);
00306
00307 cpl_table_copy_data_string(lines, "name",
00308 cpl_table_get_data_string_const(aTransitions,
00309 "name"));
00310 cpl_table_copy_data_double(lines, "lambda",
00311 cpl_table_get_data_double_const(aTransitions,
00312 "lambda"));
00313 cpl_table_copy_data_int(lines, "group",
00314 cpl_table_get_data_int_const(aTransitions, "v_u"));
00315 cpl_table_subtract_scalar(lines, "group", min_level);
00316
00317 cpl_table_fill_column_window_double(lines, "flux", 0, n_transitions, 0.0);
00318
00319 const double k_B = 1.3806504e-23;
00320 const double hc = 1.98623e-8;
00321 cpl_table_copy_data_double(lines, "flux",
00322 cpl_table_get_data_double_const(aTransitions, "E_u"));
00323 cpl_table_divide_scalar(lines, "flux", -k_B * aTemperature);
00324 cpl_table_exponential_column(lines, "flux", CPL_MATH_E);
00325
00326 cpl_table_duplicate_column(lines, "J_u", aTransitions, "J_u");
00327 cpl_table_multiply_scalar(lines, "J_u", 2.0);
00328 cpl_table_add_scalar(lines, "J_u", 1.0);
00329 cpl_table_multiply_columns(lines, "flux", "J_u");
00330 cpl_table_erase_column(lines, "J_u");
00331
00332 cpl_table_fill_column_window_int(lines, "dq", 0, n_transitions, 0);
00333
00334 double *flux = cpl_table_get_data_double(lines, "flux");
00335 const int *group = cpl_table_get_data_int_const(lines, "group");
00336
00337 double q[max_level - min_level + 1];
00338 memset(q, 0, (max_level - min_level + 1)*sizeof(double));
00339 int i_transition;
00340 for (i_transition = 0; i_transition < n_transitions; i_transition++,
00341 group++, flux++) {
00342 q[*group] += *flux;
00343 }
00344
00345 cpl_table_duplicate_column(lines, "A", aTransitions, "A");
00346 cpl_table_multiply_columns(lines, "flux", "A");
00347 cpl_table_erase_column(lines, "A");
00348 cpl_table_multiply_scalar(lines, "flux", 2.0 * hc);
00349 cpl_table_divide_columns(lines, "flux", "lambda");
00350
00351 flux = cpl_table_get_data_double(lines, "flux");
00352 group = cpl_table_get_data_int_const(lines, "group");
00353
00354 for (i_transition = 0; i_transition < n_transitions; i_transition++,
00355 flux++, group++) {
00356 *flux /= q[*group];
00357 }
00358
00359 cpl_table_multiply_scalar(lines, "flux", 1e20);
00360
00361 cpl_table_divide_scalar(lines, "flux", 50);
00362
00363 muse_sky_lines_reindex_groups(lines);
00364 return lines;
00365 }
00366
00367
00381
00382 cpl_table *
00383 muse_sky_lines_create(const cpl_table *aLines,
00384 const cpl_table *aOh_transitions, double aT_vibr)
00385 {
00386 int group_start = (aLines && cpl_table_get_nrow(aLines) > 0)?
00387 cpl_table_get_column_max(aLines, "group") + 1: 0;
00388 cpl_table *res = muse_sky_lines_create_oh(aOh_transitions, aT_vibr);
00389 cpl_errorstate prestate = cpl_errorstate_get();
00390 if (aLines) {
00391 cpl_table_add_scalar(res, "group", group_start);
00392 cpl_table_insert(res, aLines, 0);
00393 }
00394 if (!cpl_errorstate_is_equal(prestate)) {
00395 cpl_msg_error(__func__, "while cpl_table_insert(): %s, %s",
00396 cpl_table_get_column_unit(res, "flux"),
00397 cpl_table_get_column_unit(aLines, "flux"));
00398 cpl_errorstate_dump(prestate, CPL_FALSE, NULL);
00399 cpl_errorstate_set(prestate);
00400 }
00401 return res;
00402 }
00403