GIRAFFE Pipeline Reference Manual

gisgcalibration.c

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

This file is part of the GIRAFFE Pipeline Reference Manual 2.9.0.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Thu Jan 26 14:20:28 2012 by doxygen 1.6.3 written by Dimitri van Heesch, © 1997-2004