30 #include "muse_instrument.h" 32 #include "muse_optimize.h" 33 #include "muse_utils.h" 34 #include "muse_data_format_z.h" 51 muse_sky_lines_firstguess(
int ngroups) {
52 cpl_array *pars = cpl_array_new(ngroups+2, CPL_TYPE_DOUBLE);
56 for (i = 0; i < ngroups; i++) {
57 cpl_array_set(pars, i, 1e-1);
59 cpl_array_set(pars, ngroups, 0.0);
60 cpl_array_set(pars, ngroups+1, 0.0);
65 const cpl_array *lambda;
66 const cpl_array *values;
67 const cpl_array *weights;
68 const cpl_table *lines;
69 const cpl_size ngroups;
70 const cpl_image *lsfImage;
72 } muse_master_fit_struct;
84 simulate_master_sky_parameters(muse_master_fit_struct *aFitData,
85 const cpl_array *aPar)
87 cpl_table *lines = cpl_table_duplicate(aFitData->lines);
89 double fac = cpl_array_get(aPar, cpl_array_get_size(aPar)-2, &res);
90 double offset = cpl_array_get(aPar, cpl_array_get_size(aPar)-1, &res);
91 cpl_table_multiply_scalar(lines,
"lambda", 1+fac);
92 cpl_table_add_scalar(lines,
"lambda", offset-7000 * fac);
93 cpl_array *line_strengths = cpl_array_duplicate(aPar);
94 cpl_array_multiply(line_strengths, aPar);
96 cpl_array_delete(line_strengths);
98 double maxflux = cpl_table_get_column_max(lines,
"flux");
103 aFitData->lsfImage, aFitData->wcs);
104 cpl_table_delete(lines);
119 static cpl_error_code
120 muse_sky_master_eval(
void *aData, cpl_array *aPar, cpl_array *aRetval)
122 cpl_size size = cpl_array_get_size(aRetval);
123 muse_master_fit_struct *fitData = aData;
124 cpl_array *simulated = simulate_master_sky_parameters(fitData, aPar);
125 cpl_array_subtract(simulated, fitData->values);
128 cpl_array_multiply(dsimulated, fitData->weights);
130 cpl_array_fill_window_double(aRetval, 0, size, 0.0);
131 memcpy(cpl_array_get_data_double(aRetval),
132 cpl_array_get_data_double_const(dsimulated),
133 size *
sizeof(
double));
134 cpl_array_delete(simulated);
135 cpl_array_delete(dsimulated);
137 return CPL_ERROR_NONE;
154 static cpl_error_code
155 muse_sky_lines_correct_firstguess(muse_master_fit_struct *aFitData,
159 cpl_array *simulated = simulate_master_sky_parameters(aFitData, aPar);
161 cpl_table *lines = cpl_table_duplicate(aFitData->lines);
162 cpl_array *line_strengths = cpl_array_duplicate(aPar);
163 cpl_array_multiply(line_strengths, aPar);
165 cpl_array_delete(line_strengths);
167 for (i_group = 0; i_group < aFitData->ngroups; i_group++) {
169 cpl_table_unselect_all(lines);
170 cpl_table_or_selected_int(lines,
"group", CPL_EQUAL_TO, i_group);
171 cpl_table *gtable = cpl_table_extract_selected(lines);
172 if (cpl_table_get_nrow(gtable) == 0) {
173 cpl_table_delete(gtable);
177 cpl_table_get_column_maxpos(gtable,
"flux", &row);
178 double wavelength = cpl_table_get_double(gtable,
"lambda", row, NULL);
187 double offset = cpl_array_get(aFitData->values, i_lbda1, NULL);
188 offset += cpl_array_get(aFitData->values, i_lbda2, NULL);
191 for (i_lbda = i_lbda1; i_lbda <= i_lbda2; i_lbda++) {
192 double wy_data = cpl_array_get(aFitData->values, i_lbda, NULL) - offset;
193 if (wy_data < 0) wy_data = 0;
194 double wy_sim = cpl_array_get(simulated, i_lbda, NULL);
201 double y = cpl_array_get(aPar, i_group, NULL);
202 cpl_array_set(aPar, i_group, y*sqrt(y_data/y_sim));
204 cpl_table_delete(gtable);
206 cpl_table_delete(lines);
207 cpl_array_delete(simulated);
209 return CPL_ERROR_NONE;
228 cpl_image *aLsfImage,
muse_wcs *aWCS)
230 cpl_ensure_code(aSpectrum, CPL_ERROR_NULL_INPUT);
231 cpl_ensure_code(aLines, CPL_ERROR_NULL_INPUT);
232 cpl_size nRows = cpl_table_get_nrow(aSpectrum);
233 cpl_ensure_code(nRows > 0, CPL_ERROR_DATA_NOT_FOUND);
239 cpl_array *weights = cpl_array_extract(stat, 0, nRows - 1);
240 cpl_array *w2 = cpl_array_extract(stat, 1, nRows);
241 cpl_array_add(weights, w2);
242 cpl_array_delete(w2);
243 cpl_array_power(weights, -0.5);
246 muse_master_fit_struct fit_data = {
251 cpl_table_get_column_max(aLines,
"group") + 1,
256 cpl_array *pars = muse_sky_lines_firstguess(fit_data.ngroups);
257 muse_sky_lines_correct_firstguess(&fit_data, pars);
260 int debug = getenv(
"MUSE_DEBUG_LSF_FIT")
261 && atoi(getenv(
"MUSE_DEBUG_LSF_FIT")) > 0;
267 cpl_msg_info(__func__,
"Starting sky line fit");
269 muse_sky_master_eval, &ctrl);
270 if (r != CPL_ERROR_NONE) {
271 cpl_msg_error(__func__,
"Sky line fit failed with error code %i: %s",
272 r, cpl_error_get_message());
275 double fac = cpl_array_get(pars, cpl_array_get_size(pars)-2, &res);
276 double offset = cpl_array_get(pars, cpl_array_get_size(pars)-1, &res);
277 cpl_table_multiply_scalar(aLines,
"lambda", 1+fac);
278 cpl_table_add_scalar(aLines,
"lambda", offset-7000 * fac);
279 double l_min = cpl_table_get_column_min(aLines,
"lambda");
280 double l_max = cpl_table_get_column_max(aLines,
"lambda");
281 cpl_msg_info(__func__,
"Sky line fit finished successfully. " 282 "Offset %.3f A (at %.0f A) ... %.3f A (at %.0f A)",
283 offset + (l_min - 7000) *fac, l_min,
284 offset + (l_max - 7000) * fac, l_max);
287 cpl_array_multiply(pars, pars);
289 cpl_array_delete(pars);
291 cpl_propertylist *order = cpl_propertylist_new();
292 cpl_propertylist_append_bool(order,
"flux", TRUE);
293 cpl_table_sort(aLines, order);
294 cpl_propertylist_delete(order);
295 cpl_array_unwrap(lambda);
296 cpl_array_unwrap(data);
297 cpl_array_unwrap(stat);
298 cpl_array_delete(weights);
300 return CPL_ERROR_NONE;
320 cpl_image *aLsfImage,
muse_wcs *aLsfWCS,
323 cpl_ensure(aSpectrum, CPL_ERROR_NULL_INPUT, NULL);
324 cpl_ensure(aLines, CPL_ERROR_NULL_INPUT, NULL);
325 cpl_ensure(aLsfImage, CPL_ERROR_NULL_INPUT, NULL);
326 cpl_ensure(aLsfImage, CPL_ERROR_NULL_INPUT, NULL);
331 cpl_array_subtract(simulated, flux);
332 cpl_array_multiply_scalar(simulated, -1.);
334 double l_min = cpl_array_get_min(lambda);
335 double l_max = cpl_array_get_max(lambda);
336 cpl_size n_new = (l_max - l_min) / aBinWidth;
338 cpl_table_fill_column_window(continuum,
"flux", 0, n_new, 0.0);
342 for (i = 0; i < n_new; i++) {
343 cpl_table_set(continuum,
"lambda", i, l_min + i * aBinWidth);
348 memcpy(cpl_table_get_data_double(continuum,
"flux"),
349 cpl_array_get_data_double(flux_new),
350 n_new *
sizeof(
double));
351 cpl_array_delete(simulated);
352 cpl_array_unwrap(lambda);
353 cpl_array_unwrap(flux);
354 cpl_array_unwrap(lambda_new);
355 cpl_array_delete(flux_new);
369 cpl_ensure(aProcessing, CPL_ERROR_NULL_INPUT, NULL);
373 MUSE_TAG_SKY_CONT, 0, CPL_FALSE);
374 if (frames_c == NULL || cpl_frameset_get_size(frames_c) < 1) {
375 cpl_frameset_delete(frames_c);
376 cpl_msg_debug(__func__,
"No sky continuum found in input frameset!");
379 cpl_frame *frame_c = cpl_frameset_get_position(frames_c, 0);
380 const char *fn = cpl_frame_get_filename(frame_c);
384 if (continuum == NULL) {
385 cpl_msg_warning(__func__,
"Could not load sky continuum from \"%s\"", fn);
386 cpl_frameset_delete(frames_c);
390 cpl_msg_info(__func__,
"Loaded sky continuum from \"%s\"", fn);
392 cpl_frameset_delete(frames_c);
cpl_error_code muse_sky_lines_fit(cpl_table *aSpectrum, cpl_table *aLines, cpl_image *aLsfImage, muse_wcs *aWCS)
Fit all entries of the pixel table to the master sky.
cpl_table * muse_sky_continuum_create(cpl_table *aSpectrum, cpl_table *aLines, cpl_image *aLsfImage, muse_wcs *aLsfWCS, double aBinWidth)
Create a continuum spectrum.
cpl_error_code muse_sky_lines_apply_strength(cpl_table *, const cpl_array *)
Apply the line strengths to the lines.
A structure containing a spatial two-axis WCS.
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.
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_table * muse_sky_continuum_load(muse_processing *aProcessing)
Load the sky continuum.
cpl_array * muse_cpltable_extract_column(cpl_table *aTable, const char *aColumn)
Create an array from a section of a column.
cpl_array * muse_cplarray_interpolate_linear(const cpl_array *aTargetAbscissa, const cpl_array *aSourceAbscissa, const cpl_array *aSourceOrdinate)
Linear interpolation of a 1d array.
Optimization control parameters.
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.
cpl_array * muse_cplarray_diff(const cpl_array *aArray, int aOffset)
Build the difference of any element and one of the next elements.
cpl_array * muse_sky_lines_spectrum(const cpl_array *, cpl_table *, const cpl_image *, const muse_wcs *)
Create spectrum for a single slice.
cpl_error_code muse_sky_lines_cut(cpl_table *, double)
Remove all lines below a certain flux limit.
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
cpl_size muse_cplarray_find_sorted(const cpl_array *aArray, double aValue)
Find a row in an array.