GIRAFFE Pipeline Reference Manual

girebinning.c

00001 /* $Id: girebinning.c,v 1.40.2.1 2008/02/21 10:52:40 rpalsa Exp $
00002  *
00003  * This file is part of the GIRAFFE Pipeline
00004  * Copyright (C) 2002-2006 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 /*
00022  * $Author: rpalsa $
00023  * $Date: 2008/02/21 10:52:40 $
00024  * $Revision: 1.40.2.1 $
00025  * $Name: giraffe-2_5_1 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #  include <config.h>
00030 #endif
00031 
00032 #include <math.h>
00033 
00034 #include <cxmacros.h>
00035 #include <cxtypes.h>
00036 #include <cxmemory.h>
00037 
00038 #include <cpl_parameter.h>
00039 #include <cpl_parameterlist.h>
00040 #include <cpl_image.h>
00041 #include <cpl_msg.h>
00042 
00043 #include "gimacros.h"
00044 #include "gidebug.h"
00045 #include "gierror.h"
00046 #include "gialias.h"
00047 #include "gimatrix.h"
00048 #include "gimessages.h"
00049 #include "gimath.h"
00050 #include "gimath_lm.h"
00051 #include "gifiberutils.h"
00052 #include "giutils.h"
00053 #include "girebinning.h"
00054 
00055 
00064 #define GIFITS_KEYWORD_MISSING_MSG "FITS KEYWORD [%s] not found!! Aborting..."
00065 #define GIWAVECAL_GRATING_WAVELENGTH_EPSILON 0.0001
00066 
00067 
00068 enum GiLocDataType {
00069     GILOCDATATYPE_UNDEFINED,
00070     GILOCDATATYPE_FITTED_DATA,
00071     GILOCDATATYPE_FIT_COEFFS
00072 };
00073 
00074 typedef enum GiLocDataType GiLocDataType;
00075 
00076 
00077 struct GiGrat {
00078     cx_string *name;         
00079     cx_string *filter_name;  
00080     cx_string *setup_name;   
00081     cx_string *slit_name;    
00082     cxint      order;        
00083     cxdouble   wlen0;        
00084     cxdouble   wlenmin;      
00085     cxdouble   wlenmax;      
00086     cxdouble   band;         
00087     cxdouble   resol;        
00088     cxdouble   space;        
00089     cxdouble   theta;        
00090     cxdouble   fcoll;        
00091     cxdouble   gcam;         
00092     cxdouble   slitdx;       
00093     cxdouble   slitdy;       
00094     cxdouble   slitphi;      
00095 };
00096 
00097 typedef struct GiGrat GiGrat;
00098 
00099 
00100 struct GiFiberPosition {
00101     cpl_matrix *x_fiber;   
00102     cpl_matrix *y_fiber;   
00103 };
00104 
00105 typedef struct GiFiberPosition GiFiberPosition;
00106 
00107 
00108 struct GiLocPosition {
00109     cxint           ydeg;
00110     cxint           wdeg;
00111     GiLocDataType   type;
00112     cpl_image      *centroids;
00113     cpl_image      *widths;
00114 };
00115 
00116 typedef struct GiLocPosition GiLocPosition;
00117 
00118 
00119 struct GiBinnParams {
00120     cxint  xdeg;     
00121     cxint  ydeg;     
00122 };
00123 
00124 typedef struct GiBinnParams GiBinnParams;
00125 
00126 
00127 struct GiSlitGeo {
00128     cxint        nsubslits;
00129     cpl_matrix **subslits;
00130 };
00131 
00132 typedef struct GiSlitGeo GiSlitGeo;
00133 
00134 struct GiWcalSolution {
00135     cxbool subslitfit;
00136     lmrq_model_id opt_mod;
00137     cpl_matrix *opt_mod_params;
00138     GiSlitGeo *wav_coeffs;
00139     GiSlitGeo *wav_limits;
00140 };
00141 
00142 typedef struct GiWcalSolution GiWcalSolution;
00143 
00144 
00145 struct GiRebinInfo {
00146     const cxchar* method;
00147     const cxchar* scale;
00148     const cxchar* range;
00149     const cxchar* units;
00150 
00151     cxdouble wmin;
00152     cxdouble wcenter;
00153     cxdouble wmax;
00154     cxdouble wstep;
00155 
00156     cxint offset;
00157 
00158 };
00159 
00160 typedef struct GiRebinInfo GiRebinInfo;
00161 
00162 
00163 /*
00164  *  Static vars for spline interpolation...
00165  */
00166 
00167 static cxdouble ddb, dde;
00168 
00169 
00170 inline static cxint
00171 _giraffe_resample_update_properties(GiImage* spectra, GiRebinInfo* info)
00172 {
00173 
00174     cpl_image* image = giraffe_image_get(spectra);
00175 
00176     cpl_propertylist* properties = giraffe_image_get_properties(spectra);
00177 
00178 
00179     giraffe_error_push();
00180 
00181     cpl_propertylist_update_double(properties, GIALIAS_DATAMIN,
00182                                    cpl_image_get_min(image));
00183     cpl_propertylist_update_double(properties, GIALIAS_DATAMAX,
00184                                    cpl_image_get_max(image));
00185 
00186     cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE,
00187                                    "BINSP");
00188 
00189     cpl_propertylist_update_int(properties, GIALIAS_BINWNX,
00190                                 cpl_image_get_size_y(image));
00191     cpl_propertylist_update_int(properties, GIALIAS_BINWNS,
00192                                 cpl_image_get_size_x(image));
00193 
00194     cpl_propertylist_update_string(properties, GIALIAS_CTYPE2,
00195                                    info->units);
00196     cpl_propertylist_update_double(properties, GIALIAS_CRPIX2,
00197                                    info->offset + 1);
00198     cpl_propertylist_update_double(properties, GIALIAS_CRVAL2,
00199                                    info->wmin);
00200     cpl_propertylist_update_double(properties, GIALIAS_CDELT2,
00201                                    info->wstep);
00202 
00203     cpl_propertylist_update_double(properties, GIALIAS_BINWLMIN,
00204                                    info->wmin);
00205     cpl_propertylist_update_double(properties, GIALIAS_BINWL0,
00206                                    info->wcenter);
00207     cpl_propertylist_update_double(properties, GIALIAS_BINWLMAX,
00208                                    info->wmax);
00209     cpl_propertylist_update_double(properties, GIALIAS_BINSTEP,
00210                                    info->wstep);
00211     cpl_propertylist_update_string(properties, GIALIAS_BINMETHOD,
00212                                    info->method);
00213     cpl_propertylist_update_string(properties, GIALIAS_BINSCALE,
00214                                    info->scale);
00215     cpl_propertylist_update_string(properties, GIALIAS_BINRANGE,
00216                                    info->range);
00217 
00218     if (cpl_error_get_code() != CPL_ERROR_NONE) {
00219         return 1;
00220     }
00221 
00222     giraffe_error_pop();
00223 
00224     return 0;
00225 
00226 }
00227 
00228 
00229 static GiGrat*
00230 _giraffe_grating_new(void)
00231 {
00232 
00233     GiGrat *grating = NULL;
00234 
00235     grating = (GiGrat*) cx_calloc(1, (cxsize)sizeof(GiGrat));
00236 
00237     grating->name        = cx_string_create("UNKNOWN");
00238     grating->filter_name = cx_string_create("UNKNOWN");
00239     grating->setup_name  = cx_string_create("UNKNOWN");
00240     grating->slit_name   = cx_string_create("UNKNOWN");
00241 
00242     return grating;
00243 
00244 }
00245 
00246 
00247 static void
00248 _giraffe_grating_delete(GiGrat *grating)
00249 {
00250 
00251     if (grating==NULL) { return; }
00252 
00253     if (grating->name!=NULL) {
00254         cx_string_delete(grating->name);
00255     }
00256     if (grating->filter_name!=NULL) {
00257         cx_string_delete(grating->filter_name);
00258     }
00259     if (grating->setup_name!=NULL) {
00260         cx_string_delete(grating->setup_name);
00261     }
00262     if (grating->slit_name!=NULL) {
00263         cx_string_delete(grating->slit_name);
00264     }
00265     cx_free(grating);
00266 
00267 }
00268 
00269 
00270 static cxint
00271 _giraffe_grating_setup(const GiTable *grating_table,
00272                        const GiImage *grating_ass_img, GiGrat *grating_setup)
00273 {
00274 
00275     /*************************************************************************
00276                                      Variables
00277     *************************************************************************/
00278 
00279     const cxchar *fctid = "_giraffe_grating_setup";
00280 
00281     cxdouble    wlen_match    = 0.0,
00282         wlen          = 0.0,
00283         tmp_gratgrv   = 0.0;
00284 
00285     cxint32     row_match     = 0,
00286         row_nulls,
00287         i             = 0;
00288 
00289     const cxchar *c_name_setup  = "SETUP";
00290     const cxchar *c_name_order  = "ORDER";
00291     const cxchar *c_name_wl0    = "WLEN0";
00292     const cxchar *c_name_wlmin  = "WLMIN";
00293     const cxchar *c_name_wlmax  = "WLMAX";
00294     const cxchar *c_name_band   = "BAND";
00295     const cxchar *c_name_theta  = "THETA";
00296     const cxchar *c_name_fcoll  = "FCOLL";
00297     const cxchar *c_name_gcam   = "GCAM";
00298     const cxchar *c_name_sdx    = "SDX";
00299     const cxchar *c_name_sdy    = "SDY";
00300     const cxchar *c_name_sdphi  = "SPHI";
00301     const cxchar *c_name_rmed   = "RMED";
00302     const cxchar *c_name_rifa   = "RIFA";
00303 
00304     cpl_propertylist  *ref_plimg     = NULL;
00305     cpl_table  *ref_gtable    = NULL;
00306     cx_string  *slit_name     = NULL;
00307 
00308     GiInstrumentMode  instrument_mode;
00309 
00310 
00311     /*************************************************************************
00312                                     Preprocessing
00313     *************************************************************************/
00314 
00315     if (grating_table  ==NULL) { return 1; }
00316     if (grating_ass_img==NULL) { return 1; }
00317     if (grating_setup  ==NULL) { return 1; }
00318 
00319     if ((ref_plimg=giraffe_image_get_properties(grating_ass_img))==NULL) {
00320         return 128;
00321     }
00322 
00323     if ((ref_gtable = giraffe_table_get(grating_table))==NULL) {
00324         return 128;
00325     }
00326 
00327     slit_name = cx_string_new();
00328 
00329     /*************************************************************************
00330                                      Processing
00331     *************************************************************************/
00332 
00333     /*
00334      *  Retrieve Grating information from associated image...
00335      */
00336 
00337     if (!cpl_propertylist_has(ref_plimg, GIALIAS_GRATWLEN)) {
00338         cpl_msg_error(fctid, GIFITS_KEYWORD_MISSING_MSG, GIALIAS_GRATWLEN);
00339         cx_string_delete(slit_name);
00340         return 2;
00341     }
00342     else {
00343         grating_setup->wlen0 = cpl_propertylist_get_double(ref_plimg,
00344                                                            GIALIAS_GRATWLEN);
00345     }
00346 
00347     if (!cpl_propertylist_has(ref_plimg, GIALIAS_GRATORDER)) {
00348         cpl_msg_error(fctid, GIFITS_KEYWORD_MISSING_MSG, GIALIAS_GRATORDER);
00349         cx_string_delete(slit_name);
00350         return 2;
00351     }
00352     else {
00353         grating_setup->order = cpl_propertylist_get_int(ref_plimg, GIALIAS_GRATORDER);
00354     }
00355 
00356     if (!cpl_propertylist_has(ref_plimg, GIALIAS_SLITNAME)) {
00357 
00358         cpl_msg_error(fctid, GIFITS_KEYWORD_MISSING_MSG, GIALIAS_SLITNAME);
00359         cx_string_delete(slit_name);
00360         return 2;
00361     } else {
00362         cx_string_set(slit_name,
00363                       cpl_propertylist_get_string(ref_plimg, GIALIAS_SLITNAME));
00364     }
00365 
00366     if (!cpl_propertylist_has(ref_plimg, GIALIAS_GRATGRV)) {
00367 
00368         cpl_msg_error(fctid, GIFITS_KEYWORD_MISSING_MSG, GIALIAS_GRATGRV);
00369         cx_string_delete(slit_name);
00370         return 2;
00371     } else {
00372         tmp_gratgrv = cpl_propertylist_get_double(ref_plimg, GIALIAS_GRATGRV );
00373     }
00374 
00375     if (!cpl_propertylist_has(ref_plimg, GIALIAS_GRATNAME)) {
00376         cpl_msg_error(fctid, GIFITS_KEYWORD_MISSING_MSG, GIALIAS_GRATNAME);
00377         cx_string_delete(slit_name);
00378         return 2;
00379     } else {
00380         cx_string_set(grating_setup->name,
00381                       cpl_propertylist_get_string(ref_plimg, GIALIAS_GRATNAME));
00382     }
00383 
00384     if (!cpl_propertylist_has(ref_plimg, GIALIAS_FILTNAME)) {
00385         cpl_msg_error(fctid, GIFITS_KEYWORD_MISSING_MSG, GIALIAS_FILTNAME);
00386         cx_string_delete(slit_name);
00387         return 2;
00388     }
00389     else {
00390         cx_string_set(grating_setup->filter_name,
00391                       cpl_propertylist_get_string(ref_plimg, GIALIAS_FILTNAME));
00392     }
00393 
00394 
00395     /*
00396      *  Find wavelength nearest to central wavelength...
00397      */
00398 
00399     for (i = 0; i < cpl_table_get_nrow(ref_gtable); i++) {
00400 
00401         cxint _order = cpl_table_get_int(ref_gtable, c_name_order, i, NULL);
00402 
00403         if (_order == grating_setup->order) {
00404 
00405             wlen = cpl_table_get(ref_gtable, c_name_wl0, i, &row_nulls);
00406 
00407             if (fabs(wlen - grating_setup->wlen0) <
00408                 fabs(wlen_match - grating_setup->wlen0)) {
00409                 wlen_match = wlen;
00410                 row_match  = i;
00411             }
00412 
00413         }
00414     }
00415 
00416 
00417     /*
00418      *  Have we found a match?...
00419      */
00420 
00421     if (fabs(wlen_match - grating_setup->wlen0) >
00422         GIWAVECAL_GRATING_WAVELENGTH_EPSILON) {
00423 
00424         cpl_msg_error(fctid, "Grating setup (wavelength %.2f nm, order %d) "
00425                       "not found in grating table!", grating_setup->wlen0,
00426                       grating_setup->order);
00427         cx_string_delete(slit_name);
00428         return 3;
00429     }
00430     else {
00431         cpl_msg_debug(fctid, "Found wlen0 in grating table at position %d",
00432                       row_match);
00433     }
00434 
00435 
00436     /*
00437      *  Retrieve values associated to matched wavelength from grating table...
00438      */
00439 
00440     cx_string_set(grating_setup->setup_name,
00441                   (cxchar*) cpl_table_get_string(ref_gtable, c_name_setup,
00442                                                  row_match));
00443 
00444     cx_string_set(grating_setup->slit_name, cx_string_get(slit_name));
00445 
00446     grating_setup->wlenmin = cpl_table_get(ref_gtable, c_name_wlmin,
00447                                            row_match, &row_nulls);
00448 
00449     grating_setup->wlenmax = cpl_table_get(ref_gtable, c_name_wlmax,
00450                                            row_match, &row_nulls);
00451 
00452     grating_setup->band = cpl_table_get(ref_gtable, c_name_band,
00453                                         row_match, &row_nulls);
00454 
00455     grating_setup->theta = cpl_table_get(ref_gtable, c_name_theta,
00456                                          row_match, &row_nulls);
00457 
00458     grating_setup->space = 1.0 / fabs(GI_MM_TO_NM * tmp_gratgrv);
00459 
00460 
00461     instrument_mode = giraffe_get_mode(ref_plimg);
00462 
00463     switch (instrument_mode) {
00464         case GIMODE_MEDUSA:
00465             grating_setup->resol = cpl_table_get(ref_gtable, c_name_rmed,
00466                                                  row_match, &row_nulls);
00467             break;
00468 
00469         case GIMODE_IFU:
00470             grating_setup->resol = cpl_table_get(ref_gtable, c_name_rifa,
00471                                                  row_match, &row_nulls);
00472             break;
00473 
00474         case GIMODE_ARGUS:
00475             grating_setup->resol = cpl_table_get(ref_gtable, c_name_rifa,
00476                                                  row_match, &row_nulls);
00477             break;
00478 
00479         default:
00480             grating_setup->resol = -1.0;
00481             break;
00482     }
00483 
00484     grating_setup->fcoll   =
00485         cpl_table_get(ref_gtable, c_name_fcoll, row_match, &row_nulls);
00486 
00487     grating_setup->gcam    =
00488         cpl_table_get(ref_gtable, c_name_gcam,  row_match, &row_nulls);
00489 
00490     grating_setup->slitdx  =
00491         cpl_table_get(ref_gtable, c_name_sdx,   row_match, &row_nulls);
00492 
00493     grating_setup->slitdy  =
00494         cpl_table_get(ref_gtable, c_name_sdy,   row_match, &row_nulls);
00495 
00496     grating_setup->slitphi =
00497         cpl_table_get(ref_gtable, c_name_sdphi, row_match, &row_nulls);
00498 
00499     cx_string_delete(slit_name);
00500 
00501     return 0;
00502 
00503 }
00504 
00505 
00506 static GiFiberPosition*
00507 _giraffe_fiberposition_new(void)
00508 {
00509 
00510     GiFiberPosition* tmp = NULL;
00511 
00512     tmp = (GiFiberPosition*) cx_calloc(1, sizeof(GiFiberPosition));
00513 
00514     tmp->x_fiber = NULL;
00515     tmp->y_fiber = NULL;
00516 
00517     return tmp;
00518 }
00519 
00520 
00521 static void
00522 _giraffe_fiberposition_delete(GiFiberPosition *fp)
00523 {
00524 
00525     if (fp != NULL) {
00526 
00527         if (fp->x_fiber) {
00528             cpl_matrix_delete(fp->x_fiber);
00529         }
00530 
00531         if (fp->y_fiber) {
00532             cpl_matrix_delete(fp->y_fiber);
00533         }
00534 
00535         cx_free(fp);
00536 
00537     }
00538 
00539     return;
00540 
00541 }
00542 
00543 
00544 static GiSlitGeo*
00545 _giraffe_slitgeo_new(void)
00546 {
00547 
00548     GiSlitGeo *sgeometry = NULL;
00549 
00550     sgeometry = cx_malloc(sizeof(GiSlitGeo));
00551 
00552     sgeometry->subslits = NULL;
00553     sgeometry->nsubslits = 0;
00554 
00555     return sgeometry;
00556 
00557 }
00558 
00559 
00560 static void
00561 _giraffe_slitgeo_delete(GiSlitGeo *sgeometry)
00562 {
00563 
00564     if (sgeometry != NULL) {
00565 
00566         if (sgeometry->subslits != NULL) {
00567 
00568             cxint i;
00569 
00570             for (i = 0; i < sgeometry->nsubslits; i++) {
00571                 cpl_matrix_delete(sgeometry->subslits[i]);
00572             }
00573 
00574             cx_free(sgeometry->subslits);
00575         }
00576 
00577         cx_free(sgeometry);
00578 
00579     }
00580 
00581     return;
00582 
00583 }
00584 
00585 
00586 static cxint
00587 _giraffe_slitgeo_size(GiSlitGeo *sgeometry)
00588 {
00589 
00590     if (sgeometry == NULL) {
00591         return -1;
00592     }
00593 
00594     if (sgeometry->subslits != NULL) {
00595         return sgeometry->nsubslits;
00596     }
00597 
00598     return -1;
00599 
00600 }
00601 
00602 
00603 static void
00604 _giraffe_slitgeo_resize(GiSlitGeo *sgeometry, cxint size)
00605 {
00606 
00607     if (sgeometry == NULL) {
00608         return;
00609     }
00610 
00611     if (size == sgeometry->nsubslits) {
00612         return;
00613     }
00614 
00615     if (sgeometry->subslits != NULL) {
00616 
00617         cxint i;
00618 
00619         for (i = 0; i < sgeometry->nsubslits; i++) {
00620             cpl_matrix_delete(sgeometry->subslits[i]);
00621         }
00622     }
00623 
00624     cx_free(sgeometry->subslits);
00625 
00626     sgeometry->nsubslits = size;
00627     sgeometry->subslits = cx_calloc(sgeometry->nsubslits, sizeof(cpl_matrix*));
00628 
00629     return;
00630 
00631 }
00632 
00633 
00634 static void
00635 _giraffe_slitgeo_create(GiSlitGeo *sgeometry, cxint idx, cxint nrow,
00636                         cxint ncol)
00637 {
00638 
00639     if (sgeometry == NULL) {
00640         return;
00641     }
00642 
00643     if (sgeometry->subslits == NULL) {
00644         return;
00645     }
00646 
00647     if ((idx < 0) || (idx > sgeometry->nsubslits)) {
00648         return;
00649     }
00650 
00651     if (sgeometry->subslits[idx] != NULL) {
00652         cpl_matrix_delete(sgeometry->subslits[idx]);
00653     }
00654 
00655     sgeometry->subslits[idx] = cpl_matrix_new(nrow, ncol);
00656 
00657     return;
00658 
00659 }
00660 
00661 
00662 static void
00663 _giraffe_slitgeo_set(GiSlitGeo *sgeometry, cxint idx, cpl_matrix *nm)
00664 {
00665 
00666     if (sgeometry == NULL) {
00667         return;
00668     }
00669 
00670     if (sgeometry->subslits == NULL) {
00671         return;
00672     }
00673 
00674     if ((idx < 0) || (idx > sgeometry->nsubslits)) {
00675         return;
00676     }
00677 
00678     if (sgeometry->subslits[idx] != NULL) {
00679         cpl_matrix_delete(sgeometry->subslits[idx]);
00680     }
00681 
00682     if (nm) {
00683         sgeometry->subslits[idx] = cpl_matrix_duplicate(nm);
00684     }
00685     else {
00686         sgeometry->subslits[idx] = NULL;
00687     }
00688 
00689 }
00690 
00691 
00692 static cpl_matrix*
00693 _giraffe_slitgeo_get(GiSlitGeo *sgeometry, cxint idx)
00694 {
00695 
00696     if (sgeometry == NULL) {
00697         return NULL;
00698     }
00699 
00700     if (sgeometry->subslits == NULL) {
00701         return NULL;
00702     }
00703 
00704     if ((idx < 0)||(idx > sgeometry->nsubslits)) {
00705         return NULL;
00706     }
00707 
00708     return (sgeometry->subslits[idx]);
00709 
00710 }
00711 
00712 
00713 static cxint
00714 _giraffe_slitgeo_setup(const GiTable *slitgeo,
00715                        GiFiberPosition *fiber_slit_position,
00716                        GiSlitGeo *subslits, cxbool fitsubslit)
00717 {
00718 
00719     const cxchar *const fctid = "_giraffe_slitgeo_setup";
00720 
00721 
00722     const cxchar *c_name_xf     = "XF";
00723     const cxchar *c_name_yf     = "YF";
00724     const cxchar *c_name_nspec  = "FPS";
00725     const cxchar *c_name_ssn    = "SSN";
00726 
00727 
00728     cpl_matrix *nspec = NULL;
00729     cpl_matrix *nsubslits = NULL;
00730 
00731     cxint       nr_slitgeo    = 0,
00732         max_nsubslits = 0,
00733         i             = 0,
00734         j             = 0,
00735         row_null      = 0,
00736         count         = 0,
00737         column_index  = 0,
00738         tmp_nspec     = 0,
00739         tmp_nsubslits = 0;
00740 
00741     cxdouble    tmp_xf,
00742         tmp_yf;
00743 
00744     cpl_table  *ref_slitgeo   = NULL;
00745 
00746     cpl_error_code ce_code;
00747 
00748 
00749     /*************************************************************************
00750                                     Preprocessing
00751     *************************************************************************/
00752 
00753     if (slitgeo            ==NULL) { return 1; }
00754     if (fiber_slit_position==NULL) { return 1; }
00755     if (subslits           ==NULL) { return 1; }
00756 
00757     /*************************************************************************
00758                                      Processing
00759     *************************************************************************/
00760 
00761     ref_slitgeo = giraffe_table_get(slitgeo);
00762     nr_slitgeo  = cpl_table_get_nrow(ref_slitgeo);
00763 
00764     fiber_slit_position->x_fiber = cpl_matrix_new(nr_slitgeo, 1);
00765     fiber_slit_position->y_fiber = cpl_matrix_new(nr_slitgeo, 1);
00766 
00767     nspec     = cpl_matrix_new(nr_slitgeo, 1);
00768     nsubslits = cpl_matrix_new(nr_slitgeo, 1);
00769 
00770     /*
00771      *  Copy relevant data to matrices
00772      */
00773 
00774     max_nsubslits = 0;
00775 
00776     for (i = 0; i < nr_slitgeo; i++) {
00777 
00778         tmp_xf = cpl_table_get(ref_slitgeo, c_name_xf, i, &row_null);
00779         tmp_yf = cpl_table_get(ref_slitgeo, c_name_yf, i, &row_null);
00780 
00781         tmp_nspec = cpl_table_get_int(ref_slitgeo, c_name_nspec, i,
00782                                       &row_null) - 1;
00783 
00784         tmp_nsubslits = cpl_table_get_int(ref_slitgeo, c_name_ssn, i,
00785                                           &row_null);
00786 
00787         if (tmp_nsubslits>max_nsubslits) {
00788             max_nsubslits = tmp_nsubslits;
00789         }
00790 
00791         ce_code = cpl_matrix_set(fiber_slit_position->x_fiber, i, 0, tmp_xf);
00792         ce_code = cpl_matrix_set(fiber_slit_position->y_fiber, i, 0, tmp_yf);
00793 
00794         ce_code = cpl_matrix_set(nspec,     i, 0, (cxdouble)tmp_nspec);
00795         ce_code = cpl_matrix_set(nsubslits, i, 0, (cxdouble)tmp_nsubslits);
00796 
00797     }
00798 
00799     /*
00800      *  Create Slit Geometry
00801      */
00802 
00803     if (fitsubslit) {
00804 
00805         /* create multiple subslits */
00806 
00807         _giraffe_slitgeo_resize(subslits, max_nsubslits);
00808 
00809         for (i = 1; i <= max_nsubslits; i++) {
00810 
00811             cpl_matrix *ref_matrix = NULL;
00812             cxint       curr_ssn;
00813 
00814             count = 0;
00815             for (j=0; j<nr_slitgeo; j++) {
00816                 curr_ssn = (cxint) cpl_matrix_get(nsubslits, j, 0);
00817                 if (i==curr_ssn) {
00818                     ++count;
00819                 }
00820             }
00821 
00822             _giraffe_slitgeo_create(subslits, i-1, count, 1);
00823 
00824             ref_matrix = _giraffe_slitgeo_get(subslits, i-1);
00825 
00826             column_index = 0;
00827             for (j = 0; j < nr_slitgeo; j++) {
00828 
00829                 curr_ssn = (cxint) cpl_matrix_get(nsubslits, j, 0);
00830 
00831                 if (i == curr_ssn) {
00832                     ce_code = cpl_matrix_set(ref_matrix, column_index, 0,
00833                                              (cxdouble)j);
00834                     column_index++;
00835                 }
00836 
00837             }
00838         }
00839 
00840         cpl_msg_debug(fctid, "Using multiple slits for Slit Geometry");
00841 
00842     }
00843     else {
00844 
00845         const cxchar *idx = giraffe_fiberlist_query_index(ref_slitgeo);
00846 
00847 
00848         /*
00849          * Create one subslit containing all fibers
00850          */
00851 
00852         cpl_matrix *ref_matrix = NULL;
00853 
00854         _giraffe_slitgeo_resize(subslits, 1);
00855         _giraffe_slitgeo_create(subslits, 0, nr_slitgeo, 1);
00856 
00857         ref_matrix = _giraffe_slitgeo_get(subslits, 0);
00858 
00859         for (j = 0; j < nr_slitgeo; j++) {
00860 
00861             cxint cs = cpl_table_get_int(ref_slitgeo, idx, j, NULL) - 1;
00862             ce_code = cpl_matrix_set(ref_matrix, j, 0, cs);
00863 //            ce_code = cpl_matrix_set(ref_matrix, j, 0, (cxdouble)j);
00864 
00865         }
00866 
00867         cpl_msg_debug(fctid, "Using single slit for Slit Geometry");
00868 
00869     }
00870 
00871     cpl_matrix_delete(nspec);
00872     nspec = NULL;
00873 
00874     cpl_matrix_delete(nsubslits);
00875     nsubslits = NULL;
00876 
00877     return 0;
00878 
00879 }
00880 
00881 
00882 static GiWcalSolution*
00883 _giraffe_wcalsolution_new(void)
00884 {
00885 
00886     GiWcalSolution* tmp = NULL;
00887 
00888     tmp = (GiWcalSolution*) cx_calloc(1, sizeof(GiWcalSolution));
00889 
00890     tmp->subslitfit     = FALSE;
00891     tmp->opt_mod        = LMRQ_UNDEFINED;
00892     tmp->opt_mod_params = NULL;
00893     tmp->wav_coeffs     = NULL;
00894     tmp->wav_limits     = NULL;
00895 
00896     return tmp;
00897 }
00898 
00899 
00900 static void
00901 _giraffe_wcalsolution_delete(GiWcalSolution *ws)
00902 {
00903 
00904     if (ws != NULL) {
00905 
00906         if (ws->opt_mod_params!=NULL) {
00907             cpl_matrix_delete(ws->opt_mod_params);
00908         }
00909 
00910         if (ws->wav_coeffs!=NULL) {
00911             _giraffe_slitgeo_delete(ws->wav_coeffs);
00912         }
00913 
00914         if (ws->wav_limits!=NULL) {
00915             _giraffe_slitgeo_delete(ws->wav_limits);
00916         }
00917 
00918         cx_free(ws);
00919 
00920     }
00921 
00922     return;
00923 
00924 }
00925 
00926 
00927 static GiWcalSolution*
00928 _giraffe_wcalsolution_create(const GiTable *wavesolution)
00929 {
00930 
00931     GiWcalSolution *wavcoeff        = NULL;
00932 
00933     cpl_propertylist      *_properties     = NULL;
00934     cpl_table      *_table          = NULL;
00935 
00936     cxint           poly_x_deg      = 0,
00937         poly_y_deg      = 0,
00938         ncoefficients   = 0,
00939         i;
00940 
00941     cpl_matrix     *coefficients    = NULL;
00942     cpl_matrix     *limits          = NULL;
00943     cxdouble       *pd_coefficients = NULL;
00944 
00945     cxchar          buffer[68];
00946 
00947 
00948     if (wavesolution == NULL) {
00949         return NULL;
00950     }
00951 
00952     wavcoeff = _giraffe_wcalsolution_new();
00953 
00954     _properties = giraffe_table_get_properties(wavesolution);
00955 
00956 
00957     /*
00958      *  Build up optical model from the wavelength solution properties
00959      */
00960 
00961     if (cpl_propertylist_has(_properties, GIALIAS_OPT_MOD) == TRUE) {
00962 
00963         const cxchar* optmod = cpl_propertylist_get_string(_properties,
00964             GIALIAS_OPT_MOD);
00965 
00966         if (strncmp(optmod, "xoptmod2", 8) == 0) {
00967             wavcoeff->opt_mod = LMRQ_XOPTMOD2;
00968         }
00969         else if (strncmp(optmod, "xoptmod", 7) == 0) {
00970             wavcoeff->opt_mod = LMRQ_XOPTMOD;
00971         }
00972         else {
00973             wavcoeff->opt_mod = LMRQ_UNDEFINED;
00974         }
00975     }
00976 
00977     if (wavcoeff->opt_mod == LMRQ_XOPTMOD2) {
00978 
00979         wavcoeff->opt_mod_params = cpl_matrix_new(7,1);
00980 
00981         if (cpl_propertylist_has(_properties, GIALIAS_OPTMDIR)) {
00982             cpl_matrix_set(
00983                 wavcoeff->opt_mod_params,
00984                 0,
00985                 0,
00986                 cpl_propertylist_get_int(_properties, GIALIAS_OPTMDIR)
00987                 );
00988         } else {
00989             _giraffe_wcalsolution_delete(wavcoeff);
00990             return NULL;
00991         }
00992 
00993         if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMFCOLL)) {
00994             cpl_matrix_set(
00995                 wavcoeff->opt_mod_params,
00996                 1,
00997                 0,
00998                 cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMFCOLL)
00999                 );
01000         } else {
01001             _giraffe_wcalsolution_delete(wavcoeff);
01002             return NULL;
01003         }
01004 
01005         if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMGCAM)) {
01006             cpl_matrix_set(
01007                 wavcoeff->opt_mod_params,
01008                 2,
01009                 0,
01010                 cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMGCAM)
01011                 );
01012         } else {
01013             _giraffe_wcalsolution_delete(wavcoeff);
01014             return NULL;
01015         }
01016 
01017         if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMTHETA)) {
01018             cpl_matrix_set(
01019                 wavcoeff->opt_mod_params,
01020                 3,
01021                 0,
01022                 cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMTHETA)
01023                 );
01024         } else {
01025             _giraffe_wcalsolution_delete(wavcoeff);
01026             return NULL;
01027         }
01028 
01029         if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMSDX)) {
01030             cpl_matrix_set(
01031                 wavcoeff->opt_mod_params,
01032                 4,
01033                 0,
01034                 cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMSDX)
01035                 );
01036         } else {
01037             _giraffe_wcalsolution_delete(wavcoeff);
01038             return NULL;
01039         }
01040 
01041         if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMSDY)) {
01042 
01043 
01044 
01045             cpl_matrix_set(
01046                 wavcoeff->opt_mod_params,
01047                 5,
01048                 0,
01049                 cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMSDY)
01050                 );
01051 
01052         } else {
01053             _giraffe_wcalsolution_delete(wavcoeff);
01054             return NULL;
01055         }
01056 
01057         if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMSPHI)) {
01058             cpl_matrix_set(
01059                 wavcoeff->opt_mod_params,
01060                 6,
01061                 0,
01062                 cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMSPHI)
01063                 );
01064 
01065         } else {
01066             _giraffe_wcalsolution_delete(wavcoeff);
01067             return NULL;
01068         }
01069 
01070     } else if (wavcoeff->opt_mod==LMRQ_XOPTMOD) {
01071 
01072         wavcoeff->opt_mod_params = cpl_matrix_new(4,1);
01073 
01074         if (cpl_propertylist_has(_properties, GIALIAS_OPTMDIR)) {
01075             cpl_matrix_set(
01076                 wavcoeff->opt_mod_params,
01077                 0,
01078                 0,
01079                 cpl_propertylist_get_int(_properties, GIALIAS_OPTMDIR)
01080                 );
01081         } else {
01082             _giraffe_wcalsolution_delete(wavcoeff);
01083             return NULL;
01084         }
01085 
01086         if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMFCOLL)) {
01087             cpl_matrix_set(
01088                 wavcoeff->opt_mod_params,
01089                 1,
01090                 0,
01091                 cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMFCOLL)
01092                 );
01093         } else {
01094             _giraffe_wcalsolution_delete(wavcoeff);
01095             return NULL;
01096         }
01097 
01098         if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMGCAM)) {
01099             cpl_matrix_set(
01100                 wavcoeff->opt_mod_params,
01101                 2,
01102                 0,
01103                 cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMGCAM)
01104                 );
01105         } else {
01106             _giraffe_wcalsolution_delete(wavcoeff);
01107             return NULL;
01108         }
01109 
01110         if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMTHETA)) {
01111             cpl_matrix_set(
01112                 wavcoeff->opt_mod_params,
01113                 3,
01114                 0,
01115                 cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMTHETA)
01116                 );
01117         } else {
01118             _giraffe_wcalsolution_delete(wavcoeff);
01119             return NULL;
01120         }
01121 
01122 
01123     } else {
01124 
01125         _giraffe_wcalsolution_delete(wavcoeff);
01126         return NULL;
01127 
01128     }
01129 
01130 
01131     /*
01132      * Set up the optical model residuals if the given table contains them.
01133      */
01134 
01135     _table = giraffe_table_get(wavesolution);
01136 
01137     if (_table != NULL) {
01138 
01139 
01140         if (cpl_propertylist_has(_properties, GIALIAS_SSF)) {
01141 
01142             if (cpl_propertylist_get_bool(_properties, GIALIAS_SSF) == 0) {
01143                 wavcoeff->subslitfit = FALSE;
01144             }
01145             else {
01146                 wavcoeff->subslitfit = TRUE;
01147             }
01148 
01149         }
01150         else {
01151 
01152             _giraffe_wcalsolution_delete(wavcoeff);
01153             return NULL;
01154 
01155         }
01156 
01157         wavcoeff->wav_limits = _giraffe_slitgeo_new();
01158         _giraffe_slitgeo_resize(wavcoeff->wav_limits, 1);
01159 
01160         limits = cpl_matrix_new(1, 4);
01161         cpl_matrix_fill(limits, -1.);
01162 
01163         if (cpl_table_has_column(_table, "XMIN") &&
01164             cpl_table_has_column(_table, "XMAX")) {
01165             cpl_matrix_set(limits, 0, 0,
01166                            cpl_table_get_double(_table, "XMIN", 0, NULL));
01167             cpl_matrix_set(limits, 0, 1,
01168                            cpl_table_get_double(_table, "XMAX", 0, NULL));
01169         }
01170 
01171         if (cpl_table_has_column(_table, "YMIN") &&
01172             cpl_table_has_column(_table, "YMAX")) {
01173             cpl_matrix_set(limits, 0, 2,
01174                            cpl_table_get_double(_table, "YMIN", 0, NULL));
01175             cpl_matrix_set(limits, 0, 3,
01176                            cpl_table_get_double(_table, "YMAX", 0, NULL));
01177         }
01178 
01179         _giraffe_slitgeo_set(wavcoeff->wav_limits, 0, limits);
01180 
01181         cpl_matrix_delete(limits);
01182         limits = NULL;
01183 
01184         wavcoeff->wav_coeffs = _giraffe_slitgeo_new();
01185         _giraffe_slitgeo_resize(wavcoeff->wav_coeffs, 1);
01186 
01187         if (cpl_propertylist_has(_properties, GIALIAS_XRES_PDEG)) {
01188 
01189             cxchar *l, *r, *tmpstr;
01190 
01191             tmpstr = (cxchar*) cpl_propertylist_get_string(_properties,
01192                                                            GIALIAS_XRES_PDEG);
01193 
01194             l = &(tmpstr[0]);
01195             r = &(tmpstr[2]);
01196 
01197             poly_x_deg = atoi(l) + 1;
01198             poly_y_deg = atoi(r) + 1;
01199 
01200         }
01201         else {
01202 
01203             _giraffe_wcalsolution_delete(wavcoeff);
01204             return NULL;
01205 
01206         }
01207 
01208         ncoefficients = poly_x_deg * poly_y_deg;
01209 
01210         coefficients = cpl_matrix_new(poly_x_deg,poly_y_deg);
01211         pd_coefficients = cpl_matrix_get_data(coefficients);
01212 
01213         for (i=0; i<ncoefficients; i++) {
01214 
01215             snprintf(buffer, sizeof(cxchar)*80, "XC%d", i);
01216 
01217             pd_coefficients[i] =
01218                 cpl_table_get_double(_table, buffer, 0, NULL);
01219 
01220         }
01221 
01222         _giraffe_slitgeo_set(wavcoeff->wav_coeffs, 0, coefficients);
01223 
01224         cpl_matrix_delete(coefficients);
01225         coefficients = NULL;
01226 
01227     }
01228 
01229     return wavcoeff;
01230 
01231 }
01232 
01233 
01234 static cpl_image*
01235 _giraffe_compute_pixel_abscissa(cpl_matrix* m_wavelengths,
01236                                 cpl_matrix* m_wloffset,
01237                                 GiFiberPosition* fiber_slit_position,
01238                                 cpl_matrix* m_opt_mod_params,
01239                                 lmrq_model lmrq_opt_mod_x)
01240 {
01241 
01242     /*************************************************************************
01243                                      VARIABLES
01244     *************************************************************************/
01245 
01246     const cxchar *fctid = "_giraffe_compute_pixel_abscissa";
01247 
01248     register cxint n;
01249     register cxint line;
01250     register cxint nwlen;    /* number of reference lines    */
01251     register cxint ns;       /* number of reference spectra  */
01252 
01253     cxint nr_m_opt_mod_params = 0;
01254 
01255     cxdouble xccd = 0.;
01256     cxdouble* pd_xref             = NULL;
01257     cxdouble* pd_m_inputs         = NULL;
01258     cxdouble* pd_m_yfibre         = NULL;
01259     cxdouble* pd_m_xfibre         = NULL;
01260     cxdouble* pd_m_wavelengths    = NULL;
01261     cxdouble* pd_m_opt_mod_params = NULL;
01262 
01263     cpl_image* xref = NULL;
01264 
01265     cpl_matrix* m_inputs = NULL;
01266 
01267 
01268     /************************************************************************
01269                                    INITIALIZATION
01270     ************************************************************************/
01271 
01272     if (m_wavelengths == NULL) {
01273         return NULL;
01274     }
01275 
01276     if ((fiber_slit_position == NULL) ||
01277         (fiber_slit_position->x_fiber == NULL) ||
01278         (fiber_slit_position->y_fiber == NULL)) {
01279         return NULL;
01280     }
01281 
01282     if (m_opt_mod_params == NULL) {
01283         return NULL;
01284     }
01285 
01286 
01287     nwlen = cpl_matrix_get_nrow(m_wavelengths);
01288     ns    = cpl_matrix_get_nrow(fiber_slit_position->y_fiber);
01289 
01290     if ((m_wloffset != NULL) && (cpl_matrix_get_nrow(m_wloffset) != ns)) {
01291         return NULL;
01292     }
01293 
01294 
01295     /************************************************************************
01296                                     PREPROCESSING
01297     ************************************************************************/
01298 
01299     xref       = cpl_image_new(ns, nwlen, CPL_TYPE_DOUBLE);
01300     pd_xref    = cpl_image_get_data_double(xref);
01301 
01302     m_inputs    = cpl_matrix_new(lmrq_opt_mod_x.ninputs, 1);
01303     pd_m_inputs = cpl_matrix_get_data(m_inputs);
01304 
01305     pd_m_yfibre      = cpl_matrix_get_data(fiber_slit_position->y_fiber);
01306     pd_m_xfibre      = cpl_matrix_get_data(fiber_slit_position->x_fiber);
01307     pd_m_wavelengths = cpl_matrix_get_data(m_wavelengths);
01308 
01309     pd_m_opt_mod_params = cpl_matrix_get_data(m_opt_mod_params);
01310     nr_m_opt_mod_params = cpl_matrix_get_nrow(m_opt_mod_params);
01311 
01312 
01313     /************************************************************************
01314                                      PROCESSING
01315     ************************************************************************/
01316 
01317     if (m_wloffset != NULL) {
01318 
01319         cxdouble* pd_m_wloffset = cpl_matrix_get_data(m_wloffset);
01320 
01321         for (n = 0; n < ns; n++) {
01322 
01323             pd_m_inputs[2] = pd_m_yfibre[n];
01324             pd_m_inputs[1] = pd_m_xfibre[n];
01325 
01326             for (line = 0; line < nwlen; line++) {
01327 
01328                 pd_m_inputs[0] = pd_m_wavelengths[line] + pd_m_wloffset[n];
01329 
01330                 lmrq_opt_mod_x.cfunc(pd_m_inputs, pd_m_opt_mod_params,
01331                                      NULL, &xccd, NULL, nr_m_opt_mod_params);
01332 
01333                 pd_xref[line * ns + n] = xccd;
01334 
01335             } /* each line */
01336 
01337         } /* each spectrum */
01338 
01339     }
01340     else {
01341 
01342         for (n = 0; n < ns; n++) {
01343 
01344             pd_m_inputs[2] = pd_m_yfibre[n];
01345             pd_m_inputs[1] = pd_m_xfibre[n];
01346 
01347             for (line = 0; line < nwlen; line++) {
01348 
01349                 pd_m_inputs[0] = pd_m_wavelengths[line];
01350 
01351                 lmrq_opt_mod_x.cfunc(pd_m_inputs, pd_m_opt_mod_params,
01352                                      NULL, &xccd, NULL, nr_m_opt_mod_params);
01353 
01354                 pd_xref[line * ns + n] = xccd;
01355 
01356             } /* each line */
01357 
01358         } /* each spectrum */
01359 
01360     }
01361 
01362     cpl_matrix_delete(m_inputs);
01363 
01364     cpl_msg_debug(
01365         fctid,
01366         "Processing completed: Returning image [x,y] = [%d,%d]",
01367         cpl_image_get_size_x(xref),
01368         cpl_image_get_size_y(xref)
01369         );
01370 
01371     return xref;
01372 
01373 }
01374 
01375 
01376 inline static cpl_matrix *
01377 _giraffe_rebin_setup_model(GiImage *extspectra, GiWcalSolution *wcal)
01378 {
01379 
01380     cxint npixel;
01381 
01382     cxdouble pixelsize;
01383 
01384     cpl_propertylist *properties = NULL;
01385 
01386     cpl_matrix *model = NULL;
01387 
01388 
01389     if (extspectra == NULL) {
01390         return NULL;
01391     }
01392 
01393     if (wcal == NULL) {
01394         return NULL;
01395     }
01396 
01397     properties = giraffe_image_get_properties(extspectra);
01398 
01399     if (properties == NULL) {
01400         return NULL;
01401     }
01402 
01403 
01404     /*
01405      * Get the number of pixels extracted along the dispersion axis.
01406      */
01407 
01408     if (!cpl_propertylist_has(properties, GIALIAS_EXT_NX)) {
01409         return NULL;
01410     }
01411 
01412     npixel = cpl_propertylist_get_int(properties, GIALIAS_EXT_NX);
01413 
01414 
01415     /*
01416      * Compute pixel size along the dispersion axis in terms of mm.
01417      */
01418 
01419     if (!cpl_propertylist_has(properties, GIALIAS_PIXSIZX)) {
01420         return NULL;
01421     }
01422 
01423     pixelsize = cpl_propertylist_get_double(properties, GIALIAS_PIXSIZX);
01424     pixelsize /= 1000.;
01425 
01426 
01427     /*
01428      * Setup the optical model parameters
01429      */
01430 
01431     switch (wcal->opt_mod) {
01432         case LMRQ_XOPTMOD:
01433             if (cpl_matrix_get_nrow(wcal->opt_mod_params) != 4) {
01434                 return NULL;
01435             }
01436             else {
01437 
01438                 cxdouble direction = cpl_matrix_get(wcal->opt_mod_params, 0, 0);
01439                 cxdouble fcoll = cpl_matrix_get(wcal->opt_mod_params, 1, 0);
01440                 cxdouble cfact = cpl_matrix_get(wcal->opt_mod_params, 2, 0);
01441 
01442                 model = cpl_matrix_new(4, 1);
01443 
01444                 cpl_matrix_set(model, 0, 0, npixel * direction);
01445                 cpl_matrix_set(model, 1, 0, pixelsize);
01446                 cpl_matrix_set(model, 2, 0, fcoll);
01447                 cpl_matrix_set(model, 3, 0, cfact);
01448             }
01449             break;
01450 
01451         case LMRQ_XOPTMOD2:
01452             if (cpl_matrix_get_nrow(wcal->opt_mod_params) != 7) {
01453                 return NULL;
01454             }
01455             else {
01456 
01457                 cxdouble direction = cpl_matrix_get(wcal->opt_mod_params, 0, 0);
01458                 cxdouble fcoll = cpl_matrix_get(wcal->opt_mod_params, 1, 0);
01459                 cxdouble cfact = cpl_matrix_get(wcal->opt_mod_params, 2, 0);
01460                 cxdouble sdx = cpl_matrix_get(wcal->opt_mod_params, 4, 0);
01461                 cxdouble sdy = cpl_matrix_get(wcal->opt_mod_params, 5, 0);
01462                 cxdouble sphi = cpl_matrix_get(wcal->opt_mod_params, 6, 0);
01463 
01464                 model = cpl_matrix_new(7, 1);
01465 
01466                 cpl_matrix_set(model, 0, 0, npixel * direction);
01467                 cpl_matrix_set(model, 1, 0, pixelsize);
01468                 cpl_matrix_set(model, 2, 0, fcoll);
01469                 cpl_matrix_set(model, 3, 0, cfact);
01470                 cpl_matrix_set(model, 4, 0, sdx);
01471                 cpl_matrix_set(model, 5, 0, sdy);
01472                 cpl_matrix_set(model, 6, 0, sphi);
01473             }
01474             break;
01475 
01476         default:
01477             return NULL;
01478             break;
01479     }
01480 
01481     cx_assert(model != NULL);
01482 
01483     return model;
01484 
01485 }
01486 
01487 
01488 inline static cpl_matrix *
01489 _giraffe_rebin_setup_grating(GiImage *extspectra, GiTable *grating,
01490                              GiTable *wlsolution)
01491 {
01492 
01493     cxint status = 0;
01494 
01495     cpl_propertylist *properties = NULL;
01496 
01497     cpl_matrix *setup = NULL;
01498 
01499     GiGrat *grating_data = _giraffe_grating_new();
01500 
01501 
01502     status = _giraffe_grating_setup(grating, extspectra, grating_data);
01503 
01504     if (status != 0) {
01505         _giraffe_grating_delete(grating_data);
01506         return NULL;
01507     }
01508 
01509 
01510     properties = giraffe_table_get_properties(wlsolution);
01511 
01512     if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMFCOLL)) {
01513         grating_data->fcoll = cpl_propertylist_get_double(properties,
01514                                                           GIALIAS_WSOL_OMFCOLL);
01515     }
01516 
01517     if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMGCAM)) {
01518         grating_data->gcam = cpl_propertylist_get_double(properties,
01519                                                          GIALIAS_WSOL_OMGCAM);
01520     }
01521 
01522     if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMGTHETA)) {
01523         grating_data->theta = cpl_propertylist_get_double(properties,
01524                                                           GIALIAS_WSOL_OMGTHETA);
01525     }
01526 
01527     if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMSDX)) {
01528         grating_data->slitdx = cpl_propertylist_get_double(properties,
01529                                                            GIALIAS_WSOL_OMSDX);
01530     }
01531 
01532     if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMSDY)) {
01533         grating_data->slitdy = cpl_propertylist_get_double(properties,
01534                                                            GIALIAS_WSOL_OMSDY);
01535     }
01536 
01537     if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMSPHI)) {
01538         grating_data->slitphi = cpl_propertylist_get_double(properties,
01539                                                             GIALIAS_WSOL_OMSPHI);
01540     }
01541 
01542 
01543     setup = cpl_matrix_new(7, 1);
01544 
01545     cpl_matrix_set(setup, 0, 0, grating_data->theta);
01546     cpl_matrix_set(setup, 1, 0, grating_data->order);
01547     cpl_matrix_set(setup, 2, 0, grating_data->wlenmin / GI_MM_TO_NM);
01548     cpl_matrix_set(setup, 3, 0, grating_data->wlen0 / GI_MM_TO_NM);
01549     cpl_matrix_set(setup, 4, 0, grating_data->wlenmax / GI_MM_TO_NM);
01550     cpl_matrix_set(setup, 5, 0, grating_data->resol);
01551     cpl_matrix_set(setup, 6, 0, grating_data->space);
01552 
01553     _giraffe_grating_delete(grating_data);
01554     grating_data = NULL;
01555 
01556     return setup;
01557 
01558 }
01559 
01560 
01573 inline static cxint
01574 _giraffe_spline_calc_circe(cxdouble x, register cxdouble* t, cxint n)
01575 {
01576 
01577     register cxint lo = 0;
01578     register cxint hi = n - 1;
01579 
01580 
01581     if (x >= t[0] && x <= t[n - 1]) {
01582 
01583         while (hi - lo > 1) {
01584 
01585             register cxint mid = (lo + hi) / 2.;
01586 
01587             cxdouble tm = 0.;
01588 
01589             tm = t[mid];
01590 
01591             if (x < tm) {
01592                 hi = mid;
01593             }
01594             else {
01595                 lo = mid;
01596             }
01597         }
01598 
01599         return hi;
01600 
01601     }
01602 
01603     return -1;
01604 
01605 }
01606 
01626 inline static void
01627 _giraffe_spline_calc_tridi(register cxdouble* a, register cxdouble* b,
01628                            register cxdouble* c, register cxdouble* f,
01629                            register cxdouble* x, cxint n)
01630 {
01631 
01632     register cxint i = 0;
01633 
01634     c[0] /= a[0];
01635 
01636     for (i = 1; i < n; i++) {
01637         c[i] /= (a[i] - b[i] * c[i - 1]);
01638     }
01639 
01640     f[0] /= a[0];
01641 
01642     for (i = 1; i < n; i++) {
01643         f[i] = (f[i] - b[i] * f[i - 1]) / (a[i] - b[i] * c[i - 1]);
01644     }
01645 
01646     x[n - 1] = f[n - 1];
01647 
01648     for (i = n - 2; i >= 0; i--) {
01649         x[i] = f[i] - c[i] * x[i + 1];
01650     }
01651 
01652     return;
01653 }
01654 
01674 inline static cxint
01675 _giraffe_spline_calc_interpolate(cxdouble z, cxdouble* val,
01676                                  register cxdouble* x, register cxdouble* y,
01677                                  register cxdouble* k, cxint n)
01678 {
01679 
01680     cxint m = 0;
01681 
01682     cxdouble h = 0.;
01683     cxdouble t = 0.;
01684     cxdouble d = 0.;
01685     cxdouble a = 0.;
01686     cxdouble b = 0.;
01687     cxdouble dx = 0.;
01688 
01689 
01690     m = _giraffe_spline_calc_circe(z, x, n);
01691 
01692     if (m < 0) {
01693 
01694         /* out of bounds */
01695         if (z < x[0]) {
01696             dx   = z - x[0];
01697             *val = y[0] + dx * (k[0] + 0.5 * dx * ddb);
01698         } else {
01699             dx   = z - x[n - 1];
01700             *val = y[n - 1] + dx * (k[n - 1] + 0.5 * dx * dde);
01701         }
01702 
01703         return 1;
01704 
01705     }
01706 
01707     dx   = z - x[m - 1];
01708     h    = x[m] - x[m - 1];
01709     d    = (y[m] - y[m - 1]) / h;
01710     t    = dx / h;
01711     a    = (k[m - 1] - d) * (1 - t);
01712     b    = (k[m] - d) * t;
01713     *val = t * y[m] + (1 - t) * y[m - 1] + h * t * (1 - t) * (a - b);
01714 
01715     return 0;
01716 
01717 }
01718 
01739 inline static cxint
01740 _giraffe_spline_calc_initalize(cxdouble* x, cxdouble* y, cxdouble* k,
01741                                cxint n, cxdouble q2b, cxdouble q2e)
01742 {
01743 
01744     register cxint i = 0;
01745     register cxint ip = 0;
01746 
01747     register cxdouble* a;
01748     register cxdouble* b;
01749     register cxdouble* c;
01750     register cxdouble* f;
01751 
01752     cxdouble hio = 0.;
01753     cxdouble hip = 0.;
01754     cxdouble dio = 0.;
01755     cxdouble dip = 0.;
01756 
01757 
01758 
01759     ddb = q2b;
01760     dde = q2e; /* save end second derivatives */
01761 
01762     a   = (cxdouble*) cx_malloc(4 * n * sizeof(cxdouble));
01763 
01764     b   = a + n;
01765     c   = b + n;
01766     f   = c + n;
01767 
01768     for (i = 0; i < n; i++) {
01769 
01770         hip  = ((ip = i + 1) < n ? x[ip] - x[i] : 0.0);
01771         dip  = (ip < n ? (y[ip] - y[i]) / hip : 0.0);
01772         b[i] = (ip < n ? hip : hio);
01773         a[i] = 2.0 * (hip + hio);
01774         c[i] = (i > 0 ? hio : hip);
01775         f[i] = 3.0 * (hip * dio + hio * dip);
01776 
01777         if (i == 0) {
01778             f[0] = 3.0 * hip * dip - hip * hip * q2b * 0.5;
01779         }
01780         else if (i == n - 1) {
01781             f[n - 1] = 3.0 * hio * dio + hio * hio * q2e * 0.5;
01782         }
01783 
01784         dio = dip;
01785         hio = hip;
01786     }
01787 
01788     _giraffe_spline_calc_tridi(a, b, c, f, k, n);
01789 
01790     cx_free(a);
01791 
01792     return 0;
01793 
01794 }
01795 
01814 inline static cxint
01815 _giraffe_rebin_interpolate_spline(cpl_matrix* x_1, cpl_matrix* y_1,
01816                                   cpl_matrix* x_2, cpl_matrix* y_2)
01817 {
01818 
01819     cxint i = 0;
01820     cxint res = 0;
01821     cxint nr_x1 = 0;
01822     cxint nr_x2 = 0;
01823 
01824     cxdouble* k = NULL;
01825     cxdouble* pd_x1 = NULL;
01826     cxdouble* pd_y1 = NULL;
01827     cxdouble* pd_x2 = NULL;
01828     cxdouble* pd_y2 = NULL;
01829 
01830 
01831 
01832     if (x_1 == NULL || y_1 == NULL || x_2 == NULL || y_2 == NULL) {
01833         return 1;
01834     }
01835 
01836     nr_x1 = cpl_matrix_get_nrow(x_1);
01837     nr_x2 = cpl_matrix_get_nrow(x_2);
01838 
01839     pd_x1 = cpl_matrix_get_data(x_1);
01840     pd_y1 = cpl_matrix_get_data(y_1);
01841     pd_y2 = cpl_matrix_get_data(y_2);
01842     pd_x2 = cpl_matrix_get_data(x_2);
01843 
01844 
01845     /*
01846      * Get storage for spline coefficients and vector y2
01847      */
01848 
01849     k = (cxdouble*) cx_malloc(nr_x1 * sizeof(cxdouble));
01850 
01851 
01852     /*
01853      * Initialise spline calculation...
01854      */
01855 
01856     res = _giraffe_spline_calc_initalize(pd_x1, pd_y1, k, nr_x1, 0.0, 0.0);
01857 
01858     if (res < 0) {
01859         cx_free(k);
01860         return res;
01861     }
01862 
01863     /*
01864      *  Calculate spline...
01865      */
01866 
01867     for (i = 0; i < nr_x2; i++) {
01868         res = _giraffe_spline_calc_interpolate(pd_x2[i], &(pd_y2[i]), pd_x1,
01869                                                pd_y1, k, nr_x1);
01870     }
01871 
01872     cx_free(k);
01873 
01874     return 0;
01875 
01876 }
01877 
01899 inline static cxint
01900 _giraffe_rebin_interpolate_linear(
01901     cpl_matrix *x_1,
01902     cpl_matrix *y_1,
01903     cpl_matrix *x_2,
01904     cpl_matrix *y_2
01905     )
01906 {
01907 
01908     /*************************************************************************
01909                                      Variables
01910     *************************************************************************/
01911 
01912     register cxdouble a, b ;
01913     register cxint    i, j, j_1, found, n1;
01914 
01915     cxint     nr_x1 = 0,
01916         nr_x2 = 0;
01917     cxdouble *pd_x1 = NULL,
01918         *pd_x2 = NULL,
01919         *pd_y2 = NULL,
01920         *pd_y1 = NULL;
01921 
01922     /*************************************************************************
01923                                     Preprocessing
01924     *************************************************************************/
01925 
01926     if (x_1 == NULL) { return 1; }
01927     if (y_1 == NULL) { return 1; }
01928     if (x_2 == NULL) { return 1; }
01929     if (y_2 == NULL) { return 1; }
01930 
01931     nr_x1 = cpl_matrix_get_nrow(x_1);
01932     nr_x2 = cpl_matrix_get_nrow(x_2);
01933     pd_x1 = cpl_matrix_get_data(x_1);
01934     pd_x2 = cpl_matrix_get_data(x_2);
01935     pd_y1 = cpl_matrix_get_data(y_1);
01936     pd_y2 = cpl_matrix_get_data(y_2);
01937 
01938     /*************************************************************************
01939                                      Processing
01940     *************************************************************************/
01941 
01942     n1 = nr_x1 - 1;
01943 
01944     for (i = 0; i < nr_x2; i++) {
01945         /* Find (x1,y1) on the left of the current point */
01946         found = 0;
01947         for (j = 0; j < n1; j++) {
01948             if ((pd_x2[i] >= pd_x1[j]) && (pd_x2[i] <= pd_x1[j+1])) {
01949                 found++ ;
01950                 break ;
01951             }
01952         }
01953 
01954         if (!found) {
01955             pd_y2[i] = 0.0;
01956         } else {
01957             j_1      = j + 1;
01958             a        = (pd_y1[j_1] - pd_y1[j]) / (pd_x1[j_1] - pd_x1[j]);
01959             b        = pd_y1[j] - a * pd_x1[j];
01960             pd_y2[i] = (a * pd_x2[i] + b);
01961 
01962         }
01963     }
01964 
01965     return 0;
01966 
01967 } /* end giraffe_rebin_interpolate_linear() */
01968 
01994 inline static cxint
01995 _giraffe_rebin_interpolate_linear_error(
01996     cpl_matrix *x_1,
01997     cpl_matrix *y_1,
01998     cpl_matrix *y_1err,
01999     cpl_matrix *x_2,
02000     cpl_matrix *y_2,
02001     cpl_matrix *y_2err
02002     ) {
02003 
02004     /*************************************************************************
02005                                      Variables
02006     *************************************************************************/
02007 
02008     register double a, b ,dx;
02009     register int    i, j, j_1, found, n1 ;
02010 
02011     cxint     nr_x1    = 0,
02012         nr_x2    = 0;
02013     cxdouble *pd_x1    = NULL,
02014         *pd_y1    = NULL,
02015         *pd_y1err = NULL,
02016         *pd_x2    = NULL,
02017         *pd_y2    = NULL,
02018         *pd_y2err = NULL;
02019 
02020     /*************************************************************************
02021                                     Preprocessing
02022     *************************************************************************/
02023 
02024     if (x_1 == NULL) { return 1; }
02025     if (y_1 == NULL) { return 1; }
02026     if (y_1err == NULL) { return 1; }
02027     if (x_2 == NULL) { return 1; }
02028     if (y_2 == NULL) { return 1; }
02029     if (y_2err == NULL) { return 1; }
02030 
02031     nr_x1    = cpl_matrix_get_nrow(x_1);
02032     nr_x2    = cpl_matrix_get_nrow(x_2);
02033     pd_x1    = cpl_matrix_get_data(x_1);
02034     pd_y1    = cpl_matrix_get_data(y_1);
02035     pd_y1err = cpl_matrix_get_data(y_1err);
02036     pd_x2    = cpl_matrix_get_data(x_2);
02037     pd_y2    = cpl_matrix_get_data(y_2);
02038     pd_y2err = cpl_matrix_get_data(y_2err);
02039 
02040     /*************************************************************************
02041                                      Processing
02042     *************************************************************************/
02043 
02044     n1 = nr_x1 - 1;
02045 
02046     for (i = 0; i < nr_x2; i++) {
02047         /* Find (x1,y1) on the left of the current point */
02048         found = 0;
02049         for (j = 0; j < n1; j++) {
02050             if ((pd_x2[i] >= pd_x1[j]) && (pd_x2[i] <= pd_x1[j+1])) {
02051                 found++ ;
02052                 break ;
02053             }
02054         }
02055 
02056         if (!found) {
02057             pd_y2[i]    = 0.0;
02058             pd_y2err[i] = 0.0;
02059         } else {
02060 
02061             j_1         = j + 1;
02062             dx          = (pd_x1[j_1] - pd_x1[j]);
02063             a           = (pd_y1[j_1] - pd_y1[j]) / dx;
02064             b           = pd_y1[j] - a * pd_x1[j] ;
02065             pd_y2[i]    = (a * pd_x2[i] + b) ;
02066             a           = (pd_y1err[j_1] - pd_y1err[j]) / dx;
02067             b           = pd_y1err[j] - a * pd_x1[j] ;
02068             pd_y2err[i] = (a * pd_x2[i] + b) ;
02069 
02070         }
02071     }
02072 
02073     return 0;
02074 
02075 } /* end giraffe_rebin_interpolate_linear_error() */
02076 
02096 inline static cxint
02097 _giraffe_resample_linear(cpl_image* rbspectra, cpl_image* rberrors,
02098                          cpl_image* abscissa, cpl_image* exspectra,
02099                          cpl_image* exerrors, cxint opt_direction)
02100 {
02101 
02102     const cxchar* const fctid = "_giraffe_resample_linear";
02103 
02104     register cxlong n = 0;
02105 
02106     cxint status = 0;
02107     cxint nx = 0;         /* size of extracted spectra   */
02108     cxint ns = 0;         /* number of extracted spectra */
02109     cxint nwl = 0;        /* size of rebinned spectra    */
02110 
02111     cxdouble nx1 = 0.;
02112     cxdouble* _mabscissa = NULL;
02113     cxdouble* _mexspectra = NULL;
02114     cxdouble* _mexerrors = NULL;
02115     cxdouble* _mwavelength = NULL;
02116     cxdouble* _mrbspectra = NULL;
02117     cxdouble* _mrberrors = NULL;
02118     cxdouble* _abscissa = NULL;
02119     cxdouble* _exspectra = NULL;
02120     cxdouble* _exerrors = NULL;
02121     cxdouble* _rbspectra = NULL;
02122     cxdouble* _rberrors = NULL;
02123 
02124     cpl_matrix* mabscissa = NULL;
02125     cpl_matrix* mwavelength = NULL;
02126     cpl_matrix* mexspectra = NULL;
02127     cpl_matrix* mexerrors = NULL;
02128     cpl_matrix* mrbspectra = NULL;
02129     cpl_matrix* mrberrors = NULL;
02130 
02131 
02132 
02133     if ((abscissa == NULL) || (exspectra == NULL) || (rbspectra == NULL)) {
02134         return 1;
02135     }
02136 
02137     if ((exerrors != NULL) && (rberrors == NULL)) {
02138         return 1;
02139     }
02140 
02141 
02142     nx = cpl_image_get_size_y(exspectra);
02143     ns = cpl_image_get_size_x(exspectra);
02144     nwl = cpl_image_get_size_y(abscissa);
02145 
02146     if ((exerrors != NULL) &&
02147         ((nx != cpl_image_get_size_y(exerrors)) ||
02148          (ns != cpl_image_get_size_x(exerrors)))) {
02149          return 1;
02150     }
02151 
02152     nx1 = nx - 0.5;
02153 
02154     mabscissa = cpl_matrix_new(nx, 1);
02155     mexspectra = cpl_matrix_new(nx, 1);
02156 
02157     mwavelength = cpl_matrix_new(nwl, 1);
02158     mrbspectra = cpl_matrix_new(nwl, 1);
02159 
02160     _mabscissa = cpl_matrix_get_data(mabscissa);
02161     _mexspectra = cpl_matrix_get_data(mexspectra);
02162     _mwavelength = cpl_matrix_get_data(mwavelength);
02163     _mrbspectra = cpl_matrix_get_data(mrbspectra);
02164 
02165     _abscissa = cpl_image_get_data_double(abscissa);
02166     _exspectra = cpl_image_get_data_double(exspectra);
02167     _rbspectra = cpl_image_get_data_double(rbspectra);
02168 
02169     if (exerrors != NULL) {
02170         mexerrors = cpl_matrix_new(nx, 1);
02171         mrberrors = cpl_matrix_new(nwl, 1);
02172 
02173         _mexerrors = cpl_matrix_get_data(mexerrors);
02174         _mrberrors = cpl_matrix_get_data(mrberrors);
02175 
02176         _exerrors = cpl_image_get_data_double(exerrors);
02177         _rberrors = cpl_image_get_data_double(rberrors);
02178     }
02179 
02180 
02181     /*
02182      * Resample each spectrum to the new grid, taking the direction of the
02183      * optical model into account. If the errors of the spectra are
02184      * available they are also resampled to the new grid.
02185      */
02186 
02187     cpl_msg_debug(fctid, "Rebinning %d spectra, using dispersion direction "
02188                   "%d and linear interpolation", ns, opt_direction);
02189 
02190     for (n = 0; n < ns; n++) {
02191 
02192         register cxlong x = 0;
02193 
02194 
02195         for (x = 0; x < nwl; x++) {
02196             register cxlong j = x * ns + n;
02197             _mwavelength[x] = _abscissa[j];
02198         }
02199 
02200         if (exerrors == NULL) {
02201 
02202             if (opt_direction < 0) {
02203 
02204                 for (x = 0; x < nx; x++) {
02205 
02206                     register cxlong j = x * ns + n;
02207                     register cxlong k = nx - x - 1;
02208 
02209                     _mabscissa[x] = (cxdouble) x;
02210                     _mexspectra[k] = _exspectra[j];
02211                 }
02212 
02213             }
02214             else {
02215 
02216                 for (x = 0; x < nx; x++) {
02217 
02218                     register cxlong j = x * ns + n;
02219 
02220                     _mabscissa[x] = (cxdouble) x;
02221                     _mexspectra[x] = _exspectra[j];
02222 
02223                 }
02224 
02225             }
02226 
02227 
02228             /*
02229              * Linear interpolation of spectra and errors
02230              */
02231 
02232             status = _giraffe_rebin_interpolate_linear(mabscissa,
02233                                                        mexspectra,
02234                                                        mwavelength,
02235                                                        mrbspectra);
02236 
02237             for (x = 0; x < nwl; x++) {
02238 
02239                 register cxlong j = x * ns + n;
02240 
02241                 if ((-0.5 > _mwavelength[x]) || (_mwavelength[x] > nx1)) {
02242                     _rbspectra[j] = 0.;
02243                 }
02244                 else {
02245                     _rbspectra[j] = _mrbspectra[x];
02246                 }
02247 
02248             }
02249 
02250         }
02251         else {
02252 
02253             if (opt_direction < 0) {
02254 
02255                 for (x = 0; x < nx; x++) {
02256 
02257                     register cxlong j = x * ns + n;
02258                     register cxlong k = nx - x - 1;
02259 
02260                     _mabscissa[x] = (cxdouble) x;
02261                     _mexspectra[k] = _exspectra[j];
02262                     _mexerrors[k] = _exerrors[j];
02263                 }
02264 
02265             }
02266             else {
02267 
02268                 for (x = 0; x < nx; x++) {
02269 
02270                     register cxlong j = x * ns + n;
02271 
02272                     _mabscissa[x] = (cxdouble) x;
02273                     _mexspectra[x] = _exspectra[j];
02274                     _mexerrors[x] = _exerrors[j];
02275 
02276                 }
02277 
02278             }
02279 
02280 
02281             /*
02282              * Linear interpolation of spectra and errors
02283              */
02284 
02285             status =
02286                 _giraffe_rebin_interpolate_linear_error(mabscissa,
02287                                                         mexspectra,
02288                                                         mexerrors,
02289                                                         mwavelength,
02290                                                         mrbspectra,
02291                                                         mrberrors);
02292 
02293             for (x = 0; x < nwl; x++) {
02294 
02295                 register cxlong j = x * ns + n;
02296 
02297                 if ((-0.5 > _mwavelength[x]) || (_mwavelength[x] > nx1)) {
02298                     _rbspectra[j] = 0.;
02299                     _rberrors[j] = 0.;
02300                 }
02301                 else {
02302                     _rbspectra[j] = _mrbspectra[x];
02303                     _rberrors[j] = _mrberrors[x];
02304                 }
02305 
02306             }
02307 
02308         }
02309 
02310     } /* each spectrum */
02311 
02312 
02313     cpl_matrix_delete(mrbspectra);
02314     mrbspectra = NULL;
02315 
02316     cpl_matrix_delete(mwavelength);
02317     mwavelength = NULL;
02318 
02319     cpl_matrix_delete(mexspectra);
02320     mexspectra = NULL;
02321 
02322     cpl_matrix_delete(mabscissa);
02323     mabscissa = NULL;
02324 
02325     if (exerrors != NULL) {
02326         cpl_matrix_delete(mrberrors);
02327         mrberrors = NULL;
02328 
02329         cpl_matrix_delete(mexerrors);
02330         mexerrors = NULL;
02331     }
02332 
02333     cpl_msg_debug(fctid, "Rebinned %d spectra", ns);
02334 
02335     return 0;
02336 
02337 }
02338 
02339 
02359 inline static cxint
02360 _giraffe_resample_spline(cpl_image* rbspectra, cpl_image* rberrors,
02361                          cpl_image* abscissa, cpl_image* exspectra,
02362                          cpl_image* exerrors, cxint opt_direction)
02363 {
02364 
02365     const cxchar* const fctid = "_giraffe_resample_spline";
02366 
02367     register cxlong n = 0;
02368 
02369     cxint status = 0;
02370     cxint nx = 0;         /* size of extracted spectra   */
02371     cxint ns = 0;         /* number of extracted spectra */
02372     cxint nwl = 0;        /* size of rebinned spectra    */
02373 
02374     cxdouble nx1 = 0.;
02375     cxdouble* _mabscissa = NULL;
02376     cxdouble* _mexspectra = NULL;
02377     cxdouble* _mexerrors = NULL;
02378     cxdouble* _mwavelength = NULL;
02379     cxdouble* _mrbspectra = NULL;
02380     cxdouble* _mrberrors = NULL;
02381     cxdouble* _abscissa = NULL;
02382     cxdouble* _exspectra = NULL;
02383     cxdouble* _exerrors = NULL;
02384     cxdouble* _rbspectra = NULL;
02385     cxdouble* _rberrors = NULL;
02386 
02387     cpl_matrix* mabscissa = NULL;
02388     cpl_matrix* mwavelength = NULL;
02389     cpl_matrix* mexspectra = NULL;
02390     cpl_matrix* mexerrors = NULL;
02391     cpl_matrix* mrbspectra = NULL;
02392     cpl_matrix* mrberrors = NULL;
02393 
02394 
02395 
02396     if ((abscissa == NULL) || (exspectra == NULL) || (rbspectra == NULL)) {
02397         return 1;
02398     }
02399 
02400     if ((exerrors != NULL) && (rberrors == NULL)) {
02401         return 1;
02402     }
02403 
02404 
02405     nx = cpl_image_get_size_y(exspectra);
02406     ns = cpl_image_get_size_x(exspectra);
02407     nwl = cpl_image_get_size_y(abscissa);
02408 
02409     if ((exerrors != NULL) &&
02410         ((nx != cpl_image_get_size_y(exerrors)) ||
02411          (ns != cpl_image_get_size_x(exerrors)))) {
02412              return 1;
02413          }
02414 
02415     nx1 = nx - 0.5;
02416 
02417     mabscissa = cpl_matrix_new(nx, 1);
02418     mexspectra = cpl_matrix_new(nx, 1);
02419 
02420     mwavelength = cpl_matrix_new(nwl, 1);
02421     mrbspectra = cpl_matrix_new(nwl, 1);
02422 
02423     _mabscissa = cpl_matrix_get_data(mabscissa);
02424     _mexspectra = cpl_matrix_get_data(mexspectra);
02425     _mwavelength = cpl_matrix_get_data(mwavelength);
02426     _mrbspectra = cpl_matrix_get_data(mrbspectra);
02427 
02428     _abscissa = cpl_image_get_data_double(abscissa);
02429     _exspectra = cpl_image_get_data_double(exspectra);
02430     _rbspectra = cpl_image_get_data_double(rbspectra);
02431 
02432     if (exerrors != NULL) {
02433         mexerrors = cpl_matrix_new(nx, 1);
02434         mrberrors = cpl_matrix_new(nwl, 1);
02435 
02436         _mexerrors = cpl_matrix_get_data(mexerrors);
02437         _mrberrors = cpl_matrix_get_data(mrberrors);
02438 
02439         _exerrors = cpl_image_get_data_double(exerrors);
02440         _rberrors = cpl_image_get_data_double(rberrors);
02441     }
02442 
02443 
02444     /*
02445      * Resample each spectrum to the new grid, taking the direction of the
02446      * optical model into account. If the errors of the spectra are
02447      * available they are also resampled to the new grid.
02448      */
02449 
02450     cpl_msg_debug(fctid, "Rebinning %d spectra, using dispersion direction "
02451                   "%d and linear interpolation", ns, opt_direction);
02452 
02453     for (n = 0; n < ns; n++) {
02454 
02455         register cxlong x = 0;
02456 
02457 
02458         for (x = 0; x < nwl; x++) {
02459             register cxlong j = x * ns + n;
02460             _mwavelength[x] = _abscissa[j];
02461         }
02462 
02463         if (exerrors == NULL) {
02464 
02465             if (opt_direction < 0) {
02466 
02467                 for (x = 0; x < nx; x++) {
02468 
02469                     register cxlong j = x * ns + n;
02470                     register cxlong k = nx - x - 1;
02471 
02472                     _mabscissa[x] = (cxdouble) x;
02473                     _mexspectra[k] = _exspectra[j];
02474                 }
02475 
02476             }
02477             else {
02478 
02479                 for (x = 0; x < nx; x++) {
02480 
02481                     register cxlong j = x * ns + n;
02482 
02483                     _mabscissa[x] = (cxdouble) x;
02484                     _mexspectra[x] = _exspectra[j];
02485 
02486                 }
02487 
02488             }
02489 
02490 
02491             /*
02492              * Spline interpolation of spectra and errors
02493              */
02494 
02495             status = _giraffe_rebin_interpolate_spline(mabscissa,
02496                                                        mexspectra,
02497                                                        mwavelength,
02498                                                        mrbspectra);
02499 
02500             for (x = 0; x < nwl; x++) {
02501 
02502                 register cxlong j = x * ns + n;
02503 
02504                 if ((-0.5 > _mwavelength[x]) || (_mwavelength[x] > nx1)) {
02505                     _rbspectra[j] = 0.;
02506                 }
02507                 else {
02508                     _rbspectra[j] = _mrbspectra[x];
02509                 }
02510 
02511             }
02512 
02513         }
02514         else {
02515 
02516             if (opt_direction < 0) {
02517 
02518                 for (x = 0; x < nx; x++) {
02519 
02520                     register cxlong j = x * ns + n;
02521                     register cxlong k = nx - x - 1;
02522 
02523                     _mabscissa[x] = (cxdouble) x;
02524                     _mexspectra[k] = _exspectra[j];
02525                     _mexerrors[k] = _exerrors[j];
02526                 }
02527 
02528             }
02529             else {
02530 
02531                 for (x = 0; x < nx; x++) {
02532 
02533                     register cxlong j = x * ns + n;
02534 
02535                     _mabscissa[x] = (cxdouble) x;
02536                     _mexspectra[x] = _exspectra[j];
02537                     _mexerrors[x] = _exerrors[j];
02538 
02539                 }
02540 
02541             }
02542 
02543 
02544             /*
02545              * Spline interpolation of spectra and linear interpolation of
02546              * errors
02547              */
02548 
02549             status = _giraffe_rebin_interpolate_spline(mabscissa,
02550                                                        mexspectra,
02551                                                        mwavelength,
02552                                                        mrbspectra);
02553 
02554             status = _giraffe_rebin_interpolate_linear(mabscissa,
02555                                                        mexerrors,
02556                                                        mwavelength,
02557                                                        mrberrors);
02558 
02559             for (x = 0; x < nwl; x++) {
02560 
02561                 register cxlong j = x * ns + n;
02562 
02563                 if ((-0.5 > _mwavelength[x]) || (_mwavelength[x] > nx1)) {
02564                     _rbspectra[j] = 0.;
02565                     _rberrors[j] = 0.;
02566                 }
02567                 else {
02568                     _rbspectra[j] = _mrbspectra[x];
02569                     _rberrors[j] = _mrberrors[x];
02570                 }
02571 
02572             }
02573 
02574         }
02575 
02576     } /* each spectrum */
02577 
02578 
02579     cpl_matrix_delete(mrbspectra);
02580     mrbspectra = NULL;
02581 
02582     cpl_matrix_delete(mwavelength);
02583     mwavelength = NULL;
02584 
02585     cpl_matrix_delete(mexspectra);
02586     mexspectra = NULL;
02587 
02588     cpl_matrix_delete(mabscissa);
02589     mabscissa = NULL;
02590 
02591     if (exerrors != NULL) {
02592         cpl_matrix_delete(mrberrors);
02593         mrberrors = NULL;
02594 
02595         cpl_matrix_delete(mexerrors);
02596         mexerrors = NULL;
02597     }
02598 
02599     cpl_msg_debug(fctid, "Rebinned %d spectra", ns);
02600 
02601     return 0;
02602 
02603 }
02604 
02605 
02679 static cxdouble
02680 giraffe_rebin_compute_opt_mod3(cxdouble xccd, cxdouble xfibre,
02681                                cxdouble yfibre, cxdouble nx,
02682                                cxdouble pixsize, cxdouble fcoll,
02683                                cxdouble cfact, cxdouble gtheta,
02684                                cxdouble gorder, cxdouble gspace,
02685                                cxdouble slitdx, cxdouble slitdy,
02686                                cxdouble slitphi)
02687 {
02688 
02689     /*************************************************************************
02690                                      Variables
02691     *************************************************************************/
02692 
02693     cxdouble xf, yf, d, t1, t12, t13, t18, t19, t2, t23, t28,
02694         t3, t31, t32, t36, t37, t39, t4, t40, t5, t62, t8, t9;
02695 
02696     /*************************************************************************
02697                                      Processing
02698     *************************************************************************/
02699 
02700     /* should take care of negative NX value */
02701 
02702     xf = xfibre * (1.0 + slitphi * yfibre) + slitdx;
02703     yf = yfibre * sqrt(1.0 - slitphi * slitphi) + slitdy;
02704     d = sqrt(xf * xf + yf * yf + fcoll * fcoll);
02705     t1 = cos(gtheta);
02706     t2 = xf*t1;
02707     t3 = xccd*xccd;
02708     t4 = pixsize*pixsize;
02709     t5 = t3*t4;
02710     t8 = sin(gtheta);
02711     t9 = fcoll*t8;
02712     t12 = cfact*cfact;
02713     t13 = fcoll*fcoll;
02714     t18 = nx*nx;
02715     t19 = t18*t4;
02716     t23 = xccd*t4*nx;
02717     t28 = t12*t13;
02718     t31 = yf*yf;
02719     t32 = d*d;
02720     t36 = 4.0*t28;
02721     t37 = t19+4.0*t5-4.0*t23+t36;
02722     t39 = t1*t1;
02723     t40 = t39*t4;
02724     t62 = sqrt((-t31+t32)*t37*(4.0*t40*t3-4.0*xccd*nx*t40 +
02725                                8.0*xccd*t1*cfact*t9*pixsize+t19*t39 -
02726                                4.0*cfact*fcoll*t8*nx*t1*pixsize+t36 -
02727                                4.0*t28*t39));
02728 
02729     return((4.0*t2*t5 + 4.0*t9*t5 + 4.0*t12*t13*fcoll*t8+t2*t19+t9*t19 -
02730             4.0*t9*t23 - 4.0*t2*t23 + 4.0*t28*t2+t62)*gspace/t37/gorder/d);
02731 
02732 } /* end giraffe_rebin_compute_opt_mod3() */
02733 
02758 static cxdouble
02759 giraffe_rebin_compute_log_opt_mod3(cxdouble xccd, cxdouble xfibre,
02760                                    cxdouble yfibre, cxdouble nx,
02761                                    cxdouble pixsize, cxdouble fcoll,
02762                                    cxdouble cfact, cxdouble gtheta,
02763                                    cxdouble gorder, cxdouble gspace,
02764                                    cxdouble slitdx, cxdouble slitdy,
02765                                    cxdouble slitphi)
02766 {
02767 
02768     return log(giraffe_rebin_compute_opt_mod3(xccd, xfibre, yfibre, nx,
02769                                               pixsize, fcoll, cfact, gtheta,
02770                                               gorder, gspace, slitdx, slitdy,
02771                                               slitphi));
02772 
02773 } /* end of giraffe_rebin_compute_log_opt_mod3() */
02774 
02821 static cxint
02822 giraffe_rebin_compute_lambda_range(GiFiberPosition *fiber_slit_position,
02823                                    cpl_matrix *opt_mod_params,
02824                                    cpl_matrix *grat_params,
02825                                    cxbool lambda_logarithmic,
02826                                    cxbool wlen_range_common,
02827                                    cxdouble *lambda_min, cxdouble *lambda_max)
02828 {
02829 
02830     /*************************************************************************
02831                                      Variables
02832     *************************************************************************/
02833 
02834     const cxchar *fctid = "giraffe_rebin_compute_lambda_range";
02835 
02836     register cxlong   n, ns;
02837     register cxdouble dx2, dnx, wl1, wl2;
02838 
02839     double (*computeWl) (double, double, double, double, double, double,
02840                          double, double, double, double, double, double,
02841                          double);
02842 
02843     cxdouble    *pd_opt_mod_params = NULL,
02844         *pd_xfiber        = NULL,
02845         *pd_yfiber        = NULL,
02846         *pd_grat_params    = NULL;
02847 
02848     cxint        nr_xfiber;
02849 
02850     /*************************************************************************
02851                                     Preprocessing
02852     *************************************************************************/
02853 
02854     if (fiber_slit_position         ==NULL) { return 1; }
02855     if (fiber_slit_position->x_fiber==NULL) { return 1; }
02856     if (fiber_slit_position->y_fiber==NULL) { return 1; }
02857     if (opt_mod_params              ==NULL) { return 1; }
02858     if (grat_params                 ==NULL) { return 1; }
02859     if (lambda_min                  ==NULL) { return 1; }
02860     if (lambda_max                  ==NULL) { return 1; }
02861 
02862     pd_opt_mod_params = cpl_matrix_get_data(opt_mod_params);
02863 
02864     pd_xfiber = cpl_matrix_get_data(fiber_slit_position->x_fiber);
02865     nr_xfiber = cpl_matrix_get_nrow(fiber_slit_position->x_fiber);
02866 
02867     /*************************************************************************
02868                                      Processing
02869     *************************************************************************/
02870 
02871     if (lambda_logarithmic==TRUE) {
02872         computeWl = giraffe_rebin_compute_log_opt_mod3;
02873     } else {
02874         computeWl = giraffe_rebin_compute_opt_mod3;
02875     }
02876 
02877     dnx = abs(pd_opt_mod_params[O_NX]);
02878     dx2 = dnx - 1.0;
02879     ns  = nr_xfiber;
02880 
02881     if (wlen_range_common==TRUE) {
02882         *lambda_min = 0.0;
02883         *lambda_max = CX_MAXDOUBLE;
02884     } else {
02885         *lambda_min = CX_MAXDOUBLE;
02886         *lambda_max = 0.0;
02887     }
02888 
02889     pd_yfiber = cpl_matrix_get_data(fiber_slit_position->y_fiber);
02890     pd_grat_params = cpl_matrix_get_data(grat_params);
02891 
02892     for (n = 0; n < ns; n++) {
02893 
02894         /* first abcissa  of each spectrum */
02895         wl1 =
02896             computeWl(
02897                 0.0,
02898                 pd_xfiber[n],
02899                 pd_yfiber[n],
02900                 dnx,
02901                 pd_opt_mod_params[O_PXSIZ],
02902                 pd_opt_mod_params[O_FCOLL],
02903                 pd_opt_mod_params[O_CFACT],
02904                 pd_grat_params[G_THETA],
02905                 pd_grat_params[G_ORDER],
02906                 pd_grat_params[G_SPACE],
02907                 pd_opt_mod_params[O_SOFFX],
02908                 pd_opt_mod_params[O_SOFFY],
02909                 pd_opt_mod_params[O_SPHI]
02910                 );
02911 
02912         /* last abcissa  of each spectrum */
02913         wl2 =
02914             computeWl(
02915                 dx2,
02916                 pd_xfiber[n],
02917                 pd_yfiber[n],
02918                 dnx,
02919                 pd_opt_mod_params[O_PXSIZ],
02920                 pd_opt_mod_params[O_FCOLL],
02921                 pd_opt_mod_params[O_CFACT],
02922                 pd_grat_params[G_THETA],
02923                 pd_grat_params[G_ORDER],
02924                 pd_grat_params[G_SPACE],
02925                 pd_opt_mod_params[O_SOFFX],
02926                 pd_opt_mod_params[O_SOFFY],
02927                 pd_opt_mod_params[O_SPHI]
02928                 );
02929 
02930         if (wlen_range_common==TRUE) {
02931 
02932             /* common range = [max(wlen_min), min(wlen_max)] */
02933 
02934             if (pd_opt_mod_params[O_NX] < 0) {
02935                 *lambda_max = CX_MIN(*lambda_max, wl1);
02936                 *lambda_min = CX_MAX(*lambda_min, wl2);
02937             } else {
02938                 *lambda_max = CX_MIN(*lambda_max, wl2);
02939                 *lambda_min = CX_MAX(*lambda_min, wl1);
02940             }
02941 
02942         } else {
02943 
02944             /* full range = [min(wlen_min), max(wlen_max)] */
02945 
02946             if (pd_opt_mod_params[O_NX] < 0) {
02947                 *lambda_max = CX_MAX(*lambda_max, wl1);
02948                 *lambda_min = CX_MIN(*lambda_min, wl2);
02949             } else {
02950                 *lambda_max = CX_MAX(*lambda_max, wl2);
02951                 *lambda_min = CX_MIN(*lambda_min, wl1);
02952             }
02953 
02954         }
02955 
02956     } /* for each spectrum */
02957 
02958     if (wlen_range_common==TRUE) {
02959         /* round to minimum range in integer nanometers */
02960         *lambda_max = floor((*lambda_max) * GI_MM_TO_NM) / GI_MM_TO_NM;
02961         *lambda_min = ceil( (*lambda_min) * GI_MM_TO_NM) / GI_MM_TO_NM;
02962     } else {
02963         /* round to maximum range in integer nanometers */
02964         *lambda_max = ceil( (*lambda_max) * GI_MM_TO_NM) / GI_MM_TO_NM;
02965         *lambda_min = floor((*lambda_min) * GI_MM_TO_NM) / GI_MM_TO_NM;
02966     }
02967 
02968     cpl_msg_debug(fctid, "Rebinning lambda range now: [%12.6f,%12.6f]",
02969                   *lambda_min, *lambda_max);
02970 
02971     return 0;
02972 
02973 } /* end giraffe_rebin_compute_lambda_range() */
02974 
02997 static cpl_image*
02998 giraffe_rebin_compute_pixel_x_residuals(
02999     GiLocPosition   *locPos,
03000     cpl_image       *abcissa,
03001     GiSlitGeo  *slitGeo,
03002     GiSlitGeo  *xresiduals_limits,
03003     GiSlitGeo  *xresiduals_coeff
03004     ) {
03005 
03006     /*************************************************************************
03007                                      Variables
03008     *************************************************************************/
03009 
03010     const cxchar *fctid = "giraffe_rebin_compute_pixel_x_residuals";
03011 
03012     cxdouble xmin, xmax, ymin, ymax, yup, ylo, yccd, ywid;
03013     cxint    n, m, x, xx, x0, i, j, k, l, xxp, x0p;
03014 
03015     cxint             subslit,
03016         nfibers,
03017         nmin,
03018         nmax,
03019         nlen,
03020         nx,       /* size of original spectra */
03021         ns,       /* number of spectra */
03022         nwl,      /* size of rebinned spectra */
03023         nf,
03024         nstart,
03025         ndata,
03026         nr_fit,
03027         nc_fit;
03028 
03029     cpl_matrix       *xss                = NULL,
03030         *yss                = NULL,
03031         *fit                = NULL,
03032         *curr_xres_limits   = NULL,
03033         *curr_xres_coeff    = NULL;
03034 
03035     cpl_image        *x_residuals_img    = NULL;
03036 
03037     cpl_matrix       *curr_subslit       = NULL;
03038 
03039     cxdouble         *pd_curr_subslit    = NULL,
03040         *pd_abcissa         = NULL,
03041         *pd_xss             = NULL,
03042         *pd_yss             = NULL;
03043 
03044     cxdouble         *pd_locy            = NULL,
03045         *pd_locw            = NULL,
03046         *buffer             = NULL,
03047         *pd_fit             = NULL,
03048         *pd_x_residuals_img = NULL;
03049 
03050 
03051     /*************************************************************************
03052                                     Preprocessing
03053     *************************************************************************/
03054 
03055     if (locPos            ==NULL) { return NULL; }
03056     if (locPos->centroids ==NULL) { return NULL; }
03057     if (locPos->widths    ==NULL) { return NULL; }
03058     if (abcissa           ==NULL) { return NULL; }
03059     if (slitGeo           ==NULL) { return NULL; }
03060     if (xresiduals_limits ==NULL) { return NULL; }
03061     if (xresiduals_coeff  ==NULL) { return NULL; }
03062 
03063     nx  = cpl_image_get_size_y(locPos->centroids);
03064     ns  = cpl_image_get_size_x(locPos->centroids);
03065     nf  = cpl_image_get_size_x(abcissa);
03066     nwl = cpl_image_get_size_y(abcissa);
03067 
03068     cpl_msg_debug(
03069         fctid,
03070         "Computing pixel x residuals, using nr spec/nr lines/orig abcissa "
03071         "size: %d/%d/%d",
03072         ns,
03073         nwl,
03074         nx
03075         );
03076 
03077     /*************************************************************************
03078                                      Processing
03079     *************************************************************************/
03080 
03081     x_residuals_img    = cpl_image_new(nf, nwl, CPL_TYPE_DOUBLE);
03082     pd_x_residuals_img = cpl_image_get_data_double(x_residuals_img);
03083     pd_abcissa         = cpl_image_get_data_double(abcissa);
03084 
03085     nstart = 0;
03086 
03087     for (subslit = 0; subslit<_giraffe_slitgeo_size(slitGeo); subslit++) {
03088 
03089         curr_subslit    = _giraffe_slitgeo_get(slitGeo, subslit);
03090         pd_curr_subslit = cpl_matrix_get_data(curr_subslit);
03091 
03092         giraffe_matrix_sort(curr_subslit);
03093 
03094         curr_xres_limits =
03095             cpl_matrix_duplicate(
03096                 _giraffe_slitgeo_get(xresiduals_limits, subslit)
03097                 );
03098 
03099         curr_xres_coeff =
03100             cpl_matrix_duplicate(
03101                 _giraffe_slitgeo_get(xresiduals_coeff, subslit)
03102                 );
03103 
03104         /* Get spectra/fibers range for current subslit */
03105         nfibers = cpl_matrix_get_nrow(curr_subslit);
03106 
03107         nmin    = (cxint) pd_curr_subslit[0];
03108         nmax    = (cxint) pd_curr_subslit[nfibers - 1];
03109         nlen    = nmax - nmin + 1;
03110         ndata   = nwl * nfibers;
03111 
03112         ymax    = 0.0;
03113         ymin    = CX_MAXDOUBLE;   /* has to be smaller than this one! */
03114 
03115         xss     = cpl_matrix_new(ndata, 1); /* X abcissas for subslit  */
03116         yss     = cpl_matrix_new(ndata, 1); /* Y ordinates             */
03117 
03118         pd_xss  = cpl_matrix_get_data(xss);
03119         pd_yss  = cpl_matrix_get_data(yss);
03120 
03121         pd_locy = cpl_image_get_data_double(locPos->centroids);
03122         pd_locw = cpl_image_get_data_double(locPos->widths);
03123 
03124 
03125         k = 0;
03126 
03127         for (m = 0, n = 0; n < nfibers; n++, m++) {
03128 
03129             i = 0;  /* running index for valid points */
03130 
03131             for (x = 0; x < nwl; x++) {
03132 
03133                 j  = x * nf + (nstart + n);
03134                 x0 = (cxint) floor(pd_abcissa[j]);
03135                 xx = (cxint) ceil(pd_abcissa[j]);
03136 
03137                 x0 = CX_MAX(CX_MIN(x0, nx - 1), 0);
03138                 xx = CX_MAX(CX_MIN(xx, nx - 1), 0);
03139 
03140                 l   = i  * nfibers + m;
03141                 xxp = xx * ns   + cpl_matrix_get(curr_subslit, n, 0);
03142                 x0p = x0 * ns   + cpl_matrix_get(curr_subslit, n, 0);
03143 
03144                 pd_xss[l] = pd_abcissa[j];
03145 
03146                 /*
03147                  * Corresponding Y centroid  and width using
03148                  * linear interpolation)
03149                  */
03150 
03151                 yccd      = pd_locy[x0p];
03152                 pd_yss[l] = yccd + ((pd_locy[xxp] - yccd) * (pd_xss[l] - x0));
03153 
03154                 ywid = pd_locw[x0p];
03155                 ywid = ywid + ((pd_locw[xxp] - ywid) * (pd_xss[l] - x0));
03156 
03157                 /* Get y range for current subslit */
03158                 yup = yccd + ywid;
03159                 ylo = yccd - ywid;
03160 
03161                 /* determine minimum and maximum */
03162                 if (ymax < yup) {
03163                     ymax = yup;
03164                 }
03165 
03166                 if (ymin > ylo) {
03167                     ymin = ylo;
03168                 }
03169 
03170                 ++i;
03171                 ++k;
03172 
03173             }
03174         }
03175 
03176         /* resize matrices to number of points found */
03177         cpl_matrix_set_size(xss, k, 1);
03178         cpl_matrix_set_size(yss, k, 1);
03179         pd_xss = cpl_matrix_get_data(xss);
03180         pd_yss = cpl_matrix_get_data(yss);
03181 
03182         xmin = cpl_matrix_get(curr_xres_limits, 0, 0);
03183         xmax = cpl_matrix_get(curr_xres_limits, 0, 1);
03184         ymin = cpl_matrix_get(curr_xres_limits, 0, 2);
03185         ymax = cpl_matrix_get(curr_xres_limits, 0, 3);
03186 
03187         xmin = xmin < 0. ? 0. : xmin;
03188         xmax = xmax < 0. ? (cxdouble)nx : xmax;
03189 
03190         ymin = ymin < 0. ? 0. : ymin;
03191         ymax = ymax < 0. ? 2048. : ymax;
03192 
03193         /* do chebyshev fit */
03194         fit =
03195             giraffe_chebyshev_fit2d(
03196                 xmin, ymin,
03197                 (xmax - xmin),
03198                 (ymax - ymin + 1.0),
03199                 curr_xres_coeff,
03200                 xss,
03201                 yss
03202                 );
03203 
03204         cpl_matrix_delete(yss);
03205         cpl_matrix_delete(xss);
03206         cpl_matrix_delete(curr_xres_coeff);
03207         cpl_matrix_delete(curr_xres_limits);
03208 
03209         /* resize fit found to match image dimensions */
03210         buffer = cpl_matrix_get_data(fit);
03211         cpl_matrix_unwrap(fit);
03212         fit = NULL;
03213 
03214         fit = cpl_matrix_wrap(nwl, nfibers, buffer);
03215         pd_fit = cpl_matrix_get_data(fit);
03216         nr_fit = cpl_matrix_get_nrow(fit);
03217         nc_fit = cpl_matrix_get_ncol(fit);
03218 
03219         /* subslit fit goes into whole fit */
03220         for (x = 0; x < nr_fit; x++) {
03221             for (k = nstart, n = 0; n < nc_fit; n++, k++) {
03222                 pd_x_residuals_img[x * nf + k] = pd_fit[x * nc_fit + n];
03223             }
03224         }
03225 
03226         cpl_matrix_delete(fit);
03227         fit = NULL;
03228 
03229         nstart += nfibers;
03230 
03231     } /* for each subslit */
03232 
03233     cpl_msg_debug(
03234         fctid,
03235         "Computed pixel x residuals, returning image [%d,%d]",
03236         ns,
03237         nwl
03238         );
03239 
03240     return x_residuals_img;
03241 
03242 } /* end giraffe_rebin_compute_pixel_x_residuals() */
03243 
03244 
03277 static cpl_image*
03278 giraffe_rebin_compute_rebin_abcissa(GiFiberPosition* fiber_slit_position,
03279                                     GiLocPosition* locPos,
03280                                     GiSlitGeo* slitGeo,
03281                                     GiSlitGeo* xresiduals_limits,
03282                                     GiSlitGeo* xresiduals_coeff,
03283                                     cpl_matrix* grat_params,
03284                                     cpl_matrix* opt_mod_params,
03285                                     cpl_matrix* wloffsets,
03286                                     lmrq_model lmrq_opt_mod_x,
03287                                     GiRebinParams binPrms)
03288 {
03289 
03290     /*************************************************************************
03291                                      Variables
03292     *************************************************************************/
03293 
03294     const cxchar* const fctid = "giraffe_rebin_compute_rebin_abcissa";
03295 
03296     cpl_matrix* wlengths    = NULL;
03297     cpl_matrix* temp_params = NULL;
03298 
03299     cpl_image* abcissa         = NULL;
03300     cpl_image* x_residuals_img = NULL;
03301 
03302     cxdouble* pd_wlengths       = NULL;
03303     cxdouble* pd_temp_params    = NULL;
03304     cxdouble* pd_opt_mod_params = NULL;
03305     cxdouble* pd_grat_params    = NULL;
03306 
03307     /*************************************************************************
03308                                     Preprocessing
03309     *************************************************************************/
03310 
03311     if (fiber_slit_position == NULL) {
03312         return NULL;
03313     }
03314 
03315     if (locPos == NULL) {
03316         return NULL;
03317     }
03318 
03319     if (slitGeo == NULL) {
03320         return NULL;
03321     }
03322 
03323     if (grat_params == NULL) {
03324         return NULL;
03325     }
03326 
03327     if (opt_mod_params == NULL) {
03328         return NULL;
03329     }
03330 
03331     wlengths    = cpl_matrix_new(binPrms.size, 1);
03332     pd_wlengths = cpl_matrix_get_data(wlengths);
03333 
03334     temp_params = cpl_matrix_new(lmrq_opt_mod_x.nparams, 1);
03335 
03336     pd_temp_params    = cpl_matrix_get_data(temp_params);
03337     pd_opt_mod_params = cpl_matrix_get_data(opt_mod_params);
03338     pd_grat_params    = cpl_matrix_get_data(grat_params);
03339 
03340     pd_temp_params[OG_NX]    = pd_opt_mod_params[O_NX];
03341     pd_temp_params[OG_PXSIZ] = pd_opt_mod_params[O_PXSIZ];
03342     pd_temp_params[OG_FCOLL] = pd_opt_mod_params[O_FCOLL];
03343     pd_temp_params[OG_CFACT] = pd_opt_mod_params[O_CFACT];
03344     pd_temp_params[OG_THETA] = pd_grat_params[G_THETA];
03345     pd_temp_params[OG_ORDER] = pd_grat_params[G_ORDER];
03346     pd_temp_params[OG_SPACE] = pd_grat_params[G_SPACE];
03347 
03348     if (lmrq_opt_mod_x.nparams > OG_SOFFX) {
03349         pd_temp_params[OG_SOFFX] = pd_opt_mod_params[O_SOFFX];
03350         pd_temp_params[OG_SOFFY] = pd_opt_mod_params[O_SOFFY];
03351         pd_temp_params[OG_SPHI]  = pd_opt_mod_params[O_SPHI];
03352     }
03353 
03354     /*************************************************************************
03355                                      Processing
03356     *************************************************************************/
03357 
03358     /*
03359      *  Compute lambda abcissa for rebinning
03360      */
03361 
03362     if (binPrms.log==TRUE) {
03363         /* lambda was specified in log(lambda) */
03364         cxint i;
03365         for (i = 0; i < binPrms.size; i++) {
03366             pd_wlengths[i] = exp(binPrms.min + (cxdouble) i * binPrms.step);
03367         }
03368     } else {
03369         cxint i;
03370         for (i = 0; i < binPrms.size; i++) {
03371             pd_wlengths[i] = binPrms.min + (cxdouble) i * binPrms.step;
03372         }
03373     }
03374 
03375     abcissa = _giraffe_compute_pixel_abscissa(wlengths, wloffsets,
03376                                               fiber_slit_position,
03377                                               temp_params, lmrq_opt_mod_x);
03378 
03379 
03380     /*
03381      *  If X residuals use, specified, calculate them and subtract
03382      *  them from the computed abcissa...
03383      */
03384 
03385     if ((binPrms.xres==TRUE) && (xresiduals_coeff!=NULL)) {
03386 
03387         x_residuals_img =
03388             giraffe_rebin_compute_pixel_x_residuals(
03389                 locPos,
03390                 abcissa,
03391                 slitGeo,
03392                 xresiduals_limits,
03393                 xresiduals_coeff
03394                 );
03395 
03396         cpl_image_subtract(abcissa, x_residuals_img);
03397         cpl_image_delete(x_residuals_img);
03398 
03399     }
03400 
03401     cpl_matrix_delete(wlengths);
03402     cpl_matrix_delete(temp_params);
03403 
03404     cpl_msg_debug(
03405         fctid,
03406         "Processing complete : returning image [%d, %d]",
03407         cpl_image_get_size_x(abcissa),
03408         cpl_image_get_size_y(abcissa)
03409         );
03410 
03411     return abcissa;
03412 
03413 } /* end giraffe_rebin_compute_rebin_abcissa() */
03414 
03442 inline static cxint
03443 _giraffe_resample_spectra(GiRebinning* result,
03444                           const GiExtraction* extraction,
03445                           const GiLocalization* localization,
03446                           GiFiberPosition* fiber_position,
03447                           GiSlitGeo* subslits,
03448                           GiSlitGeo* xres_limits,
03449                           GiSlitGeo* xres_coeff,
03450                           GiBinnParams* xres_order,
03451                           cpl_matrix* grating_data,
03452                           cpl_matrix* optical_model,
03453                           cpl_matrix* wlen_offsets,
03454                           cxdouble rbstep,
03455                           GiRebinMethod method,
03456                           GiRebinRange range,
03457                           GiRebinScale scale)
03458 {
03459 
03460     const cxchar* const fctid = "_giraffe_resample_spectra";
03461 
03462 
03463     cxbool log_scale = FALSE;
03464 
03465     cxint i = 0;
03466     cxint status = 0;
03467     cxint om_sign = 0;
03468     cxint rbsize = 0;
03469     cxint nspectra = 0;
03470 
03471     cxdouble wlmin = 0.;
03472     cxdouble wlmax = 0.;
03473     cxdouble* _optical_model = NULL;
03474 
03475     cpl_matrix* wavelengths = NULL;
03476 
03477     cpl_image* _exspectra = NULL;
03478     cpl_image* _exerrors = NULL;
03479     cpl_image* _rbspectra = NULL;
03480     cpl_image* _rberrors = NULL;
03481     cpl_image* abscissa = NULL;
03482 
03483     cpl_propertylist* properties = NULL;
03484 
03485     GiImage* rbspectra = NULL;
03486     GiImage* rberrors = NULL;
03487 
03488     GiLocPosition locPos;
03489 
03490     GiRebinParams binPrms;
03491 
03492     GiRebinInfo setup;
03493 
03494 
03495     /*
03496      * default opt model is xoptmod2, python code
03497      * can not handle anything else anyway
03498      */
03499 
03500      lmrq_model_id opt_mod_id = LMRQ_XOPTMOD2;
03501 
03502 
03503     if (result == NULL || extraction == NULL || localization == NULL) {
03504         return 1;
03505     }
03506 
03507     if (result->spectra != NULL || result->errors != NULL) {
03508         return 1;
03509     }
03510 
03511     if (extraction->spectra == NULL) {
03512         return 1;
03513     }
03514 
03515     if (localization->locy == NULL || localization->locw == NULL) {
03516         return 1;
03517     }
03518 
03519     if (fiber_position == NULL) {
03520         return 1;
03521     }
03522 
03523     if (subslits == NULL) {
03524         return 1;
03525     }
03526 
03527     if (grating_data == NULL) {
03528         return 1;
03529     }
03530 
03531     if (optical_model == NULL) {
03532         return 1;
03533     }
03534 
03535 
03536     if (xres_coeff != NULL) {
03537         if (xres_limits == NULL || xres_order == NULL) {
03538             return 1;
03539         }
03540     }
03541 
03542 
03543     /*
03544      * FIXME: Should we set opt_mod_id to opt_mod_id used by wave
03545      *        calibration? Yes!!!
03546      */
03547 
03548     _exspectra = giraffe_image_get(extraction->spectra);
03549 
03550     if (extraction->error != NULL) {
03551         _exerrors = giraffe_image_get(extraction->error);
03552     }
03553 
03554     _optical_model = cpl_matrix_get_data(optical_model);
03555 
03556     nspectra = cpl_image_get_size_x(_exspectra);
03557 
03558     om_sign = (_optical_model[O_NX] >= 0) ? 1 : -1;
03559 
03560     if (scale == GIREBIN_SCALE_LOG) {
03561         log_scale = TRUE;
03562     }
03563 
03564 
03565     /*
03566      *  Find wavelength range
03567      */
03568 
03569      if (range == GIREBIN_RANGE_SETUP) {
03570 
03571         /*
03572          * Wavelength range taken from observed mode
03573          */
03574 
03575         wlmin = cpl_matrix_get(grating_data, 2, 0);
03576         wlmax = cpl_matrix_get(grating_data, 4, 0);
03577 
03578         if (log_scale == TRUE) {
03579             wlmin = log(wlmin);
03580             wlmax = log(wlmax);
03581         }
03582 
03583     }
03584     else {
03585 
03586         /*
03587          * Spectral range based on max/min wavelengths
03588          */
03589 
03590         status = giraffe_rebin_compute_lambda_range(fiber_position,
03591                                                     optical_model,
03592                                                     grating_data, log_scale,
03593                                                     TRUE, &wlmin, &wlmax);
03594 
03595     }
03596 
03597     rbsize = 1 + (cxint) ((wlmax - wlmin) / rbstep);
03598 
03599     if (rbsize < 0) {
03600 
03601         cpl_msg_debug(fctid, "Invalid dispersion direction [%d], changing "
03602                       "optical model orientation", om_sign);
03603 
03604         om_sign = -om_sign;
03605         _optical_model[O_NX] = -_optical_model[O_NX];
03606 
03607         status = giraffe_rebin_compute_lambda_range(fiber_position,
03608                                                     optical_model,
03609                                                     grating_data, log_scale,
03610                                                     TRUE, &wlmin, &wlmax);
03611 
03612         rbsize = 1 + (cxint) ((wlmax - wlmin) / rbstep);
03613 
03614     }
03615 
03616     if (rbsize < 1) {
03617         cpl_msg_error(fctid, "Invalid size %d of rebinned spectra, "
03618                       "aborting...", rbsize);
03619         return 2;
03620     }
03621 
03622 
03623     /*
03624      *  Calculate rebinned X positions...
03625      */
03626 
03627     locPos.type      = GILOCDATATYPE_FITTED_DATA;
03628     locPos.centroids = giraffe_image_get(localization->locy);
03629     locPos.widths    = giraffe_image_get(localization->locw);
03630 
03631     binPrms.min  = wlmin;
03632     binPrms.step = rbstep;
03633     binPrms.size = rbsize;
03634     binPrms.log  = log_scale;
03635 
03636     if (xres_coeff == NULL || (xres_order->xdeg == 0 &&
03637                                xres_order->ydeg == 0)) {
03638         binPrms.xres = FALSE;
03639     }
03640     else {
03641         binPrms.xres = TRUE;
03642     }
03643 
03644     abscissa = giraffe_rebin_compute_rebin_abcissa(fiber_position, &locPos,
03645                                                    subslits, xres_limits,
03646                                                    xres_coeff, grating_data,
03647                                                    optical_model, wlen_offsets,
03648                                                    lmrq_models[opt_mod_id],
03649                                                    binPrms);
03650 
03651 
03652     /*
03653      *  Perform rebinng of spectra and associated errors...
03654      */
03655 
03656     wavelengths = cpl_matrix_new(rbsize, 1);
03657 
03658     for (i = 0; i < rbsize; i++) {
03659         cpl_matrix_set(wavelengths, i, 0, wlmin + (cxdouble) i * rbstep);
03660     }
03661 
03662     rbspectra = giraffe_image_create(CPL_TYPE_DOUBLE, nspectra, rbsize);
03663     _rbspectra = giraffe_image_get(rbspectra);
03664 
03665     if (_exerrors != NULL) {
03666         rberrors = giraffe_image_create(CPL_TYPE_DOUBLE, nspectra, rbsize);
03667         _rberrors = giraffe_image_get(rberrors);
03668     }
03669 
03670     switch (method) {
03671     case GIREBIN_METHOD_LINEAR:
03672         status = _giraffe_resample_linear(_rbspectra, _rberrors, abscissa,
03673                                           _exspectra, _exerrors, om_sign);
03674         break;
03675 
03676     case GIREBIN_METHOD_SPLINE:
03677         status = _giraffe_resample_spline(_rbspectra, _rberrors, abscissa,
03678                                           _exspectra, _exerrors, om_sign);
03679         break;
03680 
03681     default:
03682 
03683         /* We should never get to this point! */
03684 
03685         gi_error("Invalid rebinning method!");
03686         break;
03687     }
03688 
03689     cpl_image_delete(abscissa);
03690     abscissa = NULL;
03691 
03692     if (status != 0) {
03693         cpl_msg_error(fctid, "Error during rebinning, aborting...");
03694 
03695         cpl_matrix_delete(wavelengths);
03696         wavelengths = NULL;
03697 
03698         giraffe_image_delete(rbspectra);
03699         rbspectra = NULL;
03700 
03701         if (rberrors != NULL) {
03702             giraffe_image_delete(rberrors);
03703             rberrors = NULL;
03704         }
03705 
03706         return 3;
03707     }
03708 
03709 
03710 
03711     /*
03712      *  Add calculated image, keywords etc. to rebinned spectrum frame...
03713      */
03714 
03715     switch (scale) {
03716     case GIREBIN_SCALE_LOG:
03717         {
03718             cxsize nw = cpl_matrix_get_nrow(wavelengths);
03719 
03720             cxdouble mm2nm = log(GI_MM_TO_NM);
03721 
03722             setup.wmin = mm2nm + cpl_matrix_get(wavelengths, 0, 0);
03723             setup.wcenter = mm2nm + cpl_matrix_get(wavelengths, nw / 2, 0);
03724             setup.wmax = mm2nm + cpl_matrix_get(wavelengths, nw - 1, 0);
03725             setup.wstep  = rbstep;
03726 
03727             setup.units = "log(nm)";
03728             setup.offset = 0;
03729         }
03730         break;
03731 
03732     case GIREBIN_SCALE_LINEAR:
03733         {
03734             cxsize nw = cpl_matrix_get_nrow(wavelengths);
03735 
03736             setup.wmin = GI_MM_TO_NM * cpl_matrix_get(wavelengths, 0, 0);
03737             setup.wcenter = GI_MM_TO_NM * cpl_matrix_get(wavelengths,
03738                                                          nw / 2, 0);
03739             setup.wmax = GI_MM_TO_NM * cpl_matrix_get(wavelengths,
03740                                                       nw - 1, 0);
03741             setup.wstep  = GI_MM_TO_NM * rbstep;
03742 
03743             setup.units = "nm";
03744             setup.offset = 0;
03745         }
03746         break;
03747 
03748     default:
03749 
03750         /* We should never get here */
03751 
03752         gi_error("Invalid scaling option!");
03753         break;
03754     }
03755 
03756     cpl_matrix_delete(wavelengths);
03757     wavelengths = NULL;
03758 
03759 
03760     switch (method) {
03761     case GIREBIN_METHOD_LINEAR:
03762         setup.method = "linear";
03763         break;
03764 
03765     case GIREBIN_METHOD_SPLINE:
03766         setup.method = "spline";
03767         break;
03768 
03769     default:
03770 
03771         /* We should never get here */
03772 
03773         gi_error("Invalid rebinning method!");
03774         break;
03775     }
03776 
03777 
03778     switch (scale) {
03779     case GIREBIN_SCALE_LINEAR:
03780         setup.scale = "linear";
03781         break;
03782 
03783     case GIREBIN_SCALE_LOG:
03784         setup.scale = "logarithmic";
03785         break;
03786 
03787     default:
03788 
03789         /* We should never get here */
03790 
03791         gi_error("Invalid scaling option!");
03792         break;
03793     }
03794 
03795     switch (range) {
03796     case GIREBIN_RANGE_SETUP:
03797         setup.range = "setup";
03798         break;
03799 
03800     case GIREBIN_RANGE_COMMON:
03801         setup.range = "common";
03802         break;
03803 
03804     default:
03805 
03806         /* We should never get here */
03807 
03808         gi_error("Invalid range option!");
03809         break;
03810     }
03811 
03812 
03813     /*
03814      * Finalize resampled spectra
03815      */
03816 
03817     giraffe_error_push();
03818 
03819     properties = giraffe_image_get_properties(extraction->spectra);
03820     giraffe_image_set_properties(rbspectra, properties);
03821 
03822     if (cpl_error_get_code() != CPL_ERROR_NONE) {
03823         giraffe_image_delete(rbspectra);
03824         rbspectra = NULL;
03825 
03826         if (rberrors != NULL) {
03827             giraffe_image_delete(rberrors);
03828             rberrors = NULL;
03829         }
03830 
03831         return 4;
03832     }
03833 
03834     giraffe_error_pop();
03835 
03836     status = _giraffe_resample_update_properties(rbspectra, &setup);
03837 
03838     if (status != 0) {
03839         giraffe_image_delete(rbspectra);
03840         rbspectra = NULL;
03841 
03842         if (rberrors != NULL) {
03843             giraffe_image_delete(rberrors);
03844             rberrors = NULL;
03845         }
03846 
03847         return 4;
03848     }
03849 
03850 
03851     /*
03852      * Finalize resampled spectra errors if they are available
03853      */
03854 
03855     if (_rberrors != NULL) {
03856 
03857         giraffe_error_push();
03858 
03859         properties =  giraffe_image_get_properties(extraction->error);
03860         giraffe_image_set_properties(rberrors, properties);
03861 
03862         if (cpl_error_get_code() != CPL_ERROR_NONE) {
03863             giraffe_image_delete(rbspectra);
03864             rbspectra = NULL;
03865 
03866             if (rberrors != NULL) {
03867                 giraffe_image_delete(rberrors);
03868                 rberrors = NULL;
03869             }
03870 
03871             return 5;
03872         }
03873 
03874         giraffe_error_pop();
03875 
03876         status = _giraffe_resample_update_properties(rberrors, &setup);
03877 
03878         if (status != 0) {
03879             giraffe_image_delete(rbspectra);
03880             rbspectra = NULL;
03881 
03882             if (rberrors != NULL) {
03883                 giraffe_image_delete(rberrors);
03884                 rberrors = NULL;
03885             }
03886 
03887             return 5;
03888         }
03889 
03890     }
03891 
03892     result->spectra = rbspectra;
03893     result->errors = rberrors;
03894 
03895     return 0;
03896 
03897 }
03898 
03899 
03907 GiRange *
03908 giraffe_rebin_get_wavelength_range(GiImage *spectra, GiTable *wlsolution,
03909                                    GiTable *grating, GiTable *slitgeometry,
03910                                    cxbool common)
03911 {
03912 
03913     cxint status = 0;
03914 
03915     cxdouble min = 0.;
03916     cxdouble max = 0.;
03917 
03918     cpl_matrix *optical_model = NULL;
03919     cpl_matrix *grating_data = NULL;
03920 
03921     GiFiberPosition *positions = NULL;
03922     GiSlitGeo *subslits = NULL;
03923 
03924     GiWcalSolution *wcal = NULL;
03925 
03926     GiRange *range = NULL;
03927 
03928 
03929     if (spectra == NULL) {
03930         return NULL;
03931     }
03932 
03933     if (grating == NULL) {
03934         return NULL;
03935     }
03936 
03937     if (slitgeometry == NULL) {
03938         return NULL;
03939     }
03940 
03941 
03942     wcal = _giraffe_wcalsolution_create(wlsolution);
03943 
03944     if (wcal == NULL) {
03945         return NULL;
03946     }
03947 
03948     optical_model = _giraffe_rebin_setup_model(spectra, wcal);
03949 
03950     if (optical_model == NULL) {
03951         _giraffe_wcalsolution_delete(wcal);
03952         return NULL;
03953     }
03954 
03955     _giraffe_wcalsolution_delete(wcal);
03956 
03957     grating_data = _giraffe_rebin_setup_grating(spectra, grating,
03958                                                 wlsolution);
03959 
03960     if (grating_data == NULL) {
03961 
03962         cpl_matrix_delete(grating_data);
03963         cpl_matrix_delete(optical_model);
03964 
03965         return NULL;
03966 
03967     }
03968 
03969     positions = _giraffe_fiberposition_new();
03970     subslits = _giraffe_slitgeo_new();
03971 
03972     status = _giraffe_slitgeo_setup(slitgeometry, positions, subslits,
03973                                     FALSE);
03974 
03975     if (status != 0) {
03976 
03977         _giraffe_slitgeo_delete(subslits);
03978         _giraffe_fiberposition_delete(positions);
03979 
03980         cpl_matrix_delete(grating_data);
03981         cpl_matrix_delete(optical_model);
03982 
03983         return NULL;
03984 
03985     }
03986 
03987     status = giraffe_rebin_compute_lambda_range(positions, optical_model,
03988                                                 grating_data,
03989                                                 GIREBIN_SCALE_LINEAR,
03990                                                 common, &min, &max);
03991 
03992     /*
03993      * Convert wavelength from millimeters to nanometers.
03994      */
03995 
03996     min *= GI_MM_TO_NM;
03997     max *= GI_MM_TO_NM;
03998 
03999     _giraffe_slitgeo_delete(subslits);
04000     _giraffe_fiberposition_delete(positions);
04001 
04002     cpl_matrix_delete(grating_data);
04003     cpl_matrix_delete(optical_model);
04004 
04005     range = giraffe_range_create(min, max);
04006 
04007     return range;
04008 
04009 }
04010 
04011 
04045 cxint
04046 giraffe_rebin_spectra(GiRebinning *rebinning,
04047                       const GiExtraction *extraction,
04048                       const GiTable *fibers,
04049                       const GiLocalization *localization,
04050                       const GiTable *grating,
04051                       const GiTable *slitgeo,
04052                       const GiTable *solution,
04053                       const GiRebinConfig *config)
04054 {
04055 
04056     const cxchar* const fctid = "giraffe_rebin_spectra";
04057 
04058 
04059     cxint status = 0;
04060     cxint ex_sp_extr_pixels = 0;
04061     cxint calc_rebinned_size = 0;
04062     cxint default_rebinned_size = GIREBIN_SIZE_Y_DEFAULT;
04063 
04064     cxdouble rbin_multiplier = 0.;
04065     cxdouble ex_sp_pixsize_x = 0.;
04066     cxdouble rbin_stepsize = 0.;
04067 
04068     cpl_matrix* grat_params    = NULL;
04069     cpl_matrix* opt_mod_params = NULL;
04070     cpl_matrix* wloffsets      = NULL;
04071 
04072     cpl_table* _fibers = NULL;
04073 
04074     cpl_propertylist* _pl_ext_sp = NULL;
04075     cpl_propertylist* _pl_wsol   = NULL;
04076 
04077     GiImage* ex_sp_frame = NULL;
04078     GiImage* ex_sp_err_frame = NULL;
04079     GiImage* loc_y_frame = NULL;
04080     GiImage* loc_w_frame = NULL;
04081 
04082     GiSlitGeo* subslit_fibers = NULL;
04083     GiSlitGeo* wav_coeffs = NULL;
04084     GiSlitGeo* wav_limits = NULL;
04085 
04086     GiGrat* grating_data = NULL;
04087 
04088     GiFiberPosition* fiber_slit_position  = NULL;
04089 
04090     GiWcalSolution* wcalib_solution = NULL;
04091 
04092     GiBinnParams xres_polynom_deg = {0, 0};
04093 
04094 
04095 
04096     /*
04097      * Preprocessing
04098      */
04099 
04100     if (extraction == NULL) {
04101         cpl_msg_error(fctid, "No extracted data, aborting...");
04102         return 1;
04103     }
04104 
04105     if (extraction->spectra == NULL) {
04106         cpl_msg_error(fctid, "No extracted spectra, aborting...");
04107         return 1;
04108     }
04109 
04110     if (fibers == NULL) {
04111         cpl_msg_error(fctid, "No fiber table, aborting ...");
04112         return 1;
04113     }
04114 
04115     if (localization == NULL) {
04116         cpl_msg_error(fctid, "No localization data, aborting...");
04117         return 1;
04118     }
04119 
04120     if (localization->locy == NULL) {
04121         cpl_msg_error(fctid, "No localization centroids, aborting...");
04122         return 1;
04123     }
04124 
04125     if (localization->locw == NULL) {
04126         cpl_msg_error(fctid, "No localization widths, aborting...");
04127         return 1;
04128     }
04129 
04130     if (grating == NULL) {
04131         cpl_msg_error(fctid, "No grating data, aborting...");
04132         return 1;
04133     }
04134 
04135     if (rebinning == NULL) {
04136         cpl_msg_error(fctid, "No rebinning results container, aborting...");
04137         return 1;
04138     }
04139 
04140     if (config == NULL) {
04141         cpl_msg_error(fctid, "No rebinning configuration data, aborting...");
04142         return 1;
04143     }
04144 
04145     if (solution == NULL) {
04146         cpl_msg_error(fctid, "No wavecalibration solution, aborting...");
04147         return 1;
04148     }
04149 
04150     ex_sp_frame          = extraction->spectra;
04151     ex_sp_err_frame      = extraction->error;
04152     loc_y_frame          = localization->locy;
04153     loc_w_frame          = localization->locw;
04154 
04155     _pl_ext_sp           = giraffe_image_get_properties(ex_sp_frame);
04156     _pl_wsol             = giraffe_table_get_properties(solution);
04157 
04158 
04159     _fibers = giraffe_table_get(fibers);
04160     cx_assert(_fibers != NULL);
04161 
04162 
04163 
04164     /*
04165      * Initialization
04166      */
04167 
04168     /*
04169      *  Retrieve necessary values from FITS keywords
04170      */
04171 
04172     if (cpl_propertylist_has(_pl_ext_sp, GIALIAS_PIXSIZX) == TRUE) {
04173         ex_sp_pixsize_x = cpl_propertylist_get_double(_pl_ext_sp,
04174                                                       GIALIAS_PIXSIZX);
04175 
04176     }
04177     else {
04178         cpl_msg_error(fctid, "%s Keyword missing in Extracted Spectra "
04179                       "Frame, aborting ...", GIALIAS_PIXSIZX);
04180         return 2;
04181     }
04182 
04183 
04184     /*
04185      * Convert pixel size to microns
04186      */
04187 
04188     if (ex_sp_pixsize_x > 1.) {
04189         ex_sp_pixsize_x /= 1000.;
04190     }
04191 
04192 
04193     /*
04194      * Determine rebinning step size multiplier
04195      */
04196 
04197     if (cpl_propertylist_has(_pl_ext_sp, GIALIAS_GRATNAME) == TRUE) {
04198 
04199         const cxchar* _string = NULL;
04200 
04201         _string = cpl_propertylist_get_string(_pl_ext_sp, GIALIAS_GRATNAME);
04202 
04203         if (strncmp(_string, "LR", 2) == 0) {
04204             rbin_multiplier = 4.;
04205         }
04206         else if (strncmp(_string, "HR", 2) == 0) {
04207             rbin_multiplier = 1.;
04208         }
04209         else {
04210             rbin_multiplier = 1.;
04211         }
04212 
04213     }
04214     else {
04215         cpl_msg_error(fctid, "%s Keyword missing in Extracted Spectra Frame, "
04216                       "aborting ...", GIALIAS_GRATNAME);
04217         return 2;
04218     }
04219 
04220 
04221     /*
04222      * find number of pixel per spectrum
04223      */
04224 
04225     if (cpl_propertylist_has(_pl_ext_sp, GIALIAS_EXT_NX) == TRUE) {
04226         ex_sp_extr_pixels = cpl_propertylist_get_int(_pl_ext_sp,
04227                                                      GIALIAS_EXT_NX);
04228 
04229     }
04230     else {
04231         cpl_msg_error(fctid, "%s Keyword missing in Extracted Spectra Frame, "
04232                       "aborting ...", GIALIAS_EXT_NX);
04233         return 2;
04234     }
04235 
04236 
04237     /*
04238      *  Retrieve Grating information
04239      */
04240 
04241     grating_data = _giraffe_grating_new();
04242 
04243     status = _giraffe_grating_setup(grating, ex_sp_frame, grating_data);
04244 
04245     if (status != 0) {
04246         cpl_msg_error(fctid, "Unable to retrieve grating information, "
04247                       "aborting...");
04248         _giraffe_grating_delete(grating_data);
04249         return 3;
04250     }
04251 
04252     /*
04253      *  Retrieve Slit Geometry Information
04254      */
04255 
04256     fiber_slit_position = _giraffe_fiberposition_new();
04257     subslit_fibers = _giraffe_slitgeo_new();
04258 
04259     status = _giraffe_slitgeo_setup(slitgeo, fiber_slit_position,
04260                                     subslit_fibers, FALSE);
04261 
04262     if (status != 0) {
04263         cpl_msg_error(fctid, "Unable to retrieve slit geometry information, "
04264                       "aborting...");
04265         _giraffe_grating_delete(grating_data);
04266         _giraffe_fiberposition_delete(fiber_slit_position);
04267         _giraffe_slitgeo_delete(subslit_fibers);
04268         return 7;
04269     }
04270 
04271 
04272     wcalib_solution = _giraffe_wcalsolution_create(solution);
04273 
04274     if (wcalib_solution == NULL) {
04275         cpl_msg_error(fctid, "Cannot create wavelength solution, "
04276                       "aborting ...");
04277         _giraffe_grating_delete(grating_data);
04278         _giraffe_fiberposition_delete(fiber_slit_position);
04279         _giraffe_slitgeo_delete(subslit_fibers);
04280         return 4;
04281     }
04282 
04283     if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMFCOLL) == TRUE) {
04284         grating_data->fcoll =
04285             cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMFCOLL);
04286     }
04287 
04288     if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMGCAM) == TRUE) {
04289         grating_data->gcam =
04290             cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMGCAM);
04291     }
04292 
04293     if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMGTHETA) == TRUE) {
04294         grating_data->theta =
04295             cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMGTHETA);
04296     }
04297 
04298     if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMSDX) == TRUE) {
04299         grating_data->slitdx =
04300             cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMSDX);
04301     }
04302 
04303     if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMSDY) == TRUE) {
04304         grating_data->slitdy =
04305             cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMSDY);
04306     }
04307 
04308     if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMSPHI) == TRUE) {
04309         grating_data->slitphi =
04310             cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMSPHI);
04311     }
04312 
04313 
04314     /*
04315      * If wavelength corrections were provided, convert the wavelength
04316      * offsets from nanometers to millimeters and store them as a
04317      * matrix (nfibers x 1).
04318      */
04319 
04320     if (cpl_table_has_column(_fibers, "WLRES") != 0) {
04321 
04322         cxint fiber = 0;
04323         cxint nfibers = cpl_table_get_nrow(_fibers);
04324 
04325 
04326         wloffsets  = cpl_matrix_new(nfibers, 1);
04327 
04328         for (fiber = 0; fiber < nfibers; ++fiber) {
04329 
04330             cxdouble wloffset = cpl_table_get_double(_fibers, "WLRES",
04331                 fiber, NULL);
04332 
04333 
04334             wloffset *= -GI_NM_TO_MM;
04335             cpl_matrix_set(wloffsets, fiber, 0, wloffset);
04336 
04337         }
04338 
04339         cpl_msg_info(fctid, "Applying SIMCAL wavelength corrections ...");
04340 
04341     }
04342 
04343 
04344 
04345     /*
04346      * Processing
04347      */
04348 
04349 
04350     /*
04351      *  Determine rebinning stepsize and size in y direction after rebinning
04352      */
04353 
04354     if (config->scmethod == GIREBIN_SCALE_LOG) {
04355 
04356         cxint rebin_size;
04357 
04358         cxdouble wlenmax;
04359         cxdouble wlenmin;
04360 
04361         rebin_size = default_rebinned_size;
04362 
04363         wlenmin = log(grating_data->wlenmin / GI_MM_TO_NM);
04364         wlenmax = log(grating_data->wlenmax / GI_MM_TO_NM);
04365 
04366         if ((config->size != rebin_size) && (config->size != 0)) {
04367             rebin_size = config->size;
04368         }
04369 
04370         rbin_stepsize = (wlenmax - wlenmin) / rebin_size;
04371 
04372         calc_rebinned_size = 1 + (cxint) ((wlenmax-wlenmin)/ rbin_stepsize);
04373 
04374     }
04375     else {
04376 
04377         cxint rebin_size;
04378 
04379         cxdouble wlenmax;
04380         cxdouble wlenmin;
04381 
04382         wlenmin = grating_data->wlenmin / GI_MM_TO_NM;
04383         wlenmax = grating_data->wlenmax / GI_MM_TO_NM;
04384 
04385         rbin_stepsize = (config->lstep / GI_MM_TO_NM) * rbin_multiplier;
04386         rebin_size    = (wlenmax - wlenmin) / rbin_stepsize;
04387 
04388         if ((config->size != rebin_size) && (config->size != 0)) {
04389             rebin_size = config->size;
04390             rbin_stepsize = (wlenmax - wlenmin) / rebin_size;
04391         }
04392 
04393         calc_rebinned_size = 1 + (cxint) ((wlenmax-wlenmin) / rbin_stepsize);
04394 
04395     }
04396 
04397     /*
04398      *  Retrieve Wavecalibration Solution Physical Optical Paramters
04399      */
04400 
04401     if (wcalib_solution!=NULL) {
04402 
04403         if (wcalib_solution->opt_mod==LMRQ_XOPTMOD) {
04404 
04405             cxint    nrow;
04406             cxdouble opt_direction, fcoll, cfact;
04407 
04408             nrow = cpl_matrix_get_nrow(wcalib_solution->opt_mod_params);
04409             if (nrow==4) {
04410                 opt_direction =
04411                     cpl_matrix_get(wcalib_solution->opt_mod_params, 0, 0);
04412                 fcoll =
04413                     cpl_matrix_get(wcalib_solution->opt_mod_params, 1, 0);
04414                 cfact =
04415                     cpl_matrix_get(wcalib_solution->opt_mod_params, 2, 0);
04416 
04417                 opt_mod_params = cpl_matrix_new(4,1);
04418                 cpl_matrix_set(opt_mod_params, 0, 0,
04419                                ex_sp_extr_pixels * opt_direction);
04420                 cpl_matrix_set(opt_mod_params, 1, 0, ex_sp_pixsize_x);
04421                 cpl_matrix_set(opt_mod_params, 2, 0, fcoll);
04422                 cpl_matrix_set(opt_mod_params, 3, 0, cfact);
04423             }
04424             else {
04425                 cpl_msg_error(fctid, "Invalid number of physical optical "
04426                               "parameters, aborting...");
04427 
04428                 if (wloffsets != NULL) {
04429                     cpl_matrix_delete(wloffsets);
04430                 }
04431 
04432                 _giraffe_wcalsolution_delete(wcalib_solution);
04433                 _giraffe_grating_delete(grating_data);
04434                 _giraffe_fiberposition_delete(fiber_slit_position);
04435                 _giraffe_slitgeo_delete(subslit_fibers);
04436                 return 6;
04437             }
04438 
04439         }
04440         else if (wcalib_solution->opt_mod==LMRQ_XOPTMOD2) {
04441 
04442             cxint nrow;
04443             cxdouble opt_direction, fcoll, cfact, gtheta, slitdx,
04444                 slitdy, slitphi;
04445 
04446             nrow = cpl_matrix_get_nrow(wcalib_solution->opt_mod_params);
04447             if (nrow==7) {
04448                 opt_direction =
04449                     cpl_matrix_get(wcalib_solution->opt_mod_params, 0, 0);
04450                 fcoll   =
04451                     cpl_matrix_get(wcalib_solution->opt_mod_params, 1, 0);
04452                 cfact   =
04453                     cpl_matrix_get(wcalib_solution->opt_mod_params, 2, 0);
04454                 gtheta  =
04455                     cpl_matrix_get(wcalib_solution->opt_mod_params, 3, 0);
04456                 slitdx  =
04457                     cpl_matrix_get(wcalib_solution->opt_mod_params, 4, 0);
04458                 slitdy  =
04459                     cpl_matrix_get(wcalib_solution->opt_mod_params, 5, 0);
04460                 slitphi =
04461                     cpl_matrix_get(wcalib_solution->opt_mod_params, 6, 0);
04462 
04463                 opt_mod_params = cpl_matrix_new(7,1);
04464                 cpl_matrix_set(opt_mod_params, 0, 0,
04465                                ex_sp_extr_pixels * opt_direction);
04466                 cpl_matrix_set(opt_mod_params, 1, 0, ex_sp_pixsize_x);
04467                 cpl_matrix_set(opt_mod_params, 2, 0, fcoll);
04468                 cpl_matrix_set(opt_mod_params, 3, 0, cfact);
04469                 cpl_matrix_set(opt_mod_params, 4, 0, slitdx);
04470                 cpl_matrix_set(opt_mod_params, 5, 0, slitdy);
04471                 cpl_matrix_set(opt_mod_params, 6, 0, slitphi);
04472 
04473             }
04474             else {
04475                 cpl_msg_error(fctid, "Invalid number of physical optical "
04476                               "parameters, aborting...");
04477 
04478                 if (wloffsets != NULL) {
04479                     cpl_matrix_delete(wloffsets);
04480                 }
04481 
04482                 _giraffe_wcalsolution_delete(wcalib_solution);
04483                 _giraffe_grating_delete(grating_data);
04484                 _giraffe_fiberposition_delete(fiber_slit_position);
04485                 _giraffe_slitgeo_delete(subslit_fibers);
04486                 return 6;
04487             }
04488 
04489         }
04490         else {
04491             cpl_msg_error(fctid, "Invalid optical model, aborting...");
04492 
04493             if (wloffsets != NULL) {
04494                 cpl_matrix_delete(wloffsets);
04495             }
04496 
04497             _giraffe_wcalsolution_delete(wcalib_solution);
04498             _giraffe_grating_delete(grating_data);
04499             _giraffe_fiberposition_delete(fiber_slit_position);
04500             _giraffe_slitgeo_delete(subslit_fibers);
04501             return 5;
04502         }
04503 
04504 
04505         if (wcalib_solution->wav_coeffs != NULL) {
04506 
04507             GiSlitGeo* coeffs = wcalib_solution->wav_coeffs;
04508 
04509             xres_polynom_deg.xdeg =
04510                 cpl_matrix_get_nrow(_giraffe_slitgeo_get(coeffs, 0));
04511             xres_polynom_deg.ydeg =
04512                 cpl_matrix_get_ncol(_giraffe_slitgeo_get(coeffs, 0));
04513         }
04514 
04515     }
04516     else {
04517         cpl_msg_error(fctid, "No Wavelength Calibration solution found, "
04518                       "aborting...");
04519 
04520         if (wloffsets != NULL) {
04521             cpl_matrix_delete(wloffsets);
04522         }
04523 
04524         _giraffe_wcalsolution_delete(wcalib_solution);
04525         _giraffe_grating_delete(grating_data);
04526         _giraffe_fiberposition_delete(fiber_slit_position);
04527         _giraffe_slitgeo_delete(subslit_fibers);
04528         return 4;
04529     }
04530 
04531     if (config->xresiduals==FALSE) {
04532         xres_polynom_deg.xdeg = 0;
04533         xres_polynom_deg.ydeg = 0;
04534     }
04535 
04536     if (wcalib_solution->wav_coeffs!=NULL) {
04537         wav_coeffs = wcalib_solution->wav_coeffs;
04538     }
04539 
04540     if (wcalib_solution->wav_limits!=NULL) {
04541         wav_limits = wcalib_solution->wav_limits;
04542     }
04543 
04544 
04545     /*
04546      *  Setup Rebinning grating parameters
04547      */
04548 
04549     grat_params = cpl_matrix_new(7,1);
04550 
04551     cpl_matrix_set(grat_params, 0, 0, grating_data->theta);
04552     cpl_matrix_set(grat_params, 1, 0, grating_data->order);
04553     cpl_matrix_set(grat_params, 2, 0, grating_data->wlenmin / GI_MM_TO_NM);
04554     cpl_matrix_set(grat_params, 3, 0, grating_data->wlen0   / GI_MM_TO_NM);
04555     cpl_matrix_set(grat_params, 4, 0, grating_data->wlenmax / GI_MM_TO_NM);
04556     cpl_matrix_set(grat_params, 5, 0, grating_data->resol);
04557     cpl_matrix_set(grat_params, 6, 0, grating_data->space );
04558 
04559 
04560     /*
04561      *  Give user some feedback...
04562      */
04563 
04564     cpl_msg_info(fctid, "Performing Rebinning of spectra, stepsize=%12.11f "
04565                  "[nm], resulting image size=%d, using x residuals : %s",
04566                  rbin_stepsize * GI_MM_TO_NM, calc_rebinned_size,
04567                  config->xresiduals ? "Yes" : "No");
04568 
04569 
04570     switch (config->rmethod) {
04571         case GIREBIN_METHOD_LINEAR:
04572             cpl_msg_info(fctid, "Rebinning method    : linear");
04573             break;
04574 
04575         case GIREBIN_METHOD_SPLINE:
04576             cpl_msg_info(fctid, "Rebinning method    : spline");
04577             break;
04578 
04579         default:
04580             cpl_msg_info(fctid, "Rebinning method    : undefined");
04581             break;
04582     }
04583 
04584     switch (config->scmethod) {
04585         case GIREBIN_SCALE_LOG:
04586             cpl_msg_info(fctid, "Scaling method      : logarithmic, "
04587                          "log(wavelength) : min,max,range=%12.6f,%12.6f,%12.6f",
04588                          log(grating_data->wlenmin / GI_MM_TO_NM),
04589                          log(grating_data->wlenmax / GI_MM_TO_NM),
04590                          log(grating_data->wlenmax / GI_MM_TO_NM) -
04591                          log(grating_data->wlenmin / GI_MM_TO_NM));
04592             break;
04593 
04594         case GIREBIN_SCALE_LINEAR:
04595             cpl_msg_info(fctid, "Scaling method      : linear, wavelength : "
04596                          "min,max,range=%12.6f,%12.6f,%12.6f",
04597                          grating_data->wlenmin / GI_MM_TO_NM,
04598                          grating_data->wlenmax / GI_MM_TO_NM,
04599                          grating_data->wlenmax - grating_data->wlenmin);
04600             break;
04601 
04602         default:
04603             cpl_msg_info(fctid, "Scaling method      : undefined");
04604             break;
04605     }
04606 
04607     switch (config->range) {
04608         case GIREBIN_RANGE_SETUP:
04609             cpl_msg_info(fctid, "Wavelength range    : Setup");
04610             break;
04611 
04612         case GIREBIN_RANGE_COMMON:
04613             cpl_msg_info(fctid, "Wavelength range    : Common");
04614             break;
04615 
04616         default:
04617             cpl_msg_info(fctid, "Wavelength range    : undefined");
04618             break;
04619     }
04620 
04621 
04622     /*
04623      * Resample the spectra to the wavelength grid
04624      */
04625 
04626     status = _giraffe_resample_spectra(rebinning, extraction,
04627                                        localization, fiber_slit_position,
04628                                        subslit_fibers, wav_limits,
04629                                        wav_coeffs, &xres_polynom_deg,
04630                                        grat_params, opt_mod_params,
04631                                        wloffsets, rbin_stepsize,
04632                                        config->rmethod, config->range,
04633                                        config->scmethod);
04634 
04635     if (status != 0) {
04636 
04637         if (wloffsets != NULL) {
04638             cpl_matrix_delete(wloffsets);
04639         }
04640 
04641         cpl_matrix_delete(opt_mod_params);
04642         cpl_matrix_delete(grat_params);
04643 
04644         _giraffe_wcalsolution_delete(wcalib_solution);
04645         _giraffe_grating_delete(grating_data);
04646         _giraffe_fiberposition_delete(fiber_slit_position);
04647         _giraffe_slitgeo_delete(subslit_fibers);
04648 
04649         return 8;
04650 
04651     }
04652 
04653 
04654     /*
04655      *  Cleanup...
04656      */
04657 
04658     if (wloffsets != NULL) {
04659         cpl_matrix_delete(wloffsets);
04660     }
04661 
04662     cpl_matrix_delete(opt_mod_params);
04663     cpl_matrix_delete(grat_params);
04664 
04665     _giraffe_wcalsolution_delete(wcalib_solution);
04666     _giraffe_grating_delete(grating_data);
04667     _giraffe_fiberposition_delete(fiber_slit_position);
04668     _giraffe_slitgeo_delete(subslit_fibers);
04669 
04670     return 0;
04671 
04672 } /* end giraffe_rebin_spectra() */
04673 
04674 
04680 
04693 GiRebinning*
04694 giraffe_rebinning_new(void)
04695 {
04696 
04697     GiRebinning *rebinn = cx_malloc(sizeof(GiRebinning));
04698 
04699     rebinn->spectra = NULL;
04700     rebinn->errors  = NULL;
04701 
04702     return rebinn;
04703 
04704 }
04705 
04722 GiRebinning*
04723 giraffe_rebinning_create(GiImage *spectra, GiImage *errors)
04724 {
04725 
04726     GiRebinning *rebin = giraffe_rebinning_new();
04727 
04728     if (spectra) {
04729         rebin->spectra = spectra;
04730     }
04731 
04732     if (errors) {
04733         rebin->errors = errors;
04734     }
04735 
04736     return rebin;
04737 
04738 }
04739 
04740 
04759 void
04760 giraffe_rebinning_delete(GiRebinning *rebinning)
04761 {
04762 
04763     if (rebinning) {
04764         cx_free(rebinning);
04765     }
04766 
04767     return;
04768 
04769 }
04770 
04771 
04787 void
04788 giraffe_rebinning_destroy(GiRebinning *rebinning)
04789 {
04790 
04791     if (rebinning) {
04792 
04793         if (rebinning->spectra) {
04794             giraffe_image_delete(rebinning->spectra);
04795             rebinning->spectra = NULL;
04796         }
04797 
04798         if (rebinning->errors) {
04799             giraffe_image_delete(rebinning->errors);
04800             rebinning->errors = NULL;
04801         }
04802 
04803         cx_free(rebinning);
04804     }
04805 
04806     return;
04807 
04808 }
04809 
04813 
04832 GiRebinConfig *
04833 giraffe_rebin_config_create(cpl_parameterlist *list)
04834 {
04835 
04836     const cxchar *fctid = "giraffe_rebin_config_create";
04837 
04838     const cxchar *s;
04839 
04840     cpl_parameter *p;
04841 
04842     GiRebinConfig *config = NULL;
04843 
04844 
04845     if (!list) {
04846         return NULL;
04847     }
04848 
04849     config = cx_calloc(1, sizeof *config);
04850 
04851 
04852     config->rmethod    = GIREBIN_METHOD_UNDEFINED;
04853     config->xresiduals = FALSE;
04854     config->lstep      = 0.0;
04855     config->scmethod   = GIREBIN_SCALE_UNDEFINED;
04856     config->size       = 0;
04857     config->range      = GIREBIN_RANGE_UNDEFINED;
04858 
04859 
04860     p = cpl_parameterlist_find(list, "giraffe.rebinning.method");
04861     s = cpl_parameter_get_string(p);
04862     if (strcmp(s, "linear")==0) {
04863         config->rmethod = GIREBIN_METHOD_LINEAR;
04864     } else if (strcmp(s, "spline")==0) {
04865         config->rmethod = GIREBIN_METHOD_SPLINE;
04866     }
04867 
04868     p = cpl_parameterlist_find(list, "giraffe.rebinning.xresiduals");
04869     config->xresiduals = cpl_parameter_get_bool(p);
04870 
04871     p = cpl_parameterlist_find(list, "giraffe.rebinning.lstep");
04872     config->lstep = cpl_parameter_get_double(p);
04873 
04874     p = cpl_parameterlist_find(list, "giraffe.rebinning.scalemethod");
04875     s = cpl_parameter_get_string(p);
04876     if (strcmp(s, "log")==0) {
04877         config->scmethod = GIREBIN_SCALE_LOG;
04878     } else if (strcmp(s, "linear")==0) {
04879         config->scmethod = GIREBIN_SCALE_LINEAR;
04880     }
04881 
04882     p = cpl_parameterlist_find(list, "giraffe.rebinning.size");
04883     config->size = cpl_parameter_get_int(p);
04884 
04885     p = cpl_parameterlist_find(list, "giraffe.rebinning.range");
04886     s = cpl_parameter_get_string(p);
04887     if (strcmp(s, "setup")==0) {
04888         config->range = GIREBIN_RANGE_SETUP;
04889     } else if (strcmp(s, "common")==0) {
04890         config->range = GIREBIN_RANGE_COMMON;
04891     }
04892 
04893     /* Validate */
04894 
04895     if (config->rmethod==GIREBIN_METHOD_UNDEFINED) {
04896         cpl_msg_info(fctid, "Invalid Rebinning method, aborting");
04897         cx_free(config);
04898         return NULL;
04899     }
04900 
04901     if (config->scmethod==GIREBIN_SCALE_UNDEFINED) {
04902         cpl_msg_info(fctid, "Invalid Rebinning scaling method, aborting");
04903         cx_free(config);
04904         return NULL;
04905     }
04906 
04907     if (config->range==GIREBIN_RANGE_UNDEFINED) {
04908         cpl_msg_info(fctid, "Invalid Rebinning range, aborting");
04909         cx_free(config);
04910         return NULL;
04911     }
04912 
04913     return config;
04914 
04915 }
04916 
04917 
04932 void
04933 giraffe_rebin_config_destroy(GiRebinConfig *config)
04934 {
04935 
04936     if (config) {
04937         cx_free(config);
04938     }
04939 
04940     return;
04941 
04942 }
04943 
04956 void
04957 giraffe_rebin_config_add(cpl_parameterlist *list)
04958 {
04959 
04960     cpl_parameter *p;
04961 
04962     if (!list) {
04963         return;
04964     }
04965 
04966     p = cpl_parameter_new_enum("giraffe.rebinning.method",
04967                                CPL_TYPE_STRING,
04968                                "Method to use : `linear' or `spline'",
04969                                "giraffe.rebinning.method",
04970                                "linear", 2, "linear", "spline");
04971     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-method");
04972     cpl_parameterlist_append(list, p);
04973 
04974     p = cpl_parameter_new_value("giraffe.rebinning.xresiduals",
04975                                 CPL_TYPE_BOOL,
04976                                 "Use x residuals during rebinning? `true'/"
04977                                 "`false'",
04978                                 "giraffe.rebinning.xresiduals",
04979                                 TRUE);
04980     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-xresid");
04981     cpl_parameterlist_append(list, p);
04982 
04983     p = cpl_parameter_new_value("giraffe.rebinning.lstep",
04984                                 CPL_TYPE_DOUBLE,
04985                                 "Lambda step size, only used if "
04986                                 "scalemethod is 'linear'",
04987                                 "giraffe.rebinning.lstep",
04988                                 0.005);
04989     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-lstep");
04990     cpl_parameterlist_append(list, p);
04991 
04992     p = cpl_parameter_new_enum("giraffe.rebinning.scalemethod",
04993                                CPL_TYPE_STRING,
04994                                "Scaling method: `log' or `linear'",
04995                                "giraffe.rebinning.scalemethod",
04996                                "linear", 2, "linear", "log");
04997     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-scmethod");
04998     cpl_parameterlist_append(list, p);
04999 
05000     p = cpl_parameter_new_value("giraffe.rebinning.size",
05001                                 CPL_TYPE_INT,
05002                                 "Size of output rebinned spectra, 0 means "
05003                                 "calculate size based on wavelength range "
05004                                 "and lambda stepsize",
05005                                 "giraffe.rebinning.size",
05006                                 0);
05007     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-size");
05008     cpl_parameterlist_append(list, p);
05009 
05010     p = cpl_parameter_new_enum("giraffe.rebinning.range",
05011                                CPL_TYPE_STRING,
05012                                "Rebinning range: `setup' or `common'",
05013                                "giraffe.rebinning.scalemethod",
05014                                "setup", 2, "setup", "common");
05015     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-range");
05016     cpl_parameterlist_append(list, p);
05017 
05018     return;
05019 
05020 }

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