GIRAFFE Pipeline Reference Manual

gisgcalibration.c
1 /* $Id$
2  *
3  * This file is part of the GIRAFFE Pipeline
4  * Copyright (C) 2002-2006 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 02110-1301 USA
19  */
20 
21 /*
22  * $Author$
23  * $Date$
24  * $Revision$
25  * $Name$
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31 
32 #include <math.h>
33 
34 #include <cxmemory.h>
35 #include <cxmessages.h>
36 #include <cxstrutils.h>
37 
38 #include <cpl_error.h>
39 #include <cpl_parameterlist.h>
40 #include <cpl_propertylist.h>
41 #include <cpl_matrix.h>
42 #include <cpl_image.h>
43 #include <cpl_table.h>
44 
45 #include "gialias.h"
46 #include "gierror.h"
47 #include "gimatrix.h"
48 #include "gifiberutils.h"
49 #include "gigrating.h"
50 #include "gimodel.h"
51 #include "gilocalization.h"
52 #include "giextraction.h"
53 #include "girebinning.h"
54 #include "gisgcalibration.h"
55 
56 
65 struct GiMeasurement {
66  cxdouble value;
67  cxdouble sigma;
68 };
69 
70 typedef struct GiMeasurement GiMeasurement;
71 
72 
73 struct GiSGSetup {
74 
75  cxint nx;
76  cxint nex;
77 
78  GiRebinScale scale;
79 
80  cxdouble wlmin;
81  cxdouble wlmax;
82  cxdouble wlstep;
83 
84  cxdouble pixelsize;
85 
86 };
87 
88 typedef struct GiSGSetup GiSGSetup;
89 
90 
91 struct GiCPFitParams {
92 
93  cxint dnmin;
94  cxint iterations;
95 
96  cxdouble step;
97  cxdouble wfactor;
98  cxdouble sigma;
99 
100  GiRebinScale scale;
101 
102  GiFitSetup fit;
103 
104 };
105 
106 typedef struct GiCPFitParams GiCPFitParams;
107 
108 
109 struct GiCPeakFit {
110  GiMeasurement amplitude;
111  GiMeasurement background;
112  GiMeasurement center;
113  GiMeasurement width;
114 
115  cxint status;
116 };
117 
118 typedef struct GiCPeakFit GiCPeakFit;
119 
120 
121 struct GiSGMask {
122 
123  cxsize size;
124  cxsize nholes;
125 
126  GiRebinScale scale;
127 
128  cxdouble start;
129  cxdouble step;
130 
131  cpl_matrix* wavelength;
132  cpl_matrix* flux;
133 
134 };
135 
136 typedef struct GiSGMask GiSGMask;
137 
138 
139 inline static GiSGMask*
140 _giraffe_sgmask_new(cxsize size)
141 {
142 
143  GiSGMask* self = cx_calloc(1, sizeof *self);
144 
145  self->wavelength = cpl_matrix_new(1, size);
146  self->flux = cpl_matrix_new(1, size);
147 
148  self->size = size;
149  self->nholes = 0;
150 
151  self->scale = GIREBIN_SCALE_LINEAR;
152 
153  self->start = 0.;
154  self->step = 1.;
155 
156  return self;
157 
158 }
159 
160 
161 inline static void
162 _giraffe_sgmask_delete(GiSGMask* self)
163 {
164 
165  if (self) {
166 
167  if (self->wavelength != NULL) {
168  cpl_matrix_delete(self->wavelength);
169  self->wavelength = NULL;
170  }
171 
172  if (self->flux != NULL) {
173  cpl_matrix_delete(self->flux);
174  self->flux = NULL;
175  }
176 
177  cx_free(self);
178 
179  }
180 
181  return;
182 
183 }
184 
185 
186 inline static GiSGMask*
187 _giraffe_sgmask_create(cxsize size, cxdouble start, cxdouble step,
188  GiRebinScale scale, const GiTable* mask)
189 {
190 
191  register cxsize i;
192 
193  cxdouble wlmin = 0.;
194  cxdouble wlmax = 0.;
195  cxdouble wlstep = 0.;
196 
197  cpl_table* _mask = NULL;
198 
199  GiSGMask* self = NULL;
200 
201 
202  cx_assert(mask != NULL);
203 
204  _mask = giraffe_table_get(mask);
205  cx_assert(_mask != NULL);
206 
207  self = _giraffe_sgmask_new(size);
208 
209  self->start = start;
210  self->step = step;
211  self->scale = scale;
212 
213 
214  /*
215  * Fill wavelength array
216  */
217 
218  for (i = 0; i < self->size; i++) {
219  cpl_matrix_set(self->wavelength, 0, i, self->start + i * self->step);
220  }
221 
222 
223  wlmin = cpl_matrix_get(self->wavelength, 0, 0);
224  wlmax = cpl_matrix_get(self->wavelength, 0, self->size - 1);
225  wlstep = self->step;
226 
227  if (self->scale == GIREBIN_SCALE_LOG) {
228 
229  wlmin = exp(wlmin);
230  wlmax = exp(wlmax);
231  wlstep = exp(wlstep);
232 
233  }
234 
235 
236  /*
237  * Create the mask's flux array from the mask template `mask', i.e.
238  * the flux values are set to 1. within the holes and 0. otherwise.
239  */
240 
241  cpl_table_select_all(_mask);
242 
243  cpl_table_and_selected_double(_mask, "WLEN1", CPL_GREATER_THAN, wlmin);
244  cpl_table_and_selected_double(_mask, "WLEN2", CPL_LESS_THAN, wlmax);
245 
246  _mask = cpl_table_extract_selected(_mask);
247 
248  if (_mask == NULL || cpl_table_get_nrow(_mask) <= 0) {
249  _giraffe_sgmask_delete(self);
250  self = NULL;
251 
252  return NULL;
253  }
254 
255 
256  self->nholes = cpl_table_get_nrow(_mask);
257 
258  for (i = 0; i < self->nholes; i++) {
259 
260  register cxsize j;
261 
262  cxdouble hstart = cpl_table_get(_mask, "WLEN1", i, NULL) - wlmin;
263  cxdouble hend = cpl_table_get(_mask, "WLEN2", i, NULL) - wlmin;
264 
265 
266  hstart /= wlstep;
267  hend /= wlstep;
268 
269  for (j = (cxsize)(hstart + 0.5); j <= (cxsize)(hend + 0.5); j++) {
270 
271  cpl_matrix_set(self->flux, 0, j, 1.);
272 
273  }
274 
275  }
276 
277  cpl_table_delete(_mask);
278 
279  return self;
280 
281 }
282 
283 
284 inline static cxsize
285 _giraffe_sgmask_size(const GiSGMask* self)
286 {
287 
288  cx_assert(self != NULL);
289 
290  return self->size;
291 
292 }
293 
294 
295 inline static cxsize
296 _giraffe_sgmask_holes(const GiSGMask* self)
297 {
298 
299  cx_assert(self != NULL);
300 
301  return self->nholes;
302 
303 }
304 
305 
306 inline static cxint
307 _giraffe_sgmask_set_flux(GiSGMask* self, cxsize position, cxdouble value)
308 {
309 
310  cx_assert(self != NULL);
311 
312  if (position >= (cxsize)cpl_matrix_get_ncol(self->flux)) {
313  return 1;
314  }
315 
316  cpl_matrix_set(self->flux, 0, position, value);
317 
318  return 0;
319 
320 }
321 
322 
323 inline static cxdouble
324 _giraffe_sgmask_get_flux(GiSGMask* self, cxsize position)
325 {
326 
327  const cxchar* const fctid = "_giraffe_sgmask_get_flux";
328 
329 
330  cx_assert(self != NULL);
331 
332  if (position >= (cxsize)cpl_matrix_get_ncol(self->flux)) {
333  cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
334  return 0.;
335  }
336 
337  return cpl_matrix_get(self->flux, 0, position);
338 
339 }
340 
341 
342 inline static const cpl_matrix*
343 _giraffe_sgmask_get(GiSGMask* self)
344 {
345 
346  cx_assert(self != NULL);
347 
348  return self->flux;
349 
350 }
351 
352 
353 inline static cxint
354 _giraffe_sgmask_crop(GiSGMask* self, cxsize begin, cxsize end)
355 {
356 
357  cxsize size = 0;
358 
359  cpl_matrix* buffer = NULL;
360 
361 
362  cx_assert(self != NULL);
363  cx_assert(end > begin);
364  cx_assert(cpl_matrix_get_nrow(self->wavelength) == 1);
365  cx_assert(cpl_matrix_get_nrow(self->flux) == 1);
366 
367  if (begin >= (cxsize)cpl_matrix_get_ncol(self->flux)) {
368  return 1;
369  }
370 
371  if (end > (cxsize)cpl_matrix_get_ncol(self->flux)) {
372  end = cpl_matrix_get_ncol(self->flux);
373  }
374 
375  if (begin == 0 && end == (cxsize)cpl_matrix_get_ncol(self->flux)) {
376  return 0;
377  }
378 
379  size = end - begin;
380 
381  buffer = cpl_matrix_extract(self->wavelength, 0, begin, 1, 1, 1, size);
382  cpl_matrix_delete(self->wavelength);
383  self->wavelength = buffer;
384 
385  buffer = cpl_matrix_extract(self->flux, 0, begin, 1, 1, 1, size);
386  cpl_matrix_delete(self->flux);
387  self->flux = buffer;
388 
389  cx_assert(cpl_matrix_get_nrow(self->flux) == 1);
390  cx_assert((cxsize)cpl_matrix_get_ncol(self->flux) == size);
391 
392  self->size = size;
393 
394  return 0;
395 
396 }
397 
398 
399 inline static cxdouble
400 _giraffe_clip_value(cxdouble value, cxdouble low, cxdouble high,
401  cxbool* flag)
402 {
403 
404  cxbool status = FALSE;
405 
406  if (value < low) {
407  value = low;
408  status = TRUE;
409  }
410 
411  if (value >= high) {
412  value = high;
413  status = TRUE;
414  }
415 
416  if (flag != NULL) {
417  *flag = status;
418  }
419 
420  return value;
421 
422 }
423 
424 
425 /*
426  * The function performs a linear interpolation and simultaneous re-sampling
427  * of the input image `signal' from the input bin size `step1' to a signal
428  * with a sampling of `step2'.
429  */
430 
431 inline static cpl_image*
432 _giraffe_resample_image(cpl_image* signal, cxdouble step1, cxdouble step2)
433 {
434 
435  cxint i;
436  cxint nx1 = 0;
437  cxint ny = 0;
438  cxint nx2 = 0;
439  cxint step = CX_MAX(1, (cxint)(step1/step2));
440 
441  cpl_image* _signal = NULL;
442 
443 
444  cx_assert(signal != NULL);
445 
446  ny = cpl_image_get_size_x(signal);
447  nx1 = cpl_image_get_size_y(signal);
448 
449  nx2 = (nx1 - 1) * step + 1;
450 
451  _signal = cpl_image_new(ny, nx2, CPL_TYPE_DOUBLE);
452 
453  for (i = 0; i < ny; i++) {
454 
455  register cxint j;
456 
457  register cxdouble* data = cpl_image_get_data(signal);
458  register cxdouble* _data = cpl_image_get_data(_signal);
459 
460 
461  for (j = 0; j < nx1 - 1; j++) {
462 
463  register cxint k;
464  register cxint l = j * ny + i;
465  register cxint m = j * ny * step + i;
466 
467  for (k = 0; k < step; k++) {
468 
469  cxdouble f = (cxdouble)k / (cxdouble)step;
470 
471  _data[m + k * ny] = (1. - f) * data[l] + f * data[l + ny];
472 
473  }
474 
475  }
476 
477  _data[nx2 - 1] = data[nx1 - 1];
478 
479  }
480 
481  return _signal;
482 
483 }
484 
485 
486 /*
487  * Compute cross-correlation function s * T for the window [start, end]
488  */
489 
490 inline static cpl_matrix*
491 _giraffe_compute_cross_correlation(const cpl_matrix* signal,
492  const cpl_matrix* template,
493  cxint start, cxint end)
494 {
495 
496  const cxchar* const fctid = "_giraffe_compute_cross_correlation";
497 
498 
499  cxint i;
500  cxint n = 0;
501  cxint nmax = 0;
502  cxint ns = 0;
503  cxint nccf = 0;
504 
505  cxdouble sum = 0.;
506 
507  cpl_matrix* _signal = (cpl_matrix*)signal;
508  cpl_matrix* _template = (cpl_matrix*)template;
509  cpl_matrix* ccf = NULL;
510  cpl_matrix* _ccf = NULL;
511 
512 
513  cx_assert(_signal != NULL);
514  cx_assert(cpl_matrix_get_nrow(_signal) == 1);
515 
516  cx_assert(_template != NULL);
517  cx_assert(cpl_matrix_get_nrow(_template) == 1);
518 
519  ns = cpl_matrix_get_ncol(_signal);
520  cx_assert(ns == cpl_matrix_get_ncol(_template));
521 
522  cx_assert(start <= end);
523 
524 
525  /*
526  * The number of shifts should not exceed the half-window
527  */
528 
529  nmax = cpl_matrix_get_ncol(_signal) / 2;
530 
531  start = CX_MAX(CX_MIN(start, nmax), -nmax);
532  end = CX_MAX(CX_MIN(end, nmax), -nmax);
533 
534  nccf = end - start;
535 
536  cpl_msg_debug(fctid, "Cross-correlation function: signal size = %"
537  CPL_SIZE_FORMAT ", template size = %" CPL_SIZE_FORMAT
538  ", window start = %d, window end = %d",
539  cpl_matrix_get_ncol(_signal), cpl_matrix_get_ncol(_template),
540  start, end);
541 
542 
543  ccf = cpl_matrix_new(1, nccf);
544 
545  for (i = start; i < end; i++) {
546 
547  if (i < 0) {
548 
549  cxint j;
550 
551 
552  /*
553  * - shift template i < 0
554  */
555 
556  sum = 0.;
557 
558  for (j = 0; j < ns + i; j++) {
559 
560  cxdouble s = cpl_matrix_get(_signal, 0, j);
561  cxdouble t = cpl_matrix_get(_template, 0, j - i);
562 
563  sum += t * s;
564 
565  }
566 
567  sum /= (cxdouble)(ns + i);
568 
569  cpl_matrix_set(ccf, 0, i - start, sum);
570 
571  }
572  else if (i > 0) {
573 
574  cxint j;
575 
576 
577  /*
578  * + shift template i > 0
579  */
580 
581  sum = 0.;
582 
583  for (j = i; j < ns; j++) {
584 
585  cxdouble s = cpl_matrix_get(_signal, 0, j);
586  cxdouble t = cpl_matrix_get(_template, 0, j - i);
587 
588  sum += t * s;
589 
590  }
591 
592  sum /= (cxdouble)(ns - i);
593 
594  cpl_matrix_set(ccf, 0, i - start, sum);
595 
596  }
597  else {
598 
599  cxint j;
600 
601 
602  /*
603  * The central value
604  */
605 
606  sum = 0.;
607 
608  for (j = 0; j < ns; j++) {
609 
610  cxdouble t = cpl_matrix_get(_template, 0, j);
611  cxdouble s = cpl_matrix_get(_signal, 0, j);
612 
613  sum += t * s;
614 
615  }
616 
617  sum /= (cxdouble)ns;
618 
619  cpl_matrix_set(ccf, 0, -start, sum);
620 
621  }
622 
623 
624  }
625 
626 
627  /*
628  * Normalize peak to approximately 1.0. For this purpose the 10% of
629  * the cross-correlation function's data points with the highest
630  * values are used.
631  */
632 
633  n = CX_MAX(1, nccf / 10);
634 
635  _ccf = cpl_matrix_duplicate(ccf);
636  giraffe_matrix_sort(_ccf);
637 
638  sum = 0.;
639 
640  for (i = nccf - n; i < nccf; i++) {
641  sum += cpl_matrix_get(_ccf, 0, i);
642  }
643 
644  sum /= (cxdouble)n;
645 
646  cpl_matrix_delete(_ccf);
647  _ccf = NULL;
648 
649  if (sum != 0.) {
650 
651  for (i = 0; i < nccf; i++) {
652  cpl_matrix_set(ccf, 0, i, cpl_matrix_get(ccf, 0, i) / sum);
653  }
654 
655  }
656 
657  return ccf;
658 
659 }
660 
661 
662 inline static cxint
663 _giraffe_create_setup(GiSGSetup* setup, const GiImage* spectra)
664 {
665 
666  cpl_propertylist* properties = NULL;
667 
668  cpl_image* _spectra = NULL;
669 
670 
671  cx_assert(setup != NULL);
672  cx_assert(spectra != NULL);
673 
674  properties = giraffe_image_get_properties(spectra);
675  cx_assert(properties != NULL);
676 
677  _spectra = giraffe_image_get(spectra);
678  cx_assert(_spectra != NULL);
679 
680 
681  /*
682  * Retrieve rebinned spectra information.
683  */
684 
685  setup->nx = cpl_image_get_size_y(_spectra);
686 
687 
688  if (!cpl_propertylist_has(properties, GIALIAS_EXT_NX)) {
689  return 1;
690  }
691  else {
692 
693  setup->nex = cpl_propertylist_get_int(properties, GIALIAS_EXT_NX);
694 
695  }
696 
697  if (!cpl_propertylist_has(properties, GIALIAS_BINSCALE)) {
698  return 1;
699  }
700  else {
701 
702  const cxchar* s = cpl_propertylist_get_string(properties,
703  GIALIAS_BINSCALE);
704 
705 
706  if (cx_strncasecmp(s, "log", 3) == 0) {
707  setup->scale = GIREBIN_SCALE_LOG;
708  }
709  else {
710  setup->scale = GIREBIN_SCALE_LINEAR;
711  }
712 
713  }
714 
715  if (!cpl_propertylist_has(properties, GIALIAS_BINWLMIN)) {
716  return 1;
717  }
718  else {
719  setup->wlmin = cpl_propertylist_get_double(properties,
720  GIALIAS_BINWLMIN);
721  }
722 
723  if (!cpl_propertylist_has(properties, GIALIAS_BINSTEP)) {
724  return 1;
725  }
726  else {
727  setup->wlstep = cpl_propertylist_get_double(properties,
728  GIALIAS_BINSTEP);
729  }
730 
731  setup->wlmax = setup->wlmin + (setup->nx - 1) * setup->wlstep;
732 
733 
734  if (!cpl_propertylist_has(properties, GIALIAS_PIXSIZY)) {
735  return 1;
736  }
737  else {
738  setup->pixelsize = cpl_propertylist_get_double(properties,
739  GIALIAS_PIXSIZY);
740  }
741 
742  return 0;
743 
744 }
745 
746 
747 inline static cxint
748 _giraffe_peak_fit(GiCPeakFit* peak, const cpl_matrix* lambda,
749  const cpl_matrix* ccf, const GiGrating* grating,
750  const GiCPFitParams* setup)
751 {
752 
753  const cxchar* const fctid = "_giraffe_peak_fit";
754 
755 
756  cxbool stop = FALSE;
757 
758  cxint i;
759  cxint dn1 = 0;
760  cxint dn2 = 0;
761 
762  cxdouble amplitude = 0.;
763  cxdouble background = 0.;
764  cxdouble center = 0.;
765  cxdouble width = 0.;
766  cxdouble lower = 0.;
767  cxdouble upper = 0.;
768 
769  struct {
770  cxdouble amplitude;
771  cxdouble background;
772  cxdouble center;
773  cxdouble width;
774  } initial = {0., 0., 0., 0.};
775 
776  cpl_size nr = 0;
777  cpl_size nc = 0;
778 
779  GiModel* model = giraffe_model_new("gaussian");
780 
781 
782 
783  cx_assert(model != NULL);
784  cx_assert(strcmp(giraffe_model_get_name(model), "gaussian") == 0);
785  cx_assert(lambda != NULL);
786  cx_assert(ccf != NULL);
787  cx_assert(grating != NULL);
788  cx_assert(setup != NULL);
789 
790 
791  /*
792  * Initial guesses of the peak profile model. For the background
793  * 0. can be used in case of ThAr spectra, otherwise the mean of
794  * the 2 lowest values of the CCF should be used. The half-width
795  * is derived from the nominal resolution of the grating.
796  */
797 
798  background = 0.;
799 
800  amplitude = cpl_matrix_get_max((cpl_matrix*)ccf) - background;
801 
802  cpl_matrix_get_maxpos((cpl_matrix*)ccf, &nr, &nc);
803  cx_assert(nr == 0);
804 
805  center = cpl_matrix_get((cpl_matrix*)lambda, 0, nc);
806 
807 
808  if (setup->scale == GIREBIN_SCALE_LOG) {
809  width = 0.5 / grating->resol;
810  }
811  else {
812  width = 0.5 / grating->resol * grating->wlen0;
813  }
814 
815  giraffe_model_set_parameter(model, "Background", background);
816  giraffe_model_set_parameter(model, "Amplitude", amplitude);
817  giraffe_model_set_parameter(model, "Center", center);
818  giraffe_model_set_parameter(model, "Width1", width);
819 
820  giraffe_model_thaw(model);
821 
822  giraffe_model_set_iterations(model, setup->fit.iterations);
823  giraffe_model_set_tests(model, setup->fit.tests);
824  giraffe_model_set_delta(model, setup->fit.delta);
825 
826 
827  /*
828  * Save the initial parameter values.
829  */
830 
831  initial.amplitude = amplitude;
832  initial.background = background;
833  initial.center = center;
834  initial.width = width;
835 
836  i = 0;
837 
838  while (i < setup->iterations && !stop) {
839 
840  cxint j;
841  cxint _dn1 = 0;
842  cxint _dn2 = 0;
843 
844  cxdouble dwc = 0.;
845  cxdouble dwd = 0.;
846 
847  cpl_matrix* tlambda = (cpl_matrix*)lambda;
848  cpl_matrix* tccf = (cpl_matrix*)ccf;
849 
850 
851  /*
852  * The second iteration uses a weighted mean of the initial guess and
853  * the first result. For all further iterations the new parameter
854  * values are just taken from the previous iteration.
855  */
856 
857  if (i == 1) {
858 
859  const cxdouble da = 0.2;
860  const cxdouble dc = 1.;
861  const cxdouble db = 1.;
862  const cxdouble dw = 0.2;
863 
864  cxdouble value = 0.;
865 
866  value = giraffe_model_get_parameter(model, "Amplitude") * da;
867  value += (1. - da) * initial.amplitude;
868 
869  giraffe_model_set_parameter(model, "Amplitude", value);
870 
871 
872  value = giraffe_model_get_parameter(model, "Center") * dc;
873  value += (1. - dc) * initial.center;
874 
875  giraffe_model_set_parameter(model, "Center", value);
876 
877 
878  value = giraffe_model_get_parameter(model, "Background") * db;
879  value += (1. - db) * initial.background;
880 
881  giraffe_model_set_parameter(model, "Background", value);
882 
883 
884  value = giraffe_model_get_parameter(model, "Width1") * dw;
885  value += (1. - dw) * initial.width;
886 
887  giraffe_model_set_parameter(model, "Width1", value);
888 
889  }
890 
891 
892  /*
893  * Set the window center and width. For the width a lower limit is
894  * established to guarantee a minimum number of point for the fit.
895  */
896 
897  dwd = 2. * giraffe_model_get_parameter(model, "Width1") *
898  setup->wfactor;
899  dwc = giraffe_model_get_parameter(model, "Center");
900 
901  dwd = CX_MAX(setup->dnmin, 2. * dwd / setup->step) * setup->step / 2.;
902 
903  lower = dwc + 0.5 * setup->step - dwd;
904  upper = dwc + 0.5 * setup->step + dwd;
905 
906 
907  /*
908  * Extract the slices corresponding to the reduced window size
909  * from the input data arrays. This is the data set which is
910  * actually fitted.
911  */
912 
913  for (j = 0; j < cpl_matrix_get_ncol(tlambda); j++) {
914 
915  if (cpl_matrix_get(tlambda, 0, j) > lower) {
916  _dn1 = j;
917  break;
918  }
919 
920  }
921 
922  for (j = cpl_matrix_get_ncol(tlambda) - 1; j >= 0; j--) {
923 
924  if (cpl_matrix_get(tlambda, 0, j) < upper) {
925  _dn2 = j + 1;
926  break;
927  }
928 
929  }
930 
931 
932  if (i > 0 && dn1 == _dn1 && dn2 == _dn2) {
933 
934  cxdouble _width = giraffe_model_get_parameter(model, "Width1");
935 
936  /*
937  * This is the same set of points. The fitting stops after
938  * one last iteration on the further reduced data set.
939  */
940 
941  dwd = CX_MAX(setup->dnmin, 4. * _width * setup->wfactor /
942  setup->step) * setup->step / 2.;
943 
944  lower = dwc + 0.5 * setup->step - dwd;
945  upper = dwc + 0.5 * setup->step + dwd;
946 
947  for (j = 0; j < cpl_matrix_get_ncol(tlambda); j++) {
948 
949  if (cpl_matrix_get(tlambda, 0, j) > lower) {
950  _dn1 = j;
951  break;
952  }
953 
954  }
955 
956  for (j = cpl_matrix_get_ncol(tlambda) - 1; j <= 0; j--) {
957 
958  if (cpl_matrix_get(tlambda, 0, j) < upper) {
959  _dn2 = j + 1;
960  break;
961  }
962 
963  }
964 
965  stop = TRUE;
966 
967  }
968 
969 
970  /* FIXME: The original code uses i == 0 instead of i <= 1. Check
971  * whether there is a reason for that or if this is just
972  * a bug.
973  */
974 
975  if (i <= 1 || dn1 != _dn1 || dn2 != _dn2) {
976 
977  cxbool flag = FALSE;
978 
979  const cxint pflag = 1;
980  cxint status = 0;
981 
982  cxdouble damplitude = 0.;
983  cxdouble dbackground = 0.;
984  cxdouble dcenter = 0.;
985  cxdouble dwidth = 0.;
986 
987  cpl_matrix* x = NULL;
988  cpl_matrix* y = NULL;
989  cpl_matrix* sigma = NULL;
990 
991 
992  dn1 = _dn1;
993  dn2 = _dn2;
994 
995  x = cpl_matrix_new(dn2 - dn1, 1);
996  y = cpl_matrix_new(dn2 - dn1, 1);
997  sigma = cpl_matrix_new(dn2 - dn1, 1);
998 
999  for (j = 0; j < cpl_matrix_get_nrow(y); j++) {
1000 
1001  cpl_matrix_set(x, j, 0, cpl_matrix_get(tlambda, 0, dn1 + j));
1002  cpl_matrix_set(y, j, 0, cpl_matrix_get(tccf, 0, dn1 + j));
1003  cpl_matrix_set(sigma, j, 0, setup->sigma);
1004 
1005  }
1006 
1007 
1008  /*
1009  * Finally, fit the peak profile.
1010  */
1011 
1012  status = giraffe_model_fit(model, x, y, sigma);
1013 
1014  if (status != 0) {
1015 
1016  peak->amplitude.value = initial.amplitude;
1017  peak->background.value = initial.background;
1018  peak->center.value = initial.center;
1019  peak->width.value = initial.width;
1020 
1021  peak->amplitude.sigma = 1.;
1022  peak->background.sigma = 1.;
1023  peak->center.sigma = 1.;
1024  peak->width.sigma = 1.;
1025 
1026  peak->status = -1;
1027 
1028  cpl_matrix_delete(x);
1029  cpl_matrix_delete(y);
1030  cpl_matrix_delete(sigma);
1031 
1032  giraffe_model_delete(model);
1033 
1034  return 1;
1035 
1036  }
1037 
1038 
1039  /*
1040  * Check `out of bounds' condition for the fitted parameters.
1041  * and their uncertainties.
1042  */
1043 
1044  amplitude = giraffe_model_get_parameter(model, "Amplitude");
1045  damplitude = giraffe_model_get_sigma(model, "Amplitude");
1046 
1047  center = giraffe_model_get_parameter(model, "Center");
1048  dcenter = giraffe_model_get_sigma(model, "Center");
1049 
1050  background = giraffe_model_get_parameter(model, "Background");
1051  dbackground = giraffe_model_get_sigma(model, "Background");
1052 
1053  width = giraffe_model_get_parameter(model, "Width1");
1054  dwidth = giraffe_model_get_sigma(model, "Width1");
1055 
1056 
1057  /* FIXME: Where do these limits come from? (RP)
1058  */
1059 
1060  /* Amplitude */
1061 
1062  lower = -9. * (1 - pflag) + 1.e-5 * pflag;
1063  upper = 9. * pflag - 1.e-5 * (1 - pflag);
1064 
1065  peak->amplitude.value = _giraffe_clip_value(amplitude, lower,
1066  upper, &flag);
1067  peak->amplitude.sigma = _giraffe_clip_value(damplitude, 0.,
1068  1., NULL);
1069 
1070  stop = stop == FALSE ? flag == TRUE ? TRUE : FALSE : stop;
1071 
1072  /* Center */
1073 
1074  lower = cpl_matrix_get(x, 1, 0);
1075  upper = cpl_matrix_get(x, cpl_matrix_get_nrow(x) - 2, 0);
1076 
1077  peak->center.value = _giraffe_clip_value(center, lower,
1078  upper, &flag);
1079  peak->center.sigma = _giraffe_clip_value(dcenter, 0.,
1080  initial.width, NULL);
1081 
1082  stop = stop == FALSE ? flag == TRUE ? TRUE : FALSE : stop;
1083 
1084  /* Background */
1085 
1086  lower = -2;
1087  upper = 2.;
1088 
1089  peak->background.value = _giraffe_clip_value(background, lower,
1090  upper, &flag);
1091  peak->background.sigma = _giraffe_clip_value(dbackground, 0.,
1092  1., NULL);
1093 
1094  stop = stop == FALSE ? flag == TRUE ? TRUE : FALSE : stop;
1095 
1096  /* Width */
1097 
1098  lower = 0.5 * initial.width;
1099  upper = 2. * (cpl_matrix_get(x, cpl_matrix_get_nrow(x) - 2, 0) -
1100  cpl_matrix_get(x, 0, 0));
1101 
1102  peak->width.value = _giraffe_clip_value(width, lower,
1103  upper, &flag);
1104  peak->width.sigma = _giraffe_clip_value(dwidth, 0.,
1105  9., NULL);
1106 
1107  stop = stop == FALSE ? flag == TRUE ? TRUE : FALSE : stop;
1108 
1109  cpl_matrix_delete(x);
1110  cpl_matrix_delete(y);
1111  cpl_matrix_delete(sigma);
1112 
1113  if (stop == TRUE) {
1114  cpl_msg_debug(fctid, "Cross-correlation peak fit "
1115  "parameter out of bounds!");
1116 
1117  peak->status = 1;
1118  }
1119  else {
1120  peak->status = 0;
1121  }
1122 
1123  ++i;
1124 
1125  }
1126  else {
1127 
1128  stop = TRUE;
1129 
1130  }
1131 
1132  }
1133 
1134  giraffe_model_delete(model);
1135 
1136  return 0;
1137 
1138 }
1139 
1140 
1141 inline static cxint
1142 _giraffe_compute_fiber_offsets(cpl_table* offsets,
1143  const GiGrating* grating,
1144  const GiSGSetup* setup)
1145 {
1146 
1147  cxint i;
1148 
1149  const cxdouble ccdfactor = 1.1;
1150 
1151  cxdouble gcamera = 1.;
1152  cxdouble cfactor = 1.;
1153  cxdouble lincorr = 1.;
1154  cxdouble wlen0 = 0.;
1155 
1156 
1157  cx_assert(offsets != NULL);
1158 
1159  if (!cpl_table_has_column(offsets, "WAVELENGTH")) {
1160  return 1;
1161  }
1162 
1163  if (!cpl_table_has_column(offsets, "DWF")) {
1164  cpl_table_new_column(offsets, "DWF", CPL_TYPE_DOUBLE);
1165  }
1166 
1167  if (!cpl_table_has_column(offsets, "DXF")) {
1168  cpl_table_new_column(offsets, "DXF", CPL_TYPE_DOUBLE);
1169  }
1170 
1171 
1172  /*
1173  * Compute the central wavelength of the spectral band, taking into
1174  * account the scaling used to rebin the spectra.
1175  */
1176 
1177  if (setup->scale == GIREBIN_SCALE_LOG) {
1178  wlen0 = 0.5 * (exp(setup->wlmin) + exp(setup->wlmax));
1179  }
1180  else {
1181  wlen0 = 0.5 * (setup->wlmin + setup->wlmax);
1182  }
1183 
1184 
1185  /*
1186  * Approximate magnification of the camera.
1187  */
1188 
1189  /*
1190  * FIXME: Any hint on these numbers? (RP)
1191  */
1192 
1193  gcamera = 0.3894 - 5. * (1. / wlen0 - 1. / 550.) -
1194  0.00025 * pow(1. / wlen0 - 1. / 550., 2.);
1195 
1196  /*
1197  * Conversion factor from CCD displacement to slit geometry.
1198  */
1199 
1200  /* FIXME: This will be used until there is a better formula
1201  * (OGL comment).
1202  */
1203 
1204  cfactor = (setup->nex * setup->pixelsize / 1000. * ccdfactor) /
1205  ((grating->wlenmax - grating->wlenmin) * gcamera);
1206 
1207 
1208  /*
1209  * Correction factor for linear scale on the correlation
1210  */
1211 
1212  if (setup->scale == GIREBIN_SCALE_LOG) {
1213  lincorr = 1.0;
1214  }
1215  else {
1216  lincorr = 0.5 * (setup->wlmin + setup->wlmax) /
1217  exp(0.5 * (log(setup->wlmin) + log(setup->wlmax)));
1218  }
1219 
1220 
1221  /*
1222  * Compute slit offsets
1223  */
1224 
1225  for (i = 0; i < cpl_table_get_nrow(offsets); i++) {
1226 
1227 
1228  cxdouble dwf = cpl_table_get_double(offsets, "WAVELENGTH", i, NULL);
1229  cxdouble dxf = 0.;
1230 
1231 
1232  dwf *= -lincorr;
1233  dxf = dwf * cfactor;
1234 
1235  cpl_table_set_double(offsets, "DWF", i, dwf);
1236  cpl_table_set_double(offsets, "DXF", i, dxf);
1237 
1238  }
1239 
1240  return 0;
1241 
1242 }
1243 
1244 
1245 inline static cpl_table*
1246 _giraffe_compute_offsets(const GiImage* spectra, const GiTable* mask,
1247  const cpl_table* fibers, const GiGrating* grating,
1248  const GiSGSetup* setup, const GiSGCalConfig* config)
1249 {
1250 
1251  const cxchar* const fctid = "_giraffe_compute_offsets";
1252 
1253  const cxint dnmin = 7; /* Minimum number of points */
1254 
1255  cxint i;
1256  cxint k;
1257  cxint status = 0;
1258  cxint sampling = 0;
1259  cxint pixel0 = 0;
1260  cxint dn1 = 0;
1261  cxint dn2 = 0;
1262  cxint dnc = 0;
1263  cxint dnd = 0;
1264  cxint xc1 = 0;
1265  cxint xc2 = 0;
1266 
1267  const cxdouble clight = 299702.547; /* Vacuum light speed [km/s] */
1268 
1269  cxdouble cstep = 0.;
1270  cxdouble wlen0 = 0.;
1271  cxdouble nm2km = clight;
1272  cxdouble hpixels = 0.;
1273  cxdouble dv1 = 0.;
1274  cxdouble dv2 = 0.;
1275  cxdouble dw1 = 0.;
1276  cxdouble dw2 = 0.;
1277  cxdouble dwc = 0.;
1278  cxdouble dwd = 0.;
1279 
1280  cpl_matrix* spectrum = NULL;
1281 
1282  cpl_image* _spectra = NULL;
1283  cpl_image* tspectra = NULL;
1284 
1285  cpl_table* peakdata = NULL;
1286 
1287  GiSGMask* _mask = NULL;
1288 
1289 
1290  cx_assert(spectra != NULL);
1291  cx_assert(mask != NULL);
1292  cx_assert(fibers != NULL);
1293  cx_assert(grating != NULL);
1294  cx_assert(setup != NULL);
1295  cx_assert(config != NULL);
1296 
1297 
1298  /*
1299  * Compute the sampling step size
1300  */
1301 
1302  if (config->cc_step <= 0.) {
1303  sampling = 1;
1304  }
1305  else {
1306 
1307  if (setup->scale == GIREBIN_SCALE_LOG) {
1308 
1309  cxdouble wlstep = (exp(setup->wlmax) - exp(setup->wlmin)) /
1310  setup->nx;
1311 
1312  sampling = (cxint)(0.5 + wlstep / config->cc_step);
1313 
1314  }
1315  else {
1316 
1317  sampling = (cxint)(0.5 + setup->wlstep / config->cc_step);
1318 
1319  }
1320 
1321  }
1322 
1323  cstep = setup->wlstep / sampling;
1324 
1325 
1326  /*
1327  * Create and initialize the final mask
1328  */
1329 
1330  _mask = _giraffe_sgmask_create((setup->nx - 1) * sampling + 1,
1331  setup->wlmin, cstep, setup->scale,
1332  mask);
1333 
1334  if (_mask == NULL) {
1335  return NULL;
1336  }
1337 
1338 
1339  /*
1340  * Prepare the initial window
1341  */
1342 
1343  pixel0 = setup->nx / 2;
1344 
1345  if (setup->scale == GIREBIN_SCALE_LOG) {
1346 
1347  /*
1348  * Logarithmic scale: dv / clight = d(log(lambda))
1349  */
1350 
1351  wlen0 = 0.5 * (exp(setup->wlmin) + exp(setup->wlmax));
1352  nm2km = clight;
1353 
1354  }
1355  else {
1356 
1357  /*
1358  * Linear scale: dv / clight = d(log(lambda)) / lambda
1359  */
1360 
1361  wlen0 = 0.5 * (setup->wlmin + setup->wlmax);
1362  nm2km = clight / wlen0;
1363 
1364  }
1365 
1366 
1367  /*
1368  * Window limits in km/s, nm and pxl and window center and
1369  * half-width in nm and pxl.
1370  */
1371 
1372  dv1 = giraffe_range_get_min(config->rv_limits);
1373  dv2 = giraffe_range_get_max(config->rv_limits);
1374 
1375  dw1 = dv1 / nm2km;
1376  dw2 = dv2 / nm2km;
1377 
1378  cpl_msg_debug(fctid, "Cross-correlation limits: RVlow = %.4f km/s "
1379  "(%.4f nm), RVhigh = %.4f km/s (%.4f nm)", dv1, dw1,
1380  dv2, dw2);
1381 
1382  dwd = (dw2 - dw1) / 2.;
1383  dwc = (dw2 + dw1) / 2.;
1384 
1385  dnd = CX_MIN(pixel0, CX_MAX(dnmin, (cxint)(dwd / cstep + 0.5)));
1386  dnc = CX_MIN(pixel0, CX_MAX(-pixel0, (cxint)(dwc / cstep + 0.5)));
1387 
1388  dn1 = CX_MIN(pixel0 + 1, CX_MAX(-pixel0, dnc - dnd));
1389  dn2 = CX_MIN(pixel0 + 1, CX_MAX(-pixel0, dnc + dnd + 1));
1390 
1391  cpl_msg_debug(fctid, "Cross-correlation window: center = %.4f nm "
1392  "(%d pxl) half-width = %.4f nm (%d pxl)", dwc, dnc,
1393  dwd, dnd);
1394 
1395 
1396  /*
1397  * Select spectral range of the spectra and the template which should
1398  * be used for the cross-correlation.
1399  */
1400 
1401  xc1 = (cxint)(giraffe_range_get_min(config->cc_domain) * sampling);
1402  xc2 = (cxint)(giraffe_range_get_max(config->cc_domain) * sampling);
1403 
1404  if (xc1 > 0 || xc2 > 0) {
1405  _giraffe_sgmask_crop(_mask, xc1, xc2);
1406  }
1407 
1408  for (i = 0; (cxsize)i < _giraffe_sgmask_size(_mask); i++) {
1409 
1410  cxdouble value = _giraffe_sgmask_get_flux(_mask, i);
1411 
1412  if (value > 0.) {
1413  hpixels += value;
1414  }
1415 
1416  }
1417 
1418  hpixels /= _giraffe_sgmask_holes(_mask);
1419 
1420 
1421  /*
1422  * The left- and rightmost dn1 points of the mask are set to 0. In
1423  * addition partial holes at the beginning and the end of the mask
1424  * removed, i.e. set to 0 flux.
1425  */
1426 
1427  i = 0;
1428  k = CX_MAX(0, -dn1);
1429 
1430  while (i < k || _giraffe_sgmask_get_flux(_mask, i) > 0.) {
1431 
1432  _giraffe_sgmask_set_flux(_mask, i, 0.);
1433  ++i;
1434 
1435  }
1436 
1437  cpl_msg_debug(fctid, "Mask cleared from 0 to %d", i - 1);
1438 
1439  i = _giraffe_sgmask_size(_mask);
1440  k = _giraffe_sgmask_size(_mask) - CX_MAX(0, dn2);
1441 
1442  while (i > k || _giraffe_sgmask_get_flux(_mask, i) > 0.) {
1443 
1444  _giraffe_sgmask_set_flux(_mask, i, 0.);
1445  --i;
1446 
1447  }
1448 
1449  cpl_msg_debug(fctid, "Mask cleared from %d to %ld", k,
1450  _giraffe_sgmask_size(_mask) - 1);
1451 
1452 
1453  /*
1454  * Resample the input image to the mask's sampling step and crop its
1455  * spectral range so that it matches the template.
1456  */
1457 
1458  _spectra = cpl_image_duplicate(giraffe_image_get(spectra));
1459 
1460  if (_spectra == NULL) {
1461 
1462  _giraffe_sgmask_delete(_mask);
1463 
1464  return NULL;
1465 
1466  }
1467 
1468 
1469  if (config->zmax > 0.) {
1470 
1471  cpl_image_threshold(_spectra, CX_MINDOUBLE, config->zmax,
1472  0., config->zmax);
1473 
1474  }
1475 
1476 
1477  tspectra = _giraffe_resample_image(_spectra, setup->wlstep, cstep);
1478 
1479  if (tspectra == NULL) {
1480 
1481  cpl_image_delete(_spectra);
1482 
1483  _giraffe_sgmask_delete(_mask);
1484 
1485  return NULL;
1486 
1487  }
1488 
1489  cpl_image_delete(_spectra);
1490  _spectra = NULL;
1491 
1492  if (xc1 > 0 || xc2 > 0) {
1493 
1494  _spectra = cpl_image_extract(tspectra, 1, xc1 + 1,
1495  cpl_image_get_size_x(tspectra), xc2 + 1);
1496 
1497  if (_spectra == NULL) {
1498 
1499  cpl_image_delete(tspectra);
1500 
1501  _giraffe_sgmask_delete(_mask);
1502 
1503  return NULL;
1504 
1505  }
1506 
1507  cpl_image_delete(tspectra);
1508  tspectra = NULL;
1509 
1510  }
1511  else {
1512 
1513  _spectra = tspectra;
1514  tspectra = NULL;
1515 
1516  }
1517 
1518 
1519  /*
1520  * Create the table to record the results from the cross-correlation
1521  * peak fitting for each fiber.
1522  */
1523 
1524  peakdata = cpl_table_new(cpl_table_get_nrow(fibers));
1525 
1526  cpl_table_duplicate_column(peakdata, "INDEX", (cpl_table*)fibers,
1527  "INDEX");
1528  cpl_table_duplicate_column(peakdata, "FPS", (cpl_table*)fibers,
1529  "FPS");
1530 
1531  cpl_table_new_column(peakdata, "WAVELENGTH", CPL_TYPE_DOUBLE);
1532  cpl_table_new_column(peakdata, "FWHM", CPL_TYPE_DOUBLE);
1533  cpl_table_new_column(peakdata, "AMPLITUDE", CPL_TYPE_DOUBLE);
1534  cpl_table_new_column(peakdata, "BACKGROUND", CPL_TYPE_DOUBLE);
1535  cpl_table_new_column(peakdata, "RV", CPL_TYPE_DOUBLE);
1536  cpl_table_new_column(peakdata, "RVERR", CPL_TYPE_DOUBLE);
1537  cpl_table_new_column(peakdata, "RESOLUTION", CPL_TYPE_DOUBLE);
1538  cpl_table_new_column(peakdata, "STATUS", CPL_TYPE_INT);
1539 
1540 
1541  /*
1542  * Compute the cross-correlation with the mask for each spectrum in
1543  * the input image.
1544  */
1545 
1546  cpl_msg_debug(fctid, "Computing cross-correlation: central wavelength = "
1547  "%.4f, window = [%.4f, %.4f] [km/s]", wlen0, dv1, dv2);
1548 
1549  spectrum = cpl_matrix_new(1, cpl_image_get_size_y(_spectra));
1550 
1551  for (i = 0; i < cpl_table_get_nrow(fibers); i++) {
1552 
1553  cxint j;
1554  cxint ns = cpl_image_get_size_x(_spectra);
1555  cxint fiber = cpl_table_get_int(fibers, "FPS", i, NULL);
1556  cxint idx = cpl_table_get_int(fibers, "INDEX", i, NULL) - 1;
1557 
1558  const cxdouble fwhm_ratio = 2. * sqrt(2. * log(2.));
1559 
1560  cxdouble avsigma = 0.;
1561  cxdouble fx = 0.;
1562  cxdouble fxtotal = 0.;
1563  cxdouble fxaverage = 0.;
1564  cxdouble fxmask = 0.;
1565  cxdouble sum = 0.;
1566  cxdouble position = 0.;
1567  cxdouble fwhm = 0.;
1568  cxdouble width = 0.;
1569  cxdouble resolution = 0.;
1570  cxdouble rv = 0.;
1571  cxdouble rverr = 0.;
1572  cxdouble* data = cpl_image_get_data(_spectra);
1573 
1574  const cpl_matrix* template = NULL;
1575  cpl_matrix* ccf = NULL;
1576  cpl_matrix* lambda = NULL;
1577 
1578  GiCPFitParams peak_setup;
1579  GiCPeakFit peak;
1580 
1581 
1582 
1583  /*
1584  * Copy the current spectrum to the working matrix and
1585  * compute the total flux of the masked spectrum.
1586  */
1587 
1588  for (j = 0; j < cpl_matrix_get_ncol(spectrum); j++) {
1589 
1590  cxdouble flux = data[j * ns + idx];
1591 
1592 
1593  cpl_matrix_set(spectrum, 0, j, flux);
1594 
1595  fxtotal += flux;
1596  fxmask += _giraffe_sgmask_get_flux(_mask, j);
1597  fx += flux * _giraffe_sgmask_get_flux(_mask, j);
1598 
1599  }
1600 
1601  fx /= sampling;
1602  fxaverage = fxtotal / fxmask;
1603 
1604  if (fx > 0.) {
1605  avsigma = 1. / sqrt(fx);
1606  }
1607 
1608  cpl_msg_debug(fctid, "Cross-correlation of spectrum %d in window "
1609  "from %d pxl to %d pxl (%.4f nm to %.4f nm)", fiber,
1610  dn1, dn2, dw1, dw2);
1611 
1612 
1613  /*
1614  * Wavelength within the cross-correlation window
1615  */
1616 
1617  lambda = cpl_matrix_new(1, dn2 - dn1);
1618 
1619  for (j = dn1; j < dn2; j++) {
1620  cpl_matrix_set(lambda, 0, j - dn1, j * cstep);
1621  }
1622 
1623 
1624  /*
1625  * Cross-correlation
1626  */
1627 
1628  template = _giraffe_sgmask_get(_mask);
1629 
1630  ccf = _giraffe_compute_cross_correlation(spectrum, template, dn1, dn2);
1631 
1632  if (ccf == NULL) {
1633 
1634  cpl_matrix_delete(lambda);
1635  cpl_matrix_delete(spectrum);
1636 
1637  cpl_image_delete(_spectra);
1638 
1639  cpl_table_delete(peakdata);
1640 
1641  _giraffe_sgmask_delete(_mask);
1642 
1643  return NULL;
1644 
1645  }
1646 
1647  sum = 0.;
1648 
1649  for (j = 0; j < cpl_matrix_get_ncol(ccf); j++) {
1650  sum += cpl_matrix_get(ccf, 0, j);
1651  }
1652 
1653  if (sum <= 0.) {
1654  cpl_msg_debug(fctid, "Cross-correlation failed: Skipping "
1655  "spectrum %d.", fiber);
1656 
1657  cpl_matrix_delete(lambda);
1658  lambda = NULL;
1659 
1660  continue;
1661  }
1662 
1663 
1664  /*
1665  * Fit the cross-correlation peak
1666  */
1667 
1668  peak_setup.dnmin = dnmin;
1669  peak_setup.iterations = config->rv_niter;
1670  peak_setup.step = cstep;
1671  peak_setup.wfactor = config->rv_wfactor;
1672  peak_setup.sigma = avsigma;
1673  peak_setup.scale = setup->scale;
1674 
1675  peak_setup.fit.iterations = config->pf_niter;
1676  peak_setup.fit.tests = config->pf_ntest;
1677  peak_setup.fit.delta = config->pf_dchisq;
1678 
1679  status = _giraffe_peak_fit(&peak, lambda, ccf, grating, &peak_setup);
1680 
1681  if (status < 0) {
1682 
1683  cpl_matrix_delete(ccf);
1684  cpl_matrix_delete(lambda);
1685 
1686  cpl_matrix_delete(spectrum);
1687  cpl_image_delete(_spectra);
1688 
1689  cpl_table_delete(peakdata);
1690 
1691  _giraffe_sgmask_delete(_mask);
1692 
1693  return NULL;
1694 
1695  }
1696 
1697 
1698  /*
1699  * Save the results to the output table.
1700  */
1701 
1702  if (setup->scale == GIREBIN_SCALE_LOG) {
1703  position = peak.center.value * wlen0;
1704  fwhm = (exp(peak.width.value) - 1.) * wlen0;
1705  }
1706  else {
1707  position = peak.center.value;
1708  fwhm = peak.width.value;
1709  }
1710 
1711  width = pow(fwhm_ratio * fwhm, 2.) - pow(0.6 * hpixels * cstep, 2.);
1712  resolution = width > 0. ? wlen0 / sqrt(width) : 0.;
1713 
1714  fwhm *= 2.;
1715 
1716  rv = CX_MAX(dv1, CX_MIN(dv2, peak.center.value * nm2km));
1717  rverr = CX_MIN(dv2 - dv1, peak.center.sigma * nm2km);
1718 
1719  cpl_table_set_double(peakdata, "WAVELENGTH", i, position);
1720  cpl_table_set_double(peakdata, "FWHM", i, fwhm);
1721  cpl_table_set_double(peakdata, "AMPLITUDE", i, peak.amplitude.value);
1722  cpl_table_set_double(peakdata, "BACKGROUND", i,
1723  peak.background.value);
1724  cpl_table_set_double(peakdata, "RESOLUTION", i, resolution);
1725  cpl_table_set_double(peakdata, "RV", i, rv);
1726  cpl_table_set_double(peakdata, "RVERR", i, rverr);
1727  cpl_table_set_int(peakdata, "STATUS", i, peak.status);
1728 
1729  cpl_matrix_delete(lambda);
1730  cpl_matrix_delete(ccf);
1731 
1732  }
1733 
1734  cpl_matrix_delete(spectrum);
1735  cpl_image_delete(_spectra);
1736 
1737  _giraffe_sgmask_delete(_mask);
1738 
1739  return peakdata;
1740 
1741 }
1742 
1743 
1744 inline static cpl_table*
1745 _giraffe_compute_slitgeometry(const GiImage* spectra, const GiTable* mask,
1746  const GiTable* slitgeometry,
1747  const GiGrating* grating,
1748  const GiSGCalConfig* config)
1749 {
1750 
1751  cxint status = 0;
1752 
1753  cpl_table* _slitgeometry = giraffe_table_get(slitgeometry);
1754  cpl_table* peakdata = NULL;
1755 
1756  GiSGSetup setup;
1757 
1758 
1759  /*
1760  * Get setup information from the rebinned spectra frame
1761  */
1762 
1763  status = _giraffe_create_setup(&setup, spectra);
1764 
1765  if (status != 0) {
1766  return NULL;
1767  }
1768 
1769  /*
1770  * Compute the wavelength shifts between the reference mask and
1771  * the arc-lamp spectra, from the position of the cross-correlation
1772  * peak.
1773  *
1774  * Note that either a fiber, or a slitgeometry table may be passed to
1775  * _giraffe_compute_offsets(). Actually any table providing the
1776  * columns "INDEX" and "FPS", describing the pixel column of each
1777  * spectrum in the input image and the fiber position within the
1778  * pseudo slit.
1779  */
1780 
1781  peakdata = _giraffe_compute_offsets(spectra, mask, _slitgeometry,
1782  grating, &setup, config);
1783 
1784  if (peakdata == NULL) {
1785  return NULL;
1786  }
1787 
1788 
1789  /*
1790  * Compute the offsets of the fibers in the pseudo-slit (i.e. in the
1791  * focal plane.
1792  */
1793 
1794  status = _giraffe_compute_fiber_offsets(peakdata, grating, &setup);
1795 
1796  if (status != 0) {
1797  cpl_table_delete(peakdata);
1798  return NULL;
1799  }
1800 
1801 
1802  /*
1803  * Compute fiber positions
1804  */
1805 
1806  cpl_table_duplicate_column(peakdata, "XF", _slitgeometry, "XF");
1807  cpl_table_add_columns(peakdata, "XF", "DXF");
1808 
1809  return peakdata;
1810 
1811 }
1812 
1813 
1814 inline static GiTable*
1815 _giraffe_slitgeometry_table(const cpl_table* offsets,
1816  const GiImage* spectra,
1817  const GiTable* fibers,
1818  const GiTable* slitgeometry,
1819  const GiSGCalConfig* config)
1820 {
1821 
1822  const cxchar* idx = NULL;
1823 
1824  cxint i;
1825 
1826  cpl_propertylist* properties = NULL;
1827  cpl_propertylist* _properties = NULL;
1828 
1829  cpl_table* _slit = NULL;
1830  cpl_table* _fibers = NULL;
1831  cpl_table* _slitgeometry = NULL;
1832 
1833  GiTable* slit = NULL;
1834 
1835 
1836  cx_assert(spectra != NULL);
1837  cx_assert(fibers != NULL);
1838 
1839  _fibers = giraffe_table_get(fibers);
1840  cx_assert(_fibers != NULL);
1841 
1842  _slitgeometry = giraffe_table_get(slitgeometry);
1843  cx_assert(_slitgeometry != NULL);
1844 
1845  if (offsets == NULL) {
1846  return NULL;
1847  }
1848 
1849 
1850  slit = giraffe_table_new();
1851 
1852  properties = giraffe_image_get_properties(spectra);
1853  cx_assert(properties != NULL);
1854 
1855  giraffe_error_push();
1856 
1857  _properties = cpl_propertylist_new();
1858 
1859  giraffe_propertylist_copy(_properties, GIALIAS_INSTRUMENT, properties,
1860  GIALIAS_INSTRUMENT);
1861 
1862  giraffe_propertylist_copy(_properties, GIALIAS_DATEOBS, properties,
1863  GIALIAS_DATEOBS);
1864 
1865  giraffe_propertylist_copy(_properties, GIALIAS_MJDOBS, properties,
1866  GIALIAS_MJDOBS);
1867 
1868  giraffe_propertylist_copy(_properties, GIALIAS_INSMODE, properties,
1869  GIALIAS_INSMODE);
1870 
1871  giraffe_propertylist_copy(_properties, GIALIAS_INSMODE, properties,
1872  GIALIAS_INSMODE);
1873 
1874  giraffe_propertylist_copy(_properties, GIALIAS_SETUPNAME, properties,
1875  GIALIAS_SETUPNAME);
1876 
1877  giraffe_propertylist_copy(_properties, GIALIAS_SLITNAME, properties,
1878  GIALIAS_SLITNAME);
1879 
1880  giraffe_propertylist_copy(_properties, GIALIAS_FILTNAME, properties,
1881  GIALIAS_FILTNAME);
1882 
1883  giraffe_propertylist_copy(_properties, GIALIAS_GRATNAME, properties,
1884  GIALIAS_GRATNAME);
1885 
1886  giraffe_propertylist_copy(_properties, GIALIAS_GRATWLEN, properties,
1887  GIALIAS_GRATWLEN);
1888 
1889  giraffe_propertylist_copy(_properties, GIALIAS_GRATORDER, properties,
1890  GIALIAS_GRATORDER);
1891 
1892  cpl_propertylist_update_double(_properties, GIALIAS_SCAL_CUTOFF,
1893  config->zmax);
1894  cpl_propertylist_set_comment(_properties, GIALIAS_SCAL_CUTOFF,
1895  "Cutoff pixel value.");
1896 
1897  cpl_propertylist_update_string(_properties, GIALIAS_GIRFTYPE, "SLITGEOTAB");
1898  cpl_propertylist_set_comment(_properties, GIALIAS_GIRFTYPE,
1899  "Giraffe frame type.");
1900 
1901 
1902  _slit = cpl_table_new(cpl_table_get_nrow(_fibers));
1903 
1904  cpl_table_new_column(_slit, "INDEX", CPL_TYPE_INT);
1905 
1906  for (i = 0; i < cpl_table_get_nrow(_slit); i++) {
1907  cpl_table_set_int(_slit, "INDEX", i, i + 1);
1908  }
1909 
1910  cpl_table_duplicate_column(_slit, "FPS", (cpl_table*)_fibers, "FPS");
1911  cpl_table_duplicate_column(_slit, "SSN", (cpl_table*)_fibers, "SSN");
1912  cpl_table_duplicate_column(_slit, "XF", (cpl_table*)offsets, "XF");
1913  cpl_table_duplicate_column(_slit, "YF", (cpl_table*)_slitgeometry, "YF");
1914 
1915  if (cpl_table_has_column(_slitgeometry, "ZF")) {
1916  cpl_table_duplicate_column(_slit, "ZF",
1917  (cpl_table*)_slitgeometry, "ZF");
1918  }
1919 
1920  if (cpl_table_has_column(_slitgeometry, "ZDEFOCUS")) {
1921  cpl_table_duplicate_column(_slit, "ZDEFOCUS",
1922  (cpl_table*)_slitgeometry, "ZDEFOCUS");
1923  }
1924 
1925  cpl_table_duplicate_column(_slit, "RV", (cpl_table*)offsets, "RV");
1926  cpl_table_duplicate_column(_slit, "RVERR", (cpl_table*)offsets, "RVERR");
1927  cpl_table_duplicate_column(_slit, "RESOLUTION", (cpl_table*)offsets,
1928  "RESOLUTION");
1929 
1930  idx = giraffe_fiberlist_query_index(_fibers);
1931  cpl_table_duplicate_column(_slit, "RINDEX", _fibers, idx);
1932 
1933  if (cpl_error_get_code() != CPL_ERROR_NONE) {
1934  cpl_propertylist_delete(_properties);
1935  cpl_table_delete(_slit);
1936 
1937  giraffe_table_delete(slit);
1938 
1939  return NULL;
1940  }
1941 
1942  giraffe_error_pop();
1943 
1944  giraffe_table_set_properties(slit, _properties);
1945  cpl_propertylist_delete(_properties);
1946 
1947  giraffe_table_set(slit, _slit);
1948  cpl_table_delete(_slit);
1949 
1950  return slit;
1951 
1952 }
1953 
1954 
1960 cxint
1961 giraffe_calibrate_slit(GiTable* result, const GiExtraction* extraction,
1962  const GiLocalization* localization,
1963  const GiTable* fibers, const GiTable* wlsolution,
1964  const GiTable* slitgeometry, const GiTable* grating,
1965  const GiTable* mask, const GiSGCalConfig* config)
1966 {
1967 
1968  const cxchar* const fctid = "giraffe_calibrate_slit";
1969 
1970  cxint i;
1971  cxint status = 0;
1972 
1973  cpl_table* _fibers = NULL;
1974  cpl_table* _slitgeometry = NULL;
1975  cpl_table* offsets = NULL;
1976 
1977  GiTable* slit = NULL;
1978 
1979  GiGrating* setup = NULL;
1980 
1981  GiExtraction* _extraction = NULL;
1982 
1983 
1984  if (result == NULL) {
1985  return 1;
1986  }
1987 
1988  if (extraction == NULL) {
1989  return 1;
1990  }
1991 
1992  if (extraction->spectra == NULL) {
1993  return 1;
1994  }
1995 
1996  if (localization == NULL) {
1997  return 1;
1998  }
1999 
2000  if (fibers == NULL) {
2001  return 1;
2002  }
2003 
2004  if (wlsolution == NULL) {
2005  return 1;
2006  }
2007 
2008  if (slitgeometry == NULL) {
2009  return 1;
2010  }
2011 
2012  if (grating == NULL) {
2013  return 1;
2014  }
2015 
2016  if (mask == NULL) {
2017  return 1;
2018  }
2019 
2020  if (config == NULL) {
2021  return 1;
2022  }
2023 
2024 
2025  _fibers = giraffe_table_get(fibers);
2026  cx_assert(_fibers != NULL);
2027 
2028  _slitgeometry = giraffe_table_get(slitgeometry);
2029  cx_assert(_slitgeometry != NULL);
2030 
2031  if (cpl_table_get_nrow(_fibers) != cpl_table_get_nrow(_slitgeometry)) {
2032  return 2;
2033  }
2034 
2035 
2036  /*
2037  * Create grating setup
2038  */
2039 
2040  setup = giraffe_grating_create(extraction->spectra, grating);
2041 
2042  if (setup == NULL) {
2043  return 3;
2044  }
2045 
2046 
2047  /*
2048  * Set up the spectrum rebinning. Make sure that only the spectra are
2049  * rebinned.
2050  */
2051 
2052  _extraction = giraffe_extraction_new();
2053 
2054  _extraction->spectra = extraction->spectra;
2055  _extraction->error = NULL;
2056 
2057 
2058  slit = giraffe_table_duplicate(slitgeometry);
2059 
2060  for (i = 0; i < config->repeat; i++) {
2061 
2062  cxint fps_rvmin = 0;
2063  cxint fps_rvmax = 0;
2064 
2065  cxdouble rvmin = 0.;
2066  cxdouble rvmax = 0.;
2067  cxdouble rvmean = 0.;
2068 
2069  cpl_size row = 0;
2070 
2071  GiRebinning* rebinning = giraffe_rebinning_new();
2072 
2073  GiRebinConfig rebin_config = {
2074  GIREBIN_METHOD_LINEAR,
2075  TRUE,
2076  0.005,
2077  GIREBIN_SCALE_LINEAR,
2078  0,
2079  GIREBIN_RANGE_SETUP
2080  };
2081 
2082 
2083  status = giraffe_rebin_spectra(rebinning, _extraction, fibers,
2084  localization, grating, slit,
2085  wlsolution, &rebin_config);
2086 
2087  if (status != 0) {
2088  giraffe_table_delete(slit);
2089 
2090  giraffe_extraction_delete(_extraction);
2091  giraffe_rebinning_destroy(rebinning);
2092 
2093  giraffe_grating_delete(setup);
2094 
2095  return 4;
2096  }
2097 
2098  offsets = _giraffe_compute_slitgeometry(rebinning->spectra, mask,
2099  slit, setup, config);
2100 
2101  if (offsets == NULL) {
2102  giraffe_table_delete(slit);
2103 
2104  giraffe_extraction_delete(_extraction);
2105  giraffe_rebinning_destroy(rebinning);
2106 
2107  giraffe_grating_delete(setup);
2108 
2109  return 5;
2110  }
2111 
2112 
2113  /*
2114  * Build new slit geometry table
2115  */
2116 
2117  cx_assert(cpl_table_get_nrow(offsets) == cpl_table_get_nrow(_fibers));
2118 
2119  giraffe_table_delete(slit);
2120  slit = _giraffe_slitgeometry_table(offsets, rebinning->spectra,
2121  fibers, slitgeometry, config);
2122 
2123  if (slit == NULL) {
2124 
2125  cpl_table_delete(offsets);
2126 
2127  giraffe_extraction_delete(_extraction);
2128  giraffe_rebinning_destroy(rebinning);
2129 
2130  giraffe_grating_delete(setup);
2131 
2132  return 6;
2133  }
2134 
2135  cpl_table_delete(offsets);
2136  offsets = NULL;
2137 
2138  rvmin = cpl_table_get_column_min(giraffe_table_get(slit), "RV");
2139  cpl_table_get_column_minpos(giraffe_table_get(slit), "RV", &row);
2140  fps_rvmin = cpl_table_get_int(giraffe_table_get(slit), "FPS",
2141  row, NULL);
2142 
2143  rvmax = cpl_table_get_column_max(giraffe_table_get(slit), "RV");
2144  cpl_table_get_column_maxpos(giraffe_table_get(slit), "RV", &row);
2145  fps_rvmax = cpl_table_get_int(giraffe_table_get(slit), "FPS",
2146  row, NULL);
2147 
2148  rvmean = cpl_table_get_column_mean(giraffe_table_get(slit), "RV");
2149 
2150  cpl_msg_info(fctid, "Iteration %d: Fiber offsets [km/s]: minimum = "
2151  "%.6e (fps %d), maximum = %.6e (fps %d), mean = %.6e",
2152  i + 1, rvmin, fps_rvmin, rvmax, fps_rvmax, rvmean);
2153 
2154  giraffe_rebinning_destroy(rebinning);
2155  rebinning = NULL;
2156 
2157  }
2158 
2159  giraffe_extraction_delete(_extraction);
2160  giraffe_grating_delete(setup);
2161 
2162  cx_assert(slit != NULL);
2163 
2165  giraffe_table_set(result, giraffe_table_get(slit));
2166 
2167  giraffe_table_delete(slit);
2168 
2169  return 0;
2170 
2171 }
2172 
2173 
2198 cxint
2199 giraffe_compute_offsets(GiTable* fibers, const GiRebinning* rebinning,
2200  const GiTable* grating, const GiTable* mask,
2201  const GiSGCalConfig* config)
2202 {
2203 
2204  cxint status = 0;
2205  cxint nfibers = 0;
2206  cxint fiber = 0;
2207  cxint peak = 0;
2208  cxint fps = 0;
2209  cxint fps0 = 0;
2210  cxint fps1 = 0;
2211 
2212  cxdouble dwf0 = 0.;
2213 
2214  cpl_table* _fibers = NULL;
2215  cpl_table* peakdata = NULL;
2216 
2217  GiGrating* _grating = NULL;
2218 
2219  GiSGSetup setup;
2220 
2221 
2222  if ((rebinning == NULL) || (rebinning->spectra == NULL)) {
2223  return -1;
2224  }
2225 
2226  if (fibers == NULL) {
2227  return -2;
2228  }
2229 
2230  if (grating == NULL) {
2231  return -3;
2232  }
2233 
2234  if (mask == NULL) {
2235  return -4;
2236  }
2237 
2238  if (config == NULL) {
2239  return -5;
2240  }
2241 
2242 
2243  _fibers = giraffe_table_get(fibers);
2244  cx_assert(_fibers != NULL);
2245 
2246 
2247  /*
2248  * Extract the SIWC fibers from the fiber table. The simultaneous
2249  * calibration spectra are indicated by a -1 as retractor position.
2250  */
2251 
2252  cpl_table_unselect_all(_fibers);
2253  cpl_table_or_selected_int(_fibers, "RP", CPL_EQUAL_TO, -1);
2254 
2255  _fibers = cpl_table_extract_selected(_fibers);
2256 
2257  if (_fibers == NULL) {
2258  return 1;
2259  }
2260 
2261 
2262  /*
2263  * Create grating setup
2264  */
2265 
2266  _grating = giraffe_grating_create(rebinning->spectra, grating);
2267 
2268  if (_grating == NULL) {
2269  cpl_table_delete(_fibers);
2270  return 2;
2271  }
2272 
2273  /*
2274  * Get setup information from the rebinned spectra frame
2275  */
2276 
2277  status = _giraffe_create_setup(&setup, rebinning->spectra);
2278 
2279  if (status != 0) {
2280 
2281  giraffe_grating_delete(_grating);
2282  cpl_table_delete(_fibers);
2283 
2284  return 3;
2285 
2286  }
2287 
2288 
2289  /*
2290  * Compute the wavelength shifts between the reference mask and
2291  * the arc-lamp spectra, from the position of the cross-correlation
2292  * peak.
2293  *
2294  * Note that either a fiber, or a slitgeometry table may be passed to
2295  * _giraffe_compute_offsets(). Actually any table providing the
2296  * columns "INDEX" and "FPS", describing the pixel column of each
2297  * spectrum in the input image and the fiber position within the
2298  * pseudo slit.
2299  */
2300 
2301  peakdata = _giraffe_compute_offsets(rebinning->spectra, mask, _fibers,
2302  _grating, &setup, config);
2303 
2304  if (peakdata == NULL) {
2305 
2306  giraffe_grating_delete(_grating);
2307  cpl_table_delete(_fibers);
2308 
2309  return 4;
2310 
2311  }
2312 
2313 
2314  /*
2315  * Compute the offsets of the fibers in the pseudo-slit (i.e. in the
2316  * focal plane.
2317  */
2318 
2319  status = _giraffe_compute_fiber_offsets(peakdata, _grating, &setup);
2320 
2321  if (status != 0) {
2322  cpl_table_delete(peakdata);
2323  cpl_table_delete(_fibers);
2324 
2325  return 5;
2326  }
2327 
2328  giraffe_grating_delete(_grating);
2329  cpl_table_delete(_fibers);
2330 
2331 
2332  /*
2333  * Interpolate the wavelength offsets between the position of 2 adjacent
2334  * simultaneous calibration fibers.
2335  *
2336  * Note: The while loops traversing the fiber table _fiber just check
2337  * whether the two fiber positions are equal or not. In that way
2338  * it is possible to process Argus data, where the order of the
2339  * fibers is reversed, without sorting the fiber and peakdata
2340  * tables, or using dedicated code for Argus observations.
2341  */
2342 
2343  _fibers = giraffe_table_get(fibers);
2344 
2345  giraffe_error_push();
2346 
2347  cpl_table_new_column(_fibers, "WLRES", CPL_TYPE_DOUBLE);
2348  cpl_table_set_column_unit(_fibers, "WLRES", "nm");
2349 
2350  if (cpl_error_get_code() != CPL_ERROR_NONE) {
2351  cpl_table_delete(peakdata);
2352  return 6;
2353  }
2354 
2355  giraffe_error_pop();
2356 
2357 
2358  giraffe_error_push();
2359 
2360  fps0 = cpl_table_get_int(peakdata, "FPS", 0, NULL);
2361  dwf0 = cpl_table_get_double(peakdata, "DWF", 0, NULL);
2362 
2363  nfibers = cpl_table_get_nrow(_fibers);
2364 
2365  fps = cpl_table_get_int(_fibers, "FPS", 0, NULL);
2366 
2367  while (fps != fps0) {
2368 
2369  cpl_table_set_double(_fibers, "WLRES", fiber, dwf0);
2370 
2371  ++fiber;
2372  fps = cpl_table_get_int(_fibers, "FPS", fiber, NULL);
2373 
2374  }
2375 
2376  for (peak = 1; peak < cpl_table_get_nrow(peakdata); ++peak) {
2377 
2378  cxdouble dwf1 = cpl_table_get_double(peakdata, "DWF", peak, NULL);
2379  cxdouble slope = 0.;
2380 
2381 
2382  fps1 = cpl_table_get_int(peakdata, "FPS", peak, NULL);
2383 
2384  slope = (dwf1 - dwf0) / ((cxdouble)(fps1 - fps0));
2385 
2386  while (fps != fps1) {
2387 
2388  cpl_table_set_double(_fibers, "WLRES", fiber,
2389  slope * (fps - fps0) + dwf0);
2390 
2391  ++fiber;
2392  fps = cpl_table_get_int(_fibers, "FPS", fiber, NULL);
2393  }
2394 
2395  fps0 = fps1;
2396  dwf0 = dwf1;
2397 
2398  }
2399 
2400  fps1 = cpl_table_get_int(_fibers, "FPS", nfibers - 1, NULL);
2401 
2402  while (fps != fps1) {
2403 
2404  cpl_table_set_double(_fibers, "WLRES", fiber, dwf0);
2405 
2406  ++fiber;
2407  fps = cpl_table_get_int(_fibers, "FPS", fiber, NULL);
2408 
2409  }
2410 
2411  cpl_table_set_double(_fibers, "WLRES", fiber, dwf0);
2412 
2413  cx_assert(fiber == nfibers - 1);
2414 
2415  if (cpl_error_get_code() != CPL_ERROR_NONE) {
2416  cpl_table_delete(peakdata);
2417  return 7;
2418  }
2419 
2420  cpl_table_delete(peakdata);
2421 
2422  giraffe_error_pop();
2423 
2424  return 0;
2425 
2426 }
2427 
2428 
2442 giraffe_sgcalibration_config_create(cpl_parameterlist* list)
2443 {
2444 
2445  const cxchar* s = NULL;
2446 
2447  cpl_parameter* p = NULL;
2448 
2449  GiSGCalConfig* config = NULL;
2450 
2451 
2452  if (!list) {
2453  return NULL;
2454  }
2455 
2456  config = cx_calloc(1, sizeof *config);
2457 
2458  config->cc_wdomain = FALSE;
2459 
2460  p = cpl_parameterlist_find(list, "giraffe.sgcalibration.iterations");
2461  config->repeat = cpl_parameter_get_int(p);
2462 
2463  p = cpl_parameterlist_find(list, "giraffe.sgcalibration.zmax");
2464  config->zmax = cpl_parameter_get_double(p);
2465 
2466  p = cpl_parameterlist_find(list, "giraffe.sgcalibration.cc.step");
2467  config->cc_step = cpl_parameter_get_double(p);
2468 
2469  p = cpl_parameterlist_find(list, "giraffe.sgcalibration.cc.domain");
2470  s = cpl_parameter_get_string(p);
2471 
2472  if (s) {
2473 
2474  cxchar** values = cx_strsplit(s, ",", 3);
2475 
2476  if (values == NULL) {
2477 
2479  return NULL;
2480 
2481  }
2482  else {
2483 
2484  cxchar* last;
2485 
2486  cxdouble lower = 0.;
2487  cxdouble upper = 0.;
2488 
2489 
2490  lower = strtod(values[0], &last);
2491 
2492  if (*last != '\0') {
2493 
2494  cx_strfreev(values);
2496 
2497  return NULL;
2498 
2499  }
2500 
2501  lower = lower >= 0. ? lower : 0.;
2502 
2503 
2504  if (values[1] != NULL) {
2505 
2506  upper = strtod(values[1], &last);
2507 
2508  if (*last != '\0') {
2509 
2510  cx_strfreev(values);
2512 
2513  return NULL;
2514 
2515  }
2516 
2517  upper = upper > lower ? upper : 0.;
2518 
2519  }
2520 
2521  config->cc_domain = giraffe_range_create(lower, upper);
2522  cx_assert(config->cc_domain != NULL);
2523 
2524  }
2525 
2526  cx_strfreev(values);
2527  values = NULL;
2528 
2529  }
2530 
2531 
2532  p = cpl_parameterlist_find(list, "giraffe.sgcalibration.rv.limits");
2533  s = cpl_parameter_get_string(p);
2534 
2535  if (s) {
2536 
2537  cxchar** values = cx_strsplit(s, ",", 3);
2538 
2539  if (values == NULL) {
2540 
2542  return NULL;
2543 
2544  }
2545  else {
2546 
2547  cxchar* last;
2548 
2549  cxdouble lower = 0.;
2550  cxdouble upper = 0.;
2551 
2552 
2553  lower = strtod(values[0], &last);
2554 
2555  if (*last != '\0') {
2556 
2557  cx_strfreev(values);
2559 
2560  return NULL;
2561 
2562  }
2563 
2564  if (values[1] != NULL) {
2565 
2566  upper = strtod(values[1], &last);
2567 
2568  if (*last != '\0') {
2569 
2570  cx_strfreev(values);
2572 
2573  return NULL;
2574 
2575  }
2576 
2577  if (lower > 0 || upper < lower) {
2578 
2579  cx_strfreev(values);
2581 
2582  return NULL;
2583 
2584  }
2585 
2586  }
2587  else {
2588 
2589  if (lower > 0.) {
2590 
2591  upper = lower;
2592  lower = -upper;
2593 
2594  }
2595  else {
2596 
2597  upper = -lower;
2598 
2599  }
2600 
2601  }
2602 
2603  cx_assert(lower <= 0);
2604  cx_assert(lower < upper);
2605 
2606  config->rv_limits = giraffe_range_create(lower, upper);
2607  cx_assert(config->rv_limits != NULL);
2608 
2609  }
2610 
2611  cx_strfreev(values);
2612  values = NULL;
2613 
2614  }
2615 
2616 
2617  p = cpl_parameterlist_find(list, "giraffe.sgcalibration.rv.iterations");
2618  config->rv_niter = cpl_parameter_get_int(p);
2619 
2620  p = cpl_parameterlist_find(list, "giraffe.sgcalibration.rv.wfactor");
2621  config->rv_wfactor = cpl_parameter_get_double(p);
2622 
2623  p = cpl_parameterlist_find(list, "giraffe.sgcalibration.peak.iterations");
2624  config->pf_niter = cpl_parameter_get_int(p);
2625 
2626  p = cpl_parameterlist_find(list, "giraffe.sgcalibration.peak.tests");
2627  config->pf_ntest = cpl_parameter_get_int(p);
2628 
2629  p = cpl_parameterlist_find(list, "giraffe.sgcalibration.peak.dchisquare");
2630  config->pf_dchisq = cpl_parameter_get_double(p);
2631 
2632  return config;
2633 
2634 }
2635 
2636 
2651 void
2653 {
2654 
2655  if (config) {
2656  if (config->cc_domain) {
2658  }
2659 
2660  if (config->rv_limits) {
2662  }
2663 
2664  cx_free(config);
2665  }
2666 
2667  return;
2668 }
2669 
2670 
2682 void
2683 giraffe_sgcalibration_config_add(cpl_parameterlist* list)
2684 {
2685 
2686  cpl_parameter* p;
2687 
2688 
2689  if (!list) {
2690  return;
2691  }
2692 
2693  p = cpl_parameter_new_value("giraffe.sgcalibration.iterations",
2694  CPL_TYPE_INT,
2695  "Slit geometry calibration maximum number "
2696  "of iterations.",
2697  "giraffe.sgcalibration",
2698  1);
2699  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-cniter");
2700  cpl_parameterlist_append(list, p);
2701 
2702 
2703  p = cpl_parameter_new_value("giraffe.sgcalibration.zmax",
2704  CPL_TYPE_DOUBLE,
2705  "Maximum allowed pixel value. To be "
2706  "effective it must be larger than 0.",
2707  "giraffe.sgcalibration",
2708  10000.);
2709  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-zmax");
2710  cpl_parameterlist_append(list, p);
2711 
2712 
2713  p = cpl_parameter_new_value("giraffe.sgcalibration.cc.step",
2714  CPL_TYPE_DOUBLE,
2715  "Cross-correlation step.",
2716  "giraffe.sgcalibration",
2717  -0.005);
2718  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-cstep");
2719  cpl_parameterlist_append(list, p);
2720 
2721 
2722  p = cpl_parameter_new_value("giraffe.sgcalibration.cc.domain",
2723  CPL_TYPE_STRING,
2724  "Restricts the cross-correlation to the "
2725  "given domain.",
2726  "giraffe.sgcalibration",
2727  "0.,0.");
2728  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-cdomain");
2729  cpl_parameterlist_append(list, p);
2730 
2731 
2732  p = cpl_parameter_new_value("giraffe.sgcalibration.rv.limits",
2733  CPL_TYPE_STRING,
2734  "Delta RV limits of the cross-correlation "
2735  "window in km/s.",
2736  "giraffe.sgcalibration",
2737  "-200.,200.");
2738  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-rvlimits");
2739  cpl_parameterlist_append(list, p);
2740 
2741 
2742  p = cpl_parameter_new_value("giraffe.sgcalibration.rv.iterations",
2743  CPL_TYPE_INT,
2744  "Maximum number of iterations used for the "
2745  "RV determination.",
2746  "giraffe.sgcalibration",
2747  3);
2748  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-rvniter");
2749  cpl_parameterlist_append(list, p);
2750 
2751 
2752  p = cpl_parameter_new_value("giraffe.sgcalibration.rv.wfactor",
2753  CPL_TYPE_DOUBLE,
2754  "Data window width factor. The FWHM times "
2755  "this value determines the window width.",
2756  "giraffe.sgcalibration",
2757  1.5);
2758  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-rvwfactor");
2759  cpl_parameterlist_append(list, p);
2760 
2761 
2762  p = cpl_parameter_new_value("giraffe.sgcalibration.peak.iterations",
2763  CPL_TYPE_INT,
2764  "Peak model fit maximum number of "
2765  "iterations.",
2766  "giraffe.sgcalibration",
2767  50);
2768 
2769  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-pfniter");
2770  cpl_parameterlist_append(list, p);
2771 
2772 
2773  p = cpl_parameter_new_value("giraffe.sgcalibration.peak.tests",
2774  CPL_TYPE_INT,
2775  "Cross-correlation peak fit maximum number "
2776  "of tests",
2777  "giraffe.sgcalibration",
2778  7);
2779 
2780  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-pfntest");
2781  cpl_parameterlist_append(list, p);
2782 
2783 
2784  p = cpl_parameter_new_value("giraffe.sgcalibration.peak.dchisquare",
2785  CPL_TYPE_DOUBLE,
2786  "Cross-correlation peak fit minimum "
2787  "chi-square difference.",
2788  "giraffe.sgcalibration",
2789  0.0001);
2790 
2791  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-pfdchisq");
2792  cpl_parameterlist_append(list, p);
2793 
2794  return;
2795 
2796 }

This file is part of the GIRAFFE Pipeline Reference Manual 2.12.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Mon Mar 24 2014 11:43:53 by doxygen 1.8.2 written by Dimitri van Heesch, © 1997-2004