GIRAFFE Pipeline Reference Manual

gilocalize.c

00001 /* $Id: gilocalize.c,v 1.50 2009/02/26 10:57:40 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: 2009/02/26 10:57:40 $
00024  * $Revision: 1.50 $
00025  * $Name: giraffe-2_8 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #  include <config.h>
00030 #endif
00031 
00032 #include <string.h>
00033 #include <math.h>
00034 
00035 #include <cxstring.h>
00036 #include <cxmemory.h>
00037 
00038 #include <cpl_image.h>
00039 #include <cpl_vector.h>
00040 #include <cpl_matrix.h>
00041 #include <cpl_mask.h>
00042 #include <cpl_parameterlist.h>
00043 #include <cpl_msg.h>
00044 
00045 #include "gimacros.h"
00046 #include "gialias.h"
00047 #include "giarray.h"
00048 #include "giimage.h"
00049 #include "gitable.h"
00050 #include "gimatrix.h"
00051 #include "giarray.h"
00052 #include "gimask.h"
00053 #include "gimath.h"
00054 #include "gimessages.h"
00055 #include "giutils.h"
00056 #include "gilocalize.h"
00057 #include "gidebug.h"
00058 
00059 
00060 
00069 /* FIXME: Is this really needed? It really seems questionable! (RP) */
00070 
00071 enum GiLocalizeMethod {
00072     GILOCALIZE_HALF_WIDTH,
00073     GILOCALIZE_BARYCENTER
00074 };
00075 
00076 typedef enum GiLocalizeMethod GiLocalizeMethod;
00077 
00078 
00079 /*
00080  * Main task identifier. Used for terminal output from internal functions.
00081  */
00082 
00083 static const cxchar *_task = "giraffe_localize_spectra";
00084 
00085 
00086 /*
00087  * @brief
00088  *   Check whether a pixel in a detection mask belongs to a spectrum.
00089  *
00090  * @param pixels  The pixel buffer.
00091  * @param xsize   The size of the pixel buffer along x.
00092  * @param ysize   The size of the pixel buffer along y.
00093  * @param xpos    x-position of the pixel to check.
00094  * @param ypos    y-position of the pixel to check.
00095  * @param xwidth  Half width of the pixel neighbourhood along x.
00096  * @param ywidth  Half width of the pixel neighbourhood along y.
00097  * @param count   The number of required, non-zero mask pixels.
00098  *
00099  * @return The function returns 1 if the pixel at (@em xpos, @em ypos) is
00100  *   found to be valid, or 0 otherwise.
00101  *
00102  * The function checks whether the pixel at position (@em xpos, @em ypos) in
00103  * the detection mask's pixel buffer @em pixels belongs to a spectrum. It
00104  * expects in input a pixel buffer of a detection mask, i.e. the pixel values
00105  * must be non-zero only at pixel positions associated to a positive
00106  * detection.
00107  *
00108  * A pixel is considered to be valid if, at least, @em count non-zero pixels
00109  * are found in the neighborhood of the pixel position (@em xpos, @em ypos).
00110  * The neighborhood is specified by @em xsize and @em ysize the number of
00111  * pixels to be checked on both sides of the pixel along the x and y axis.
00112  * The pixel row given by @em ypos which contains the pixel to check is
00113  * not considered when the pixel neighbourhood is checked. Assuming that
00114  * the spectra extend along the y-axis only the neighbours along the
00115  * dispersion axis are taken into account.
00116  */
00117 
00118 inline static cxbool
00119 _giraffe_validate_pixel(cxint *pixels, cxint xsize, cxint ysize,
00120                         cxint xpos, cxint ypos, cxint xwidth, cxint ywidth,
00121                         cxsize count)
00122 {
00123 
00124     cxint i;
00125     cxint xstart = xpos - xwidth;
00126     cxint ystart = ypos - ywidth;
00127     cxint xend = xpos + xwidth;
00128     cxint yend = ypos + ywidth;
00129 
00130     cxsize _count = 0;
00131 
00132 
00133 
00134     /*
00135      * Clip start and end positions to pixel buffer boundaries
00136      */
00137 
00138     xstart = CX_MAX(0, xstart);
00139     ystart = CX_MAX(0, ystart);
00140 
00141     xend = CX_MIN(xsize - 1, xend);
00142     yend = CX_MIN(ysize - 1, yend);
00143 
00144     xwidth = CX_MAX(xwidth,1 );
00145     ywidth = CX_MAX(ywidth,1 );
00146 
00147 
00148     /*
00149      * Search for count non-zero pixel values in the pixel region
00150      * defined by the rectangle (xstart, ystart, xend, yend).
00151      */
00152 
00153     for (i = ystart; i <= yend; i++) {
00154 
00155         cxint j;
00156         cxint row;
00157 
00158 
00159         /*
00160          * Skip the pixel row containing the pixel to check. Since the pixel
00161          * should be checked whether it belongs to a spectrum (extending
00162          * along the y-axis) we only check the adjacent pixel rows on
00163          * both sides.
00164          */
00165 
00166         if (i == ypos) {
00167             continue;
00168         }
00169 
00170         row = i * xsize;
00171 
00172         for (j = xstart; j <= xend; j++) {
00173             if (pixels[row + j]) {
00174                 ++_count;
00175             }
00176 
00177             if (_count >= count) {
00178                 return 1;
00179             }
00180         }
00181 
00182     }
00183 
00184     return 0;
00185 
00186 }
00187 
00188 
00189 /*
00190  * @brief
00191  *   Polynomial fit of raw spectrum region border.
00192  *
00193  * @param mborder   Y of detected borders
00194  * @param mbase     Full Chebyshev base
00195  * @param mxok      Good abcissa
00196  * @param nspectra  Spectrum number
00197  * @param sigma     Sigma clipping: sigma threshold level
00198  * @param niter     Sigma clipping: number of iterations
00199  * @param mfrac     Sigma clipping: minimum fraction of points accepted/total
00200  * @param mcoeff    Computed Chebyshev coefficients
00201  *
00202  * @return Matrix with the polynomial fit of @em mborder.
00203  *
00204  * Computes Chebyshev polynomial fit of @em mborder[:,nspectra].
00205  * The order of the polynomial fit is given by the Chebyshev base
00206  * @em mbase 1st dimension. The matrices @em mxtmp and @em mcoeff
00207  * are pre-allocated. The returned matrix @em mfit must be freed
00208  * using @b cpl_matrix_delete().
00209  *
00210  * @code
00211  *   mfit = _giraffe_fit_border(mborder, mbase, mxtmp, mxok, nspectra,
00212  *                               sigma, niter, mfrac, mcoeff);
00213  * @endcode
00214  */
00215 
00216 inline static cpl_matrix*
00217 _giraffe_fit_border(cpl_matrix* mborder, cpl_matrix* mbase,
00218                     cpl_matrix* mxok, cxint nspectra, cxdouble sigma,
00219                     cxint niter, cxdouble mfrac, cpl_matrix* mcoeff)
00220 {
00221 
00222     const cxchar* const fctid = "_giraffe_fit_border";
00223 
00224     register cxint x = 0;
00225     register cxint naccept = 0;
00226     register cxint ntotal = 0;
00227     register cxint iteration = 0;
00228     register cxint nx = cpl_matrix_get_ncol(mbase);
00229     register cxint yorder = cpl_matrix_get_nrow(mbase);
00230     register cxint nxok = cpl_matrix_get_nrow(mxok);
00231 
00232     register cxdouble ratio = 1.0;
00233 
00234     cpl_matrix* mtmp = NULL;
00235     cpl_matrix* yraw = NULL;
00236     cpl_matrix* ydiff = NULL;
00237     cpl_matrix* mfit = NULL;
00238     cpl_matrix* coeffs = NULL;
00239 
00240 
00241 
00242     if (nxok < yorder) {
00243         cpl_error_set(fctid, CPL_ERROR_INCOMPATIBLE_INPUT);
00244 
00245         GIDEBUG(gi_warning("%s: not enough points mxok[%d] for %d order fit",
00246                            fctid, nxok, yorder));
00247 
00248         return NULL;
00249     }
00250 
00251 
00252     /*
00253      * Initialize X,Y to be fit
00254      */
00255 
00256     yraw = cpl_matrix_new(1, nxok);
00257     ydiff = cpl_matrix_new(nxok, 1);
00258 
00259     mtmp = cpl_matrix_duplicate(mxok);
00260 
00261     /*
00262      * For each good x bin
00263      */
00264 
00265     for (x = 0; x < nxok; x++) {
00266         cxdouble data = cpl_matrix_get(mborder, x, nspectra);
00267         cpl_matrix_set(yraw, 0, x, data);
00268     }
00269 
00270 
00271     /*
00272      * Here comes the sigma clipping
00273      */
00274 
00275     ntotal = nxok;
00276     naccept = ntotal;
00277 
00278     while (naccept > 0 && iteration < niter && ratio > mfrac) {
00279 
00280         register cxint k = 0;
00281         register cxint l = 0;
00282 
00283         register cxdouble ysigma = 0.;
00284 
00285         cpl_matrix* rawbase = giraffe_chebyshev_base1d(0., nx, yorder, mtmp);
00286         cx_assert(rawbase != NULL);
00287 
00288         if (coeffs != NULL) {
00289             cpl_matrix_delete(coeffs);
00290         }
00291 
00292         coeffs = giraffe_matrix_leastsq(rawbase, yraw);
00293         if (coeffs == NULL) {
00294             gi_warning("%s: error in giraffe_matrix_leastsq(), spectrum %d",
00295                        fctid, nspectra);
00296             break;
00297         }
00298 
00299         cpl_matrix_delete(rawbase);
00300         rawbase = NULL;
00301 
00302         if (mfit != NULL) {
00303             cpl_matrix_delete(mfit);
00304         }
00305 
00306         mfit = cpl_matrix_product_create(coeffs, mbase);
00307 
00308         for (x = 0; x < cpl_matrix_get_nrow(ydiff); x++) {
00309 
00310             cxint xok = (cxint) cpl_matrix_get(mtmp, x, 0);
00311 
00312             cxdouble diff =
00313                 cpl_matrix_get(yraw, 0, x) - cpl_matrix_get(mfit, 0, xok);
00314 
00315 
00316             cpl_matrix_set(ydiff, x , 0, diff);
00317 
00318         }
00319 
00320         ysigma = sigma * giraffe_matrix_sigma_mean(ydiff, 0.);
00321 
00322 
00323         /*
00324          * Reset sizes
00325          */
00326 
00327         k = 0;
00328         for (l = 0; l < cpl_matrix_get_nrow(ydiff); l++) {
00329 
00330             if (fabs(cpl_matrix_get(ydiff, l, 0)) <= ysigma) {
00331 
00332                 cxint xok = cpl_matrix_get(mtmp, l, 0);
00333                 cxdouble data = cpl_matrix_get(yraw, 0, l);
00334 
00335                 cpl_matrix_set(mtmp, k, 0, xok);
00336                 cpl_matrix_set(yraw, 0, k, data);
00337 
00338                 ++k;
00339             }
00340 
00341         }
00342 
00343 
00344         /*
00345          * No new points rejected, no more iterations
00346          */
00347 
00348         if (k == naccept) {
00349             break;
00350         }
00351 
00352 
00353         /*
00354          * Merry-go-round once more
00355          */
00356 
00357         naccept = k;
00358         ratio = (cxdouble) naccept / (cxdouble) ntotal;
00359 
00360         GIDEBUG(gi_message("Iteration %d: Sigma %f, accepted bins: %d, "
00361                            "rejected %d\n", iteration, ysigma, naccept,
00362                            ntotal - naccept));
00363 
00364         /*
00365          * Extract the new clipped matrices
00366          */
00367 
00368         cpl_matrix_resize(mtmp, 0,
00369                           naccept - cpl_matrix_get_nrow(mtmp), 0, 0);
00370         cpl_matrix_resize(yraw, 0,
00371                           0, 0, naccept - cpl_matrix_get_ncol(yraw));
00372         cpl_matrix_resize(ydiff, 0,
00373                           naccept - cpl_matrix_get_nrow(ydiff), 0, 0);
00374 
00375         iteration++;
00376     }
00377 
00378     if (coeffs != NULL) {
00379         register cxint l;
00380 
00381         for (l = 0; l < cpl_matrix_get_nrow(mcoeff); l++) {
00382             cpl_matrix_set(mcoeff, l, 0, cpl_matrix_get(coeffs, 0, l));
00383         }
00384     }
00385 
00386 
00387     /*
00388      * Cleanup
00389      */
00390 
00391     cpl_matrix_delete(coeffs);
00392     cpl_matrix_delete(ydiff);
00393     cpl_matrix_delete(yraw);
00394     cpl_matrix_delete(mtmp);
00395 
00396     return mfit;
00397 
00398 }
00399 
00400 
00401 /*
00402  * @brief
00403  *   Computes initial raw localization borders.
00404  *
00405  * @param image     The image to process [nx,ny]
00406  * @param nspectra  Number of expected spectra
00407  * @param noise     Spectra/noise threshold
00408  * @param config    Mask parameters.
00409  * @param ndetect   Number of spectra detected.
00410  * @param mxok      Matrix[nx] of @em nxok good x bins.
00411  * @param myup      Matrix[nx,nspectra] of @em nxok upper Y borders.
00412  * @param mylo      Matrix[nx,nspectra] of @em nxok lower Y borders.
00413  *
00414  * @return The function returns the number of good X bins on success, or
00415  *   a negative value on failure.
00416  *
00417  * Starting from @em config.start bin of the CCD, the function tries to
00418  * detect spectrum pixels pattern:
00419  *
00420  *     '0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 0 0'
00421  *
00422  * for each X bin and sets @em mylo[nx,ns] and @em myup[nx,ns] to Y values
00423  * of first '1' and last '1' of each '1' group. '0' and '1' are determined
00424  * by a @em noise value.
00425  *
00426  * Each group of '1' is supposed to be a spectrum. @em nspectra is the
00427  * expected number of spectra defined by the current instrument setup.
00428  * if X bin is ok @em mxok, @em mylo and @em myup matrices are updated
00429  * otherwise go and try the next X bin until @em config.tries is reached.
00430  *
00431  * @em mxok[nx], @em mylo[nx,ns] and @em myup[nx,ns] are pre-allocated
00432  * matrices.
00433  */
00434 
00435 inline static cxint
00436 _giraffe_build_raw_mask(cpl_image *raw, cpl_image *bpixel, cxint nspectra,
00437                         cxdouble noise, GiMaskParameters *config,
00438                         cxint *ndetect, cpl_matrix *mxok, cpl_matrix *myup,
00439                         cpl_matrix *mylo)
00440 {
00441 
00442     register cxint x = 0;
00443     register cxint y = 0;
00444     register cxint xretry = 0;
00445     register cxint xok = 0;
00446 
00447     cxint ny = 0;
00448     cxint nrows = 0;
00449     cxint ncols = 0;
00450     cxint *yabove = NULL;
00451     cxint *ybelow = NULL;
00452     cxint *good_pixels = NULL;
00453     cxint ywidth = config->ywidth > 1 ? config->ywidth : 2;
00454     cxint ckwidth = config->ckdata.width;
00455     cxint ckheight = config->ckdata.height;
00456     cxint ckcount = config->ckdata.count;
00457 
00458 
00459     cxdouble *pixels = NULL;
00460 
00461     cpl_mask* med = NULL;
00462 
00463     cpl_image *img = NULL;
00464 
00465 
00466     med = cpl_mask_new(1, 9);
00467     if (med != NULL) {
00468 
00469         cxint i = 0;
00470 
00471         for (i = 0; i < cpl_mask_get_size_x(med); ++i) {
00472             cpl_mask_set(med, 1, i + 1, CPL_BINARY_1);
00473         }
00474 
00475         img = cpl_image_new(cpl_image_get_size_x(raw),
00476                             cpl_image_get_size_y(raw),
00477                             cpl_image_get_type(raw));
00478         cpl_image_filter_mask(img, raw, med, CPL_FILTER_MEDIAN,
00479                               CPL_BORDER_FILTER);
00480     }
00481     else {
00482         img = raw;
00483     }
00484 
00485     cpl_mask_delete(med);
00486 
00487 
00488 
00489     *ndetect = 0;
00490 
00491     cpl_msg_info(_task, "Generating mask (%d spectra expected) ...",
00492                  nspectra);
00493 
00494     GIDEBUG(gi_message("noise = %g start = %d tries = %d xbin = %d "
00495                        "ywidth = %d", noise, config->start, config->retry,
00496                        config->xbin, ywidth));
00497 
00498     pixels = cpl_image_get_data_double(img);
00499 
00500     nrows = cpl_image_get_size_y(img);
00501     ncols = cpl_image_get_size_x(img);
00502 
00503     // TODO: Verify test code performance
00504 #if 0
00505     cxdouble sigma = 2.;
00506     cxdouble ssqr = sigma * sigma;
00507 
00508     cxint xr = 2;
00509     cxint yr = 2;
00510 
00511     cpl_matrix* kern = cpl_matrix_new(2 * xr + 1, 2 * yr + 1);
00512 
00513     for (i = -xr; i <= xr; ++i) {
00514 
00515         cxint j = 0;
00516 
00517         for (j = -yr; j <= yr; ++j) {
00518 
00519             cxdouble rsqr = i * i + j * j;
00520             cxdouble h = (rsqr / ssqr - 1.) * exp(-rsqr / (2. * ssqr));
00521 
00522             cpl_matrix_set(kern, i + xr, j + yr, h);
00523         }
00524 
00525     }
00526 
00527     cpl_image* lod = cpl_image_filter_linear(raw, kern);
00528     cpl_image_save(lod, "lod.fits", -32, 0, CPL_IO_DEFAULT);
00529     cpl_image_delete(lod);
00530     cpl_matrix_delete(kern);
00531 #endif
00532 
00533 #if 0
00534 
00535     cpl_matrix* h1 = cpl_matrix_new(3, 3);
00536     cpl_matrix* h3 = cpl_matrix_new(3, 3);
00537 
00538     cpl_matrix_set(h1, 0, 0, 1);
00539     cpl_matrix_set(h1, 0, 1, 2);
00540     cpl_matrix_set(h1, 0, 2, 1);
00541 
00542     cpl_matrix_set(h1, 2, 0, -1);
00543     cpl_matrix_set(h1, 2, 1, -2);
00544     cpl_matrix_set(h1, 2, 2, -1);
00545 
00546     cpl_matrix_set(h3, 0, 0, -1);
00547     cpl_matrix_set(h3, 1, 0, -2);
00548     cpl_matrix_set(h3, 2, 0, -1);
00549 
00550     cpl_matrix_set(h3, 0, 2, 1);
00551     cpl_matrix_set(h3, 1, 2, 2);
00552     cpl_matrix_set(h3, 2, 2, 1);
00553 
00554     cpl_matrix* med = cpl_matrix_new(9, 1);
00555     cpl_matrix_fill(med, 1.);
00556 
00557     cpl_image* sraw = cpl_image_filter_median(raw, med);
00558     cpl_image* hz = cpl_image_filter_linear(sraw, h1);
00559     cpl_image* vt = cpl_image_filter_linear(sraw, h3);
00560     cpl_image* vt2 = cpl_image_filter_linear(vt, h3);
00561 
00562     cpl_image_save(sraw, "master_flat_smooth.fits", -32, 0, CPL_IO_DEFAULT);
00563     cpl_image_save(hz, "horizontal.fits", -32, 0, CPL_IO_DEFAULT);
00564     cpl_image_save(vt, "vertical.fits", -32, 0, CPL_IO_DEFAULT);
00565     cpl_image_save(vt2, "vertical2.fits", -32, 0, CPL_IO_DEFAULT);
00566 
00567 
00568     const cxdouble* _vt2 = cpl_image_get_data_double_const(vt2);
00569 
00570     cpl_image* center = cpl_image_new(ncols, nrows, CPL_TYPE_INT);
00571 
00572     cxint* _center = cpl_image_get_data_int(center);
00573     cxdouble* _buffer = cx_calloc(ncols, sizeof(cxdouble));
00574 
00575     cxint m = 0;
00576     cxint pos = 0;
00577 
00578     for (m = 0; m < nrows; ++m) {
00579 
00580         cxint n = 0;
00581         cxint k = 0;
00582         cxint iteration = 0;
00583 
00584         cxdouble low = -1;
00585         cxdouble avg = 0.;
00586         cxdouble rms = 0.;
00587 
00588 
00589         memcpy(_buffer, &_vt2[m * ncols], ncols * sizeof(cxdouble));
00590 
00591         avg = giraffe_array_mean(_buffer, ncols);
00592 
00593         for (n = 0; n < ncols; ++n) {
00594             rms += (_buffer[n] - avg) * (_buffer[n] - avg);
00595         }
00596         rms = sqrt(rms / (ncols - 1.) / ncols);
00597 
00598         // FIXME: Replace hardcoded threshold value
00599         avg -= 5. * rms;
00600 
00601         while (iteration < ncols && low < 0.) {
00602 
00603             cxdouble d2x = (avg < 0.) ? avg : 0.;
00604 
00605             for (n = 0; n < ncols; ++n) {
00606 
00607                 if (_buffer[n] < d2x) {
00608                     d2x = _buffer[n];
00609                     pos = n;
00610                 }
00611 
00612             }
00613 
00614             _center[m * ncols + pos] = 1;
00615             low = d2x;
00616 
00617             k = pos - 1;
00618 
00619             while (_buffer[k] > _buffer[k + 1] && k >= 0) {
00620                 _buffer[k] = 0.;
00621                 _center[m * ncols + pos] += 1;
00622                 --k;
00623             }
00624 
00625             k = pos + 1;
00626 
00627             while (_buffer[k] > _buffer[k - 1] && k < ncols) {
00628                 _buffer[k] = 0.;
00629                 _center[m * ncols + pos] += 1;
00630                 ++k;
00631             }
00632 
00633             _buffer[pos] = 0.;
00634 
00635             ++iteration;
00636 
00637         }
00638 
00639     }
00640 
00641     cx_free(_buffer);
00642 
00643     cpl_image_save(center, "mask.fits", -32, 0, CPL_IO_DEFAULT);
00644 
00645     cpl_image_delete(center);
00646     cpl_image_delete(vt2);
00647     cpl_image_delete(vt);
00648     cpl_image_delete(hz);
00649 #endif
00650     // << Test
00651 
00652     if (config->xbin > 1) {
00653 
00654         cxint nx = nrows;
00655 
00656         cxdouble* _pixels = NULL;
00657 
00658 
00659         nrows = (cxint) ceil(nrows / config->xbin);
00660         config->start = (cxint) ceil(config->start / config->xbin);
00661 
00662         _pixels = cx_calloc(ncols * nrows, sizeof(cxdouble));
00663 
00664         for (y = 0; y < ncols; ++y) {
00665 
00666             for (x = 0; x < nrows; ++x) {
00667 
00668                 register cxint xx = 0;
00669                 register cxint zx = x * ncols;
00670                 register cxint xr = x * config->xbin;
00671                 register cxint zr = xr * ncols;
00672 
00673 
00674                 _pixels[zx + y] = 0.;
00675 
00676                 for (xx = 0; xx < config->xbin && xr < nx; ++xx) {
00677                     _pixels[zx + y] += pixels[zr + y];
00678                 }
00679 
00680                 _pixels[zx + y] /= config->xbin;
00681 
00682             }
00683 
00684         }
00685 
00686         pixels = _pixels;
00687 
00688     }
00689 
00690     good_pixels = cx_calloc(nrows * ncols, sizeof(cxint));
00691 
00692     if (config->local) {
00693 
00694         cxint ywidth2 = ywidth / 2;
00695         cxint sz = 2 * ywidth2 + 1;
00696 
00697         cpl_vector *ymins = cpl_vector_new(sz);
00698 
00699 
00700         /*
00701          * We define a window along y axis to compute a local minimum
00702          * and threshold. To handle variation of "background"
00703          * between spectra in subslits
00704          */
00705 
00706         for (x = 0; x < nrows; x++) {
00707 
00708             cpl_vector_fill(ymins, 0.);
00709 
00710             for (y = 0; y < ncols; y++) {
00711 
00712                 register cxint k, kk;
00713 
00714                 cxdouble value = 0.;
00715                 cxdouble bkg = 0.;
00716                 cxdouble threshold = 0.;
00717 
00718 
00719                 for (kk = 0, k = -ywidth2; k <= ywidth2; k++) {
00720 
00721                     register cxint ky = y + k;
00722 
00723                     if (ky < 0 || ky >= ncols) {
00724                         continue;
00725                     }
00726 
00727                     cpl_vector_set(ymins, kk, pixels[x * ncols + ky]);
00728                     ++kk;
00729                 }
00730 
00731                 if (kk == 0) {
00732                     continue;
00733                 }
00734 
00735                 if (config->threshold > 0.) {
00736 
00737                     const cxint count = 2;
00738 
00739                     cxint i = 0;
00740 
00741                     /* Note that ymins has, by construction, an odd number
00742                      * of elements which must be at least 3 at this point.
00743                      * Also kk must be at least ywidth2 + 1, since at most we
00744                      * loose ywidth2 pixels at the borders.
00745                      */
00746 
00747                     giraffe_array_sort(cpl_vector_get_data(ymins), kk);
00748 
00749                     bkg = 0.;
00750 
00751                     for (i = 0; i < count; i++) {
00752                         bkg += cpl_vector_get(ymins, i);
00753                     }
00754                     bkg /= (cxdouble)count;
00755                     threshold = sqrt((noise * noise +
00756                             fabs(pixels[x * ncols + y])) / config->xbin);
00757 
00758                 }
00759                 else {
00760 
00761                     register cxint i;
00762                     register cxdouble mean = 0.;
00763 
00764 
00765                     for (i = 0; i < kk; i++) {
00766                         mean += cpl_vector_get(ymins, i);
00767                     }
00768                     mean /= kk;
00769 
00770                     giraffe_array_sort(cpl_vector_get_data(ymins), kk);
00771 
00772                     bkg = (cpl_vector_get(ymins, 0) +
00773                            cpl_vector_get(ymins, 1)) / 2.0;
00774                     threshold = mean - bkg;
00775 
00776                 }
00777 
00778 
00779                 /*
00780                  * Check background corrected pixel value
00781                  */
00782 
00783                 value = pixels[x * ncols + y] - bkg;
00784 
00785                 if (value < 0.) {
00786                     continue;
00787                 }
00788 
00789                 if (value > fabs(config->threshold) * threshold) {
00790                     good_pixels[x * ncols + y] = 1;
00791                 }
00792             }
00793         }
00794 
00795         cpl_vector_delete(ymins);
00796         ymins = NULL;
00797 
00798     }
00799     else {
00800 
00801         cxdouble threshold = 0.;
00802 
00803 
00804         /*
00805          * We use global background and threshold
00806          */
00807 
00808         if (config->threshold > 0.) {
00809             threshold = config->threshold * noise;
00810         }
00811         else {
00812             cxdouble mean = cpl_image_get_mean(raw);
00813 
00814             threshold = -config->threshold * mean * nspectra *
00815                 config->wavg / ncols;
00816         }
00817 
00818         for (x = 0; x < nrows; x++) {
00819             for (y = 0; y < ncols; y++) {
00820 
00821                 if (pixels[x * ncols + y] > threshold) {
00822                     good_pixels[x * ncols + y] = 1;
00823                 }
00824 
00825             }
00826         }
00827 
00828     }
00829 
00830     GIDEBUG(cxint *data = cx_calloc(nrows * ncols, sizeof(cxint));
00831 
00832             memcpy(data, good_pixels, nrows * ncols * sizeof(cxint));
00833             cpl_image *gp = cpl_image_wrap_int(ncols, nrows, data);
00834             cpl_image_save(gp, "locmask.fits", 32, NULL, CPL_IO_DEFAULT);
00835             cpl_image_unwrap(gp);
00836             cx_free(data));
00837 
00838 
00839     /*
00840      * Buffers used to store the fiber boundaries.
00841      */
00842 
00843     yabove = cx_calloc(nspectra + 1, sizeof(cxint));
00844     ybelow = cx_calloc(nspectra + 1, sizeof(cxint));
00845 
00846 
00847     /*
00848      * Start from <config->start> of CCD to first pixel
00849      */
00850 
00851     ny = ncols - 1;
00852 
00853     xretry = 0;
00854     xok = 0;
00855 
00856     for (x = config->start; (x >= 0) && (xretry <= config->retry); x--) {
00857 
00858         register cxint zx = x * ncols;
00859         register cxint nborders = 0;
00860         register cxint nbelow = 0;
00861         register cxint nabove = 0;
00862         register cxint in_spectrum = 0;
00863 
00864 
00865         for (y = 1; y < ny; y++) {
00866 
00867             register cxint tmp = 2 * good_pixels[zx + y];
00868 
00869             /*
00870              * Number of spectra = max number of borders
00871              */
00872 
00873             nborders = CX_MAX(CX_MAX(nborders, nbelow), nabove);
00874 
00875             if (nborders > nspectra) {
00876                 break;   /* Error: too many spectrum borders detected */
00877             }
00878 
00879             /*
00880              * Try to detect spectrum pattern:
00881              *    0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1
00882              * we need at least two consecutive one to detect a spectrum.
00883              */
00884 
00885             if (good_pixels[zx + y + 1]) {
00886 
00887                 /*
00888                  * Next pixel is a spectrum pixel: it's a border if
00889                  * previous one is zero
00890                  */
00891 
00892                 if ((tmp - good_pixels[zx + y - 1]) == 2) {
00893 
00894                     /*
00895                      * 0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1
00896                      *       ^ so, here we are...
00897                      */
00898 
00899                     if (!in_spectrum) {
00900 
00901                         /*
00902                          * Could not be a below border if we are already
00903                          * into a spectrum
00904                          */
00905 
00906                         ybelow[nbelow++] = y;
00907                         in_spectrum = 1;    /* entering */
00908 
00909                     }
00910 
00911                 }
00912 
00913             }
00914 
00915             if (good_pixels[zx + y - 1]) {
00916 
00917                 /*
00918                  * Previous pixel is a spectrum pixel: it's a border if
00919                  * next one is zero
00920                  */
00921 
00922                 if ((tmp - good_pixels[zx + y + 1]) == 2) {
00923 
00924                     /*
00925                      * 0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1
00926                      *               ^ and now, there
00927                      */
00928 
00929                     if (in_spectrum) {
00930 
00931                         /*
00932                          * taken into account only if we already found a
00933                          * lower border, we really are into a spectrum
00934                          */
00935 
00936                         yabove[nabove++] = y;
00937                         in_spectrum = 0;    /* going out */
00938 
00939                     }
00940 
00941                 }
00942 
00943             }
00944 
00945 // FIXME: Just a try
00946 
00947             if (tmp &&
00948                 !good_pixels[zx + y - 1] && !good_pixels[zx + y + 1]) {
00949 
00950                 if (_giraffe_validate_pixel(good_pixels, ncols, nrows, y, x,
00951                                             ckwidth, ckheight, ckcount)) {
00952 
00953                     yabove[nabove++] = y;
00954                     ybelow[nbelow++] = y;
00955                 }
00956 
00957             }
00958 
00959         }   /* finished with this x bin */
00960 
00961         if (in_spectrum) {
00962             nborders--;
00963             nbelow--;
00964             in_spectrum = 0;
00965         }
00966 
00967         *ndetect = nborders;
00968 
00969         if (!in_spectrum && (nbelow == nspectra) && (nbelow == nabove)) {
00970 
00971             /*
00972              * Good number of upper and lower cuples found for all spectra:
00973              * xend will be the first good value and the updated xstart is
00974              * the current value. We also do not want last CCD clipped
00975              * spectrum
00976              */
00977 
00978             for (y = 0; y < nspectra; y++) {
00979                 cpl_matrix_set(mylo, xok, y, (cxdouble) ybelow[y]);
00980                 cpl_matrix_set(myup, xok, y, (cxdouble) yabove[y]);
00981                 cpl_matrix_set(mxok, xok, 0, (config->xbin > 1) ?
00982                                (cxdouble) (x + 0.5) * config->xbin :
00983                                (cxdouble) x);
00984             }
00985             xok++;
00986             xretry = 0; /* back on your feet */
00987         }
00988         else if (xretry++ < config->retry) {
00989 
00990             /*
00991              * Do not find good number of spectra but we still have some
00992              * credit for a next try
00993              */
00994 
00995             continue;
00996         }
00997         else {
00998 
00999             /*
01000              * This is the end of our rope
01001              */
01002 
01003             break;
01004         }
01005     } /* next x bin */
01006 
01007 
01008     /*
01009      * Second half: start from <config->start+1> of CCD to last pixel
01010      */
01011 
01012     /*
01013      * Oops we could have a 2 * xretry width hole around xstart!!!
01014      */
01015 
01016     xretry = 0;
01017 
01018     for (x = config->start + 1; (x < nrows) &&
01019              (xretry <= config->retry); x++) {
01020 
01021         register cxint zx = x * ncols;
01022         register cxint nborders = 0;
01023         register cxint nbelow = 0;
01024         register cxint nabove = 0;
01025         register cxint in_spectrum = 0;
01026 
01027 
01028         for (y = 1; y < ny; y++) {
01029 
01030             register cxint tmp = 2 * good_pixels[zx + y];
01031 
01032             nborders = CX_MAX(CX_MAX(nborders, nbelow), nabove);
01033 
01034             if (nborders > nspectra) {
01035                 break;
01036             }
01037 
01038             if (good_pixels[zx + y + 1]) {
01039                 if ((tmp - good_pixels[zx + y - 1]) == 2) {
01040                     if (!in_spectrum) {
01041                         ybelow[nbelow++] = y;
01042                         in_spectrum = 1;
01043                     }
01044                 }
01045             }
01046 
01047             if (good_pixels[zx + y - 1]) {
01048                 if ((tmp - good_pixels[zx + y + 1]) == 2) {
01049                     if (in_spectrum) {
01050                         yabove[nabove++] = y;
01051                         in_spectrum = 0;
01052                     }
01053                 }
01054             }
01055 
01056 // FIXME: Just a try
01057 
01058             if (tmp &&
01059                 !good_pixels[zx + y - 1] && !good_pixels[zx + y + 1]) {
01060 
01061                 if (_giraffe_validate_pixel(good_pixels, ncols, nrows, y, x,
01062                                             ckwidth, ckheight, ckcount)) {
01063 
01064                     yabove[nabove++] = y;
01065                     ybelow[nbelow++] = y;
01066                 }
01067 
01068             }
01069 
01070         } /* finished with this x bin */
01071 
01072         if (in_spectrum) {
01073             nborders--;
01074             nbelow--;
01075             in_spectrum = 0;
01076         }
01077 
01078         *ndetect = nborders;
01079 
01080         if (!in_spectrum && (nbelow == nspectra) && (nbelow == nabove)) {
01081 
01082             for (y = 0; y < nspectra; y++) {
01083                 cpl_matrix_set(mylo, xok, y, (cxdouble) ybelow[y]);
01084                 cpl_matrix_set(myup, xok, y, (cxdouble) yabove[y]);
01085                 cpl_matrix_set(mxok, xok, 0, (config->xbin > 1) ?
01086                                (cxdouble) (x + 0.5) * config->xbin :
01087                                (cxdouble) x);
01088             }
01089             xok++;
01090             xretry = 0;
01091         }
01092         else if (xretry++ < config->retry) {
01093             continue;
01094         }
01095         else {
01096             break;
01097         }
01098 
01099     } /* next x bin */
01100 
01101     cx_free(ybelow);
01102     cx_free(yabove);
01103     cx_free(good_pixels);
01104 
01105     if (pixels != cpl_image_get_data_double(img)) {
01106         cx_free(pixels);
01107         pixels = NULL;
01108     }
01109 
01110     if (img != raw) {
01111         cpl_image_delete(img);
01112         img = NULL;
01113     }
01114 
01115     if (xok == 0) {
01116         if (*ndetect < nspectra) {
01117             return -1;
01118         }
01119         else if (*ndetect > nspectra) {
01120             return -1;
01121         }
01122         else {
01123             return -2;
01124         }
01125     }
01126     else {
01127         *ndetect = nspectra;
01128         cpl_msg_info(_task, "%d spectra detected in %d wavelength bins",
01129                      *ndetect, xok);
01130     }
01131 
01132     return xok;
01133 
01134 }
01135 
01136 
01137 /*
01138  * @brief
01139  *   Computes fitted localization centroid and width.
01140  *
01141  * @param mxok      good X bins (all nspectra detected) [nxok]
01142  * @param myup      upper Y of spectra [nxok,nspectra]
01143  * @param mylo      lower Y of spectra [nxok,nspectra]
01144  * @param fibers    Table of spectra/fibers to localize [ns]
01145  * @param config    localization mask parameters
01146  * @param position  localization mask: locy[nx,ns] and locw[nx,ns]
01147  *
01148  * Computes Chebyshev polynomial fit of raw localization borders for each
01149  * spectrum specified in @em fibers.
01150  *
01151  * The @em myup[nxok,nspectra] and @em mylo[nxok,nspectra] border matrices
01152  * had been computed by @b _giraffe_build_raw_mask().
01153  *
01154  * The expected number of spectra to be localized is given by @em nspectra.
01155  * The computed results are stored in the pre-allocated matrices
01156  * @em position->my[nx,ns] and @em position->mw[nx,ns]. The fiber setup
01157  * for a particular observation is given by @em fibers, a table of all
01158  * fibers specifying the spectra to be processed where @em ns is number of
01159  * entries (fibers) in @em fibers defined by the current instrument setup.
01160  */
01161 
01162 inline static void
01163 _giraffe_fit_raw_mask(cpl_matrix *mxok, cpl_matrix *myup, cpl_matrix *mylo,
01164                       cpl_table *fibers, GiMaskParameters *config,
01165                       GiMaskPosition *position)
01166 {
01167 
01168     register cxint nn, x, nspectra;
01169     register cxint nx = cpl_matrix_get_nrow(position->my);
01170     register cxint ns = cpl_table_get_nrow(fibers);
01171 
01172     cpl_matrix *mxraw;
01173     cpl_matrix *base;
01174     cpl_matrix *mcoeff;
01175 
01176 
01177 
01178     mxraw  = cpl_matrix_new(nx, 1);
01179     mcoeff = cpl_matrix_new(config->ydeg + 1, 1);
01180 
01181 
01182     /*
01183      * Initialize with all abcissa
01184      */
01185 
01186     for (x = 0; x < nx; x++) {
01187         cpl_matrix_set(mxraw, x, 0, x);
01188     }
01189 
01190     /*
01191      * Compute Chebyshev base over all x bins
01192      */
01193 
01194     base = giraffe_chebyshev_base1d(0., nx, config->ydeg + 1, mxraw);
01195     cpl_matrix_delete(mxraw);
01196 
01197     nspectra = 0;
01198     for (nn = 0; nn < ns; nn++) {
01199         cpl_matrix *ylofit = NULL;
01200         cpl_matrix *yupfit = NULL;
01201 
01202         /* FIXME: The fiber selection changed the following piece of code
01203          *        should not be necessary but we have to check that the
01204          *        accessed to the matrix rows correspond to the selected
01205          *        fibers.
01206          */
01207 
01208         //if (mButton->m[nn] != LOC_OK_SPECTRUM) {
01209         //    continue;
01210         //}
01211 
01212         /* Fitting the lower border */
01213         ylofit = _giraffe_fit_border(mylo, base, mxok, nspectra,
01214                                      config->sigma, config->niter,
01215                                      config->mfrac, mcoeff);
01216         if (ylofit == NULL) {
01217             cpl_msg_warning(_task, "Could not compute low border for "
01218                             "spectrum %d", nn);
01219             nspectra++;
01220             continue;
01221         }
01222 
01223         /* Fitting the upper border */
01224         yupfit = _giraffe_fit_border(myup, base, mxok, nspectra,
01225                                      config->sigma, config->niter,
01226                                      config->mfrac, mcoeff);
01227         if (yupfit == NULL) {
01228             cpl_msg_warning(_task, "Could not compute up border for "
01229                             "spectrum %d", nn);
01230             nspectra++;
01231             continue;
01232         }
01233 
01234         /*
01235          * For each X bin the centroid and the half-width of the
01236          * corresponding mask is computed as the half-sum and the
01237          * half-difference of the fitted borders.
01238          */
01239 
01240         for (x = 0; x < nx; x++) {
01241 
01242             cpl_matrix_set(position->my, x, nn, 0.5 *
01243                            (cpl_matrix_get(yupfit, x, 0) +
01244                             cpl_matrix_get(ylofit, x, 0)));
01245 
01246             cpl_matrix_set(position->my, x, nn, 0.5 *
01247                            (cpl_matrix_get(yupfit, x, 0) -
01248                             cpl_matrix_get(ylofit, x, 0)) + config->ewid);
01249 
01250         }
01251         cpl_matrix_delete(ylofit);
01252         cpl_matrix_delete(yupfit);
01253         nspectra++;
01254 
01255     } /* each spectrum */
01256 
01257     cpl_msg_info(_task, "%03d spectrum positions fitted", nspectra);
01258 
01259     cpl_matrix_delete(base);
01260     cpl_matrix_delete(mcoeff);
01261 
01262     if (nspectra == 0) {
01263         cpl_msg_warning(_task, "could not fit any spectra, check number "
01264                         "of good wavelength bins");
01265         return;
01266     }
01267 
01268     return;
01269 
01270 }
01271 
01272 
01273 /*
01274  * @brief
01275  *   Computes fitted localization centroid and width.
01276  *
01277  * @param mz        Image[nx,ny] of pixels values
01278  * @param mxok      Good x bins (all nspectra detected) [nxok]
01279  * @param myup      Upper Y of spectra [nxok,nspectra]
01280  * @param mylo      Lower Y of spectra [nxok,nspectra]
01281  * @param fibers    Spectra used for localization [ns]
01282  * @param config    Localization mask parameters
01283  * @param position  Localization mask: my[nx, ns] and mw[nx, ns]
01284  * @param coeffs    Localization mask Chebyshev fit coefficients
01285  *
01286  * Computes Chebyshev polynomial fit of raw localization borders for each
01287  * spectrum specified in fibers[ns].
01288  *
01289  * The @em myup[nxok, nspectra] and @em mylo[nxok, nspectra] border matrices
01290  * had been computed by @b _giraffe_build_raw_mask(). The expected number
01291  * of spectra to be localized is given by @em nspectra. The matrix
01292  * @em position->my[nx, ns] is the fitted barycenter of Y values between raw
01293  * localization borders, while @em position->mw[nx,ns] is the 2D fit of
01294  * the half-width of the raw localization borders (+ extra width:
01295  * @em config->ewid).
01296  *
01297  * The matrices @em position->my[nx, ns], @em position->mw[nx, ns],
01298  * @em coeffs->my[ydeg + 1, ns] and @em coeffs->mw[(config->wdeg + 1)^2]
01299  * are pre-allocated matrices.
01300  *
01301  * The fiber setup for a particular observation is given by @em fibers,
01302  * a table of all fibers specifying the spectra to be processed where
01303  * @em ns is number of entries (fibers) in @em fibers defined by the
01304  * current instrument setup.
01305  */
01306 
01307 inline static void
01308 _giraffe_fit_raw_centroid(cpl_image* mz, cpl_matrix* mxok, cpl_matrix* myup,
01309                           cpl_matrix* mylo, cpl_table* fibers,
01310                           GiMaskParameters* config, GiMaskPosition* position,
01311                           GiMaskPosition* coeffs)
01312 {
01313 
01314     const cxchar* const fctid = "_giraffe_fit_raw_centroid";
01315 
01316     register cxint nn = 0;
01317     register cxint x = 0;
01318     register cxint y = 0;
01319     register cxint nspectra = 0;
01320     register cxint nx = cpl_image_get_size_y(mz);
01321     register cxint ny = cpl_image_get_size_x(mz);
01322     register cxint ns = cpl_table_get_nrow(fibers);
01323 
01324     cxint yorder = config->ydeg + 1;
01325     cxint worder = config->wdeg + 1;
01326 
01327     cpl_matrix* mxraw = NULL;
01328     cpl_matrix* base = NULL;
01329     cpl_matrix* mycenter = NULL;
01330     cpl_matrix* mywidth = NULL;
01331     cpl_matrix* mx = NULL;
01332     cpl_matrix* my = NULL;
01333     cpl_matrix* mw = NULL;
01334     cpl_matrix* chebcoeff = NULL;
01335     cpl_matrix* mfitlocw = NULL;
01336     cpl_matrix* ycenfit = NULL;
01337     cpl_matrix* ycencoeff = NULL;
01338 
01339 
01340 
01341     if (cpl_matrix_get_nrow(position->my) != nx ||
01342         cpl_matrix_get_ncol(position->my) != ns) {
01343         gi_error("%s: invalid size for position->my[%d,%d], expected "
01344                  "[%d,%d]", fctid, cpl_matrix_get_nrow(position->my),
01345                  cpl_matrix_get_ncol(position->my), nx, ns);
01346         return;
01347     }
01348 
01349     if (cpl_matrix_get_nrow(position->mw) != nx ||
01350         cpl_matrix_get_ncol(position->mw) != ns) {
01351         gi_error("%s: invalid size for position->mw[%d,%d], expected "
01352                  "[%d,%d]", fctid, cpl_matrix_get_nrow(position->my),
01353                  cpl_matrix_get_ncol(position->my), nx, ns);
01354         return;
01355     }
01356 
01357 
01358     /*
01359      * Initialize with all abcissa
01360      */
01361 
01362     mxraw = cpl_matrix_new(nx, 1);
01363 
01364     for (x = 0; x < nx; x++) {
01365         cpl_matrix_set(mxraw, x, 0, x);
01366     }
01367 
01368 
01369     /*
01370      * Compute Chebyshev base over all x bins
01371      */
01372 
01373     base = giraffe_chebyshev_base1d(0., nx, yorder, mxraw);
01374     cpl_matrix_delete(mxraw);
01375 
01376     mycenter = cpl_matrix_new(cpl_matrix_get_nrow(mxok), ns);
01377     mywidth = cpl_matrix_new(1, cpl_matrix_get_nrow(mxok) * ns);
01378 
01379     ycencoeff = cpl_matrix_new(yorder, 1);
01380 
01381     for (nn = 0; nn < ns; nn++) {
01382 
01383         /* FIXME: The fiber selection changed the following piece of code
01384          *        should not be necessary but we have to check that the
01385          *        accessed to the matrix rows correspond to the selected
01386          *        fibers.
01387          */
01388 
01389         //if (mButton->m[nn] != LOC_OK_SPECTRUM) {
01390         //    continue;
01391         //}
01392 
01393         /*
01394          * compute the barycenter and half-width of the corresponding mask
01395          * between raw borders.
01396          */
01397 
01398         cxdouble* pixels = cpl_image_get_data_double(mz);
01399 
01400         for (x = 0; x < cpl_matrix_get_nrow(mxok); x++) {
01401 
01402             register cxint zx = (cxint) cpl_matrix_get(mxok, x, 0);
01403 
01404             register cxdouble zz = 0.;
01405             register cxdouble yy = 0.;
01406 
01407             cxdouble lower = cpl_matrix_get(mylo, x, nspectra);
01408             cxdouble upper = cpl_matrix_get(myup, x, nspectra);
01409 
01410 
01411             for (y = (cxint) lower; y <= (cxint) upper; y++) {
01412                 yy += pixels[zx * ny + y] * y;
01413                 zz += pixels[zx * ny + y];
01414             }
01415 
01416             cpl_matrix_set(mycenter, x, nspectra, yy / zz);
01417             cpl_matrix_set(mywidth, 0, x * ns + nspectra, config->ewid +
01418                            (upper - lower) / 2.0);
01419 
01420         }   /* for each x bin */
01421 
01422         /*
01423          * The matrix ycenfit[nx] stores the fitted centroid
01424          */
01425 
01426         cpl_matrix_fill(ycencoeff, 0.);
01427         ycenfit = _giraffe_fit_border(mycenter, base, mxok, nspectra,
01428                                       config->sigma, config->niter,
01429                                       config->mfrac, ycencoeff);
01430         if (ycenfit == NULL) {
01431             cpl_msg_warning(_task, "Could not fit centroid for spectrum %d",
01432                             nn);
01433             nspectra++;
01434             continue;
01435         }
01436 
01437         /*
01438          * Save centroid Chebyshev fit coeffs
01439          */
01440 
01441         for (x = 0; x < yorder; x++) {
01442             cpl_matrix_set(coeffs->my, x, nn,
01443                            cpl_matrix_get(ycencoeff, x, 0));
01444         }
01445 
01446         /*
01447          * The localization centroid is a Chebyshev polynomial fit
01448          * of Y barycenters in raw mask
01449          */
01450 
01451         for (x = 0; x < nx; x++) {
01452             cpl_matrix_set(position->my, x, nn,
01453                            cpl_matrix_get(ycenfit, 0, x));
01454         }   /* for each x bin */
01455 
01456         cpl_matrix_delete(ycenfit);
01457         nspectra++;
01458 
01459     } /* each spectrum */
01460 
01461     GIDEBUG(cpl_image *lycenter = giraffe_matrix_create_image(mycenter);
01462             cpl_image_save(lycenter, "lycenter.fits", -32, NULL,
01463                            CPL_IO_DEFAULT);
01464             cpl_image_delete(lycenter);
01465 
01466             lycenter = giraffe_matrix_create_image(position->my);
01467             cpl_image_save(lycenter, "lycenterfit.fits", -32, NULL,
01468                            CPL_IO_DEFAULT);
01469             cpl_image_delete(lycenter);
01470 
01471             cpl_image *lyxok = giraffe_matrix_create_image(mxok);
01472             cpl_image_save(lyxok, "lyxok.fits", -32, NULL,
01473                            CPL_IO_DEFAULT);
01474             cpl_image_delete(lyxok));
01475 
01476 
01477     cpl_msg_info(_task, "%03d spectrum positions fitted", nspectra);
01478 
01479     cpl_matrix_delete(base);
01480     cpl_matrix_delete(mycenter);
01481     cpl_matrix_delete(ycencoeff);
01482 
01483     if (nspectra == 0) {
01484         cpl_msg_warning(_task, "Could not fit any spectra, check number of "
01485                         "good wavelength bins");
01486 
01487         cpl_matrix_delete(mywidth);
01488         return;
01489     }
01490 
01491     /*
01492      * 2D fit of mask width
01493      */
01494 
01495     cpl_msg_info(_task, "2D fit (order %dx%d) of mask width", worder,
01496                  worder);
01497 
01498     /*
01499      * Computes grid[nxok, nspectra]
01500      */
01501 
01502     mx = cpl_matrix_new(cpl_matrix_get_nrow(mxok) * nspectra, 1);
01503     my = cpl_matrix_new(cpl_matrix_get_nrow(mxok) * nspectra, 1);
01504     mw = cpl_matrix_new(1, cpl_matrix_get_nrow(mxok) * nspectra);
01505 
01506     for (y = 0, nn = 0; nn < nspectra; nn++) {
01507 
01508         /* FIXME: The fiber selection changed the following piece of code
01509          *        should not be necessary but we have to check that the
01510          *        accessed to the matrix rows correspond to the selected
01511          *        fibers.
01512          */
01513 
01514         //if (mButton->m[nn] != LOC_OK_SPECTRUM) {
01515         //    continue;
01516         //}
01517 
01518         for (x = 0; x < cpl_matrix_get_nrow(mxok); x++) {
01519 
01520             register cxint zx = (cxint) cpl_matrix_get(mxok, x, 0);
01521             register cxint lx = x * nspectra + y;
01522 
01523 
01524             cpl_matrix_set(mx, lx, 0, cpl_matrix_get(mxok, x, 0));
01525             cpl_matrix_set(my, lx, 0, cpl_matrix_get(position->my, zx, nn));
01526             cpl_matrix_set(mw, 0, lx, cpl_matrix_get(mywidth, 0, x * ns + y));
01527         }
01528         y++;
01529     }
01530 
01531     base = giraffe_chebyshev_base2d(0., 0., nx, ny, worder, worder, mx, my);
01532 
01533     cpl_matrix_delete(my);
01534     cpl_matrix_delete(mx);
01535 
01536     chebcoeff = giraffe_matrix_leastsq(base, mw);
01537     cpl_matrix_delete(base);
01538     cpl_matrix_delete(mw);
01539 
01540     cpl_matrix_delete(mywidth);
01541 
01542     if (chebcoeff == NULL) {
01543         gi_warning("%s: error in giraffe_matrix_leastsq() for width 2D fit",
01544                    fctid);
01545         return;
01546     }
01547 
01548     /*
01549      * Save half-width Chebyshev 2-D fit coeffs
01550      */
01551 
01552     for (nn = 0; nn < cpl_matrix_get_ncol(chebcoeff); nn++) {
01553         cpl_matrix_set(coeffs->mw, 0, nn, cpl_matrix_get(chebcoeff, 0, nn));
01554     }
01555 
01556     /*
01557      * Computes grid[nx, nspectra]
01558      */
01559 
01560     mx = cpl_matrix_new(nx * nspectra, 1);
01561     my = cpl_matrix_new(nx * nspectra, 1);
01562 
01563     for (y = 0, nn = 0; nn < nspectra; nn++) {
01564 
01565         /* FIXME: The fiber selection changed the following piece of code
01566          *        should not be necessary but we have to check that the
01567          *        accessed to the matrix rows correspond to the selected
01568          *        fibers.
01569          */
01570 
01571         //if (mButton->m[nn] != LOC_OK_SPECTRUM) {
01572         //    continue;
01573         //}
01574 
01575         for (x = 0; x < nx; x++) {
01576 
01577             register cxint lx = x * nspectra + y;
01578 
01579             cpl_matrix_set(mx, lx, 0, x);
01580             cpl_matrix_set(my, lx, 0, cpl_matrix_get(position->my, x, nn));
01581 
01582         }
01583         y++;
01584     }
01585 
01586     cpl_matrix_set_size(chebcoeff, worder, worder);
01587 
01588     mfitlocw = giraffe_chebyshev_fit2d(0., 0., nx, ny, chebcoeff, mx, my);
01589     cpl_matrix_delete(chebcoeff);
01590 
01591     cpl_matrix_delete(my);
01592     cpl_matrix_delete(mx);
01593 
01594     for (y = 0, nn = 0; nn < nspectra; nn++) {
01595 
01596         /* FIXME: The fiber selection changed the following piece of code
01597          *        should not be necessary but we have to check that the
01598          *        accessed to the matrix rows correspond to the selected
01599          *        fibers.
01600          */
01601 
01602         //if (mButton->m[nn] != LOC_OK_SPECTRUM) {
01603         //    continue;
01604         //}
01605 
01606         for (x = 0; x < nx; x++) {
01607 
01608             register cxint lx = x * nspectra + y;
01609 
01610             cpl_matrix_set(position->mw, x, nn,
01611                            cpl_matrix_get(mfitlocw, lx, 0));
01612 
01613         }
01614         y++;
01615     }
01616 
01617     cpl_matrix_delete(mfitlocw);
01618 
01619     return;
01620 
01621 }
01622 
01623 
01624 /*
01625  * @brief
01626  *   Computes fitted localization centroid and width on all spectra.
01627  *
01628  * @param mZraw      Matrix[nx,ny] of pixels values
01629  * @param mButton    Matrix[ns] of spectra used for localization
01630  * @param locMethod  Centroid computation method:
01631  *                   HALF_WIDTH, BARYCENTER, PSF_PROFIL
01632  * @param sNormalize Normalize spectra along dispersion axis
01633  * @param noithresh  Spectra/noise threshold
01634  * @param locPrms    Localization mask parameters
01635  * @param locPos     Localization mask: locY[nx,ns] and locW[nx,ns]
01636  * @param locCoeff   Localization mask Chebyshev fit coefficients
01637  *
01638  * @return The function returns 0 on success, or a negative value otherwise.
01639  *
01640  * Computes localization mask (centroid and half-width) for the given
01641  * image @a mZraw[nx,ny]. @a mButton[nspectra] is a matrix of 0/1 values
01642  * specifying spectra to be processed. @a *noithresh is the threshold value
01643  * use to select spectra or inter-spectra pixels. @a locMethod defines the
01644  * method used to compute localization mask centroid and half-width.
01645  * @a locPos.mY[nx,ns], @a locPos.mW[nx,ns], @a locCoeff.mY[ydeg+1,ns] and
01646  * @a locCoeff.mW[(wdeg+1)**2] are pre-allocated matrices.
01647  */
01648 
01649 inline static cxint
01650 _giraffe_localize_spectra(cpl_image *mzraw, cpl_image *bpixel,
01651                           cpl_table *fibers, GiLocalizeMethod method,
01652                           cxbool normalize, cxdouble noise,
01653                           GiMaskParameters *config, GiMaskPosition *position,
01654                           GiMaskPosition *coeffs)
01655 {
01656 
01657     cxint n, nn;
01658     cxint nx, ny, nxok;
01659     cxint ndetect, nspectra;
01660     cxint x, y;
01661 
01662     cxdouble uplost = 0.;
01663     cxdouble lolost = 0.;
01664     cxdouble avglost = 0.;
01665     cxdouble avgmask = 0.;
01666     cxdouble sigmask = 0.;
01667     cxdouble sigmean = 0.;
01668     cxdouble avgborders = 0.;
01669 
01670     cxdouble *_mzraw;
01671 
01672     cpl_matrix *mxok;         /* mylo[nx] abcissa og good x bins */
01673     cpl_matrix *myup;         /* myup[nx,ns] of upper Y for each spectrum */
01674     cpl_matrix *mylo;         /* mylo[nx,ns] of lower Y for each spectrum */
01675     cpl_matrix *mwid;
01676 
01677     cpl_image *mz = NULL;
01678     cpl_image *mznorm = NULL;
01679 
01680 
01681 
01682     nx = cpl_image_get_size_y(mzraw);
01683     ny = cpl_image_get_size_x(mzraw);
01684     _mzraw = cpl_image_get_data_double(mzraw);
01685 
01686 
01687     if (normalize == TRUE) {
01688 
01689         cxdouble zxmax = 0.0;
01690         cxdouble *_mzx = NULL;
01691         cxdouble *_mznorm = NULL;
01692 
01693         cpl_image *mzx = NULL;
01694 
01695 
01696         cpl_msg_info(_task, "Using normalized spectra for localization");
01697 
01698 
01699         /*
01700          * The matrix mznorm contains the pixel values from mz
01701          * normalized along X axis and the matrix mzx is the summ
01702          * of all spectra along X (dispersion) axis
01703          */
01704 
01705         mznorm = cpl_image_new(ny, nx, CPL_TYPE_DOUBLE);
01706         _mznorm = cpl_image_get_data_double(mznorm);
01707 
01708         mzx = cpl_image_new(1, nx, CPL_TYPE_DOUBLE);
01709         _mzx = cpl_image_get_data_double(mzx);
01710 
01711 
01712         /*
01713          * For each x bin, summ all y values
01714          */
01715 
01716         for (x = 0 ; x < nx; x++) {
01717             for (y = 0 ; y < ny; y++) {
01718                 _mzx[x] += _mzraw[x * ny + y];
01719             }
01720 
01721             /*
01722              * Maximum value of summ
01723              */
01724 
01725             if (_mzx[x] > zxmax) {
01726                 zxmax = _mzx[x];
01727             }
01728         }
01729 
01730         GIDEBUG(cpl_image_save(mzx, "mzx.fits", -32, NULL, CPL_IO_DEFAULT));
01731 
01732         for (x = 0 ; x < nx; x++) {
01733 
01734             register cxdouble zxnorm = zxmax / _mzx[x];
01735 
01736             for (y = 0 ; y < ny; y++) {
01737                 _mznorm[x * ny + y] = _mzraw[x * ny + y] * zxnorm;
01738             }
01739 
01740         }
01741 
01742         cpl_image_delete(mzx);
01743         mz = mznorm;
01744     }
01745     else {
01746 
01747         /*
01748          * Use pixel values as they are
01749          */
01750 
01751         cpl_msg_info(_task, "Using raw spectra for localization");
01752         mz = mzraw;
01753     }
01754 
01755 
01756     /*
01757      * Full localization: takes care of all spectra
01758      */
01759 
01760     nspectra = cpl_table_get_nrow(fibers);
01761 
01762     mxok = cpl_matrix_new(nx, 1);
01763     myup = cpl_matrix_new(nx, nspectra);
01764     mylo = cpl_matrix_new(nx, nspectra);
01765 
01766 
01767     /*
01768      *  Make the bin size an even value if it is larger than 1
01769      */
01770 
01771     config->xbin = (config->xbin > 1) ? 2 * (config->xbin / 2) : 1;
01772 
01773     GIDEBUG(cpl_image_save(mz, "mz.fits", -32, NULL, CPL_IO_DEFAULT));
01774 
01775     nxok = _giraffe_build_raw_mask(mz, bpixel, nspectra, noise, config,
01776                                    &ndetect, mxok, myup, mylo);
01777 
01778     if (nxok < 0) {
01779         switch (nxok) {
01780             case -1:
01781                 cpl_msg_warning(_task, "Invalid number of spectra detected: "
01782                                 "%d != %d", ndetect, nspectra);
01783                 break;
01784 
01785             case -2:
01786                 cpl_msg_warning(_task, "No abcissa with good number "
01787                                 "of spectra");
01788                 break;
01789 
01790             default:
01791                 cpl_msg_warning(_task, "Error while searching for spectra");
01792         }
01793 
01794         return nxok;
01795     }
01796 
01797 
01798     /*
01799      * Only takes care of good values
01800      */
01801 
01802     cpl_matrix_resize(mxok, 0, nxok - cpl_matrix_get_nrow(mxok), 0, 0);
01803     cpl_matrix_resize(myup, 0, nxok - cpl_matrix_get_nrow(myup), 0, 0);
01804     cpl_matrix_resize(mylo, 0, nxok - cpl_matrix_get_nrow(mylo), 0, 0);
01805 
01806     GIDEBUG(gi_message("%s: mxok[0-%d]=[%g-%g]", __func__,
01807                        cpl_matrix_get_nrow(mxok) - 1,
01808                        cpl_matrix_get_min(mxok),
01809                        cpl_matrix_get_max(mxok)));
01810 
01811 
01812     cpl_msg_info(_task, "Computing spectrum positions and widths in "
01813                  "pixel range [%g,%g]", cpl_matrix_get_min(mxok),
01814                  cpl_matrix_get_max(mxok));
01815 
01816     if (cpl_matrix_get_nrow(mxok) <= config->ydeg) {
01817         cpl_msg_info(_task, "Not enough data points %d for %d order fit",
01818                      cpl_matrix_get_nrow(mxok), config->ydeg);
01819 
01820         return -1;
01821     }
01822 
01823     switch (method) {
01824         case GILOCALIZE_HALF_WIDTH:
01825             cpl_msg_info(_task, "Using half-width for localization");
01826             _giraffe_fit_raw_mask(mxok, myup, mylo, fibers, config,
01827                                   position);
01828             break;
01829 
01830         case GILOCALIZE_BARYCENTER:
01831         default:
01832             cpl_msg_info(_task, "Using barycenter for localization");
01833             _giraffe_fit_raw_centroid(mz, mxok, myup, mylo, fibers, config,
01834                                       position, coeffs);
01835             break;
01836     }
01837 
01838     if (normalize == 1) {
01839         cpl_image_delete(mznorm);
01840     }
01841 
01842     /*
01843      * Compute the number of pixels rejected by the fit
01844      */
01845 
01846 
01847     /* FIXME: Here again nspectra equals cpl_table_get_nrow(fibers),
01848      *        where OGL used mButtons->nr. We have to check the
01849      *        correctness carefully here !!
01850      */
01851 
01852     mwid = cpl_matrix_new(nxok, nspectra);
01853 
01854     for (n = 0, nn = 0; nn < cpl_table_get_nrow(fibers); nn++) {
01855 
01856         for (x = 0; x < nxok; x++) {
01857             register cxint lx = (cxint) cpl_matrix_get(mxok, x, 0);
01858 
01859             cxdouble lower = cpl_matrix_get(mylo, x, n);
01860             cxdouble upper = cpl_matrix_get(myup, x, n);
01861             cxdouble width = cpl_matrix_get(position->mw, lx, nn);
01862 
01863             uplost += cpl_matrix_get(position->my, lx, nn) + width - upper;
01864             lolost += cpl_matrix_get(position->my, lx, nn) - width - lower;
01865 
01866             avgborders += upper - lower;
01867             avgmask += width;
01868 
01869             cpl_matrix_set(mwid, x, n, 2. * width);
01870         }
01871         n++;
01872     }
01873 
01874     sigmean = cpl_matrix_get_mean(mwid);
01875     sigmask = giraffe_matrix_sigma_mean(mwid, sigmean);
01876     avglost = (lolost + uplost) / (nspectra * nxok);
01877     avgmask = 2.0 * avgmask / nspectra;
01878 
01879     cpl_msg_info(_task, "Mask was computed using %d of %d wavelength bins",
01880                  nxok, nx);
01881     cpl_msg_info(_task, "Average # of pixels per spectra: %.4g",
01882                  avgmask);
01883     cpl_msg_info(_task, "Average # of in-borders pixels per spectra: %.4g",
01884                  avgborders / nspectra);
01885     cpl_msg_info(_task, "Average lost pixels per spectra: %.4g",
01886                  avglost);
01887     cpl_msg_info(_task, "Average lost pixels at upper border: %.4g",
01888                  uplost / (nspectra * nxok));
01889     cpl_msg_info(_task, "Average lost pixels at lower border: %.4g",
01890                  lolost / (nspectra * nxok));
01891     cpl_msg_info(_task, "Average spectrum width: %.4g +/- %.4g, "
01892                  "(min, max) = (%.4g, %.4g)", sigmean, sigmask,
01893                  cpl_matrix_get_min(mwid), cpl_matrix_get_max(mwid));
01894 
01895     cpl_matrix_delete(mwid);
01896 
01897     cpl_matrix_delete(mylo);
01898     cpl_matrix_delete(myup);
01899     cpl_matrix_delete(mxok);
01900 
01901     return 0;
01902 
01903 }
01904 
01905 
01906 inline static cxint
01907 _giraffe_finalize_fibers(cpl_table *fibers, cpl_matrix *locy, GiImage *mlocy,
01908                          cxdouble maxoffset, cxdouble* maxshift)
01909 {
01910 
01911     cxint i = 0;
01912     cxint j = 0;
01913     cxint nx = 0;
01914     cxint ny = 0;
01915     cxint _nx = 0;
01916     cxint _ny = 0;
01917     cxint nfibers = 0;
01918     cxint irow = 0;
01919 
01920     cxdouble max_shift = 0.;
01921     cxdouble *positions = NULL;
01922 
01923     cpl_image *_mlocy = NULL;
01924 
01925 
01926     if (fibers == NULL || locy == NULL || mlocy == NULL) {
01927         return -1;
01928     }
01929 
01930     if (cpl_table_has_column(fibers, "RINDEX") == FALSE) {
01931         return -1;
01932     }
01933 
01934     nx = cpl_matrix_get_ncol(locy);
01935     ny = cpl_matrix_get_nrow(locy);
01936 
01937     nfibers = cpl_table_get_nrow(fibers);
01938 
01939     _mlocy = giraffe_image_get(mlocy);
01940     _nx = cpl_image_get_size_x(_mlocy);
01941     _ny = cpl_image_get_size_y(_mlocy);
01942 
01943     if (ny != _ny) {
01944         return -2;
01945     }
01946 
01947     if (nfibers > _nx) {
01948         return -3;
01949     }
01950 
01951     cpl_table_select_all(fibers);
01952 
01953 
01954     /*
01955      * Get pointer to the central scan line.
01956      */
01957 
01958     irow = (_ny - 1) / 2;
01959     positions = (cxdouble *)cpl_image_get_data(_mlocy) + irow * _nx;
01960 
01961 
01962     /*
01963      * Compare the detected fiber positions with the positions
01964      * from the reference localization. Select only those fibers
01965      * whose distance from the reference positions is less than
01966      * a given offset. All other fibers are removed from the
01967      * fiber table.
01968      */
01969 
01970     for (i = 0; i < nfibers; i++) {
01971 
01972         if (j < nx) {
01973 
01974             cxint pos = cpl_table_get_int(fibers, "RINDEX", i, NULL) - 1;
01975 
01976             cxdouble yc = cpl_matrix_get(locy, irow, j);
01977             cxdouble shift = fabs(yc - positions[pos]);
01978 
01979             if (shift <= maxoffset) {
01980                 cpl_table_unselect_row(fibers, i);
01981                 ++j;
01982             }
01983             else {
01984                 max_shift = CX_MAX(max_shift, shift);
01985             }
01986 
01987         }
01988     }
01989 
01990     cpl_table_erase_selected(fibers);
01991 
01992     if (maxshift != NULL) {
01993         *maxshift = max_shift;
01994     }
01995 
01996     return 0;
01997 
01998 }
01999 
02000 
02029 cxint
02030 giraffe_localize_spectra(GiLocalization *result, GiImage *image,
02031                          GiTable *fibers, GiLocalization *master,
02032                          GiImage *badpixels, GiLocalizeConfig *config)
02033 {
02034 
02035     const cxchar *fctid = "giraffe_localize_spectra";
02036 
02037     cxint i;
02038     cxint status;
02039     cxint nrows;
02040     cxint nfibers;
02041     cxint ckwidth;
02042     cxint ckheight;
02043     cxint ckcount;
02044 
02045     cxdouble mwidth;
02046     cxdouble sigma;
02047 
02048     cx_string *pname;
02049 
02050     cpl_propertylist *properties;
02051 
02052     cpl_image *_image = giraffe_image_get(image);
02053     cpl_image *_bpixel = giraffe_image_get(badpixels);
02054     cpl_image *_result = NULL;
02055 
02056     cpl_matrix *_my;
02057 
02058     cpl_table *_fibers = NULL;
02059     cpl_table *fiber_setup = NULL;
02060     cpl_table *locc;
02061 
02062     GiLocalizeMethod method;
02063 
02064     GiInstrumentMode mode;
02065 
02066     GiMaskParameters mask_config;
02067 
02068     GiMaskPosition mask_position;
02069     GiMaskPosition mask_coeffs;
02070 
02071 
02072 
02073     /*
02074      * Preprocessing
02075      */
02076 
02077     if (result == NULL || image == NULL || fibers == NULL || config == NULL) {
02078         cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
02079         return 1;
02080     }
02081 
02082     if (badpixels != NULL) {
02083 #if 1
02084         cpl_msg_debug(fctid,"Bad pixel correction is not available. Bad "
02085                       "pixel map will be ignored.");
02086 #else
02087         gi_warning("%s: Bad pixel correction is not available. Bad "
02088                    "pixel map at %p will be ignored.", fctid, badpixels);
02089 #endif
02090     }
02091 
02092     _fibers = giraffe_table_get(fibers);
02093 
02094     if (_fibers == NULL) {
02095         cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
02096         return 1;
02097     }
02098     else {
02099         fiber_setup = _fibers;
02100     }
02101 
02102     properties = giraffe_image_get_properties(image);
02103 
02104 
02105     /*
02106      * Add the number of fibers to the image properties.
02107      */
02108 
02109     nfibers = cpl_table_get_nrow(_fibers);
02110 
02111     cpl_msg_info(fctid, "Setting number of fibers (%s) to %d",
02112                  GIALIAS_NFIBERS, nfibers);
02113 
02114     cpl_propertylist_update_int(properties, GIALIAS_NFIBERS, nfibers);
02115     cpl_propertylist_set_comment(properties, GIALIAS_NFIBERS,
02116                                  "Number of fibres");
02117 
02118 
02119     /*
02120      * If a ron value is provided write it to the image properties.
02121      */
02122 
02123     if (config->ron > 0.) {
02124         cpl_msg_info(fctid, "Setting bias sigma value (%s) to %.5g",
02125                      GIALIAS_BIASSIGMA, config->ron);
02126         cpl_propertylist_update_double(properties, GIALIAS_BIASSIGMA,
02127                                        config->ron);
02128     }
02129 
02130 
02131     sigma = cpl_propertylist_get_double(properties, GIALIAS_BIASSIGMA);
02132 
02133     if (cpl_propertylist_has(properties, GIALIAS_CONAD)) {
02134 
02135         cxdouble conad = cpl_propertylist_get_double(properties,
02136                                                      GIALIAS_CONAD);
02137 
02138 
02139         if (conad > 0.) {
02140             sigma *= conad;
02141         }
02142         else {
02143             cpl_msg_error(fctid, "Invalid conversion factor "
02144                           "(ADU to e-): %.2g", conad);
02145             return 1;
02146         }
02147 
02148     }
02149 
02150     cpl_msg_info(fctid, "Bias sigma value: %.3g e-", sigma);
02151 
02152     if (config->noise > 0.) {
02153         cpl_msg_info(fctid, "Noise multiplier: %.3g",
02154                      config->noise);
02155     }
02156     else {
02157         cpl_msg_info(fctid, "Threshold multiplier: %.3g",
02158                      fabs(config->noise));
02159     }
02160 
02161 
02162     /*
02163      * Setup localization start position in the dispersion direction.
02164      */
02165 
02166     nrows = cpl_image_get_size_y(_image);
02167 
02168     if (config->start < 0) {
02169         config->start = nrows / 2;
02170     }
02171 
02172     /*
02173      * Set instrument mode specific parameters like the width of a spectrum
02174      * and the width of the intra-spectrum gap.
02175      */
02176 
02177     mode = giraffe_get_mode(properties);
02178 
02179     if (config->ywidth < 1) {
02180 
02181         cpl_msg_info(fctid, "Configuring equilizing filter width from "
02182                      "instrument mode");
02183 
02184         switch (mode) {
02185             case GIMODE_MEDUSA:
02186                 config->ywidth = 16;
02187                 break;
02188 
02189             case GIMODE_IFU:
02190                 config->ywidth = 6;
02191                 break;
02192 
02193             case GIMODE_ARGUS:
02194                 config->ywidth = 6;
02195                 break;
02196 
02197             default:
02198                 cpl_msg_error(fctid, "Invalid instrument mode!");
02199                 return 1;
02200                 break;
02201         }
02202 
02203 
02204         if (!cpl_propertylist_has(properties, GIALIAS_SLITNAME)) {
02205             cpl_msg_error(fctid, "Property (%s) not found in raw image",
02206                           GIALIAS_SLITNAME);
02207             return 1;
02208         }
02209         else {
02210             const cxchar *slit =
02211                 cpl_propertylist_get_string(properties, GIALIAS_SLITNAME);
02212 
02213             cpl_msg_info(fctid, "Setting equilizing filter to %d [pxl] "
02214                          "for slit configuration `%s'", config->ywidth,
02215                          slit);
02216         }
02217 
02218     }
02219 
02220 
02221     /*
02222      * Set mean spectrum width according to the instrument mode
02223      */
02224 
02225     switch (mode) {
02226         case GIMODE_MEDUSA:
02227             mwidth = GISPECTRUM_MWIDTH_MEDUSA;
02228 
02229             ckwidth = 1;
02230             ckheight = 3;
02231             ckcount = 8;
02232 
02233             break;
02234 
02235         case GIMODE_IFU:
02236             mwidth = GISPECTRUM_MWIDTH_IFU;
02237 
02238             ckwidth = 0;
02239             ckheight = 3;
02240             ckcount = 4;
02241 
02242             break;
02243 
02244         case GIMODE_ARGUS:
02245             mwidth = GISPECTRUM_MWIDTH_IFU;
02246 
02247             ckwidth = 0;
02248             ckheight = 3;
02249             ckcount = 4;
02250 
02251             break;
02252 
02253         default:
02254             cpl_msg_error(fctid, "Invalid instrument mode!");
02255             return 1;
02256             break;
02257     }
02258 
02259 
02260     /*
02261      * Setup localization method
02262      */
02263 
02264     if (config->centroid == TRUE) {
02265         method = GILOCALIZE_BARYCENTER;
02266     }
02267     else {
02268         method = GILOCALIZE_HALF_WIDTH;
02269     }
02270 
02271 
02272     /*
02273      * Fill the parameter structure for the localization mask computation
02274      * with the actual values.
02275      */
02276 
02277     mask_config.ywidth = config->ywidth;
02278     mask_config.local = config->local;
02279     mask_config.threshold = config->noise;
02280     mask_config.ydeg = config->yorder;
02281     mask_config.wdeg = config->worder;
02282     mask_config.ewid = config->ewidth;
02283     mask_config.wavg = mwidth;
02284     mask_config.ckdata.width = ckwidth;
02285     mask_config.ckdata.height = ckheight;
02286     mask_config.ckdata.count = ckcount;
02287     mask_config.sigma = config->sigma;
02288     mask_config.niter = config->iterations;
02289     mask_config.mfrac = config->fraction;
02290     mask_config.start = config->start;
02291     mask_config.retry = config->retries;
02292     mask_config.xbin = config->binsize;
02293 
02294 
02295     /*
02296      * Processing
02297      */
02298 
02299     /*
02300      * Localize spectra. Depending on the setup we either do a full
02301      * localization or we just localize the simultaneous calibration
02302      * fibers using an existing, full master localization.
02303      */
02304 
02305     if (config->full != TRUE) {
02306 
02307         cpl_msg_info(fctid, "Computing spectrum localization using SIWC "
02308                      "spectra");
02309 
02310         if (!master || !master->locy || !master->locy) {
02311             cpl_msg_error(fctid, "Required full master localization is "
02312                           "missing!");
02313             return 1;
02314         }
02315 
02316 
02317         /*
02318          * Select SIWC fibers from the fiber table. The simultaneous
02319          * calibration spectra are indicated by a -1 as retractor position.
02320          */
02321 
02322         cpl_table_unselect_all(_fibers);
02323         cpl_table_or_selected_int(_fibers, "RP", CPL_EQUAL_TO, -1);
02324 
02325         fiber_setup = cpl_table_extract_selected(_fibers);
02326         nfibers = cpl_table_get_nrow(fiber_setup);
02327 
02328     }
02329 
02330 
02331     /*
02332      * Allocate required output matrices and hook them into the appropriate
02333      * structures.
02334      */
02335 
02336     mask_position.type = GIMASK_FITTED_DATA;
02337     mask_position.my = cpl_matrix_new(nrows, nfibers);
02338     mask_position.mw = cpl_matrix_new(nrows, nfibers);
02339 
02340     mask_coeffs.type = GIMASK_FIT_COEFFS;
02341     mask_coeffs.my = cpl_matrix_new(mask_config.ydeg + 1, nfibers);
02342     mask_coeffs.mw = cpl_matrix_new(1, (mask_config.wdeg + 1) *
02343                                     (mask_config.wdeg + 1));
02344 
02345 
02346     /*
02347      * Compute the position of the spectra on the CCD
02348      */
02349 
02350     status = _giraffe_localize_spectra(_image, _bpixel, fiber_setup,
02351                                        method, config->normalize, sigma,
02352                                        &mask_config, &mask_position,
02353                                        &mask_coeffs);
02354 
02355     if (status) {
02356         result->locy = NULL;
02357         result->locw = NULL;
02358         result->locc = NULL;
02359         result->psf = NULL;
02360 
02361         cpl_matrix_delete(mask_position.my);
02362         cpl_matrix_delete(mask_position.mw);
02363 
02364         cpl_matrix_delete(mask_coeffs.my);
02365         cpl_matrix_delete(mask_coeffs.mw);
02366 
02367         if (config->full != TRUE) {
02368             cpl_table_delete(fiber_setup);
02369         }
02370 
02371         cpl_msg_error(fctid, "Spectrum localization computation failed!");
02372 
02373         return 1;
02374     }
02375 
02376 
02377     /*
02378      * Post processing
02379      */
02380 
02381     if (config->full != TRUE) {
02382 
02383         /*
02384          * TBD: Postprocessing of localization. Compare computed spectrum
02385          *      locations with master, i.e. calculate differences.
02386          */
02387 
02388         cpl_table_delete(fiber_setup);
02389 
02390     }
02391     else {
02392 
02393         if (master != NULL && master->locy != NULL) {
02394 
02395             cxint nf = cpl_table_get_nrow(_fibers);
02396 
02397             cxdouble maxoffset = 0.5 * mask_config.wavg;
02398             cxdouble maxshift = 0.;
02399 
02400 
02401             cpl_msg_info(fctid, "Comparing detected and expected fiber "
02402                          "positions.");
02403 
02404             status = _giraffe_finalize_fibers(_fibers, mask_position.my,
02405                                               master->locy, maxoffset,
02406                                               &maxshift);
02407 
02408             if (status != 0) {
02409 
02410                 if (status == -3) {
02411 
02412                     const cpl_image* mlocy = giraffe_image_get(master->locy);
02413                     cxint _nf = cpl_image_get_size_x(mlocy);
02414 
02415                     cpl_msg_error(fctid, "More fibers (%d) than expected "
02416                             "(%d) were found!", nf, _nf);
02417 
02418                 }
02419 
02420                 result->locy = NULL;
02421                 result->locw = NULL;
02422                 result->locc = NULL;
02423                 result->psf = NULL;
02424 
02425                 cpl_matrix_delete(mask_position.my);
02426                 cpl_matrix_delete(mask_position.mw);
02427 
02428                 cpl_matrix_delete(mask_coeffs.my);
02429                 cpl_matrix_delete(mask_coeffs.mw);
02430 
02431                 if (config->full != TRUE) {
02432                     cpl_table_delete(fiber_setup);
02433                 }
02434 
02435                 cpl_msg_error(fctid, "Comparison of fiber positions "
02436                               "failed!");
02437 
02438                 return 1;
02439             }
02440 
02441             cx_assert(cpl_table_get_nrow(_fibers) <= nf);
02442 
02443             cpl_msg_info(fctid, "%d of %d expected fibers were detected.",
02444                          cpl_table_get_nrow(_fibers), nf);
02445 
02446             if (cpl_table_get_nrow(_fibers) < nf) {
02447                 cpl_msg_debug(fctid, "Maximum offset from the expected "
02448                         "position is %.2f, maximum allowed offset is %.2f",
02449                         maxshift, maxoffset);
02450                 cpl_msg_warning(fctid, "%d fibers are missing!",
02451                                 nf - cpl_table_get_nrow(_fibers));
02452             }
02453 
02454         }
02455 
02456     }
02457 
02458 
02459     /*
02460      * Convert matrices into images and tables and add the necessary
02461      * properties.
02462      */
02463 
02464     /* Spectrum center position */
02465 
02466     result->locy =
02467         giraffe_image_create(CPL_TYPE_DOUBLE,
02468                              cpl_matrix_get_ncol(mask_position.my),
02469                              cpl_matrix_get_nrow(mask_position.my));
02470 
02471     giraffe_image_copy_matrix(result->locy, mask_position.my);
02472     cpl_matrix_delete(mask_position.my);
02473 
02474     giraffe_image_set_properties(result->locy, properties);
02475     properties = giraffe_image_get_properties(result->locy);
02476 
02477     _result = giraffe_image_get(result->locy);
02478 
02479     cpl_propertylist_set_int(properties, GIALIAS_NAXIS1,
02480                              cpl_image_get_size_x(_result));
02481     cpl_propertylist_set_int(properties, GIALIAS_NAXIS2,
02482                              cpl_image_get_size_y(_result));
02483     cpl_propertylist_set_int(properties, GIALIAS_BITPIX, -32);
02484     cpl_propertylist_set_double(properties, GIALIAS_BZERO, 0.);
02485     cpl_propertylist_set_double(properties, GIALIAS_BSCALE, 1.);
02486 
02487     cpl_propertylist_append_int(properties, GIALIAS_LOCNX,
02488                                 cpl_image_get_size_y(_result));
02489     cpl_propertylist_append_int(properties, GIALIAS_LOCNS,
02490                                 cpl_image_get_size_x(_result));
02491 
02492     if (config->centroid) {
02493         cpl_propertylist_append_string(properties, GIALIAS_LMETHOD,
02494                                        "BARYCENTER");
02495     }
02496     else {
02497         cpl_propertylist_append_string(properties, GIALIAS_LMETHOD,
02498                                        "HALF_WIDTH");
02499     }
02500 
02501     if (config->normalize) {
02502         cpl_propertylist_append_int(properties, GIALIAS_LNORMALIZE,
02503                                     config->ywidth);
02504     }
02505     else {
02506         cpl_propertylist_append_int(properties, GIALIAS_LNORMALIZE,
02507                                     -config->ywidth);
02508     }
02509 
02510     cpl_propertylist_append_bool(properties, GIALIAS_LFULLLOC, config->full);
02511     cpl_propertylist_append_int(properties, GIALIAS_LOCYDEG, config->yorder);
02512     cpl_propertylist_append_int(properties, GIALIAS_LOCWDEG, config->worder);
02513     cpl_propertylist_append_double(properties, GIALIAS_LEXTRAWID,
02514                                    config->ewidth);
02515     cpl_propertylist_append_double(properties, GIALIAS_LNOISEMULT,
02516                                    config->noise);
02517 
02518     cpl_propertylist_append_double(properties, GIALIAS_LCLIPSIGMA,
02519                                    config->sigma);
02520     cpl_propertylist_append_int(properties, GIALIAS_LCLIPNITER,
02521                                 config->iterations);
02522     cpl_propertylist_append_double(properties, GIALIAS_LCLIPMFRAC,
02523                                    config->fraction);
02524 
02525 
02526     if (cpl_propertylist_has(properties, GIALIAS_GIRFTYPE)) {
02527         cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE, "LOCY");
02528     }
02529     else {
02530         cpl_propertylist_append_string(properties, GIALIAS_GIRFTYPE, "LOCY");
02531     }
02532     cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE, "GIRAFFE "
02533                                  "localization centroid");
02534 
02535 
02536     /* Spectrum width */
02537 
02538     result->locw =
02539         giraffe_image_create(CPL_TYPE_DOUBLE,
02540                              cpl_matrix_get_ncol(mask_position.mw),
02541                              cpl_matrix_get_nrow(mask_position.mw));
02542 
02543     giraffe_image_copy_matrix(result->locw, mask_position.mw);
02544     cpl_matrix_delete(mask_position.mw);
02545 
02546     giraffe_image_set_properties(result->locw, properties);
02547     properties = giraffe_image_get_properties(result->locw);
02548 
02549     _result = giraffe_image_get(result->locw);
02550 
02551     cpl_propertylist_set_int(properties, GIALIAS_NAXIS1,
02552                              cpl_image_get_size_x(_result));
02553     cpl_propertylist_set_int(properties, GIALIAS_NAXIS2,
02554                              cpl_image_get_size_y(_result));
02555 
02556     if (cpl_propertylist_has(properties, GIALIAS_GIRFTYPE)) {
02557         cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE,
02558                                     "LOCWY");
02559     }
02560     else {
02561         cpl_propertylist_append_string(properties, GIALIAS_GIRFTYPE,
02562                                        "LOCWY");
02563     }
02564     cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE, "GIRAFFE "
02565                                  "localization half-width");
02566 
02567 
02568     /* Coefficients table */
02569 
02570     locc = cpl_table_new(cpl_matrix_get_ncol(mask_coeffs.my));
02571 
02572     cpl_table_new_column(locc, "BUTTON", CPL_TYPE_INT);
02573     for (i = 0; i < cpl_table_get_nrow(locc); i++) {
02574         cpl_table_set_int(locc, "BUTTON", i, i);
02575     }
02576 
02577     for (i = 0; i < cpl_matrix_get_nrow(mask_coeffs.my); i++) {
02578         cxchar *label = NULL;
02579 
02580         cx_asprintf(&label, "YC%d", i);
02581         cpl_table_new_column(locc, label, CPL_TYPE_DOUBLE);
02582         cx_free(label);
02583     }
02584 
02585 
02586     result->locc = giraffe_table_create(locc, properties);
02587     cpl_table_delete(locc);
02588 
02589     _my = cpl_matrix_transpose_create(mask_coeffs.my);
02590     giraffe_table_copy_matrix(result->locc, "YC0", _my);
02591     cpl_matrix_delete(_my);
02592     cpl_matrix_delete(mask_coeffs.my);
02593 
02594     properties = giraffe_table_get_properties(result->locc);
02595 
02596 
02597     /* Add coefficients of the 2D fit to the table properties */
02598 
02599     pname = cx_string_new();
02600 
02601     for (i = 0; i < cpl_matrix_get_ncol(mask_coeffs.mw); i++) {
02602         cx_string_sprintf(pname, "%s%d", GIALIAS_LOCWIDCOEF, i);
02603         cpl_propertylist_append_double(properties, cx_string_get(pname),
02604                                        cpl_matrix_get(mask_coeffs.mw, 0, i));
02605     }
02606 
02607     cx_string_delete(pname);
02608     cpl_matrix_delete(mask_coeffs.mw);
02609 
02610     cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE,
02611                                    "LOCYWCHEB");
02612     cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE, "GIRAFFE "
02613                                  "localization fit coefficients");
02614 
02615 
02616     /* Not used */
02617 
02618     result->psf = NULL;
02619 
02620     return 0;
02621 
02622 }
02623 
02624 
02635 GiLocalizeConfig *
02636 giraffe_localize_config_create(cpl_parameterlist *list)
02637 {
02638 
02639     const cxchar *s;
02640     cpl_parameter *p;
02641 
02642     GiLocalizeConfig *config = NULL;
02643 
02644 
02645     if (list == NULL) {
02646         return NULL;
02647     }
02648 
02649     config = cx_calloc(1, sizeof *config);
02650 
02651 
02652     /*
02653      * Some defaults
02654      */
02655 
02656     config->full = TRUE;
02657     config->centroid = TRUE;
02658     config->local = TRUE;
02659 
02660 
02661     p = cpl_parameterlist_find(list, "giraffe.localization.mode");
02662     s = cpl_parameter_get_string(p);
02663     if (strcmp(s, "siwc") == 0) {
02664         config->full = FALSE;
02665     }
02666 
02667     p = cpl_parameterlist_find(list, "giraffe.localization.start");
02668     config->start = cpl_parameter_get_int(p);
02669 
02670     p = cpl_parameterlist_find(list, "giraffe.localization.retries");
02671     config->retries = cpl_parameter_get_int(p);
02672 
02673     p = cpl_parameterlist_find(list, "giraffe.localization.binsize");
02674     config->binsize = cpl_parameter_get_int(p);
02675 
02676     p = cpl_parameterlist_find(list, "giraffe.localization.ewidth");
02677     config->ewidth = cpl_parameter_get_double(p);
02678 
02679     p = cpl_parameterlist_find(list, "giraffe.localization.ywidth");
02680     config->ywidth = cpl_parameter_get_int(p);
02681 
02682     p = cpl_parameterlist_find(list, "giraffe.localization.center");
02683     s = cpl_parameter_get_string(p);
02684     if (!strcmp(s, "hwidth")) {
02685         config->centroid = FALSE;
02686     }
02687 
02688     p = cpl_parameterlist_find(list, "giraffe.localization.normalize");
02689     config->normalize = cpl_parameter_get_bool(p);
02690 
02691     p = cpl_parameterlist_find(list, "giraffe.localization.threshold");
02692     s = cpl_parameter_get_string(p);
02693     if (!strcmp(s, "global")) {
02694         config->local = FALSE;
02695     }
02696 
02697     p = cpl_parameterlist_find(list, "giraffe.localization.noise");
02698     config->noise = cpl_parameter_get_double(p);
02699 
02700     p = cpl_parameterlist_find(list, "giraffe.localization.ron");
02701     config->ron = cpl_parameter_get_double(p);
02702 
02703     p = cpl_parameterlist_find(list, "giraffe.localization.yorder");
02704     config->yorder = cpl_parameter_get_int(p);
02705 
02706     p = cpl_parameterlist_find(list, "giraffe.localization.worder");
02707     config->worder = cpl_parameter_get_int(p);
02708 
02709     p = cpl_parameterlist_find(list, "giraffe.localization.sigma");
02710     config->sigma = cpl_parameter_get_double(p);
02711 
02712     p = cpl_parameterlist_find(list, "giraffe.localization.iterations");
02713     config->iterations = cpl_parameter_get_int(p);
02714 
02715     p = cpl_parameterlist_find(list, "giraffe.localization.fraction");
02716     config->fraction = cpl_parameter_get_double(p);
02717 
02718     return config;
02719 
02720 }
02721 
02722 
02735 void
02736 giraffe_localize_config_destroy(GiLocalizeConfig *config)
02737 {
02738 
02739     if (config) {
02740         cx_free(config);
02741     }
02742 
02743     return;
02744 
02745 }
02746 
02747 
02759 void
02760 giraffe_localize_config_add(cpl_parameterlist *list)
02761 {
02762 
02763     cpl_parameter *p;
02764 
02765 
02766     if (list == NULL) {
02767         return;
02768     }
02769 
02770     p = cpl_parameter_new_enum("giraffe.localization.mode",
02771                                CPL_TYPE_STRING,
02772                                "Localization mode: Use all spectra "
02773                                "or the 5 SIWC spectra",
02774                                "giraffe.localization",
02775                                "all", 2, "all", "siwc");
02776     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-mode");
02777     cpl_parameterlist_append(list, p);
02778 
02779 
02780     p = cpl_parameter_new_value("giraffe.localization.start",
02781                                 CPL_TYPE_INT,
02782                                 "Bin along x-axis",
02783                                 "giraffe.localization",
02784                                 -1);
02785     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-start");
02786     cpl_parameterlist_append(list, p);
02787 
02788 
02789     p = cpl_parameter_new_value("giraffe.localization.retries",
02790                                 CPL_TYPE_INT,
02791                                 "Initial localization detection "
02792                                 "xbin retries.",
02793                                 "giraffe.localization",
02794                                 10);
02795     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-retries");
02796     cpl_parameterlist_append(list, p);
02797 
02798 
02799     p = cpl_parameter_new_value("giraffe.localization.binsize",
02800                                 CPL_TYPE_INT,
02801                                 "Initial localization detection "
02802                                 "xbin size.",
02803                                 "giraffe.localization",
02804                                 -1);
02805     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-binsize");
02806     cpl_parameterlist_append(list, p);
02807 
02808 
02809     p = cpl_parameter_new_value("giraffe.localization.ewidth",
02810                                 CPL_TYPE_DOUBLE,
02811                                 "Localization detection extra width.",
02812                                 "giraffe.localization",
02813                                 1.0);
02814     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-ewidth");
02815     cpl_parameterlist_append(list, p);
02816 
02817 
02818     p = cpl_parameter_new_value("giraffe.localization.ywidth",
02819                                 CPL_TYPE_INT,
02820                                 "Full width [pxl] of the equilizing "
02821                                 "filter (distance between two "
02822                                 "adjacent fibers).",
02823                                 "giraffe.localization",
02824                                 -1);
02825     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-ywidth");
02826     cpl_parameterlist_append(list, p);
02827 
02828 
02829     p = cpl_parameter_new_enum("giraffe.localization.center",
02830                                CPL_TYPE_STRING,
02831                                "Method used for mask center "
02832                                "computation.",
02833                                "giraffe.localization",
02834                                "centroid", 2, "centroid",
02835                                "hwidth");
02836     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-center");
02837     cpl_parameterlist_append(list, p);
02838 
02839 
02840     p = cpl_parameter_new_value("giraffe.localization.normalize",
02841                                 CPL_TYPE_BOOL,
02842                                 "Enable spectrum normalization along "
02843                                 "the dispersion axis.",
02844                                 "giraffe.localization",
02845                                 FALSE);
02846     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-norm");
02847     cpl_parameterlist_append(list, p);
02848 
02849 
02850     p = cpl_parameter_new_value("giraffe.localization.noise",
02851                                 CPL_TYPE_DOUBLE,
02852                                 "Threshold multiplier.",
02853                                 "giraffe.localization",
02854                                 7.0);
02855     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-noise");
02856     cpl_parameterlist_append(list, p);
02857 
02858 
02859     p = cpl_parameter_new_enum("giraffe.localization.threshold",
02860                                CPL_TYPE_STRING,
02861                                "Selects thresholding algorithm: local or "
02862                                "global",
02863                                "giraffe.localization",
02864                                "local", 2, "local", "global");
02865     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-threshold");
02866     cpl_parameterlist_append(list, p);
02867 
02868 
02869     p = cpl_parameter_new_value("giraffe.localization.ron",
02870                                 CPL_TYPE_DOUBLE,
02871                                 "New bias sigma (RON) value for dark "
02872                                 "subtraction",
02873                                 "giraffe.localization",
02874                                 -1.);
02875     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-ron");
02876     cpl_parameterlist_append(list, p);
02877 
02878 
02879     p = cpl_parameter_new_value("giraffe.localization.yorder",
02880                                 CPL_TYPE_INT,
02881                                 "Order of Chebyshev polynomial fit.",
02882                                 "giraffe.localization",
02883                                 4);
02884     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-yorder");
02885     cpl_parameterlist_append(list, p);
02886 
02887 
02888     p = cpl_parameter_new_value("giraffe.localization.worder",
02889                                 CPL_TYPE_INT,
02890                                 "Order of Chebyshev 2D polynomial fit.",
02891                                 "giraffe.localization",
02892                                 2);
02893     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-worder");
02894     cpl_parameterlist_append(list, p);
02895 
02896 
02897     p = cpl_parameter_new_value("giraffe.localization.sigma",
02898                                 CPL_TYPE_DOUBLE,
02899                                 "Localization clipping: sigma threshold "
02900                                 "factor",
02901                                 "giraffe.localization",
02902                                 2.5);
02903     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-sigma");
02904     cpl_parameterlist_append(list, p);
02905 
02906 
02907     p = cpl_parameter_new_value("giraffe.localization.iterations",
02908                                 CPL_TYPE_INT,
02909                                 "Localization clipping: number of "
02910                                 "iterations",
02911                                 "giraffe.localization",
02912                                 5);
02913     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-niter");
02914     cpl_parameterlist_append(list, p);
02915 
02916 
02917     p = cpl_parameter_new_range("giraffe.localization.fraction",
02918                                 CPL_TYPE_DOUBLE,
02919                                 "Localization clipping: minimum fraction "
02920                                 "of points accepted/total.",
02921                                 "giraffe.localization",
02922                                 0.9, 0.0, 1.0);
02923     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-mfrac");
02924     cpl_parameterlist_append(list, p);
02925 
02926     return;
02927 
02928 }

This file is part of the GIRAFFE Pipeline Reference Manual 2.8.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Tue Jun 2 07:15:34 2009 by doxygen 1.5.1 written by Dimitri van Heesch, © 1997-2004