GIRAFFE Pipeline Reference Manual

gisgcalibration.c

00001 /* $Id: gisgcalibration.c,v 1.22 2010/03/08 08:47:14 rpalsa Exp $
00002  *
00003  * This file is part of the GIRAFFE Pipeline
00004  * Copyright (C) 2002-2006 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 /*
00022  * $Author: rpalsa $
00023  * $Date: 2010/03/08 08:47:14 $
00024  * $Revision: 1.22 $
00025  * $Name: giraffe-2_8_8 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #  include <config.h>
00030 #endif
00031 
00032 #include <math.h>
00033 
00034 #include <cxmemory.h>
00035 #include <cxmessages.h>
00036 #include <cxstrutils.h>
00037 
00038 #include <cpl_error.h>
00039 #include <cpl_parameterlist.h>
00040 #include <cpl_propertylist.h>
00041 #include <cpl_matrix.h>
00042 #include <cpl_image.h>
00043 #include <cpl_table.h>
00044 
00045 #include "gialias.h"
00046 #include "gierror.h"
00047 #include "gimatrix.h"
00048 #include "gifiberutils.h"
00049 #include "gigrating.h"
00050 #include "gimodel.h"
00051 #include "gilocalization.h"
00052 #include "giextraction.h"
00053 #include "girebinning.h"
00054 #include "gisgcalibration.h"
00055 
00056 
00065 struct GiMeasurement {
00066     cxdouble value;
00067     cxdouble sigma;
00068 };
00069 
00070 typedef struct GiMeasurement GiMeasurement;
00071 
00072 
00073 struct GiSGSetup {
00074 
00075     cxint nx;
00076     cxint nex;
00077 
00078     GiRebinScale scale;
00079 
00080     cxdouble wlmin;
00081     cxdouble wlmax;
00082     cxdouble wlstep;
00083 
00084     cxdouble pixelsize;
00085 
00086 };
00087 
00088 typedef struct GiSGSetup GiSGSetup;
00089 
00090 
00091 struct GiCPFitParams {
00092 
00093     cxint dnmin;
00094     cxint iterations;
00095 
00096     cxdouble step;
00097     cxdouble wfactor;
00098     cxdouble sigma;
00099 
00100     GiRebinScale scale;
00101 
00102     GiFitSetup fit;
00103 
00104 };
00105 
00106 typedef struct GiCPFitParams GiCPFitParams;
00107 
00108 
00109 struct GiCPeakFit {
00110     GiMeasurement amplitude;
00111     GiMeasurement background;
00112     GiMeasurement center;
00113     GiMeasurement width;
00114 
00115     cxint status;
00116 };
00117 
00118 typedef struct GiCPeakFit GiCPeakFit;
00119 
00120 
00121 struct GiSGMask {
00122 
00123     cxsize size;
00124     cxsize nholes;
00125 
00126     GiRebinScale scale;
00127 
00128     cxdouble start;
00129     cxdouble step;
00130 
00131     cpl_matrix* wavelength;
00132     cpl_matrix* flux;
00133 
00134 };
00135 
00136 typedef struct GiSGMask GiSGMask;
00137 
00138 
00139 inline static GiSGMask*
00140 _giraffe_sgmask_new(cxsize size)
00141 {
00142 
00143     GiSGMask* self = cx_calloc(1, sizeof *self);
00144 
00145     self->wavelength = cpl_matrix_new(1, size);
00146     self->flux = cpl_matrix_new(1, size);
00147 
00148     self->size = size;
00149     self->nholes = 0;
00150 
00151     self->scale = GIREBIN_SCALE_LINEAR;
00152 
00153     self->start = 0.;
00154     self->step = 1.;
00155 
00156     return self;
00157 
00158 }
00159 
00160 
00161 inline static void
00162 _giraffe_sgmask_delete(GiSGMask* self)
00163 {
00164 
00165     if (self) {
00166 
00167         if (self->wavelength != NULL) {
00168             cpl_matrix_delete(self->wavelength);
00169             self->wavelength = NULL;
00170         }
00171 
00172         if (self->flux != NULL) {
00173             cpl_matrix_delete(self->flux);
00174             self->flux = NULL;
00175         }
00176 
00177         cx_free(self);
00178 
00179     }
00180 
00181     return;
00182 
00183 }
00184 
00185 
00186 inline static GiSGMask*
00187 _giraffe_sgmask_create(cxsize size, cxdouble start, cxdouble step,
00188                        GiRebinScale scale, const GiTable* mask)
00189 {
00190 
00191     register cxsize i;
00192 
00193     cxdouble wlmin = 0.;
00194     cxdouble wlmax = 0.;
00195     cxdouble wlstep = 0.;
00196 
00197     cpl_table* _mask = NULL;
00198 
00199     GiSGMask* self = NULL;
00200 
00201 
00202     cx_assert(mask != NULL);
00203 
00204     _mask = giraffe_table_get(mask);
00205     cx_assert(_mask != NULL);
00206 
00207     self = _giraffe_sgmask_new(size);
00208 
00209     self->start = start;
00210     self->step = step;
00211     self->scale = scale;
00212 
00213 
00214     /*
00215      * Fill wavelength array
00216      */
00217 
00218     for (i = 0; i < self->size; i++) {
00219         cpl_matrix_set(self->wavelength, 0, i, self->start + i * self->step);
00220     }
00221 
00222 
00223     wlmin = cpl_matrix_get(self->wavelength, 0, 0);
00224     wlmax = cpl_matrix_get(self->wavelength, 0, self->size - 1);
00225     wlstep = self->step;
00226 
00227     if (self->scale == GIREBIN_SCALE_LOG) {
00228 
00229         wlmin = exp(wlmin);
00230         wlmax = exp(wlmax);
00231         wlstep = exp(wlstep);
00232 
00233     }
00234 
00235 
00236     /*
00237      * Create the mask's flux array from the mask template `mask', i.e.
00238      * the flux values are set to 1. within the holes and 0. otherwise.
00239      */
00240 
00241     cpl_table_select_all(_mask);
00242 
00243     cpl_table_and_selected_double(_mask, "WLEN1", CPL_GREATER_THAN, wlmin);
00244     cpl_table_and_selected_double(_mask, "WLEN2", CPL_LESS_THAN, wlmax);
00245 
00246     _mask = cpl_table_extract_selected(_mask);
00247 
00248     if (_mask == NULL || cpl_table_get_nrow(_mask) <= 0) {
00249         _giraffe_sgmask_delete(self);
00250         self = NULL;
00251 
00252         return NULL;
00253     }
00254 
00255 
00256     self->nholes = cpl_table_get_nrow(_mask);
00257 
00258     for (i = 0; i < self->nholes; i++) {
00259 
00260         register cxsize j;
00261 
00262         cxdouble hstart = cpl_table_get(_mask, "WLEN1", i, NULL) - wlmin;
00263         cxdouble hend = cpl_table_get(_mask, "WLEN2", i, NULL) - wlmin;
00264 
00265 
00266         hstart /= wlstep;
00267         hend /= wlstep;
00268 
00269         for (j = (cxsize)(hstart + 0.5); j <= (cxsize)(hend + 0.5); j++) {
00270 
00271             cpl_matrix_set(self->flux, 0, j, 1.);
00272 
00273         }
00274 
00275     }
00276 
00277     cpl_table_delete(_mask);
00278 
00279     return self;
00280 
00281 }
00282 
00283 
00284 inline static cxsize
00285 _giraffe_sgmask_size(const GiSGMask* self)
00286 {
00287 
00288     cx_assert(self != NULL);
00289 
00290     return self->size;
00291 
00292 }
00293 
00294 
00295 inline static cxsize
00296 _giraffe_sgmask_holes(const GiSGMask* self)
00297 {
00298 
00299     cx_assert(self != NULL);
00300 
00301     return self->nholes;
00302 
00303 }
00304 
00305 
00306 inline static cxint
00307 _giraffe_sgmask_set_flux(GiSGMask* self, cxsize position, cxdouble value)
00308 {
00309 
00310     cx_assert(self != NULL);
00311 
00312     if (position >= (cxsize)cpl_matrix_get_ncol(self->flux)) {
00313         return 1;
00314     }
00315 
00316     cpl_matrix_set(self->flux, 0, position, value);
00317 
00318     return 0;
00319 
00320 }
00321 
00322 
00323 inline static cxdouble
00324 _giraffe_sgmask_get_flux(GiSGMask* self, cxsize position)
00325 {
00326 
00327     const cxchar* const fctid = "_giraffe_sgmask_get_flux";
00328 
00329 
00330     cx_assert(self != NULL);
00331 
00332     if (position >= (cxsize)cpl_matrix_get_ncol(self->flux)) {
00333         cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
00334         return 0.;
00335     }
00336 
00337     return cpl_matrix_get(self->flux, 0, position);
00338 
00339 }
00340 
00341 
00342 inline static const cpl_matrix*
00343 _giraffe_sgmask_get(GiSGMask* self)
00344 {
00345 
00346     cx_assert(self != NULL);
00347 
00348     return self->flux;
00349 
00350 }
00351 
00352 
00353 inline static cxint
00354 _giraffe_sgmask_crop(GiSGMask* self, cxsize begin, cxsize end)
00355 {
00356 
00357     cxsize size = 0;
00358 
00359     cpl_matrix* buffer = NULL;
00360 
00361 
00362     cx_assert(self != NULL);
00363     cx_assert(end > begin);
00364     cx_assert(cpl_matrix_get_nrow(self->wavelength) == 1);
00365     cx_assert(cpl_matrix_get_nrow(self->flux) == 1);
00366 
00367     if (begin >= (cxsize)cpl_matrix_get_ncol(self->flux)) {
00368         return 1;
00369     }
00370 
00371     if (end > (cxsize)cpl_matrix_get_ncol(self->flux)) {
00372         end = cpl_matrix_get_ncol(self->flux);
00373     }
00374 
00375     if (begin == 0 && end == (cxsize)cpl_matrix_get_ncol(self->flux)) {
00376         return 0;
00377     }
00378 
00379     size = end - begin;
00380 
00381     buffer = cpl_matrix_extract(self->wavelength, 0, begin, 1, 1, 1, size);
00382     cpl_matrix_delete(self->wavelength);
00383     self->wavelength = buffer;
00384 
00385     buffer = cpl_matrix_extract(self->flux, 0, begin, 1, 1, 1, size);
00386     cpl_matrix_delete(self->flux);
00387     self->flux = buffer;
00388 
00389     cx_assert(cpl_matrix_get_nrow(self->flux) == 1);
00390     cx_assert((cxsize)cpl_matrix_get_ncol(self->flux) == size);
00391 
00392     self->size = size;
00393 
00394     return 0;
00395 
00396 }
00397 
00398 
00399 inline static cxdouble
00400 _giraffe_clip_value(cxdouble value, cxdouble low, cxdouble high,
00401                     cxbool* flag)
00402 {
00403 
00404     cxbool status = FALSE;
00405 
00406     if (value < low) {
00407         value = low;
00408         status = TRUE;
00409     }
00410 
00411     if (value >= high) {
00412         value = high;
00413         status = TRUE;
00414     }
00415 
00416     if (flag != NULL) {
00417         *flag = status;
00418     }
00419 
00420     return value;
00421 
00422 }
00423 
00424 
00425 /*
00426  * The function performs a linear interpolation and simultaneous re-sampling
00427  * of the input image `signal' from the input bin size `step1' to a signal
00428  * with a sampling of `step2'.
00429  */
00430 
00431 inline static cpl_image*
00432 _giraffe_resample_image(cpl_image* signal, cxdouble step1, cxdouble step2)
00433 {
00434 
00435     cxint i;
00436     cxint nx1 = 0;
00437     cxint ny = 0;
00438     cxint nx2 = 0;
00439     cxint step = CX_MAX(1, (cxint)(step1/step2));
00440 
00441     cpl_image* _signal = NULL;
00442 
00443 
00444     cx_assert(signal != NULL);
00445 
00446     ny = cpl_image_get_size_x(signal);
00447     nx1 = cpl_image_get_size_y(signal);
00448 
00449     nx2 = (nx1 - 1) * step + 1;
00450 
00451     _signal = cpl_image_new(ny, nx2, CPL_TYPE_DOUBLE);
00452 
00453     for (i = 0; i < ny; i++) {
00454 
00455         register cxint j;
00456 
00457         register cxdouble* data = cpl_image_get_data(signal);
00458         register cxdouble* _data = cpl_image_get_data(_signal);
00459 
00460 
00461         for (j = 0; j < nx1 - 1; j++) {
00462 
00463             register cxint k;
00464             register cxint l = j * ny + i;
00465             register cxint m = j * ny * step + i;
00466 
00467             for (k = 0; k < step; k++) {
00468 
00469                 cxdouble f = (cxdouble)k / (cxdouble)step;
00470 
00471                 _data[m + k * ny] = (1. - f) * data[l] + f * data[l + ny];
00472 
00473             }
00474 
00475         }
00476 
00477         _data[nx2 - 1] = data[nx1 - 1];
00478 
00479     }
00480 
00481     return _signal;
00482 
00483 }
00484 
00485 
00486 /*
00487  * Compute cross-correlation function s * T for the window [start, end]
00488  */
00489 
00490 inline static cpl_matrix*
00491 _giraffe_compute_cross_correlation(const cpl_matrix* signal,
00492                                    const cpl_matrix* template,
00493                                    cxint start, cxint end)
00494 {
00495 
00496     const cxchar* const fctid = "_giraffe_compute_cross_correlation";
00497 
00498 
00499     cxint i;
00500     cxint n = 0;
00501     cxint nmax = 0;
00502     cxint ns = 0;
00503     cxint nccf = 0;
00504 
00505     cxdouble sum = 0.;
00506 
00507     cpl_matrix* _signal = (cpl_matrix*)signal;
00508     cpl_matrix* _template = (cpl_matrix*)template;
00509     cpl_matrix* ccf = NULL;
00510     cpl_matrix* _ccf = NULL;
00511 
00512 
00513     cx_assert(_signal != NULL);
00514     cx_assert(cpl_matrix_get_nrow(_signal) == 1);
00515 
00516     cx_assert(_template != NULL);
00517     cx_assert(cpl_matrix_get_nrow(_template) == 1);
00518 
00519     ns = cpl_matrix_get_ncol(_signal);
00520     cx_assert(ns == cpl_matrix_get_ncol(_template));
00521 
00522     cx_assert(start <= end);
00523 
00524 
00525     /*
00526      * The number of shifts should not exceed the half-window
00527      */
00528 
00529     nmax = cpl_matrix_get_ncol(_signal) / 2;
00530 
00531     start = CX_MAX(CX_MIN(start, nmax), -nmax);
00532     end = CX_MAX(CX_MIN(end, nmax), -nmax);
00533 
00534     nccf = end - start;
00535 
00536     cpl_msg_debug(fctid, "Cross-correlation function: signal size = %d, "
00537                   "template size = %d, window start = %d, window end = %d",
00538                   cpl_matrix_get_ncol(_signal), cpl_matrix_get_ncol(_template),
00539                   start, end);
00540 
00541 
00542     ccf = cpl_matrix_new(1, nccf);
00543 
00544     for (i = start; i < end; i++) {
00545 
00546         if (i < 0) {
00547 
00548             cxint j;
00549 
00550 
00551             /*
00552              * - shift template i < 0
00553              */
00554 
00555             sum = 0.;
00556 
00557             for (j = 0; j < ns + i; j++) {
00558 
00559                 cxdouble s = cpl_matrix_get(_signal, 0, j);
00560                 cxdouble t = cpl_matrix_get(_template, 0, j - i);
00561 
00562                 sum += t * s;
00563 
00564             }
00565 
00566             sum /= (cxdouble)(ns + i);
00567 
00568             cpl_matrix_set(ccf, 0, i - start, sum);
00569 
00570         }
00571         else if (i > 0) {
00572 
00573             cxint j;
00574 
00575 
00576             /*
00577              * + shift template i > 0
00578              */
00579 
00580             sum = 0.;
00581 
00582             for (j = i; j < ns; j++) {
00583 
00584                 cxdouble s = cpl_matrix_get(_signal, 0, j);
00585                 cxdouble t = cpl_matrix_get(_template, 0, j - i);
00586 
00587                 sum += t * s;
00588 
00589             }
00590 
00591             sum /= (cxdouble)(ns - i);
00592 
00593             cpl_matrix_set(ccf, 0, i - start, sum);
00594 
00595         }
00596         else {
00597 
00598             cxint j;
00599 
00600 
00601             /*
00602              * The central value
00603              */
00604 
00605             sum = 0.;
00606 
00607             for (j = 0; j < ns; j++) {
00608 
00609                 cxdouble t = cpl_matrix_get(_template, 0, j);
00610                 cxdouble s = cpl_matrix_get(_signal, 0, j);
00611 
00612                 sum += t * s;
00613 
00614             }
00615 
00616             sum /= (cxdouble)ns;
00617 
00618             cpl_matrix_set(ccf, 0, -start, sum);
00619 
00620         }
00621 
00622 
00623     }
00624 
00625 
00626     /*
00627      * Normalize peak to approximately 1.0. For this purpose the 10% of
00628      * the cross-correlation function's data points with the highest
00629      * values are used.
00630      */
00631 
00632     n = CX_MAX(1, nccf / 10);
00633 
00634     _ccf = cpl_matrix_duplicate(ccf);
00635     giraffe_matrix_sort(_ccf);
00636 
00637     sum = 0.;
00638 
00639     for (i = nccf - n; i < nccf; i++) {
00640         sum += cpl_matrix_get(_ccf, 0, i);
00641     }
00642 
00643     sum /= (cxdouble)n;
00644 
00645     cpl_matrix_delete(_ccf);
00646     _ccf = NULL;
00647 
00648     if (sum != 0.) {
00649 
00650         for (i = 0; i < nccf; i++) {
00651             cpl_matrix_set(ccf, 0, i, cpl_matrix_get(ccf, 0, i) / sum);
00652         }
00653 
00654     }
00655 
00656     return ccf;
00657 
00658 }
00659 
00660 
00661 inline static cxint
00662 _giraffe_create_setup(GiSGSetup* setup, const GiImage* spectra)
00663 {
00664 
00665     cpl_propertylist* properties = NULL;
00666 
00667     cpl_image* _spectra = NULL;
00668 
00669 
00670     cx_assert(setup != NULL);
00671     cx_assert(spectra != NULL);
00672 
00673     properties = giraffe_image_get_properties(spectra);
00674     cx_assert(properties != NULL);
00675 
00676     _spectra = giraffe_image_get(spectra);
00677     cx_assert(_spectra != NULL);
00678 
00679 
00680     /*
00681      * Retrieve rebinned spectra information.
00682      */
00683 
00684     setup->nx = cpl_image_get_size_y(_spectra);
00685 
00686 
00687     if (!cpl_propertylist_has(properties, GIALIAS_EXT_NX)) {
00688         return 1;
00689     }
00690     else {
00691 
00692         setup->nex = cpl_propertylist_get_int(properties, GIALIAS_EXT_NX);
00693 
00694     }
00695 
00696     if (!cpl_propertylist_has(properties, GIALIAS_BINSCALE)) {
00697         return 1;
00698     }
00699     else {
00700 
00701         const cxchar* s = cpl_propertylist_get_string(properties,
00702             GIALIAS_BINSCALE);
00703 
00704 
00705         if (cx_strncasecmp(s, "log", 3) == 0) {
00706             setup->scale = GIREBIN_SCALE_LOG;
00707         }
00708         else {
00709             setup->scale = GIREBIN_SCALE_LINEAR;
00710         }
00711 
00712     }
00713 
00714     if (!cpl_propertylist_has(properties, GIALIAS_BINWLMIN)) {
00715         return 1;
00716     }
00717     else {
00718         setup->wlmin = cpl_propertylist_get_double(properties,
00719             GIALIAS_BINWLMIN);
00720     }
00721 
00722     if (!cpl_propertylist_has(properties, GIALIAS_BINSTEP)) {
00723         return 1;
00724     }
00725     else {
00726         setup->wlstep = cpl_propertylist_get_double(properties,
00727             GIALIAS_BINSTEP);
00728     }
00729 
00730     setup->wlmax = setup->wlmin + (setup->nx - 1) * setup->wlstep;
00731 
00732 
00733     if (!cpl_propertylist_has(properties, GIALIAS_PIXSIZY)) {
00734         return 1;
00735     }
00736     else {
00737         setup->pixelsize = cpl_propertylist_get_double(properties,
00738             GIALIAS_PIXSIZY);
00739     }
00740 
00741     return 0;
00742 
00743 }
00744 
00745 
00746 inline static cxint
00747 _giraffe_peak_fit(GiCPeakFit* peak, const cpl_matrix* lambda,
00748                   const cpl_matrix* ccf, const GiGrating* grating,
00749                   const GiCPFitParams* setup)
00750 {
00751 
00752     const cxchar* const fctid = "_giraffe_peak_fit";
00753 
00754 
00755     cxbool stop = FALSE;
00756 
00757     cxint i;
00758     cxint nr = 0;
00759     cxint nc = 0;
00760     cxint dn1 = 0;
00761     cxint dn2 = 0;
00762 
00763     cxdouble amplitude = 0.;
00764     cxdouble background = 0.;
00765     cxdouble center = 0.;
00766     cxdouble width = 0.;
00767     cxdouble lower = 0.;
00768     cxdouble upper = 0.;
00769 
00770     struct {
00771         cxdouble amplitude;
00772         cxdouble background;
00773         cxdouble center;
00774         cxdouble width;
00775     } initial = {0., 0., 0., 0.};
00776 
00777     GiModel* model = giraffe_model_new("gaussian");
00778 
00779 
00780 
00781     cx_assert(model != NULL);
00782     cx_assert(strcmp(giraffe_model_get_name(model), "gaussian") == 0);
00783     cx_assert(lambda != NULL);
00784     cx_assert(ccf != NULL);
00785     cx_assert(grating != NULL);
00786     cx_assert(setup != NULL);
00787 
00788 
00789     /*
00790      * Initial guesses of the peak profile model. For the background
00791      * 0. can be used in case of ThAr spectra, otherwise the mean of
00792      * the 2 lowest values of the CCF should be used. The half-width
00793      * is derived from the nominal resolution of the grating.
00794      */
00795 
00796     background = 0.;
00797 
00798     amplitude = cpl_matrix_get_max((cpl_matrix*)ccf) - background;
00799 
00800     cpl_matrix_get_maxpos((cpl_matrix*)ccf, &nr, &nc);
00801     cx_assert(nr == 0);
00802 
00803     center = cpl_matrix_get((cpl_matrix*)lambda, 0, nc);
00804 
00805 
00806     if (setup->scale == GIREBIN_SCALE_LOG) {
00807         width = 0.5 / grating->resol;
00808     }
00809     else {
00810         width = 0.5 / grating->resol * grating->wlen0;
00811     }
00812 
00813     giraffe_model_set_parameter(model, "Background", background);
00814     giraffe_model_set_parameter(model, "Amplitude", amplitude);
00815     giraffe_model_set_parameter(model, "Center", center);
00816     giraffe_model_set_parameter(model, "Width1", width);
00817 
00818     giraffe_model_thaw(model);
00819 
00820     giraffe_model_set_iterations(model, setup->fit.iterations);
00821     giraffe_model_set_tests(model, setup->fit.tests);
00822     giraffe_model_set_delta(model, setup->fit.delta);
00823 
00824 
00825     /*
00826      * Save the initial parameter values.
00827      */
00828 
00829     initial.amplitude = amplitude;
00830     initial.background = background;
00831     initial.center = center;
00832     initial.width = width;
00833 
00834     i = 0;
00835 
00836     while (i < setup->iterations && !stop) {
00837 
00838         cxint j;
00839         cxint _dn1 = 0;
00840         cxint _dn2 = 0;
00841 
00842         cxdouble dwc = 0.;
00843         cxdouble dwd = 0.;
00844 
00845         cpl_matrix* tlambda = (cpl_matrix*)lambda;
00846         cpl_matrix* tccf = (cpl_matrix*)ccf;
00847 
00848 
00849         /*
00850          * The second iteration uses a weighted mean of the initial guess and
00851          * the first result. For all further iterations the new parameter
00852          * values are just taken from the previous iteration.
00853          */
00854 
00855         if (i == 1) {
00856 
00857             const cxdouble da = 0.2;
00858             const cxdouble dc = 1.;
00859             const cxdouble db = 1.;
00860             const cxdouble dw = 0.2;
00861 
00862             cxdouble value = 0.;
00863 
00864             value = giraffe_model_get_parameter(model, "Amplitude") * da;
00865             value += (1. - da) * initial.amplitude;
00866 
00867             giraffe_model_set_parameter(model, "Amplitude", value);
00868 
00869 
00870             value = giraffe_model_get_parameter(model, "Center") * dc;
00871             value += (1. - dc) * initial.center;
00872 
00873             giraffe_model_set_parameter(model, "Center", value);
00874 
00875 
00876             value = giraffe_model_get_parameter(model, "Background") * db;
00877             value += (1. - db) * initial.background;
00878 
00879             giraffe_model_set_parameter(model, "Background", value);
00880 
00881 
00882             value = giraffe_model_get_parameter(model, "Width1") * dw;
00883             value += (1. - dw) * initial.width;
00884 
00885             giraffe_model_set_parameter(model, "Width1", value);
00886 
00887         }
00888 
00889 
00890         /*
00891          * Set the window center and width. For the width a lower limit is
00892          * established to guarantee a minimum number of point for the fit.
00893          */
00894 
00895         dwd = 2. * giraffe_model_get_parameter(model, "Width1") *
00896             setup->wfactor;
00897         dwc = giraffe_model_get_parameter(model, "Center");
00898 
00899         dwd = CX_MAX(setup->dnmin, 2. * dwd / setup->step) * setup->step / 2.;
00900 
00901         lower = dwc + 0.5 * setup->step - dwd;
00902         upper = dwc + 0.5 * setup->step + dwd;
00903 
00904 
00905         /*
00906          * Extract the slices corresponding to the reduced window size
00907          * from the input data arrays. This is the data set which is
00908          * actually fitted.
00909          */
00910 
00911         for (j = 0; j < cpl_matrix_get_ncol(tlambda); j++) {
00912 
00913             if (cpl_matrix_get(tlambda, 0, j) > lower) {
00914                 _dn1 = j;
00915                 break;
00916             }
00917 
00918         }
00919 
00920         for (j = cpl_matrix_get_ncol(tlambda) - 1; j >= 0; j--) {
00921 
00922             if (cpl_matrix_get(tlambda, 0, j) < upper) {
00923                 _dn2 = j + 1;
00924                 break;
00925             }
00926 
00927         }
00928 
00929 
00930         if (i > 0 && dn1 == _dn1 && dn2 == _dn2) {
00931 
00932             cxdouble _width = giraffe_model_get_parameter(model, "Width1");
00933 
00934             /*
00935              * This is the same set of points. The fitting stops after
00936              * one last iteration on the further reduced data set.
00937              */
00938 
00939             dwd = CX_MAX(setup->dnmin, 4. * _width * setup->wfactor /
00940                          setup->step) * setup->step / 2.;
00941 
00942             lower = dwc + 0.5 * setup->step - dwd;
00943             upper = dwc + 0.5 * setup->step + dwd;
00944 
00945             for (j = 0; j < cpl_matrix_get_ncol(tlambda); j++) {
00946 
00947                 if (cpl_matrix_get(tlambda, 0, j) > lower) {
00948                     _dn1 = j;
00949                     break;
00950                 }
00951 
00952             }
00953 
00954             for (j = cpl_matrix_get_ncol(tlambda) - 1; j <= 0; j--) {
00955 
00956                 if (cpl_matrix_get(tlambda, 0, j) < upper) {
00957                     _dn2 = j + 1;
00958                     break;
00959                 }
00960 
00961             }
00962 
00963             stop = TRUE;
00964 
00965         }
00966 
00967 
00968         /* FIXME: The original code uses i == 0 instead of i <= 1. Check
00969          *        whether there is a reason for that or if this is just
00970          *        a bug.
00971          */
00972 
00973         if (i <= 1 || dn1 != _dn1 || dn2 != _dn2) {
00974 
00975             cxbool flag = FALSE;
00976 
00977             const cxint pflag = 1;
00978             cxint status = 0;
00979 
00980             cxdouble damplitude = 0.;
00981             cxdouble dbackground = 0.;
00982             cxdouble dcenter = 0.;
00983             cxdouble dwidth = 0.;
00984 
00985             cpl_matrix* x = NULL;
00986             cpl_matrix* y = NULL;
00987             cpl_matrix* sigma = NULL;
00988 
00989 
00990             dn1 = _dn1;
00991             dn2 = _dn2;
00992 
00993             x = cpl_matrix_new(dn2 - dn1, 1);
00994             y = cpl_matrix_new(dn2 - dn1, 1);
00995             sigma = cpl_matrix_new(dn2 - dn1, 1);
00996 
00997             for (j = 0; j < cpl_matrix_get_nrow(y); j++) {
00998 
00999                 cpl_matrix_set(x, j, 0, cpl_matrix_get(tlambda, 0, dn1 + j));
01000                 cpl_matrix_set(y, j, 0, cpl_matrix_get(tccf, 0, dn1 + j));
01001                 cpl_matrix_set(sigma, j, 0, setup->sigma);
01002 
01003             }
01004 
01005 
01006             /*
01007              * Finally, fit the peak profile.
01008              */
01009 
01010             status = giraffe_model_fit(model, x, y, sigma);
01011 
01012             if (status != 0) {
01013 
01014                 peak->amplitude.value = initial.amplitude;
01015                 peak->background.value = initial.background;
01016                 peak->center.value = initial.center;
01017                 peak->width.value = initial.width;
01018 
01019                 peak->amplitude.sigma = 1.;
01020                 peak->background.sigma = 1.;
01021                 peak->center.sigma = 1.;
01022                 peak->width.sigma = 1.;
01023 
01024                 peak->status = -1;
01025 
01026                 cpl_matrix_delete(x);
01027                 cpl_matrix_delete(y);
01028                 cpl_matrix_delete(sigma);
01029 
01030                 giraffe_model_delete(model);
01031 
01032                 return 1;
01033 
01034             }
01035 
01036 
01037             /*
01038              * Check `out of bounds' condition for the fitted parameters.
01039              * and their uncertainties.
01040              */
01041 
01042             amplitude = giraffe_model_get_parameter(model, "Amplitude");
01043             damplitude = giraffe_model_get_sigma(model, "Amplitude");
01044 
01045             center = giraffe_model_get_parameter(model, "Center");
01046             dcenter = giraffe_model_get_sigma(model, "Center");
01047 
01048             background = giraffe_model_get_parameter(model, "Background");
01049             dbackground = giraffe_model_get_sigma(model, "Background");
01050 
01051             width = giraffe_model_get_parameter(model, "Width1");
01052             dwidth = giraffe_model_get_sigma(model, "Width1");
01053 
01054 
01055             /* FIXME: Where do these limits come from? (RP)
01056              */
01057 
01058             /* Amplitude */
01059 
01060             lower = -9. * (1 - pflag) + 1.e-5 * pflag;
01061             upper =  9. * pflag - 1.e-5 * (1 - pflag);
01062 
01063             peak->amplitude.value = _giraffe_clip_value(amplitude, lower,
01064                                                         upper, &flag);
01065             peak->amplitude.sigma = _giraffe_clip_value(damplitude, 0.,
01066                                                         1., NULL);
01067 
01068             stop = stop == FALSE ? flag == TRUE ? TRUE : FALSE : stop;
01069 
01070             /* Center */
01071 
01072             lower = cpl_matrix_get(x, 1, 0);
01073             upper = cpl_matrix_get(x, cpl_matrix_get_nrow(x) - 2, 0);
01074 
01075             peak->center.value = _giraffe_clip_value(center, lower,
01076                                                      upper, &flag);
01077             peak->center.sigma = _giraffe_clip_value(dcenter, 0.,
01078                                                      initial.width, NULL);
01079 
01080             stop = stop == FALSE ? flag == TRUE ? TRUE : FALSE : stop;
01081 
01082             /* Background */
01083 
01084             lower = -2;
01085             upper =  2.;
01086 
01087             peak->background.value = _giraffe_clip_value(background, lower,
01088                                                          upper, &flag);
01089             peak->background.sigma = _giraffe_clip_value(dbackground, 0.,
01090                                                          1., NULL);
01091 
01092             stop = stop == FALSE ? flag == TRUE ? TRUE : FALSE : stop;
01093 
01094             /* Width */
01095 
01096             lower = 0.5 * initial.width;
01097             upper = 2. * (cpl_matrix_get(x, cpl_matrix_get_nrow(x) - 2, 0) -
01098                           cpl_matrix_get(x, 0, 0));
01099 
01100             peak->width.value = _giraffe_clip_value(width, lower,
01101                                                     upper, &flag);
01102             peak->width.sigma = _giraffe_clip_value(dwidth, 0.,
01103                                                     9., NULL);
01104 
01105             stop = stop == FALSE ? flag == TRUE ? TRUE : FALSE : stop;
01106 
01107             cpl_matrix_delete(x);
01108             cpl_matrix_delete(y);
01109             cpl_matrix_delete(sigma);
01110 
01111             if (stop == TRUE) {
01112                 cpl_msg_debug(fctid, "Cross-correlation peak fit "
01113                               "parameter out of bounds!");
01114 
01115                 peak->status = 1;
01116             }
01117             else {
01118                 peak->status = 0;
01119             }
01120 
01121             ++i;
01122 
01123         }
01124         else {
01125 
01126             stop = TRUE;
01127 
01128         }
01129 
01130     }
01131 
01132     giraffe_model_delete(model);
01133 
01134     return 0;
01135 
01136 }
01137 
01138 
01139 inline static cxint
01140 _giraffe_compute_fiber_offsets(cpl_table* offsets,
01141                                const GiGrating* grating,
01142                                const GiSGSetup* setup)
01143 {
01144 
01145     cxint i;
01146 
01147     const cxdouble ccdfactor = 1.1;
01148 
01149     cxdouble gcamera = 1.;
01150     cxdouble cfactor = 1.;
01151     cxdouble lincorr = 1.;
01152     cxdouble wlen0 = 0.;
01153 
01154 
01155     cx_assert(offsets != NULL);
01156 
01157     if (!cpl_table_has_column(offsets, "WAVELENGTH")) {
01158         return 1;
01159     }
01160 
01161     if (!cpl_table_has_column(offsets, "DWF")) {
01162         cpl_table_new_column(offsets, "DWF", CPL_TYPE_DOUBLE);
01163     }
01164 
01165     if (!cpl_table_has_column(offsets, "DXF")) {
01166         cpl_table_new_column(offsets, "DXF", CPL_TYPE_DOUBLE);
01167     }
01168 
01169 
01170     /*
01171      * Compute the central wavelength of the spectral band, taking into
01172      * account the scaling used to rebin the spectra.
01173      */
01174 
01175     if (setup->scale == GIREBIN_SCALE_LOG) {
01176         wlen0 = 0.5 * (exp(setup->wlmin) + exp(setup->wlmax));
01177     }
01178     else {
01179         wlen0 = 0.5 * (setup->wlmin + setup->wlmax);
01180     }
01181 
01182 
01183     /*
01184      * Approximate magnification of the camera.
01185      */
01186 
01187     /*
01188      * FIXME: Any hint on these numbers? (RP)
01189      */
01190 
01191     gcamera = 0.3894 - 5. * (1. / wlen0 - 1. / 550.) -
01192         0.00025 * pow(1. / wlen0 - 1. / 550., 2.);
01193 
01194     /*
01195      * Conversion factor from CCD displacement to slit geometry.
01196      */
01197 
01198     /* FIXME: This will be used until there is a better formula
01199      *        (OGL comment).
01200      */
01201 
01202     cfactor = (setup->nex * setup->pixelsize / 1000. * ccdfactor) /
01203         ((grating->wlenmax - grating->wlenmin) * gcamera);
01204 
01205 
01206     /*
01207      * Correction factor for linear scale on the correlation
01208      */
01209 
01210     if (setup->scale == GIREBIN_SCALE_LOG) {
01211         lincorr = 1.0;
01212     }
01213     else {
01214         lincorr = 0.5 * (setup->wlmin + setup->wlmax) /
01215             exp(0.5 * (log(setup->wlmin) + log(setup->wlmax)));
01216     }
01217 
01218 
01219     /*
01220      * Compute slit offsets
01221      */
01222 
01223     for (i = 0; i < cpl_table_get_nrow(offsets); i++) {
01224 
01225 
01226         cxdouble dwf = cpl_table_get_double(offsets, "WAVELENGTH", i, NULL);
01227         cxdouble dxf = 0.;
01228 
01229 
01230         dwf *= -lincorr;
01231         dxf = dwf * cfactor;
01232 
01233         cpl_table_set_double(offsets, "DWF", i, dwf);
01234         cpl_table_set_double(offsets, "DXF", i, dxf);
01235 
01236     }
01237 
01238     return 0;
01239 
01240 }
01241 
01242 
01243 inline static cpl_table*
01244 _giraffe_compute_offsets(const GiImage* spectra, const GiTable* mask,
01245                          const cpl_table* fibers, const GiGrating* grating,
01246                          const GiSGSetup* setup, const GiSGCalConfig* config)
01247 {
01248 
01249     const cxchar* const fctid = "_giraffe_compute_offsets";
01250 
01251     const cxint dnmin = 7;  /* Minimum number of points */
01252 
01253     cxint i;
01254     cxint k;
01255     cxint status = 0;
01256     cxint sampling = 0;
01257     cxint pixel0 = 0;
01258     cxint dn1 = 0;
01259     cxint dn2 = 0;
01260     cxint dnc = 0;
01261     cxint dnd = 0;
01262     cxint xc1 = 0;
01263     cxint xc2 = 0;
01264 
01265     const cxdouble clight = 299702.547;   /* Vacuum light speed [km/s] */
01266 
01267     cxdouble cstep = 0.;
01268     cxdouble wlen0 = 0.;
01269     cxdouble nm2km = clight;
01270     cxdouble hpixels = 0.;
01271     cxdouble dv1 = 0.;
01272     cxdouble dv2 = 0.;
01273     cxdouble dw1 = 0.;
01274     cxdouble dw2 = 0.;
01275     cxdouble dwc = 0.;
01276     cxdouble dwd = 0.;
01277 
01278     cpl_matrix* spectrum = NULL;
01279 
01280     cpl_image* _spectra = NULL;
01281     cpl_image* tspectra = NULL;
01282 
01283     cpl_table* peakdata = NULL;
01284 
01285     GiSGMask* _mask = NULL;
01286 
01287 
01288     cx_assert(spectra != NULL);
01289     cx_assert(mask != NULL);
01290     cx_assert(fibers != NULL);
01291     cx_assert(grating != NULL);
01292     cx_assert(setup != NULL);
01293     cx_assert(config != NULL);
01294 
01295 
01296     /*
01297      * Compute the sampling step size
01298      */
01299 
01300     if (config->cc_step <= 0.) {
01301         sampling = 1;
01302     }
01303     else {
01304 
01305         if (setup->scale == GIREBIN_SCALE_LOG) {
01306 
01307             cxdouble wlstep = (exp(setup->wlmax) - exp(setup->wlmin)) /
01308                 setup->nx;
01309 
01310             sampling = (cxint)(0.5 + wlstep / config->cc_step);
01311 
01312         }
01313         else {
01314 
01315             sampling = (cxint)(0.5 + setup->wlstep / config->cc_step);
01316 
01317         }
01318 
01319     }
01320 
01321     cstep = setup->wlstep / sampling;
01322 
01323 
01324     /*
01325      * Create and initialize the final mask
01326      */
01327 
01328     _mask = _giraffe_sgmask_create((setup->nx - 1) * sampling + 1,
01329                                    setup->wlmin, cstep, setup->scale,
01330                                    mask);
01331 
01332     if (_mask == NULL) {
01333         return NULL;
01334     }
01335 
01336 
01337     /*
01338      * Prepare the initial window
01339      */
01340 
01341     pixel0 = setup->nx / 2;
01342 
01343     if (setup->scale == GIREBIN_SCALE_LOG) {
01344 
01345         /*
01346          * Logarithmic scale: dv / clight = d(log(lambda))
01347          */
01348 
01349         wlen0 = 0.5 * (exp(setup->wlmin) + exp(setup->wlmax));
01350         nm2km = clight;
01351 
01352     }
01353     else {
01354 
01355         /*
01356          * Linear scale: dv / clight = d(log(lambda)) / lambda
01357          */
01358 
01359         wlen0 = 0.5 * (setup->wlmin + setup->wlmax);
01360         nm2km = clight / wlen0;
01361 
01362     }
01363 
01364 
01365     /*
01366      * Window limits in km/s, nm and pxl and window center and
01367      * half-width in nm and pxl.
01368      */
01369 
01370     dv1 = giraffe_range_get_min(config->rv_limits);
01371     dv2 = giraffe_range_get_max(config->rv_limits);
01372 
01373     dw1 = dv1 / nm2km;
01374     dw2 = dv2 / nm2km;
01375 
01376     cpl_msg_debug(fctid, "Cross-correlation limits: RVlow = %.4f km/s "
01377                   "(%.4f nm), RVhigh = %.4f km/s (%.4f nm)", dv1, dw1,
01378                   dv2, dw2);
01379 
01380     dwd = (dw2 - dw1) / 2.;
01381     dwc = (dw2 + dw1) / 2.;
01382 
01383     dnd = CX_MIN(pixel0, CX_MAX(dnmin, (cxint)(dwd / cstep + 0.5)));
01384     dnc = CX_MIN(pixel0, CX_MAX(-pixel0, (cxint)(dwc / cstep + 0.5)));
01385 
01386     dn1 = CX_MIN(pixel0 + 1, CX_MAX(-pixel0, dnc - dnd));
01387     dn2 = CX_MIN(pixel0 + 1, CX_MAX(-pixel0, dnc + dnd + 1));
01388 
01389     cpl_msg_debug(fctid, "Cross-correlation window: center = %.4f nm "
01390                   "(%d pxl) half-width = %.4f nm (%d pxl)", dwc, dnc,
01391                   dwd, dnd);
01392 
01393 
01394     /*
01395      * Select spectral range of the spectra and the template which should
01396      * be used for the cross-correlation.
01397      */
01398 
01399     xc1 = (cxint)(giraffe_range_get_min(config->cc_domain) * sampling);
01400     xc2 = (cxint)(giraffe_range_get_max(config->cc_domain) * sampling);
01401 
01402     if (xc1 > 0 || xc2 > 0) {
01403         _giraffe_sgmask_crop(_mask, xc1, xc2);
01404     }
01405 
01406     for (i = 0; (cxsize)i < _giraffe_sgmask_size(_mask); i++) {
01407 
01408         cxdouble value = _giraffe_sgmask_get_flux(_mask, i);
01409 
01410         if (value > 0.) {
01411             hpixels += value;
01412         }
01413 
01414     }
01415 
01416     hpixels /= _giraffe_sgmask_holes(_mask);
01417 
01418 
01419     /*
01420      * The left- and rightmost dn1 points of the mask are set to 0. In
01421      * addition partial holes at the beginning and the end of the mask
01422      * removed, i.e. set to 0 flux.
01423      */
01424 
01425     i = 0;
01426     k = CX_MAX(0, -dn1);
01427 
01428     while (i < k || _giraffe_sgmask_get_flux(_mask, i) > 0.) {
01429 
01430         _giraffe_sgmask_set_flux(_mask, i, 0.);
01431         ++i;
01432 
01433     }
01434 
01435     cpl_msg_debug(fctid, "Mask cleared from 0 to %d", i - 1);
01436 
01437     i = _giraffe_sgmask_size(_mask);
01438     k = _giraffe_sgmask_size(_mask) - CX_MAX(0, dn2);
01439 
01440     while (i > k || _giraffe_sgmask_get_flux(_mask, i) > 0.) {
01441 
01442         _giraffe_sgmask_set_flux(_mask, i, 0.);
01443         --i;
01444 
01445     }
01446 
01447     cpl_msg_debug(fctid, "Mask cleared from %d to %d", k,
01448                   _giraffe_sgmask_size(_mask) - 1);
01449 
01450 
01451     /*
01452      * Resample the input image to the mask's sampling step and crop its
01453      * spectral range so that it matches the template.
01454      */
01455 
01456     _spectra = cpl_image_duplicate(giraffe_image_get(spectra));
01457 
01458     if (_spectra == NULL) {
01459 
01460         _giraffe_sgmask_delete(_mask);
01461 
01462         return NULL;
01463 
01464     }
01465 
01466 
01467     if (config->zmax > 0.) {
01468 
01469         cpl_image_threshold(_spectra, CX_MINDOUBLE, config->zmax,
01470                             0., config->zmax);
01471 
01472     }
01473 
01474 
01475     tspectra = _giraffe_resample_image(_spectra, setup->wlstep, cstep);
01476 
01477     if (tspectra == NULL) {
01478 
01479         cpl_image_delete(_spectra);
01480 
01481         _giraffe_sgmask_delete(_mask);
01482 
01483         return NULL;
01484 
01485     }
01486 
01487     cpl_image_delete(_spectra);
01488     _spectra = NULL;
01489 
01490     if (xc1 > 0 || xc2 > 0) {
01491 
01492         _spectra = cpl_image_extract(tspectra, 1, xc1 + 1,
01493                                      cpl_image_get_size_x(tspectra), xc2 + 1);
01494 
01495         if (_spectra == NULL) {
01496 
01497             cpl_image_delete(tspectra);
01498 
01499             _giraffe_sgmask_delete(_mask);
01500 
01501             return NULL;
01502 
01503         }
01504 
01505         cpl_image_delete(tspectra);
01506         tspectra = NULL;
01507 
01508     }
01509     else {
01510 
01511         _spectra = tspectra;
01512         tspectra = NULL;
01513 
01514     }
01515 
01516 
01517     /*
01518      * Create the table to record the results from the cross-correlation
01519      * peak fitting for each fiber.
01520      */
01521 
01522     peakdata = cpl_table_new(cpl_table_get_nrow(fibers));
01523 
01524     cpl_table_duplicate_column(peakdata, "INDEX", (cpl_table*)fibers,
01525                                "INDEX");
01526     cpl_table_duplicate_column(peakdata, "FPS", (cpl_table*)fibers,
01527                                "FPS");
01528 
01529     cpl_table_new_column(peakdata, "WAVELENGTH", CPL_TYPE_DOUBLE);
01530     cpl_table_new_column(peakdata, "FWHM", CPL_TYPE_DOUBLE);
01531     cpl_table_new_column(peakdata, "AMPLITUDE", CPL_TYPE_DOUBLE);
01532     cpl_table_new_column(peakdata, "BACKGROUND", CPL_TYPE_DOUBLE);
01533     cpl_table_new_column(peakdata, "RV", CPL_TYPE_DOUBLE);
01534     cpl_table_new_column(peakdata, "RVERR", CPL_TYPE_DOUBLE);
01535     cpl_table_new_column(peakdata, "RESOLUTION", CPL_TYPE_DOUBLE);
01536     cpl_table_new_column(peakdata, "STATUS", CPL_TYPE_INT);
01537 
01538 
01539     /*
01540      * Compute the cross-correlation with the mask for each spectrum in
01541      * the input image.
01542      */
01543 
01544     cpl_msg_debug(fctid, "Computing cross-correlation: central wavelength = "
01545                   "%.4f, window = [%.4f, %.4f] [km/s]", wlen0, dv1, dv2);
01546 
01547     spectrum = cpl_matrix_new(1, cpl_image_get_size_y(_spectra));
01548 
01549     for (i = 0; i < cpl_table_get_nrow(fibers); i++) {
01550 
01551         cxint j;
01552         cxint ns = cpl_image_get_size_x(_spectra);
01553         cxint fiber = cpl_table_get_int(fibers, "FPS", i, NULL);
01554         cxint idx = cpl_table_get_int(fibers, "INDEX", i, NULL) - 1;
01555 
01556         const cxdouble fwhm_ratio = 2. * sqrt(2. * log(2.));
01557 
01558         cxdouble avsigma = 0.;
01559         cxdouble fx = 0.;
01560         cxdouble fxtotal = 0.;
01561         cxdouble fxaverage = 0.;
01562         cxdouble fxmask = 0.;
01563         cxdouble sum = 0.;
01564         cxdouble position = 0.;
01565         cxdouble fwhm = 0.;
01566         cxdouble width = 0.;
01567         cxdouble resolution = 0.;
01568         cxdouble rv = 0.;
01569         cxdouble rverr = 0.;
01570         cxdouble* data = cpl_image_get_data(_spectra);
01571 
01572         const cpl_matrix* template = NULL;
01573         cpl_matrix* ccf = NULL;
01574         cpl_matrix* lambda = NULL;
01575 
01576         GiCPFitParams peak_setup;
01577         GiCPeakFit peak;
01578 
01579 
01580 
01581         /*
01582          * Copy the current spectrum to the working matrix and
01583          * compute the total flux of the masked spectrum.
01584          */
01585 
01586         for (j = 0; j < cpl_matrix_get_ncol(spectrum); j++) {
01587 
01588             cxdouble flux = data[j * ns + idx];
01589 
01590 
01591             cpl_matrix_set(spectrum, 0, j, flux);
01592 
01593             fxtotal += flux;
01594             fxmask += _giraffe_sgmask_get_flux(_mask, j);
01595             fx += flux * _giraffe_sgmask_get_flux(_mask, j);
01596 
01597         }
01598 
01599         fx /= sampling;
01600         fxaverage = fxtotal / fxmask;
01601 
01602         if (fx > 0.) {
01603             avsigma = 1. / sqrt(fx);
01604         }
01605 
01606         cpl_msg_debug(fctid, "Cross-correlation of spectrum %d in window "
01607                       "from %d pxl to %d pxl (%.4f nm to %.4f nm)", fiber,
01608                       dn1, dn2, dw1, dw2);
01609 
01610 
01611         /*
01612          * Wavelength within the cross-correlation window
01613          */
01614 
01615         lambda = cpl_matrix_new(1, dn2 - dn1);
01616 
01617         for (j = dn1; j < dn2; j++) {
01618             cpl_matrix_set(lambda, 0, j - dn1, j * cstep);
01619         }
01620 
01621 
01622         /*
01623          * Cross-correlation
01624          */
01625 
01626         template = _giraffe_sgmask_get(_mask);
01627 
01628         ccf = _giraffe_compute_cross_correlation(spectrum, template, dn1, dn2);
01629 
01630         if (ccf == NULL) {
01631 
01632             cpl_matrix_delete(lambda);
01633             cpl_matrix_delete(spectrum);
01634 
01635             cpl_image_delete(_spectra);
01636 
01637             cpl_table_delete(peakdata);
01638 
01639             _giraffe_sgmask_delete(_mask);
01640 
01641             return NULL;
01642 
01643         }
01644 
01645         sum = 0.;
01646 
01647         for (j = 0; j < cpl_matrix_get_ncol(ccf); j++) {
01648             sum += cpl_matrix_get(ccf, 0, j);
01649         }
01650 
01651         if (sum <= 0.) {
01652             cpl_msg_debug(fctid, "Cross-correlation failed: Skipping "
01653                           "spectrum %d.", fiber);
01654 
01655             cpl_matrix_delete(lambda);
01656             lambda = NULL;
01657 
01658             continue;
01659         }
01660 
01661 
01662         /*
01663          * Fit the cross-correlation peak
01664          */
01665 
01666         peak_setup.dnmin = dnmin;
01667         peak_setup.iterations = config->rv_niter;
01668         peak_setup.step = cstep;
01669         peak_setup.wfactor = config->rv_wfactor;
01670         peak_setup.sigma = avsigma;
01671         peak_setup.scale = setup->scale;
01672 
01673         peak_setup.fit.iterations = config->pf_niter;
01674         peak_setup.fit.tests = config->pf_ntest;
01675         peak_setup.fit.delta = config->pf_dchisq;
01676 
01677         status = _giraffe_peak_fit(&peak, lambda, ccf, grating, &peak_setup);
01678 
01679         if (status < 0) {
01680 
01681             cpl_matrix_delete(ccf);
01682             cpl_matrix_delete(lambda);
01683 
01684             cpl_matrix_delete(spectrum);
01685             cpl_image_delete(_spectra);
01686 
01687             cpl_table_delete(peakdata);
01688 
01689             _giraffe_sgmask_delete(_mask);
01690 
01691             return NULL;
01692 
01693         }
01694 
01695 
01696         /*
01697          * Save the results to the output table.
01698          */
01699 
01700         if (setup->scale == GIREBIN_SCALE_LOG) {
01701             position = peak.center.value * wlen0;
01702             fwhm = (exp(peak.width.value) - 1.) * wlen0;
01703         }
01704         else {
01705             position = peak.center.value;
01706             fwhm = peak.width.value;
01707         }
01708 
01709         width = pow(fwhm_ratio * fwhm, 2.) - pow(0.6 * hpixels * cstep, 2.);
01710         resolution = width > 0. ? wlen0 / sqrt(width) : 0.;
01711 
01712         fwhm *= 2.;
01713 
01714         rv = CX_MAX(dv1, CX_MIN(dv2, peak.center.value * nm2km));
01715         rverr = CX_MIN(dv2 - dv1, peak.center.sigma * nm2km);
01716 
01717         cpl_table_set_double(peakdata, "WAVELENGTH", i, position);
01718         cpl_table_set_double(peakdata, "FWHM", i, fwhm);
01719         cpl_table_set_double(peakdata, "AMPLITUDE", i, peak.amplitude.value);
01720         cpl_table_set_double(peakdata, "BACKGROUND", i,
01721                              peak.background.value);
01722         cpl_table_set_double(peakdata, "RESOLUTION", i, resolution);
01723         cpl_table_set_double(peakdata, "RV", i, rv);
01724         cpl_table_set_double(peakdata, "RVERR", i, rverr);
01725         cpl_table_set_int(peakdata, "STATUS", i, peak.status);
01726 
01727         cpl_matrix_delete(lambda);
01728         cpl_matrix_delete(ccf);
01729 
01730     }
01731 
01732     cpl_matrix_delete(spectrum);
01733     cpl_image_delete(_spectra);
01734 
01735     _giraffe_sgmask_delete(_mask);
01736 
01737     return peakdata;
01738 
01739 }
01740 
01741 
01742 inline static cpl_table*
01743 _giraffe_compute_slitgeometry(const GiImage* spectra, const GiTable* mask,
01744                               const GiTable* slitgeometry,
01745                               const GiGrating* grating,
01746                               const GiSGCalConfig* config)
01747 {
01748 
01749     cxint status = 0;
01750 
01751     cpl_table* _slitgeometry = giraffe_table_get(slitgeometry);
01752     cpl_table* peakdata = NULL;
01753 
01754     GiSGSetup setup;
01755 
01756 
01757     /*
01758      * Get setup information from the rebinned spectra frame
01759      */
01760 
01761     status = _giraffe_create_setup(&setup, spectra);
01762 
01763     if (status != 0) {
01764         return NULL;
01765     }
01766 
01767     /*
01768      * Compute the wavelength shifts between the reference mask and
01769      * the arc-lamp spectra, from the position of the cross-correlation
01770      * peak.
01771      *
01772      * Note that either a fiber, or a slitgeometry table may be passed to
01773      * _giraffe_compute_offsets(). Actually any table providing the
01774      * columns "INDEX" and "FPS", describing the pixel column of each
01775      * spectrum in the input image and the fiber position within the
01776      * pseudo slit.
01777      */
01778 
01779     peakdata = _giraffe_compute_offsets(spectra, mask, _slitgeometry,
01780                                         grating, &setup, config);
01781 
01782     if (peakdata == NULL) {
01783         return NULL;
01784     }
01785 
01786 
01787     /*
01788      * Compute the offsets of the fibers in the pseudo-slit (i.e. in the
01789      * focal plane.
01790      */
01791 
01792     status = _giraffe_compute_fiber_offsets(peakdata, grating, &setup);
01793 
01794     if (status != 0) {
01795         cpl_table_delete(peakdata);
01796         return NULL;
01797     }
01798 
01799 
01800     /*
01801      * Compute fiber positions
01802      */
01803 
01804     cpl_table_duplicate_column(peakdata, "XF", _slitgeometry, "XF");
01805     cpl_table_add_columns(peakdata, "XF", "DXF");
01806 
01807     return peakdata;
01808 
01809 }
01810 
01811 
01812 inline static GiTable*
01813 _giraffe_slitgeometry_table(const cpl_table* offsets,
01814                             const GiImage* spectra,
01815                             const GiTable* fibers,
01816                             const GiTable* slitgeometry,
01817                             const GiSGCalConfig* config)
01818 {
01819 
01820     const cxchar* idx = NULL;
01821 
01822     cxint i;
01823 
01824     cpl_propertylist* properties = NULL;
01825     cpl_propertylist* _properties = NULL;
01826 
01827     cpl_table* _slit = NULL;
01828     cpl_table* _fibers = NULL;
01829     cpl_table* _slitgeometry = NULL;
01830 
01831     GiTable* slit = NULL;
01832 
01833 
01834     cx_assert(spectra != NULL);
01835     cx_assert(fibers != NULL);
01836 
01837     _fibers = giraffe_table_get(fibers);
01838     cx_assert(_fibers != NULL);
01839 
01840     _slitgeometry = giraffe_table_get(slitgeometry);
01841     cx_assert(_slitgeometry != NULL);
01842 
01843     if (offsets == NULL) {
01844         return NULL;
01845     }
01846 
01847 
01848     slit = giraffe_table_new();
01849 
01850     properties = giraffe_image_get_properties(spectra);
01851     cx_assert(properties != NULL);
01852 
01853     giraffe_error_push();
01854 
01855     _properties = cpl_propertylist_new();
01856 
01857     giraffe_propertylist_copy(_properties, GIALIAS_INSTRUMENT, properties,
01858                               GIALIAS_INSTRUMENT);
01859 
01860     giraffe_propertylist_copy(_properties, GIALIAS_DATEOBS, properties,
01861                               GIALIAS_DATEOBS);
01862 
01863     giraffe_propertylist_copy(_properties, GIALIAS_MJDOBS, properties,
01864                               GIALIAS_MJDOBS);
01865 
01866     giraffe_propertylist_copy(_properties, GIALIAS_INSMODE, properties,
01867                               GIALIAS_INSMODE);
01868 
01869     giraffe_propertylist_copy(_properties, GIALIAS_INSMODE, properties,
01870                               GIALIAS_INSMODE);
01871 
01872     giraffe_propertylist_copy(_properties, GIALIAS_SETUPNAME, properties,
01873                               GIALIAS_SETUPNAME);
01874 
01875     giraffe_propertylist_copy(_properties, GIALIAS_SLITNAME, properties,
01876                               GIALIAS_SLITNAME);
01877 
01878     giraffe_propertylist_copy(_properties, GIALIAS_FILTNAME, properties,
01879                               GIALIAS_FILTNAME);
01880 
01881     giraffe_propertylist_copy(_properties, GIALIAS_GRATNAME, properties,
01882                               GIALIAS_GRATNAME);
01883 
01884     giraffe_propertylist_copy(_properties, GIALIAS_GRATWLEN, properties,
01885                               GIALIAS_GRATWLEN);
01886 
01887     giraffe_propertylist_copy(_properties, GIALIAS_GRATORDER, properties,
01888                               GIALIAS_GRATORDER);
01889 
01890     cpl_propertylist_update_double(_properties, GIALIAS_SCAL_CUTOFF,
01891                                    config->zmax);
01892     cpl_propertylist_set_comment(_properties, GIALIAS_SCAL_CUTOFF,
01893                                  "Cutoff pixel value.");
01894 
01895     cpl_propertylist_update_string(_properties, GIALIAS_GIRFTYPE, "SLITGEOTAB");
01896     cpl_propertylist_set_comment(_properties, GIALIAS_GIRFTYPE,
01897                                  "Giraffe frame type.");
01898 
01899 
01900     _slit = cpl_table_new(cpl_table_get_nrow(_fibers));
01901 
01902     cpl_table_new_column(_slit, "INDEX", CPL_TYPE_INT);
01903 
01904     for (i = 0; i < cpl_table_get_nrow(_slit); i++) {
01905         cpl_table_set_int(_slit, "INDEX", i, i + 1);
01906     }
01907 
01908     cpl_table_duplicate_column(_slit, "FPS", (cpl_table*)_fibers, "FPS");
01909     cpl_table_duplicate_column(_slit, "SSN", (cpl_table*)_fibers, "SSN");
01910     cpl_table_duplicate_column(_slit, "XF", (cpl_table*)offsets, "XF");
01911     cpl_table_duplicate_column(_slit, "YF", (cpl_table*)_slitgeometry, "YF");
01912 
01913     if (cpl_table_has_column(_slitgeometry, "ZF")) {
01914         cpl_table_duplicate_column(_slit, "ZF",
01915                                    (cpl_table*)_slitgeometry, "ZF");
01916     }
01917 
01918     if (cpl_table_has_column(_slitgeometry, "ZDEFOCUS")) {
01919         cpl_table_duplicate_column(_slit, "ZDEFOCUS",
01920                                    (cpl_table*)_slitgeometry, "ZDEFOCUS");
01921     }
01922 
01923     cpl_table_duplicate_column(_slit, "RV", (cpl_table*)offsets, "RV");
01924     cpl_table_duplicate_column(_slit, "RVERR", (cpl_table*)offsets, "RVERR");
01925     cpl_table_duplicate_column(_slit, "RESOLUTION", (cpl_table*)offsets,
01926                                "RESOLUTION");
01927 
01928     idx = giraffe_fiberlist_query_index(_fibers);
01929     cpl_table_duplicate_column(_slit, "RINDEX", _fibers, idx);
01930 
01931     if (cpl_error_get_code() != CPL_ERROR_NONE) {
01932         cpl_propertylist_delete(_properties);
01933         cpl_table_delete(_slit);
01934 
01935         giraffe_table_delete(slit);
01936 
01937         return NULL;
01938     }
01939 
01940     giraffe_error_pop();
01941 
01942     giraffe_table_set_properties(slit, _properties);
01943     cpl_propertylist_delete(_properties);
01944 
01945     giraffe_table_set(slit, _slit);
01946     cpl_table_delete(_slit);
01947 
01948     return slit;
01949 
01950 }
01951 
01952 
01958 cxint
01959 giraffe_calibrate_slit(GiTable* result, const GiExtraction* extraction,
01960                        const GiLocalization* localization,
01961                        const GiTable* fibers, const GiTable* wlsolution,
01962                        const GiTable* slitgeometry, const GiTable* grating,
01963                        const GiTable* mask, const GiSGCalConfig* config)
01964 {
01965 
01966     const cxchar* const fctid = "giraffe_calibrate_slit";
01967 
01968     cxint i;
01969     cxint status = 0;
01970 
01971     cpl_table* _fibers = NULL;
01972     cpl_table* _slitgeometry = NULL;
01973     cpl_table* offsets = NULL;
01974 
01975     GiTable* slit = NULL;
01976 
01977     GiGrating* setup = NULL;
01978 
01979     GiExtraction* _extraction = NULL;
01980 
01981 
01982     if (result == NULL) {
01983         return 1;
01984     }
01985 
01986     if (extraction == NULL) {
01987         return 1;
01988     }
01989 
01990     if (extraction->spectra == NULL) {
01991         return 1;
01992     }
01993 
01994     if (localization == NULL) {
01995         return 1;
01996     }
01997 
01998     if (fibers == NULL) {
01999         return 1;
02000     }
02001 
02002     if (wlsolution == NULL) {
02003         return 1;
02004     }
02005 
02006     if (slitgeometry == NULL) {
02007         return 1;
02008     }
02009 
02010     if (grating == NULL) {
02011         return 1;
02012     }
02013 
02014     if (mask == NULL) {
02015         return 1;
02016     }
02017 
02018     if (config == NULL) {
02019         return 1;
02020     }
02021 
02022 
02023     _fibers = giraffe_table_get(fibers);
02024     cx_assert(_fibers != NULL);
02025 
02026     _slitgeometry = giraffe_table_get(slitgeometry);
02027     cx_assert(_slitgeometry != NULL);
02028 
02029     if (cpl_table_get_nrow(_fibers) != cpl_table_get_nrow(_slitgeometry)) {
02030         return 2;
02031     }
02032 
02033 
02034     /*
02035      * Create grating setup
02036      */
02037 
02038     setup = giraffe_grating_create(extraction->spectra, grating);
02039 
02040     if (setup == NULL) {
02041         return 3;
02042     }
02043 
02044 
02045     /*
02046      * Set up the spectrum rebinning. Make sure that only the spectra are
02047      * rebinned.
02048      */
02049 
02050     _extraction = giraffe_extraction_new();
02051 
02052     _extraction->spectra = extraction->spectra;
02053     _extraction->error = NULL;
02054 
02055 
02056     slit = giraffe_table_duplicate(slitgeometry);
02057 
02058     for (i = 0; i < config->repeat; i++) {
02059 
02060         cxint row = 0;
02061         cxint fps_rvmin = 0;
02062         cxint fps_rvmax = 0;
02063 
02064         cxdouble rvmin = 0.;
02065         cxdouble rvmax = 0.;
02066         cxdouble rvmean = 0.;
02067 
02068         GiRebinning* rebinning = giraffe_rebinning_new();
02069 
02070         GiRebinConfig rebin_config = {
02071             GIREBIN_METHOD_LINEAR,
02072             TRUE,
02073             0.005,
02074             GIREBIN_SCALE_LINEAR,
02075             0,
02076             GIREBIN_RANGE_SETUP
02077         };
02078 
02079 
02080         status = giraffe_rebin_spectra(rebinning, _extraction, fibers,
02081                                        localization, grating, slit,
02082                                        wlsolution, &rebin_config);
02083 
02084         if (status != 0) {
02085             giraffe_table_delete(slit);
02086 
02087             giraffe_extraction_delete(_extraction);
02088             giraffe_rebinning_destroy(rebinning);
02089 
02090             giraffe_grating_delete(setup);
02091 
02092             return 4;
02093         }
02094 
02095         offsets = _giraffe_compute_slitgeometry(rebinning->spectra, mask,
02096                                                 slit, setup, config);
02097 
02098         if (offsets == NULL) {
02099             giraffe_table_delete(slit);
02100 
02101             giraffe_extraction_delete(_extraction);
02102             giraffe_rebinning_destroy(rebinning);
02103 
02104             giraffe_grating_delete(setup);
02105 
02106             return 5;
02107         }
02108 
02109 
02110         /*
02111          * Build new slit geometry table
02112          */
02113 
02114         cx_assert(cpl_table_get_nrow(offsets) == cpl_table_get_nrow(_fibers));
02115 
02116         giraffe_table_delete(slit);
02117         slit = _giraffe_slitgeometry_table(offsets, rebinning->spectra,
02118                                            fibers, slitgeometry, config);
02119 
02120         if (slit == NULL) {
02121 
02122             cpl_table_delete(offsets);
02123 
02124             giraffe_extraction_delete(_extraction);
02125             giraffe_rebinning_destroy(rebinning);
02126 
02127             giraffe_grating_delete(setup);
02128 
02129             return 6;
02130         }
02131 
02132         cpl_table_delete(offsets);
02133         offsets = NULL;
02134 
02135         rvmin = cpl_table_get_column_min(giraffe_table_get(slit), "RV");
02136         cpl_table_get_column_minpos(giraffe_table_get(slit), "RV", &row);
02137         fps_rvmin = cpl_table_get_int(giraffe_table_get(slit), "FPS",
02138                                       row, NULL);
02139 
02140         rvmax = cpl_table_get_column_max(giraffe_table_get(slit), "RV");
02141         cpl_table_get_column_maxpos(giraffe_table_get(slit), "RV", &row);
02142         fps_rvmax = cpl_table_get_int(giraffe_table_get(slit), "FPS",
02143                                       row, NULL);
02144 
02145         rvmean = cpl_table_get_column_mean(giraffe_table_get(slit), "RV");
02146 
02147         cpl_msg_info(fctid, "Iteration %d: Fiber offsets [km/s]: minimum = "
02148                      "%.6e (fps %d), maximum = %.6e (fps %d), mean = %.6e",
02149                      i + 1, rvmin, fps_rvmin, rvmax, fps_rvmax, rvmean);
02150 
02151         giraffe_rebinning_destroy(rebinning);
02152         rebinning = NULL;
02153 
02154     }
02155 
02156     giraffe_extraction_delete(_extraction);
02157     giraffe_grating_delete(setup);
02158 
02159     cx_assert(slit != NULL);
02160 
02161     giraffe_table_set_properties(result, giraffe_table_get_properties(slit));
02162     giraffe_table_set(result, giraffe_table_get(slit));
02163 
02164     giraffe_table_delete(slit);
02165 
02166     return 0;
02167 
02168 }
02169 
02170 
02195 cxint
02196 giraffe_compute_offsets(GiTable* fibers, const GiRebinning* rebinning,
02197                         const GiTable* grating, const GiTable* mask,
02198                         const GiSGCalConfig* config)
02199 {
02200 
02201     cxint status = 0;
02202     cxint nfibers = 0;
02203     cxint fiber = 0;
02204     cxint peak = 0;
02205     cxint fps = 0;
02206     cxint fps0 = 0;
02207     cxint fps1 = 0;
02208 
02209     cxdouble dwf0 = 0.;
02210 
02211     cpl_table* _fibers = NULL;
02212     cpl_table* peakdata = NULL;
02213 
02214     GiGrating* _grating = NULL;
02215 
02216     GiSGSetup setup;
02217 
02218 
02219     if ((rebinning == NULL) || (rebinning->spectra == NULL)) {
02220         return -1;
02221     }
02222 
02223     if (fibers == NULL) {
02224         return -2;
02225     }
02226 
02227     if (grating == NULL) {
02228         return -3;
02229     }
02230 
02231     if (mask == NULL) {
02232         return -4;
02233     }
02234 
02235     if (config == NULL) {
02236         return -5;
02237     }
02238 
02239 
02240     _fibers = giraffe_table_get(fibers);
02241     cx_assert(_fibers != NULL);
02242 
02243 
02244     /*
02245      * Extract the  SIWC fibers from the fiber table. The simultaneous
02246      * calibration spectra are indicated by a -1 as retractor position.
02247      */
02248 
02249     cpl_table_unselect_all(_fibers);
02250     cpl_table_or_selected_int(_fibers, "RP", CPL_EQUAL_TO, -1);
02251 
02252     _fibers = cpl_table_extract_selected(_fibers);
02253 
02254     if (_fibers == NULL) {
02255         return 1;
02256     }
02257 
02258 
02259     /*
02260      * Create grating setup
02261      */
02262 
02263     _grating = giraffe_grating_create(rebinning->spectra, grating);
02264 
02265     if (_grating == NULL) {
02266         cpl_table_delete(_fibers);
02267         return 2;
02268     }
02269 
02270     /*
02271      * Get setup information from the rebinned spectra frame
02272      */
02273 
02274     status = _giraffe_create_setup(&setup, rebinning->spectra);
02275 
02276     if (status != 0) {
02277         cpl_table_delete(_fibers);
02278         return 3;
02279     }
02280 
02281 
02282     /*
02283      * Compute the wavelength shifts between the reference mask and
02284      * the arc-lamp spectra, from the position of the cross-correlation
02285      * peak.
02286      *
02287      * Note that either a fiber, or a slitgeometry table may be passed to
02288      * _giraffe_compute_offsets(). Actually any table providing the
02289      * columns "INDEX" and "FPS", describing the pixel column of each
02290      * spectrum in the input image and the fiber position within the
02291      * pseudo slit.
02292      */
02293 
02294     peakdata = _giraffe_compute_offsets(rebinning->spectra, mask, _fibers,
02295                                         _grating, &setup, config);
02296 
02297     if (peakdata == NULL) {
02298         cpl_table_delete(_fibers);
02299         return 4;
02300     }
02301 
02302 
02303     /*
02304      * Compute the offsets of the fibers in the pseudo-slit (i.e. in the
02305      * focal plane.
02306      */
02307 
02308     status = _giraffe_compute_fiber_offsets(peakdata, _grating, &setup);
02309 
02310     if (status != 0) {
02311         cpl_table_delete(peakdata);
02312         cpl_table_delete(_fibers);
02313 
02314         return 5;
02315     }
02316 
02317     cpl_table_delete(_fibers);
02318 
02319     /*
02320      * Interpolate the wavelength offsets between the position of 2 adjacent
02321      * simultaneous calibration fibers.
02322      *
02323      * Note: The while loops traversing the fiber table _fiber just check
02324      *       whether the two fiber positions are equal or not. In that way
02325      *       it is possible to process Argus data, where the order of the
02326      *       fibers is reversed, without sorting the fiber and peakdata
02327      *       tables, or using dedicated code for Argus observations.
02328      */
02329 
02330     _fibers = giraffe_table_get(fibers);
02331 
02332     giraffe_error_push();
02333 
02334     cpl_table_new_column(_fibers, "WLRES", CPL_TYPE_DOUBLE);
02335     cpl_table_set_column_unit(_fibers, "WLRES", "nm");
02336 
02337     if (cpl_error_get_code() != CPL_ERROR_NONE) {
02338         cpl_table_delete(peakdata);
02339         return 6;
02340     }
02341 
02342     giraffe_error_pop();
02343 
02344 
02345     giraffe_error_push();
02346 
02347     fps0 = cpl_table_get_int(peakdata, "FPS", 0, NULL);
02348     dwf0 = cpl_table_get_double(peakdata, "DWF", 0, NULL);
02349 
02350     nfibers = cpl_table_get_nrow(_fibers);
02351 
02352     fps = cpl_table_get_int(_fibers, "FPS", 0, NULL);
02353 
02354     while (fps != fps0) {
02355 
02356         cpl_table_set_double(_fibers, "WLRES", fiber, dwf0);
02357 
02358         ++fiber;
02359         fps = cpl_table_get_int(_fibers, "FPS", fiber, NULL);
02360 
02361     }
02362 
02363     for (peak = 1; peak < cpl_table_get_nrow(peakdata); ++peak) {
02364 
02365         cxdouble dwf1 = cpl_table_get_double(peakdata, "DWF", peak, NULL);
02366         cxdouble slope = 0.;
02367 
02368 
02369         fps1 = cpl_table_get_int(peakdata, "FPS", peak, NULL);
02370 
02371         slope = (dwf1 - dwf0) / ((cxdouble)(fps1 - fps0));
02372 
02373         while (fps != fps1) {
02374 
02375             cpl_table_set_double(_fibers, "WLRES", fiber,
02376                                  slope * (fps - fps0) + dwf0);
02377 
02378             ++fiber;
02379             fps = cpl_table_get_int(_fibers, "FPS", fiber, NULL);
02380         }
02381 
02382         fps0 = fps1;
02383         dwf0 = dwf1;
02384 
02385     }
02386 
02387     fps1 = cpl_table_get_int(_fibers, "FPS", nfibers - 1, NULL);
02388 
02389     while (fps != fps1) {
02390 
02391         cpl_table_set_double(_fibers, "WLRES", fiber, dwf0);
02392 
02393         ++fiber;
02394         fps = cpl_table_get_int(_fibers, "FPS", fiber, NULL);
02395 
02396     }
02397 
02398     cpl_table_set_double(_fibers, "WLRES", fiber, dwf0);
02399 
02400     cx_assert(fiber == nfibers - 1);
02401 
02402     if (cpl_error_get_code() != CPL_ERROR_NONE) {
02403         cpl_table_delete(peakdata);
02404         return 7;
02405     }
02406 
02407     giraffe_error_pop();
02408 
02409     return 0;
02410 
02411 }
02412 
02413 
02426 GiSGCalConfig*
02427 giraffe_sgcalibration_config_create(cpl_parameterlist* list)
02428 {
02429 
02430     const cxchar* s = NULL;
02431 
02432     cpl_parameter* p = NULL;
02433 
02434     GiSGCalConfig* config = NULL;
02435 
02436 
02437     if (!list) {
02438         return NULL;
02439     }
02440 
02441     config = cx_calloc(1, sizeof *config);
02442 
02443     config->cc_wdomain = FALSE;
02444 
02445     p = cpl_parameterlist_find(list, "giraffe.sgcalibration.iterations");
02446     config->repeat = cpl_parameter_get_int(p);
02447 
02448     p = cpl_parameterlist_find(list, "giraffe.sgcalibration.zmax");
02449     config->zmax = cpl_parameter_get_double(p);
02450 
02451     p = cpl_parameterlist_find(list, "giraffe.sgcalibration.cc.step");
02452     config->cc_step = cpl_parameter_get_double(p);
02453 
02454     p = cpl_parameterlist_find(list, "giraffe.sgcalibration.cc.domain");
02455     s = cpl_parameter_get_string(p);
02456 
02457     if (s) {
02458 
02459         cxchar** values = cx_strsplit(s, ",", 3);
02460 
02461         if (values == NULL) {
02462 
02463             giraffe_sgcalibration_config_destroy(config);
02464             return NULL;
02465 
02466         }
02467         else {
02468 
02469             cxchar* last;
02470 
02471             cxdouble lower = 0.;
02472             cxdouble upper = 0.;
02473 
02474 
02475             lower = strtod(values[0], &last);
02476 
02477             if (*last != '\0') {
02478 
02479                 cx_strfreev(values);
02480                 giraffe_sgcalibration_config_destroy(config);
02481 
02482                 return NULL;
02483 
02484             }
02485 
02486             lower = lower >= 0. ? lower : 0.;
02487 
02488 
02489             if (values[1] != NULL) {
02490 
02491                 upper = strtod(values[1], &last);
02492 
02493                 if (*last != '\0') {
02494 
02495                     cx_strfreev(values);
02496                     giraffe_sgcalibration_config_destroy(config);
02497 
02498                     return NULL;
02499 
02500                 }
02501 
02502                 upper = upper > lower ? upper : 0.;
02503 
02504             }
02505 
02506             config->cc_domain = giraffe_range_create(lower, upper);
02507             cx_assert(config->cc_domain != NULL);
02508 
02509         }
02510 
02511         cx_strfreev(values);
02512         values = NULL;
02513 
02514     }
02515 
02516 
02517     p = cpl_parameterlist_find(list, "giraffe.sgcalibration.rv.limits");
02518     s = cpl_parameter_get_string(p);
02519 
02520     if (s) {
02521 
02522         cxchar** values = cx_strsplit(s, ",", 3);
02523 
02524         if (values == NULL) {
02525 
02526             giraffe_sgcalibration_config_destroy(config);
02527             return NULL;
02528 
02529         }
02530         else {
02531 
02532             cxchar* last;
02533 
02534             cxdouble lower = 0.;
02535             cxdouble upper = 0.;
02536 
02537 
02538             lower = strtod(values[0], &last);
02539 
02540             if (*last != '\0') {
02541 
02542                 cx_strfreev(values);
02543                 giraffe_sgcalibration_config_destroy(config);
02544 
02545                 return NULL;
02546 
02547             }
02548 
02549             if (values[1] != NULL) {
02550 
02551                 upper = strtod(values[1], &last);
02552 
02553                 if (*last != '\0') {
02554 
02555                     cx_strfreev(values);
02556                     giraffe_sgcalibration_config_destroy(config);
02557 
02558                     return NULL;
02559 
02560                 }
02561 
02562                 if (lower > 0 || upper < lower) {
02563 
02564                     cx_strfreev(values);
02565                     giraffe_sgcalibration_config_destroy(config);
02566 
02567                     return NULL;
02568 
02569                 }
02570 
02571             }
02572             else {
02573 
02574                 if (lower > 0.) {
02575 
02576                     upper = lower;
02577                     lower = -upper;
02578 
02579                 }
02580                 else {
02581 
02582                     upper = -lower;
02583 
02584                 }
02585 
02586             }
02587 
02588             cx_assert(lower <= 0);
02589             cx_assert(lower < upper);
02590 
02591             config->rv_limits = giraffe_range_create(lower, upper);
02592             cx_assert(config->rv_limits != NULL);
02593 
02594         }
02595 
02596         cx_strfreev(values);
02597         values = NULL;
02598 
02599     }
02600 
02601 
02602     p = cpl_parameterlist_find(list, "giraffe.sgcalibration.rv.iterations");
02603     config->rv_niter = cpl_parameter_get_int(p);
02604 
02605     p = cpl_parameterlist_find(list, "giraffe.sgcalibration.rv.wfactor");
02606     config->rv_wfactor = cpl_parameter_get_double(p);
02607 
02608     p = cpl_parameterlist_find(list, "giraffe.sgcalibration.peak.iterations");
02609     config->pf_niter = cpl_parameter_get_int(p);
02610 
02611     p = cpl_parameterlist_find(list, "giraffe.sgcalibration.peak.tests");
02612     config->pf_ntest = cpl_parameter_get_int(p);
02613 
02614     p = cpl_parameterlist_find(list, "giraffe.sgcalibration.peak.dchisquare");
02615     config->pf_dchisq = cpl_parameter_get_double(p);
02616 
02617     return config;
02618 
02619 }
02620 
02621 
02636 void
02637 giraffe_sgcalibration_config_destroy(GiSGCalConfig* config)
02638 {
02639 
02640     if (config) {
02641         if (config->cc_domain) {
02642             giraffe_range_delete(config->cc_domain);
02643         }
02644 
02645         if (config->rv_limits) {
02646             giraffe_range_delete(config->rv_limits);
02647         }
02648 
02649         cx_free(config);
02650     }
02651 
02652     return;
02653 }
02654 
02655 
02667 void
02668 giraffe_sgcalibration_config_add(cpl_parameterlist* list)
02669 {
02670 
02671     cpl_parameter* p;
02672 
02673 
02674     if (!list) {
02675         return;
02676     }
02677 
02678     p = cpl_parameter_new_value("giraffe.sgcalibration.iterations",
02679                                 CPL_TYPE_INT,
02680                                 "Slit geometry calibration maximum number "
02681                                 "of iterations.",
02682                                 "giraffe.sgcalibration",
02683                                 1);
02684     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-cniter");
02685     cpl_parameterlist_append(list, p);
02686 
02687 
02688     p = cpl_parameter_new_value("giraffe.sgcalibration.zmax",
02689                                 CPL_TYPE_DOUBLE,
02690                                 "Maximum allowed pixel value. To be "
02691                                 "effective it must be larger than 0.",
02692                                 "giraffe.sgcalibration",
02693                                 10000.);
02694     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-zmax");
02695     cpl_parameterlist_append(list, p);
02696 
02697 
02698     p = cpl_parameter_new_value("giraffe.sgcalibration.cc.step",
02699                                 CPL_TYPE_DOUBLE,
02700                                 "Cross-correlation step.",
02701                                 "giraffe.sgcalibration",
02702                                 -0.005);
02703     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-cstep");
02704     cpl_parameterlist_append(list, p);
02705 
02706 
02707     p = cpl_parameter_new_value("giraffe.sgcalibration.cc.domain",
02708                                 CPL_TYPE_STRING,
02709                                 "Restricts the cross-correlation to the "
02710                                 "given domain.",
02711                                 "giraffe.sgcalibration",
02712                                 "0.,0.");
02713     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-cdomain");
02714     cpl_parameterlist_append(list, p);
02715 
02716 
02717     p = cpl_parameter_new_value("giraffe.sgcalibration.rv.limits",
02718                                 CPL_TYPE_STRING,
02719                                 "Delta RV limits of the cross-correlation "
02720                                 "window in km/s.",
02721                                 "giraffe.sgcalibration",
02722                                 "-200.,200.");
02723     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-rvlimits");
02724     cpl_parameterlist_append(list, p);
02725 
02726 
02727     p = cpl_parameter_new_value("giraffe.sgcalibration.rv.iterations",
02728                                 CPL_TYPE_INT,
02729                                 "Maximum number of iterations used for the "
02730                                 "RV determination.",
02731                                 "giraffe.sgcalibration",
02732                                 3);
02733     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-rvniter");
02734     cpl_parameterlist_append(list, p);
02735 
02736 
02737     p = cpl_parameter_new_value("giraffe.sgcalibration.rv.wfactor",
02738                                 CPL_TYPE_DOUBLE,
02739                                 "Data window width factor. The FWHM times "
02740                                 "this value determines the window width.",
02741                                 "giraffe.sgcalibration",
02742                                 1.5);
02743     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-rvwfactor");
02744     cpl_parameterlist_append(list, p);
02745 
02746 
02747     p = cpl_parameter_new_value("giraffe.sgcalibration.peak.iterations",
02748                                 CPL_TYPE_INT,
02749                                 "Peak model fit maximum number of "
02750                                 "iterations.",
02751                                 "giraffe.sgcalibration",
02752                                 50);
02753 
02754     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-pfniter");
02755     cpl_parameterlist_append(list, p);
02756 
02757 
02758     p = cpl_parameter_new_value("giraffe.sgcalibration.peak.tests",
02759                                 CPL_TYPE_INT,
02760                                 "Cross-correlation peak fit maximum number "
02761                                 "of tests",
02762                                 "giraffe.sgcalibration",
02763                                 7);
02764 
02765     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-pfntest");
02766     cpl_parameterlist_append(list, p);
02767 
02768 
02769     p = cpl_parameter_new_value("giraffe.sgcalibration.peak.dchisquare",
02770                                 CPL_TYPE_DOUBLE,
02771                                 "Cross-correlation peak fit minimum "
02772                                 "chi-square difference.",
02773                                 "giraffe.sgcalibration",
02774                                 0.0001);
02775 
02776     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "scal-pfdchisq");
02777     cpl_parameterlist_append(list, p);
02778 
02779     return;
02780 
02781 }

This file is part of the GIRAFFE Pipeline Reference Manual 2.8.8.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Fri Mar 4 10:50:28 2011 by doxygen 1.6.3 written by Dimitri van Heesch, © 1997-2004