GIRAFFE Pipeline Reference Manual

giwavecalib.c

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

This file is part of the GIRAFFE Pipeline Reference Manual 2.8.8.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Fri Mar 4 10:50:28 2011 by doxygen 1.6.3 written by Dimitri van Heesch, © 1997-2004