GIRAFFE Pipeline Reference Manual

giextract.c

00001 /* $Id: giextract.c,v 1.34 2008/05/29 11:18:47 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/05/29 11:18:47 $
00024  * $Revision: 1.34 $
00025  * $Name: giraffe-2_8_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 
02423     /*
02424      * Compute errors of the extracted spectra from the variance
02425      */
02426 
02427     cpl_image_power(mse, 0.5);
02428 
02429     _giraffe_optimal_workspace_delete(workspace);
02430     workspace = NULL;
02431 
02432     _giraffe_extraction_psflimits_delete(limits);
02433     limits = NULL;
02434 
02435     _giraffe_extractionslice_delete(slice);
02436     slice = NULL;
02437 
02438     cpl_matrix_delete(weights);
02439     weights = NULL;
02440 
02441     cpl_matrix_delete(mask);
02442     mask = NULL;
02443 
02444     cpl_matrix_delete(variance);
02445     variance = NULL;
02446 
02447     cpl_matrix_delete(signal);
02448     signal = NULL;
02449 
02450     cpl_matrix_delete(profiles);
02451     profiles = NULL;
02452 
02453     giraffe_model_delete(psfmodel);
02454     psfmodel = NULL;
02455 
02456     return 0;
02457 
02458 }
02459 
02460 
02485 cxint
02486 giraffe_extract_spectra(GiExtraction* result, GiImage* image,
02487                         GiTable* fibers, GiLocalization* sloc,
02488                         GiImage* bpixel, GiImage* slight,
02489                         GiExtractConfig* config)
02490 {
02491 
02492     const cxchar *fctid = "giraffe_extract_spectra";
02493 
02494 
02495     cxint ns = 0;
02496     cxint nx = 0;
02497     cxint ny = 0;
02498     cxint status = 0;
02499 
02500     cxdouble bias_sigma = 0.;
02501     cxdouble dark_value = 0;
02502     cxdouble exptime = 0;
02503 
02504     cpl_propertylist *properties;
02505 
02506     cpl_image* _image = NULL;
02507     cpl_image* _locy = NULL;
02508     cpl_image* _locw = NULL;
02509     cpl_image* _spectra = NULL;
02510     cpl_image* _error = NULL;
02511     cpl_image* _npixels = NULL;
02512     cpl_image* _centroid = NULL;
02513     cpl_image* _model = NULL;
02514 
02515     cpl_table* _fibers = NULL;
02516 
02517 
02518     /*
02519      * Preprocessing
02520      */
02521 
02522     if (!result || !image || !fibers || !sloc || !config) {
02523         cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
02524         return 1;
02525     }
02526 
02527 
02528     if ((sloc->locy == NULL) || (sloc->locw == NULL)) {
02529         cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
02530         return 1;
02531     }
02532 
02533     if (result->spectra != NULL || result->error != NULL ||
02534         result->npixels != NULL || result->centroid != NULL ||
02535         result->model != NULL) {
02536         gi_warning("%s: Results structure at %p is not empty! Contents "
02537                    "might be lost.", fctid, result);
02538     }
02539 
02540     _fibers = giraffe_table_get(fibers);
02541 
02542     if (_fibers == NULL) {
02543         cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
02544         return 1;
02545     }
02546 
02547     properties = giraffe_image_get_properties(image);
02548 
02549     if (properties == NULL) {
02550         cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
02551         return 1;
02552     }
02553 
02554     if ((config->emethod == GIEXTRACT_OPTIMAL) && (sloc->psf == NULL)) {
02555         cpl_msg_error(fctid, "Missing data: PSF profile data is required "
02556                 "for optimal spectrum extraction!");
02557         return 1;
02558     }
02559 
02560     if (config->ron > 0.) {
02561 
02562         cpl_msg_info(fctid, "Setting bias sigma value property (%s) to %.4g",
02563                      GIALIAS_BIASSIGMA, config->ron);
02564 
02565         cpl_propertylist_update_double(properties, GIALIAS_BIASSIGMA,
02566                                        config->ron);
02567     }
02568     else {
02569         if (!cpl_propertylist_has(properties, GIALIAS_BIASSIGMA)) {
02570             cpl_msg_error(fctid, "Missing bias value property (%s)!",
02571                           GIALIAS_BIASSIGMA);
02572             return 1;
02573         }
02574     }
02575 
02576     bias_sigma = cpl_propertylist_get_double(properties, GIALIAS_BIASSIGMA);
02577 
02578 
02579     if (!cpl_propertylist_has(properties, GIALIAS_DARKVALUE)) {
02580 
02581         dark_value = 0.;
02582 
02583         cpl_msg_warning(fctid, "Missing dark value property (%s), will be "
02584                         "set to 0.!", GIALIAS_DARKVALUE);
02585         cpl_propertylist_append_double(properties, GIALIAS_DARKVALUE,
02586                                        dark_value);
02587 
02588     }
02589     else {
02590         dark_value = cpl_propertylist_get_double(properties,
02591                                                  GIALIAS_DARKVALUE);
02592     }
02593 
02594 
02595     if (!cpl_propertylist_has(properties, GIALIAS_EXPTIME)) {
02596         cpl_msg_error(fctid, "Missing exposure time property (%s)!",
02597                       GIALIAS_EXPTIME);
02598         return 1;
02599     }
02600     else {
02601         exptime = cpl_propertylist_get_double(properties, GIALIAS_EXPTIME);
02602     }
02603 
02604     if (cpl_propertylist_has(properties, GIALIAS_CONAD)) {
02605 
02606         cxdouble conad = cpl_propertylist_get_double(properties,
02607                                                      GIALIAS_CONAD);
02608 
02609         bias_sigma *= conad;
02610         dark_value *= conad;
02611 
02612     }
02613 
02614 
02615     /*
02616      * Processing
02617      */
02618 
02619     _image = giraffe_image_get(image);
02620     _locy = giraffe_image_get(sloc->locy);
02621     _locw = giraffe_image_get(sloc->locw);
02622 
02623     ny = cpl_image_get_size_x(_image);
02624     nx = cpl_image_get_size_y(_locw);
02625     ns = cpl_table_get_nrow(_fibers);
02626 
02627 
02628     switch (config->emethod) {
02629         case GIEXTRACT_SUM:
02630         {
02631 
02632             cxint xsize = cpl_image_get_size_x(_image);
02633             cxint ysize = cpl_image_get_size_y(_image);
02634 
02635             cxdouble bias_variance = bias_sigma * bias_sigma;
02636 
02637             cpl_image* bpixmap = NULL;
02638             cpl_image* variance = NULL;
02639 
02640 
02641             result->spectra = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02642             result->error = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02643             result->npixels = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02644             result->centroid = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02645             result->model = NULL;
02646 
02647             _spectra = giraffe_image_get(result->spectra);
02648             _error = giraffe_image_get(result->error);
02649             _npixels = giraffe_image_get(result->npixels);
02650             _centroid = giraffe_image_get(result->centroid);
02651 
02652             if (bpixel != NULL) {
02653 
02654                 bpixmap = giraffe_image_get(bpixel);
02655 
02656                 if (cpl_image_get_size_x(bpixmap) != xsize ||
02657                     cpl_image_get_size_y(bpixmap) != ysize) {
02658 
02659                     cxbool crop = FALSE;
02660 
02661                     cpl_propertylist *p =
02662                             giraffe_image_get_properties(bpixel);
02663 
02664                     GiWindow w = {1, 1, 0, 0};
02665 
02666 
02667                     w.x1 = cpl_image_get_size_x(bpixmap);
02668                     w.y1 = cpl_image_get_size_y(bpixmap);
02669 
02670                     if (cpl_propertylist_has(p, GIALIAS_PRSCX)) {
02671                         w.x0 += cpl_propertylist_get_int(p, GIALIAS_PRSCX);
02672                         crop = TRUE;
02673                     }
02674 
02675                     if (cpl_propertylist_has(p, GIALIAS_OVSCX)) {
02676                         w.x1 -= cpl_propertylist_get_int(p, GIALIAS_OVSCX);
02677                         crop = TRUE;
02678                     }
02679 
02680                     if (cpl_propertylist_has(p, GIALIAS_PRSCY)) {
02681                         w.y0 += cpl_propertylist_get_int(p, GIALIAS_PRSCY);
02682                         crop = TRUE;
02683                     }
02684 
02685                     if (cpl_propertylist_has(p, GIALIAS_OVSCY)) {
02686                         w.y1 -= cpl_propertylist_get_int(p, GIALIAS_OVSCY);
02687                         crop = TRUE;
02688                     }
02689 
02690                     if ((w.x1 - w.x0 + 1) != xsize ||
02691                         (w.y1 - w.y0 + 1) != ysize) {
02692                         cpl_msg_error(fctid, "Invalid bad pixel map! Image "
02693                                       "sizes do not match!");
02694 
02695                         giraffe_image_delete(result->spectra);
02696                         result->spectra = NULL;
02697 
02698                         giraffe_image_delete(result->error);
02699                         result->error = NULL;
02700 
02701                         giraffe_image_delete(result->npixels);
02702                         result->npixels = NULL;
02703 
02704                         giraffe_image_delete(result->centroid);
02705                         result->centroid = NULL;
02706 
02707                         giraffe_image_delete(result->model);
02708                         result->model = NULL;
02709 
02710                             return 1;
02711                     }
02712 
02713                     if (crop == TRUE) {
02714                         bpixmap = cpl_image_extract(bpixmap, w.x0, w.y0,
02715                                                     w.x1, w.y1);
02716                     }
02717 
02718                 }
02719 
02720             }
02721 
02722             if (slight != NULL) {
02723                 cpl_msg_warning(fctid, "Scattered light model will be "
02724                                 "ignored for extraction method `SUM'");
02725             }
02726 
02727             variance = cpl_image_abs_create(_image);
02728             cpl_image_add_scalar(variance,
02729                                  bias_variance + dark_value * exptime);
02730 
02731             status = _giraffe_extract_summation(_image, variance, _fibers,
02732                                                 _locy, _locw, bpixmap,
02733                                                 _spectra, _error, _npixels,
02734                                                 _centroid);
02735 
02736             cpl_image_delete(variance);
02737             if (bpixmap != giraffe_image_get(bpixel)) {
02738                 cpl_image_delete(bpixmap);
02739             }
02740             bpixmap = NULL;
02741 
02742             break;
02743 
02744         }
02745 
02746         case GIEXTRACT_OPTIMAL:
02747         {
02748 
02749             cxint xsize = cpl_image_get_size_x(_image);
02750             cxint ysize = cpl_image_get_size_y(_image);
02751 
02752             cxdouble v0 = 0.;
02753 
02754             cpl_image* variance = NULL;
02755             cpl_image* bpixmap = NULL;
02756 
02757             GiExtractOptimalConfig setup;
02758 
02759 
02760             result->spectra = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02761             result->error = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02762             result->npixels = NULL;
02763             result->model = giraffe_image_create(CPL_TYPE_DOUBLE, ny, nx);
02764             result->centroid = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02765 
02766             _spectra = giraffe_image_get(result->spectra);
02767             _error = giraffe_image_get(result->error);
02768             _model = giraffe_image_get(result->model);
02769             _centroid = giraffe_image_get(result->centroid);
02770 
02771             setup.clip.iterations = config->psf.iterations;
02772             setup.clip.level = config->psf.sigma;
02773             setup.clip.fraction = config->optimal.fraction;
02774             setup.limits = config->optimal.wfactor < 0. ? FALSE : TRUE;
02775             setup.ewidth = CX_MAX(1., fabs(config->optimal.wfactor));
02776             setup.bkgorder = config->optimal.bkgorder;
02777             setup.exptime = exptime;
02778             setup.ron = bias_sigma;
02779             setup.dark = dark_value;
02780 
02781 
02782             if (bpixel != NULL) {
02783 
02784                 bpixmap = giraffe_image_get(bpixel);
02785 
02786                 if (cpl_image_get_size_x(bpixmap) != xsize ||
02787                     cpl_image_get_size_y(bpixmap) != ysize) {
02788 
02789                         cxbool crop = FALSE;
02790 
02791                         cpl_propertylist *p =
02792                             giraffe_image_get_properties(bpixel);
02793 
02794                         GiWindow w = {1, 1, 0, 0};
02795 
02796 
02797                         w.x1 = cpl_image_get_size_x(bpixmap);
02798                         w.y1 = cpl_image_get_size_y(bpixmap);
02799 
02800                         if (cpl_propertylist_has(p, GIALIAS_PRSCX)) {
02801                             w.x0 += cpl_propertylist_get_int(p, GIALIAS_PRSCX);
02802                             crop = TRUE;
02803                         }
02804 
02805                         if (cpl_propertylist_has(p, GIALIAS_OVSCX)) {
02806                             w.x1 -= cpl_propertylist_get_int(p, GIALIAS_OVSCX);
02807                             crop = TRUE;
02808                         }
02809 
02810                         if (cpl_propertylist_has(p, GIALIAS_PRSCY)) {
02811                             w.y0 += cpl_propertylist_get_int(p, GIALIAS_PRSCY);
02812                             crop = TRUE;
02813                         }
02814 
02815                         if (cpl_propertylist_has(p, GIALIAS_OVSCY)) {
02816                             w.y1 -= cpl_propertylist_get_int(p, GIALIAS_OVSCY);
02817                             crop = TRUE;
02818                         }
02819 
02820                         if ((w.x1 - w.x0 + 1) != xsize ||
02821                             (w.y1 - w.y0 + 1) != ysize) {
02822 
02823                                 cpl_msg_error(fctid, "Invalid bad pixel map! "
02824                                     "Image sizes do not match!");
02825 
02826                                 giraffe_image_delete(result->spectra);
02827                                 result->spectra = NULL;
02828 
02829                                 giraffe_image_delete(result->error);
02830                                 result->error = NULL;
02831 
02832                                 giraffe_image_delete(result->npixels);
02833                                 result->npixels = NULL;
02834 
02835                                 giraffe_image_delete(result->centroid);
02836                                 result->centroid = NULL;
02837 
02838                                 giraffe_image_delete(result->model);
02839                                 result->model = NULL;
02840 
02841                                 return 1;
02842 
02843                             }
02844 
02845                         if (crop == TRUE) {
02846                             bpixmap = cpl_image_extract(bpixmap, w.x0, w.y0,
02847                                 w.x1, w.y1);
02848                         }
02849 
02850                     }
02851 
02852             }
02853 
02854             variance = cpl_image_new(xsize, ysize, CPL_TYPE_DOUBLE);
02855             v0 = bias_sigma * bias_sigma + dark_value * exptime;
02856 
02857 
02858             if (slight != NULL) {
02859 
02860                 register cxsize i = 0;
02861                 register cxsize npixels = xsize * ysize;
02862 
02863                 const cxdouble* _slight =
02864                     cpl_image_get_data_double(giraffe_image_get(slight));
02865 
02866                 cxdouble* _variance = cpl_image_get_data_double(variance);
02867 
02868                 for (i = 0; i < npixels; i++) {
02869                     _variance[i] = v0 + fabs(_slight[i]);
02870                 }
02871 
02872             }
02873             else {
02874 
02875                 register cxsize i = 0;
02876                 register cxsize npixels = xsize * ysize;
02877 
02878                 cxdouble* _variance = cpl_image_get_data_double(variance);
02879 
02880                 for (i = 0; i < npixels; i++) {
02881                     _variance[i] = v0;
02882                 }
02883 
02884             }
02885 
02886 
02887             status = _giraffe_extract_optimal(_image, variance, _fibers,
02888                                               _locy, _locw, sloc->psf,
02889                                               bpixmap, _spectra, _error,
02890                                               _model, _centroid, &setup);
02891 
02892             cpl_image_delete(variance);
02893             variance = NULL;
02894 
02895             if (bpixmap != giraffe_image_get(bpixel)) {
02896                 cpl_image_delete(bpixmap);
02897             }
02898             bpixmap = NULL;
02899 
02900             break;
02901 
02902         }
02903 
02904         case GIEXTRACT_HORNE:
02905         {
02906 
02907             cxint xsize = cpl_image_get_size_x(_image);
02908             cxint ysize = cpl_image_get_size_y(_image);
02909 
02910             cxdouble v0 = 0.;
02911 
02912             cpl_image* variance = NULL;
02913             cpl_image* bpixmap = NULL;
02914 
02915             GiExtractHorneConfig setup;
02916 
02917 
02918             result->spectra = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02919             result->error = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02920             result->npixels = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02921             result->centroid = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02922             result->model = NULL;
02923 
02924             _spectra = giraffe_image_get(result->spectra);
02925             _error = giraffe_image_get(result->error);
02926             _npixels = giraffe_image_get(result->npixels);
02927             _centroid = giraffe_image_get(result->centroid);
02928 
02929             setup.clip.iterations = config->psf.iterations;
02930             setup.clip.level = config->psf.sigma;
02931             setup.clip.fraction = config->horne.mingood;
02932             setup.ewidth = config->horne.ewidth;
02933             setup.exptime = exptime;
02934             setup.ron = bias_sigma;
02935             setup.dark = dark_value;
02936 
02937             if (bpixel != NULL) {
02938 
02939                 bpixmap = giraffe_image_get(bpixel);
02940 
02941                 if (cpl_image_get_size_x(bpixmap) != xsize ||
02942                     cpl_image_get_size_y(bpixmap) != ysize) {
02943 
02944                     cxbool crop = FALSE;
02945 
02946                     cpl_propertylist *p =
02947                         giraffe_image_get_properties(bpixel);
02948 
02949                     GiWindow w = {1, 1, 0, 0};
02950 
02951 
02952                     w.x1 = cpl_image_get_size_x(bpixmap);
02953                     w.y1 = cpl_image_get_size_y(bpixmap);
02954 
02955                     if (cpl_propertylist_has(p, GIALIAS_PRSCX)) {
02956                         w.x0 += cpl_propertylist_get_int(p, GIALIAS_PRSCX);
02957                         crop = TRUE;
02958                     }
02959 
02960                     if (cpl_propertylist_has(p, GIALIAS_OVSCX)) {
02961                         w.x1 -= cpl_propertylist_get_int(p, GIALIAS_OVSCX);
02962                         crop = TRUE;
02963                     }
02964 
02965                     if (cpl_propertylist_has(p, GIALIAS_PRSCY)) {
02966                         w.y0 += cpl_propertylist_get_int(p, GIALIAS_PRSCY);
02967                         crop = TRUE;
02968                     }
02969 
02970                     if (cpl_propertylist_has(p, GIALIAS_OVSCY)) {
02971                         w.y1 -= cpl_propertylist_get_int(p, GIALIAS_OVSCY);
02972                         crop = TRUE;
02973                     }
02974 
02975                     if ((w.x1 - w.x0 + 1) != xsize ||
02976                         (w.y1 - w.y0 + 1) != ysize) {
02977 
02978                         cpl_msg_error(fctid, "Invalid bad pixel map! "
02979                                         "Image sizes do not match!");
02980 
02981                         giraffe_image_delete(result->spectra);
02982                         result->spectra = NULL;
02983 
02984                         giraffe_image_delete(result->error);
02985                         result->error = NULL;
02986 
02987                         giraffe_image_delete(result->npixels);
02988                         result->npixels = NULL;
02989 
02990                         giraffe_image_delete(result->centroid);
02991                         result->centroid = NULL;
02992 
02993                         giraffe_image_delete(result->model);
02994                         result->model = NULL;
02995 
02996                         return 1;
02997 
02998                     }
02999 
03000                     if (crop == TRUE) {
03001                         bpixmap = cpl_image_extract(bpixmap, w.x0, w.y0,
03002                             w.x1, w.y1);
03003                     }
03004 
03005                 }
03006 
03007             }
03008 
03009             variance = cpl_image_new(xsize, ysize, CPL_TYPE_DOUBLE);
03010             v0 = bias_sigma * bias_sigma + dark_value * exptime;
03011 
03012 
03013             if (slight != NULL) {
03014 
03015                 register cxsize i = 0;
03016                 register cxsize npixels = xsize * ysize;
03017 
03018                 const cxdouble* _slight =
03019                     cpl_image_get_data_double(giraffe_image_get(slight));
03020 
03021                 cxdouble* _variance = cpl_image_get_data_double(variance);
03022 
03023                 for (i = 0; i < npixels; i++) {
03024                     _variance[i] = v0 + fabs(_slight[i]);
03025                 }
03026 
03027             }
03028             else {
03029 
03030                 register cxsize i = 0;
03031                 register cxsize npixels = xsize * ysize;
03032 
03033                 cxdouble* _variance = cpl_image_get_data_double(variance);
03034 
03035                 for (i = 0; i < npixels; i++) {
03036                     _variance[i] = v0;
03037                 }
03038 
03039             }
03040 
03041 
03042             status = _giraffe_extract_horne(_image, variance, _fibers,
03043                                             _locy, _locw, sloc->psf,
03044                                             bpixmap, _spectra, _error,
03045                                             _npixels, _centroid, &setup);
03046 
03047             cpl_image_delete(variance);
03048             variance = NULL;
03049 
03050             if (bpixmap != giraffe_image_get(bpixel)) {
03051                 cpl_image_delete(bpixmap);
03052             }
03053             bpixmap = NULL;
03054 
03055             break;
03056 
03057         }
03058 
03059         default:
03060             gi_message("%s: Method %d selected for spectrum extraction.",
03061                        fctid, config->emethod);
03062             cpl_msg_error(fctid, "Invalid extraction method!");
03063 
03064             status = 1;
03065             break;
03066     }
03067 
03068 
03069     if (status) {
03070 
03071         giraffe_image_delete(result->spectra);
03072         result->spectra = NULL;
03073 
03074         giraffe_image_delete(result->error);
03075         result->error = NULL;
03076 
03077         giraffe_image_delete(result->npixels);
03078         result->npixels = NULL;
03079 
03080         giraffe_image_delete(result->centroid);
03081         result->centroid = NULL;
03082 
03083         giraffe_image_delete(result->model);
03084         result->model = NULL;
03085 
03086         cpl_msg_error(fctid, "Spectrum extraction (method %d) failed!",
03087                       config->emethod);
03088 
03089         return 1;
03090 
03091     }
03092 
03093 
03094     /*
03095      * Postprocessing
03096      */
03097 
03098     /*
03099      * Extracted spectra frame
03100      */
03101 
03102     properties = giraffe_image_get_properties(image);
03103     giraffe_image_set_properties(result->spectra, properties);
03104 
03105     properties = giraffe_image_get_properties(result->spectra);
03106 
03107     /*
03108      * Copy some properties from the localization frame.
03109      */
03110 
03111     // FIXME: Is this really needed? (RP)
03112 
03113     giraffe_propertylist_update(properties,
03114                                 giraffe_image_get_properties(sloc->locy),
03115                                 "^ESO PRO LOC.*");
03116 
03117     cpl_propertylist_set_int(properties, GIALIAS_NAXIS1,
03118                              cpl_image_get_size_x(_spectra));
03119     cpl_propertylist_set_int(properties, GIALIAS_NAXIS2,
03120                              cpl_image_get_size_y(_spectra));
03121 
03122     cpl_propertylist_set_int(properties, GIALIAS_BITPIX, -32);
03123     cpl_propertylist_set_double(properties, GIALIAS_BZERO, 0.);
03124     cpl_propertylist_set_double(properties, GIALIAS_BSCALE, 1.);
03125 
03126     cpl_propertylist_update_int(properties, GIALIAS_NFIBERS,
03127                                 cpl_image_get_size_x(_spectra));
03128 
03129     cpl_propertylist_append_int(properties, GIALIAS_EXT_NX,
03130                                 cpl_image_get_size_y(_spectra));
03131     cpl_propertylist_append_int(properties, GIALIAS_EXT_NS,
03132                                 cpl_image_get_size_x(_spectra));
03133 
03134     switch (config->emethod) {
03135         case GIEXTRACT_SUM:
03136             cpl_propertylist_append_string(properties, GIALIAS_EXT_METHOD,
03137                                            "SUM");
03138             cpl_propertylist_set_comment(properties, GIALIAS_EXT_METHOD,
03139                                          "Spectrum extraction method");
03140         break;
03141 
03142         case GIEXTRACT_HORNE:
03143         {
03144 
03145             cpl_propertylist_append_string(properties, GIALIAS_EXT_METHOD,
03146                                            "HORNE");
03147             cpl_propertylist_set_comment(properties, GIALIAS_EXT_METHOD,
03148                                          "Spectrum extraction method");
03149 
03150             cpl_propertylist_append_string(properties, GIALIAS_EXTPSF_MODEL,
03151                                            config->psf.model);
03152             cpl_propertylist_set_comment(properties, GIALIAS_EXTPSF_MODEL,
03153                                          "PSF model used");
03154             cpl_propertylist_append_double(properties, GIALIAS_EXTPSF_SIGMA,
03155                                            config->psf.sigma);
03156             cpl_propertylist_set_comment(properties, GIALIAS_EXTPSF_SIGMA,
03157                                          "PSF fit sigma clipping threshold");
03158             cpl_propertylist_append_int(properties, GIALIAS_EXTPSF_NITER,
03159                                         config->psf.iterations);
03160             cpl_propertylist_set_comment(properties, GIALIAS_EXTPSF_NITER,
03161                                          "PSF fit maximum number of "
03162                                          "iterations");
03163 
03164             cpl_propertylist_append_int(properties, GIALIAS_EXTHRN_EWIDTH,
03165                                         config->horne.ewidth);
03166             cpl_propertylist_set_comment(properties, GIALIAS_EXTHRN_EWIDTH,
03167                                          "Number of extra pixels used");
03168             cpl_propertylist_append_int(properties, GIALIAS_EXTHRN_MINGOOD,
03169                                            config->horne.mingood);
03170             cpl_propertylist_set_comment(properties, GIALIAS_EXTHRN_MINGOOD,
03171                                          "Minimum number of pixels to keep");
03172 
03173 
03174             break;
03175         }
03176 
03177         case GIEXTRACT_OPTIMAL:
03178             cpl_propertylist_append_string(properties, GIALIAS_EXT_METHOD,
03179                                            "OPTIMAL");
03180             cpl_propertylist_set_comment(properties, GIALIAS_EXT_METHOD,
03181                                          "Spectrum extraction method");
03182 
03183             cpl_propertylist_append_string(properties, GIALIAS_EXTPSF_MODEL,
03184                                            config->psf.model);
03185             cpl_propertylist_set_comment(properties, GIALIAS_EXTPSF_MODEL,
03186                                          "PSF model used");
03187             cpl_propertylist_append_double(properties, GIALIAS_EXTPSF_SIGMA,
03188                                            config->psf.sigma);
03189             cpl_propertylist_set_comment(properties, GIALIAS_EXTPSF_SIGMA,
03190                                          "PSF fit sigma clipping threshold");
03191             cpl_propertylist_append_int(properties, GIALIAS_EXTPSF_NITER,
03192                                         config->psf.iterations);
03193             cpl_propertylist_set_comment(properties, GIALIAS_EXTPSF_NITER,
03194                                          "PSF fit maximum number of "
03195                                          "iterations");
03196 
03197             cpl_propertylist_append_double(properties, GIALIAS_EXTOPT_FRACTION,
03198                                         config->optimal.fraction);
03199             cpl_propertylist_set_comment(properties, GIALIAS_EXTOPT_FRACTION,
03200                                          "Minimum fraction of pixels used.");
03201             cpl_propertylist_append_double(properties, GIALIAS_EXTOPT_WFACTOR,
03202                                            config->optimal.wfactor);
03203             cpl_propertylist_set_comment(properties, GIALIAS_EXTOPT_WFACTOR,
03204                                          "Multiple of the fiber PSF half "
03205                                          "width used for spectrum "
03206                                          "extraction.");
03207             cpl_propertylist_append_int(properties, GIALIAS_EXTOPT_BGORDER,
03208                                         config->optimal.bkgorder);
03209             cpl_propertylist_set_comment(properties, GIALIAS_EXTOPT_BGORDER,
03210                                          "Order of the background polynomial "
03211                                          "model along the spatial direction.");
03212 
03213             break;
03214 
03215         default:
03216             break;
03217     }
03218 
03219     cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE, "EXTSP");
03220     cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
03221                                  "Extracted spectra");
03222 
03223 
03224     /*
03225      * Extracted spectra errors frame
03226      */
03227 
03228     giraffe_image_set_properties(result->error, properties);
03229     properties = giraffe_image_get_properties(result->error);
03230 
03231     cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE, "EXTERRS");
03232     cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
03233                                  "Extracted spectra errors");
03234 
03235 
03236     /*
03237      * Extracted spectra centroids frame
03238      */
03239 
03240     giraffe_image_set_properties(result->centroid, properties);
03241     properties = giraffe_image_get_properties(result->centroid);
03242 
03243     cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE, "EXTYCEN");
03244     cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
03245                                  "Extracted spectra centroids");
03246 
03247 
03248     /*
03249      * Extracted spectra npixels frame
03250      */
03251 
03252     if (result->npixels != NULL) {
03253         giraffe_image_set_properties(result->npixels, properties);
03254         properties = giraffe_image_get_properties(result->npixels);
03255 
03256         cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE, "EXTNPIX");
03257         cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
03258                                     "Extracted spectra npixels");
03259     }
03260 
03261 
03262     /*
03263      * Model spectra frame
03264      */
03265 
03266     if (result->model != NULL) {
03267         giraffe_image_set_properties(result->model, properties);
03268         properties = giraffe_image_get_properties(result->model);
03269 
03270         cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE, "EXTMODEL");
03271         cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
03272                                      "Model spectra used for extraction");
03273     }
03274 
03275     return 0;
03276 
03277 }
03278 
03279 
03290 GiExtractConfig*
03291 giraffe_extract_config_create(cpl_parameterlist* list)
03292 {
03293 
03294     const cxchar* s;
03295     cpl_parameter* p;
03296 
03297     GiExtractConfig* config = NULL;
03298 
03299 
03300     if (!list) {
03301         return NULL;
03302     }
03303 
03304     config = cx_calloc(1, sizeof *config);
03305 
03306     p = cpl_parameterlist_find(list, "giraffe.extraction.method");
03307     s = cpl_parameter_get_string(p);
03308     if (!strcmp(s, "OPTIMAL")) {
03309         config->emethod = GIEXTRACT_OPTIMAL;
03310     }
03311     else if (!strcmp(s, "HORNE")) {
03312         config->emethod = GIEXTRACT_HORNE;
03313     }
03314     else {
03315         config->emethod = GIEXTRACT_SUM;
03316     }
03317 
03318     p = cpl_parameterlist_find(list, "giraffe.extraction.ron");
03319     config->ron = cpl_parameter_get_double(p);
03320 
03321     p = cpl_parameterlist_find(list, "giraffe.extraction.psf.model");
03322     config->psf.model = cx_strdup(cpl_parameter_get_string(p));
03323 
03324     p = cpl_parameterlist_find(list, "giraffe.extraction.psf.sigma");
03325     config->psf.sigma = cpl_parameter_get_double(p);
03326 
03327     p = cpl_parameterlist_find(list, "giraffe.extraction.psf.iterations");
03328     config->psf.iterations = cpl_parameter_get_int(p);
03329 
03330 
03331     p = cpl_parameterlist_find(list, "giraffe.extraction.horne.extrawidth");
03332     config->horne.ewidth = cpl_parameter_get_int(p);
03333 
03334     p = cpl_parameterlist_find(list, "giraffe.extraction.horne.mingood");
03335     config->horne.mingood = cpl_parameter_get_double(p);
03336 
03337 
03338     p = cpl_parameterlist_find(list, "giraffe.extraction.optimal.fraction");
03339     config->optimal.fraction = cpl_parameter_get_double(p);
03340 
03341     p = cpl_parameterlist_find(list, "giraffe.extraction.optimal.wfactor");
03342     config->optimal.wfactor = cpl_parameter_get_double(p);
03343 
03344     p = cpl_parameterlist_find(list, "giraffe.extraction.optimal.bkgorder");
03345     config->optimal.bkgorder = cpl_parameter_get_int(p);
03346 
03347     return config;
03348 
03349 }
03350 
03351 
03364 void
03365 giraffe_extract_config_destroy(GiExtractConfig* config)
03366 {
03367 
03368     if (config) {
03369 
03370         if (config->psf.model) {
03371             cx_free(config->psf.model);
03372         }
03373 
03374         cx_free(config);
03375 
03376     }
03377 
03378     return;
03379 
03380 }
03381 
03382 
03394 void
03395 giraffe_extract_config_add(cpl_parameterlist* list)
03396 {
03397 
03398     cpl_parameter* p = NULL;
03399 
03400 
03401     if (list == NULL) {
03402         return;
03403     }
03404 
03405     p = cpl_parameter_new_enum("giraffe.extraction.method",
03406                                CPL_TYPE_STRING,
03407                                "Extraction method: 'SUM', 'HORNE' or "
03408                                "'OPTIMAL'",
03409                                "giraffe.extraction",
03410                                "SUM", 3, "SUM", "OPTIMAL", "HORNE");
03411     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-method");
03412     cpl_parameterlist_append(list, p);
03413 
03414 
03415     p = cpl_parameter_new_value("giraffe.extraction.ron",
03416                                 CPL_TYPE_DOUBLE,
03417                                 "New bias sigma (RON) value for "
03418                                 "bias and dark "
03419                                 "corrected image",
03420                                 "giraffe.extraction",
03421                                 -1.);
03422     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-ron");
03423     cpl_parameterlist_append(list, p);
03424 
03425 
03426     p = cpl_parameter_new_enum("giraffe.extraction.psf.model",
03427                                CPL_TYPE_STRING,
03428                                "PSF profile model: `psfexp', `psfexp2'",
03429                                "giraffe.extraction.psf",
03430                                "psfexp2", 2, "psfexp", "psfexp2");
03431     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-psfmodel");
03432     cpl_parameterlist_append(list, p);
03433 
03434 
03435     p = cpl_parameter_new_value("giraffe.extraction.psf.sigma",
03436                                 CPL_TYPE_DOUBLE,
03437                                 "Sigma clippging threshold used for "
03438                                 "rejecting data points during PSF fitting "
03439                                 "(Horne's sigma). It is used to reject bad "
03440                                 "pixels and cosmics.",
03441                                 "giraffe.extraction.psf",
03442                                 7.);
03443     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-psfsigma");
03444     cpl_parameterlist_append(list, p);
03445 
03446 
03447     p = cpl_parameter_new_value("giraffe.extraction.psf.iterations",
03448                                 CPL_TYPE_INT,
03449                                 "Maximum number of iterations used for "
03450                                 "fitting the PSF profile.",
03451                                 "giraffe.extraction.psf",
03452                                 2);
03453     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-psfniter");
03454     cpl_parameterlist_append(list, p);
03455 
03456 
03457     p = cpl_parameter_new_value("giraffe.extraction.horne.extrawidth",
03458                                 CPL_TYPE_INT,
03459                                 "Horne extraction method: Number of "
03460                                 "extra pixels added to the fiber "
03461                                 "half-width.",
03462                                 "giraffe.extraction.horne",
03463                                 2);
03464     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-hewidth");
03465     cpl_parameterlist_append(list, p);
03466 
03467 
03468     p = cpl_parameter_new_value("giraffe.extraction.horne.mingood",
03469                                 CPL_TYPE_INT,
03470                                 "Horne extraction method: Minimum number of "
03471                                 "points used for the profile fit. It sets "
03472                                 "the lower limit of data points for the "
03473                                 "pixel rejection.",
03474                                 "giraffe.extraction.horne",
03475                                 3);
03476     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-hmingood");
03477     cpl_parameterlist_append(list, p);
03478 
03479 
03480     p = cpl_parameter_new_range("giraffe.extraction.optimal.fraction",
03481                                 CPL_TYPE_DOUBLE,
03482                                 "Optimal extraction method: Minimum fraction "
03483                                 "of the data points used for fitting the "
03484                                 "fiber profiles. It sets the lower limit "
03485                                 "for the pixel rejection.",
03486                                 "giraffe.extraction.optimal",
03487                                 0.9, 0.0, 1.0);
03488     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-omfrac");
03489     cpl_parameterlist_append(list, p);
03490 
03491 
03492     p = cpl_parameter_new_value("giraffe.extraction.optimal.wfactor",
03493                                 CPL_TYPE_DOUBLE,
03494                                 "Optimal extraction method: Factor by which "
03495                                 "the fiber PSF half width is multiplied. "
03496                                 "Adjacent spectra within this area are "
03497                                 "assumed to affect the spectrum being "
03498                                 "extracted.",
03499                                 "giraffe.extraction.optimal",
03500                                 3.);
03501     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-owfactor");
03502     cpl_parameterlist_append(list, p);
03503 
03504 
03505     p = cpl_parameter_new_value("giraffe.extraction.optimal.bkgorder",
03506                                 CPL_TYPE_INT,
03507                                 "Optimal extraction method: Order of the "
03508                                 "polynomial background model, which is "
03509                                 "fitted for each wavelength bin along the "
03510                                 "spatial direction.",
03511                                 "giraffe.extraction.optimal",
03512                                 2);
03513     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-obkgorder");
03514     cpl_parameterlist_append(list, p);
03515 
03516 
03517     return;
03518 
03519 }

This file is part of the GIRAFFE Pipeline Reference Manual 2.8.1.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Mon Aug 3 13:13:33 2009 by doxygen 1.5.1 written by Dimitri van Heesch, © 1997-2004