GIRAFFE Pipeline Reference Manual

giextract.c

00001 /* $Id: giextract.c,v 1.32.2.1 2008/02/21 10:52: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: 2008/02/21 10:52:40 $
00024  * $Revision: 1.32.2.1 $
00025  * $Name: giraffe-2_5_1 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #  include <config.h>
00030 #endif
00031 
00032 #include <math.h>
00033 #include <float.h>
00034 
00035 #include <cxmemory.h>
00036 #include <cxstring.h>
00037 #include <cxstrutils.h>
00038 
00039 #include <cpl_parameterlist.h>
00040 #include <cpl_matrix.h>
00041 #include <cpl_table.h>
00042 #include <cpl_msg.h>
00043 
00044 #include "gimacros.h"
00045 #include "gialias.h"
00046 #include "giclip.h"
00047 #include "giarray.h"
00048 #include "giimage.h"
00049 #include "gimatrix.h"
00050 #include "giwindow.h"
00051 #include "gipsfdata.h"
00052 #include "gimodel.h"
00053 #include "gimath.h"
00054 #include "gilocalization.h"
00055 #include "gimessages.h"
00056 #include "gifiberutils.h"
00057 #include "giutils.h"
00058 #include "giextract.h"
00059 
00060 #define HORNE_PURE_METHOD
00061 
00062 
00071 enum GiProfileId {
00072     PROFILE_PSFEXP   = 1 << 1,
00073     PROFILE_PSFEXP2  = 1 << 2,
00074     PROFILE_GAUSSIAN = 1 << 3
00075 };
00076 
00077 typedef enum GiProfileId GiProfileId;
00078 
00079 
00080 /*
00081  * Optimal spectrum extraction algorithm configuration data
00082  */
00083 
00084 struct GiExtractOptimalConfig {
00085 
00086     GiClipParams clip;
00087 
00088     cxbool limits;
00089 
00090     cxint bkgorder;
00091 
00092     cxdouble exptime;
00093     cxdouble ron;
00094     cxdouble dark;
00095     cxdouble ewidth;
00096 };
00097 
00098 typedef struct GiExtractOptimalConfig GiExtractOptimalConfig;
00099 
00100 
00101 /*
00102  * Original Horne spectrum extraction algorithm configuration data
00103  */
00104 
00105 struct GiExtractHorneConfig {
00106     GiClipParams clip;
00107 
00108     cxdouble exptime;
00109     cxdouble ron;
00110     cxdouble dark;
00111     cxdouble ewidth;
00112 };
00113 
00114 typedef struct GiExtractHorneConfig GiExtractHorneConfig;
00115 
00116 
00117 struct GiExtractionData {
00118     cxdouble value;
00119     cxdouble error;
00120     cxdouble position;
00121     cxdouble npixels;
00122 };
00123 
00124 typedef struct GiExtractionData GiExtractionData;
00125 
00126 
00127 struct GiExtractionSlice {
00128     cxint fsize;
00129     cxint msize;
00130 
00131     cxint nflx;
00132     cxint nbkg;
00133 
00134     cpl_matrix* flux;
00135     cpl_matrix* variance;
00136     cpl_matrix* model;
00137 };
00138 
00139 typedef struct GiExtractionSlice GiExtractionSlice;
00140 
00141 
00142 struct GiExtractionPsfLimits {
00143     cxint size;
00144 
00145     cxint* ymin;
00146     cxint* ymax;
00147 };
00148 
00149 typedef struct GiExtractionPsfLimits GiExtractionPsfLimits;
00150 
00151 
00152 struct GiExtractionWorkspace {
00153     cpl_matrix* atw;
00154     cpl_matrix* atwa;
00155     cpl_matrix* atws;
00156     cpl_matrix* c;
00157     cpl_matrix* tmp;
00158 };
00159 
00160 typedef struct GiExtractionWorkspace GiExtractionWorkspace;
00161 
00162 
00163 struct GiVirtualSlit {
00164     cxint width;
00165 
00166     cxdouble center;
00167     cxdouble extra_width;
00168 
00169     cxdouble* position;
00170     cxdouble* signal;
00171     cxdouble* variance;
00172     cxdouble* fraction;
00173 
00174     cxint* mask;
00175     cxint* offset;
00176 };
00177 
00178 typedef struct GiVirtualSlit GiVirtualSlit;
00179 
00180 
00181 /*
00182  * Extraction slice implementation
00183  */
00184 
00185 inline static GiExtractionSlice*
00186 _giraffe_extractionslice_new(cxint nflx, cxint ndata, cxint nbkg)
00187 {
00188 
00189     GiExtractionSlice* self = cx_malloc(sizeof *self);
00190 
00191     self->nflx = nflx;
00192     self->nbkg = nbkg;
00193 
00194     self->fsize = nflx + nbkg;
00195     self->msize = ndata;
00196 
00197     self->flux = cpl_matrix_new(self->fsize, 1);
00198     self->variance = cpl_matrix_new(self->fsize, 1);
00199     self->model = cpl_matrix_new(self->msize, 1);
00200 
00201     return self;
00202 
00203 }
00204 
00205 
00206 inline static void
00207 _giraffe_extractionslice_delete(GiExtractionSlice* self)
00208 {
00209 
00210     if (self != NULL) {
00211         if (self->model != NULL) {
00212             cpl_matrix_delete(self->model);
00213             self->model = NULL;
00214         }
00215 
00216         if (self->variance != NULL) {
00217             cpl_matrix_delete(self->variance);
00218             self->variance = NULL;
00219         }
00220 
00221         if (self->flux != NULL) {
00222             cpl_matrix_delete(self->flux);
00223             self->flux = NULL;
00224         }
00225 
00226         cx_free(self);
00227     }
00228 
00229     return;
00230 
00231 }
00232 
00233 
00234 inline static GiExtractionPsfLimits*
00235 _giraffe_extraction_psflimits_new(cxint size)
00236 {
00237 
00238     GiExtractionPsfLimits* self = cx_malloc(sizeof *self);
00239 
00240     self->size = size;
00241 
00242     self->ymin = cx_calloc(self->size, sizeof(cxint));
00243     self->ymax = cx_calloc(self->size, sizeof(cxint));
00244 
00245     return self;
00246 
00247 }
00248 
00249 
00250 inline static void
00251 _giraffe_extraction_psflimits_delete(GiExtractionPsfLimits* self)
00252 {
00253 
00254     if (self != NULL) {
00255         if (self->ymin != NULL) {
00256             cx_free(self->ymin);
00257         }
00258 
00259         if (self->ymax != NULL) {
00260             cx_free(self->ymax);
00261         }
00262 
00263         cx_free(self);
00264     }
00265 
00266     return;
00267 
00268 }
00269 
00270 
00271 inline static GiExtractionWorkspace*
00272 _giraffe_optimal_workspace_new(cxint m, cxint n)
00273 {
00274 
00275     GiExtractionWorkspace* self = cx_malloc(sizeof *self);
00276 
00277 
00278     self->atw  = cpl_matrix_new(m, n);
00279     self->atwa = cpl_matrix_new(m, m);
00280     self->c    = cpl_matrix_new(m, m);
00281     self->atws = cpl_matrix_new(m, 1);
00282 
00283     self->tmp  = cpl_matrix_new(m, m);
00284 
00285     return self;
00286 
00287 }
00288 
00289 
00290 inline static void
00291 _giraffe_optimal_workspace_delete(GiExtractionWorkspace* self)
00292 {
00293 
00294     if (self != NULL) {
00295         if (self->atws != NULL) {
00296             cpl_matrix_delete(self->atws);
00297         }
00298 
00299         if (self->atwa != NULL) {
00300             cpl_matrix_delete(self->atwa);
00301         }
00302 
00303         if (self->c != NULL) {
00304             cpl_matrix_delete(self->c);
00305         }
00306 
00307         if (self->atw != NULL) {
00308             cpl_matrix_delete(self->atw);
00309         }
00310 
00311         if (self->tmp != NULL) {
00312             cpl_matrix_delete(self->tmp);
00313         }
00314 
00315         cx_free(self);
00316 
00317     }
00318 
00319     return;
00320 
00321 }
00322 
00323 
00324 /*
00325  * Virtual slit implementation
00326  */
00327 
00328 inline static void
00329 _giraffe_virtualslit_allocate(GiVirtualSlit* self)
00330 {
00331 
00332     if ((self != NULL) && (self->width > 0)) {
00333 
00334         self->position = cx_calloc(self->width, sizeof(cxdouble));
00335         self->signal = cx_calloc(self->width, sizeof(cxdouble));
00336         self->variance = cx_calloc(self->width, sizeof(cxdouble));
00337         self->fraction = cx_calloc(self->width, sizeof(cxdouble));
00338 
00339         self->mask = cx_calloc(self->width, sizeof(cxdouble));
00340         self->offset = cx_calloc(self->width, sizeof(cxdouble));
00341 
00342     }
00343 
00344     return;
00345 
00346 }
00347 
00348 
00349 inline static GiVirtualSlit*
00350 _giraffe_virtualslit_new(cxdouble extra_width)
00351 {
00352 
00353     GiVirtualSlit* self = cx_calloc(1, sizeof *self);
00354 
00355     self->width = 0;
00356     self->center = 0.;
00357     self->extra_width = extra_width;
00358 
00359     self->position = NULL;
00360     self->signal = NULL;
00361     self->variance = NULL;
00362     self->fraction = NULL;
00363     self->mask = NULL;
00364     self->offset = NULL;
00365 
00366     return self;
00367 
00368 }
00369 
00370 
00371 inline static void
00372 _giraffe_virtualslit_clear(GiVirtualSlit* self)
00373 {
00374 
00375     if (self != NULL) {
00376 
00377         if (self->position != NULL) {
00378             cx_free(self->position);
00379             self->position = NULL;
00380         }
00381 
00382         if (self->signal != NULL) {
00383             cx_free(self->signal);
00384             self->signal = NULL;
00385         }
00386 
00387         if (self->variance != NULL) {
00388             cx_free(self->variance);
00389             self->variance = NULL;
00390         }
00391 
00392         if (self->fraction != NULL) {
00393             cx_free(self->fraction);
00394             self->fraction = NULL;
00395         }
00396 
00397         if (self->mask != NULL) {
00398             cx_free(self->mask);
00399             self->mask = NULL;
00400         }
00401 
00402         if (self->offset != NULL) {
00403             cx_free(self->offset);
00404             self->offset = NULL;
00405         }
00406 
00407         self->extra_width = 0.;
00408         self->center = 0.;
00409         self->width = 0;
00410 
00411     }
00412 
00413     return;
00414 
00415 }
00416 
00417 
00418 inline static void
00419 _giraffe_virtualslit_delete(GiVirtualSlit* self)
00420 {
00421 
00422     if (self != NULL) {
00423         _giraffe_virtualslit_clear(self);
00424 
00425         cx_free(self);
00426         self = NULL;
00427     }
00428 
00429     return;
00430 
00431 }
00432 
00433 
00434 inline static cxint
00435 _giraffe_virtualslit_setup(GiVirtualSlit* self, cxint bin,
00436                            cxdouble center, cxdouble width,
00437                            const cpl_image* signal, const cpl_image* variance,
00438                            const cpl_image* bpixel)
00439 {
00440 
00441     register cxint ny = cpl_image_get_size_x(signal);
00442     register cxint offset = bin * cpl_image_get_size_x(signal);
00443 
00444     register cxdouble lower = center - (width + self->extra_width);
00445     register cxdouble upper = center + (width + self->extra_width);
00446 
00447     register cxint first = (cxint) floor(lower);
00448     register cxint last = (cxint) ceil(upper);
00449 
00450     const cxdouble* s = cpl_image_get_data_double_const(signal);
00451     const cxdouble* v = cpl_image_get_data_double_const(variance);
00452 
00453 
00454     /*
00455      * Upper, lower border and width of the virtual slit
00456      */
00457 
00458     lower = CX_MAX(0., lower);
00459     upper = CX_MIN(ny, upper);
00460 
00461     first = CX_MAX(0, first);
00462     last = CX_MIN(ny, last);
00463 
00464     self->center = center;
00465     self->width = last - first + 1;
00466 
00467 
00468     /*
00469      * Create and fill the buffers
00470      */
00471 
00472     _giraffe_virtualslit_allocate(self);
00473 
00474     if (bpixel != NULL) {
00475 
00476         register cxint k = 0;
00477         register cxint y = 0;
00478 
00479         const cxint* _bpixel = cpl_image_get_data_int_const(bpixel);
00480 
00481 
00482         for (y = first; y <= last; y++) {
00483 
00484             register cxint ypos = offset + y;
00485 
00486             cxint ok = (_bpixel[ypos] & GIR_M_PIX_SET) == 0 ? 1 : 0;
00487 
00488 
00489             self->position[k] = y - center;
00490             self->fraction[k]  = 1.;
00491 
00492             self->signal[k] = s[ypos];
00493             self->variance[k] = v[ypos];
00494 
00495             self->mask[k] = ok;
00496             self->offset[k] = ypos;
00497             ++k;
00498 
00499         }
00500 
00501     }
00502     else {
00503 
00504         register cxint k = 0;
00505         register cxint y = 0;
00506 
00507 
00508         for (y = first; y <= last; y++) {
00509 
00510             register cxint ypos = offset + y;
00511 
00512             cxint ok = 1;
00513 
00514 
00515             self->position[k] = y - center;
00516             self->fraction[k]  = 1.;
00517 
00518             self->signal[k] = s[ypos];
00519             self->variance[k] = v[ypos];
00520 
00521             self->mask[k] = ok;
00522             self->offset[k] = ypos;
00523             ++k;
00524 
00525         }
00526 
00527     }
00528 
00529 
00530     /*
00531      * Correct for pixel fractions at the borders of the
00532      * virtual slit, since they have been set to the full
00533      * pixel in the above loop.
00534      */
00535 
00536     self->fraction[0] = ((cxdouble)first + 1.) - lower;
00537     self->fraction[self->width - 1] = upper - ((cxdouble)last - 1.);
00538 
00539     return self->width;
00540 
00541 }
00542 
00543 
00544 /*
00545  * Compute the inverse of a square matrix
00546  */
00547 
00548 inline static cxint
00549 _giraffe_matrix_invert(cpl_matrix* m_inv, const cpl_matrix* m, cpl_matrix* lu)
00550 {
00551 
00552     cxint i = 0;
00553     cxint status = 0;
00554     cxint n = cpl_matrix_get_ncol(m);
00555 
00556     register cxint sz = n * n * sizeof(cxdouble);
00557     register cxint* perm = cx_malloc(n * sizeof(cxint));
00558 
00559     const cxdouble* _m = cpl_matrix_get_data_const(m);
00560 
00561     cxdouble* _m_inv = cpl_matrix_get_data(m_inv);
00562     cxdouble* _m_lu = cpl_matrix_get_data(lu);
00563 
00564 
00565     memset(_m_inv, 0, sz);
00566     memcpy(_m_lu, _m, sz);
00567 
00568     if (cpl_matrix_decomp_lu(lu, perm, &i) != 0) {
00569         cx_free(perm);
00570         return 1;
00571     }
00572 
00573 
00574     /*
00575      * Create an identity matrix with the rows permuted
00576      */
00577 
00578     for (i = 0; i < n; ++i) {
00579         _m_inv[i * n + perm[i]] = 1.;
00580     }
00581 
00582     cx_free(perm);
00583 
00584 
00585     status = cpl_matrix_solve_lu(lu, m_inv, NULL);
00586 
00587     if (status != 0) {
00588         cpl_matrix_delete(m_inv);
00589         return 2;
00590     }
00591 
00592     return 0;
00593 
00594 }
00595 
00596 
00597 /*
00598  * Compute the PSF profile for a set of abscissa values.
00599  */
00600 
00601 inline static cpl_matrix*
00602 _giraffe_compute_psf(GiModel* psf, const cpl_matrix* x)
00603 {
00604 
00605     register cxint i = 0;
00606     register cxint n = 0;
00607 
00608     cxint status = 0;
00609 
00610     const cxdouble* _x = NULL;
00611 
00612     cxdouble* _y = NULL;
00613 
00614     cpl_matrix* y = NULL;
00615 
00616     cx_assert(psf != NULL);
00617     cx_assert(x != NULL);
00618     cx_assert(cpl_matrix_get_ncol(x) == 1);
00619 
00620     n = cpl_matrix_get_nrow(x);
00621 
00622     y = cpl_matrix_new(n, 1);
00623 
00624     _x = cpl_matrix_get_data_const(x);
00625     _y = cpl_matrix_get_data(y);
00626 
00627     for (i = 0; i < n; i++) {
00628         giraffe_model_set_argument(psf, "x", _x[i]);
00629         giraffe_model_evaluate(psf, &_y[i], &status);
00630 
00631         if (status != 0) {
00632             cpl_matrix_delete(y);
00633             return NULL;
00634         }
00635     }
00636 
00637     return y;
00638 
00639 }
00640 
00641 
00642 /*
00643  * Horne extraction of a single wavelength bin for the given virtual
00644  * slit.
00645  */
00646 
00647 inline static cxint
00648 _giraffe_horne_extract_slit(GiExtractionData* result,
00649                             const GiVirtualSlit* vslit, GiModel* psf,
00650                             const GiExtractHorneConfig* config)
00651 {
00652 
00653     cxint i = 0;
00654     cxint iteration = 0;
00655     cxint ngood = 0;
00656     cxint nreject = -1;
00657     cxint niter = config->clip.iterations;
00658     cxint nmin = (cxint)config->clip.fraction;
00659 
00660     cxdouble sigma = config->clip.level * config->clip.level;
00661     cxdouble var = 0.;
00662     cxdouble bkg = 0.;
00663     cxdouble flx = 0.;
00664     cxdouble norm = 0.;
00665     cxdouble u = 0.;
00666     cxdouble v = 0.;
00667     cxdouble w = 0.;
00668     cxdouble fs = 0.;
00669     cxdouble fp = 0.;
00670     cxdouble* tdata = NULL;
00671     cxdouble* _mnpsf = NULL;
00672     cxdouble* variance = NULL;
00673 
00674     cpl_matrix* mnpsf = NULL;
00675     cpl_matrix* mvslit = NULL;
00676 
00677 
00678 
00679     /*
00680      * Compute the PSF model.
00681      */
00682 
00683     mvslit = cpl_matrix_wrap(vslit->width, 1, vslit->position);
00684     mnpsf = _giraffe_compute_psf(psf, mvslit);
00685 
00686     cpl_matrix_unwrap(mvslit);
00687     mvslit = NULL;
00688 
00689     if (mnpsf == NULL) {
00690         return -1;
00691     }
00692 
00693 
00694     /*
00695      * Enforce positivity and normalization of the profile model.
00696      * Determine the number of valid pixels
00697      */
00698 
00699     _mnpsf = cpl_matrix_get_data(mnpsf);
00700 
00701     norm = 0.;
00702     ngood = 0;
00703 
00704     for (i = 0; i < vslit->width; ++i) {
00705         _mnpsf[i] = CX_MAX(_mnpsf[i], 0.);
00706         norm += _mnpsf[i];
00707         ngood += vslit->mask[i];
00708     }
00709 
00710     for (i = 0; i < vslit->width; ++i) {
00711         _mnpsf[i] /= norm;
00712     }
00713 
00714 
00715     /*
00716      * Allocate buffer for variance and profile computation
00717      */
00718 
00719     variance = cx_calloc(vslit->width, sizeof(cxdouble));
00720 
00721 
00722     /*
00723      * Estimate background
00724      */
00725 
00726     tdata = cx_malloc(vslit->width * sizeof(cxdouble));
00727 
00728     i = 0;
00729     ngood = 0;
00730 
00731     while (i < vslit->width) {
00732         if (vslit->mask[i] > 0) {
00733             tdata[i] = CX_MAX(vslit->signal[i], 0.);
00734             ++ngood;
00735         }
00736         ++i;
00737     }
00738 
00739     if (ngood > 0) {
00740         giraffe_array_sort(tdata, ngood);
00741         bkg = 0.5 * (tdata[0] + tdata[1]);
00742     }
00743 
00744     cx_free(tdata);
00745     tdata = NULL;
00746 
00747 
00748     /*
00749      * Compute standard extraction flux
00750      */
00751 
00752     norm = 0.;
00753     flx = 0.;
00754 
00755     for (i = 0; i < vslit->width; ++i) {
00756         if (vslit->mask[i] != 0) {
00757             flx += (vslit->signal[i] - bkg) * vslit->fraction[i];
00758             norm += vslit->fraction[i] * _mnpsf[i];
00759         }
00760     }
00761 
00762 
00763     /*
00764      * Compute expected profile and initial variance
00765      */
00766 
00767     for (i = 0; i < vslit->width; ++i) {
00768 
00769         register cxdouble _flx = flx * vslit->fraction[i] * _mnpsf[i] / norm;
00770 
00771         variance[i] = vslit->variance[i] + _flx + bkg;
00772 
00773     }
00774 
00775 
00776 #if defined(HORNE_PURE_METHOD)
00777 
00778     /*
00779      * Reject cosmics and extract spectrum
00780      */
00781 
00782     nreject = -1;
00783 
00784     while ((iteration < niter) && (ngood > nmin) && (nreject != 0)) {
00785 
00786         cxint imax = 0;
00787 
00788         cxdouble _flx = 0.;
00789         cxdouble mmax = 0.;
00790 
00791 
00792         norm = 0.;
00793         var = 0.;
00794         nreject = 0;
00795 
00796         for (i = 0; i < vslit->width; ++i) {
00797 
00798             if (vslit->mask[i] != 0) {
00799 
00800                 register cxdouble data = vslit->signal[i] - bkg;
00801                 register cxdouble p   = _mnpsf[i];
00802 
00803                 norm += p * p / variance[i];
00804                 _flx += p * data / variance[i];
00805                 var  += p;
00806 
00807             }
00808 
00809         }
00810 
00811         flx = _flx / norm;
00812         var /= norm;
00813 
00814 
00815         /*
00816          * Reject cosmics
00817          */
00818 
00819         for (i = 0; i < vslit->width; ++i) {
00820 
00821             if (vslit->mask[i] != 0) {
00822 
00823                 cxdouble m = vslit->signal[i] - bkg - flx * _mnpsf[i];
00824 
00825                 variance[i] = vslit->variance[i] + fabs(flx * _mnpsf[i] + bkg);
00826 
00827                 m *= m / variance[i] ;
00828                 if (m > mmax) {
00829                     mmax = m;
00830                     imax = i;
00831                 }
00832 
00833             }
00834 
00835         }
00836 
00837         if ((sigma > 0.) && (mmax > sigma)) {
00838             vslit->mask[imax] = 0;
00839             ++nreject;
00840             --ngood;
00841         }
00842 
00843         ++iteration;
00844 
00845     }
00846 
00847 #else
00848 
00849     while ((iteration < niter) && (ngood > nmin) && (nreject != 0)) {
00850 
00851         cxint imax = 0;
00852 
00853         cxdouble mmax = 0.;
00854 
00855 
00856         nreject = 0;
00857         var = 0.;
00858 
00859         u = 0.;
00860         v = 0.;
00861         w = 0.;
00862         fs = 0.;
00863         fp = 0.;
00864 
00865         for (i = 0; i < vslit->width; ++i) {
00866 
00867             if (vslit->mask[i] != 0) {
00868 
00869                 register cxdouble p = _mnpsf[i];
00870                 register cxdouble signal = vslit->signal[i];
00871                 register cxdouble weight = 1. / variance[i];
00872 
00873                 u += weight;
00874                 v += p * weight;
00875                 w += p * p * weight;
00876 
00877                 fs += signal * weight;
00878                 fp += p * signal * weight;
00879 
00880             }
00881 
00882         }
00883 
00884         norm = u * w - v * v;
00885         flx = (u * fp - v * fs) / norm;
00886         bkg = (w * fs - v * fp) / norm;
00887 
00888         var = u / norm;
00889 
00890         for (i = 0; i < vslit->width; ++i) {
00891 
00892             if (vslit->mask[i] != 0) {
00893 
00894                 cxdouble m = (vslit->signal[i] - bkg - flx * _mnpsf[i]);
00895 
00896                 variance[i] = vslit->variance[i] + fabs(flx * _mnpsf[i] + bkg);
00897 
00898                 m *= m / variance[i] ;
00899                 if (m > mmax) {
00900                     mmax = m;
00901                     imax = i;
00902                 }
00903 
00904             }
00905 
00906         }
00907 
00908         if ((sigma > 0.) && (mmax > sigma)) {
00909             vslit->mask[imax] = 0;
00910             ++nreject;
00911             --ngood;
00912         }
00913 
00914     }
00915 
00916 #endif
00917 
00918     cx_free(variance);
00919     variance = NULL;
00920 
00921     cpl_matrix_delete(mnpsf);
00922     mnpsf = NULL;
00923 
00924     result->value = flx;
00925     result->error = sqrt(var);
00926     result->position = vslit->center;
00927     result->npixels = ngood;
00928 
00929     return 0;
00930 
00931 }
00932 
00933 
00934 inline static cxint
00935 _giraffe_optimal_extract_slice(GiExtractionSlice* slice,
00936                                const cpl_matrix* AT,
00937                                const cpl_matrix* S,
00938                                const cpl_matrix* W,
00939                                GiExtractionPsfLimits* limits,
00940                                GiExtractionWorkspace* ws)
00941 {
00942 
00943     register cxint i = 0;
00944     register cxint n = cpl_matrix_get_ncol(AT);
00945     register cxint m = cpl_matrix_get_nrow(AT);
00946 
00947     cxint status = 0;
00948 
00949     const cxdouble* at = cpl_matrix_get_data_const(AT);
00950     const cxdouble* w = cpl_matrix_get_data_const(W);
00951     const cxdouble* s = cpl_matrix_get_data_const(S);
00952     const cxdouble* c = cpl_matrix_get_data_const(ws->c);
00953 
00954     cxdouble* atw = cpl_matrix_get_data(ws->atw);
00955     cxdouble* atwa = cpl_matrix_get_data(ws->atwa);
00956     cxdouble* atws = cpl_matrix_get_data(ws->atws);
00957     cxdouble* sf = cpl_matrix_get_data(slice->flux);
00958     cxdouble* sv = cpl_matrix_get_data(slice->variance);
00959     cxdouble* sm = cpl_matrix_get_data(slice->model);
00960 
00961 
00962     for (i = 0; i < m; ++i) {
00963 
00964         register cxint j = 0;
00965         register cxint im = i * m;
00966         register cxint in = i * n;
00967         register cxint ymin = limits->ymin[i];
00968         register cxint ymax = limits->ymax[i];
00969 
00970 
00971         atws[i] = 0.;
00972 
00973         for (j = 0; j < n; ++j) {
00974 
00975             register cxint k = in + j;
00976 
00977 
00978             atw[k] = w[j] * at[k];
00979             atws[i] += atw[k] * s[j];
00980 
00981         }
00982 
00983         for (j = 0; j < i; ++j) {
00984 
00985             register cxint k = 0;
00986             register cxint l = im + j;
00987 
00988             atwa[l] = 0.;
00989             for (k = ymin; k < ymax; ++k) {
00990                 atwa[l] += atw[in + k] * at[j * n + k];
00991             }
00992 
00993             atwa[j * m + i] = atwa[l];
00994 
00995         }
00996 
00997         atwa[im + i] = 0.;
00998 
00999         for (j = ymin; j < ymax; ++j) {
01000             atwa[im + i] += atw[in + j] * at[in + j];
01001         }
01002 
01003     }
01004 
01005 
01006     status = _giraffe_matrix_invert(ws->c, ws->atwa, ws->tmp);
01007 
01008     if (status != 0) {
01009         return 1;
01010     }
01011 
01012     for (i = 0; i < m; ++i) {
01013 
01014         register cxint j = 0;
01015         register cxint im = i * m;
01016 
01017 
01018         sf[i] = 0.;
01019         sv[i] = c[im + i];
01020 
01021         for (j = 0; j < m; ++j) {
01022             sf[i] += c[im + j] * atws[j];
01023         }
01024 
01025     }
01026 
01027     for (i = 0; i < n; ++i) {
01028 
01029         register cxint j = 0;
01030 
01031 
01032         sm[i] = 0.;
01033 
01034         for (j = 0; j < m; ++j) {
01035             sm[i] += at[j * n + i] * sf[j];
01036         }
01037 
01038     }
01039 
01040     return 0;
01041 
01042 }
01043 
01044 
01045 /*
01046  * @brief
01047  *   Extract spectra by simple summation.
01048  *
01049  * @param mz      Pixels values [nx, ny]
01050  * @param mslz    Scattered light model pixel values [nx, ny]
01051  * @param fibers  List of fibers to extract
01052  * @param my      Fiber centroid positions [ns, ny]
01053  * @param mw      Fiber widths [ns, ny]
01054  * @param ms      Extracted flux [ns, ny]
01055  * @param mse     Extracted flux error [ns, ny]
01056  * @param msn     Number of extracted pixels [ns, ny]
01057  * @param msy     Extracted flux centroid position [ns, ny]
01058  *
01059  * For each X bin and each spectrum the flux is computed as the sum of
01060  * pixels value from @em mz[nx,ny] along the virtual slit computed using
01061  * the localization mask @em my[ns, ny] and @em mw[ns, ny].
01062  * The table @em fibers specifies the spectra to extract.
01063  *
01064  * The images @em ms[ns, ny], @em mse[ns, ny], @em msn[ns, ny] and
01065  * @em msy[ns, ny] must be allocated by the caller.
01066  */
01067 
01068 inline static cxint
01069 _giraffe_extract_summation(const cpl_image* mz, const cpl_image* mvarz,
01070                            const cpl_table* fibers, const cpl_image* my,
01071                            const cpl_image* mw, cpl_image* mbpx,
01072                            cpl_image* ms, cpl_image* mse,
01073                            cpl_image* msn, cpl_image* msy)
01074 {
01075 
01076     register cxint nn;
01077 
01078     const cxchar* idx = NULL;
01079 
01080     cxint ny = cpl_image_get_size_x(mz);
01081     cxint nfibers = cpl_table_get_nrow(fibers);
01082     cxint nspectra = cpl_image_get_size_x(my);
01083     cxint nbins = cpl_image_get_size_y(my);
01084 
01085     const cxdouble* pixels = cpl_image_get_data_double_const(mz);
01086     const cxdouble* variances = cpl_image_get_data_double_const(mvarz);
01087     const cxdouble* locy = cpl_image_get_data_double_const(my);
01088     const cxdouble* locw = cpl_image_get_data_double_const(mw);
01089 
01090     cxdouble* flux = cpl_image_get_data_double(ms);
01091     cxdouble* flux_error = cpl_image_get_data_double(mse);
01092     cxdouble* flux_npixels = cpl_image_get_data_double(msn);
01093     cxdouble* flux_ypos = cpl_image_get_data_double(msy);
01094 
01095 
01096     /*
01097      * The number of fibers to be process must be less or equal to the
01098      * number of spectra available in the localization.
01099      */
01100 
01101     cx_assert(nfibers <= nspectra);
01102 
01103     idx = giraffe_fiberlist_query_index(fibers);
01104 
01105     cx_assert(cpl_table_has_column(fibers, idx) != 0);
01106 
01107     if (mbpx != NULL) {
01108 
01109         const cxint* bpx = cpl_image_get_data_int(mbpx);
01110 
01111         for (nn = 0; nn < nfibers; nn++) {
01112 
01113             register cxint x;
01114             register cxint ns = cpl_table_get_int(fibers, idx, nn, NULL) - 1;
01115 
01116 
01117             for (x = 0; x < cpl_image_get_size_y(mz) && x < nbins; x++) {
01118 
01119                 cxint y;
01120                 cxint yup, ylo;
01121                 cxint lx = x * nspectra + ns;
01122                 cxint sx = x * nfibers + nn;
01123 
01124                 cxdouble ylower = locy[lx] - locw[lx];
01125                 cxdouble yupper = locy[lx] + locw[lx];
01126                 cxdouble zsum = 0.;
01127                 cxdouble ysum = 0.;
01128                 cxdouble error2 = 0.;
01129 
01130 
01131                 flux[sx] = 0.;
01132                 flux_npixels[sx] = 0.;
01133                 flux_error[sx] = 0.;
01134                 flux_ypos[sx] = 0.;
01135 
01136 
01137                 /*
01138                  * Skip zero-width (invalid) spectra
01139                  */
01140 
01141                 if (locw[lx] <= 0.0) {
01142                     continue;
01143                 }
01144 
01145 
01146                 /*
01147                  * Upper and lower border of the virtual slit. The real ones
01148                  * and the borders corrected for pixel fractions. If we are
01149                  * out of the the image boundaries we skip the extraction
01150                  * for this bin and fiber.
01151                  */
01152 
01153                 ylo = (cxint) ceil(ylower);
01154                 yup = (cxint) floor(yupper);
01155 
01156 
01157                 if (yup < 0. || ylo - 1 >= ny) {
01158                     continue;
01159                 }
01160 
01161 
01162                 /*
01163                  * Summation along the virtual slit. Check that y is always
01164                  * in the range of valid pixels [0, ny[. Take into account
01165                  * pixel fractions at the beginning and the end of the
01166                  * virtual slit.
01167                  */
01168 
01169                 /*
01170                  * Lower ordinate pixel fraction
01171                  */
01172 
01173                 y = ylo - 1;
01174 
01175                 if (y >= 0) {
01176 
01177                     if (!(bpx[x * ny + y] & GIR_M_PIX_SET)) {
01178 
01179                         cxdouble extcoeff  = (cxdouble)ylo - ylower;
01180                         cxdouble extcoeff2 = extcoeff * extcoeff;
01181                         cxdouble px = CX_MAX(pixels[x * ny + y], 0.);
01182 
01183                         flux[sx] = pixels[x * ny + y] * extcoeff;
01184                         flux_npixels[sx] = extcoeff;
01185                         error2 = variances[x * ny + y] * extcoeff2;
01186 
01187                         zsum = px * extcoeff;
01188                         ysum = y * px * extcoeff;
01189 
01190                     }
01191 
01192                 }
01193 
01194 
01195                 /*
01196                  * Sum pixel values along virtual slit.
01197                  */
01198 
01199                 for (y = CX_MAX(ylo, 0); y < yup && y < ny; y++) {
01200 
01201                     if (!(bpx[x * ny + y] & GIR_M_PIX_SET)) {
01202 
01203                         cxdouble px = CX_MAX(pixels[x * ny + y], 0.);
01204 
01205                         flux[sx] += pixels[x * ny + y];
01206                         flux_npixels[sx] += 1.0;
01207                         error2 += variances[x * ny + y];
01208 
01209                         zsum += px;
01210                         ysum += y * px;
01211 
01212                     }
01213 
01214                 }
01215 
01216 
01217                 /*
01218                  * Upper ordinate pixel fraction
01219                  */
01220 
01221                 y = yup;
01222 
01223                 if (y < ny) {
01224 
01225                     if (!(bpx[x * ny + y] & GIR_M_PIX_SET)) {
01226 
01227                         cxdouble extcoeff  = yupper - (cxdouble)yup;
01228                         cxdouble extcoeff2 = extcoeff * extcoeff;
01229                         cxdouble px = CX_MAX(pixels[x * ny + y], 0.);
01230 
01231                         flux[sx] += pixels[x * ny + y] * extcoeff;
01232                         flux_npixels[sx] += extcoeff;
01233                         error2 += variances[x * ny + y] * extcoeff2;
01234 
01235                         zsum += px * extcoeff;
01236                         ysum += y * px * extcoeff;
01237 
01238                     }
01239 
01240                 }
01241 
01242                 flux_error[sx] = sqrt(error2);
01243 
01244                 // FIXME: Check this protection from division by zero. Also
01245                 //        the minimum condition for the pixel values above.
01246 
01247                 if (fabs(ysum) < DBL_EPSILON || fabs(zsum) < DBL_EPSILON) {
01248                     flux_ypos[sx] = 0.5 * (yupper + ylower);
01249                 }
01250                 else {
01251                     flux_ypos[sx] = ysum / zsum;
01252                 }
01253 
01254             }
01255 
01256         }
01257 
01258     }
01259     else {
01260 
01261         for (nn = 0; nn < nfibers; nn++) {
01262 
01263             register cxint x;
01264             register cxint ns = cpl_table_get_int(fibers, idx,
01265                                                   nn, NULL) - 1;
01266 
01267 
01268             for (x = 0; x < cpl_image_get_size_y(mz) && x < nbins; x++) {
01269 
01270                 cxint y;
01271                 cxint yup, ylo;
01272                 cxint lx = x * nspectra + ns;
01273                 cxint sx = x * nfibers + nn;
01274 
01275                 cxdouble yupper, ylower;
01276                 cxdouble zsum = 0.;
01277                 cxdouble ysum = 0.;
01278                 cxdouble error2 = 0.;
01279 
01280 
01281                 flux[sx] = 0.;
01282                 flux_npixels[sx] = 0.;
01283                 flux_error[sx] = 0.;
01284                 flux_ypos[sx] = 0.;
01285 
01286 
01287                 /*
01288                  * Skip zero-width (invalid) spectra
01289                  */
01290 
01291                 if (locw[lx] <= 0.0) {
01292                     continue;
01293                 }
01294 
01295 
01296                 /*
01297                  * Upper and lower border of the virtual slit. The real ones
01298                  * and the borders corrected for pixel fractions. If we are
01299                  * out of the the image boundaries we skip the extraction
01300                  * for this bin and fiber.
01301                  */
01302 
01303                 yupper = locy[lx] + locw[lx];
01304                 ylower = locy[lx] - locw[lx];
01305 
01306                 ylo = (cxint) ceil(ylower);
01307                 yup = (cxint) floor(yupper);
01308 
01309 
01310                 if (yup < 0. || ylo - 1 >= ny) {
01311                     continue;
01312                 }
01313 
01314 
01315                 /*
01316                  * Summation along the virtual slit. Check that y is always
01317                  * in the range of valid pixels [0, ny[. Take into account
01318                  * pixel fractions at the beginning and the end of the
01319                  * virtual slit.
01320                  */
01321 
01322                 /*
01323                  * Lower ordinate pixel fraction
01324                  */
01325 
01326                 y = ylo - 1;
01327 
01328                 if (y >= 0) {
01329 
01330                     cxdouble extcoeff  = (cxdouble)ylo - ylower;
01331                     cxdouble extcoeff2 = extcoeff * extcoeff;
01332                     cxdouble px = CX_MAX(pixels[x * ny + y], 0.);
01333 
01334                     flux[sx] = pixels[x * ny + y] * extcoeff;
01335                     flux_npixels[sx] = extcoeff;
01336                     error2 = variances[x * ny + y] * extcoeff2;
01337 
01338                     zsum = px * extcoeff;
01339                     ysum = y * px * extcoeff;
01340 
01341                 }
01342 
01343 
01344                 /*
01345                  * Sum pixel values along virtual slit.
01346                  */
01347 
01348                 for (y = CX_MAX(ylo, 0); y < yup && y < ny; y++) {
01349 
01350                     cxdouble px = CX_MAX(pixels[x * ny + y], 0.);
01351 
01352                     flux[sx] += pixels[x * ny + y];
01353                     flux_npixels[sx] += 1.0;
01354                     error2 += variances[x * ny + y];
01355 
01356                     zsum += px;
01357                     ysum += y * px;
01358                 }
01359 
01360 
01361                 /*
01362                  * Upper ordinate pixel fraction
01363                  */
01364 
01365                 y = yup;
01366 
01367                 if (y < ny) {
01368 
01369                     cxdouble extcoeff  = yupper - (cxdouble)yup;
01370                     cxdouble extcoeff2 = extcoeff * extcoeff;
01371                     cxdouble px = CX_MAX(pixels[x * ny + y], 0.);
01372 
01373                     flux[sx] += pixels[x * ny + y] * extcoeff;
01374                     flux_npixels[sx] += extcoeff;
01375                     error2 += variances[x * ny + y] * extcoeff2;
01376 
01377                     zsum += px * extcoeff;
01378                     ysum += y * px * extcoeff;
01379 
01380                 }
01381 
01382                 flux_error[sx] = sqrt(error2);
01383 
01384                 // FIXME: Check this protection from division by zero. Also
01385                 //        the minimum condition for the pixel values above.
01386 
01387                 if (fabs(ysum) < DBL_EPSILON || fabs(zsum) < DBL_EPSILON) {
01388                     flux_ypos[sx] = 0.5 * (yupper + ylower);
01389                 }
01390                 else {
01391                     flux_ypos[sx] = ysum / zsum;
01392                 }
01393 
01394             }
01395 
01396         }
01397 
01398     }
01399 
01400     return 0;
01401 
01402 }
01403 
01404 
01405 /*
01406  * @brief
01407  *   Extract spectra using the optimal extraction method.
01408  *
01409  * @param mz      Pixels values [nx, ny]
01410  * @param mvar    Initial variance [nx, ny]
01411  * @param fibers  List of fibers to extract
01412  * @param my      Fiber centroid positions [ns, ny]
01413  * @param mw      Fiber widths [ns, ny]
01414  * @param ms      Extracted flux [ns, ny]
01415  * @param mse     Extracted flux error [ns, ny]
01416  * @param msn     Number of extracted pixels [ns, ny]
01417  * @param msy     Extracted flux centroid position [ns, ny]
01418  * @param config  Optimal extraction method setup
01419  *
01420  * TBD
01421  *
01422  * The images @em ms[ns, ny], @em mse[ns, ny], @em msn[ns, ny] and
01423  * @em msy[ns, ny] must be allocated by the caller.
01424  */
01425 
01426 inline static cxint
01427 _giraffe_extract_horne(const cpl_image* mz, const cpl_image* mzvar,
01428                        const cpl_table* fibers, const cpl_image* my,
01429                        const cpl_image* mw, const GiPsfData* psfdata,
01430                        cpl_image* mbpx, cpl_image* ms, cpl_image* mse,
01431                        cpl_image* msn, cpl_image* msy,
01432                        const GiExtractHorneConfig* config)
01433 {
01434 
01435     const cxchar* idx = NULL;
01436 
01437     cxint nx = 0;
01438     cxint ny = 0;
01439     cxint fiber = 0;
01440     cxint nfibers = 0;
01441 
01442     const cxdouble* locy = NULL;
01443     const cxdouble* locw = NULL;
01444     const cxdouble* width = NULL;
01445     const cxdouble* exponent = NULL;
01446 
01447     GiModel* psfmodel = NULL;
01448 
01449 
01450     cx_assert(mz != NULL);
01451     cx_assert(mzvar != NULL);
01452 
01453     cx_assert(fibers != NULL);
01454 
01455     cx_assert(my != NULL);
01456     cx_assert(mw != NULL);
01457 
01458     cx_assert(psfdata != NULL);
01459 
01460     cx_assert(ms != NULL);
01461     cx_assert(mse != NULL);
01462     cx_assert(msn != NULL);
01463     cx_assert(msy != NULL);
01464 
01465     cx_assert(config != NULL);
01466 
01467     ny = cpl_image_get_size_x(mz);
01468     nx = cpl_image_get_size_y(mz);
01469     nfibers = cpl_table_get_nrow(fibers);
01470 
01471     locy = cpl_image_get_data_double_const(my);
01472     locw = cpl_image_get_data_double_const(mw);
01473 
01474     cx_assert((ny == cpl_image_get_size_x(mzvar)) &&
01475               (nx == cpl_image_get_size_y(mzvar)));
01476 
01477     cx_assert(cpl_image_get_size_x(my) == cpl_image_get_size_x(mw));
01478     cx_assert(cpl_image_get_size_y(my) == cpl_image_get_size_y(mw));
01479 
01480     cx_assert(giraffe_psfdata_fibers(psfdata) ==
01481               (cxsize)cpl_image_get_size_x(my));
01482     cx_assert(giraffe_psfdata_bins(psfdata) ==
01483               (cxsize)cpl_image_get_size_y(my));
01484 
01485     cx_assert((nfibers == cpl_image_get_size_x(ms)) &&
01486               (nx == cpl_image_get_size_y(ms)));
01487     cx_assert((nfibers == cpl_image_get_size_x(mse)) &&
01488               (nx == cpl_image_get_size_y(mse)));
01489     cx_assert((nfibers == cpl_image_get_size_x(msn)) &&
01490               (nx == cpl_image_get_size_y(msn)));
01491     cx_assert((nfibers == cpl_image_get_size_x(msy)) &&
01492               (nx == cpl_image_get_size_y(msy)));
01493 
01494     cx_assert((mbpx == NULL) || ((ny == cpl_image_get_size_x(mbpx)) &&
01495                                  (nx == cpl_image_get_size_y(mbpx))));
01496 
01497 
01498     /*
01499      * Get the index column mapping the current spectum number to the
01500      * corresponding reference localization spectrum number.
01501      */
01502 
01503     idx = giraffe_fiberlist_query_index(fibers);
01504 
01505     cx_assert(cpl_table_has_column(fibers, idx) != 0);
01506 
01507 
01508     /*
01509      * Get the PSF profile data arrays for efficency reasons in the
01510      * following loops.
01511      */
01512 
01513     if (giraffe_psfdata_contains(psfdata, "Center") == FALSE) {
01514         return -1;
01515     }
01516 
01517     if (giraffe_psfdata_contains(psfdata, "Width2") == TRUE) {
01518         exponent = cpl_image_get_data_const(giraffe_psfdata_get_data(psfdata,
01519             "Width2"));
01520     }
01521 
01522     width = cpl_image_get_data_const(giraffe_psfdata_get_data(psfdata,
01523         "Width1"));
01524 
01525 
01526     /*
01527      * Create the PSF profile model from the PSF data object.
01528      */
01529 
01530     psfmodel = giraffe_model_new(giraffe_psfdata_get_model(psfdata));
01531 
01532     if (psfmodel == NULL) {
01533         return -2;
01534     }
01535 
01536     giraffe_model_set_parameter(psfmodel, "Center", 0.);
01537     giraffe_model_set_parameter(psfmodel, "Amplitude", 1.);
01538     giraffe_model_set_parameter(psfmodel, "Background", 0.);
01539 
01540 
01541     /*
01542      * Extract each fiber spectrum
01543      */
01544 
01545     for (fiber = 0; fiber < nfibers; ++fiber) {
01546 
01547         register cxint bin = 0;
01548         register cxint fidx = cpl_table_get_int(fibers, idx, fiber, NULL) - 1;
01549 
01550         cxint nbins = CX_MIN(nx, cpl_image_get_size_y(my));
01551 
01552         cxdouble* _ms = cpl_image_get_data_double(ms);
01553         cxdouble* _mse  = cpl_image_get_data_double(mse);
01554         cxdouble* _msy = cpl_image_get_data_double(msy);
01555         cxdouble* _msn = cpl_image_get_data_double(msn);
01556 
01557 
01558         for (bin = 0; bin < nbins; bin++) {
01559 
01560             register cxint lpos = bin * cpl_image_get_size_x(my) + fidx;
01561             register cxint spos = bin * nfibers + fiber;
01562 
01563             cxint status = 0;
01564             cxint vwidth = 0;
01565 
01566             register cxdouble lcenter = locy[lpos];
01567             register cxdouble lwidth = locw[lpos];
01568 
01569             register cxdouble ylower = lcenter - lwidth;
01570             register cxdouble yupper = lcenter + lwidth;
01571 
01572             GiVirtualSlit* vslit = NULL;
01573 
01574             GiExtractionData result = {0., 0., 0., 0.};
01575 
01576 
01577             /*
01578              * Skip zero-width, invalid spectra
01579              */
01580 
01581             if ((lwidth <= 0.) || (yupper < 0.) || (ylower > ny)) {
01582                 continue;
01583             }
01584 
01585             /*
01586              * Fill the virtual slit with data
01587              */
01588 
01589             vslit = _giraffe_virtualslit_new(config->ewidth);
01590 
01591             vwidth = _giraffe_virtualslit_setup(vslit, bin, lcenter, lwidth,
01592                                                 mz, mzvar, mbpx);
01593 
01594             if (vwidth == 0) {
01595                 _giraffe_virtualslit_delete(vslit);
01596                 vslit = NULL;
01597 
01598                 continue;
01599             }
01600 
01601 
01602             /*
01603              * Update PSF profile model width and exponent
01604              */
01605 
01606             giraffe_model_set_parameter(psfmodel, "Width1", width[lpos]);
01607 
01608             if (exponent != NULL) {
01609                 giraffe_model_set_parameter(psfmodel, "Width2",
01610                                             exponent[lpos]);
01611             }
01612 
01613 
01614             /*
01615              * Compute flux from the virtual slit using Horne's optimal
01616              * extraction algorithm.
01617              */
01618 
01619             status = _giraffe_horne_extract_slit(&result, vslit, psfmodel,
01620                                                  config);
01621 
01622             _giraffe_virtualslit_delete(vslit);
01623             vslit = NULL;
01624 
01625             if (status != 0) {
01626 
01627                 giraffe_model_delete(psfmodel);
01628                 psfmodel = NULL;
01629 
01630                 return 1;
01631             }
01632 
01633             _ms[spos] = result.value;
01634             _mse[spos] = result.error;
01635             _msy[spos] = result.position;
01636             _msn[spos] = result.npixels;
01637 
01638         }
01639 
01640     }
01641 
01642 
01643     giraffe_model_delete(psfmodel);
01644     psfmodel = NULL;
01645 
01646     return 0;
01647 
01648 }
01649 
01650 
01651 /*
01652  * Fill extraction matrix with the fiber profiles and the coefficients of
01653  * the Chebyshev polynomial model of the background.
01654  */
01655 
01656 inline static cxint
01657 _giraffe_optimal_build_profiles(cpl_matrix* profiles,
01658                                 GiExtractionPsfLimits* limits,
01659                                 const cpl_image* my, const cpl_image* mw,
01660                                 const cpl_table* fibers, cxint bin,
01661                                 GiModel* psf, const cxdouble* width,
01662                                 const cxdouble* exponent, cxdouble wfactor)
01663 {
01664 
01665     const cxchar* idx = giraffe_fiberlist_query_index(fibers);
01666 
01667     cxint fiber = 0;
01668     cxint nfibers = cpl_table_get_nrow(fibers);
01669     cxint ny = cpl_matrix_get_ncol(profiles);
01670 
01671     const cxdouble* locy = cpl_image_get_data_double_const(my);
01672     const cxdouble* locw = cpl_image_get_data_double_const(mw);
01673 
01674     cxdouble* _profiles = cpl_matrix_get_data(profiles);
01675 
01676     cxdouble* ypos = NULL;
01677 
01678 
01679     cx_assert(cpl_table_has_column(fibers, idx) != 0);
01680     cx_assert(cpl_matrix_get_nrow(profiles) == limits->size);
01681 
01682     ypos = cx_calloc(ny, sizeof(cxdouble));
01683 
01684     for (fiber = 0; fiber < nfibers; ++fiber) {
01685 
01686         register cxint i = 0;
01687         register cxint y = 0;
01688         register cxint k = 0;
01689 
01690         cxint fidx = cpl_table_get_int(fibers, idx, fiber, NULL) - 1;
01691         cxint lpos = bin * cpl_image_get_size_x(my) + fidx;
01692 
01693         register cxdouble lcenter = locy[lpos];
01694         register cxdouble lwidth = locw[lpos];
01695 
01696         register cxdouble ylower = lcenter - fabs(wfactor) * lwidth;
01697         register cxdouble yupper = lcenter + fabs(wfactor) * lwidth;
01698 
01699         register cxint first = (cxint) floor(ylower);
01700         register cxint last = (cxint) ceil(yupper);
01701 
01702         register cxint vwidth = 0;
01703 
01704         cxdouble norm = 0.;
01705         cxdouble* _mnpsf = NULL;
01706 
01707         cpl_matrix* positions = NULL;
01708         cpl_matrix* mnpsf = NULL;
01709 
01710 
01711         /*
01712          * Upper, lower border and width of the virtual slit
01713          */
01714 
01715         ylower = CX_MAX(0., ylower);
01716         yupper = CX_MIN(ny - 1., yupper);
01717 
01718         first = CX_MAX(0, first);
01719         last = CX_MIN(ny - 1, last);
01720 
01721         vwidth = last - first + 1;
01722 
01723         if (limits != NULL) {
01724             limits->ymin[fiber] = first;
01725             limits->ymax[fiber] = last + 1;
01726         }
01727 
01728 
01729         /*
01730          * Update PSF profile model width and exponent
01731          */
01732 
01733         giraffe_model_set_parameter(psf, "Width1", width[lpos]);
01734 
01735         if (exponent != NULL) {
01736             giraffe_model_set_parameter(psf, "Width2", exponent[lpos]);
01737         }
01738 
01739 
01740         /*
01741          * Compute normalized psf model
01742          */
01743 
01744         k = 0;
01745         for (y = first; y <= last; ++y) {
01746             ypos[k] = y - lcenter;
01747             ++k;
01748         }
01749 
01750         positions = cpl_matrix_wrap(vwidth, 1, ypos);
01751         mnpsf = _giraffe_compute_psf(psf, positions);
01752 
01753         cpl_matrix_unwrap(positions);
01754         positions = NULL;
01755 
01756         if (mnpsf == NULL) {
01757             cx_free(ypos);
01758             ypos = NULL;
01759 
01760             return 1;
01761         }
01762 
01763         _mnpsf = cpl_matrix_get_data(mnpsf);
01764 
01765         for (i = 0; i < vwidth; ++i) {
01766             _mnpsf[i] = CX_MAX(_mnpsf[i], 0.);
01767             norm += _mnpsf[i];
01768         }
01769 
01770         for (i = 0; i < vwidth; ++i) {
01771             _mnpsf[i] /= norm;
01772         }
01773 
01774         k = fiber * ny + first;
01775         for (y = 0; y < vwidth; ++y) {
01776             _profiles[k + y] = _mnpsf[y];
01777         }
01778 
01779         cpl_matrix_delete(mnpsf);
01780         mnpsf = NULL;
01781 
01782     }
01783 
01784     cx_free(ypos);
01785     ypos = NULL;
01786 
01787     return 0;
01788 
01789 }
01790 
01791 
01792 inline static cxint
01793 _giraffe_extract_optimal(const cpl_image* mz, const cpl_image* mzvar,
01794                          const cpl_table* fibers, const cpl_image* my,
01795                          const cpl_image* mw, const GiPsfData* psfdata,
01796                          cpl_image* mbpx, cpl_image* ms, cpl_image* mse,
01797                          cpl_image* msm, cpl_image* msy,
01798                          const GiExtractOptimalConfig* config)
01799 {
01800 
01801     const cxbool nolimits = (config->limits == TRUE) ? FALSE : TRUE;
01802 
01803     const cxint bkg_nc = config->bkgorder + 1;
01804     const cxint niter = config->clip.iterations;
01805 
01806     register cxint i = 0;
01807 
01808     cxint nx = 0;
01809     cxint ny = 0;
01810     cxint bin = 0;
01811     cxint nbins = 0;
01812     cxint nfibers = 0;
01813 
01814     const cxdouble wfactor = config->ewidth;
01815     const cxdouble sigma = config->clip.level * config->clip.level;
01816     const cxdouble fraction = config->clip.fraction;
01817 
01818     const cxdouble* width = NULL;
01819     const cxdouble* exponent = NULL;
01820 
01821     cxdouble* _ypos = NULL;
01822     cxdouble* _bkg_base = NULL;
01823     cxdouble* _profiles = NULL;
01824     cxdouble* _signal = NULL;
01825     cxdouble* _variance = NULL;
01826     cxdouble* _mask = NULL;
01827     cxdouble* _weights = NULL;
01828 
01829     cpl_matrix* ypos = NULL;
01830     cpl_matrix* bkg_base = NULL;
01831     cpl_matrix* profiles = NULL;
01832     cpl_matrix* weights = NULL;
01833     cpl_matrix* signal = NULL;
01834     cpl_matrix* variance = NULL;
01835     cpl_matrix* mask = NULL;
01836 
01837     GiModel* psfmodel = NULL;
01838 
01839     GiExtractionPsfLimits* limits = NULL;
01840 
01841     GiExtractionSlice* slice = NULL;
01842 
01843     GiExtractionWorkspace* workspace;
01844 
01845 
01846     cx_assert(mz != NULL);
01847     cx_assert(mzvar != NULL);
01848 
01849     cx_assert(fibers != NULL);
01850 
01851     cx_assert(my != NULL);
01852     cx_assert(mw != NULL);
01853 
01854     cx_assert(psfdata != NULL);
01855 
01856     cx_assert(ms != NULL);
01857     cx_assert(mse != NULL);
01858     cx_assert(msm != NULL);
01859     cx_assert(msy != NULL);
01860 
01861     ny = cpl_image_get_size_x(mz);
01862     nx = cpl_image_get_size_y(mz);
01863 
01864     nfibers = cpl_table_get_nrow(fibers);
01865     nbins = CX_MIN(nx, cpl_image_get_size_y(my));
01866 
01867     cx_assert((ny == cpl_image_get_size_x(mzvar)) &&
01868               (nx == cpl_image_get_size_y(mzvar)));
01869 
01870     cx_assert(cpl_image_get_size_x(my) == cpl_image_get_size_x(mw));
01871     cx_assert(cpl_image_get_size_y(my) == cpl_image_get_size_y(mw));
01872 
01873     cx_assert(giraffe_psfdata_fibers(psfdata) ==
01874               (cxsize)cpl_image_get_size_x(my));
01875     cx_assert(giraffe_psfdata_bins(psfdata) ==
01876               (cxsize)cpl_image_get_size_y(my));
01877 
01878     cx_assert((nfibers == cpl_image_get_size_x(ms)) &&
01879               (nx == cpl_image_get_size_y(ms)));
01880     cx_assert((nfibers == cpl_image_get_size_x(mse)) &&
01881               (nx == cpl_image_get_size_y(mse)));
01882     cx_assert((nfibers == cpl_image_get_size_x(msy)) &&
01883               (nx == cpl_image_get_size_y(msy)));
01884     cx_assert((ny == cpl_image_get_size_x(msm)) &&
01885               (nx == cpl_image_get_size_y(msm)));
01886 
01887     cx_assert((mbpx == NULL) || ((ny == cpl_image_get_size_x(mbpx)) &&
01888                                  (nx == cpl_image_get_size_y(mbpx))));
01889 
01890 
01891     /*
01892      * Get the PSF profile data arrays for efficency reasons in the
01893      * following loops.
01894      */
01895 
01896     if (giraffe_psfdata_contains(psfdata, "Center") == FALSE) {
01897         return -1;
01898     }
01899 
01900     if (giraffe_psfdata_contains(psfdata, "Width2") == TRUE) {
01901         exponent = cpl_image_get_data_const(giraffe_psfdata_get_data(psfdata,
01902             "Width2"));
01903     }
01904 
01905     width = cpl_image_get_data_const(giraffe_psfdata_get_data(psfdata,
01906         "Width1"));
01907 
01908 
01909     /*
01910      * Create the PSF profile model from the PSF data object.
01911      */
01912 
01913     psfmodel = giraffe_model_new(giraffe_psfdata_get_model(psfdata));
01914 
01915     if (psfmodel == NULL) {
01916         return -2;
01917     }
01918 
01919     giraffe_model_set_parameter(psfmodel, "Amplitude", 1.);
01920     giraffe_model_set_parameter(psfmodel, "Background", 0.);
01921     giraffe_model_set_parameter(psfmodel, "Center", 0.);
01922 
01923 
01924     /*
01925      * Set up the vector of pixel positions
01926      */
01927 
01928     ypos = cpl_matrix_new(ny, 1);
01929 
01930     if (ypos == NULL) {
01931         giraffe_model_delete(psfmodel);
01932         psfmodel = NULL;
01933 
01934         return -3;
01935     }
01936 
01937     _ypos = cpl_matrix_get_data(ypos);
01938 
01939     for (i = 0; i < ny; ++i) {
01940         _ypos[i] = i;
01941     }
01942 
01943 
01944     /*
01945      * Create profile matrix and the matrices for the signal, bad
01946      * pixel mask, variance and the weights.
01947      */
01948 
01949     profiles = cpl_matrix_new(nfibers + bkg_nc, ny);
01950 
01951     if (profiles == NULL) {
01952         cpl_matrix_delete(ypos);
01953         ypos = NULL;
01954 
01955         giraffe_model_delete(psfmodel);
01956         psfmodel = NULL;
01957 
01958         return -3;
01959     }
01960 
01961     _profiles = cpl_matrix_get_data(profiles);
01962 
01963 
01964     signal = cpl_matrix_new(ny, 1);
01965 
01966     if (signal == NULL) {
01967         cpl_matrix_delete(profiles);
01968         profiles = NULL;
01969 
01970         cpl_matrix_delete(ypos);
01971         ypos = NULL;
01972 
01973         giraffe_model_delete(psfmodel);
01974         psfmodel = NULL;
01975 
01976         return -3;
01977     }
01978 
01979     _signal = cpl_matrix_get_data(signal);
01980 
01981 
01982     variance = cpl_matrix_new(ny, 1);
01983 
01984     if (variance == NULL) {
01985         cpl_matrix_delete(signal);
01986         signal = NULL;
01987 
01988         cpl_matrix_delete(profiles);
01989         profiles = NULL;
01990 
01991         cpl_matrix_delete(ypos);
01992         ypos = NULL;
01993 
01994         giraffe_model_delete(psfmodel);
01995         psfmodel = NULL;
01996 
01997         return -3;
01998     }
01999 
02000     _variance = cpl_matrix_get_data(variance);
02001 
02002 
02003     mask = cpl_matrix_new(ny, 1);
02004 
02005     if (mask == NULL) {
02006         cpl_matrix_delete(variance);
02007         variance = NULL;
02008 
02009         cpl_matrix_delete(signal);
02010         signal = NULL;
02011 
02012         cpl_matrix_delete(profiles);
02013         profiles = NULL;
02014 
02015         cpl_matrix_delete(ypos);
02016         ypos = NULL;
02017 
02018         giraffe_model_delete(psfmodel);
02019         psfmodel = NULL;
02020 
02021         return -3;
02022     }
02023 
02024     _mask = cpl_matrix_get_data(mask);
02025 
02026 
02027     weights = cpl_matrix_new(ny, 1);
02028 
02029     if (mask == NULL) {
02030         cpl_matrix_delete(mask);
02031         mask = NULL;
02032 
02033         cpl_matrix_delete(variance);
02034         variance = NULL;
02035 
02036         cpl_matrix_delete(signal);
02037         signal = NULL;
02038 
02039         cpl_matrix_delete(profiles);
02040         profiles = NULL;
02041 
02042         cpl_matrix_delete(ypos);
02043         ypos = NULL;
02044 
02045         giraffe_model_delete(psfmodel);
02046         psfmodel = NULL;
02047 
02048         return -3;
02049     }
02050 
02051     _weights = cpl_matrix_get_data(weights);
02052 
02053 
02054     /*
02055      * Fill design matrix with the basis functions of the
02056      * background polynomial model.
02057      */
02058 
02059     bkg_base = giraffe_chebyshev_base1d(0., ny, bkg_nc, ypos);
02060 
02061     cpl_matrix_delete(ypos);
02062     ypos = NULL;
02063 
02064     if (bkg_base == NULL) {
02065         cpl_matrix_delete(weights);
02066         weights = NULL;
02067 
02068         cpl_matrix_delete(mask);
02069         mask = NULL;
02070 
02071         cpl_matrix_delete(variance);
02072         variance = NULL;
02073 
02074         cpl_matrix_delete(signal);
02075         signal = NULL;
02076 
02077         cpl_matrix_delete(profiles);
02078         profiles = NULL;
02079 
02080         cpl_matrix_delete(ypos);
02081         ypos = NULL;
02082 
02083         giraffe_model_delete(psfmodel);
02084         psfmodel = NULL;
02085 
02086         return -3;
02087     }
02088 
02089     _bkg_base = cpl_matrix_get_data(bkg_base);
02090 
02091     for (i = 0; i < bkg_nc; ++i) {
02092 
02093         register cxint j = 0;
02094         register cxint offset = nfibers * ny;
02095 
02096         for (j = 0; j < ny; ++j) {
02097             _profiles[i * ny + j + offset] = _bkg_base[i * ny + j];
02098         }
02099 
02100     }
02101 
02102     _bkg_base = NULL;
02103 
02104     cpl_matrix_delete(bkg_base);
02105     bkg_base = NULL;
02106 
02107 
02108     /*
02109      * Extract all fiber spectra simultanously for each wavelength bin
02110      */
02111 
02112     slice = _giraffe_extractionslice_new(nfibers, ny, bkg_nc);
02113 
02114     if (slice == NULL) {
02115         cpl_matrix_delete(weights);
02116         weights = NULL;
02117 
02118         cpl_matrix_delete(mask);
02119         mask = NULL;
02120 
02121         cpl_matrix_delete(variance);
02122         variance = NULL;
02123 
02124         cpl_matrix_delete(signal);
02125         signal = NULL;
02126 
02127         cpl_matrix_delete(profiles);
02128         profiles = NULL;
02129 
02130         cpl_matrix_delete(ypos);
02131         ypos = NULL;
02132 
02133         giraffe_model_delete(psfmodel);
02134         psfmodel = NULL;
02135 
02136         return -3;
02137     }
02138 
02139 
02140     limits = _giraffe_extraction_psflimits_new(nfibers + bkg_nc);
02141 
02142     if (limits == NULL) {
02143 
02144         _giraffe_extractionslice_delete(slice);
02145         slice = NULL;
02146 
02147         cpl_matrix_delete(weights);
02148         weights = NULL;
02149 
02150         cpl_matrix_delete(mask);
02151         mask = NULL;
02152 
02153         cpl_matrix_delete(variance);
02154         variance = NULL;
02155 
02156         cpl_matrix_delete(signal);
02157         signal = NULL;
02158 
02159         cpl_matrix_delete(profiles);
02160         profiles = NULL;
02161 
02162         cpl_matrix_delete(ypos);
02163         ypos = NULL;
02164 
02165         giraffe_model_delete(psfmodel);
02166         psfmodel = NULL;
02167 
02168         return -3;
02169 
02170     }
02171 
02172     for (i = 0; i < limits->size; ++i) {
02173         limits->ymin[i] = 0;
02174         limits->ymax[i] = ny;
02175     }
02176 
02177 
02178     /*
02179      * Allocate workspace for matrix multiplications
02180      */
02181 
02182     workspace = _giraffe_optimal_workspace_new(nfibers + bkg_nc, ny);
02183 
02184     for (bin = 0; bin < nbins; ++bin) {
02185 
02186         cxbool stop = FALSE;
02187 
02188         cxint iter = 0;
02189         cxint nmin = 0;
02190         cxint ngood = ny;
02191 
02192         const cxdouble* _my = cpl_image_get_data_double_const(my);
02193         const cxdouble* _mz = cpl_image_get_data_double_const(mz);
02194         const cxdouble* _mzvar = cpl_image_get_data_double_const(mzvar);
02195 
02196         cxdouble* _ms = cpl_image_get_data_double(ms);
02197         cxdouble* _mse = cpl_image_get_data_double(mse);
02198         cxdouble* _msy = cpl_image_get_data_double(msy);
02199         cxdouble* _msm = cpl_image_get_data_double(msm);
02200 
02201         cxint status = 0;
02202 
02203         GiExtractionPsfLimits* _limits = (nolimits == FALSE) ? limits : NULL;
02204 
02205         cx_assert(_mz != NULL);
02206         cx_assert(_mzvar != NULL);
02207 
02208 
02209         /*
02210          * Fill the design matrix with the fiber profiles for the
02211          * current wavelength bin
02212          */
02213 
02214         status = _giraffe_optimal_build_profiles(profiles, _limits, my, mw,
02215                                                  fibers, bin, psfmodel, width,
02216                                                  exponent, wfactor);
02217 
02218         if (status != 0) {
02219             _giraffe_optimal_workspace_delete(workspace);
02220             workspace = NULL;
02221 
02222             _giraffe_extraction_psflimits_delete(limits);
02223             limits = NULL;
02224 
02225             _giraffe_extractionslice_delete(slice);
02226             slice = NULL;
02227 
02228             cpl_matrix_delete(weights);
02229             weights = NULL;
02230 
02231             cpl_matrix_delete(mask);
02232             mask = NULL;
02233 
02234             cpl_matrix_delete(variance);
02235             variance = NULL;
02236 
02237             cpl_matrix_delete(signal);
02238             signal = NULL;
02239 
02240             cpl_matrix_delete(profiles);
02241             profiles = NULL;
02242 
02243             cpl_matrix_delete(ypos);
02244             ypos = NULL;
02245 
02246             giraffe_model_delete(psfmodel);
02247             psfmodel = NULL;
02248 
02249             return -4;
02250         }
02251 
02252 
02253         /*
02254          * Fill the signal, variance, mask and weight matrices
02255          */
02256 
02257 
02258         if (mbpx != NULL) {
02259 
02260             const cxint* _mbpx = cpl_image_get_data_int_const(mbpx);
02261 
02262 
02263             cx_assert(_mbpx != NULL);
02264 
02265             for (i = 0; i < ny; ++i) {
02266 
02267                 cxbool bad = (_mbpx[bin * ny + i] & GIR_M_PIX_SET) ||
02268                     (_mz[bin * ny + i] < 0.);
02269 
02270                 _signal[i] = _mz[bin * ny + i];
02271                 _variance[i] = _signal[i] + _mzvar[bin * ny + i];
02272                 _mask[i] = 1.;
02273 
02274                 if (bad == TRUE) {
02275                     _mask[i] = 0.;
02276                     --ngood;
02277                 }
02278 
02279                 _weights[i] = _mask[i] / _variance[i];
02280 
02281             }
02282 
02283         }
02284         else {
02285 
02286             for (i = 0; i < ny; ++i) {
02287 
02288                 cxbool bad = (_mz[bin * ny + i] < 0.);
02289 
02290                 _signal[i] = _mz[bin * ny + i];
02291                 _variance[i] = _signal[i] + _mzvar[bin * ny + i];
02292                 _mask[i] = 1.;
02293 
02294                 if (bad == TRUE) {
02295                     _mask[i] = 0.;
02296                     --ngood;
02297                 }
02298 
02299                 _weights[i] = _mask[i] / _variance[i];
02300 
02301             }
02302 
02303         }
02304 
02305 
02306         /*
02307          * Extrat simultaneously the fluxes of all fibers for the current
02308          * wavelength bin
02309          */
02310 
02311         nmin = (cxint)(fraction * ngood);
02312 
02313         while ((iter < niter) && (stop == FALSE)) {
02314 
02315             cxint nreject = 0;
02316 
02317             const cxdouble* _model = NULL;
02318 
02319 
02320             status = _giraffe_optimal_extract_slice(slice, profiles,
02321                 signal, weights, limits, workspace);
02322 
02323             if (status != 0) {
02324                 _giraffe_optimal_workspace_delete(workspace);
02325                 workspace = NULL;
02326 
02327                 _giraffe_extraction_psflimits_delete(limits);
02328                 limits = NULL;
02329 
02330                 _giraffe_extractionslice_delete(slice);
02331                 slice = NULL;
02332 
02333                 cpl_matrix_delete(weights);
02334                 weights = NULL;
02335 
02336                 cpl_matrix_delete(mask);
02337                 mask = NULL;
02338 
02339                 cpl_matrix_delete(variance);
02340                 variance = NULL;
02341 
02342                 cpl_matrix_delete(signal);
02343                 signal = NULL;
02344 
02345                 cpl_matrix_delete(profiles);
02346                 profiles = NULL;
02347 
02348                 cpl_matrix_delete(ypos);
02349                 ypos = NULL;
02350 
02351                 giraffe_model_delete(psfmodel);
02352                 psfmodel = NULL;
02353 
02354                 return -5;
02355             }
02356 
02357 
02358             /*
02359              * Update weighting factors
02360              */
02361 
02362             _model = cpl_matrix_get_data(slice->model);
02363 
02364             for (i = 0; i < ny; ++i) {
02365 
02366                 if (_mask[i] > 0.) {
02367 
02368                     cxbool bad = FALSE;
02369                     cxdouble residual = _signal[i] - _model[i];
02370 
02371 
02372                     _variance[i] = _model[i] + _mzvar[bin * ny + i];
02373 
02374                     bad = (residual * residual) > (sigma * _variance[i]) ?
02375                         TRUE : FALSE;
02376 
02377                     if (bad == TRUE) {
02378                         _mask[i] = 0.;
02379                         ++nreject;
02380                         --ngood;
02381                     }
02382 
02383                     _weights[i] = _mask[i] / _variance[i];
02384 
02385                 }
02386 
02387             }
02388 
02389             if ((nreject == 0) || (ngood <= nmin)) {
02390                 stop = TRUE;
02391             }
02392 
02393             ++iter;
02394 
02395         }
02396 
02397 
02398         /*
02399          * Copy the extracted fluxes, their variance and the modeled signal
02400          * to the result images.
02401          */
02402 
02403         memcpy(&_ms[bin * nfibers], cpl_matrix_get_data(slice->flux),
02404                slice->nflx * sizeof(cxdouble));
02405         memcpy(&_mse[bin * nfibers], cpl_matrix_get_data(slice->variance),
02406                slice->nflx * sizeof(cxdouble));
02407         memcpy(&_msm[bin * ny], cpl_matrix_get_data(slice->model),
02408                slice->msize * sizeof(cxdouble));
02409 
02410         memcpy(&_msy[bin * nfibers], &_my[bin * nfibers],
02411                nfibers * sizeof(cxdouble));
02412 
02413 
02414         /*
02415          * Reset the profile part of the design matrix
02416          */
02417 
02418         cpl_matrix_fill_window(profiles, 0., 0, 0, nfibers, ny);
02419 
02420     }
02421 
02422     _giraffe_optimal_workspace_delete(workspace);
02423     workspace = NULL;
02424 
02425     _giraffe_extraction_psflimits_delete(limits);
02426     limits = NULL;
02427 
02428     _giraffe_extractionslice_delete(slice);
02429     slice = NULL;
02430 
02431     cpl_matrix_delete(weights);
02432     weights = NULL;
02433 
02434     cpl_matrix_delete(mask);
02435     mask = NULL;
02436 
02437     cpl_matrix_delete(variance);
02438     variance = NULL;
02439 
02440     cpl_matrix_delete(signal);
02441     signal = NULL;
02442 
02443     cpl_matrix_delete(profiles);
02444     profiles = NULL;
02445 
02446     giraffe_model_delete(psfmodel);
02447     psfmodel = NULL;
02448 
02449     return 0;
02450 
02451 }
02452 
02453 
02478 cxint
02479 giraffe_extract_spectra(GiExtraction* result, GiImage* image,
02480                         GiTable* fibers, GiLocalization* sloc,
02481                         GiImage* bpixel, GiImage* slight,
02482                         GiExtractConfig* config)
02483 {
02484 
02485     const cxchar *fctid = "giraffe_extract_spectra";
02486 
02487 
02488     cxint ns = 0;
02489     cxint nx = 0;
02490     cxint ny = 0;
02491     cxint status = 0;
02492 
02493     cxdouble bias_sigma = 0.;
02494     cxdouble dark_value = 0;
02495     cxdouble exptime = 0;
02496 
02497     cpl_propertylist *properties;
02498 
02499     cpl_image* _image = NULL;
02500     cpl_image* _locy = NULL;
02501     cpl_image* _locw = NULL;
02502     cpl_image* _spectra = NULL;
02503     cpl_image* _error = NULL;
02504     cpl_image* _npixels = NULL;
02505     cpl_image* _centroid = NULL;
02506     cpl_image* _model = NULL;
02507 
02508     cpl_table* _fibers = NULL;
02509 
02510 
02511     /*
02512      * Preprocessing
02513      */
02514 
02515     if (!result || !image || !fibers || !sloc || !config) {
02516         cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
02517         return 1;
02518     }
02519 
02520 
02521     if ((sloc->locy == NULL) || (sloc->locw == NULL)) {
02522         cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
02523         return 1;
02524     }
02525 
02526     if (result->spectra != NULL || result->error != NULL ||
02527         result->npixels != NULL || result->centroid != NULL ||
02528         result->model != NULL) {
02529         gi_warning("%s: Results structure at %p is not empty! Contents "
02530                    "might be lost.", fctid, result);
02531     }
02532 
02533     _fibers = giraffe_table_get(fibers);
02534 
02535     if (_fibers == NULL) {
02536         cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
02537         return 1;
02538     }
02539 
02540     properties = giraffe_image_get_properties(image);
02541 
02542     if (properties == NULL) {
02543         cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
02544         return 1;
02545     }
02546 
02547     if ((config->emethod == GIEXTRACT_OPTIMAL) && (sloc->psf == NULL)) {
02548         cpl_msg_error(fctid, "Missing data: PSF profile data is required "
02549                 "for optimal spectrum extraction!");
02550         return 1;
02551     }
02552 
02553     if (config->ron > 0.) {
02554 
02555         cpl_msg_info(fctid, "Setting bias sigma value property (%s) to %.4g",
02556                      GIALIAS_BIASSIGMA, config->ron);
02557 
02558         cpl_propertylist_update_double(properties, GIALIAS_BIASSIGMA,
02559                                        config->ron);
02560     }
02561     else {
02562         if (!cpl_propertylist_has(properties, GIALIAS_BIASSIGMA)) {
02563             cpl_msg_error(fctid, "Missing bias value property (%s)!",
02564                           GIALIAS_BIASSIGMA);
02565             return 1;
02566         }
02567     }
02568 
02569     bias_sigma = cpl_propertylist_get_double(properties, GIALIAS_BIASSIGMA);
02570 
02571 
02572     if (!cpl_propertylist_has(properties, GIALIAS_DARKVALUE)) {
02573 
02574         dark_value = 0.;
02575 
02576         cpl_msg_warning(fctid, "Missing dark value property (%s), will be "
02577                         "set to 0.!", GIALIAS_DARKVALUE);
02578         cpl_propertylist_append_double(properties, GIALIAS_DARKVALUE,
02579                                        dark_value);
02580 
02581     }
02582     else {
02583         dark_value = cpl_propertylist_get_double(properties,
02584                                                  GIALIAS_DARKVALUE);
02585     }
02586 
02587 
02588     if (!cpl_propertylist_has(properties, GIALIAS_EXPTIME)) {
02589         cpl_msg_error(fctid, "Missing exposure time property (%s)!",
02590                       GIALIAS_EXPTIME);
02591         return 1;
02592     }
02593     else {
02594         exptime = cpl_propertylist_get_double(properties, GIALIAS_EXPTIME);
02595     }
02596 
02597     if (cpl_propertylist_has(properties, GIALIAS_CONAD)) {
02598 
02599         cxdouble conad = cpl_propertylist_get_double(properties,
02600                                                      GIALIAS_CONAD);
02601 
02602         bias_sigma *= conad;
02603         dark_value *= conad;
02604 
02605     }
02606 
02607 
02608     /*
02609      * Processing
02610      */
02611 
02612     _image = giraffe_image_get(image);
02613     _locy = giraffe_image_get(sloc->locy);
02614     _locw = giraffe_image_get(sloc->locw);
02615 
02616     ny = cpl_image_get_size_x(_image);
02617     nx = cpl_image_get_size_y(_locw);
02618     ns = cpl_table_get_nrow(_fibers);
02619 
02620 
02621     switch (config->emethod) {
02622         case GIEXTRACT_SUM:
02623         {
02624 
02625             cxint xsize = cpl_image_get_size_x(_image);
02626             cxint ysize = cpl_image_get_size_y(_image);
02627 
02628             cxdouble bias_variance = bias_sigma * bias_sigma;
02629 
02630             cpl_image* bpixmap = NULL;
02631             cpl_image* variance = NULL;
02632 
02633 
02634             result->spectra = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02635             result->error = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02636             result->npixels = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02637             result->centroid = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02638             result->model = NULL;
02639 
02640             _spectra = giraffe_image_get(result->spectra);
02641             _error = giraffe_image_get(result->error);
02642             _npixels = giraffe_image_get(result->npixels);
02643             _centroid = giraffe_image_get(result->centroid);
02644 
02645             if (bpixel != NULL) {
02646 
02647                 bpixmap = giraffe_image_get(bpixel);
02648 
02649                 if (cpl_image_get_size_x(bpixmap) != xsize ||
02650                     cpl_image_get_size_y(bpixmap) != ysize) {
02651 
02652                     cxbool crop = FALSE;
02653 
02654                     cpl_propertylist *p =
02655                             giraffe_image_get_properties(bpixel);
02656 
02657                     GiWindow w = {1, 1, 0, 0};
02658 
02659 
02660                     w.x1 = cpl_image_get_size_x(bpixmap);
02661                     w.y1 = cpl_image_get_size_y(bpixmap);
02662 
02663                     if (cpl_propertylist_has(p, GIALIAS_PRSCX)) {
02664                         w.x0 += cpl_propertylist_get_int(p, GIALIAS_PRSCX);
02665                         crop = TRUE;
02666                     }
02667 
02668                     if (cpl_propertylist_has(p, GIALIAS_OVSCX)) {
02669                         w.x1 -= cpl_propertylist_get_int(p, GIALIAS_OVSCX);
02670                         crop = TRUE;
02671                     }
02672 
02673                     if (cpl_propertylist_has(p, GIALIAS_PRSCY)) {
02674                         w.y0 += cpl_propertylist_get_int(p, GIALIAS_PRSCY);
02675                         crop = TRUE;
02676                     }
02677 
02678                     if (cpl_propertylist_has(p, GIALIAS_OVSCY)) {
02679                         w.y1 -= cpl_propertylist_get_int(p, GIALIAS_OVSCY);
02680                         crop = TRUE;
02681                     }
02682 
02683                     if ((w.x1 - w.x0 + 1) != xsize ||
02684                         (w.y1 - w.y0 + 1) != ysize) {
02685                         cpl_msg_error(fctid, "Invalid bad pixel map! Image "
02686                                       "sizes do not match!");
02687 
02688                         giraffe_image_delete(result->spectra);
02689                         result->spectra = NULL;
02690 
02691                         giraffe_image_delete(result->error);
02692                         result->error = NULL;
02693 
02694                         giraffe_image_delete(result->npixels);
02695                         result->npixels = NULL;
02696 
02697                         giraffe_image_delete(result->centroid);
02698                         result->centroid = NULL;
02699 
02700                         giraffe_image_delete(result->model);
02701                         result->model = NULL;
02702 
02703                             return 1;
02704                     }
02705 
02706                     if (crop == TRUE) {
02707                         bpixmap = cpl_image_extract(bpixmap, w.x0, w.y0,
02708                                                     w.x1, w.y1);
02709                     }
02710 
02711                 }
02712 
02713             }
02714 
02715             if (slight != NULL) {
02716                 cpl_msg_warning(fctid, "Scattered light model will be "
02717                                 "ignored for extraction method `SUM'");
02718             }
02719 
02720             variance = cpl_image_abs_create(_image);
02721             cpl_image_add_scalar(variance,
02722                                  bias_variance + dark_value * exptime);
02723 
02724             status = _giraffe_extract_summation(_image, variance, _fibers,
02725                                                 _locy, _locw, bpixmap,
02726                                                 _spectra, _error, _npixels,
02727                                                 _centroid);
02728 
02729             cpl_image_delete(variance);
02730             if (bpixmap != giraffe_image_get(bpixel)) {
02731                 cpl_image_delete(bpixmap);
02732             }
02733             bpixmap = NULL;
02734 
02735             break;
02736 
02737         }
02738 
02739         case GIEXTRACT_OPTIMAL:
02740         {
02741 
02742             cxint xsize = cpl_image_get_size_x(_image);
02743             cxint ysize = cpl_image_get_size_y(_image);
02744 
02745             cxdouble v0 = 0.;
02746 
02747             cpl_image* variance = NULL;
02748             cpl_image* bpixmap = NULL;
02749 
02750             GiExtractOptimalConfig setup;
02751 
02752 
02753             result->spectra = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02754             result->error = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02755             result->npixels = NULL;
02756             result->model = giraffe_image_create(CPL_TYPE_DOUBLE, ny, nx);
02757             result->centroid = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02758 
02759             _spectra = giraffe_image_get(result->spectra);
02760             _error = giraffe_image_get(result->error);
02761             _model = giraffe_image_get(result->model);
02762             _centroid = giraffe_image_get(result->centroid);
02763 
02764             setup.clip.iterations = config->psf.iterations;
02765             setup.clip.level = config->psf.sigma;
02766             setup.clip.fraction = config->optimal.fraction;
02767             setup.limits = config->optimal.wfactor < 0. ? FALSE : TRUE;
02768             setup.ewidth = CX_MAX(1., fabs(config->optimal.wfactor));
02769             setup.bkgorder = config->optimal.bkgorder;
02770             setup.exptime = exptime;
02771             setup.ron = bias_sigma;
02772             setup.dark = dark_value;
02773 
02774 
02775             if (bpixel != NULL) {
02776 
02777                 bpixmap = giraffe_image_get(bpixel);
02778 
02779                 if (cpl_image_get_size_x(bpixmap) != xsize ||
02780                     cpl_image_get_size_y(bpixmap) != ysize) {
02781 
02782                         cxbool crop = FALSE;
02783 
02784                         cpl_propertylist *p =
02785                             giraffe_image_get_properties(bpixel);
02786 
02787                         GiWindow w = {1, 1, 0, 0};
02788 
02789 
02790                         w.x1 = cpl_image_get_size_x(bpixmap);
02791                         w.y1 = cpl_image_get_size_y(bpixmap);
02792 
02793                         if (cpl_propertylist_has(p, GIALIAS_PRSCX)) {
02794                             w.x0 += cpl_propertylist_get_int(p, GIALIAS_PRSCX);
02795                             crop = TRUE;
02796                         }
02797 
02798                         if (cpl_propertylist_has(p, GIALIAS_OVSCX)) {
02799                             w.x1 -= cpl_propertylist_get_int(p, GIALIAS_OVSCX);
02800                             crop = TRUE;
02801                         }
02802 
02803                         if (cpl_propertylist_has(p, GIALIAS_PRSCY)) {
02804                             w.y0 += cpl_propertylist_get_int(p, GIALIAS_PRSCY);
02805                             crop = TRUE;
02806                         }
02807 
02808                         if (cpl_propertylist_has(p, GIALIAS_OVSCY)) {
02809                             w.y1 -= cpl_propertylist_get_int(p, GIALIAS_OVSCY);
02810                             crop = TRUE;
02811                         }
02812 
02813                         if ((w.x1 - w.x0 + 1) != xsize ||
02814                             (w.y1 - w.y0 + 1) != ysize) {
02815 
02816                                 cpl_msg_error(fctid, "Invalid bad pixel map! "
02817                                     "Image sizes do not match!");
02818 
02819                                 giraffe_image_delete(result->spectra);
02820                                 result->spectra = NULL;
02821 
02822                                 giraffe_image_delete(result->error);
02823                                 result->error = NULL;
02824 
02825                                 giraffe_image_delete(result->npixels);
02826                                 result->npixels = NULL;
02827 
02828                                 giraffe_image_delete(result->centroid);
02829                                 result->centroid = NULL;
02830 
02831                                 giraffe_image_delete(result->model);
02832                                 result->model = NULL;
02833 
02834                                 return 1;
02835 
02836                             }
02837 
02838                         if (crop == TRUE) {
02839                             bpixmap = cpl_image_extract(bpixmap, w.x0, w.y0,
02840                                 w.x1, w.y1);
02841                         }
02842 
02843                     }
02844 
02845             }
02846 
02847             variance = cpl_image_new(xsize, ysize, CPL_TYPE_DOUBLE);
02848             v0 = bias_sigma * bias_sigma + dark_value * exptime;
02849 
02850 
02851             if (slight != NULL) {
02852 
02853                 register cxsize i = 0;
02854                 register cxsize npixels = xsize * ysize;
02855 
02856                 const cxdouble* _slight =
02857                     cpl_image_get_data_double(giraffe_image_get(slight));
02858 
02859                 cxdouble* _variance = cpl_image_get_data_double(variance);
02860 
02861                 for (i = 0; i < npixels; i++) {
02862                     _variance[i] = v0 + fabs(_slight[i]);
02863                 }
02864 
02865             }
02866             else {
02867 
02868                 register cxsize i = 0;
02869                 register cxsize npixels = xsize * ysize;
02870 
02871                 cxdouble* _variance = cpl_image_get_data_double(variance);
02872 
02873                 for (i = 0; i < npixels; i++) {
02874                     _variance[i] = v0;
02875                 }
02876 
02877             }
02878 
02879 
02880             status = _giraffe_extract_optimal(_image, variance, _fibers,
02881                                               _locy, _locw, sloc->psf,
02882                                               bpixmap, _spectra, _error,
02883                                               _model, _centroid, &setup);
02884 
02885             cpl_image_delete(variance);
02886             variance = NULL;
02887 
02888             if (bpixmap != giraffe_image_get(bpixel)) {
02889                 cpl_image_delete(bpixmap);
02890             }
02891             bpixmap = NULL;
02892 
02893             break;
02894 
02895         }
02896 
02897         case GIEXTRACT_HORNE:
02898         {
02899 
02900             cxint xsize = cpl_image_get_size_x(_image);
02901             cxint ysize = cpl_image_get_size_y(_image);
02902 
02903             cxdouble v0 = 0.;
02904 
02905             cpl_image* variance = NULL;
02906             cpl_image* bpixmap = NULL;
02907 
02908             GiExtractHorneConfig setup;
02909 
02910 
02911             result->spectra = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02912             result->error = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02913             result->npixels = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02914             result->centroid = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02915             result->model = NULL;
02916 
02917             _spectra = giraffe_image_get(result->spectra);
02918             _error = giraffe_image_get(result->error);
02919             _npixels = giraffe_image_get(result->npixels);
02920             _centroid = giraffe_image_get(result->centroid);
02921 
02922             setup.clip.iterations = config->psf.iterations;
02923             setup.clip.level = config->psf.sigma;
02924             setup.clip.fraction = config->horne.mingood;
02925             setup.ewidth = config->horne.ewidth;
02926             setup.exptime = exptime;
02927             setup.ron = bias_sigma;
02928             setup.dark = dark_value;
02929 
02930             if (bpixel != NULL) {
02931 
02932                 bpixmap = giraffe_image_get(bpixel);
02933 
02934                 if (cpl_image_get_size_x(bpixmap) != xsize ||
02935                     cpl_image_get_size_y(bpixmap) != ysize) {
02936 
02937                     cxbool crop = FALSE;
02938 
02939                     cpl_propertylist *p =
02940                         giraffe_image_get_properties(bpixel);
02941 
02942                     GiWindow w = {1, 1, 0, 0};
02943 
02944 
02945                     w.x1 = cpl_image_get_size_x(bpixmap);
02946                     w.y1 = cpl_image_get_size_y(bpixmap);
02947 
02948                     if (cpl_propertylist_has(p, GIALIAS_PRSCX)) {
02949                         w.x0 += cpl_propertylist_get_int(p, GIALIAS_PRSCX);
02950                         crop = TRUE;
02951                     }
02952 
02953                     if (cpl_propertylist_has(p, GIALIAS_OVSCX)) {
02954                         w.x1 -= cpl_propertylist_get_int(p, GIALIAS_OVSCX);
02955                         crop = TRUE;
02956                     }
02957 
02958                     if (cpl_propertylist_has(p, GIALIAS_PRSCY)) {
02959                         w.y0 += cpl_propertylist_get_int(p, GIALIAS_PRSCY);
02960                         crop = TRUE;
02961                     }
02962 
02963                     if (cpl_propertylist_has(p, GIALIAS_OVSCY)) {
02964                         w.y1 -= cpl_propertylist_get_int(p, GIALIAS_OVSCY);
02965                         crop = TRUE;
02966                     }
02967 
02968                     if ((w.x1 - w.x0 + 1) != xsize ||
02969                         (w.y1 - w.y0 + 1) != ysize) {
02970 
02971                         cpl_msg_error(fctid, "Invalid bad pixel map! "
02972                                         "Image sizes do not match!");
02973 
02974                         giraffe_image_delete(result->spectra);
02975                         result->spectra = NULL;
02976 
02977                         giraffe_image_delete(result->error);
02978                         result->error = NULL;
02979 
02980                         giraffe_image_delete(result->npixels);
02981                         result->npixels = NULL;
02982 
02983                         giraffe_image_delete(result->centroid);
02984                         result->centroid = NULL;
02985 
02986                         giraffe_image_delete(result->model);
02987                         result->model = NULL;
02988 
02989                         return 1;
02990 
02991                     }
02992 
02993                     if (crop == TRUE) {
02994                         bpixmap = cpl_image_extract(bpixmap, w.x0, w.y0,
02995                             w.x1, w.y1);
02996                     }
02997 
02998                 }
02999 
03000             }
03001 
03002             variance = cpl_image_new(xsize, ysize, CPL_TYPE_DOUBLE);
03003             v0 = bias_sigma * bias_sigma + dark_value * exptime;
03004 
03005 
03006             if (slight != NULL) {
03007 
03008                 register cxsize i = 0;
03009                 register cxsize npixels = xsize * ysize;
03010 
03011                 const cxdouble* _slight =
03012                     cpl_image_get_data_double(giraffe_image_get(slight));
03013 
03014                 cxdouble* _variance = cpl_image_get_data_double(variance);
03015 
03016                 for (i = 0; i < npixels; i++) {
03017                     _variance[i] = v0 + fabs(_slight[i]);
03018                 }
03019 
03020             }
03021             else {
03022 
03023                 register cxsize i = 0;
03024                 register cxsize npixels = xsize * ysize;
03025 
03026                 cxdouble* _variance = cpl_image_get_data_double(variance);
03027 
03028                 for (i = 0; i < npixels; i++) {
03029                     _variance[i] = v0;
03030                 }
03031 
03032             }
03033 
03034 
03035             status = _giraffe_extract_horne(_image, variance, _fibers,
03036                                             _locy, _locw, sloc->psf,
03037                                             bpixmap, _spectra, _error,
03038                                             _npixels, _centroid, &setup);
03039 
03040             cpl_image_delete(variance);
03041             variance = NULL;
03042 
03043             if (bpixmap != giraffe_image_get(bpixel)) {
03044                 cpl_image_delete(bpixmap);
03045             }
03046             bpixmap = NULL;
03047 
03048             break;
03049 
03050         }
03051 
03052         default:
03053             gi_message("%s: Method %d selected for spectrum extraction.",
03054                        fctid, config->emethod);
03055             cpl_msg_error(fctid, "Invalid extraction method!");
03056 
03057             status = 1;
03058             break;
03059     }
03060 
03061 
03062     if (status) {
03063 
03064         giraffe_image_delete(result->spectra);
03065         result->spectra = NULL;
03066 
03067         giraffe_image_delete(result->error);
03068         result->error = NULL;
03069 
03070         giraffe_image_delete(result->npixels);
03071         result->npixels = NULL;
03072 
03073         giraffe_image_delete(result->centroid);
03074         result->centroid = NULL;
03075 
03076         giraffe_image_delete(result->model);
03077         result->model = NULL;
03078 
03079         cpl_msg_error(fctid, "Spectrum extraction (method %d) failed!",
03080                       config->emethod);
03081 
03082         return 1;
03083 
03084     }
03085 
03086 
03087     /*
03088      * Postprocessing
03089      */
03090 
03091     /*
03092      * Extracted spectra frame
03093      */
03094 
03095     properties = giraffe_image_get_properties(image);
03096     giraffe_image_set_properties(result->spectra, properties);
03097 
03098     properties = giraffe_image_get_properties(result->spectra);
03099 
03100     /*
03101      * Copy some properties from the localization frame.
03102      */
03103 
03104     // FIXME: Is this really needed? (RP)
03105 
03106     giraffe_propertylist_update(properties,
03107                                 giraffe_image_get_properties(sloc->locy),
03108                                 "^ESO PRO LOC.*");
03109 
03110     cpl_propertylist_set_int(properties, GIALIAS_NAXIS1,
03111                              cpl_image_get_size_x(_spectra));
03112     cpl_propertylist_set_int(properties, GIALIAS_NAXIS2,
03113                              cpl_image_get_size_y(_spectra));
03114 
03115     cpl_propertylist_set_int(properties, GIALIAS_BITPIX, -32);
03116     cpl_propertylist_set_double(properties, GIALIAS_BZERO, 0.);
03117     cpl_propertylist_set_double(properties, GIALIAS_BSCALE, 1.);
03118 
03119     cpl_propertylist_update_int(properties, GIALIAS_NFIBERS,
03120                                 cpl_image_get_size_x(_spectra));
03121 
03122     cpl_propertylist_append_int(properties, GIALIAS_EXT_NX,
03123                                 cpl_image_get_size_y(_spectra));
03124     cpl_propertylist_append_int(properties, GIALIAS_EXT_NS,
03125                                 cpl_image_get_size_x(_spectra));
03126 
03127     switch (config->emethod) {
03128         case GIEXTRACT_SUM:
03129             cpl_propertylist_append_string(properties, GIALIAS_EXT_METHOD,
03130                                            "SUM");
03131             cpl_propertylist_set_comment(properties, GIALIAS_EXT_METHOD,
03132                                          "Spectrum extraction method");
03133         break;
03134 
03135         case GIEXTRACT_HORNE:
03136         {
03137 
03138             cpl_propertylist_append_string(properties, GIALIAS_EXT_METHOD,
03139                                            "HORNE");
03140             cpl_propertylist_set_comment(properties, GIALIAS_EXT_METHOD,
03141                                          "Spectrum extraction method");
03142 
03143             cpl_propertylist_append_string(properties, GIALIAS_EXTPSF_MODEL,
03144                                            config->psf.model);
03145             cpl_propertylist_set_comment(properties, GIALIAS_EXTPSF_MODEL,
03146                                          "PSF model used");
03147             cpl_propertylist_append_double(properties, GIALIAS_EXTPSF_SIGMA,
03148                                            config->psf.sigma);
03149             cpl_propertylist_set_comment(properties, GIALIAS_EXTPSF_SIGMA,
03150                                          "PSF fit sigma clipping threshold");
03151             cpl_propertylist_append_int(properties, GIALIAS_EXTPSF_NITER,
03152                                         config->psf.iterations);
03153             cpl_propertylist_set_comment(properties, GIALIAS_EXTPSF_NITER,
03154                                          "PSF fit maximum number of "
03155                                          "iterations");
03156 
03157             cpl_propertylist_append_int(properties, GIALIAS_EXTHRN_EWIDTH,
03158                                         config->horne.ewidth);
03159             cpl_propertylist_set_comment(properties, GIALIAS_EXTHRN_EWIDTH,
03160                                          "Number of extra pixels used");
03161             cpl_propertylist_append_int(properties, GIALIAS_EXTHRN_MINGOOD,
03162                                            config->horne.mingood);
03163             cpl_propertylist_set_comment(properties, GIALIAS_EXTHRN_MINGOOD,
03164                                          "Minimum number of pixels to keep");
03165 
03166 
03167             break;
03168         }
03169 
03170         case GIEXTRACT_OPTIMAL:
03171             cpl_propertylist_append_string(properties, GIALIAS_EXT_METHOD,
03172                                            "OPTIMAL");
03173             cpl_propertylist_set_comment(properties, GIALIAS_EXT_METHOD,
03174                                          "Spectrum extraction method");
03175 
03176             cpl_propertylist_append_string(properties, GIALIAS_EXTPSF_MODEL,
03177                                            config->psf.model);
03178             cpl_propertylist_set_comment(properties, GIALIAS_EXTPSF_MODEL,
03179                                          "PSF model used");
03180             cpl_propertylist_append_double(properties, GIALIAS_EXTPSF_SIGMA,
03181                                            config->psf.sigma);
03182             cpl_propertylist_set_comment(properties, GIALIAS_EXTPSF_SIGMA,
03183                                          "PSF fit sigma clipping threshold");
03184             cpl_propertylist_append_int(properties, GIALIAS_EXTPSF_NITER,
03185                                         config->psf.iterations);
03186             cpl_propertylist_set_comment(properties, GIALIAS_EXTPSF_NITER,
03187                                          "PSF fit maximum number of "
03188                                          "iterations");
03189 
03190             cpl_propertylist_append_double(properties, GIALIAS_EXTOPT_FRACTION,
03191                                         config->optimal.fraction);
03192             cpl_propertylist_set_comment(properties, GIALIAS_EXTOPT_FRACTION,
03193                                          "Minimum fraction of pixels used.");
03194             cpl_propertylist_append_double(properties, GIALIAS_EXTOPT_WFACTOR,
03195                                            config->optimal.wfactor);
03196             cpl_propertylist_set_comment(properties, GIALIAS_EXTOPT_WFACTOR,
03197                                          "Multiple of the fiber PSF half "
03198                                          "width used for spectrum "
03199                                          "extraction.");
03200             cpl_propertylist_append_int(properties, GIALIAS_EXTOPT_BGORDER,
03201                                         config->optimal.bkgorder);
03202             cpl_propertylist_set_comment(properties, GIALIAS_EXTOPT_BGORDER,
03203                                          "Order of the background polynomial "
03204                                          "model along the spatial direction.");
03205 
03206             break;
03207 
03208         default:
03209             break;
03210     }
03211 
03212     cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE, "EXTSP");
03213     cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
03214                                  "Extracted spectra");
03215 
03216 
03217     /*
03218      * Extracted spectra errors frame
03219      */
03220 
03221     giraffe_image_set_properties(result->error, properties);
03222     properties = giraffe_image_get_properties(result->error);
03223 
03224     cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE, "EXTERRS");
03225     cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
03226                                  "Extracted spectra errors");
03227 
03228 
03229     /*
03230      * Extracted spectra centroids frame
03231      */
03232 
03233     giraffe_image_set_properties(result->centroid, properties);
03234     properties = giraffe_image_get_properties(result->centroid);
03235 
03236     cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE, "EXTYCEN");
03237     cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
03238                                  "Extracted spectra centroids");
03239 
03240 
03241     /*
03242      * Extracted spectra npixels frame
03243      */
03244 
03245     if (result->npixels != NULL) {
03246         giraffe_image_set_properties(result->npixels, properties);
03247         properties = giraffe_image_get_properties(result->npixels);
03248 
03249         cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE, "EXTNPIX");
03250         cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
03251                                     "Extracted spectra npixels");
03252     }
03253 
03254 
03255     /*
03256      * Model spectra frame
03257      */
03258 
03259     if (result->model != NULL) {
03260         giraffe_image_set_properties(result->model, properties);
03261         properties = giraffe_image_get_properties(result->model);
03262 
03263         cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE, "EXTMODEL");
03264         cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
03265                                      "Model spectra used for extraction");
03266     }
03267 
03268     return 0;
03269 
03270 }
03271 
03272 
03283 GiExtractConfig*
03284 giraffe_extract_config_create(cpl_parameterlist* list)
03285 {
03286 
03287     const cxchar* s;
03288     cpl_parameter* p;
03289 
03290     GiExtractConfig* config = NULL;
03291 
03292 
03293     if (!list) {
03294         return NULL;
03295     }
03296 
03297     config = cx_calloc(1, sizeof *config);
03298 
03299     p = cpl_parameterlist_find(list, "giraffe.extraction.method");
03300     s = cpl_parameter_get_string(p);
03301     if (!strcmp(s, "OPTIMAL")) {
03302         config->emethod = GIEXTRACT_OPTIMAL;
03303     }
03304     else if (!strcmp(s, "HORNE")) {
03305         config->emethod = GIEXTRACT_HORNE;
03306     }
03307     else {
03308         config->emethod = GIEXTRACT_SUM;
03309     }
03310 
03311     p = cpl_parameterlist_find(list, "giraffe.extraction.ron");
03312     config->ron = cpl_parameter_get_double(p);
03313 
03314     p = cpl_parameterlist_find(list, "giraffe.extraction.psf.model");
03315     config->psf.model = cx_strdup(cpl_parameter_get_string(p));
03316 
03317     p = cpl_parameterlist_find(list, "giraffe.extraction.psf.sigma");
03318     config->psf.sigma = cpl_parameter_get_double(p);
03319 
03320     p = cpl_parameterlist_find(list, "giraffe.extraction.psf.iterations");
03321     config->psf.iterations = cpl_parameter_get_int(p);
03322 
03323 
03324     p = cpl_parameterlist_find(list, "giraffe.extraction.horne.extrawidth");
03325     config->horne.ewidth = cpl_parameter_get_int(p);
03326 
03327     p = cpl_parameterlist_find(list, "giraffe.extraction.horne.mingood");
03328     config->horne.mingood = cpl_parameter_get_double(p);
03329 
03330 
03331     p = cpl_parameterlist_find(list, "giraffe.extraction.optimal.fraction");
03332     config->optimal.fraction = cpl_parameter_get_double(p);
03333 
03334     p = cpl_parameterlist_find(list, "giraffe.extraction.optimal.wfactor");
03335     config->optimal.wfactor = cpl_parameter_get_double(p);
03336 
03337     p = cpl_parameterlist_find(list, "giraffe.extraction.optimal.bkgorder");
03338     config->optimal.bkgorder = cpl_parameter_get_int(p);
03339 
03340     return config;
03341 
03342 }
03343 
03344 
03357 void
03358 giraffe_extract_config_destroy(GiExtractConfig* config)
03359 {
03360 
03361     if (config) {
03362 
03363         if (config->psf.model) {
03364             cx_free(config->psf.model);
03365         }
03366 
03367         cx_free(config);
03368 
03369     }
03370 
03371     return;
03372 
03373 }
03374 
03375 
03387 void
03388 giraffe_extract_config_add(cpl_parameterlist* list)
03389 {
03390 
03391     cpl_parameter* p = NULL;
03392 
03393 
03394     if (list == NULL) {
03395         return;
03396     }
03397 
03398     p = cpl_parameter_new_enum("giraffe.extraction.method",
03399                                CPL_TYPE_STRING,
03400                                "Extraction method: 'SUM', 'HORNE' or "
03401                                "'OPTIMAL'",
03402                                "giraffe.extraction",
03403                                "SUM", 3, "SUM", "OPTIMAL", "HORNE");
03404     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-method");
03405     cpl_parameterlist_append(list, p);
03406 
03407 
03408     p = cpl_parameter_new_value("giraffe.extraction.ron",
03409                                 CPL_TYPE_DOUBLE,
03410                                 "New bias sigma (RON) value for "
03411                                 "bias and dark "
03412                                 "corrected image",
03413                                 "giraffe.extraction",
03414                                 -1.);
03415     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-ron");
03416     cpl_parameterlist_append(list, p);
03417 
03418 
03419     p = cpl_parameter_new_enum("giraffe.extraction.psf.model",
03420                                CPL_TYPE_STRING,
03421                                "PSF profile model: `psfexp', `psfexp2'",
03422                                "giraffe.extraction.psf",
03423                                "psfexp2", 2, "psfexp", "psfexp2");
03424     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-psfmodel");
03425     cpl_parameterlist_append(list, p);
03426 
03427 
03428     p = cpl_parameter_new_value("giraffe.extraction.psf.sigma",
03429                                 CPL_TYPE_DOUBLE,
03430                                 "Sigma clippging threshold used for "
03431                                 "rejecting data points during PSF fitting "
03432                                 "(Horne's sigma). It is used to reject bad "
03433                                 "pixels and cosmics.",
03434                                 "giraffe.extraction.psf",
03435                                 7.);
03436     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-psfsigma");
03437     cpl_parameterlist_append(list, p);
03438 
03439 
03440     p = cpl_parameter_new_value("giraffe.extraction.psf.iterations",
03441                                 CPL_TYPE_INT,
03442                                 "Maximum number of iterations used for "
03443                                 "fitting the PSF profile.",
03444                                 "giraffe.extraction.psf",
03445                                 2);
03446     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-psfniter");
03447     cpl_parameterlist_append(list, p);
03448 
03449 
03450     p = cpl_parameter_new_value("giraffe.extraction.horne.extrawidth",
03451                                 CPL_TYPE_INT,
03452                                 "Horne extraction method: Number of "
03453                                 "extra pixels added to the fiber "
03454                                 "half-width.",
03455                                 "giraffe.extraction.horne",
03456                                 2);
03457     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-hewidth");
03458     cpl_parameterlist_append(list, p);
03459 
03460 
03461     p = cpl_parameter_new_value("giraffe.extraction.horne.mingood",
03462                                 CPL_TYPE_INT,
03463                                 "Horne extraction method: Minimum number of "
03464                                 "points used for the profile fit. It sets "
03465                                 "the lower limit of data points for the "
03466                                 "pixel rejection.",
03467                                 "giraffe.extraction.horne",
03468                                 3);
03469     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-hmingood");
03470     cpl_parameterlist_append(list, p);
03471 
03472 
03473     p = cpl_parameter_new_range("giraffe.extraction.optimal.fraction",
03474                                 CPL_TYPE_DOUBLE,
03475                                 "Optimal extraction method: Minimum fraction "
03476                                 "of the data points used for fitting the "
03477                                 "fiber profiles. It sets the lower limit "
03478                                 "for the pixel rejection.",
03479                                 "giraffe.extraction.optimal",
03480                                 0.9, 0.0, 1.0);
03481     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-omfrac");
03482     cpl_parameterlist_append(list, p);
03483 
03484 
03485     p = cpl_parameter_new_value("giraffe.extraction.optimal.wfactor",
03486                                 CPL_TYPE_DOUBLE,
03487                                 "Optimal extraction method: Factor by which "
03488                                 "the fiber PSF half width is multiplied. "
03489                                 "Adjacent spectra within this area are "
03490                                 "assumed to affect the spectrum being "
03491                                 "extracted.",
03492                                 "giraffe.extraction.optimal",
03493                                 3.);
03494     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-owfactor");
03495     cpl_parameterlist_append(list, p);
03496 
03497 
03498     p = cpl_parameter_new_value("giraffe.extraction.optimal.bkgorder",
03499                                 CPL_TYPE_INT,
03500                                 "Optimal extraction method: Order of the "
03501                                 "polynomial background model, which is "
03502                                 "fitted for each wavelength bin along the "
03503                                 "spatial direction.",
03504                                 "giraffe.extraction.optimal",
03505                                 2);
03506     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-obkgorder");
03507     cpl_parameterlist_append(list, p);
03508 
03509 
03510     return;
03511 
03512 }

This file is part of the GIRAFFE Pipeline Reference Manual 2.5.1.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Tue Mar 18 10:47:41 2008 by doxygen 1.4.6 written by Dimitri van Heesch, © 1997-2004