UVES Pipeline Reference Manual  5.4.0
irplib_ppm.c
1 /* $Id: irplib_ppm.c,v 1.31 2012-06-11 07:24:09 llundin Exp $
2  *
3  * This file is part of the irplib package
4  * Copyright (C) 2002,2003 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: llundin $
23  * $Date: 2012-06-11 07:24:09 $
24  * $Revision: 1.31 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 /*-----------------------------------------------------------------------------
33  Includes
34  -----------------------------------------------------------------------------*/
35 
36 #include <math.h>
37 #include <cpl.h>
38 
39 #include "irplib_ppm.h"
40 #include "irplib_wlxcorr.h"
41 #include "irplib_spectrum.h"
42 
43 /* TEMPORARY SUPPORT OF CPL 5.x */
44 #ifndef CPL_SIZE_FORMAT
45 #define CPL_SIZE_FORMAT "d"
46 #define cpl_size int
47 #endif
48 /* END TEMPORARY SUPPORT OF CPL 5.x */
49 
50 /*-----------------------------------------------------------------------------
51  Private functions
52  -----------------------------------------------------------------------------*/
53 #ifdef IRPLIB_PPM_USE_METHOD2
54 static cpl_vector * irplib_ppm_convolve_line(const cpl_vector *, double,double);
55 static cpl_vector * irplib_ppm_detect_lines(const cpl_vector *, double) ;
56 #endif
57 
58 /*----------------------------------------------------------------------------*/
62 /*----------------------------------------------------------------------------*/
63 
66 /*----------------------------------------------------------------------------*/
83 /*----------------------------------------------------------------------------*/
84 cpl_polynomial * irplib_ppm_engine(
85  const cpl_vector * spectrum,
86  const cpl_bivector * lines_catalog,
87  const cpl_polynomial * poly_init,
88  double slitw,
89  double fwhm,
90  double thresh,
91  int degree,
92  int doplot,
93  cpl_table ** tab_infos)
94 {
95 #ifdef IRPLIB_PPM_USE_METHOD2
96  cpl_vector * spec_conv ;
97 #endif
98  int spec_sz ;
99  cpl_vector * det_lines ;
100  double * pdet_lines ;
101  cpl_vector * cat_lines ;
102  double * pcat_lines ;
103  double wmin, wmax ;
104  double disp_min, disp_max, disp ;
105  int nlines_cat, nlines ;
106  const double * plines_catalog_x ;
107  const double * plines_catalog_y ;
108  cpl_bivector * matched ;
109  cpl_matrix * matchedx;
110  int match_sz;
111  cpl_polynomial * fitted ;
112  cpl_table * spc_table ;
113  const cpl_vector* vectors_plot[3];
114  cpl_vector * plot_y ;
115  int wl_ind, start_ind, stop_ind ;
116  double fill_val ;
117  cpl_size deg_loc ;
118  int i ;
119  cpl_error_code error;
120 
121  /* Check entries */
122  if (spectrum == NULL) return NULL ;
123  if (lines_catalog == NULL) return NULL ;
124  if (poly_init == NULL) return NULL ;
125 
126  /* Initialise */
127  spec_sz = cpl_vector_get_size(spectrum) ;
128  deg_loc = (cpl_size)degree ;
129 
130 #ifdef IRPLIB_PPM_USE_METHOD2
131  /* METHOD 2 */
132  /* Correlate the spectrum with the line profile */
133  if ((spec_conv = irplib_ppm_convolve_line(spectrum, slitw, fwhm)) == NULL) {
134  cpl_msg_error(cpl_func, "Cannot convolve the signal") ;
135  return NULL ;
136  }
137 
138  /* Apply the lines detection */
139  if ((det_lines = irplib_ppm_detect_lines(spec_conv, 0.9)) == NULL) {
140  cpl_msg_error(cpl_func, "Cannot detect lines") ;
141  cpl_vector_delete(spec_conv) ;
142  return NULL ;
143  }
144  cpl_vector_delete(spec_conv) ;
145 #else
146  /* METHOD 1 */
147  if ((det_lines = irplib_spectrum_detect_peaks(spectrum, fwhm,
148  thresh, 0, NULL, NULL)) == NULL) {
149  cpl_msg_error(cpl_func, "Cannot convolve the signal") ;
150  return NULL ;
151  }
152 #endif
153  cpl_msg_info(cpl_func, "Detected %"CPL_SIZE_FORMAT" lines",
154  cpl_vector_get_size(det_lines));
155 
156  /* Get the catalog lines */
157  wmin = cpl_polynomial_eval_1d(poly_init, 1.0, NULL) ;
158  wmax = cpl_polynomial_eval_1d(poly_init, spec_sz, NULL) ;
159  plines_catalog_x = cpl_bivector_get_x_data_const(lines_catalog) ;
160  plines_catalog_y = cpl_bivector_get_y_data_const(lines_catalog) ;
161  nlines = cpl_bivector_get_size(lines_catalog) ;
162  nlines_cat = 0 ;
163  start_ind = stop_ind = -1 ;
164  for (i=0 ; i<nlines ; i++) {
165  if (plines_catalog_x[i] > wmin && plines_catalog_x[i] < wmax &&
166  plines_catalog_y[i] > 0.0) {
167  nlines_cat++ ;
168  if (start_ind<0) start_ind = i ;
169  stop_ind = i ;
170  }
171  }
172  if (nlines_cat == 0) {
173  cpl_msg_error(cpl_func, "No lines in catalog") ;
174  cpl_vector_delete(det_lines) ;
175  return NULL ;
176  }
177  cat_lines = cpl_vector_new(nlines_cat) ;
178  pcat_lines = cpl_vector_get_data(cat_lines) ;
179  nlines_cat = 0 ;
180  for (i=0 ; i<nlines ; i++) {
181  if (plines_catalog_x[i] > wmin && plines_catalog_x[i] < wmax &&
182  plines_catalog_y[i] > 0.0) {
183  pcat_lines[nlines_cat] = plines_catalog_x[i] ;
184  nlines_cat++ ;
185  }
186  }
187 
188  /* Plot inputs */
189  if (doplot) {
190  /* Catalog */
191  irplib_wlxcorr_catalog_plot(lines_catalog, wmin, wmax) ;
192 
193  /* Spectrum with detected lines */
194  fill_val = cpl_vector_get_max(spectrum) ;
195  plot_y = cpl_vector_new(spec_sz);
196  cpl_vector_fill(plot_y, 0.0) ;
197  pdet_lines = cpl_vector_get_data(det_lines) ;
198  for (i=0 ; i<cpl_vector_get_size(det_lines) ; i++) {
199  cpl_vector_set(plot_y, (int)pdet_lines[i], fill_val) ;
200  }
201  vectors_plot[0] = NULL ;
202  vectors_plot[1] = spectrum ;
203  vectors_plot[2] = plot_y ;
204 
205  cpl_plot_vectors("set grid;set xlabel 'Position (Pixel)';set ylabel "
206  "'Intensity (ADU/sec)';",
207  "t 'Spectrum with detected lines' w lines", "",
208  vectors_plot, 3);
209  cpl_vector_delete(plot_y) ;
210  }
211 
212  /* Apply the point pattern matching */
213  disp = (wmax-wmin) / spec_sz ;
214  disp_min = disp - (disp/10) ;
215  disp_max = disp + (disp/10) ;
216  matched = cpl_ppm_match_positions(det_lines, cat_lines, disp_min,
217  disp_max, 0.05, NULL, NULL);
218  cpl_vector_delete(det_lines) ;
219  cpl_vector_delete(cat_lines) ;
220 
221  if (matched == NULL) {
222  cpl_msg_error(cpl_func, "Cannot apply the point pattern matching") ;
223  return NULL ;
224  }
225 
226  match_sz = cpl_bivector_get_size(matched);
227 
228  cpl_msg_info(cpl_func, "Matched %d lines", match_sz) ;
229 
230  if (match_sz <= deg_loc) {
231  cpl_msg_error(cpl_func, "Not enough match for the fit") ;
232  cpl_bivector_delete(matched) ;
233  return NULL ;
234  }
235 
236  /* Plot if requested */
237  if (doplot) {
238  const double * pmatched ;
239  cpl_bivector * biplot ;
240  cpl_vector * plot_cat_x ;
241  cpl_vector * plot_cat_y ;
242  /* Spectrum with matched lines */
243  fill_val = cpl_vector_get_max(spectrum) ;
244  plot_y = cpl_vector_new(spec_sz);
245  cpl_vector_fill(plot_y, 0.0) ;
246  pmatched = cpl_bivector_get_x_data_const(matched) ;
247  for (i=0 ; i < match_sz; i++) {
248  cpl_vector_set(plot_y, (int)pmatched[i], fill_val) ;
249  }
250  vectors_plot[0] = NULL ;
251  vectors_plot[1] = spectrum ;
252  vectors_plot[2] = plot_y ;
253 
254  cpl_plot_vectors("set grid;set xlabel 'Position (Pixel)';set ylabel "
255  "'Intensity (ADU/sec)';",
256  "t 'Spectrum with matched lines' w lines", "",
257  vectors_plot, 3);
258  cpl_vector_delete(plot_y) ;
259 
260  /* Catalog with matched lines */
261  plot_cat_x=cpl_vector_extract(cpl_bivector_get_x_const(lines_catalog),
262  start_ind, stop_ind, 1) ;
263  plot_cat_y=cpl_vector_extract(cpl_bivector_get_y_const(lines_catalog),
264  start_ind, stop_ind, 1) ;
265  biplot = cpl_bivector_wrap_vectors(plot_cat_x, plot_cat_y) ;
266  cpl_plot_bivector("set grid;set xlabel 'Wavelength';set ylabel "
267  "'Emission';", "t 'Catalog' w impulses", "",
268  biplot);
269  cpl_bivector_unwrap_vectors(biplot) ;
270 
271  plot_y = cpl_vector_duplicate(plot_cat_y) ;
272  cpl_vector_fill(plot_y, 0.0) ;
273  pmatched = cpl_bivector_get_y_data_const(matched) ;
274  fill_val=cpl_vector_get_mean(plot_cat_y) ;
275  for (i=0 ; i < match_sz; i++) {
276  wl_ind = 0 ;
277  while (pmatched[i] > cpl_vector_get(plot_cat_x, wl_ind)
278  && wl_ind < spec_sz) wl_ind++ ;
279  if (wl_ind < spec_sz) cpl_vector_set(plot_y, wl_ind, fill_val) ;
280  }
281  biplot = cpl_bivector_wrap_vectors(plot_cat_x, plot_y) ;
282  cpl_plot_bivector("set grid;set xlabel 'Wavelength';set ylabel "
283  "'Emission';", "t 'Catalog (matched lines)' w "
284  "impulses", "", biplot) ;
285  cpl_bivector_unwrap_vectors(biplot) ;
286  cpl_vector_delete(plot_cat_x) ;
287  cpl_vector_delete(plot_cat_y) ;
288  cpl_vector_delete(plot_y) ;
289  }
290 
291  /* Apply the fit */
292  matchedx = cpl_matrix_wrap(1, match_sz, cpl_bivector_get_x_data(matched));
293  fitted = cpl_polynomial_new(1);
294  error = cpl_polynomial_fit(fitted, matchedx, NULL,
295  cpl_bivector_get_y_const(matched), NULL,
296  CPL_FALSE, NULL, &deg_loc);
297  cpl_bivector_delete(matched);
298  (void)cpl_matrix_unwrap(matchedx);
299  if (error) {
300  cpl_msg_error(cpl_func, "Cannot fit the polynomial") ;
301  cpl_polynomial_delete(fitted);
302  return NULL ;
303  }
304 
305  /* Create the infos table */
306  if ((spc_table = irplib_wlxcorr_gen_spc_table(spectrum,
307  lines_catalog, slitw, fwhm, poly_init, fitted)) == NULL) {
308  cpl_msg_error(cpl_func, "Cannot generate the infos table") ;
309  cpl_polynomial_delete(fitted) ;
310  return NULL ;
311  }
312  if (tab_infos != NULL) *tab_infos = spc_table ;
313  else cpl_table_delete(spc_table) ;
314  return fitted ;
315 }
316 
319 #ifdef IRPLIB_PPM_USE_METHOD2
320 /*----------------------------------------------------------------------------*/
331 /*----------------------------------------------------------------------------*/
332 static cpl_vector * irplib_ppm_convolve_line(
333  const cpl_vector * spectrum,
334  double slitw,
335  double fwhm)
336 {
337  cpl_vector * conv_kernel ;
338  cpl_vector * line_profile ;
339  cpl_vector * xcorrs ;
340  cpl_vector * spec_ext ;
341  cpl_vector * xc_single ;
342  int hs, line_sz, sp_sz ;
343  int i ;
344 
345  /* Test entries */
346  if (spectrum == NULL) return NULL ;
347 
348  /* Create the convolution kernel */
349  if ((conv_kernel = irplib_wlxcorr_convolve_create_kernel(slitw,
350  fwhm)) == NULL) {
351  cpl_msg_error(cpl_func, "Cannot create kernel") ;
352  return NULL ;
353  }
354  hs = cpl_vector_get_size(conv_kernel) ;
355  line_sz = 2 * hs + 1 ;
356 
357  /* Create the line profile */
358  line_profile = cpl_vector_new(line_sz) ;
359  cpl_vector_fill(line_profile, 0.0) ;
360  cpl_vector_set(line_profile, hs, 1.0) ;
361  if (irplib_wlxcorr_convolve(line_profile, conv_kernel) != 0) {
362  cpl_msg_error(cpl_func, "Cannot create line profile") ;
363  cpl_vector_delete(line_profile) ;
364  cpl_vector_delete(conv_kernel) ;
365  return NULL ;
366  }
367  cpl_vector_delete(conv_kernel) ;
368 
369  /* Create the correlations values vector */
370  sp_sz = cpl_vector_get_size(spectrum) ;
371  xcorrs = cpl_vector_new(sp_sz) ;
372  cpl_vector_fill(xcorrs, 0.0) ;
373  xc_single = cpl_vector_new(1) ;
374 
375  /* Loop on the pixels of the spectrum */
376  for (i=hs ; i<sp_sz-hs ; i++) {
377  /* Extract the current spectrum part */
378  if ((spec_ext = cpl_vector_extract(spectrum, i-hs, i+hs, 1)) == NULL) {
379  cpl_msg_error(cpl_func, "Cannot extract spectrum") ;
380  cpl_vector_delete(xc_single) ;
381  cpl_vector_delete(line_profile) ;
382  return NULL ;
383  }
384  if (cpl_vector_correlate(xc_single, spec_ext, line_profile) < 0) {
385  cpl_msg_error(cpl_func, "Cannot correlate") ;
386  cpl_vector_delete(xc_single) ;
387  cpl_vector_delete(line_profile) ;
388  cpl_vector_delete(spec_ext) ;
389  return NULL ;
390  }
391  cpl_vector_set(xcorrs, i, cpl_vector_get(xc_single, 0)) ;
392  cpl_vector_delete(spec_ext) ;
393  }
394  cpl_vector_delete(xc_single) ;
395  cpl_vector_delete(line_profile) ;
396 
397  return xcorrs ;
398 }
399 
400 /*----------------------------------------------------------------------------*/
409 /*----------------------------------------------------------------------------*/
410 static cpl_vector * irplib_ppm_detect_lines(
411  const cpl_vector * spec,
412  double threshold)
413 {
414  cpl_vector * spec_loc ;
415  double * pspec_loc ;
416  cpl_vector * lines ;
417  double * plines ;
418  int spec_loc_sz, max_ind, nlines ;
419  double max ;
420  int i ;
421 
422  /* Test inputs */
423  if (spec == NULL) return NULL ;
424 
425  /* Local spectrum */
426  spec_loc = cpl_vector_duplicate(spec) ;
427  pspec_loc = cpl_vector_get_data(spec_loc) ;
428  spec_loc_sz = cpl_vector_get_size(spec_loc) ;
429 
430  /* Threshold the local spectrum */
431  for (i=0 ; i<spec_loc_sz ; i++)
432  if (pspec_loc[i] < threshold) pspec_loc[i] = 0.0 ;
433 
434  /* Allocate lines container */
435  lines = cpl_vector_new(spec_loc_sz) ;
436  plines = cpl_vector_get_data(lines) ;
437  nlines = 0 ;
438 
439  /* Loop as long as there are lines */
440  while ((max = cpl_vector_get_max(spec_loc)) > threshold) {
441  /* Find the max position */
442  max_ind = 0 ;
443  while (max_ind < spec_loc_sz && pspec_loc[max_ind] < max) max_ind++ ;
444  if (max_ind == spec_loc_sz) {
445  cpl_msg_error(cpl_func, "Cannot find maximum") ;
446  cpl_vector_delete(spec_loc) ;
447  cpl_vector_delete(lines) ;
448  return NULL ;
449  }
450  if (max_ind == 0 || max_ind == spec_loc_sz-1) {
451  pspec_loc[max_ind] = 0 ;
452  continue ;
453  }
454 
455  /* Get the precise position from the neighbours values */
456  plines[nlines] = pspec_loc[max_ind] * max_ind +
457  pspec_loc[max_ind-1] * (max_ind-1) +
458  pspec_loc[max_ind+1] * (max_ind+1) ;
459  plines[nlines] /= pspec_loc[max_ind] + pspec_loc[max_ind+1] +
460  pspec_loc[max_ind-1] ;
461  plines[nlines] ++ ;
462  nlines ++ ;
463 
464  /* Clean the line */
465  i = max_ind ;
466  while (i>=0 && pspec_loc[i] > threshold) {
467  pspec_loc[i] = 0.0 ;
468  i-- ;
469  }
470  i = max_ind+1 ;
471  while (i<spec_loc_sz && pspec_loc[i] > threshold) {
472  pspec_loc[i] = 0.0 ;
473  i++ ;
474  }
475  }
476  cpl_vector_delete(spec_loc) ;
477 
478  /* Check if there are lines */
479  if (nlines == 0) {
480  cpl_msg_error(cpl_func, "Cannot detect any line") ;
481  cpl_vector_delete(lines) ;
482  return NULL ;
483  }
484 
485  /* Resize the vector */
486  cpl_vector_set_size(lines, nlines) ;
487 
488  /* Sort the lines */
489  cpl_vector_sort(lines, 1) ;
490 
491  return lines ;
492 }
493 
494 #endif