GIRAFFE Pipeline Reference Manual

giwavecalib.c

00001 /* $Id: giwavecalib.c,v 1.23 2006/09/20 12:39:11 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: 2006/09/20 12:39:11 $
00024  * $Revision: 1.23 $
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 <cxstrutils.h>
00037 
00038 #include <cpl_parameter.h>
00039 #include <cpl_frameset.h>
00040 
00041 #include "gimacros.h"
00042 #include "gidebug.h"
00043 #include "gialias.h"
00044 #include "giframe.h"
00045 #include "giimage.h"
00046 #include "giimagestack.h"
00047 #include "gitable.h"
00048 #include "gimatrix.h"
00049 #include "giextraction.h"
00050 #include "gimath.h"
00051 #include "gigrating.h"
00052 #include "giutils.h"
00053 #include "giwavecalib_types.h"
00054 #include "giwavecalib.h"
00055 
00056 #define GI_ENABLE_DEBUG 1
00057 
00058 #define GIFRAME_WAVE_CALIB_FIT_XCENT  "XCENTER"
00059 #define GIFRAME_WAVE_CALIB_FIT_YCENT  "YCENTER"
00060 #define GIFRAME_WAVE_CALIB_FIT_ALFIT  "AMPLITUDE"
00061 #define GIFRAME_WAVE_CALIB_FIT_BBFIT  "BACKGROUND"
00062 #define GIFRAME_WAVE_CALIB_FIT_WDFIT  "WIDTH"
00063 #define GIFRAME_WAVE_CALIB_FIT_SDFIT  "SIGWIDTH"
00064 #define GIFRAME_WAVE_CALIB_FIT_SCFIT  "SIGCENTER"
00065 
00066 #define WAVELENGTH_TABLE_BLEND        "BLEND"
00067 #define WAVELENGTH_TABLE_SELECT       "SELECT"
00068 #define WAVELENGTH_TABLE_SORT         "SORT"
00069 #define WAVELENGTH_TABLE_COMMENT      "COMMENT"
00070 #define WAVELENGTH_TABLE_WLEN         "WLEN"
00071 #define WAVELENGTH_TABLE_WLENPIX      "WLENPIX"
00072 #define WAVELENGTH_TABLE_FLUX         "FLUX"
00073 #define WAVELENGTH_SETUP_DIVISOR      500.0
00074 
00075 
00099 /*
00100  *  @brief enum definition to for line data type
00101  */
00102 
00103 enum _GiWcalLineType_ {
00104     GIWCALLINETYPE_UNDEFINED,  /* Undefined */
00105     GIWCALLINETYPE_THARNE,     /* Use ThArNe lines */
00106     GIWCALLINETYPE_TELLURIC    /* Use telluric lines */
00107 };
00108 
00109 typedef enum _GiWcalLineType_ GiWcalLineType;
00110 
00111 
00112 /*
00113  * Structure to handle sigma clipping parameter information
00114  */
00115 
00116 struct _GiClipParams_ {
00117     cxdouble  sigma;     /* multiple of sigma threshold           */
00118     cxdouble  mfrac;     /* minimum fraction of points accepted   */
00119     cxint     niter;     /* maximum number of iterations allowed  */
00120 };
00121 
00122 typedef struct _GiClipParams_ GiClipParams;
00123 
00124 
00125 /*
00126  * Structure to handle polynomial fit parameter information
00127  */
00128 
00129 struct _GiPolyDeg_ {
00130     cxint  xdeg;     /* X degree of polynomial */
00131     cxint  ydeg;     /* Y degree of polynomial */
00132     cxint  ncoeffs;  /* Num. of coeff., i.e. (xdeg + 1) * (ydeg + 1) */
00133 };
00134 
00135 typedef struct _GiPolyDeg_ GiPolyDeg;
00136 
00137 
00178 inline static cxint
00179 _giraffe_wavelength_setup(GiTable *wavelength_table, GiGrating *grating_setup,
00180                           GiWcalConfig *wcp)
00181 {
00182 
00183     const cxchar *fctid = "_giraffe_wavelength_setup";
00184 
00185 
00186     cpl_table *ref_wtable = NULL;
00187 
00188     cxint ce_code;
00189     cxint nr_ref_wtable;
00190     cxint i;
00191     cxint j;
00192     cxint row_nulls = 0;
00193     cxint row_curr;
00194     cxint row_max;
00195     cxint tmp_select;
00196     cxint tmp_sort;
00197     cxint num_blended_lines = 0;
00198 
00199     cxdouble tmp_wlmin   = 0.0,
00200              tmp_wlmax   = 0.0,
00201              tmp_wldelta = 0.0,
00202              tmp_wlcurr  = 0.0,
00203              wldivisor   = WAVELENGTH_SETUP_DIVISOR,
00204              tmp_wlen    = 0.0,
00205              maxflux     = 0.0,
00206              tmp_flux    = 0.0;
00207 
00208     cxchar    *cn_blend    = WAVELENGTH_TABLE_BLEND,
00209               *cn_select   = WAVELENGTH_TABLE_SELECT,
00210               *cn_sort     = WAVELENGTH_TABLE_SORT,
00211               *cn_comment  = WAVELENGTH_TABLE_COMMENT,
00212               *cn_wlen     = WAVELENGTH_TABLE_WLEN,
00213               *cn_flux     = WAVELENGTH_TABLE_FLUX;
00214 
00215     cxchar    *tmp_comment;
00216 
00217 
00218     /*************************************************************************
00219                                     Preprocessing
00220     *************************************************************************/
00221 
00222     if (wavelength_table==NULL) { return 1; }
00223     if (grating_setup   ==NULL) { return 1; }
00224     if (wcp             ==NULL) { return 1; }
00225 
00226     ref_wtable    = giraffe_table_get(wavelength_table);
00227     nr_ref_wtable = cpl_table_get_nrow(ref_wtable);
00228 
00229     ce_code = cpl_table_new_column_int(ref_wtable, cn_blend);
00230     ce_code = cpl_table_new_column_int(ref_wtable, cn_select);
00231     ce_code = cpl_table_new_column_int(ref_wtable, cn_sort);
00232 
00233     ce_code =
00234         cpl_table_fill_column_int(ref_wtable,cn_blend,0,nr_ref_wtable-1,0);
00235     ce_code =
00236         cpl_table_fill_column_int(ref_wtable,cn_select,0,nr_ref_wtable-1,0);
00237     ce_code =
00238         cpl_table_fill_column_int(ref_wtable,cn_sort,0,nr_ref_wtable-1,-1);
00239 
00240     /*************************************************************************
00241                                      Processing
00242     *************************************************************************/
00243 
00244     /*
00245      *  Find wavelengths marked as blended, unknown, faint, saturated etc.
00246      *  and TAG them for removal. @see giraffe_line_elimination()
00247      */
00248 
00249     for (i=0; i<nr_ref_wtable; i++) {
00250 
00251         tmp_comment =
00252             (cxchar*)cpl_table_get_string(ref_wtable, cn_comment, i);
00253 
00254         if (strlen(cx_strstrip(tmp_comment))>3) {
00255             ce_code = cpl_table_set_int(ref_wtable, cn_blend, i, 1);
00256             num_blended_lines++;
00257         }
00258     }
00259 
00260     cpl_msg_info(
00261         fctid,
00262         "Wavelengths Catalog initially contains %d lines",
00263         nr_ref_wtable
00264     );
00265 
00266     cpl_msg_debug(
00267         fctid,
00268         "of which %d are not usable (blended etc.)",
00269         num_blended_lines
00270     );
00271 
00272     /*
00273      *  Modify wavelength range
00274      */
00275 
00276     cpl_msg_debug(
00277         fctid,
00278         "Standard wavelength range from grating data: [%f,%f]",
00279         grating_setup->wlenmin,
00280         grating_setup->wlenmax
00281     );
00282 
00283     tmp_wlmin = grating_setup->wlenmin;
00284     tmp_wlmax = grating_setup->wlenmax;
00285 
00286     if (wcp->range_wlen_min>0.0)
00287         tmp_wlmin = wcp->range_wlen_min;
00288 
00289     if (wcp->range_wlen_max>0.0)
00290         tmp_wlmax = wcp->range_wlen_max;
00291 
00292     /*
00293      *  Remove part of the wavelength range on either side...
00294      */
00295 
00296     tmp_wldelta = (tmp_wlmax-tmp_wlmin) / wldivisor;
00297 
00298     tmp_wlmin += tmp_wldelta;
00299     tmp_wlmax -= tmp_wldelta;
00300 
00301     cpl_msg_debug(fctid, "Modified Wavelength range  : [%f,%f]",
00302                          tmp_wlmin, tmp_wlmax);
00303 
00304     cpl_msg_info(fctid, "Applying wavelength range restriction [%f,%f] on Wavelength Catalog",
00305                          tmp_wlmin, tmp_wlmax);
00306 
00307     cpl_msg_debug(fctid, "Removing wavelengths outside of wavelength range "
00308                          "from Wavelength Catalog...");
00309 
00310     /*
00311      *  Restrict wavelengths to wavelength range...
00312      */
00313 
00314     for (i=0; i<nr_ref_wtable; i++) {
00315 
00316         tmp_wlcurr =
00317             cpl_table_get_double(ref_wtable, cn_wlen, i, &row_nulls );
00318 
00319         if ((tmp_wlcurr>=tmp_wlmin)&&(tmp_wlcurr<=tmp_wlmax)) {
00320             ce_code = cpl_table_set_int(ref_wtable, cn_select, i, 1);
00321         }
00322     }
00323 
00324     /*
00325      *  Remove unnecessary wavelengths
00326      *  Since we selected a set of wavelenghts in the middle
00327      *  of a larger set we will remove the unwanted ones in two
00328      *  steps to enhance performance... first the ones at the end,
00329      *  then the ones at the beginning...
00330      */
00331 
00332     row_curr = nr_ref_wtable - 1;
00333 
00334     while (row_curr >= 0) {
00335 
00336         tmp_select =
00337             cpl_table_get_int(ref_wtable, cn_select, row_curr, &row_nulls);
00338 
00339         if (tmp_select==0) {
00340             row_curr--;
00341         } else {
00342             break;
00343         }
00344     }
00345 
00346     ce_code =
00347         cpl_table_erase_segment(
00348             ref_wtable,
00349             row_curr+1,
00350             nr_ref_wtable-row_curr-1
00351         );
00352 
00353     nr_ref_wtable = cpl_table_get_nrow(ref_wtable);
00354 
00355     row_curr = 0;
00356 
00357     while (row_curr < nr_ref_wtable) {
00358 
00359         tmp_select =
00360             cpl_table_get_int(ref_wtable, cn_select, row_curr, &row_nulls);
00361 
00362         if (tmp_select==0) {
00363             row_curr++;
00364         } else {
00365             break;
00366         }
00367     }
00368 
00369     ce_code = cpl_table_erase_segment(ref_wtable, 0, row_curr);
00370 
00371     nr_ref_wtable = cpl_table_get_nrow(ref_wtable);
00372 
00373     cpl_msg_info(fctid, "Number of lines now in Wavelength Catalog : %d",
00374                         nr_ref_wtable);
00375 
00376     /*
00377      *  Reset selection column
00378      */
00379 
00380     ce_code =
00381         cpl_table_fill_column_int(
00382             ref_wtable,
00383             cn_select,
00384             0,
00385             nr_ref_wtable,
00386             0
00387         );
00388 
00389     /*
00390      *  Iterate through wavelengths and remove the ones we do not want
00391      *  according to the user specified brightness criterium
00392      */
00393 
00394     if ((wcp->bright_count>0)&&(wcp->bright_count<nr_ref_wtable)) {
00395 
00396         /*
00397          *  Use N brightest lines
00398          */
00399 
00400         cpl_msg_info(
00401             fctid,
00402             "Applying brightness criterium specified (%d brightest lines) on "
00403             "Wavelength Catalog",
00404             wcp->bright_count
00405         );
00406 
00407         for (i=0; i<wcp->bright_count; i++) {
00408 
00409             maxflux = -1.0;
00410             row_max = -1;
00411 
00412             for(j=0; j<nr_ref_wtable;j++) {
00413 
00414                 tmp_sort =
00415                     cpl_table_get_int(ref_wtable, cn_sort, j, &row_nulls);
00416 
00417                 if (tmp_sort<0) {
00418 
00419                     tmp_flux =
00420                         cpl_table_get_double(
00421                             ref_wtable,
00422                             cn_flux,
00423                             j,
00424                            &row_nulls
00425                         );
00426 
00427                     if (tmp_flux>maxflux) {
00428                         maxflux = tmp_flux;
00429                         row_max = j;
00430                     }
00431                 }
00432             }
00433 
00434             ce_code = cpl_table_set_int(ref_wtable, cn_sort,   row_max, i );
00435             ce_code = cpl_table_set_int(ref_wtable, cn_select, row_max, 1 );
00436 
00437         }
00438 
00439         /*
00440          *  Delete all but the N brightest lines
00441          */
00442 
00443         row_curr = nr_ref_wtable - 1;
00444 
00445         while (row_curr>=0) {
00446 
00447             tmp_select =
00448                 cpl_table_get_int(
00449                     ref_wtable,
00450                     cn_select,
00451                     row_curr,
00452                    &row_nulls
00453                 );
00454 
00455             if (tmp_select==0) {
00456                 ce_code = cpl_table_erase_segment(ref_wtable, row_curr, 1 );
00457             }
00458 
00459             row_curr--;
00460 
00461         }
00462 
00463         nr_ref_wtable = cpl_table_get_nrow(ref_wtable);
00464 
00465         cpl_msg_info(fctid, "Number of lines now in Wavelength Catalog : %d",
00466                         nr_ref_wtable);
00467 
00468     } else if ( (wcp->bright_threshold>0.0          ) &&
00469                 (wcp->bright_threshold!=CX_MAXDOUBLE)    ) {
00470 
00471         /*
00472          *  Use only lines with flux value above Threshold
00473          */
00474 
00475         cpl_msg_info(
00476             fctid,
00477             "Applying brightness criterium specified (flux threshold %12.6f)"
00478             " on Wavelength Catalog",
00479             wcp->bright_threshold
00480         );
00481 
00482         for (j=0; j<nr_ref_wtable;j++) {
00483 
00484             tmp_flux =
00485                 cpl_table_get_double(ref_wtable, cn_flux, j, &row_nulls);
00486 
00487             if (tmp_flux>=wcp->bright_threshold) {
00488                 ce_code = cpl_table_set_int(ref_wtable, cn_select, j, 1 );
00489             }
00490         }
00491 
00492         /*
00493          *  Delete all lines not matching threshold criterium
00494          */
00495 
00496         row_curr = nr_ref_wtable - 1;
00497 
00498         while (row_curr >= 0) {
00499 
00500             tmp_select =
00501                 cpl_table_get_int(
00502                     ref_wtable,
00503                     cn_select,
00504                     row_curr,
00505                    &row_nulls
00506                 );
00507 
00508             if (tmp_select==0) {
00509                 ce_code = cpl_table_erase_segment(ref_wtable, row_curr, 1 );
00510             }
00511 
00512             row_curr--;
00513         }
00514 
00515         nr_ref_wtable = cpl_table_get_nrow(ref_wtable);
00516 
00517         cpl_msg_info(fctid, "Number of lines now in Wavelength Catalog : %d",
00518                         nr_ref_wtable);
00519 
00520     } else {
00521 
00522         /*
00523          *  No brightness criterium given
00524          *  Should not happen!
00525          */
00526 
00527         cpl_msg_warning(fctid, "Brightness criterium: None specified");
00528     }
00529 
00530     nr_ref_wtable = cpl_table_get_nrow(ref_wtable);
00531 
00532     /*
00533      *  Redimension Wavelengths to [mm] instead of [nm]
00534      */
00535 
00536     for (j = 0; j < nr_ref_wtable; j++) {
00537 
00538         tmp_wlen = cpl_table_get_double(ref_wtable, cn_wlen, j, &row_nulls);
00539         ce_code = cpl_table_set_double(ref_wtable, cn_wlen, j,
00540                                        tmp_wlen / GI_MM_TO_NM);
00541 
00542     }
00543 
00544     return 0;
00545 
00546 }
00547 
00575 static cxint
00576 giraffe_line_elimination(
00577     GiTable  *wavelength_table,
00578     cxdouble  wlen_conf_factor,
00579     cxdouble  sep_minimum,
00580     cxdouble  flux_ratio,
00581     cxdouble  line_width
00582 ) {
00583 
00584     /*************************************************************************
00585                                      VARIABLES
00586     *************************************************************************/
00587 
00588     const cxchar *fctid = "giraffe_line_elimination";
00589 
00590     cpl_table  *ref_wtable = NULL;
00591 
00592     cxint       ce_code;
00593     cxint       nr_wtable,
00594                 i,
00595                 j,
00596                 c1,
00597                 c2,
00598                 tmp_select,
00599                 tmp_blend,
00600                 row_nulls,
00601                 row_curr,
00602                 num_rows_orig,
00603                 num_rows_remove;
00604 
00605     cxchar     *cn_select   = WAVELENGTH_TABLE_SELECT,
00606                *cn_wlen     = WAVELENGTH_TABLE_WLEN,
00607                *cn_wlenpix  = WAVELENGTH_TABLE_WLENPIX,
00608                *cn_flux     = WAVELENGTH_TABLE_FLUX,
00609                *cn_blend    = WAVELENGTH_TABLE_BLEND;
00610 
00611     cxdouble    Ix,
00612                 Lx,
00613                 Iy,
00614                 Ly,
00615                 tmp_wlcurr;
00616 
00617 
00618     /*************************************************************************
00619                                    INITIALIZATION
00620     *************************************************************************/
00621 
00622     if (wavelength_table==NULL) { return 1; }
00623 
00624     ref_wtable = giraffe_table_get(wavelength_table);
00625 
00626     ce_code    = cpl_table_new_column_double(ref_wtable, cn_wlenpix);
00627     nr_wtable  = cpl_table_get_nrow(ref_wtable);
00628 
00629     num_rows_orig = nr_wtable;
00630 
00631     /*************************************************************************
00632                                      PROCESSING
00633     *************************************************************************/
00634 
00635     cpl_msg_info(
00636         fctid,
00637         "Applying crowding criteria on %d lines in Wavelength Catalog",
00638         nr_wtable
00639     );
00640 
00641     /*
00642      *  Change wavelength to pixels
00643      *  Change selection to 0 (not selected)
00644      */
00645 
00646     for (i=0; i<nr_wtable; i++) {
00647 
00648         tmp_wlcurr =
00649             cpl_table_get_double(ref_wtable, cn_wlen, i, &row_nulls );
00650 
00651         ce_code =
00652             cpl_table_set_double(ref_wtable, cn_wlenpix, i,
00653                              tmp_wlcurr * wlen_conf_factor );
00654 
00655         ce_code = cpl_table_set_int(ref_wtable, cn_select, i, 0 );
00656 
00657     }
00658 
00659     /*
00660      *  We eliminate lines which could be misidentified
00661      *  (closer than sepMinimum * lineWidth one to each other
00662      *  and with comparable brightness)
00663      *
00664      *  for each line i with (Li,Ii):
00665      *      if any line j with (Lj,Ij) and j != i, satisfies the condition:
00666      *      abs(Li-Lj)<linewidth*sep_min and Ii<Ij*fluxRatio
00667      *      the line (Li,Ii) is removed from the list
00668      *
00669      *  ALSO remove line if it is a BLENDED line!
00670      *  @see _giraffe_wavelength_setup()
00671      */
00672 
00673     /*
00674      *  Find crowded lines
00675      */
00676 
00677     for (i=0; i<nr_wtable; i++) {
00678 
00679         Ix = 0.0;
00680         Lx = 0.0;
00681 
00682         Ix = cpl_table_get_double(ref_wtable, cn_flux,    i, &row_nulls);
00683         Lx = cpl_table_get_double(ref_wtable, cn_wlenpix, i, &row_nulls);
00684 
00685         for (j=0; j<nr_wtable; j++) {
00686 
00687             if (i!=j) {
00688 
00689                 Iy = 0.0;
00690                 Ly = 0.0;
00691 
00692                 Iy =
00693                     cpl_table_get_double(
00694                         ref_wtable,
00695                         cn_flux,
00696                         j,
00697                        &row_nulls
00698                     );
00699 
00700                 Ly =
00701                     cpl_table_get_double(
00702                         ref_wtable,
00703                         cn_wlenpix,
00704                         j,
00705                        &row_nulls
00706                     );
00707 
00708                 c1 = FALSE;
00709                 c2 = FALSE;
00710 
00711                 c1 = ( fabs(Lx-Ly) < line_width * sep_minimum );
00712                 c2 = ( Ix < ( flux_ratio * Iy ) );
00713 
00714                 if ( c1 && c2 ) {
00715                     ce_code = cpl_table_set_int(ref_wtable, cn_select, i, j);
00716                 }
00717             }
00718         }
00719     }
00720 
00721     /*
00722      *  Count lines...
00723      */
00724 
00725     row_curr = cpl_table_get_nrow(ref_wtable) - 1;
00726     num_rows_remove = 0;
00727 
00728     while (row_curr >= 0) {
00729 
00730         tmp_select = 0;
00731         tmp_blend  = 0;
00732 
00733         tmp_select =
00734             cpl_table_get_int(ref_wtable, cn_select, row_curr, &row_nulls);
00735 
00736         tmp_blend =
00737             cpl_table_get_int(ref_wtable, cn_blend,  row_curr, &row_nulls);
00738 
00739         if ((tmp_select>0)||(tmp_blend>0)) {
00740             num_rows_remove++;
00741             row_curr--;
00742         } else {
00743             row_curr--;
00744         }
00745 
00746     }
00747 
00748     if (num_rows_remove==num_rows_orig) {
00749         cpl_msg_error(fctid, "No lines left after line elimination!");
00750         return 2;
00751     }
00752 
00753     /*
00754      *  Remove crowded and blended lines...
00755      */
00756 
00757     row_curr = cpl_table_get_nrow(ref_wtable) - 1;
00758 
00759     while (row_curr >= 0) {
00760 
00761         tmp_select = 0;
00762         tmp_blend  = 0;
00763 
00764         tmp_select =
00765             cpl_table_get_int(ref_wtable, cn_select, row_curr, &row_nulls);
00766 
00767         tmp_blend =
00768             cpl_table_get_int(ref_wtable, cn_blend,  row_curr, &row_nulls);
00769 
00770         if ((tmp_select>0)||(tmp_blend>0)) {
00771             ce_code = cpl_table_erase_segment(ref_wtable, row_curr, 1);
00772             row_curr--;
00773         } else {
00774             row_curr--;
00775         }
00776     }
00777 
00778     /*
00779      *  Reset selection to 0 (not selected) for all rows
00780      */
00781 
00782     nr_wtable  = cpl_table_get_nrow(ref_wtable);
00783 
00784     cpl_table_fill_column_int(
00785         ref_wtable,
00786         cn_select,
00787         0,
00788         nr_wtable,
00789         0
00790     );
00791 
00792     cpl_msg_info(
00793         fctid,
00794         "Removed %d lines, Wavelength Catalog now contains %d lines",
00795         num_rows_orig - nr_wtable,
00796         nr_wtable
00797     );
00798 
00799     return 0;
00800 
00801 } /* end giraffe_line_elimination() */
00802 
00820 static cxint
00821 giraffe_goodlines_count(GiImageStack *lines)
00822 {
00823 
00824     const cxchar *fctid = "giraffe_goodlines_count";
00825 
00826     cpl_image *status    = NULL;
00827     cxdouble  *pd_status = NULL;
00828     cxlong     goodlines = 0L,
00829                li        = 0L,
00830                nr_pixels = 0L;
00831 
00832     if (lines==NULL) { return -1; }
00833 
00834     status = giraffe_imagestack_get(lines, LF_I_STATUS);
00835 
00836     if (status==NULL) { return -1; }
00837 
00838     pd_status = cpl_image_get_data_double(status);
00839     nr_pixels = cpl_image_get_nx(status) * cpl_image_get_ny(status);
00840 
00841     for (li=0; li<nr_pixels; li++)
00842         if (pd_status[li] > 0.0)
00843             goodlines++;
00844 
00845     cpl_msg_debug(
00846         fctid,
00847         "Valid # of Spectrum/Line Combinations now : %d",
00848         goodlines
00849     );
00850 
00851     return goodlines;
00852 
00853 } /* end giraffe_goodlines_count() */
00854 
00871 static cxint
00872 giraffe_update_wavelengths(
00873     GiImageStack  *lines_data,
00874     GiGrating     *grating_data,
00875     GiTable       *wavelengths
00876 ) {
00877 
00878     /*************************************************************************
00879                                      Variables
00880     *************************************************************************/
00881 
00882     const cxchar *fctid     = "giraffe_update_wavelengths";
00883 
00884     cxchar       *cn_wlen   = WAVELENGTH_TABLE_WLEN;
00885 
00886     cxint         dimx,
00887                   dimy,
00888                   i,
00889                   j;
00890 
00891     cxdouble     *pd_img    = NULL;
00892 
00893     cpl_table    *ref_wtable = NULL;
00894     cpl_image    *ref_wlen   = NULL;
00895 
00896     /*************************************************************************
00897                                     Initialization
00898     *************************************************************************/
00899 
00900     if (lines_data  ==NULL) { return 1; }
00901     if (grating_data==NULL) { return 1; }
00902     if (wavelengths ==NULL) { return 1; }
00903 
00904     /*************************************************************************
00905                                     Preprocessing
00906     *************************************************************************/
00907 
00908     ref_wtable = giraffe_table_get(wavelengths);
00909     ref_wlen   = giraffe_imagestack_get(lines_data, LF_I_WLEN);
00910     pd_img     = cpl_image_get_data_double(ref_wlen);
00911     dimx       = cpl_image_get_nx(ref_wlen); /* lines   */
00912     dimy       = cpl_image_get_ny(ref_wlen); /* spectra */
00913 
00914     if (cpl_table_get_nrow(ref_wtable)!=dimx) {
00915         cpl_msg_debug(
00916             fctid,
00917             "Oops mismatch in wavelength array size [%d vs. %d]",
00918             cpl_table_get_nrow(ref_wtable),
00919             dimx
00920         );
00921         return 2;
00922     }
00923 
00924     for (i=0; i<dimy; i++) {
00925         for (j=0; j<dimx; j++) {
00926             pd_img[i*dimx+j] = 1000000.0 *
00927                     cpl_table_get_double(ref_wtable, cn_wlen, j, NULL);
00928         }
00929     }
00930 
00931     return 0;
00932 
00933 } /* end giraffe_update_wavelengths() */
00934 
00935 
00960 static GiImage *
00961 giraffe_compute_pixel_abcissa_wrapper(GiImage *ext_sp_frame,
00962                                       GiTable *wavelength_table,
00963                                       GiSlitGeometry *fiber_slit_position,
00964                                       cpl_matrix *m_opt_mod_params,
00965                                       lmrq_model_id opt_mod_id)
00966 {
00967 
00968     /*************************************************************************
00969                                      VARIABLES
00970     *************************************************************************/
00971 
00972     const cxchar  *fctid = "giraffe_compute_pixel_abcissa_wrapper";
00973 
00974     GiImage       *result              = NULL;
00975 
00976     cpl_image     *tmp                 = NULL;
00977 
00978     lmrq_model     opticalModel        = lmrq_models[LMRQ_XOPTMOD2];
00979 
00980     cxint          nr_m_opt_mod_params = 0,
00981                    status              = 0,
00982                    nr_wlen             = 0,
00983                    i                   = 0,
00984                    row_nulls;
00985 
00986     cxdouble       tmp_wlen            = 0.0;
00987 
00988     cpl_matrix    *m_wavelengths       = NULL;
00989 
00990     cpl_table     *ref_wtable          = NULL;
00991 
00992     cpl_plist     *ref_presult         = NULL;
00993 
00994     cxchar        *cn_wlen             = WAVELENGTH_TABLE_WLEN;
00995 
00996     cpl_image_stats *stats             = NULL;
00997 
00998     /*************************************************************************
00999                                    INITIALIZATION
01000     *************************************************************************/
01001 
01002     if (ext_sp_frame        == NULL) { return NULL; }
01003     if (wavelength_table    == NULL) { return NULL; }
01004     if (fiber_slit_position == NULL) { return NULL; }
01005     if (m_opt_mod_params    == NULL) { return NULL; }
01006 
01007     if (opt_mod_id == LMRQ_UNDEFINED) {
01008         cpl_msg_error(fctid, "Invalid Optical model, aborting...");
01009         return NULL;
01010     }
01011 
01012     opticalModel = lmrq_models[opt_mod_id];
01013 
01014     nr_m_opt_mod_params = cpl_matrix_get_nrow(m_opt_mod_params);
01015 
01016     if (nr_m_opt_mod_params != opticalModel.nparams) {
01017         cpl_msg_error(
01018             fctid,
01019             "Invalid number of parameters, aborting..."
01020         );
01021         return NULL;
01022     }
01023 
01024     ref_wtable = giraffe_table_get(wavelength_table);
01025     nr_wlen    = cpl_table_get_nrow(ref_wtable);
01026 
01027     m_wavelengths  = cpl_matrix_new(nr_wlen,1);
01028 
01029     for (i=0; i<nr_wlen; i++) {
01030         tmp_wlen = cpl_table_get(ref_wtable, cn_wlen, i, &row_nulls);
01031         cpl_matrix_set(m_wavelengths, i, 0, tmp_wlen);
01032     }
01033 
01034     /*************************************************************************
01035                                       PROCESSING
01036     *************************************************************************/
01037 
01038     tmp = giraffe_compute_pixel_abcissa(m_wavelengths, fiber_slit_position,
01039                                         m_opt_mod_params, opticalModel);
01040 
01041     if (tmp==NULL) {
01042         cpl_msg_error(
01043             fctid,
01044             "Unable to compute pixel abcissa, aborting..."
01045         );
01046         cpl_matrix_delete(m_wavelengths);
01047         return NULL;
01048     }
01049 
01050     result = giraffe_image_new(CPL_TYPE_DOUBLE);
01051 
01052     giraffe_image_set(result, tmp);
01053 
01054     status = giraffe_image_set_properties(result,
01055                                           giraffe_image_get_properties(ext_sp_frame));
01056 
01057     ref_presult = giraffe_image_get_properties(result);
01058 
01059     stats = cpl_image_stat(tmp, CPL_STAT_MIN | CPL_STAT_MAX);
01060 
01061     status =
01062         giraffe_plist_update_double(
01063             ref_presult,
01064             GIALIAS_DATAMIN,
01065             cpl_image_stats_get_min(stats)
01066         );
01067 
01068     status =
01069         giraffe_plist_update_double(
01070             ref_presult,
01071             GIALIAS_DATAMAX,
01072             cpl_image_stats_get_max(stats)
01073         );
01074 
01075     status =
01076         giraffe_plist_update_string(
01077             ref_presult,
01078             GIALIAS_WSOL_OMNAME,
01079             lmrq_models[opt_mod_id].name
01080         );
01081 
01082     cpl_matrix_delete(m_wavelengths);
01083     cpl_image_delete(tmp);
01084     cx_free(stats);
01085 
01086     return result;
01087 
01088 } /* end giraffe_compute_pixel_abcissa_wrapper() */
01089 
01124 cpl_image *
01125 giraffe_compute_pixel_abcissa(cpl_matrix *m_wavelengths,
01126                               GiSlitGeometry *fiber_slit_position,
01127                               cpl_matrix *m_opt_mod_params,
01128                               lmrq_model lmrq_opt_mod_x)
01129 {
01130 
01131     /*************************************************************************
01132                                      VARIABLES
01133     *************************************************************************/
01134 
01135     const cxchar *fctid = "giraffe_compute_pixel_abcissa";
01136 
01137     register cxint n,
01138                    line,
01139                    nwlen,    /* number of reference lines    */
01140                    ns;       /* number of reference spectra  */
01141 
01142     cxint       nr_m_opt_mod_params = 0;
01143 
01144     cxdouble    xccd                = 0.0,
01145                *pd_xref             = NULL,
01146                *pd_m_inputs         = NULL,
01147                *pd_m_yfibre         = NULL,
01148                *pd_m_xfibre         = NULL,
01149                *pd_m_wavelengths    = NULL,
01150                *pd_m_opt_mod_params = NULL;
01151 
01152     cpl_image  *xref                = NULL;
01153 
01154     cpl_matrix *m_inputs            = NULL;
01155 
01156     /************************************************************************
01157                                    INITIALIZATION
01158     ************************************************************************/
01159 
01160     if (m_wavelengths               ==NULL) { return NULL; }
01161     if (fiber_slit_position         ==NULL) { return NULL; }
01162     if (m_opt_mod_params            ==NULL) { return NULL; }
01163 
01164     nwlen = cpl_matrix_get_nrow(m_wavelengths);
01165     ns    = cpl_matrix_get_nrow(fiber_slit_position->yf);
01166 
01167     /************************************************************************
01168                                     PREPROCESSING
01169     ************************************************************************/
01170 
01171     xref       = cpl_image_new_double(ns, nwlen, NULL, NULL);
01172     pd_xref    = cpl_image_get_data_double(xref);
01173 
01174     m_inputs    = cpl_matrix_new(lmrq_opt_mod_x.ninputs, 1);
01175     pd_m_inputs = cpl_matrix_get_data(m_inputs);
01176 
01177     pd_m_yfibre      = cpl_matrix_get_data(fiber_slit_position->yf);
01178     pd_m_xfibre      = cpl_matrix_get_data(fiber_slit_position->xf);
01179     pd_m_wavelengths = cpl_matrix_get_data(m_wavelengths);
01180 
01181     pd_m_opt_mod_params = cpl_matrix_get_data(m_opt_mod_params);
01182     nr_m_opt_mod_params = cpl_matrix_get_nrow(m_opt_mod_params);
01183 
01184     /************************************************************************
01185                                      PROCESSING
01186     ************************************************************************/
01187 
01188     for (n=0; n<ns; n++) {
01189 
01190         pd_m_inputs[2] = pd_m_yfibre[n];
01191         pd_m_inputs[1] = pd_m_xfibre[n];
01192 
01193         for (line=0; line<nwlen; line++) {
01194 
01195             pd_m_inputs[0] = pd_m_wavelengths[line];
01196 
01197             lmrq_opt_mod_x.cfunc(
01198                 pd_m_inputs,
01199                 pd_m_opt_mod_params,
01200                 NULL,
01201                &xccd,
01202                 NULL,
01203                 nr_m_opt_mod_params
01204             );
01205 
01206             pd_xref[line*ns+n] = xccd;
01207 
01208         } /* each line */
01209     } /* each spectrum */
01210 
01211     cpl_matrix_delete(m_inputs);
01212 
01213     cpl_msg_debug(
01214         fctid,
01215         "Processing completed: Returning image [x,y] = [%d,%d]",
01216         cpl_image_get_nx(xref),
01217         cpl_image_get_ny(xref)
01218     );
01219 
01220     return xref;
01221 
01222 } /* end giraffe_compute_pixel_abcissa() */
01223 
01291 static cxint
01292 giraffe_fit_opt_mod(GiImageStack *lines, cpl_matrix *wavelengths,
01293                     GiSlitGeometry *fiber_slit_position,
01294                     cpl_matrix *opt_mod_params, cpl_matrix *opt_mod_flags,
01295                     lmrq_model_id opt_mod_id, lmrq_params *fit_params,
01296                     cpl_matrix *opt_mod_fit_res)
01297 {
01298 
01299     /*************************************************************************
01300                                      VARIABLES
01301     *************************************************************************/
01302 
01303     const cxchar *fctid = "giraffe_fit_opt_mod";
01304 
01305     lmrq_model    lmrq_opt_mod = lmrq_models[LMRQ_XOPTMOD2];
01306 
01307     cxint         nlines,
01308                   ns,
01309                   nlineparams,
01310                   index_center,
01311                   index_center_sigma,
01312                   ngoodlines,
01313                   nc_m_alpha,
01314                   nc_m_x,
01315                   nr_opt_mod_params,
01316                   i,
01317                   n,
01318                   line,
01319                   niter,
01320                   k,
01321                   df,
01322                  *ia_fit_flags       = NULL;
01323 
01324     cpl_matrix   *m_x                = NULL,
01325                  *m_y                = NULL,
01326                  *m_sig              = NULL,
01327                  *m_alpha            = NULL;
01328 
01329     cxdouble     *pd_m_x             = NULL,
01330                  *pd_m_y             = NULL,
01331                  *pd_m_sig           = NULL,
01332                  *pd_m_alpha         = NULL,
01333                  *pd_opt_mod_fit_res = NULL,
01334                  *pd_m_xfibre        = NULL,
01335                  *pd_m_yfibre        = NULL,
01336                  *pd_wavelengths     = NULL,
01337                  *pd_opt_mod_params  = NULL,
01338                 **qa2imgs            = NULL,
01339                   xf,
01340                   yf,
01341                   chisq              = 0.0;
01342 
01343     cxulong       nn, ll, ndata;
01344 
01345     /*************************************************************************
01346                                    INITIALIZATION
01347     *************************************************************************/
01348 
01349     if (lines              ==NULL) { return 1; }
01350     if (wavelengths        ==NULL) { return 1; }
01351     if (fiber_slit_position==NULL) { return 1; }
01352     if (opt_mod_params     ==NULL) { return 1; }
01353     if (opt_mod_flags      ==NULL) { return 1; }
01354     if (fit_params         ==NULL) { return 1; }
01355     if (opt_mod_fit_res    ==NULL) { return 1; }
01356 
01357     nlines      = cpl_matrix_get_nrow(wavelengths);
01358     ns          = cpl_image_get_ny(giraffe_imagestack_get(lines, LF_I_STATUS));
01359     nlineparams = giraffe_imagestack_size(lines);
01360     ndata       = nlines * ns;
01361 
01362     nr_opt_mod_params = cpl_matrix_get_nrow(opt_mod_params);
01363 
01364     qa2imgs = cx_calloc(nlineparams, sizeof(cxdouble*));
01365 
01366     for (i=0;i<nlineparams;i++) {
01367         cxdouble *tmpdbl;
01368         tmpdbl = cpl_image_get_data_double(giraffe_imagestack_get(lines, i));
01369         qa2imgs[i] = tmpdbl;
01370     }
01371 
01372     lmrq_opt_mod = lmrq_models[opt_mod_id];
01373 
01374     /*************************************************************************
01375                                      PREPROCESSING
01376     *************************************************************************/
01377 
01378     cpl_msg_info(
01379         fctid,
01380         "Performing Optical Model fit of spectra/reference lines using "
01381         "'%s' model, %d spectra and %d lines",
01382         lmrq_models[opt_mod_id].name,
01383         ns,
01384         nlines
01385     );
01386 
01387     cpl_msg_debug(
01388         fctid,
01389         "Using : maxiter=%4i, maxtests=%4i, maxchisq=%12.6f",
01390         fit_params->imax,
01391         fit_params->tmax,
01392         fit_params->dchsq
01393     );
01394 
01395     if (nlineparams == LF_G_NPARAMS) {
01396         /* gaussian model */
01397         index_center       = LF_O_PARAMS + LF_G_CENTER;
01398         index_center_sigma = LF_O_PARAMS + LF_G_SCENTER;
01399     } else if (nlineparams == LF_E_NPARAMS) {
01400         /* exponential model */
01401         index_center       = LF_O_PARAMS + LF_E_CENTER;
01402         index_center_sigma = LF_O_PARAMS + LF_E_SCENTER;
01403     } else {
01404         /* unknown model */
01405         cpl_msg_error(fctid, "Unknown line model, aborting...");
01406         cx_free(qa2imgs);
01407         return 2;
01408     }
01409 
01410     /*************************************************************************
01411                                       PROCESSING
01412     *************************************************************************/
01413 
01414     m_x        = cpl_matrix_new(ndata, lmrq_opt_mod.ninputs);
01415     m_y        = cpl_matrix_new(ndata, 1);
01416     m_sig      = cpl_matrix_new(ndata, 1);
01417     m_alpha    = cpl_matrix_new(lmrq_opt_mod.nparams, lmrq_opt_mod.nparams);
01418 
01419     pd_m_x     = cpl_matrix_get_data(m_x);
01420     pd_m_y     = cpl_matrix_get_data(m_y);
01421     pd_m_sig   = cpl_matrix_get_data(m_sig);
01422     pd_m_alpha = cpl_matrix_get_data(m_alpha);
01423 
01424     nc_m_x     = cpl_matrix_get_ncol(m_x);
01425     nc_m_alpha = cpl_matrix_get_ncol(m_alpha);
01426 
01427     pd_wavelengths    = cpl_matrix_get_data(wavelengths);
01428     pd_opt_mod_params = cpl_matrix_get_data(opt_mod_params);
01429 
01430     /* allocate size for params + sigparams + niter + chisq + rsq  */
01431     cpl_matrix_resize(opt_mod_fit_res, lmrq_opt_mod.nparams * 2 + 3, 1);
01432     pd_opt_mod_fit_res = cpl_matrix_get_data(opt_mod_fit_res);
01433 
01434     /* Fills mrqnlfit() inputs matrices with good lines parameters */
01435     pd_m_xfibre = cpl_matrix_get_data(fiber_slit_position->xf);
01436     pd_m_yfibre = cpl_matrix_get_data(fiber_slit_position->yf);
01437 
01438     ngoodlines = 0;
01439 
01440     for (n = 0; n < ns; n++) {
01441 
01442         xf = pd_m_xfibre[n];
01443         yf = pd_m_yfibre[n];
01444         nn = n * nlines;
01445 
01446         for (line = 0; line < nlines; line++) {
01447 
01448             ll = nn + line;
01449 
01450             if (qa2imgs[LF_I_STATUS][ll]        <= 0.0) continue;
01451             if (qa2imgs[index_center_sigma][ll] <= 0.0) continue;
01452 
01453             pd_m_x[ngoodlines*nc_m_x]   = pd_wavelengths[line];
01454             pd_m_x[ngoodlines*nc_m_x+1] = xf;
01455             pd_m_x[ngoodlines*nc_m_x+2] = yf;
01456 
01457             pd_m_y[ngoodlines]   = qa2imgs[index_center][ll];
01458             pd_m_sig[ngoodlines] = qa2imgs[index_center_sigma][ll];
01459             ngoodlines++;
01460         }
01461     }
01462 
01463     cpl_msg_debug(
01464         fctid,
01465         "Optical Model Fit will be based on %d lines out of a possible %d",
01466         ngoodlines,
01467         ndata
01468     );
01469 
01470     /* This is the initial (reduced) size  */
01471     cpl_matrix_resize(m_x,   ngoodlines, lmrq_opt_mod.ninputs);
01472     cpl_matrix_resize(m_y,   ngoodlines, 1);
01473     cpl_matrix_resize(m_sig, ngoodlines, 1);
01474 
01475     pd_m_x     = cpl_matrix_get_data(m_x);
01476     pd_m_y     = cpl_matrix_get_data(m_y);
01477     pd_m_sig   = cpl_matrix_get_data(m_sig);
01478 
01479     /* fill fit flags based on input matrix */
01480     ia_fit_flags =
01481         (cxint*) cx_calloc(cpl_matrix_get_nrow(opt_mod_flags), sizeof(cxint));
01482 
01483     for (i=0; i<cpl_matrix_get_nrow(opt_mod_flags); i++) {
01484         if (cpl_matrix_get(opt_mod_flags, i, 0)>DOUBLE2BOOLEAN)
01485             ia_fit_flags[i] = 1;
01486         else
01487             ia_fit_flags[i] = 0;
01488     }
01489 
01490     /* fit parameters */
01491     niter =
01492         mrqnlfit(
01493             m_x,
01494             m_y,
01495             m_sig,
01496             ngoodlines,
01497             opt_mod_params,
01498             NULL,
01499             ia_fit_flags,
01500             nr_opt_mod_params,
01501             m_alpha,
01502            &chisq,
01503            *fit_params,
01504             lmrq_opt_mod.cfunc
01505         );
01506 
01507     if (niter<0) {
01508         cpl_msg_error(
01509             fctid,
01510             "Error during fit of physical optical model, aborting..."
01511         );
01512 
01513         cx_free(ia_fit_flags);
01514         cpl_matrix_delete(m_alpha);
01515         cpl_matrix_delete(m_sig);
01516         cpl_matrix_delete(m_y);
01517         cpl_matrix_delete(m_x);
01518         cx_free(qa2imgs);
01519         return 3;
01520     }
01521 
01522     /*
01523      * Returned optical model parameters:
01524      * [fitNx,fitPxsize,fitFcoll,fitCfact,fitGtheta,fitGorder,fitGspace,
01525      *  sigNx,sigPxsize,sigFcoll,sigCfact,sigGtheta,sigGorder,sigGspace,
01526      *  niter,chisq,rsq]
01527      */
01528 
01529     k = 0;
01530     for (i=0; i<nr_opt_mod_params; i++) {
01531         pd_opt_mod_fit_res[k+i] = pd_opt_mod_params[i];
01532     }
01533 
01534     k += nr_opt_mod_params;
01535     for (i=0; i<nr_opt_mod_params; i++) {
01536         pd_opt_mod_fit_res[k+i] = sqrt(fabs(pd_m_alpha[i * nc_m_alpha + i]));
01537         if (isnan(pd_opt_mod_fit_res[k+i]))
01538             pd_opt_mod_fit_res[k+i] = 0.0;
01539     }
01540 
01541     k += nr_opt_mod_params;
01542     pd_opt_mod_fit_res[k++] = (cxdouble) niter;
01543     pd_opt_mod_fit_res[k++] = chisq;
01544     pd_opt_mod_fit_res[k]   = r_squared(chisq, m_y, ngoodlines);
01545 
01546     /* calculate goodness of fit */
01547     df = ndata;
01548     for (i=0; i<nr_opt_mod_params; i++)
01549         df -= ia_fit_flags[i];
01550 
01551     cpl_msg_info(
01552         fctid,
01553         "Fit completed, fit statistics: iterations=%d, chisq=%12.6g, df=%d, sd=%12.6g, "
01554         "R-squared=%12.6g",
01555         niter,
01556         chisq,
01557         df,
01558         sqrt(chisq/df),
01559         r_squared(chisq, m_y, ngoodlines)
01560     );
01561 
01562     cpl_msg_debug(
01563         fctid,
01564         "Returning matrix: r,c = [%d,%d]",
01565         cpl_matrix_get_nrow(opt_mod_fit_res),
01566         cpl_matrix_get_ncol(opt_mod_fit_res)
01567     );
01568 
01569     cx_free(ia_fit_flags);
01570     cpl_matrix_delete(m_alpha);
01571     cpl_matrix_delete(m_sig);
01572     cpl_matrix_delete(m_y);
01573     cpl_matrix_delete(m_x);
01574     cx_free(qa2imgs);
01575 
01576     return 0;
01577 
01578 } /* end giraffe_fit_opt_mod() */
01579 
01601 static cxint
01602 giraffe_fit_opt_mod_wrapper(GiImageStack *lines, GiTable *wavelength_table,
01603                             GiSlitGeometry *fiber_slit_position,
01604                             cpl_matrix *opt_mod_params,
01605                             cpl_matrix *opt_mod_flags,
01606                             lmrq_params *fit_params, lmrq_model_id opt_mod_id,
01607                             cpl_matrix *opt_mod_fit_res)
01608 {
01609 
01610     /*************************************************************************
01611                                      VARIABLES
01612     *************************************************************************/
01613 
01614     const cxchar   *fctid   = "giraffe_fit_opt_mod_wrapper";
01615     const cxchar   *cn_wlen = WAVELENGTH_TABLE_WLEN;
01616 
01617     cpl_table      *ref_wtable = NULL;
01618     cpl_matrix     *lines_wlen = NULL;
01619 
01620     cxint           status,
01621                     i;
01622 
01623     cxdouble        tmp_wlen;
01624 
01625     lmrq_model      lmrq_opt_mod = lmrq_models[LMRQ_XOPTMOD2];
01626 
01627     /*************************************************************************
01628                                    INITIALIZATION
01629     *************************************************************************/
01630 
01631     if (lines                       ==NULL) { return 1; }
01632     if (wavelength_table            ==NULL) { return 1; }
01633     if (fiber_slit_position         ==NULL) { return 1; }
01634     if (opt_mod_params              ==NULL) { return 1; }
01635     if (opt_mod_flags               ==NULL) { return 1; }
01636     if (fit_params                  ==NULL) { return 1; }
01637     if (opt_mod_fit_res             ==NULL) { return 1; }
01638 
01639     if (opt_mod_id==LMRQ_UNDEFINED) {
01640         cpl_msg_error(
01641             fctid,
01642             "Invalid Optical Model, aborting..."
01643         );
01644         return 2;
01645     }
01646 
01647     lmrq_opt_mod = lmrq_models[opt_mod_id];
01648 
01649     if (cpl_matrix_get_nrow(opt_mod_params)!=lmrq_opt_mod.nparams) {
01650         cpl_msg_error(
01651             fctid,
01652             "Invalid list of optical model parameters %d [%d expected], "
01653             "aborting...",
01654             cpl_matrix_get_nrow(opt_mod_params),
01655             lmrq_opt_mod.nparams
01656         );
01657         return 3;
01658     }
01659 
01660     if (cpl_matrix_get_nrow(opt_mod_flags)!=lmrq_opt_mod.nparams) {
01661         cpl_msg_error(
01662             fctid,
01663             "Invalid list of optical model flags %d [%d expected], "
01664             "aborting...",
01665             cpl_matrix_get_nrow(opt_mod_flags),
01666             lmrq_opt_mod.nparams
01667         );
01668         return 3;
01669     }
01670 
01671     ref_wtable   = giraffe_table_get(wavelength_table);
01672 
01673     lines_wlen   = cpl_matrix_new(cpl_table_get_nrow(ref_wtable),1);
01674 
01675     for (i=0; i<cpl_table_get_nrow(ref_wtable); i++) {
01676         tmp_wlen = cpl_table_get_double(ref_wtable, cn_wlen, i, NULL);
01677         cpl_matrix_set(lines_wlen, i, 0, tmp_wlen);
01678     }
01679 
01680     /*************************************************************************
01681                                       PROCESSING
01682     *************************************************************************/
01683 
01684     status = giraffe_fit_opt_mod(lines, lines_wlen, fiber_slit_position,
01685                                  opt_mod_params, opt_mod_flags, opt_mod_id,
01686                                  fit_params, opt_mod_fit_res);
01687 
01688     if (status != 0) {
01689         cpl_matrix_delete(lines_wlen);
01690         return 6;
01691     }
01692 
01693 
01694     /*
01695      *  opt_mod_fit_res contains:
01696      *
01697      *  fitNx,   fitPxsize,   fitFcoll,   fitCfact,   fitGtheta,   fitGorder,   fitGspace,
01698      *  sigFitNx,sigFitPxsize,sigFitFcoll,sigFitCfact,sigFitGtheta,sigFitGorder,sigFitGspace,
01699      *  niter,chisq,rsq
01700      */
01701 
01702     switch ((cxint)cpl_matrix_get(opt_mod_fit_res, 2 * lmrq_opt_mod.nparams,0)) {
01703     case -1:
01704         cpl_msg_error(fctid, "singular matrix-1 in Gauss-Jordan elimination");
01705         cpl_matrix_delete(lines_wlen);
01706         return 4;
01707     case -2:
01708         cpl_msg_error(fctid, "singular matrix-2 in Gauss-Jordan elimination");
01709         cpl_matrix_delete(lines_wlen);
01710         return 4;
01711     case -3:
01712         cpl_msg_error(fctid, "not enough memory for fit");
01713         cpl_matrix_delete(lines_wlen);
01714         return 4;
01715     case -4:
01716         cpl_msg_error(fctid, "unknown error in fit");
01717         cpl_matrix_delete(lines_wlen);
01718         return 4;
01719     }
01720 
01721     if (cpl_matrix_get_nrow(opt_mod_fit_res)<3) {
01722         cpl_msg_error(fctid, "Error during Optical Model Fit, aborting...");
01723         cpl_matrix_delete(lines_wlen);
01724         return 5;
01725     }
01726 
01727     cpl_matrix_delete(lines_wlen);
01728 
01729     return 0;
01730 
01731 } /* end giraffe_fit_opt_mod_wrapper() */
01732 
01811 static GiImageStack*
01812 giraffe_fit_lines_lmrq(
01813     cpl_image   *ext_sp,
01814     cpl_image   *ext_sp_err,
01815     cpl_image   *loc_y,
01816     cpl_image   *ref_lines,
01817     cpl_matrix  *line_params,
01818     lmrq_model   lmrq_line_model,
01819     lmrq_params  fit_params
01820 ) {
01821 
01822     /*************************************************************************
01823                                      VARIABLES
01824     *************************************************************************/
01825 
01826     const cxchar *fctid        = "giraffe_fit_lines_lmrq";
01827 
01828     /* Input Parameters */
01829 
01830     cxdouble   *pd_ext_sp      = NULL,
01831                *pd_ext_sp_err  = NULL,
01832                *pd_loc_y       = NULL,
01833                *pd_ref_lines   = NULL,
01834                *pd_line_params = NULL;
01835 
01836     cxint       nc_loc_y       = 0,
01837                 nc_ext_sp_err  = 0,
01838                 spec_size      = 0, /* size of extracted spectra ny */
01839                 spec_count     = 0, /* # of extracted spectra nx    */
01840                 numreflines    = 0, /* # of reference lines ny      */
01841                 nummodelparams = 0, /* # of parameters for model    */
01842                 numlineparams  = 0; /* # of parameters for line     */
01843 
01844     /* Non linear fit inputs */
01845 
01846     cpl_matrix *mX             = NULL, /* abcissa X pixels                  */
01847                *mY             = NULL, /* ordinates X extr. spectra fluxes  */
01848                *mYs            = NULL, /* copy mYs, for sorting algorithm   */
01849                *mSig           = NULL, /* sigma X extracted spectra errors  */
01850                *mFitParams     = NULL, /* in/out matrix for fit paramters   */
01851                *mAlpha         = NULL;
01852 
01853     cxdouble   *pd_mX          = NULL,
01854                *pd_mY          = NULL,
01855                *pd_mYs         = NULL,
01856                *pd_mSig        = NULL,
01857                *pd_mFitParams  = NULL,
01858                *pd_mAlpha      = NULL;
01859 
01860     cxint       nc_mAlpha      = 0;
01861 
01862     /* FWHM/sigma ratio for a gaussian */
01863     cxdouble    log2           = log(2.0);
01864     cxdouble    fwhmRatio      = 2.0 * sqrt(2.0 * log(2.0));
01865     cxdouble    fwhmRatio2     = 8.0 * log(2.0);
01866 
01867     /* Levenberg-Marquardt parameters */
01868     cxint      *iFitflags      = NULL; /* parameters to be fitted           */
01869     cxdouble    chisq          = 0.0;
01870 
01871     /* misc variables */
01872 
01873     GiImageStack  *lines          = NULL; /* Output array of images         */
01874     cxdouble     **qa2imgs        = NULL; /* Quick access to outp. arr. img */
01875 
01876     register cxint    i, j, niter, line;
01877     register cxdouble xccd, yccd, gwidth = 0.0, gwidth2;
01878 
01879     register cxint  spec_curr    = 0, /* # of spectrum being processed      */
01880                     numfitpoints = 0, /* # points to fit                    */
01881                     numrejected  = 0, /* # of rejected lines                */
01882                     xline        = 0, /* original abcissa of line           */
01883                     lineOK       = 0, /* line OK ?                          */
01884                     lineKO       = 0, /* line KO criterium found ?          */
01885                     xmin         = 0, /* lower boundary in fit interval     */
01886                     xmax         = 0, /* upper boundary in fit interval     */
01887                     curr_pixel   = 0; /* current pixel being processed      */
01888 
01889     /*************************************************************************
01890                                    INITIALIZATION
01891     *************************************************************************/
01892 
01893     if (ext_sp     ==NULL) { return NULL; }
01894     if (ext_sp_err ==NULL) { return NULL; }
01895     if (loc_y      ==NULL) { return NULL; }
01896     if (ref_lines  ==NULL) { return NULL; }
01897     if (line_params==NULL) { return NULL; }
01898 
01899     pd_ext_sp      = cpl_image_get_data_double(ext_sp);
01900     pd_ext_sp_err  = cpl_image_get_data_double(ext_sp_err);
01901     pd_loc_y       = cpl_image_get_data_double(loc_y);
01902     pd_ref_lines   = cpl_image_get_data_double(ref_lines);
01903     pd_line_params = cpl_matrix_get_data(line_params);
01904 
01905     nc_loc_y       = cpl_image_get_nx(loc_y);
01906     nc_ext_sp_err  = cpl_image_get_nx(ext_sp_err);
01907 
01908     spec_size      = cpl_image_get_ny(ext_sp);
01909     spec_count     = cpl_image_get_nx(ext_sp);
01910 
01911     numreflines    = cpl_image_get_ny(ref_lines);
01912 
01913     nummodelparams = lmrq_line_model.nparams;
01914     numlineparams  = 2 * nummodelparams + LF_O_PARAMS;
01915 
01916     numfitpoints   = (cxint) cpl_matrix_get_data(line_params)[LP_WIDTH];
01917 
01918     /*************************************************************************
01919                                     PREPROCESSING
01920     *************************************************************************/
01921 
01922     cpl_msg_info(
01923         fctid,
01924         "Performing detection fit of spectra/reference lines using "
01925         "'%s' model, %d spectra and %d lines",
01926         lmrq_line_model.name,
01927         spec_count,
01928         numreflines
01929     );
01930 
01931     mX         = cpl_matrix_new(numfitpoints, 1);
01932     mY         = cpl_matrix_new(numfitpoints, 1);
01933     mYs        = cpl_matrix_new(numfitpoints, 1);
01934     mSig       = cpl_matrix_new(numfitpoints, 1);
01935     mFitParams = cpl_matrix_new(nummodelparams, 1);
01936     mAlpha     = cpl_matrix_new(nummodelparams, nummodelparams);
01937 
01938     /*
01939      *  Create Output Array of Images
01940      */
01941 
01942     lines = giraffe_imagestack_new(numlineparams);
01943 
01944     for (i=0; i<numlineparams; i++) {
01945         cpl_image *tmpimg  = NULL;
01946         tmpimg  = cpl_image_new_double(numreflines, spec_count, NULL, NULL);
01947         giraffe_imagestack_set(lines, i, tmpimg);
01948     }
01949 
01950     /*
01951      *  Create Quick Access to Output Array of Images
01952      */
01953 
01954     qa2imgs = cx_calloc(numlineparams, sizeof(cxdouble*));
01955 
01956     for (i=0;i<numlineparams;i++) {
01957         cxdouble *tmpdbl;
01958         tmpdbl = cpl_image_get_data_double(giraffe_imagestack_get(lines, i));
01959         qa2imgs[i] = tmpdbl;
01960     }
01961 
01962     /*
01963      *  Create and initialize fit_flags so all parameters are fitted
01964      */
01965 
01966     iFitflags = (cxint *) cx_calloc(nummodelparams, sizeof(cxint));
01967     for (i=0; i<nummodelparams; i++) {
01968         iFitflags[i] = 1;
01969     }
01970 
01971     /*************************************************************************
01972                                      PROCESSING
01973     *************************************************************************/
01974 
01975     curr_pixel = 0;
01976 
01977     for (spec_curr = 0; spec_curr < spec_count; spec_curr++) {
01978 
01979         for (line = 0; line < numreflines; line++) {
01980 
01981             cpl_matrix_resize(mX,   (cxint)pd_line_params[LP_WIDTH], 1);
01982             cpl_matrix_resize(mY,   (cxint)pd_line_params[LP_WIDTH], 1);
01983             cpl_matrix_resize(mYs,  (cxint)pd_line_params[LP_WIDTH], 1);
01984             cpl_matrix_resize(mSig, (cxint)pd_line_params[LP_WIDTH], 1);
01985 
01986             giraffe_matrix_clear(mX);
01987             giraffe_matrix_clear(mY);
01988             giraffe_matrix_clear(mYs);
01989             giraffe_matrix_clear(mSig);
01990 
01991             cpl_matrix_resize(mFitParams, nummodelparams, 1);
01992             cpl_matrix_fill(mFitParams, 0.0);
01993 
01994             cpl_matrix_resize(mAlpha, nummodelparams, nummodelparams);
01995             cpl_matrix_fill(mAlpha, 0.0);
01996 
01997             pd_mFitParams = cpl_matrix_get_data(mFitParams);
01998             pd_mAlpha     = cpl_matrix_get_data(mAlpha);
01999             nc_mAlpha     = cpl_matrix_get_ncol(mAlpha);
02000 
02001             lineOK        = 1; /* assume line OK */
02002             lineKO        = 0; /* assume line OK */
02003             niter         = 0;
02004             numfitpoints  = 0;
02005             chisq         = 0.0;
02006 
02007             /*
02008              *  Find line position in pixels based on localization
02009              */
02010 
02011             xccd = pd_ref_lines[line * spec_count + spec_curr];
02012 
02013             xmin = xccd;
02014             xmax = xccd;
02015             yccd = 0.0;
02016 
02017             if ((0 < xccd) && (xccd < spec_size)) {
02018 
02019                 cxint d1, d2;
02020 
02021                 /* line position is on ccd... */
02022 
02023                 /* find fit interval */
02024                 xmin = (cxint) (xccd - (pd_line_params[LP_WIDTH]/2.0) + 0.5);
02025                 xmax = (cxint) (xccd + (pd_line_params[LP_WIDTH]/2.0) + 0.5);
02026 
02027                 /* constrain fit interval to ccd */
02028                 xmin     = MAX(MIN(xmin, spec_size - 1), 0);
02029                 xmax     = MAX(MIN(xmax, spec_size - 1), 0);
02030 
02031                 numfitpoints = xmax - xmin;
02032 
02033                 cpl_matrix_resize(mX,   numfitpoints, 1);
02034                 cpl_matrix_resize(mY,   numfitpoints, 1);
02035                 cpl_matrix_resize(mYs,  numfitpoints, 1);
02036                 cpl_matrix_resize(mSig, numfitpoints, 1);
02037 
02038                 /*
02039                  * Find corresponding Y localization centroid using
02040                  * linear interpolation. Not used in computation,
02041                  * will be stored in output image stack.
02042                  */
02043 
02044                 d1 = ((cxint) floor(xccd) * nc_loc_y ) + spec_curr;
02045                 d2 = ((cxint) ceil(xccd)  * nc_loc_y ) + spec_curr;
02046 
02047                 yccd = pd_loc_y[d1];
02048                 yccd = yccd + ((pd_loc_y[d2]-yccd) * (xccd-floor(xccd)));
02049 
02050             }
02051 
02052             pd_mX   = cpl_matrix_get_data(mX);
02053             pd_mY   = cpl_matrix_get_data(mY);
02054             pd_mYs  = cpl_matrix_get_data(mYs);
02055             pd_mSig = cpl_matrix_get_data(mSig);
02056 
02057             /*
02058              *  Fill non linear fit input arrays
02059              */
02060 
02061             for (i=0; i<numfitpoints; i++) {
02062 
02063                 j = xmin + i;
02064 
02065                 /* abcissa: X pixels */
02066                 pd_mX[i]   = (cxdouble) j;
02067 
02068                 /* ordinates: X extracted spectra fluxes */
02069                 j *= spec_count;
02070                 j += spec_curr;
02071 
02072                 pd_mY[i]   = pd_ext_sp[j];
02073 
02074                 /* same, to be sorted... */
02075                 pd_mYs[i]  = pd_ext_sp[j];
02076 
02077                 /* sigma: X extracted spectra errors */
02078                 pd_mSig[i] = pd_ext_sp_err[j];
02079 
02080             }
02081 
02082             /*
02083              *  Compute inital guesses for non linear fit
02084              */
02085 
02086             if (numfitpoints<=0) {
02087 
02088                 lineKO |= LF_R_XCCD;
02089 
02090             } else if (lmrq_line_model.id == LMRQ_GAUSSUM) {
02091 
02092                 /*
02093                  *  Line Width = minwidth in lambda given by
02094                  *  grating wlen0 / grating resol / fwhm_gaussian_sigma_ratio
02095                  *  Will be the same for all spectra and X's!
02096                  */
02097 
02098                 pd_mFitParams[LMP_WID1] =
02099                     pd_line_params[LP_GRWID] / fwhmRatio;
02100 
02101                 /* Mean of two smallest amplitudes for line background */
02102                 giraffe_matrix_sort(mYs);
02103                 pd_mFitParams[LMP_BACK] = (pd_mYs[0] + pd_mYs[1]) / 2.0;
02104 
02105                 /* Window max amplitude for line amplitude */
02106                 pd_mFitParams[LMP_AMPL] = pd_mYs[numfitpoints - 1];
02107 
02108             } else if ( (lmrq_line_model.id == LMRQ_PSFEXP) ||
02109                         (lmrq_line_model.id == LMRQ_PSFEXP2)   )
02110             {
02111 
02112 
02113                 if (pd_line_params[LP_PSFEXP] >= 0.0) {
02114                     /* fixed value if positive */
02115                     pd_mFitParams[LMP_WID2] = pd_line_params[LP_PSFEXP];
02116                     iFitflags[LMP_WID2] = 0;
02117                 } else {
02118                     /* fitted value if negative */
02119                     pd_mFitParams[LMP_WID2] = -(pd_line_params[LP_PSFEXP]);
02120                     iFitflags[LMP_WID2] = 1;
02121                 }
02122 
02123                 if (lmrq_line_model.id == LMRQ_PSFEXP2) {
02124 
02125                     pd_mFitParams[LMP_WID1] =
02126                         pd_line_params[LP_GRWID] /
02127                         (2 * pow(log2, 1.0/pd_mFitParams[LMP_WID2]));
02128 
02129                 } else {
02130 
02131                     pd_mFitParams[LMP_WID1] =
02132                         pow(pd_line_params[LP_GRWID] / 2.0,
02133                             pd_mFitParams[LMP_WID2]         ) / log2;
02134 
02135                 }
02136 
02137                 /* Mean of two smallest amplitudes for line background */
02138                 giraffe_matrix_sort(mYs);
02139 
02140                 pd_mFitParams[LMP_BACK] = (pd_mYs[0] + pd_mYs[1]) / 2.0;
02141 
02142                 /* Window max amplitude for line amplitude */
02143                 pd_mFitParams[LMP_AMPL] = pd_mYs[numfitpoints - 1];
02144 
02145             }
02146 
02147             /*
02148              *  Find X coordinate of max amplitude for line center
02149              */
02150 
02151             xline = xmin;
02152             for (i = 0; i<numfitpoints; i++) {
02153                 if (pd_mY[i] >= pd_mFitParams[LMP_AMPL]) {
02154                     xline = xmin + i;
02155                     pd_mFitParams[LMP_CENT] = xline;
02156                 }
02157             }
02158 
02159             /*
02160              * Line rejection
02161              *
02162              * IF extracted spectra error at line center of this
02163              * spectrum times the global threshold is larger than the maximum
02164              * flux in the current fitting window OR
02165              * the maximum flux in the current fitting window is larger than
02166              * the global saturation level
02167              * THEN discard line
02168              */
02169 
02170             if (((pd_ext_sp_err[(cxint)pd_mFitParams[LMP_CENT]*nc_ext_sp_err+spec_curr] *
02171                    pd_line_params[LP_THRES]) >= pd_mFitParams[LMP_AMPL])   ||
02172                 (pd_mFitParams[LMP_AMPL] > pd_line_params[LP_SATLV])         )
02173             {
02174 
02175                 /* Amplitude too small or saturated */
02176                 if (lineKO == 0)
02177                     lineKO |= LF_R_AMPLI;
02178 
02179             } else if (lineKO == 0) {
02180 
02181                 /* Max amplitude -/- background for line amplitude */
02182                 pd_mFitParams[LMP_AMPL] -= pd_mFitParams[LMP_BACK];
02183 
02184                 /*
02185                  *  Initial guesses:
02186                  *  [LineAmplitude,LineCenter,lineBackground,lineWidth]
02187                  */
02188 
02189                 niter =
02190                     mrqnlfit(
02191                         mX,
02192                         mY,
02193                         mSig,
02194                         numfitpoints,
02195                         mFitParams,
02196                         NULL,
02197                         iFitflags,
02198                         nummodelparams,
02199                         mAlpha,
02200                        &chisq,
02201                         fit_params,
02202                         lmrq_line_model.cfunc
02203                     );
02204 
02205                 if (lmrq_line_model.id == LMRQ_PSFEXP) {
02206 
02207                     /* exponential width */
02208                     gwidth =
02209                         pow( pd_mFitParams[LMP_WID1] * log2,
02210                              1.0 / pd_mFitParams[LMP_WID2]
02211                         );
02212 
02213                     pd_mFitParams[LMP_WID1] = gwidth;
02214 
02215                 } else if (lmrq_line_model.id == LMRQ_PSFEXP2) {
02216 
02217                     /* exponential width */
02218                     gwidth =
02219                         pow( log2,
02220                              1.0 / pd_mFitParams[LMP_WID2]
02221                         ) * pd_mFitParams[LMP_WID1];
02222 
02223                     pd_mFitParams[LMP_WID1] = gwidth;
02224 
02225                 } else if (lmrq_line_model.id == LMRQ_GAUSSUM) {
02226 
02227                     /* gaussian width */
02228                     pd_mFitParams[LMP_WID1] *= fwhmRatio;
02229                     gwidth = pd_mFitParams[LMP_WID1];
02230                     pd_mAlpha[LMP_WID1 * nc_mAlpha + LMP_WID1] *= fwhmRatio2;
02231 
02232                 }
02233 
02234                 /*
02235                  *  Fitted line rejection
02236                  */
02237 
02238                 gwidth2 = gwidth / 2.0;
02239                 if (niter >= fit_params.imax) {
02240                     /* max number of iteration reached */
02241                     lineKO |= LF_R_NITER;
02242                 }
02243                 if ( (xmin > pd_mFitParams[LMP_CENT]) ||
02244                      (pd_mFitParams[LMP_CENT] > xmax)    )
02245                 {
02246                     /* line center out of window */
02247                     lineKO |= LF_R_CENTR;
02248                 }
02249                 if (gwidth > (xmax - xmin)) {
02250                     /* line width larger than window */
02251                     lineKO |= LF_R_WIDTH;
02252                 }
02253                 if ((pd_mFitParams[LMP_CENT] - gwidth2) < xmin) {
02254                     /* line out of window (leftside) */
02255                     lineKO |= LF_R_LEFT;
02256                 }
02257                 if ((pd_mFitParams[LMP_CENT] + gwidth2) > xmax) {
02258                     /* line out of window (rightside) */
02259                     lineKO |= LF_R_RIGHT;
02260                 }
02261                 if (fabs(pd_mFitParams[LMP_CENT] - xline) >=
02262                     pd_line_params[LP_OFFST]                  )
02263                 {
02264                     /* maximum too far from original guess */
02265                     lineKO |= LF_R_OFFST;
02266                 }
02267                 if (gwidth < (pd_line_params[LP_GRWID] *
02268                     pd_line_params[LP_WFACT])
02269                 ) {
02270                     /* width too small for resolution */
02271                     lineKO |= LF_R_RESOL;
02272                 }
02273                 if (gwidth > (pd_line_params[LP_GRWID] /
02274                     pd_line_params[LP_WFACT])
02275                 ) {
02276                     /* width too large for resolution */
02277                     lineKO |= LF_R_RESOL;
02278                 }
02279                 if (niter <= 0) {
02280                     /* error in fit */
02281                     lineKO |= LF_R_ERROR;
02282                 }
02283 
02284             }   /* Line rejection */
02285 
02286             if (lineKO != 0) {
02287                 lineOK = -lineKO;
02288                 numrejected++;
02289             }
02290 
02291             /*
02292              *  Copy values to output struct
02293              *
02294              *  Lines parameters:
02295              *  [lineStatus,niter,chisq,rsq,xccd,yccd,
02296              *   fitAmpl,fitCenter,fitBackg,fitWidth,....
02297              *   sigAmpl,sigCenter,sigBackg,sigWidth,....]
02298              */
02299 
02300             /* first model independent parameters... */
02301             qa2imgs[LF_I_STATUS][curr_pixel] =
02302                 (cxdouble) lineOK;
02303             qa2imgs[LF_I_NITER][curr_pixel]  =
02304                 (cxdouble) niter;
02305             qa2imgs[LF_I_CHISQ][curr_pixel]  =
02306                 chisq;
02307             qa2imgs[LF_I_RSQ][curr_pixel]    =
02308                 r_squared(chisq, mY, numfitpoints);
02309             qa2imgs[LF_I_XCCD][curr_pixel]   =
02310                 xccd;
02311             qa2imgs[LF_I_YCCD][curr_pixel]   =
02312                 yccd;
02313 
02314             /* ...then model dependent parameters */
02315             for (i = 0; i < nummodelparams; i++) {
02316                 qa2imgs[i+LF_O_PARAMS][curr_pixel] = pd_mFitParams[i];
02317             }
02318 
02319             /* ...now write sigma's of the model dependent parameters */
02320             for (i = 0; i < nummodelparams; i++) {
02321                 qa2imgs[i+nummodelparams+LF_O_PARAMS][curr_pixel] =
02322                     sqrt(fabs(pd_mAlpha[i * nc_mAlpha + i]));
02323 
02324                 if (isnan(qa2imgs[i+nummodelparams+LF_O_PARAMS][curr_pixel]))
02325                     qa2imgs[i+nummodelparams+LF_O_PARAMS][curr_pixel] = 0.0;
02326 
02327             }
02328 
02329             curr_pixel++;
02330 
02331         } /* for (line = 0; line < numreflines; line++) */
02332     } /* for (spec_curr = 0; spec_curr < spec_count; spec_curr++) */
02333 
02334     cx_free(iFitflags);
02335     cx_free(qa2imgs);
02336     cpl_matrix_delete(mAlpha);
02337     cpl_matrix_delete(mFitParams);
02338     cpl_matrix_delete(mSig);
02339     cpl_matrix_delete(mYs);
02340     cpl_matrix_delete(mY);
02341     cpl_matrix_delete(mX);
02342 
02343     cpl_msg_info(
02344         fctid,
02345         "Fit completed, Spectra/Lines Combinations : good/rejected/total = %d/%d/%d",
02346         spec_count * numreflines - numrejected,
02347         numrejected,
02348         spec_count * numreflines
02349     );
02350 
02351     cpl_msg_debug(
02352         fctid,
02353         "Processing completed: Returning image array [x,y] = [%d,%d]",
02354         numreflines,
02355         spec_count
02356     );
02357 
02358     return lines;
02359 
02360 } /* end giraffe_fit_lines_lmrq() */
02361 
02387 static GiImageStack*
02388 giraffe_fit_lines_lmrq_wrapper(
02389     GiImage       *ext_sp_frame,
02390     GiImage       *ext_sp_err_frame,
02391     GiImage       *locy_frame,
02392     GiImage       *ref_line_frame,
02393     cpl_matrix    *lines_params,
02394     lmrq_params    fit_params,
02395     lmrq_model_id  line_mod_id
02396 ) {
02397 
02398     /*************************************************************************
02399                                      VARIABLES
02400     *************************************************************************/
02401 
02402     const cxchar  *fctid = "giraffe_fit_lines_lmrq_wrapper";
02403 
02404     cxint          tsize = 0;
02405 
02406     lmrq_model     lmrq_line_model = lmrq_models[LMRQ_PSFEXP];
02407 
02408     GiImageStack  *result = NULL;
02409 
02410     /*************************************************************************
02411                                    INITIALIZATION
02412     *************************************************************************/
02413 
02414     if (ext_sp_frame    ==NULL) { return NULL; }
02415     if (ext_sp_err_frame==NULL) { return NULL; }
02416     if (locy_frame      ==NULL) { return NULL; }
02417     if (ref_line_frame  ==NULL) { return NULL; }
02418     if (lines_params    ==NULL) { return NULL; }
02419 
02420     if (line_mod_id == LMRQ_UNDEFINED) {
02421         cpl_msg_error(fctid, "Invalid Line Model, aborting...");
02422         return NULL;
02423     }
02424 
02425     lmrq_line_model = lmrq_models[line_mod_id];
02426 
02427     tsize = cpl_matrix_get_nrow(lines_params);
02428 
02429     if ((lmrq_line_model.id == LMRQ_PSFEXP) ||
02430         (lmrq_line_model.id == LMRQ_PSFEXP2)   )
02431     {
02432         if (LP_E_NPRMS != tsize) {
02433             cpl_msg_error(
02434                 fctid,
02435                 "Invalid number of line parameters for PSF EXP, aborting..."
02436             );
02437             return NULL;
02438         }
02439     } else {
02440         /* gausssum model */
02441         if (LP_G_NPRMS != tsize) {
02442             cpl_msg_error(
02443                 fctid,
02444                 "Invalid number of line parameters for PSF GAUSS, aborting..."
02445             );
02446             return NULL;
02447         }
02448     }
02449 
02450     /*************************************************************************
02451                                       PROCESSING
02452     *************************************************************************/
02453 
02454     result =
02455         giraffe_fit_lines_lmrq(
02456             giraffe_image_get(ext_sp_frame),
02457             giraffe_image_get(ext_sp_err_frame),
02458             giraffe_image_get(locy_frame),
02459             giraffe_image_get(ref_line_frame),
02460             lines_params,
02461             lmrq_line_model,
02462             fit_params
02463         );
02464 
02465     return result;
02466 
02467 }
02468 
02515 static cxint
02516 giraffe_fit_x_optm_residuals(
02517     GiLocPosition   loc_pos,
02518     GiImageStack   *lines,
02519     GiSlitGeometry *slit_geo,
02520     GiPolyDeg       xor_poly_params,
02521     GiClipParams    xor_clip_params,
02522     cpl_image      *xor_fit,
02523     GiSlitGeometry *xor_coeff
02524 
02525 ) {
02526 
02527     /*************************************************************************
02528                                      VARIABLES
02529     *************************************************************************/
02530 
02531     const cxchar *fctid = "giraffe_fit_x_optm_residuals";
02532 
02533     cpl_matrix   *m_ss = NULL,
02534                  *xss  = NULL,
02535                  *yss  = NULL,
02536                  *rss  = NULL,
02537                  *sss  = NULL,
02538                  *nss  = NULL,
02539                  *mss  = NULL,
02540                  *base = NULL,
02541                  *cheb = NULL,
02542                  *fit  = NULL;
02543 
02544     cxdouble     *pd_m_ss,
02545                  *pd_xss,
02546                  *pd_yss,
02547                  *pd_rss,
02548                  *pd_sss,
02549                  *pd_nss,
02550                  *pd_mss,
02551                  *pd_m_y,
02552                  *pd_m_w,
02553                  *pd_fit,
02554                  *pd_xor_fit,
02555                 **qa2imgs    = NULL,
02556                   medsss,
02557                  *buffer     = NULL;
02558 
02559     cxint         nlineparams,
02560                   nc_fit,
02561                   nr_fit,
02562                   nr_mss,
02563                   nc_rss,
02564                   i,
02565                   nlines,
02566                   index_center,
02567                   index_center_sigma;
02568 
02569     register cxint    subslit, nfibers, n, nn, nx, ns, nmin, nmax, ndata,
02570                       nlen, ngoodlines;
02571     register cxint    k, l, ll, m, x, xx, nlines_accepted, nlines_total, niter;
02572     register cxdouble ymin, ymax, y_upper, y_lower, nlines_ratio;
02573 
02574     /*************************************************************************
02575                                    INITIALIZATION
02576     *************************************************************************/
02577 
02578     if (lines    ==NULL) { return -1; }
02579     if (slit_geo ==NULL) { return -1; }
02580     if (xor_fit  ==NULL) { return -1; }
02581     if (xor_coeff==NULL) { return -1; }
02582 
02583     nlineparams = giraffe_imagestack_size(lines);
02584     nlines      = cpl_image_get_nx(giraffe_imagestack_get(lines, LF_I_STATUS));
02585 
02586     nx = cpl_image_get_ny(loc_pos.centroids); /* size of spectra */
02587     ns = cpl_image_get_nx(loc_pos.centroids); /* number of spectra */
02588 
02589     qa2imgs = (cxdouble**) cx_calloc(nlineparams, sizeof(cxdouble*));
02590 
02591     for (i=0;i<nlineparams;i++) {
02592         cxdouble *tmpdbl;
02593         tmpdbl = cpl_image_get_data_double(giraffe_imagestack_get(lines, i));
02594         qa2imgs[i] = tmpdbl;
02595     }
02596 
02597     /*************************************************************************
02598                                       PROCESSING
02599     *************************************************************************/
02600 
02601     cpl_msg_info(
02602         fctid,
02603         "Performing X Optical Residuals fit of spectra/reference wavelengths using "
02604         "'%s' model, %d spectra and %d lines",
02605         nlineparams == LF_G_NPARAMS ? "Gaussian" : "Exponential",
02606         ns,
02607         nlines
02608     );
02609 
02610     cpl_msg_debug(
02611         fctid,
02612         "Using : Chebyshev polynomial (%d,%d), Sigma Clipping : sigma=%4.1f, niter=%4i, mfrac=%4.2f",
02613         xor_poly_params.xdeg,
02614         xor_poly_params.ydeg,
02615         xor_clip_params.sigma,
02616         xor_clip_params.niter,
02617         xor_clip_params.mfrac
02618     );
02619 
02620     if (nlineparams == LF_G_NPARAMS) {
02621         /* gaussian model */
02622         index_center       = LF_O_PARAMS + LF_G_CENTER;
02623         index_center_sigma = LF_O_PARAMS + LF_G_SCENTER;
02624     } else if (nlineparams == LF_E_NPARAMS) {
02625         /* exponential model */
02626         index_center       = LF_O_PARAMS + LF_E_CENTER;
02627         index_center_sigma = LF_O_PARAMS + LF_E_SCENTER;
02628     } else {
02629         cpl_msg_error(fctid, "Unknown line model, aborting...." );
02630         cx_free(qa2imgs);
02631         return -2;
02632     }
02633 
02634     ngoodlines = 0;
02635 
02636     for (subslit = 0; subslit<giraffe_slitgeometry_size(slit_geo); subslit++) {
02637 
02638         m_ss    = giraffe_slitgeometry_get(slit_geo, subslit);
02639         pd_m_ss = cpl_matrix_get_data(m_ss);
02640 
02641         giraffe_matrix_sort(m_ss);
02642 
02643         giraffe_slitgeometry_set(xor_coeff, subslit, NULL);
02644 
02645         /* Get spectra/fibers range for current subslit */
02646         nfibers = cpl_matrix_get_nrow(m_ss);
02647 
02648         nmin = (cxint) pd_m_ss[0];
02649         nmax = (cxint) pd_m_ss[nfibers - 1];
02650 
02651         nlen = nmax - nmin + 1;
02652         ymax = 0.0;
02653         ymin = CX_MAXDOUBLE;   /* has to be smaller than this */
02654 
02655         cpl_msg_debug(fctid, "Slit geometry : nmin, nmax = [%d,%d], "
02656                       "#spectra=%d", nmin, nmax, ns);
02657 
02658         pd_m_y = cpl_image_get_data_double(loc_pos.centroids);
02659         pd_m_w = cpl_image_get_data_double(loc_pos.widths);
02660 
02661         /* Get y range for current subslit */
02662         for (k = 0, n = nmin; n <= nmax; n++, k++) {
02663             for (x = 0; x < nx; x++) {
02664                 xx = x * ns + n;
02665                 y_upper = pd_m_y[xx] + pd_m_w[xx];
02666                 y_lower = pd_m_y[xx] - pd_m_w[xx];
02667                 if (ymax<y_upper) ymax = y_upper;
02668                 if (ymin>y_lower) ymin = y_lower;
02669             }
02670         }
02671 
02672         /* allocate space for all lines of specified spectra */
02673         ndata = nlines * nlen;
02674 
02675         xss = cpl_matrix_new(ndata, 1); /* X abcissas for current subslit  */
02676         yss = cpl_matrix_new(ndata, 1); /* Y ordinates                     */
02677         rss = cpl_matrix_new(1, ndata); /* X Residuals (transposed)        */
02678         sss = cpl_matrix_new(ndata, 1); /* X Residuals sigmas              */
02679         nss = cpl_matrix_new(ndata, 1); /* good lines indices              */
02680 
02681         pd_xss = cpl_matrix_get_data(xss);
02682         pd_yss = cpl_matrix_get_data(yss);
02683         pd_rss = cpl_matrix_get_data(rss);
02684         pd_sss = cpl_matrix_get_data(sss);
02685         pd_nss = cpl_matrix_get_data(nss);
02686 
02687         /*
02688          * Fills inputs matrices with good lines xccd, yccd, width,
02689          * width sigmas and line status
02690          *
02691          * assumes lines are along xaxis and spectra along y
02692          */
02693 
02694         for (k = 0, m = 0, n = nmin; n <= nmax; n++, m++) {
02695             nn = n * nlines;
02696             for (l = 0; l < nlines; l++) {
02697                 ll = l + nn;
02698 
02699                 if (qa2imgs[LF_I_STATUS][ll] <= 0.0) continue;
02700                 if (qa2imgs[LF_I_YCCD][ll]   > ymax) continue;
02701                 if (qa2imgs[LF_I_YCCD][ll]   < ymin) continue;
02702 
02703                 pd_xss[k] = qa2imgs[LF_I_XCCD][ll];
02704                 pd_yss[k] = qa2imgs[LF_I_YCCD][ll];
02705                 pd_rss[k] = qa2imgs[LF_I_XCCD][ll] - qa2imgs[index_center][ll];
02706                 pd_sss[k] = qa2imgs[index_center_sigma][ll];
02707                 pd_nss[k] = (cxdouble) ll;
02708                 k++;
02709             }
02710         }
02711 
02712         /*
02713          *  This is the initial (reduced) size
02714          */
02715 
02716         cpl_matrix_resize(xss, k, 1);
02717         cpl_matrix_resize(yss, k, 1);
02718         cpl_matrix_resize(rss, 1, k);
02719         cpl_matrix_resize(sss, k, 1);
02720         cpl_matrix_resize(nss, k, 1);
02721 
02722         pd_xss = cpl_matrix_get_data(xss);
02723         pd_yss = cpl_matrix_get_data(yss);
02724         pd_rss = cpl_matrix_get_data(rss);
02725         pd_sss = cpl_matrix_get_data(sss);
02726         pd_nss = cpl_matrix_get_data(nss);
02727 
02728         /*
02729          *  sigma used for clipping is the median value of sigma
02730          *  from fitted center
02731          */
02732         mss = cpl_matrix_duplicate(sss);
02733 
02734         pd_mss = cpl_matrix_get_data(mss);
02735         nr_mss = cpl_matrix_get_nrow(mss);
02736 
02737         giraffe_matrix_sort(mss);
02738 
02739         if (nr_mss & 1) {
02740             medsss = pd_mss[(nr_mss-1)/2];
02741         } else {
02742             medsss = (pd_mss[(nr_mss>>1)-1] + pd_mss[nr_mss>>1])/2.0;
02743         }
02744 
02745         /*
02746          *  Perform Sigma Clipping
02747          */
02748 
02749         nc_rss = cpl_matrix_get_ncol(rss);
02750 
02751         nlines_ratio = 1.0;
02752         nlines_total = nc_rss;
02753         nlines_accepted = nc_rss;
02754         niter = 0;
02755 
02756         while ( (nlines_accepted>0                 ) &&
02757                 (niter<xor_clip_params.niter       ) &&
02758                 (nlines_ratio>xor_clip_params.mfrac)    )
02759         {
02760 
02761             cpl_msg_debug(fctid,"Lines Accepted: %d>0, Iteration: %d<%d, "
02762                                 "Ratio: %12.6f > %12.6f",
02763                                 nlines_accepted, niter, xor_clip_params.niter,
02764                                 nlines_ratio, xor_clip_params.mfrac);
02765 
02766             base =
02767                 giraffe_chebyshev_base2d(
02768                     0.0,
02769                     ymin,
02770                     (cxdouble) nx,
02771                     (ymax - ymin + 1.0),
02772                     xor_poly_params.xdeg + 1,
02773                     xor_poly_params.ydeg + 1,
02774                     xss,
02775                     yss
02776                 );
02777 
02778             cpl_matrix_delete(cheb); cheb = NULL;
02779 
02780             cheb = giraffe_matrix_leastsq(base, rss);
02781 
02782             if (cheb==NULL) {
02783                 cpl_msg_error(
02784                     fctid,
02785                     "Error in leastsq solve subslit[%d], skipping...",
02786                     subslit
02787                 );
02788                 break;
02789             }
02790 
02791             fit    = cpl_matrix_product(cheb, base);
02792             nc_fit = cpl_matrix_get_ncol(fit);
02793             pd_fit = cpl_matrix_get_data(fit);
02794 
02795             k = 0;
02796             for (l=0; l<nc_fit; l++) {
02797                 if (fabs(pd_fit[l] - pd_rss[l]) >=
02798                     xor_clip_params.sigma * medsss   )
02799                 {
02800 
02801                     /* reject this line */
02802                     qa2imgs[LF_I_STATUS][(cxint)pd_nss[l]] =
02803                         -1.0 * (cxdouble) LF_R_XRFIT;
02804 
02805                     /* clip clip clip... */
02806                     continue;
02807                 }
02808 
02809                 /* last best hopes... */
02810                 pd_xss[k] = pd_xss[l];
02811                 pd_yss[k] = pd_yss[l];
02812                 pd_rss[k] = pd_rss[l];
02813                 pd_sss[k] = pd_sss[l];
02814                 pd_nss[k] = pd_nss[l];
02815                 k++;
02816 
02817             }
02818 
02819             cpl_matrix_delete(fit); fit = NULL;
02820             cpl_matrix_delete(base); base = NULL;
02821 
02822             /*
02823              * No new points rejected, no more iterations That
02824              * was the last turn, boy
02825              */
02826 
02827             if (k == nlines_accepted) break;
02828 
02829             /* Merry-go-round once more */
02830             nlines_accepted = k;
02831             nlines_ratio = (cxdouble) nlines_accepted / (cxdouble) nlines_total;
02832 
02833             /* This is the current (clipped) size */
02834             cpl_matrix_resize(xss, k, 1);
02835             cpl_matrix_resize(yss, k, 1);
02836             cpl_matrix_resize(rss, 1, k);
02837             cpl_matrix_resize(sss, k, 1);
02838             cpl_matrix_resize(nss, k, 1);
02839 
02840             pd_xss = cpl_matrix_get_data(xss);
02841             pd_yss = cpl_matrix_get_data(yss);
02842             pd_rss = cpl_matrix_get_data(rss);
02843             pd_sss = cpl_matrix_get_data(sss);
02844             pd_nss = cpl_matrix_get_data(nss);
02845 
02846             niter++;
02847         } /* sigma clipping ends */
02848 
02849 
02850         if (nlines_accepted==0) {
02851             cpl_msg_info(fctid, "subslit[%d]: no lines accepted", subslit);
02852             continue;
02853         }
02854 
02855         if (cheb==NULL) {
02856             cpl_msg_info(fctid, "subslit[%d]: error in least square",
02857                                 subslit);
02858             continue;
02859         }
02860 
02861         ngoodlines += nlines_accepted;
02862 
02863         cpl_matrix_delete(nss); nss = NULL;
02864         cpl_matrix_delete(sss); sss = NULL;
02865         cpl_matrix_delete(rss); rss = NULL;
02866         cpl_matrix_delete(yss); yss = NULL;
02867         cpl_matrix_delete(xss); xss = NULL;
02868 
02869         /* Compute coordinates mesh for whole subslit */
02870         xss = cpl_matrix_new(nx * nlen, 1);
02871 
02872         giraffe_compute_image_coordinates(nx, nlen, xss, NULL);
02873 
02874         yss = cpl_matrix_new(nx * nlen, 1);
02875         pd_yss = cpl_matrix_get_data(yss);
02876 
02877         for (k = 0, n = nmin; n <= nmax; n++, k++) {
02878             for (x = 0; x < nx; x++) {
02879                 pd_yss[k + x * nlen] = pd_m_y[n + x * ns];
02880             }
02881         }
02882 
02883         base =
02884             giraffe_chebyshev_base2d(
02885                 0.0,
02886                 ymin,
02887                 (cxdouble) nx,
02888                 (ymax - ymin + 1.0),
02889                 xor_poly_params.xdeg + 1,
02890                 xor_poly_params.ydeg + 1,
02891                 xss,
02892                 yss
02893             );
02894 
02895         cpl_matrix_delete(yss); yss = NULL;
02896         cpl_matrix_delete(xss); xss = NULL;
02897 
02898         fit = cpl_matrix_product(cheb, base);
02899 
02900         giraffe_slitgeometry_set(xor_coeff, subslit, cheb);
02901 
02902 
02903         cpl_msg_debug(
02904             fctid,
02905             "XResid subslit %d matrix r,c=:%d,%d",
02906             subslit,
02907             cpl_matrix_get_nrow(giraffe_slitgeometry_get(xor_coeff, subslit)),
02908             cpl_matrix_get_ncol(giraffe_slitgeometry_get(xor_coeff, subslit))
02909         );
02910 
02911         cpl_matrix_delete(base); base = NULL;
02912         cpl_matrix_delete(cheb); cheb = NULL;
02913 
02914         /* reshape fit to subslit area size */
02915 
02916         buffer = cpl_matrix_get_data(fit);
02917 
02918         cpl_matrix_delete_but_data(fit); fit = NULL;
02919         fit = cpl_matrix_new_from_data(buffer,nx, nlen);
02920 
02921         pd_fit = cpl_matrix_get_data(fit);
02922         nr_fit = cpl_matrix_get_nrow(fit);
02923         nc_fit = cpl_matrix_get_ncol(fit);
02924 
02925         pd_xor_fit = cpl_image_get_data_double(xor_fit);
02926 
02927         /* subslit fit goes into whole fit */
02928         for (x = 0; x < nr_fit; x++) {
02929             for (k = nmin, n = 0; n < nc_fit; n++, k++) {
02930                 pd_xor_fit[k + x * ns] = pd_fit[n + x * nc_fit];
02931             }
02932         }
02933 
02934         cpl_matrix_delete(fit); fit = NULL;
02935 
02936     } /* for each subslit */
02937 
02938     cpl_msg_debug(fctid, "Found %d goodlines", ngoodlines);
02939 
02940     cpl_msg_info(
02941         fctid,
02942         "Processing completed, Spectrum/Line Combinations : good/rejected/total = %d/%d/%d",
02943         ngoodlines,
02944         ns * nlines - ngoodlines,
02945         ns * nlines
02946     );
02947 
02948     cx_free(qa2imgs); qa2imgs = NULL;
02949 
02950     return ngoodlines;
02951 
02952 } /* end _giraffe_fit_x_optm_res() */
02953 
02986 static cxint
02987 giraffe_fit_x_optm_residuals_wrapper(
02988     GiImage        *locy_frame,
02989     GiImage        *locw_frame,
02990     GiImageStack   *lines,
02991     GiSlitGeometry *slit_geo,
02992     GiClipParams    xor_clip_params,
02993     GiPolyDeg       xor_poly_params,
02994     GiWcalSolution *wavcoeff,
02995     GiImage        *xor_fit_frame,
02996     GiTable        *xor_cheb_table,
02997     GiWcalConfig   *wcalib_config,
02998     GiGrating      *grating_data,
02999     cxdouble        curr_line_width
03000 ) {
03001 
03002     /*************************************************************************
03003                                      VARIABLES
03004     *************************************************************************/
03005 
03006     const cxchar    *fctid = "giraffe_fit_x_optm_residuals_wrapper";
03007 
03008     cpl_image       *opt_mod_resid  = NULL,
03009                     *_locy          = NULL,
03010                     *_locw          = NULL;
03011 
03012     cxint            ce_code;
03013     cxint            ssfs           = 0,
03014                      countlines     = 0,
03015                      status         = 0,
03016                      numslits       = 0,
03017                      i              = 0,
03018                      j              = 0,
03019                      num_coeff      = 0,
03020                      mcol           = 0,
03021                      mrow           = 0,
03022                      maxcount       = 0;
03023 
03024     cxdouble        *dblbuffer      = NULL,
03025                     *pd_m           = NULL,
03026                      val            = 0.0;
03027 
03028     cpl_table       *ref_wtable     = NULL;
03029 
03030     GiSlitGeometry  *opt_mod_resid_coeff = NULL;
03031 
03032     cpl_plist       *ref_presult    = NULL,
03033                     *ref_plist      = NULL;
03034 
03035     cpl_matrix      *m              = NULL;
03036 
03037     cpl_image_stats *stats          = NULL;
03038 
03039     cxchar           buffer[68],
03040                      colnamebuffer[80],
03041                      wspoly[80];
03042 
03043     GiLocPosition    loc_pos;
03044 
03045 
03046     /*************************************************************************
03047                                    INITIALIZATION
03048     *************************************************************************/
03049 
03050     if (locy_frame    ==NULL) { return 1; }
03051     if (locw_frame    ==NULL) { return 1; }
03052     if (lines         ==NULL) { return 1; }
03053     if (slit_geo      ==NULL) { return 1; }
03054     if (wavcoeff      ==NULL) { return 1; }
03055     if (xor_fit_frame ==NULL) { return 1; }
03056     if (xor_cheb_table==NULL) { return 1; }
03057     if (wcalib_config ==NULL) { return 1; }
03058     if (grating_data  ==NULL) { return 1; }
03059 
03060     _locy = giraffe_image_get(locy_frame);
03061     _locw = giraffe_image_get(locw_frame);
03062 
03063     xor_poly_params.ncoeffs =
03064         (xor_poly_params.xdeg+1) * (xor_poly_params.ydeg+1);
03065 
03066     opt_mod_resid =
03067         cpl_image_new_double(
03068             cpl_image_get_nx(_locy),
03069             cpl_image_get_ny(_locy),
03070             NULL,
03071             NULL
03072         );
03073 
03074     ssfs      = giraffe_slitgeometry_size(slit_geo);
03075     opt_mod_resid_coeff = giraffe_slitgeometry_new();
03076     giraffe_slitgeometry_resize(opt_mod_resid_coeff, ssfs);
03077 
03078     loc_pos.type      = GILOCDATATYPE_FITTED_DATA;
03079     loc_pos.centroids = _locy;
03080     loc_pos.widths    = _locw;
03081 
03082     /*************************************************************************
03083                                       PROCESSING
03084     *************************************************************************/
03085 
03086     countlines =
03087         giraffe_fit_x_optm_residuals(
03088             loc_pos,
03089             lines,
03090             slit_geo,
03091             xor_poly_params,
03092             xor_clip_params,
03093             opt_mod_resid,
03094             opt_mod_resid_coeff
03095         );
03096 
03097     if (countlines<0) {
03098         cpl_msg_error(fctid, "Error computing X residuals, aborting..." );
03099 
03100         /* return empty result set... */
03101         giraffe_image_set(xor_fit_frame, NULL);
03102         giraffe_image_set_properties(xor_fit_frame, NULL);
03103         cpl_image_delete(opt_mod_resid);
03104 
03105         /* haven't done anything with xor_cheb_table */
03106         giraffe_slitgeometry_delete(opt_mod_resid_coeff);
03107 
03108         return 2;
03109     }
03110 
03111     giraffe_image_set(xor_fit_frame, opt_mod_resid);
03112 
03113     cpl_image_delete(opt_mod_resid); opt_mod_resid = NULL;
03114 
03115     status =
03116         giraffe_image_set_properties(
03117             xor_fit_frame,
03118             giraffe_image_get_properties(locy_frame)
03119         );
03120 
03121     ref_presult = giraffe_image_get_properties(xor_fit_frame);
03122 
03123     /*
03124      *  Update keywords of output image
03125      */
03126 
03127     stats =
03128         cpl_image_stat(giraffe_image_get(xor_fit_frame),
03129                        CPL_STAT_MIN | CPL_STAT_MAX );
03130 
03131     status =
03132         giraffe_plist_update_double(
03133             ref_presult,
03134             GIALIAS_DATAMIN,
03135             cpl_image_stats_get_min(stats)
03136         );
03137 
03138     status =
03139         giraffe_plist_update_double(
03140             ref_presult,
03141             GIALIAS_DATAMAX,
03142             cpl_image_stats_get_max(stats)
03143         );
03144 
03145     status =
03146         giraffe_plist_update_double(
03147             ref_presult,
03148             GIALIAS_XRES_SIG,
03149             xor_clip_params.sigma
03150         );
03151 
03152     status =
03153         giraffe_plist_update_int(
03154             ref_presult,
03155             GIALIAS_XRES_NIT,
03156             xor_clip_params.niter
03157         );
03158 
03159     status =
03160         giraffe_plist_update_double(
03161             ref_presult,
03162             GIALIAS_XRES_MFR,
03163             xor_clip_params.mfrac
03164         );
03165 
03166     cx_snprintf(buffer, 68, "%d,%d", xor_poly_params.xdeg+1,
03167                 xor_poly_params.ydeg+1);
03168 
03169     status =
03170         giraffe_plist_update_string(
03171             ref_presult,
03172             GIALIAS_XRES_PDEG,
03173             buffer
03174         );
03175 
03176     status =
03177         giraffe_plist_update_int(
03178             ref_presult,
03179             GIALIAS_XRES_SSN,
03180             giraffe_slitgeometry_size(slit_geo)
03181         );
03182 
03183     cx_free(stats);
03184 
03185     /*
03186      *  Convert coefficients to output table and add keywords
03187      */
03188 
03189     ref_plist  = giraffe_table_get_properties(xor_cheb_table);
03190 
03191     status =
03192         giraffe_plist_update_string(
03193             ref_plist,
03194             GIALIAS_EXTNAME,
03195             "XRESCOEFF"
03196         );
03197 
03198     status =
03199         giraffe_plist_update_double(
03200             ref_plist,
03201             GIALIAS_XRES_SIG,
03202             wcalib_config->xws_clip_level
03203         );
03204 
03205     status =
03206         giraffe_plist_update_int(
03207             ref_plist,
03208             GIALIAS_XRES_NIT,
03209             wcalib_config->xws_clip_niter
03210         );
03211 
03212     status =
03213         giraffe_plist_update_double(
03214             ref_plist,
03215             GIALIAS_XRES_MFR,
03216             wcalib_config->xws_clip_mfrac
03217         );
03218 
03219     status =
03220         giraffe_plist_update_int(
03221             ref_plist,
03222             GIALIAS_XRES_SSN,
03223             giraffe_slitgeometry_size(slit_geo)
03224         );
03225 
03226     if (wcalib_config->opt_model==LMRQ_XOPTMOD2) {
03227 
03228         status =
03229             giraffe_plist_update_string(
03230                 ref_plist,
03231                 GIALIAS_WSOL_OMNAME,
03232                 "xoptmod2"
03233             );
03234 
03235     } else if (wcalib_config->opt_model==LMRQ_XOPTMOD) {
03236 
03237         status =
03238             giraffe_plist_update_string(
03239                 ref_plist,
03240                 GIALIAS_WSOL_OMNAME,
03241                 "xoptmod"
03242             );
03243 
03244     } else {
03245 
03246         status =
03247             giraffe_plist_update_string(
03248                 ref_plist,
03249                 GIALIAS_WSOL_OMNAME,
03250                 "unknown"
03251             );
03252     }
03253 
03254     sprintf(wspoly, "%d:%d", wcalib_config->xws_poly_x_deg+1,
03255             wcalib_config->xws_poly_y_deg+1);
03256 
03257     status = giraffe_plist_update_string(ref_plist, GIALIAS_XRES_PDEG,
03258                                          wspoly);
03259     status = giraffe_plist_update_string(ref_plist, GIALIAS_GIRFTYPE,
03260                                          "WAVCOEFTAB");
03261 
03262     status = giraffe_plist_update_string(ref_plist, GIALIAS_SETUPNAME,
03263                                          cx_string_get(grating_data->setup));
03264     cpl_plist_set_comment(ref_plist, GIALIAS_SETUPNAME, "Exposure mode.");
03265 
03266     status = giraffe_plist_update_string(ref_plist, GIALIAS_SLITNAME,
03267                                          cx_string_get(grating_data->slit));
03268     cpl_plist_set_comment(ref_plist, GIALIAS_SLITNAME, "Slit name.");
03269 
03270     status = giraffe_plist_update_string(ref_plist, GIALIAS_SLITS_ID,
03271                                          cx_string_get(grating_data->slit));
03272     status = giraffe_plist_update_string(ref_plist, GIALIAS_SLITS_NAME,
03273                                          cx_string_get(grating_data->slit));
03274     status = giraffe_plist_update_string(ref_plist, GIALIAS_GRATNAME,
03275                                          cx_string_get(grating_data->name));
03276     cpl_plist_set_comment(ref_plist, GIALIAS_GRATNAME, "Grating common name.");
03277 
03278     status = giraffe_plist_update_double(ref_plist, GIALIAS_GRATWLEN,
03279                                          grating_data->wlen0);
03280     cpl_plist_set_comment(ref_plist, GIALIAS_GRATWLEN, "Grating central "
03281                           "wavelength [nm].");
03282 
03283     status = giraffe_plist_update_int(ref_plist, GIALIAS_GRATORDER,
03284                                       (cxint)grating_data->order);
03285     cpl_plist_set_comment(ref_plist, GIALIAS_GRATORDER, "Grating order "
03286                           "number.");
03287 
03288     status = giraffe_plist_update_string(ref_plist, GIALIAS_FILTNAME,
03289                                          cx_string_get(grating_data->filter));
03290     cpl_plist_set_comment(ref_plist, GIALIAS_FILTNAME, "Filter name.");
03291 
03292     status = giraffe_plist_update_int(ref_plist, GIALIAS_OPTSOL,
03293                                       wcalib_config->opt_solution == TRUE ? 1 : 0);
03294     status =
03295         giraffe_plist_update_int(
03296             ref_plist,
03297             GIALIAS_WSOL_OMDIR,
03298             wcalib_config->opt_direction
03299         );
03300 
03301     status =
03302         giraffe_plist_update_int(
03303             ref_plist,
03304             GIALIAS_WSOL_SUBSLITS,
03305             wcalib_config->fit_subslits==TRUE ? 1 : 0
03306         );
03307 
03308     status =
03309         giraffe_plist_update_double(
03310             ref_plist,
03311             GIALIAS_WSOL_OMFCOLL,
03312             grating_data->fcoll
03313         );
03314 
03315     status =
03316         giraffe_plist_update_double(
03317             ref_plist,
03318             GIALIAS_WSOL_OMGCAM,
03319             grating_data->gcam
03320         );
03321 
03322     status =
03323         giraffe_plist_update_double(
03324             ref_plist,
03325             GIALIAS_WSOL_OMGTHETA,
03326             grating_data->theta
03327         );
03328 
03329     status =
03330         giraffe_plist_update_double(
03331             ref_plist,
03332             GIALIAS_WSOL_OMSDX,
03333             grating_data->sdx
03334         );
03335 
03336     status =
03337         giraffe_plist_update_double(
03338             ref_plist,
03339             GIALIAS_WSOL_OMSDY,
03340             grating_data->sdy
03341         );
03342 
03343     status =
03344         giraffe_plist_update_double(
03345             ref_plist,
03346             GIALIAS_WSOL_OMSPHI,
03347             grating_data->sphi
03348         );
03349 
03350     if (wcalib_config->line_model==LMRQ_PSFEXP2) {
03351 
03352         status =
03353             giraffe_plist_update_string(
03354                 ref_plist,
03355                 GIALIAS_WSOL_LINEM,
03356                 "psfexp2"
03357             );
03358 
03359     } else if (wcalib_config->line_model==LMRQ_PSFEXP) {
03360 
03361         status =
03362             giraffe_plist_update_string(
03363                 ref_plist,
03364                 GIALIAS_WSOL_LINEM,
03365                 "psfexp"
03366             );
03367 
03368     } else if (wcalib_config->line_model==LMRQ_GAUSSUM) {
03369 
03370         status =
03371             giraffe_plist_update_string(
03372                 ref_plist,
03373                 GIALIAS_WSOL_LINEM,
03374                 "gaussum"
03375             );
03376 
03377     } else {
03378 
03379         status =
03380             giraffe_plist_update_string(
03381                 ref_plist,
03382                 GIALIAS_WSOL_LINEM,
03383                 "unknown"
03384             );
03385     }
03386 
03387     status =
03388         giraffe_plist_update_double(
03389             ref_plist,
03390             GIALIAS_WSOL_LINEWDTH,
03391             curr_line_width
03392         );
03393 
03394     status =
03395         giraffe_plist_update_double(
03396             ref_plist,
03397             GIALIAS_WSOL_LINETHOLD,
03398             wcalib_config->line_threshold
03399         );
03400 
03401     status =
03402         giraffe_plist_update_int(
03403             ref_plist,
03404             GIALIAS_WSOL_LINENIT,
03405             wcalib_config->line_niter
03406         );
03407 
03408     status =
03409         giraffe_plist_update_int(
03410             ref_plist,
03411             GIALIAS_WSOL_LINENTST,
03412             wcalib_config->line_ntest
03413         );
03414 
03415     status =
03416         giraffe_plist_update_double(
03417             ref_plist,
03418             GIALIAS_WSOL_LINEDCHQ,
03419             wcalib_config->line_dchsq
03420         );
03421 
03422     status =
03423         giraffe_plist_update_double(
03424             ref_plist,
03425             GIALIAS_WSOL_GRTHETA,
03426             grating_data->theta
03427         );
03428 
03429     status =
03430         giraffe_plist_update_double(
03431             ref_plist,
03432             GIALIAS_WSOL_GRORDER,
03433             grating_data->order
03434         );
03435     status =
03436         giraffe_plist_update_double(
03437             ref_plist,
03438             GIALIAS_WSOL_GRSPACE,
03439             grating_data->space
03440         );
03441 
03442     /*
03443      *  Fill Table with X Residuals coefficients
03444      */
03445 
03446     num_coeff = ((xor_poly_params.xdeg+1)*(xor_poly_params.ydeg+1));
03447     numslits  = giraffe_slitgeometry_size(opt_mod_resid_coeff);
03448 
03449     /*
03450      *  Find maximum number of coefficients in subslits, just in case...
03451      */
03452 
03453     for (i=0; i<numslits; i++) {
03454 
03455         cpl_matrix *dummy;
03456         cxint       count = 0;
03457 
03458         dummy = giraffe_slitgeometry_get(opt_mod_resid_coeff, i);
03459 
03460         count  = cpl_matrix_get_ncol(dummy);
03461         count *= cpl_matrix_get_nrow(dummy);
03462 
03463         if (count>maxcount) {
03464             maxcount = count;
03465         }
03466     }
03467 
03468     if (maxcount!=num_coeff) {
03469         cpl_msg_warning(fctid, "Actual # of coefficients not equal "
03470                                "to expected #...");
03471     }
03472 
03473     ref_wtable = cpl_table_new(1);
03474 
03475     ce_code = cpl_table_new_column_int(ref_wtable, "SUBSLIT");
03476 
03477     for (i=0; i<num_coeff; i++) {
03478         snprintf(colnamebuffer, sizeof(cxchar)*80, "XC%d", i);
03479         ce_code =
03480             cpl_table_new_column_double(
03481                 ref_wtable,
03482                 (const char*)colnamebuffer
03483             );
03484     }
03485 
03486     /* handle subslits */
03487 
03488     for (j=0; j<numslits; j++) {
03489 
03490         cxint coeff_count = 0;
03491 
03492         ce_code =
03493             cpl_table_set_int(
03494                 ref_wtable,
03495                 "SUBSLIT",
03496                 j,
03497                 j
03498             );
03499 
03500         m = cpl_matrix_duplicate(giraffe_slitgeometry_get(opt_mod_resid_coeff, j));
03501 
03502         if (m==NULL) break;
03503 
03504         pd_m = cpl_matrix_get_data(m);
03505         mcol = cpl_matrix_get_ncol(m);
03506         mrow = cpl_matrix_get_nrow(m);
03507 
03508         coeff_count = mcol * mrow;
03509 
03510         /* TODO If we have more than one subslit with
03511                 different number of subslits make sure
03512                 they all get filled to the maxsize.
03513                 Right now not a problem since we only
03514                 have one subslit
03515          */
03516 
03517         dblbuffer = cpl_matrix_get_data(m);
03518         cpl_matrix_delete_but_data(m); m = NULL;
03519 
03520         m =
03521             cpl_matrix_new_from_data(
03522                 dblbuffer,
03523                 xor_poly_params.xdeg+1,
03524                 xor_poly_params.ydeg+1
03525             );
03526 
03527         if (coeff_count>num_coeff) {
03528             cpl_msg_warning(
03529                 fctid,
03530                 "More entries in matrix than expected! Only using first %d!",
03531                 num_coeff
03532             );
03533         }
03534 
03535         for (i=0; i<num_coeff; i++) {
03536 
03537             if (i<coeff_count) {
03538 
03539                 val = pd_m[i];
03540                 snprintf(colnamebuffer, sizeof(cxchar)*80, "XC%d", i);
03541 
03542                 ce_code =
03543                     cpl_table_set_double(
03544                         ref_wtable,
03545                         (const char*) colnamebuffer,
03546                         j,
03547                         val
03548                     );
03549 
03550                 val =
03551                     cpl_table_get_double(
03552                         ref_wtable,
03553                         (const char*) colnamebuffer,
03554                         j,
03555                         NULL
03556                     );
03557 
03558             } else {
03559 
03560                 snprintf(colnamebuffer, sizeof(cxchar)*80, "XC%d", i);
03561                 ce_code =
03562                     cpl_table_set_double(
03563                         ref_wtable,
03564                         (const char*) colnamebuffer,
03565                         j,
03566                         0.0
03567                     );
03568 
03569             }
03570         }
03571 
03572         cpl_matrix_delete(m);
03573 
03574     }
03575 
03576     giraffe_table_set(xor_cheb_table, ref_wtable);
03577     cpl_table_delete(ref_wtable);
03578 
03579     /*
03580      *  Update wavelength calibration solution structure
03581      */
03582 
03583     {
03584 
03585         cxdouble   *pd = NULL;
03586         cpl_matrix *m  = NULL;
03587 
03588         numslits  = giraffe_slitgeometry_size(opt_mod_resid_coeff);
03589 
03590         /* resize each entry to the right matrix shape */
03591 
03592         for (i=0; i<numslits; i++) {
03593 
03594             m = cpl_matrix_duplicate(giraffe_slitgeometry_get(opt_mod_resid_coeff, i));
03595 
03596             pd = cpl_matrix_get_data(m);
03597             cpl_matrix_delete_but_data(m); m = NULL;
03598             m =
03599                 cpl_matrix_new_from_data(
03600                     pd,
03601                     xor_poly_params.xdeg+1,
03602                     xor_poly_params.ydeg+1
03603                 );
03604 
03605             giraffe_slitgeometry_set(opt_mod_resid_coeff, i, m);
03606             cpl_matrix_delete(m);
03607         }
03608 
03609         /* copy coefficients to solutions structure */
03610 
03611         if (wavcoeff->wav_coeffs==NULL) {
03612             wavcoeff->wav_coeffs = giraffe_slitgeometry_duplicate(opt_mod_resid_coeff);
03613         } else {
03614             giraffe_slitgeometry_delete(wavcoeff->wav_coeffs);
03615             wavcoeff->wav_coeffs = giraffe_slitgeometry_duplicate(opt_mod_resid_coeff);
03616         }
03617     }
03618 
03619     giraffe_slitgeometry_delete(opt_mod_resid_coeff);
03620 
03621     return 0;
03622 
03623 } /* end giraffe_fit_x_optm_residuals_wrapper() */
03624 
03625 
03669 static cxint
03670 giraffe_fit_psf_x_width(
03671     GiLocPosition   loc_pos,
03672     GiImageStack   *lines,
03673     GiSlitGeometry *slit_geo,
03674     GiPolyDeg       pxw_poly_params,
03675     GiClipParams    pxw_clip_params,
03676     lmrq_model_id   lmrq_line_model,
03677     cpl_image      *pxw_fit,
03678     GiSlitGeometry *pxw_coeff
03679 ) {
03680 
03681     /*************************************************************************
03682                                      VARIABLES
03683     *************************************************************************/
03684 
03685     const cxchar   *fctid = "_fit_psf_x_width";
03686 
03687     cxint           nlineparams,   /* number of parameters for line */
03688                     nc_wss,
03689                     nc_fit,
03690                     nr_fit,
03691                     nlines,
03692                     index_width,
03693                     index_width_sigma,
03694                     index_expon,
03695                     i;
03696 
03697     cpl_matrix     *m_ss = NULL,
03698                    *xss  = NULL,
03699                    *yss  = NULL,
03700                    *wss  = NULL,
03701                    *sss  = NULL,
03702                    *nss  = NULL,
03703                    *base = NULL,
03704                    *cheb = NULL,
03705                    *fit  = NULL;
03706 
03707     cxdouble       *pd_m_ss    = NULL,
03708                    *pd_xss     = NULL,
03709                    *pd_yss     = NULL,
03710                    *pd_wss     = NULL,
03711                    *pd_sss     = NULL,
03712                    *pd_nss     = NULL,
03713                    *pd_mY      = NULL,
03714                    *pd_mW      = NULL,
03715                    *pd_fit     = NULL,
03716                    *pd_pxw_fit = NULL,
03717                   **qa2imgs    = NULL,
03718                    *buffer     = NULL;
03719 
03720     register cxint  subslit, nfibers, n, nn, nx, ns, nmin, nmax, ndata, nlen,
03721                     ngoodlines;
03722     register cxint  k, l, ll, m, x, xx, nlines_accepted, niter,nlines_total = 0;
03723     register cxdouble ymin, ymax, y_upper, y_lower, nlines_ratio, fwhm_ratio;
03724 
03725     cpl_image *refimg  = NULL;
03726 
03727     /*************************************************************************
03728                                    INITIALIZATION
03729     *************************************************************************/
03730 
03731     if (lines    ==NULL) { return -1; }
03732     if (slit_geo ==NULL) { return -1; }
03733     if (pxw_fit  ==NULL) { return -1; }
03734     if (pxw_coeff==NULL) { return -1; }
03735 
03736     nlineparams = giraffe_imagestack_size(lines);
03737 
03738     refimg      = giraffe_imagestack_get(lines, LF_I_STATUS);
03739     nlines      = cpl_image_get_nx(refimg); /* number of lines */
03740 
03741     nx = cpl_image_get_ny(loc_pos.centroids); /* size of spectra */
03742     ns = cpl_image_get_nx(loc_pos.centroids); /* number of spectra */
03743 
03744     qa2imgs = cx_calloc(nlineparams, sizeof(cxdouble *));
03745 
03746     for (i = 0; i < nlineparams; i++) {
03747 
03748         cpl_image *image = giraffe_imagestack_get(lines, i);
03749 
03750         qa2imgs[i] = cpl_image_get_data_double(image);
03751 
03752     }
03753 
03754     /*************************************************************************
03755                                       PROCESSING
03756     *************************************************************************/
03757 
03758     cpl_msg_info(
03759         fctid,
03760         "Performing PSF fit of spectra/reference lines using "
03761         "'%s' model, %d spectra and %d lines",
03762         lmrq_models[lmrq_line_model].name,
03763         ns,
03764         nlines
03765     );
03766 
03767     cpl_msg_debug(
03768         fctid,
03769         "Using : Chebyshev polynomial (%d,%d), Sigma Clipping : "
03770         "sigma=%4.1f, niter=%4i, mfrac=%4.2f",
03771         pxw_poly_params.xdeg,
03772         pxw_poly_params.ydeg,
03773         pxw_clip_params.sigma,
03774         pxw_clip_params.niter,
03775         pxw_clip_params.mfrac
03776     );
03777 
03778     if (nlineparams == LF_G_NPARAMS) {
03779         /* gaussian model */
03780         index_width       = LF_O_PARAMS + LF_G_WIDTH;
03781         index_width_sigma = LF_O_PARAMS + LF_G_SWIDTH;
03782         fwhm_ratio        = 2.0 * sqrt(2.0 * log(2.0));
03783     } else if (nlineparams == LF_E_NPARAMS) {
03784         /* exponential model */
03785         index_width       = LF_O_PARAMS + LF_E_WIDTH;
03786         index_width_sigma = LF_O_PARAMS + LF_E_SWIDTH;
03787         index_expon       = LF_O_PARAMS + LF_E_EXPON;
03788     } else {
03789         cpl_msg_error(fctid, "Unknown line model, aborting...." );
03790         cx_free(qa2imgs);
03791         return -1;
03792     }
03793 
03794     ngoodlines = 0;
03795 
03796     for (subslit = 0; subslit < giraffe_slitgeometry_size(slit_geo);
03797          subslit++) {
03798 
03799         cpl_msg_debug(fctid, "Processing subslit %d of %d", subslit + 1,
03800                       giraffe_slitgeometry_size(slit_geo));
03801 
03802         m_ss    = giraffe_slitgeometry_get(slit_geo, subslit);
03803         pd_m_ss = cpl_matrix_get_data(m_ss);
03804 
03805         giraffe_matrix_sort(m_ss);
03806 
03807         giraffe_slitgeometry_set(pxw_coeff, subslit, NULL);
03808 
03809         /* Get spectra/fibers range for current subslit */
03810         nfibers = cpl_matrix_get_nrow(m_ss);
03811         nmin    = (cxint) pd_m_ss[0];
03812         nmax    = (cxint) pd_m_ss[nfibers - 1];
03813         nlen    = nmax - nmin + 1;
03814         ymax    = 0.0;
03815         ymin    = CX_MAXDOUBLE;
03816 
03817         cpl_msg_debug(fctid, "Slit geometry : nmin, nmax = [%d,%d], "
03818                       "#spectra=%d", nmin, nmax, ns);
03819 
03820         pd_mY = cpl_image_get_data_double(loc_pos.centroids);
03821         pd_mW = cpl_image_get_data_double(loc_pos.widths);
03822 
03823         /* Get y range for current subslit */
03824         for (m = 0, n = nmin; n <= nmax; n++, m++) {
03825             for (x = 0; x < nx; x++) {
03826                 xx = x * ns + n;
03827                 y_upper = pd_mY[xx] + pd_mW[xx];
03828                 y_lower = pd_mY[xx] - pd_mW[xx];
03829 
03830                 if (ymax < y_upper) {
03831                     ymax = y_upper;
03832                 }
03833 
03834                 if (ymin > y_lower) {
03835                     ymin = y_lower;
03836                 }
03837             }
03838         }
03839 
03840         /* allocate space for all lines of specified spectra */
03841         ndata = nlines * nlen;
03842 
03843         xss = cpl_matrix_new(ndata, 1); /* X abcissas for current subslit  */
03844         yss = cpl_matrix_new(ndata, 1); /* Y ordinates                     */
03845         wss = cpl_matrix_new(1, ndata); /* widths  (transposed)            */
03846         sss = cpl_matrix_new(ndata, 1); /* width sigmas                    */
03847         nss = cpl_matrix_new(ndata, 1); /* good lines indices              */
03848 
03849         pd_xss = cpl_matrix_get_data(xss);
03850         pd_yss = cpl_matrix_get_data(yss);
03851         pd_wss = cpl_matrix_get_data(wss);
03852         pd_sss = cpl_matrix_get_data(sss);
03853         pd_nss = cpl_matrix_get_data(nss);
03854 
03855         /*
03856          * Fills inputs matrices with good lines xccd, yccd, width,
03857          * width sigmas and line status
03858          */
03859 
03860         for (k = 0, m = 0, n = nmin; n <= nmax; n++, m++) {
03861             nn = n * nlines;
03862             for (l = 0; l < nlines; l++) {
03863                 ll = l + nn;
03864 
03865                 if (qa2imgs[LF_I_STATUS][ll] <= 0.0 ) continue;
03866                 if (qa2imgs[LF_I_YCCD][ll]   >  ymax) continue;
03867                 if (qa2imgs[LF_I_YCCD][ll]   <  ymin) continue;
03868 
03869                 pd_xss[k] = qa2imgs[LF_I_XCCD][ll];
03870                 pd_yss[k] = qa2imgs[LF_I_YCCD][ll];
03871                 pd_wss[k] = qa2imgs[index_width][ll];
03872                 pd_sss[k] = qa2imgs[index_width_sigma][ll];
03873                 pd_nss[k] = (cxdouble) ll;
03874                 k++;
03875             }
03876         }
03877 
03878         /* This is the initial (reduced) size */
03879         cpl_matrix_resize(xss, k, 1);
03880         cpl_matrix_resize(yss, k, 1);
03881         cpl_matrix_resize(wss, 1, k);
03882         cpl_matrix_resize(sss, k, 1);
03883         cpl_matrix_resize(nss, k, 1);
03884 
03885         pd_xss = cpl_matrix_get_data(xss);
03886         pd_yss = cpl_matrix_get_data(yss);
03887         pd_wss = cpl_matrix_get_data(wss);
03888         pd_sss = cpl_matrix_get_data(sss);
03889         pd_nss = cpl_matrix_get_data(nss);
03890 
03891         /* Here comes the sigma clipping */
03892 
03893         nc_wss = cpl_matrix_get_ncol(wss);
03894 
03895         nlines_ratio = 1.0;
03896         nlines_accepted = nc_wss;
03897         nlines_total = nc_wss;
03898         niter = 0;
03899 
03900         cpl_msg_debug(fctid, "SC: Iteration, Lines accepted, Line Ratio "
03901                       ": %d/%d/%12.6f", niter, nlines_accepted, nlines_ratio);
03902 
03903         while ((nlines_accepted > 0) && (niter < pxw_clip_params.niter) &&
03904                (nlines_ratio>pxw_clip_params.mfrac)) {
03905 
03906             base =
03907                 giraffe_chebyshev_base2d(
03908                     0.0,
03909                     ymin,
03910                     (cxdouble) nx,
03911                     (ymax - ymin + 1.0),
03912                     pxw_poly_params.xdeg + 1,
03913                     pxw_poly_params.ydeg + 1,
03914                     xss,
03915                     yss
03916                 );
03917 
03918             cpl_matrix_delete(cheb); cheb = NULL;
03919 
03920             cheb = giraffe_matrix_leastsq(base, wss);
03921 
03922             if (cheb==NULL) {
03923                 cpl_msg_info(fctid, "Error in leastsq solve for cheyshev "
03924                              "matrix subslit[%d], skipping...", subslit);
03925                 break;
03926             }
03927 
03928             fit = cpl_matrix_product(cheb, base);
03929 
03930             nc_fit = cpl_matrix_get_ncol(fit);
03931             pd_fit = cpl_matrix_get_data(fit);
03932 
03933             k = 0;
03934 
03935             for (l = 0; l < nc_fit; l++) {
03936 
03937                 if ( fabs(pd_fit[l] - pd_wss[l]) >=
03938                      pxw_clip_params.sigma * pd_sss[l]
03939                 ) {
03940 
03941                     /* reject this line */
03942                     qa2imgs[LF_I_STATUS][(cxint)pd_nss[l]] =
03943                         -1.0 * (cxdouble) LF_R_PSFIT;
03944                     /* clip clip clip... */
03945                     continue;
03946                 }
03947 
03948                 /* last best hopes... */
03949                 pd_xss[k] = pd_xss[l];
03950                 pd_yss[k] = pd_yss[l];
03951                 pd_wss[k] = pd_wss[l];
03952                 pd_sss[k] = pd_sss[l];
03953                 pd_nss[k] = pd_nss[l];
03954                 k++;
03955             }
03956 
03957             cpl_matrix_delete(fit);  fit = NULL;
03958             cpl_matrix_delete(base); base = NULL;
03959 
03960             /*
03961              * No new points rejected, no more iterations That
03962              * was the last turn, boy
03963              */
03964 
03965             if (k == nlines_accepted) break;
03966 
03967             /* Merry-go-round once more */
03968             nlines_accepted = k;
03969             nlines_ratio = (cxdouble) nlines_accepted / (cxdouble) nlines_total;
03970 
03971             /* This is the current (clipped) size */
03972 
03973             cpl_matrix_resize(xss, k, 1);
03974             cpl_matrix_resize(yss, k, 1);
03975             cpl_matrix_resize(wss, 1, k);
03976             cpl_matrix_resize(sss, k, 1);
03977             cpl_matrix_resize(nss, k, 1);
03978 
03979             pd_xss = cpl_matrix_get_data(xss);
03980             pd_yss = cpl_matrix_get_data(yss);
03981             pd_wss = cpl_matrix_get_data(wss);
03982             pd_sss = cpl_matrix_get_data(sss);
03983             pd_nss = cpl_matrix_get_data(nss);
03984 
03985             niter++;
03986 
03987             cpl_msg_debug(fctid, "SC: Iteration, Lines accepted, Line Ratio "
03988                           ": %d/%d/%12.6f", niter, nlines_accepted, nlines_ratio);
03989 
03990         } /* sigma clipping ends */
03991 
03992         if (nlines_accepted==0) {
03993             cpl_msg_info(fctid, "subslit[%d]: no lines accepted", subslit);
03994             continue;
03995         }
03996 
03997         if (cheb==NULL) {
03998             cpl_msg_info(fctid, "subslit[%d]: error in least square, no "
03999                          "chebyshev matrix found", subslit);
04000             continue;
04001         }
04002 
04003         ngoodlines += nlines_accepted;
04004 
04005         cpl_msg_debug(
04006             fctid,
04007             "subslit=%d : good lines=%d, iterations=%d, lines accepted=%d, "
04008             "lines total=%d, lines ratio=%.2f",
04009             subslit,
04010             ngoodlines,
04011             niter,
04012             nlines_accepted,
04013             nlines_total,
04014             nlines_ratio
04015         );
04016 
04017         cpl_matrix_delete(nss); nss = NULL;
04018         cpl_matrix_delete(sss); sss = NULL;
04019         cpl_matrix_delete(wss); wss = NULL;
04020         cpl_matrix_delete(yss); yss = NULL;
04021         cpl_matrix_delete(xss); xss = NULL;
04022 
04023         /* Compute coordinates mesh for whole subslit */
04024         xss = cpl_matrix_new(nx * nlen, 1);
04025 
04026         giraffe_compute_image_coordinates(nx, nlen, xss, NULL);
04027 
04028         yss = cpl_matrix_new(nx * nlen, 1);
04029         pd_yss = cpl_matrix_get_data(yss);
04030 
04031         for (k = 0, n = nmin; n <= nmax; n++, k++) {
04032             for (x = 0; x < nx; x++) {
04033                 pd_yss[k + x * nlen] = pd_mY[n + x * ns];
04034             }
04035         }
04036 
04037         /* compute fitted psf width on whole subslit */
04038         base =
04039             giraffe_chebyshev_base2d(
04040                 0.0,
04041                 ymin,
04042                 (cxdouble) nx,
04043                 (ymax - ymin + 1.0),
04044                 pxw_poly_params.xdeg + 1,
04045                 pxw_poly_params.ydeg + 1,
04046                 xss,
04047                 yss
04048             );
04049 
04050         cpl_matrix_delete(yss); yss = NULL;
04051         cpl_matrix_delete(xss); xss = NULL;
04052 
04053         fit = cpl_matrix_product(cheb, base);
04054 
04055         giraffe_slitgeometry_set(pxw_coeff, subslit, cheb);
04056 
04057         cpl_matrix_delete(base); base = NULL;
04058         cpl_matrix_delete(cheb); cheb = NULL;
04059 
04060 
04061         /* reshape fit to subslit area size */
04062         buffer = cpl_matrix_get_data(fit);
04063         cpl_matrix_delete_but_data(fit); fit = NULL;
04064         fit = cpl_matrix_new_from_data(buffer,nx, nlen);
04065 
04066         pd_fit = cpl_matrix_get_data(fit);
04067         nr_fit = cpl_matrix_get_nrow(fit);
04068         nc_fit = cpl_matrix_get_ncol(fit);
04069 
04070         pd_pxw_fit = cpl_image_get_data_double(pxw_fit);
04071 
04072         /* subslit fit goes into whole fit */
04073         for (x = 0; x < nr_fit; x++) {
04074             for (k = nmin, n = 0; n < nc_fit; n++, k++) {
04075                 pd_pxw_fit[k + x * ns] = pd_fit[n + x * nc_fit];
04076             }
04077         }
04078 
04079         cpl_matrix_delete(fit); fit = NULL;
04080 
04081     } /* for each subslit */
04082 
04083     cx_free(qa2imgs); qa2imgs = NULL;
04084 
04085     cpl_msg_info(
04086         fctid,
04087         "Fit completed, Spectra/Lines Combinations : good/rejected/total = %d/%d/%d",
04088         ngoodlines,
04089         nlines_total - ngoodlines,
04090         nlines_total
04091     );
04092 
04093     return ngoodlines;
04094 
04095 } /* end giraffe_fit_psf_x_width() */
04096 
04124 static cxint
04125 giraffe_fit_psf_x_width_wrapper(
04126     GiImage        *locy_frame,
04127     GiImage        *locw_frame,
04128     GiImageStack   *lines,
04129     GiSlitGeometry *slit_geo,
04130     GiClipParams    pxw_clip_params,
04131     GiPolyDeg       pxw_poly_params,
04132     GiImage        *pxw_fit_frame,
04133     GiTable        *pxw_cheb_table,
04134     lmrq_model_id   lmrq_line_model
04135 ) {
04136 
04137     /*************************************************************************
04138                                      VARIABLES
04139     *************************************************************************/
04140 
04141     GiSlitGeometry *psf_width_var_table = NULL;
04142 
04143     GiLocPosition   loc_pos;
04144 
04145     cpl_image      *_locy            = NULL,
04146                    *_locw            = NULL,
04147                    *psf_width_var    = NULL;
04148 
04149     cxint           nx_locy,
04150                     ny_locy,
04151                     size_nx,
04152                     size_ny,
04153                     nr_good_lines    = -1,
04154                     status = 0;
04155 
04156     cpl_plist      *ref_presult      = NULL;
04157 
04158     cxchar          buffer[68];
04159 
04160     cpl_image_stats *stats = NULL;
04161 
04162     /*************************************************************************
04163                                    INITIALIZATION
04164     *************************************************************************/
04165 
04166     if (locy_frame    ==NULL) { return 1; }
04167     if (locw_frame    ==NULL) { return 1; }
04168     if (lines         ==NULL) { return 1; }
04169     if (slit_geo      ==NULL) { return 1; }
04170     if (pxw_fit_frame ==NULL) { return 1; }
04171     if (pxw_cheb_table==NULL) { return 1; }
04172 
04173     _locy = giraffe_image_get(locy_frame);
04174     _locw = giraffe_image_get(locw_frame);
04175 
04176     nx_locy = cpl_image_get_nx(_locy);
04177     ny_locy = cpl_image_get_ny(_locy);
04178 
04179     psf_width_var = cpl_image_new_double(nx_locy, ny_locy, NULL, NULL);
04180 
04181     psf_width_var_table = giraffe_slitgeometry_new();
04182     giraffe_slitgeometry_resize(psf_width_var_table, giraffe_slitgeometry_size(slit_geo));
04183 
04184     loc_pos.type      = GILOCDATATYPE_FITTED_DATA;
04185     loc_pos.centroids = _locy;
04186     loc_pos.widths    = _locw;
04187 
04188     /*************************************************************************
04189                                       PROCESSING
04190     *************************************************************************/
04191 
04192     nr_good_lines =
04193         giraffe_fit_psf_x_width(
04194             loc_pos,
04195             lines,
04196             slit_geo,
04197             pxw_poly_params,
04198             pxw_clip_params,
04199             lmrq_line_model,
04200             psf_width_var,
04201             psf_width_var_table
04202         );
04203 
04204     giraffe_image_set(pxw_fit_frame, psf_width_var);
04205 
04206     status =
04207         giraffe_image_set_properties(
04208             pxw_fit_frame,
04209             giraffe_image_get_properties(locy_frame)
04210         );
04211 
04212     ref_presult = giraffe_image_get_properties(pxw_fit_frame);
04213 
04214     status =
04215         giraffe_plist_update_string(
04216             ref_presult,
04217             GIALIAS_WSOL_OMNAME,
04218             lmrq_models[lmrq_line_model].name
04219         );
04220 
04221     status =
04222         giraffe_plist_update_int(
04223             ref_presult,
04224             GIALIAS_NAXIS1,
04225             size_nx
04226         );
04227 
04228     status =
04229         giraffe_plist_update_int(
04230             ref_presult,
04231             GIALIAS_NAXIS2,
04232             size_ny
04233         );
04234 
04235     stats =
04236         cpl_image_stat(
04237             giraffe_image_get(pxw_fit_frame),
04238             CPL_STAT_MIN | CPL_STAT_MAX
04239         );
04240 
04241     status =
04242         giraffe_plist_update_double(
04243             ref_presult,
04244             GIALIAS_DATAMIN,
04245             cpl_image_stats_get_min(stats)
04246         );
04247 
04248     status =
04249         giraffe_plist_update_double(
04250             ref_presult,
04251             GIALIAS_DATAMAX,
04252             cpl_image_stats_get_max(stats)
04253         );
04254 
04255     cx_free(stats);
04256 
04257     status =
04258         giraffe_plist_update_double(
04259             ref_presult,
04260             GIALIAS_PSFW_SIG,
04261             pxw_clip_params.sigma
04262         );
04263 
04264     status =
04265         giraffe_plist_update_int(
04266             ref_presult,
04267             GIALIAS_PSFW_NIT,
04268             pxw_clip_params.niter
04269         );
04270 
04271     status =
04272         giraffe_plist_update_double(
04273             ref_presult,
04274             GIALIAS_PSFW_MFR,
04275             pxw_clip_params.mfrac
04276         );
04277 
04278     cx_snprintf(buffer, 68, "%d,%d", pxw_poly_params.xdeg+1,
04279                                      pxw_poly_params.ydeg+1);
04280 
04281     status =
04282         giraffe_plist_update_string(
04283             ref_presult,
04284             GIALIAS_PSFW_PDEG,
04285             buffer
04286         );
04287 
04288     status =
04289         giraffe_plist_update_int(
04290             ref_presult,
04291             GIALIAS_PSFW_SSNR,
04292             giraffe_slitgeometry_size(slit_geo)
04293         );
04294 
04295 /*
04296     TODO Chebyshev table is only used to verify the computation
04297     TODO Will implement it if we have a problem with the PSF Fitting
04298     TODO pxw_cheb_table = SlitGeometry -> Convert to table
04299 
04300     pxw_cheb_table = girBLDRS.girTable()
04301     pxw_cheb_table['SIMPLE'] = 'T'
04302     pxw_cheb_table['BITPIX'] = -32
04303     pxw_cheb_table['NAXIS']  = 0
04304     pxw_cheb_table['GIRFNAME']  = _psfW['GIRFNAME']
04305     pxw_cheb_table['WSCLIPSIGMA'] = widSigClip[0]
04306     pxw_cheb_table['WSCLIPNITER'] = widSigClip[1]
04307     pxw_cheb_table['WSCLIPMFRAC'] = widSigClip[2]
04308     pxw_cheb_table['WSPOLYDEG'] = "%d:%d" % widPolyDeg
04309     pxw_cheb_table['WSSLITGNSUB'] = len(slit_geo)
04310     __trange = range((widPolyDeg[0]+1)*(widPolyDeg[1]+1))
04311     __ttype=map(lambda x:"XC%d"%x,__trange)
04312     __tform=map(lambda x:"1D",__trange)
04313     __tunit=map(lambda x:None,__trange)
04314     __tdata = {}
04315     __chebData=Numeric.array(_cheb)
04316     for i in __trange:
04317         __tdata[__ttype[i]] = __chebData[:,i]
04318     __ttype.insert(0,'SUBSLIT')
04319     __tform.insert(0,'1I')
04320     __tunit.insert(0,None)
04321     __tdata['SUBSLIT'] = Numeric.arange(Numeric.shape(_cheb)[0])
04322     pxw_cheb_table.copyTableHead(["WPSFCOEF",__ttype,__tform,__tunit])
04323     pxw_cheb_table.copyTableData(__tdata)
04324     del __ttype,__tform,__tunit,__tdata,__trange
04325     pxw_cheb_table.addKeyword('GIRTTYPE','WPSFCOEF',comment='GIRAFFE PSF width 2D Cheb. fit coef.')
04326     del _wfit,_cheb,__chebData
04327 */
04328 
04329 
04330     giraffe_slitgeometry_delete(psf_width_var_table);
04331 
04332     return 0;
04333 
04334 } /* end giraffe_fit_psf_x_width_wrapper() */
04335 
04353 static cpl_image*
04354 giraffe_map_wavelength_to_residuals(
04355     cpl_image *x_pos,
04356     cpl_image *resid
04357 ) {
04358 
04359     register cxint spec, line, pos;
04360     register cxdouble lbound, ubound, indx;
04361 
04362     cxint      nspectra,
04363                nlines,
04364                nx_resid,
04365                ny_resid;
04366 
04367     cxdouble  *pd_xcheb = NULL,
04368               *pd_x_pos = NULL,
04369               *pd_resid = NULL;
04370 
04371     cpl_image *xcheb    = NULL;
04372 
04373 
04374     if (x_pos==NULL) { return NULL; }
04375     if (resid==NULL) { return NULL; }
04376 
04377     pd_x_pos = cpl_image_get_data_double(x_pos);
04378     pd_resid = cpl_image_get_data_double(resid);
04379 
04380     nspectra = cpl_image_get_nx(x_pos);
04381     nlines   = cpl_image_get_ny(x_pos);
04382 
04383     nx_resid = cpl_image_get_nx(resid);
04384     ny_resid = cpl_image_get_ny(resid);
04385 
04386     xcheb = cpl_image_new_double(nspectra, nlines, NULL, NULL);
04387     pd_xcheb = cpl_image_get_data_double(xcheb);
04388 
04389     lbound = 0.0;
04390     ubound = (cxdouble) (nx_resid - 1);
04391 
04392     for(spec=0; spec<nspectra; spec++) {
04393         for(line=0; line<nlines; line++) {
04394 
04395             indx = pd_x_pos[line*nspectra+spec];
04396 
04397             if (indx<lbound) indx = lbound;
04398             if (indx>ubound) indx = ubound;
04399 
04400             pos = (cxint) indx;
04401 
04402             pd_xcheb[line*nspectra+spec] = pd_resid[spec*nx_resid+pos];
04403 
04404         }
04405     }
04406 
04407     return xcheb;
04408 }
04409 
04410 
04428 static void
04429 giraffe_calculate_chebyshev_statistics(
04430     cpl_image     *x_pos,
04431     GiImageStack  *lines_data,
04432     cpl_image     *x_center_pos,
04433     cpl_image     *x_center_optm_cheb
04434 ){
04435 
04436     const cxchar *fctid = "giraffe_calculate_chebyshev_statistics";
04437 
04438     cxint        nlines          = 0,
04439                  nspectra        = 0,
04440                  line,
04441                  spec,
04442                  gl_per_spec,
04443                  pix,
04444                  npixels         = 0;
04445 
04446     cxdouble    *pd_goodlines    = NULL,
04447                 *pd_status       = NULL,
04448                 *pd_x_center_pos = NULL,
04449                 *pd_x_center_optm_cheb = NULL,
04450                  total_goodlines = 0.0,
04451                  numerator       = 0.0,
04452                  denominator     = 0.0,
04453                  rms             = 0.0;
04454 
04455     cpl_matrix  *lngood          = NULL;
04456 
04457     cpl_image   *goodlines       = NULL,
04458                 *status_img      = NULL;
04459 
04460 
04461     if (x_pos             ==NULL) { return; }
04462     if (lines_data        ==NULL) { return; }
04463     if (x_center_pos      ==NULL) { return; }
04464     if (x_center_optm_cheb==NULL) { return; }
04465 
04466     nlines       = cpl_image_get_nx(x_pos);
04467     nspectra     = cpl_image_get_ny(x_pos);
04468     npixels      = nspectra*nlines;
04469 
04470     goodlines    = cpl_image_new_double(nlines, nspectra, NULL, NULL);
04471     pd_goodlines = cpl_image_get_data_double(goodlines);
04472 
04473     status_img = giraffe_imagestack_get(lines_data, LF_I_STATUS);
04474     pd_status  = cpl_image_get_data_double(status_img);
04475 
04476     for (pix=0; pix<npixels;pix++) {
04477         if (pd_status[pix]>0.0)
04478             pd_goodlines[pix] = 1.0;
04479         else
04480             pd_goodlines[pix] = 0.0;
04481     }
04482 
04483     lngood = cpl_matrix_new(nlines,1);
04484 
04485     for (line=0; line<nlines; line++) {
04486         gl_per_spec = 0.0;
04487         for (spec=0; spec<nspectra; spec++) {
04488             if (pd_goodlines[spec*nlines+line] > 0.5)
04489                 gl_per_spec += 1.0;
04490         }
04491         cpl_matrix_set(lngood, line, 0, gl_per_spec);
04492     }
04493 
04494     for (line=0;line<nlines;line++)
04495         total_goodlines += cpl_matrix_get(lngood, line, 0);
04496 
04497     pd_x_center_pos = cpl_image_get_data_double(x_center_pos);
04498     pd_x_center_optm_cheb = cpl_image_get_data_double(x_center_optm_cheb);
04499 
04500     for (pix=0; pix<npixels; pix++) {
04501         if (pd_goodlines[pix]>0.5) {
04502             numerator +=
04503                 pow(pd_x_center_pos[pix] - pd_x_center_optm_cheb[pix], 2.0);
04504         }
04505     }
04506 
04507 
04508     if (total_goodlines<0.5)
04509         denominator = 1.0;
04510     else
04511         denominator = total_goodlines;
04512 
04513     rms = pow(numerator / denominator, 0.5);
04514 
04515     cpl_msg_info(
04516         fctid,
04517         "Total Wavelength Calibration Statistics : good lines %d out of %d, RMS=%12.6f",
04518         (cxint) floor(total_goodlines),
04519         npixels,
04520         rms
04521     );
04522 
04523     cpl_matrix_delete(lngood);
04524     cpl_image_delete(goodlines);
04525 
04526 }
04527 
04528 
04545 static void
04546 giraffe_calculate_statistics_entire_fit(
04547     GiImage       *x_opt_mod_resids,
04548     GiImage       *x_ref_wlens,
04549     cpl_image     *fitted_status,
04550     GiImageStack  *lines_data,
04551     cpl_image     *fitted_x_wlen
04552 ) {
04553 
04554     cpl_image *x_pos_cheb_corr    = NULL,
04555               *x_pos_cheb_delta   = NULL,
04556               *xomr_transpose     = NULL;
04557 
04558     cxdouble  *pd_x_pos_cheb_delta,
04559               *pd_fitted_status;
04560 
04561     cxint      pix,
04562                npixels;
04563 
04564     if (x_opt_mod_resids == NULL) { return; }
04565     if (x_ref_wlens      == NULL) { return; }
04566     if (fitted_status    == NULL) { return; }
04567     if (lines_data       == NULL) { return; }
04568     if (fitted_x_wlen    == NULL) { return; }
04569 
04570     xomr_transpose = giraffe_image_get(x_opt_mod_resids);
04571     cpl_image_flip_local(xomr_transpose, 1);
04572 
04573     /*
04574      *  Find residuals for reference wavelengths
04575      */
04576 
04577     x_pos_cheb_corr =
04578         giraffe_map_wavelength_to_residuals(
04579             giraffe_image_get(x_ref_wlens),
04580             xomr_transpose
04581         );
04582 
04583     /*
04584      *  Calculate delta between actual and computed values
04585      */
04586 
04587     x_pos_cheb_delta    =
04588         cpl_image_subtract(giraffe_image_get(x_ref_wlens), x_pos_cheb_corr);
04589 
04590     cpl_image_flip_local(x_pos_cheb_delta,1);
04591 
04592     pd_x_pos_cheb_delta =
04593         cpl_image_get_data_double(x_pos_cheb_delta);
04594 
04595     /*
04596      *  Disregard pixels which have a bad fit status
04597      */
04598 
04599     pd_fitted_status = cpl_image_get_data_double(fitted_status);
04600 
04601     npixels =
04602         cpl_image_get_nx(fitted_status) *
04603         cpl_image_get_ny(fitted_status);
04604 
04605     for (pix=0; pix<npixels; pix++) {
04606         if (pd_fitted_status[pix]<=0.0)
04607             pd_x_pos_cheb_delta[pix] = 0.0;
04608     }
04609 
04610     /*
04611      *  Calculate fit statistics
04612      */
04613 
04614     giraffe_calculate_chebyshev_statistics(
04615         giraffe_image_get(x_ref_wlens),
04616         lines_data,
04617         fitted_x_wlen,
04618         x_pos_cheb_delta
04619     );
04620 
04621     cpl_image_delete(x_pos_cheb_delta);
04622     cpl_image_delete(x_pos_cheb_corr);
04623 
04624 }
04625 
04626 
04627 
04663 cxint
04664 giraffe_wavelength_calibration(GiTable *result, GiExtraction *extraction,
04665                                GiLocalization *localization, GiTable *grating,
04666                                GiTable *slitgeo, GiTable *wavelengths,
04667                                GiWcalConfig *config,
04668                                GiWcalSolution *wavcoeff)
04669 {
04670 
04671     const cxchar *fctid = "giraffe_wavelength_calibration";
04672 
04673 
04674     cxint ny           = 0;
04675     cxint ext_sp_chipx = 0;
04676     cxint irefit       = 0;
04677     cxint nrefit       = 0;
04678     cxint status       = 0;
04679 
04680     cxdouble xpixsize   = 0.0;
04681     cxdouble ypixsize   = 0.0;
04682     cxdouble bias_sigma = 0.0;
04683     cxdouble pixel_per_mm     = 0.0;
04684     cxdouble lwidth0          = 0.0;
04685     cxdouble w2fwhm           = 0.0;
04686     cxdouble sep_minimum      = 0.0;
04687     cxdouble saturation_level = 0.0;
04688 
04689     cpl_plist *properties = NULL;
04690 
04691     cpl_matrix *opt_mod_params = NULL;
04692     cpl_matrix *wlen_offset    = NULL;
04693 
04694     cpl_image *_extsp = NULL;
04695     cpl_image *dummy  = NULL;
04696 
04697     GiImage *extsp     = NULL;
04698     GiImage *extsp_err = NULL;
04699     GiImage *_locy       = NULL;
04700     GiImage *_locw       = NULL;
04701 
04702     GiGrating       *grating_data       = NULL;
04703 
04704     GiSlitGeometry  *subslitfibers      = NULL;
04705 
04706 
04707 
04708     /*
04709      *  Validate input parameters...
04710      */
04711 
04712     if (result       == NULL) { return 1; }
04713     if (extraction   == NULL) { return 1; }
04714     if (localization == NULL) { return 1; }
04715     if (grating      == NULL) { return 1; }
04716     if (slitgeo      == NULL) { return 1; }
04717     if (wavelengths  == NULL) { return 1; }
04718     if (config       == NULL) { return 1; }
04719     if (wavcoeff     == NULL) { return 1; }
04720 
04721     if (extraction->spectra == NULL) { return 1; }
04722     if (extraction->error   == NULL) { return 1; }
04723     if (localization->locy  == NULL) { return 1; }
04724     if (localization->locw  == NULL) { return 1; }
04725 
04726 
04727     /*************************************************************************
04728                                     Preprocessing
04729     *************************************************************************/
04730 
04731     extsp     = extraction->spectra;
04732     extsp_err = extraction->error;
04733     _locy       = localization->locy;
04734     _locw       = localization->locw;
04735 
04736     properties  = giraffe_image_get_properties(extsp);
04737     _extsp = giraffe_image_get(extsp);
04738 
04739 
04740     /*
04741      *  Retrieve necessary values from FITS keywords
04742      */
04743 
04744     if (cpl_plist_contains(properties, GIALIAS_PIXSIZX) == TRUE) {
04745         xpixsize = cpl_plist_get_double(properties, GIALIAS_PIXSIZX);
04746     }
04747     else {
04748         cpl_msg_error(fctid, "Property (%s) not found in extracted spectra "
04749                       "image, aborting ...", GIALIAS_PIXSIZX);
04750         return 2;
04751     }
04752 
04753 
04754     if (cpl_plist_contains(properties, GIALIAS_PIXSIZY) == TRUE) {
04755         ypixsize = cpl_plist_get_double(properties, GIALIAS_PIXSIZY);
04756 
04757     }
04758     else {
04759         cpl_msg_error(fctid, "Property (%s) not found in extracted spectra "
04760                       "image, aborting ...", GIALIAS_PIXSIZY);
04761         return 2;
04762     }
04763 
04764 // <<<<
04765 
04766     {
04767         cxint ext_sp_chip_nx = -1, ext_sp_out_nx = -1, ext_sp_hc_nx;
04768 
04769         ext_sp_hc_nx = 2048; /* number of physical pixels on detector */
04770 
04771         if (cpl_plist_contains(properties, GIALIAS_CHIPX) == TRUE) {
04772             ext_sp_chip_nx = cpl_plist_get_int(properties, GIALIAS_CHIPX);
04773         }
04774 
04775         if (cpl_plist_contains(properties, GIALIAS_OUTX) == TRUE) {
04776             ext_sp_out_nx = cpl_plist_get_int(properties, GIALIAS_OUTX);
04777         }
04778         else {
04779             ext_sp_out_nx = ext_sp_hc_nx;
04780         }
04781 
04782         if ((ext_sp_chip_nx == -1) && (ext_sp_out_nx == -1)) {
04783             /* both keywords not found use hardcoded value */
04784             ext_sp_chipx = ext_sp_hc_nx;
04785             cpl_msg_warning(fctid, "Detector width FITS keywords %s and "
04786                             "%s missing, using internal value of %d pixels "
04787                             "instead", GIALIAS_CHIPX, GIALIAS_OUTX,
04788                             ext_sp_hc_nx);
04789 
04790         }
04791         else if ((ext_sp_chip_nx == -1) && (ext_sp_out_nx > -1)) {
04792             /* chip keyword not found, det keyword found, using det */
04793             ext_sp_chipx = ext_sp_out_nx;
04794             cpl_msg_warning(fctid, "Detector width FITS Keyword %s is "
04795                             "missing, using %s with value %d instead",
04796                             GIALIAS_CHIPX, GIALIAS_OUTX, ext_sp_out_nx);
04797 
04798             if (ext_sp_chipx != ext_sp_hc_nx) {
04799                 cpl_msg_warning(fctid, "Detector width read from FITS "
04800                                 "Keywords does not match internal value %d",
04801                                 ext_sp_hc_nx);
04802             }
04803 
04804         }
04805         else if ((ext_sp_chip_nx > -1) && (ext_sp_out_nx == -1)) {
04806             /* chip keyword found, det keyword not found, using chip */
04807 
04808             ext_sp_chipx = ext_sp_chip_nx;
04809 
04810             if (ext_sp_chipx != ext_sp_hc_nx) {
04811                 cpl_msg_warning(fctid, "Detector width read from FITS "
04812                                 "Keywords does not match internal value %d",
04813                                 ext_sp_hc_nx);
04814             }
04815 
04816         }
04817         else if ((ext_sp_chip_nx > -1) && (ext_sp_out_nx > -1)) {
04818             /* chip keyword found, det keyword found */
04819 
04820             ext_sp_chipx = ext_sp_chip_nx;
04821 
04822             if (ext_sp_chip_nx != ext_sp_out_nx) {
04823                 /* situation right now because of
04824                  * wrong chip keyword, use det value
04825                  */
04826 
04827                 ext_sp_chipx = ext_sp_out_nx;
04828 
04829                 cpl_msg_warning(fctid, "Detector width FITS Keyword %s "
04830                                 "value %d does not match keyword %s value "
04831                                 "%d, using %d", GIALIAS_CHIPX, ext_sp_chip_nx,
04832                                 GIALIAS_OUTX, ext_sp_out_nx, ext_sp_out_nx);
04833             }
04834 
04835             if (ext_sp_chipx != ext_sp_hc_nx) {
04836                 cpl_msg_warning(fctid, "Detector width read from FITS "
04837                                 "Keywords does not match internal value %d",
04838                                 ext_sp_hc_nx);
04839             }
04840         }
04841     }
04842 
04843 // >>>>
04844 
04845     if (cpl_plist_contains(properties, GIALIAS_BIASSIGMA) == TRUE) {
04846         bias_sigma = cpl_plist_get_double(properties, GIALIAS_BIASSIGMA);
04847     }
04848     else {
04849         cpl_msg_error(fctid, "Property (%s) not found in extracted spectra "
04850                       "image, aborting ...", GIALIAS_BIASSIGMA);
04851         return 2;
04852     }
04853 
04854     ny = cpl_image_get_ny(_extsp);
04855 
04856     if (xpixsize > 1.0) {
04857         xpixsize /= 1000.0; /* converting to microns */
04858     }
04859 
04860     if (ypixsize > 1.0) {
04861         ypixsize /= 1000.0; /* converting to microns */
04862     }
04863 
04864 
04865     /*************************************************************************
04866                                      Processing
04867     *************************************************************************/
04868 
04869     /*
04870      *  Retrieve all necessary auxilliary data i.e. Grating data and
04871      *  Slit Geometry Data.
04872      */
04873 
04874     cpl_msg_info(fctid, "Retrieving Grating Information...");
04875 
04876     grating_data = giraffe_grating_new();
04877 
04878     status = giraffe_grating_setup(grating, extsp, grating_data);
04879 
04880     if (status != 0) {
04881         cpl_msg_error(fctid, "Unable to retrieve grating data from grating "
04882                       "table, aborting...");
04883         giraffe_grating_delete(grating_data);
04884         return 3;
04885     }
04886 
04887     /*
04888      * TODO
04889      *
04890      * At this point we should be calling the function
04891      * giraffe_get_fiberlist and augment the returned table with the
04892      * information contained in the static slit geometry table.
04893      * For the time being we load all the slit geometry from a static
04894      * table...!!!
04895      *
04896      */
04897 
04898     cpl_msg_info(fctid, "Retrieving Slit Geometry Information...");
04899 
04900     subslitfibers = giraffe_slitgeometry_create(slitgeo,
04901                                                 config->fit_subslits);
04902 
04903     if (subslitfibers == NULL) {
04904         cpl_msg_error(fctid, "Unable to retrieve slit geometry data from "
04905                       "slit geometry table, aborting...");
04906 
04907         giraffe_grating_delete(grating_data);
04908         return 4;
04909     }
04910 
04911 
04912     /*
04913      *  Retrieve/Augment/Alter Wavelength Table based on the information
04914      *  we now have for the grating used and the user specified configuration
04915      */
04916 
04917     cpl_msg_info(fctid, "Retrieving Reference Wavelengths Catalog...");
04918 
04919     status = _giraffe_wavelength_setup(wavelengths, grating_data,
04920                                        config);
04921 
04922     if (status != 0) {
04923         cpl_msg_error(fctid, "Unable to retrieve Reference Wavelengths "
04924                       "Catalog, aborting...");
04925 
04926         giraffe_grating_delete(grating_data);
04927         giraffe_slitgeometry_delete(subslitfibers);
04928         return 5;
04929     }
04930 
04931 
04932     /*
04933      *  Prepare Fitting Loop
04934      *  Setup Optical Model Parameters
04935      */
04936 
04937     opt_mod_params = cpl_matrix_new(10,1);
04938 
04939     cpl_matrix_set(opt_mod_params, 0, 0, abs(ny) * config->opt_direction);
04940     cpl_matrix_set(opt_mod_params, 1, 0, xpixsize);
04941     cpl_matrix_set(opt_mod_params, 2, 0, grating_data->fcoll);
04942     cpl_matrix_set(opt_mod_params, 3, 0, grating_data->gcam);
04943     cpl_matrix_set(opt_mod_params, 4, 0, grating_data->theta);
04944     cpl_matrix_set(opt_mod_params, 5, 0, grating_data->order);
04945     cpl_matrix_set(opt_mod_params, 6, 0, grating_data->space);
04946     cpl_matrix_set(opt_mod_params, 7, 0, grating_data->sdx);
04947     cpl_matrix_set(opt_mod_params, 8, 0, grating_data->sdy);
04948     cpl_matrix_set(opt_mod_params, 9, 0, grating_data->sphi);
04949 
04950     /*************************************************************************
04951                          Fitting Loop using Search Windows
04952     *************************************************************************/
04953 
04954     nrefit       = cpl_matrix_get_ncol(config->line_widths);
04955     pixel_per_mm = abs(ny) * GI_MM_TO_NM / grating_data->band;
04956     lwidth0      = abs(ny) * grating_data->wlen0 /
04957                    ( grating_data->band * grating_data->resol );
04958     w2fwhm       = pow(2.0 * log(2.0), 0.5);
04959     sep_minimum  = 0.9;
04960 
04961     saturation_level = pow(10.0,6.0);
04962 
04963     /*
04964      * The resulting dispersion solution inherits its properties from
04965      * the extracted spectra frame
04966      */
04967 
04968     giraffe_table_set_properties(result, properties);
04969 
04970 
04971     for (irefit=0; irefit<nrefit; irefit++) {
04972 
04973         /*********************************************************************
04974                                      VARIABLES
04975         *********************************************************************/
04976 
04977         GiImage       *x_ref_wlens            = NULL,
04978                       *x_opt_mod_resids       = NULL;
04979 
04980         GiTable       *wavelengths_copy       = NULL;
04981         GiTable       *x_opt_mod_resids_table = NULL;
04982 
04983         cpl_matrix    *lines_params           = NULL,
04984                       *fit_opt_mod            = NULL;
04985 
04986         GiImageStack  *lines_data             = NULL;
04987 
04988         cpl_image     *x_wlen                 = NULL,
04989                       *fitted_x_wlen          = NULL,
04990                       *fitted_status          = NULL;
04991 
04992         cxbool         last_refit             = FALSE;
04993 
04994         cxdouble       line_width             = 0.0;
04995 
04996         cxint          i                      = 0,
04997                        ngoodlines             = 0;
04998 
04999         lmrq_params    lf_lmrq_params;
05000 
05001         GiClipParams   xws_sigma_clip;
05002         GiPolyDeg      xws_poly_deg;
05003 
05004         /********************************************************************
05005                                      PROCESSING
05006         ********************************************************************/
05007 
05008         last_refit = (irefit==(nrefit-1));
05009         line_width = cpl_matrix_get(config->line_widths, 0, irefit);
05010 
05011         cpl_msg_info(
05012             fctid,
05013             "Performing line width iteration [%d of %d], current line "
05014             "width: %12.6f",
05015             irefit + 1,
05016             nrefit,
05017             line_width
05018         );
05019 
05020         wavelengths_copy = giraffe_table_duplicate(wavelengths);
05021 
05022         /*********************************************************************
05023                                  Wavelength Crowding
05024         *********************************************************************/
05025 
05026         /*
05027          *  Eliminate all wavelengths from the wavelength table which
05028          *  are crowded i.e. to close together etc.
05029          */
05030 
05031         status =
05032             giraffe_line_elimination(
05033                 wavelengths_copy,
05034                 pixel_per_mm,
05035                 sep_minimum,
05036                 config->flux_ratio,
05037                 line_width
05038             );
05039 
05040         if (status!=0) {
05041             cpl_msg_error(fctid, "Unable to remove 'crowded' wavelengths, "
05042                                  "aborting...");
05043             giraffe_table_delete(wavelengths_copy);
05044             giraffe_grating_delete(grating_data);
05045             giraffe_slitgeometry_delete(subslitfibers);
05046             cpl_matrix_delete(opt_mod_params);
05047             return 6;
05048         }
05049 
05050         /*********************************************************************
05051                         Compute (Pixel) Position of Reference Lines
05052         *********************************************************************/
05053 
05054         /*
05055          *  Get line x-CCD position based on Optical Model.
05056          *  Image returns contains the position of a specific
05057          *  spectrum, wavelength on the extracted spectra frame!
05058          *  I.e. how many pixels along the spectrum a given wavelength is
05059          *  in the original frame.
05060          *  optModel is either xoptmod or xoptmod2.
05061          */
05062 
05063         cpl_msg_info(fctid, "Calculating position of reference lines using "
05064                      "'%s' model, %d spectra and %d wavelengths",
05065                      lmrq_models[config->opt_model].name,
05066                      cpl_matrix_get_nrow(subslitfibers->yf),
05067                      cpl_table_get_nrow(giraffe_table_get(wavelengths_copy)));
05068 
05069         x_ref_wlens = giraffe_compute_pixel_abcissa_wrapper(extsp,
05070                                                             wavelengths_copy,
05071                                                             subslitfibers,
05072                                                             opt_mod_params,
05073                                                             config->opt_model);
05074 
05075         if (x_ref_wlens==NULL) {
05076             cpl_msg_error(fctid, "Unable to compute position of reference "
05077                                  "wavelengths,  aborting...");
05078             giraffe_image_delete(x_ref_wlens);
05079             giraffe_table_delete(wavelengths_copy);
05080             giraffe_grating_delete(grating_data);
05081             giraffe_slitgeometry_delete(subslitfibers);
05082             cpl_matrix_delete(opt_mod_params);
05083             return 14;
05084         }
05085 
05086         /*********************************************************************
05087                              LMRQ Fit of Individual Lines
05088         *********************************************************************/
05089 
05090         /*
05091          *  Setup the necessary structures, based on the LMRQ model...
05092          */
05093 
05094         if ( (config->line_model == LMRQ_PSFEXP ) ||
05095              (config->line_model == LMRQ_PSFEXP2)     )
05096         {
05097 
05098             lines_params = cpl_matrix_new(8,1);
05099 
05100             cpl_matrix_set(
05101                 lines_params,
05102                 0,
05103                 0,
05104                 abs(ny) * grating_data->wlen0 /
05105                 ( 2.0 * grating_data->band * grating_data->resol )
05106             );
05107 
05108             cpl_matrix_set(lines_params, 1, 0, saturation_level);
05109             cpl_matrix_set(lines_params, 2, 0, line_width );
05110             cpl_matrix_set(lines_params, 3, 0, config->line_threshold );
05111             cpl_matrix_set(lines_params, 4, 0, config->line_offset );
05112             cpl_matrix_set(lines_params, 5, 0, (cxdouble) GIWCALLINETYPE_THARNE );
05113             cpl_matrix_set(lines_params, 6, 0, config->line_reswidratio );
05114             cpl_matrix_set(lines_params, 7, 0, config->line_widexpo );
05115 
05116         } else if (config->line_model == LMRQ_GAUSSUM) {
05117 
05118             lines_params = cpl_matrix_new(7,1);
05119 
05120             cpl_matrix_set(
05121                 lines_params,
05122                 0,
05123                 0,
05124                 abs(ny) * grating_data->wlen0 /
05125                 ( 2.0 * grating_data->band * grating_data->resol )
05126             );
05127 
05128             cpl_matrix_set(lines_params, 1, 0, saturation_level );
05129             cpl_matrix_set(lines_params, 2, 0, line_width );
05130             cpl_matrix_set(lines_params, 3, 0, config->line_threshold );
05131             cpl_matrix_set(lines_params, 4, 0, config->line_offset );
05132             cpl_matrix_set(lines_params, 5, 0, (cxdouble) GIWCALLINETYPE_THARNE );
05133             cpl_matrix_set(lines_params, 6, 0, config->line_reswidratio );
05134 
05135         } else {
05136 
05137             cpl_msg_error(fctid, "Invalid line model, aborting ...");
05138             giraffe_image_delete(x_ref_wlens);
05139             giraffe_table_delete(wavelengths_copy);
05140             giraffe_grating_delete(grating_data);
05141             giraffe_slitgeometry_delete(subslitfibers);
05142             cpl_matrix_delete(opt_mod_params);
05143             return 7;
05144         }
05145 
05146         lf_lmrq_params.imax  = config->line_niter;
05147         lf_lmrq_params.tmax  = config->line_ntest;
05148         lf_lmrq_params.dchsq = config->line_dchsq;
05149 
05150         /*
05151          *  Perform Fit of Individual Lines
05152          */
05153 
05154         lines_data =
05155             giraffe_fit_lines_lmrq_wrapper(
05156                 extsp,
05157                 extsp_err,
05158                 _locy,
05159                 x_ref_wlens,
05160                 lines_params,
05161                 lf_lmrq_params,
05162                 config->line_model
05163             );
05164 
05165         giraffe_image_delete(x_ref_wlens); x_ref_wlens = NULL;
05166 
05167         if (lines_data==NULL) {
05168             cpl_msg_error(fctid, "Line fitting produced empty result set, "
05169                                  "aborting...");
05170             cpl_matrix_delete(lines_params);
05171             giraffe_table_delete(wavelengths_copy);
05172             giraffe_grating_delete(grating_data);
05173             giraffe_slitgeometry_delete(subslitfibers);
05174             cpl_matrix_delete(opt_mod_params);
05175             return 8;
05176 
05177         }
05178 
05179         /*
05180          *  Update wavelength information in lines_data...
05181          */
05182 
05183         status =
05184             giraffe_update_wavelengths(
05185                 lines_data,
05186                 grating_data,
05187                 wavelengths_copy
05188             );
05189 
05190         if (status!=0) {
05191             cpl_msg_error(
05192                 fctid,
05193                 "Could not update wavelength information, aborting..."
05194             );
05195             giraffe_imagestack_delete(lines_data);
05196             cpl_matrix_delete(lines_params);
05197             giraffe_table_delete(wavelengths_copy);
05198             giraffe_grating_delete(grating_data);
05199             giraffe_slitgeometry_delete(subslitfibers);
05200             cpl_matrix_delete(opt_mod_params);
05201             return 9;
05202 
05203         }
05204 
05205         if (last_refit==TRUE) {
05206             fitted_status =
05207                 cpl_image_duplicate(
05208                     giraffe_imagestack_get(lines_data, LF_I_STATUS)
05209                 );
05210         }
05211 
05212         /*
05213          *  Have we found any lines?
05214          */
05215 
05216         ngoodlines = giraffe_goodlines_count(lines_data);
05217 
05218         if (ngoodlines==0) {
05219             cpl_image_delete(fitted_status);
05220             cpl_msg_error(fctid, "No good lines found, aborting...");
05221             giraffe_imagestack_delete(lines_data);
05222             cpl_matrix_delete(lines_params);
05223             giraffe_table_delete(wavelengths_copy);
05224             giraffe_grating_delete(grating_data);
05225             giraffe_slitgeometry_delete(subslitfibers);
05226             cpl_matrix_delete(opt_mod_params);
05227             return 8;
05228         }
05229 
05230         /*********************************************************************
05231                       Polynomial Fit of the PSF Width Variation
05232         *********************************************************************/
05233 
05234         {
05235             GiImage       *psf_widths       = NULL;
05236             GiTable       *psf_widths_table = NULL;
05237             GiClipParams   pxw_sigma_clip;
05238             GiPolyDeg      pxw_poly_deg;
05239 
05240             psf_widths           = giraffe_image_new(CPL_TYPE_DOUBLE);
05241             psf_widths_table     = giraffe_table_new();
05242 
05243             pxw_sigma_clip.sigma = config->pxw_clip_level;
05244             pxw_sigma_clip.niter = config->pxw_clip_niter;
05245             pxw_sigma_clip.mfrac = config->pxw_clip_mfrac;
05246 
05247             pxw_poly_deg.xdeg    = config->pxw_poly_x_deg;
05248             pxw_poly_deg.ydeg    = config->pxw_poly_y_deg;
05249             pxw_poly_deg.ncoeffs = (pxw_poly_deg.xdeg+1)*(pxw_poly_deg.ydeg+1);
05250 
05251             /*
05252              *  NOTE: psf_widths and psf_width_table are actually not used
05253              *  beyond the purpose of debugging...
05254              *  They are necessary during the calculation, but the resultant
05255              *  image and table can be discarded...
05256              */
05257 
05258             status =
05259                 giraffe_fit_psf_x_width_wrapper(
05260                     _locy,
05261                     _locw,
05262                     lines_data,
05263                     subslitfibers,
05264                     pxw_sigma_clip,
05265                     pxw_poly_deg,
05266                     psf_widths,
05267                     psf_widths_table,
05268                     config->line_model
05269                 );
05270 
05271             if (status!=0) {
05272                 cpl_msg_error(fctid, "PSF Fitting failed, aborting...");
05273                 cpl_image_delete(fitted_status);
05274                 giraffe_image_delete(psf_widths);
05275                 giraffe_table_delete(psf_widths_table);
05276                 giraffe_imagestack_delete(lines_data);
05277                 cpl_matrix_delete(lines_params);
05278                 giraffe_table_delete(wavelengths_copy);
05279                 giraffe_grating_delete(grating_data);
05280                 giraffe_slitgeometry_delete(subslitfibers);
05281                 cpl_matrix_delete(opt_mod_params);
05282                 return 10;
05283             }
05284 
05285             giraffe_table_delete(psf_widths_table);
05286             giraffe_image_delete(psf_widths);
05287         }
05288 
05289         /*********************************************************************
05290                                  Find optimal solution
05291         *********************************************************************/
05292 
05293         if (config->opt_solution==TRUE) {
05294 
05295             cpl_matrix   *opt_mod_fit_flags = NULL,
05296                          *params_result     = NULL;
05297 
05298             lmrq_params   os_lmrq_params;
05299 
05300             cxint         nfitparams        = 0;
05301 
05302             /*
05303              *  Setup structures
05304              */
05305 
05306             os_lmrq_params.imax  = config->opt_mod_niter;
05307             os_lmrq_params.tmax  = config->opt_mod_ntest;
05308             os_lmrq_params.dchsq = config->opt_mod_dchsq;
05309 
05310             opt_mod_fit_flags = cpl_matrix_new(10, 1);
05311 
05312             cpl_matrix_set(opt_mod_fit_flags, 0, 0, 0.0);
05313             cpl_matrix_set(opt_mod_fit_flags, 1, 0, 0.0);
05314             cpl_matrix_set(opt_mod_fit_flags, 2, 0, 0.0);
05315             cpl_matrix_set(opt_mod_fit_flags, 3, 0, 0.0);
05316             cpl_matrix_set(opt_mod_fit_flags, 4, 0, 0.0);
05317             cpl_matrix_set(opt_mod_fit_flags, 5, 0, 0.0);
05318             cpl_matrix_set(opt_mod_fit_flags, 6, 0, 0.0);
05319             cpl_matrix_set(opt_mod_fit_flags, 7, 0, 1.0);
05320             cpl_matrix_set(opt_mod_fit_flags, 8, 0, 1.0);
05321             cpl_matrix_set(opt_mod_fit_flags, 9, 0, 1.0);
05322 
05323             nfitparams    = cpl_matrix_get_nrow(opt_mod_fit_flags);
05324             params_result = cpl_matrix_new(1,1);
05325 
05326             /*
05327              *  Physical Optical Model Fit
05328              */
05329 
05330             status = giraffe_fit_opt_mod_wrapper(lines_data, wavelengths_copy,
05331                                                  subslitfibers, opt_mod_params,
05332                                                  opt_mod_fit_flags,
05333                                                  &os_lmrq_params,
05334                                                  config->opt_model,
05335                                                  params_result);
05336 
05337             if (status!=0) {
05338                 cpl_msg_error(fctid, "Unable to perform optical model fit, "
05339                                      "aborting...");
05340                 cpl_image_delete(fitted_status);
05341                 cpl_matrix_delete(params_result);
05342                 cpl_matrix_delete(opt_mod_fit_flags);
05343                 giraffe_imagestack_delete(lines_data);
05344                 cpl_matrix_delete(lines_params);
05345                 giraffe_table_delete(wavelengths_copy);
05346                 giraffe_grating_delete(grating_data);
05347                 giraffe_slitgeometry_delete(subslitfibers);
05348                 cpl_matrix_delete(opt_mod_params);
05349                 return 11;
05350             }
05351 
05352             /*
05353              *
05354              *  Update physical optical parameters based on fit...
05355              *
05356              */
05357 
05358             cpl_matrix_resize(opt_mod_params, nfitparams, 1);
05359 
05360             for (i=0; i<nfitparams; i++) {
05361                 cpl_matrix_set(
05362                     opt_mod_params,
05363                     i,
05364                     0,
05365                     cpl_matrix_get(params_result, i, 0)
05366                 );
05367             }
05368 
05369             /*
05370              *  Update Grating Data for next iteration of line_width
05371              */
05372 
05373             grating_data->fcoll = cpl_matrix_get(opt_mod_params, 2, 0);
05374             grating_data->gcam  = cpl_matrix_get(opt_mod_params, 3, 0);
05375             grating_data->theta = cpl_matrix_get(opt_mod_params, 4, 0);
05376             grating_data->order = cpl_matrix_get(opt_mod_params, 5, 0);
05377             grating_data->space = cpl_matrix_get(opt_mod_params, 6, 0);
05378             grating_data->sdx   = cpl_matrix_get(opt_mod_params, 7, 0);
05379             grating_data->sdy   = cpl_matrix_get(opt_mod_params, 8, 0);
05380             grating_data->sphi  = cpl_matrix_get(opt_mod_params, 9, 0);
05381 
05382             cpl_msg_info(
05383                 fctid,
05384                 "Fitted Slit Parameters : new dx,dy,dphi="
05385                 "%12.6f,%12.6f,%12.6f",
05386                 cpl_matrix_get(opt_mod_params, 7, 0),
05387                 cpl_matrix_get(opt_mod_params, 8, 0),
05388                 cpl_matrix_get(opt_mod_params, 9, 0)
05389             );
05390 
05391             cpl_matrix_delete(opt_mod_fit_flags); opt_mod_fit_flags = NULL;
05392             cpl_matrix_delete(params_result); params_result = NULL;
05393 
05394             /*
05395              *  Recompute X and Y coordinates based on the new physical optical
05396              *  model in case we asked for the optimal solution or on the initial
05397              *  optical model in case we didn't ask for the optimal solution
05398              */
05399 
05400             cpl_matrix_set(opt_mod_params, 0, 0, abs(ny) * config->opt_direction);
05401             cpl_matrix_set(opt_mod_params, 1, 0, xpixsize);
05402 
05403         }
05404 
05405         /*********************************************************************
05406                            Find corrected X and Y Coordinates
05407         *********************************************************************/
05408 
05409         /*
05410          *  Recompute X coordinates based on the new physical optical
05411          *  model in case we asked for the optimal solution or on the initial
05412          *  optical model in case we didn't ask for the optimal solution
05413          */
05414 
05415         cpl_msg_debug(
05416             fctid,
05417             "Computing corrected X Coordinates based on current "
05418             "optical model"
05419         );
05420 
05421         x_ref_wlens  = giraffe_compute_pixel_abcissa_wrapper(extsp,
05422                                                              wavelengths_copy,
05423                                                              subslitfibers,
05424                                                              opt_mod_params,
05425                                                              config->opt_model);
05426 
05427         if (x_ref_wlens==NULL) {
05428             cpl_msg_error(fctid, "Unable to compute position of reference "
05429                                  "wavelengths,  aborting...");
05430             giraffe_image_delete(x_ref_wlens);
05431             cpl_image_delete(fitted_status);
05432             giraffe_imagestack_delete(lines_data);
05433             cpl_matrix_delete(lines_params);
05434             giraffe_table_delete(wavelengths_copy);
05435             giraffe_grating_delete(grating_data);
05436             giraffe_slitgeometry_delete(subslitfibers);
05437             cpl_matrix_delete(opt_mod_params);
05438             return 14;
05439         }
05440 
05441         /*
05442          *  Store LMRQ fitted X centroids
05443          */
05444 
05445         if (last_refit==TRUE) {
05446             if ( (config->line_model == LMRQ_PSFEXP ) ||
05447                  (config->line_model == LMRQ_PSFEXP2)     )
05448             {
05449                 fitted_x_wlen =
05450                     cpl_image_duplicate(
05451                         giraffe_imagestack_get(lines_data, LF_O_PARAMS + LF_E_CENTER)
05452                     );
05453             } else if (config->line_model == LMRQ_GAUSSUM) {
05454                 fitted_x_wlen =
05455                     cpl_image_duplicate(
05456                         giraffe_imagestack_get(lines_data, LF_O_PARAMS + LF_G_CENTER)
05457                     );
05458             }
05459         }
05460 
05461         /*
05462          *  Replace x centroids positions with computed ones based
05463          *  on the current optical model
05464          */
05465 
05466         cpl_msg_debug(
05467             fctid,
05468             "Replacing position of ref. wavelengths with ones based on "
05469             "current optical model."
05470         );
05471 
05472         dummy = giraffe_imagestack_get(lines_data, LF_I_XCCD);
05473         cpl_image_delete(dummy); dummy = NULL;
05474 
05475         dummy = cpl_image_duplicate(giraffe_image_get(x_ref_wlens));
05476         cpl_image_flip_local(dummy,1);
05477 
05478         giraffe_imagestack_set(
05479             lines_data,
05480             LF_I_XCCD,
05481             dummy
05482         );
05483 
05484         /*********************************************************************
05485                   Fit of the coefficients of the wavelength solution
05486         *********************************************************************/
05487 
05488         xws_sigma_clip.sigma   = config->xws_clip_level;
05489         xws_sigma_clip.mfrac   = config->xws_clip_mfrac;
05490         xws_sigma_clip.niter   = config->xws_clip_niter;
05491 
05492         xws_poly_deg.xdeg      = config->xws_poly_x_deg;
05493         xws_poly_deg.ydeg      = config->xws_poly_y_deg;
05494         xws_poly_deg.ncoeffs   = (xws_poly_deg.xdeg+1) * (xws_poly_deg.ydeg+1);
05495 
05496         x_opt_mod_resids       = giraffe_image_new(CPL_TYPE_DOUBLE);
05497 
05498         /* FIXME: There should be no need for the variable
05499          *        x_opt_mod_resids_table we can work on result directly.
05500          *        Actually result should be part of the wavelength
05501          *        calibration result structure. This is still to be done.
05502          */
05503 
05504         x_opt_mod_resids_table = result;
05505 
05506         status =
05507             giraffe_fit_x_optm_residuals_wrapper(
05508                 _locy,
05509                 _locw,
05510                 lines_data,
05511                 subslitfibers,
05512                 xws_sigma_clip,
05513                 xws_poly_deg,
05514                 wavcoeff,
05515                 x_opt_mod_resids,
05516                 x_opt_mod_resids_table,
05517                 config,
05518                 grating_data,
05519                 line_width
05520             );
05521 
05522         if (status!=0) {
05523             cpl_msg_error(fctid, "Unable to fit coefficients of the "
05524                                  "wavelength solution, aborting...");
05525             cpl_image_delete(fitted_status);
05526             giraffe_image_delete(x_opt_mod_resids);
05527             cpl_image_delete(fitted_x_wlen);
05528             giraffe_image_delete(x_ref_wlens);
05529             cpl_matrix_delete(fit_opt_mod);
05530             giraffe_imagestack_delete(lines_data);
05531             cpl_matrix_delete(lines_params);
05532             giraffe_table_delete(wavelengths_copy);
05533             giraffe_grating_delete(grating_data);
05534             giraffe_slitgeometry_delete(subslitfibers);
05535             cpl_matrix_delete(opt_mod_params);
05536             return 12;
05537         }
05538 
05539         /*********************************************************************
05540                      Update Wavecalibration solution structure
05541         *********************************************************************/
05542 
05543         if (last_refit==TRUE) {
05544 
05545             /*
05546              *  Fill wave solution structure with remaining info,
05547              *  wavcoeff->wav_coeffs has been filled in
05548              *  giraffe_fit_x_optm_residuals_wrapper()
05549              */
05550 
05551             wavcoeff->subslitfit     = config->fit_subslits;
05552             wavcoeff->opt_mod        = config->opt_model;
05553             wavcoeff->opt_mod_params = NULL;
05554 
05555             if (wavcoeff->opt_mod==LMRQ_XOPTMOD) {
05556 
05557                 wavcoeff->opt_mod_params = cpl_matrix_new(4,1);
05558                 cpl_matrix_set(wavcoeff->opt_mod_params, 0, 0,
05559                                config->opt_direction);
05560                 cpl_matrix_set(wavcoeff->opt_mod_params, 1, 0,
05561                                grating_data->fcoll);
05562                 cpl_matrix_set(wavcoeff->opt_mod_params, 2, 0,
05563                                grating_data->gcam);
05564                 cpl_matrix_set(wavcoeff->opt_mod_params, 3, 0,
05565                                grating_data->theta);
05566 
05567 
05568             } else if (wavcoeff->opt_mod==LMRQ_XOPTMOD2) {
05569 
05570                 wavcoeff->opt_mod_params = cpl_matrix_new(7,1);
05571                 cpl_matrix_set(wavcoeff->opt_mod_params, 0, 0,
05572                                config->opt_direction);
05573                 cpl_matrix_set(wavcoeff->opt_mod_params, 1, 0,
05574                                grating_data->fcoll);
05575                 cpl_matrix_set(wavcoeff->opt_mod_params, 2, 0,
05576                                grating_data->gcam);
05577                 cpl_matrix_set(wavcoeff->opt_mod_params, 3, 0,
05578                                grating_data->theta);
05579                 cpl_matrix_set(wavcoeff->opt_mod_params, 4, 0,
05580                                grating_data->sdx);
05581                 cpl_matrix_set(wavcoeff->opt_mod_params, 5, 0,
05582                                grating_data->sdy);
05583                 cpl_matrix_set(wavcoeff->opt_mod_params, 6, 0,
05584                                grating_data->sphi);
05585 
05586             }
05587 
05588         }
05589 
05590 
05591         /*********************************************************************
05592                         Calculate Statistics for Entire Fit
05593         *********************************************************************/
05594 
05595         if (last_refit==TRUE) {
05596             giraffe_calculate_statistics_entire_fit(
05597                 x_opt_mod_resids,
05598                 x_ref_wlens,
05599                 fitted_status,
05600                 lines_data,
05601                 fitted_x_wlen
05602             );
05603         }
05604 
05605         cpl_image_delete(fitted_status);
05606         giraffe_image_delete(x_opt_mod_resids);
05607         cpl_image_delete(fitted_x_wlen);
05608         cpl_image_delete(x_wlen);
05609         cpl_matrix_delete(fit_opt_mod);
05610         giraffe_imagestack_delete(lines_data);
05611         cpl_matrix_delete(lines_params);
05612         giraffe_table_delete(wavelengths_copy);
05613         giraffe_image_delete(x_ref_wlens);
05614 
05615     } /* for (irefit=0; irefit<nrefit; irefit++) */
05616 
05617 
05618     /*************************************************************************
05619                                     Postprocessing
05620     *************************************************************************/
05621 
05622     properties = giraffe_table_get_properties(result);
05623 
05624     cpl_plist_erase(properties, "NAXIS1");
05625     cpl_plist_erase(properties, "NAXIS2");
05626 
05627 
05628     /*************************************************************************
05629                                    Deinitialization
05630     *************************************************************************/
05631 
05632     cpl_matrix_delete(wlen_offset);
05633     giraffe_grating_delete(grating_data);
05634     giraffe_slitgeometry_delete(subslitfibers);
05635     cpl_matrix_delete(opt_mod_params);
05636 
05637     return 0;
05638 
05639 }
05640 
05658 void
05659 giraffe_wavecalibration_config_add(cpl_parlist *list)
05660 {
05661 
05662     cpl_parameter *p;
05663 
05664     if (!list) {
05665         return;
05666     }
05667 
05668 
05669     p = cpl_parameter_value_new("giraffe.wcal.linewidth",
05670                                 CPL_TYPE_STRING,
05671                                 "Line widths for Line Detection Fit and "
05672                                 "Search Window, multiple widths allowed e.g. "
05673                                 "'60.0,40.0,15.0'",
05674                                 "giraffe.wcal",
05675                                 "15.0");
05676     cpl_parameter_set_alias(p, "wcal-lnwidth", NULL, NULL);
05677     cpl_parlist_append(list, p);
05678 
05679 
05680     p = cpl_parameter_value_new("giraffe.wcal.linefluxrate",
05681                                 CPL_TYPE_DOUBLE,
05682                                 "Only lines with neighbours having "
05683                                 "relative intensity < 1.0 / linefluxrate are "
05684                                 "accepted",
05685                                 "giraffe.wcal",
05686                                 50.0);
05687 
05688     cpl_parameter_set_alias(p, "wcal-lnflux", NULL, NULL);
05689     cpl_parlist_append(list, p);
05690 
05691 
05692     p = cpl_parameter_value_new("giraffe.wcal.linebright",
05693                                 CPL_TYPE_STRING,
05694                                 "Line brightness criterium: if integer "
05695                                 "select N brightest lines, if float select "
05696                                 "lines with nominal intensity > N",
05697                                 "giraffe.wcal",
05698                                 "80");
05699 
05700     cpl_parameter_set_alias(p, "wcal-lnbright", NULL, NULL);
05701     cpl_parlist_append(list, p);
05702 
05703 
05704     p = cpl_parameter_value_new("giraffe.wcal.linethresh",
05705                                 CPL_TYPE_DOUBLE,
05706                                 "Line detection threshold during the "
05707                                 "line fitting (multiple of bias sigma)",
05708                                 "giraffe.wcal",
05709                                 1.0);
05710 
05711     cpl_parameter_set_alias(p, "wcal-lnthresh", NULL, NULL);
05712     cpl_parlist_append(list, p);
05713 
05714 
05715     p = cpl_parameter_value_new("giraffe.wcal.lineoffset",
05716                                 CPL_TYPE_DOUBLE,
05717                                 "Accepted difference: position of "
05718                                 "(raw maximum - fit)",
05719                                 "giraffe.wcal",
05720                                 10.0);
05721 
05722     cpl_parameter_set_alias(p, "wcal-lnoffset", NULL, NULL);
05723     cpl_parlist_append(list, p);
05724 
05725 
05726     p = cpl_parameter_value_new("giraffe.wcal.lineniter",
05727                                 CPL_TYPE_INT,
05728                                 "Line Detection Fit: Maximum number of "
05729                                 "iterations",
05730                                 "giraffe.wcal",
05731                                 50);
05732 
05733     cpl_parameter_set_alias(p, "wcal-lnniter", NULL, NULL);
05734     cpl_parlist_append(list, p);
05735 
05736 
05737     p = cpl_parameter_value_new("giraffe.wcal.linentest",
05738                                 CPL_TYPE_INT,
05739                                 "Line Detection Fit: Maximum number of "
05740                                 "tests",
05741                                 "giraffe.wcal",
05742                                 7);
05743 
05744     cpl_parameter_set_alias(p, "wcal-lnntest", NULL, NULL);
05745     cpl_parlist_append(list, p);
05746 
05747 
05748     p = cpl_parameter_value_new("giraffe.wcal.linedchisq",
05749                                 CPL_TYPE_DOUBLE,
05750                                 "Line Detection Fit: Maximum chisq "
05751                                 "difference for test",
05752                                 "giraffe.wcal",
05753                                 0.0001);
05754 
05755     cpl_parameter_set_alias(p, "wcal-lndchisq", NULL, NULL);
05756     cpl_parlist_append(list, p);
05757 
05758 
05759     p = cpl_parameter_enum_new("giraffe.wcal.linemodel",
05760                                CPL_TYPE_STRING,
05761                                "Line Detection Fit: Line profile model",
05762                                "giraffe.wcal",
05763                                "psfexp", 3, "psfexp", "psfexp2", "gausssum");
05764 
05765     cpl_parameter_set_alias(p, "wcal-lnmodel", NULL, NULL);
05766     cpl_parlist_append(list, p);
05767 
05768 
05769     p = cpl_parameter_value_new("giraffe.wcal.linereswid",
05770                                 CPL_TYPE_DOUBLE,
05771                                 "Line Detection Fit: Line Width to Resolution "
05772                                 "Width Conversion factor",
05773                                 "giraffe.wcal",
05774                                 0.5);
05775 
05776     cpl_parameter_set_alias(p, "wcal-lnreswid", NULL, NULL);
05777     cpl_parlist_append(list, p);
05778 
05779 
05780     p = cpl_parameter_value_new("giraffe.wcal.lineexpwid",
05781                                 CPL_TYPE_DOUBLE,
05782                                 "Line Detection Fit: Exponential line "
05783                                 "profile exponent",
05784                                 "giraffe.wcal",
05785                                 3.0);
05786 
05787     cpl_parameter_set_alias(p, "wcal-lnexpwid", NULL, NULL);
05788     cpl_parlist_append(list, p);
05789 
05790 
05791     p = cpl_parameter_value_new("giraffe.wcal.optsol",
05792                                 CPL_TYPE_BOOL,
05793                                 "Optical Model Fit: Fit optical model "
05794                                 "parameters",
05795                                 "giraffe.wcal",
05796                                 TRUE);
05797 
05798     cpl_parameter_set_alias(p, "wcal-optsol", NULL, NULL);
05799     cpl_parlist_append(list, p);
05800 
05801 
05802     p = cpl_parameter_value_new("giraffe.wcal.optdir",
05803                                 CPL_TYPE_INT,
05804                                 "Optical Model Fit: Dispersion direction",
05805                                 "giraffe.wcal",
05806                                 1);
05807 
05808     cpl_parameter_set_alias(p, "wcal-optdir", NULL, NULL);
05809     cpl_parlist_append(list, p);
05810 
05811 
05812     p = cpl_parameter_enum_new("giraffe.wcal.optmodel",
05813                                CPL_TYPE_STRING,
05814                                "Optical Model Fit: Optical model",
05815                                "giraffe.wcal",
05816                                "xoptmod2", 2, "xoptmod", "xoptmod2");
05817 
05818     cpl_parameter_set_alias(p, "wcal-optmodel", NULL, NULL);
05819     cpl_parlist_append(list, p);
05820 
05821 
05822     p = cpl_parameter_value_new("giraffe.wcal.optniter",
05823                                 CPL_TYPE_INT,
05824                                 "Optical Model Fit: Maximum number of "
05825                                 "iterations",
05826                                 "giraffe.wcal",
05827                                 50);
05828 
05829     cpl_parameter_set_alias(p, "wcal-optniter", NULL, NULL);
05830     cpl_parlist_append(list, p);
05831 
05832 
05833     p = cpl_parameter_value_new("giraffe.wcal.optntest",
05834                                 CPL_TYPE_INT,
05835                                 "Optical Model Fit: Maximum number of "
05836                                 "tests",
05837                                 "giraffe.wcal",
05838                                 7);
05839 
05840     cpl_parameter_set_alias(p, "wcal-optntest", NULL, NULL);
05841     cpl_parlist_append(list, p);
05842 
05843 
05844     p = cpl_parameter_value_new("giraffe.wcal.optdchisq",
05845                                 CPL_TYPE_DOUBLE,
05846                                 "Optical Model Fit: Maximum number of chisq "
05847                                 "difference tests",
05848                                 "giraffe.wcal",
05849                                 0.0001);
05850 
05851     cpl_parameter_set_alias(p, "wcal-optdchisq", NULL, NULL);
05852     cpl_parlist_append(list, p);
05853 
05854 
05855     p = cpl_parameter_value_new("giraffe.wcal.subslfit",
05856                                 CPL_TYPE_BOOL,
05857                                 "Optical Model Fit: Use subslit geometry "
05858                                 "'true' or whole slit 'false'",
05859                                 "giraffe.wcal",
05860                                 FALSE);
05861 
05862     cpl_parameter_set_alias(p, "wcal-ssfit", NULL, NULL);
05863     cpl_parlist_append(list, p);
05864 
05865 
05866     p = cpl_parameter_value_new("giraffe.wcal.xwsigma",
05867                                 CPL_TYPE_DOUBLE,
05868                                 "PSF Width Fitting: Sigma Clipping: Maximum "
05869                                 "multiple of sigma",
05870                                 "giraffe.wcal",
05871                                 2.5);
05872 
05873     cpl_parameter_set_alias(p, "wcal-xwsigma", NULL, NULL);
05874     cpl_parlist_append(list, p);
05875 
05876 
05877     p = cpl_parameter_value_new("giraffe.wcal.xwniter",
05878                                 CPL_TYPE_INT,
05879                                 "PSF Width Fitting: Sigma Clipping: Maximum "
05880                                 "number of iterations",
05881                                 "giraffe.wcal",
05882                                 10);
05883 
05884     cpl_parameter_set_alias(p, "wcal-xwniter", NULL, NULL);
05885     cpl_parlist_append(list, p);
05886 
05887 
05888     p = cpl_parameter_value_new("giraffe.wcal.xwmfrac",
05889                                 CPL_TYPE_DOUBLE,
05890                                 "PSF Width Fitting: Sigma Clipping: Minimum "
05891                                 "fraction of points accepted/total "
05892                                 "[0.0...1.0]",
05893                                 "giraffe.wcal",
05894                                 0.9);
05895 
05896     cpl_parameter_set_alias(p, "wcal-xwmfrac", NULL, NULL);
05897     cpl_parlist_append(list, p);
05898 
05899 
05900     p = cpl_parameter_value_new("giraffe.wcal.xworder",
05901                                 CPL_TYPE_STRING,
05902                                 "PSF Width Fitting: X and Y polynomial order "
05903                                 "for x-width chebyshev fit",
05904                                 "giraffe.wcal",
05905                                 "2,2");
05906 
05907     cpl_parameter_set_alias(p, "wcal-xworder", NULL, NULL);
05908     cpl_parlist_append(list, p);
05909 
05910 
05911     p = cpl_parameter_value_new("giraffe.wcal.wssigma",
05912                                 CPL_TYPE_DOUBLE,
05913                                 "Chebyshev Correction Fit: Sigma Clipping: "
05914                                 "Maximum multiple of sigma",
05915                                 "giraffe.wcal",
05916                                 200.0);
05917 
05918     cpl_parameter_set_alias(p, "wcal-wssigma", NULL, NULL);
05919     cpl_parlist_append(list, p);
05920 
05921 
05922     p = cpl_parameter_value_new("giraffe.wcal.wsniter",
05923                                 CPL_TYPE_INT,
05924                                 "Chebyshev Correction Fit: Sigma Clipping: "
05925                                 "Maximum number of iterations",
05926                                 "giraffe.wcal",
05927                                 10);
05928 
05929     cpl_parameter_set_alias(p, "wcal-wsniter", NULL, NULL);
05930     cpl_parlist_append(list, p);
05931 
05932 
05933     p = cpl_parameter_value_new("giraffe.wcal.wsmfrac",
05934                                 CPL_TYPE_DOUBLE,
05935                                 "Chebyshev Correction Fit: Sigma Clipping: "
05936                                 "Minimum fraction of points accepted/total "
05937                                 "[0.0...1.0]",
05938                                 "giraffe.wcal",
05939                                 0.9);
05940 
05941     cpl_parameter_set_alias(p, "wcal-wsmfrac", NULL, NULL);
05942     cpl_parlist_append(list, p);
05943 
05944 
05945     p = cpl_parameter_value_new("giraffe.wcal.wsorder",
05946                                 CPL_TYPE_STRING,
05947                                 "Chebyshev Correction Fit: X and Y polynomial "
05948                                 "order wavelength chebyshev correction",
05949                                 "giraffe.wcal",
05950                                 "6,4");
05951 
05952     cpl_parameter_set_alias(p, "wcal-wsorder", NULL, NULL);
05953     cpl_parlist_append(list, p);
05954 
05955 
05956     p = cpl_parameter_value_new("giraffe.wcal.lwlen",
05957                                 CPL_TYPE_STRING,
05958                                 "Line Detection Fit: (minimum,maximum) "
05959                                 "wavelength to use during fit [nm]",
05960                                 "giraffe.wcal",
05961                                 "0.0,0.0");
05962 
05963     cpl_parameter_set_alias(p, "wcal-wlrange", NULL, NULL);
05964     cpl_parlist_append(list, p);
05965 
05966     return;
05967 
05968 }
05969 
05983 GiWcalConfig*
05984 giraffe_wavecalibration_config_create(cpl_parlist *list)
05985 {
05986 
05987     const cxchar *fctid = "giraffe_wcal_config_create";
05988 
05989     const cxchar *delim1 = ",";
05990 
05991     cxchar *tmp_ref_value = NULL;
05992     cxchar **widths = NULL;
05993 
05994     cxint i;
05995     cxint scanlen;
05996     cxint count = 0;
05997 
05998     cxbool f_error = FALSE;
05999     cxbool f_params_invalid = FALSE;
06000     cxbool f_dot_found = FALSE;
06001 
06002 
06003     cpl_parameter *p = NULL;
06004 
06005     GiWcalConfig *config = NULL;
06006 
06007 
06008     if (!list) {
06009         return NULL;
06010     }
06011 
06012     config = cx_calloc(1, sizeof *config);
06013 
06014 
06015     /*
06016      *  Set configuration data structure to sensible defaults...
06017      */
06018 
06019     config->line_widths      = NULL;
06020     config->flux_ratio       = 0.0;
06021     config->bright_threshold = CX_MAXDOUBLE;
06022     config->bright_count     = CX_MAXINT;
06023     config->line_threshold   = 0.0;
06024     config->line_offset      = 0.0;
06025     config->line_niter       = 0;
06026     config->line_ntest       = 0;
06027     config->line_model       = LMRQ_UNDEFINED;
06028     config->line_dchsq       = 0.0;
06029     config->line_reswidratio = 0.0;
06030     config->line_widexpo     = 0.0;
06031     config->opt_solution     = TRUE;
06032     config->opt_direction    = 0;
06033     config->opt_model        = LMRQ_UNDEFINED;
06034     config->fit_subslits     = FALSE;
06035     config->opt_mod_niter    = 0;
06036     config->opt_mod_ntest    = 0;
06037     config->opt_mod_dchsq    = 0.0;
06038     config->xws_clip_level   = 0.0;
06039     config->xws_clip_niter   = 0;
06040     config->xws_clip_mfrac   = 0.0;
06041     config->pxw_clip_level   = 0.0;
06042     config->pxw_clip_niter   = 0;
06043     config->pxw_clip_mfrac   = 0.0;
06044     config->pxw_poly_x_deg   = 0;
06045     config->pxw_poly_y_deg   = 0;
06046     config->xws_poly_x_deg   = 0;
06047     config->xws_poly_y_deg   = 0;
06048     config->range_wlen_min   = 0.0;
06049     config->range_wlen_max   = 0.0;
06050 
06051     /*
06052      *  Retrieve parameter values...
06053      */
06054 
06055     p = cpl_parlist_find(list, "giraffe.wcal.linewidth");
06056     tmp_ref_value = cpl_parameter_get_string(p);
06057 
06058     if (tmp_ref_value) {
06059 
06060         cxint    count   = 0;
06061         cxint    scanlen = 0;
06062         cxint    i;
06063         cxdouble tmp_width;
06064 
06065         widths  = cx_strsplit(tmp_ref_value, ",", 255);
06066 
06067         while (widths[count]!=NULL && count<255) {
06068             count++;
06069         }
06070 
06071         config->line_widths = cpl_matrix_new(1, count);
06072 
06073         for (i=0; i<count; i++) {
06074             scanlen = sscanf(widths[i], " %le ", &(tmp_width));
06075             cpl_matrix_set(config->line_widths, 0, i, tmp_width);
06076             if (scanlen!=1)
06077                 f_error = TRUE;
06078         }
06079 
06080         if (f_error==TRUE) {
06081             cpl_matrix_delete(config->line_widths); config->line_widths = NULL;
06082         }
06083 
06084         cx_strfreev(widths); widths = NULL;
06085 
06086     }
06087 
06088     p = cpl_parlist_find(list, "giraffe.wcal.linefluxrate");
06089     config->flux_ratio = cpl_parameter_get_double(p);
06090 
06091     p = cpl_parlist_find(list, "giraffe.wcal.linebright");
06092     tmp_ref_value = cpl_parameter_get_string(p);
06093 
06094     for (i=0; i<(cxint)strlen(tmp_ref_value); i++) {
06095         if (tmp_ref_value[i]=='.')
06096             f_dot_found = TRUE;
06097     }
06098 
06099     if (f_dot_found==TRUE) {
06100         scanlen = sscanf(tmp_ref_value, " %le ", &config->bright_threshold);
06101     } else {
06102         scanlen = sscanf(tmp_ref_value, " %d ",  &config->bright_count);
06103     }
06104 
06105     p = cpl_parlist_find(list, "giraffe.wcal.linethresh");
06106     config->line_threshold = cpl_parameter_get_double(p);
06107 
06108     p = cpl_parlist_find(list, "giraffe.wcal.lineoffset");
06109     config->line_offset = cpl_parameter_get_double(p);
06110 
06111     p = cpl_parlist_find(list, "giraffe.wcal.lineniter");
06112     config->line_niter = cpl_parameter_get_int(p);
06113 
06114     p = cpl_parlist_find(list, "giraffe.wcal.linentest");
06115     config->line_ntest = cpl_parameter_get_int(p);
06116 
06117     p = cpl_parlist_find(list, "giraffe.wcal.linemodel");
06118     tmp_ref_value = cpl_parameter_get_string(p);
06119 
06120     if (strcmp(tmp_ref_value, "psfexp")==0) {
06121         config->line_model = LMRQ_PSFEXP;
06122     }
06123     if (strcmp(tmp_ref_value, "psfexp2")==0) {
06124         config->line_model = LMRQ_PSFEXP2;
06125     }
06126     if (strcmp(tmp_ref_value, "gausssum")==0) {
06127         config->line_model = LMRQ_GAUSSUM;
06128     }
06129 
06130     p = cpl_parlist_find(list, "giraffe.wcal.linedchisq");
06131     config->line_dchsq = cpl_parameter_get_double(p);
06132 
06133     p = cpl_parlist_find(list, "giraffe.wcal.linereswid");
06134     config->line_reswidratio = cpl_parameter_get_double(p);
06135 
06136     p = cpl_parlist_find(list, "giraffe.wcal.lineexpwid");
06137     config->line_widexpo = cpl_parameter_get_double(p);
06138 
06139     p = cpl_parlist_find(list, "giraffe.wcal.optsol");
06140     config->opt_solution = cpl_parameter_get_bool(p);
06141 
06142     p = cpl_parlist_find(list, "giraffe.wcal.optdir");
06143     config->opt_direction = cpl_parameter_get_int(p);
06144 
06145     p = cpl_parlist_find(list, "giraffe.wcal.optmodel");
06146     tmp_ref_value = cpl_parameter_get_string(p);
06147 
06148     if (strcmp(tmp_ref_value, "xoptmod")==0) {
06149         config->opt_model = LMRQ_XOPTMOD;
06150     }
06151     if (strcmp(tmp_ref_value, "xoptmod2")==0) {
06152         config->opt_model = LMRQ_XOPTMOD2;
06153     }
06154 
06155     p = cpl_parlist_find(list, "giraffe.wcal.subslfit");
06156     config->fit_subslits = cpl_parameter_get_bool(p);
06157 
06158     p = cpl_parlist_find(list, "giraffe.wcal.optniter");
06159     config->opt_mod_niter = cpl_parameter_get_int(p);
06160 
06161     p = cpl_parlist_find(list, "giraffe.wcal.optntest");
06162     config->opt_mod_ntest = cpl_parameter_get_int(p);
06163 
06164     p = cpl_parlist_find(list, "giraffe.wcal.optdchisq");
06165     config->opt_mod_dchsq = cpl_parameter_get_double(p);
06166 
06167     p = cpl_parlist_find(list, "giraffe.wcal.wssigma");
06168     config->xws_clip_level = cpl_parameter_get_double(p);
06169 
06170     p = cpl_parlist_find(list, "giraffe.wcal.wsniter");
06171     config->xws_clip_niter = cpl_parameter_get_int(p);
06172 
06173     p = cpl_parlist_find(list, "giraffe.wcal.wsmfrac");
06174     config->xws_clip_mfrac = cpl_parameter_get_double(p);
06175 
06176     p = cpl_parlist_find(list, "giraffe.wcal.xwsigma");
06177     config->pxw_clip_level = cpl_parameter_get_double(p);
06178 
06179     p = cpl_parlist_find(list, "giraffe.wcal.xwniter");
06180     config->pxw_clip_niter = cpl_parameter_get_int(p);
06181 
06182     p = cpl_parlist_find(list, "giraffe.wcal.xwmfrac");
06183     config->pxw_clip_mfrac = cpl_parameter_get_double(p);
06184 
06185     p = cpl_parlist_find(list, "giraffe.wcal.xworder");
06186     tmp_ref_value = cpl_parameter_get_string(p);
06187 
06188     count   = 0;
06189     scanlen = 0;
06190     widths  = cx_strsplit(tmp_ref_value, delim1, 255);
06191 
06192     while (widths[count]!=NULL && count<255) {
06193         count++;
06194     }
06195 
06196     if (count==2) {
06197         scanlen = sscanf(widths[0], " %d ", &(config->pxw_poly_x_deg));
06198         scanlen = sscanf(widths[1], " %d ", &(config->pxw_poly_y_deg));
06199     }
06200 
06201     cx_strfreev(widths); widths = NULL;
06202 
06203     p = cpl_parlist_find(list, "giraffe.wcal.wsorder");
06204     tmp_ref_value = cpl_parameter_get_string(p);
06205 
06206     count   = 0;
06207     scanlen = 0;
06208     widths  = cx_strsplit(tmp_ref_value, delim1, 255);
06209 
06210     while (widths[count]!=NULL && count<255) {
06211         count++;
06212     }
06213 
06214     if (count==2) {
06215         scanlen = sscanf(widths[0], " %d ", &(config->xws_poly_x_deg));
06216         scanlen = sscanf(widths[1], " %d ", &(config->xws_poly_y_deg));
06217     }
06218 
06219     cx_strfreev(widths); widths = NULL;
06220 
06221     p = cpl_parlist_find(list, "giraffe.wcal.lwlen");
06222     tmp_ref_value = cpl_parameter_get_string(p);
06223 
06224     count   = 0;
06225     scanlen = 0;
06226     widths  = cx_strsplit(tmp_ref_value, delim1, 255);
06227 
06228     while (widths[count]!=NULL && count<255) {
06229         count++;
06230     }
06231 
06232     if (count==2) {
06233         scanlen = sscanf(widths[0], " %le ", &(config->range_wlen_min));
06234         scanlen = sscanf(widths[1], " %le ", &(config->range_wlen_max));
06235     }
06236 
06237     cx_strfreev(widths); widths = NULL;
06238 
06239     /*
06240      *  Ok... unraveled all the values... now check them...
06241      */
06242 
06243     if (cpl_matrix_get_ncol(config->line_widths)==0) {
06244         cpl_msg_error(fctid, "Invalid line widths set..." );
06245         f_params_invalid = TRUE;
06246     }
06247 
06248     if ( (config->bright_threshold>=(CX_MAXDOUBLE/2.0)) &&
06249          (config->bright_count>=(CX_MAXINT/2)         )      ) {
06250         cpl_msg_error(fctid, "Invalid line threshold..." );
06251         f_params_invalid = TRUE;
06252     }
06253 
06254     if (config->line_model==LMRQ_UNDEFINED) {
06255         cpl_msg_error(fctid, "Invalid Levenberg Marquardt Model..." );
06256         f_params_invalid = TRUE;
06257     }
06258 
06259     if ((config->opt_direction!=1)&&(config->opt_direction!=-1)) {
06260         cpl_msg_error(fctid, "Invalid Optical Model direction..." );
06261         f_params_invalid = TRUE;
06262     }
06263 
06264     if (config->opt_model==LMRQ_UNDEFINED) {
06265         cpl_msg_error(fctid, "Invalid Optical Model..." );
06266         f_params_invalid = TRUE;
06267     }
06268 
06269     if (f_params_invalid==TRUE) {
06270         giraffe_wavecalibration_config_destroy(config);
06271         config = NULL;
06272     }
06273 
06274     return config;
06275 
06276 }
06277 
06292 void
06293 giraffe_wavecalibration_config_destroy(GiWcalConfig *config)
06294 {
06295 
06296     if (config) {
06297 
06298         if (config->line_widths)
06299             cpl_matrix_delete(config->line_widths);
06300 
06301         cx_free(config);
06302         config = NULL;
06303 
06304     }
06305 
06306     return;
06307 }

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:44 2008 by doxygen 1.4.6 written by Dimitri van Heesch, © 1997-2004