isaac_spc_jitter.c

00001 /* $Id: isaac_spc_jitter.c,v 1.94 2013-03-12 08:06:48 llundin Exp $
00002  *
00003  * This file is part of the ISAAC Pipeline
00004  * Copyright (C) 2002,2003 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  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: llundin $
00023  * $Date: 2013-03-12 08:06:48 $
00024  * $Revision: 1.94 $
00025  * $Name: not supported by cvs2svn $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*-----------------------------------------------------------------------------
00033                                 Includes
00034  -----------------------------------------------------------------------------*/
00035 
00036 #include <cpl.h>
00037 
00038 #include "irplib_plugin.h"
00039 #include "irplib_utils.h"
00040 #include "irplib_stdstar.h"
00041 #include "irplib_spectrum.h"
00042 
00043 #include "isaac_utils.h"
00044 #include "isaac_wavelength.h"
00045 #include "isaac_physicalmodel.h"
00046 #include "isaac_pfits.h"
00047 #include "isaac_dfs.h"
00048 
00049 #include <string.h>
00050 #include <math.h>
00051 
00052 /*-----------------------------------------------------------------------------
00053                                 Define
00054  -----------------------------------------------------------------------------*/
00055 
00056 #define RECIPE_STRING "isaac_spc_jitter"
00057 
00058 #define ISAAC_SPC_JITTER_OFFSET_ERR     10
00059 
00060 #define KEYSIZE 512
00061 
00062 #define CENT_WL_BAND_Z  0.9
00063 #define CENT_WL_BAND_SZ 1.06
00064 #define CENT_WL_BAND_J  1.25
00065 #define CENT_WL_BAND_H  1.65
00066 #define CENT_WL_BAND_K  2.2
00067 #define CENT_WL_BAND_SL 3.78
00068 #define CENT_WL_BAND_M  4.78
00069 
00070 #define ISAAC_MIN(A,B) ((A) < (B) ? (A) : (B))
00071 
00072 #define isaac_plot_manpage                                      \
00073     "The recipe can produce a number of predefined plots. "     \
00074     "Zero means that none of the plots are produced, while "    \
00075     "increasing values (e.g. 1 or 2) increases the number "     \
00076     "of plots produced. If the plotting fails a warning is "    \
00077     "produced, and the recipe continues. "                      \
00078     "The default behaviour of the plotting is to use "          \
00079     "gnuplot (with option -persist). The recipe currently "     \
00080     "produces 1D-plots using gnuplot commands. The recipe "     \
00081     "user can control the actual plotting-command used by "     \
00082     "the recipe to create the plot by setting the "             \
00083     "environment variable CPL_PLOTTER. Currently, if "          \
00084     "CPL_PLOTTER "                                              \
00085     "is set it must contain the string 'gnuplot'. Setting "     \
00086     "it to 'cat > my_gnuplot_$$.txt' causes a number of "       \
00087     "ASCII-files to be created, which each produce a plot "     \
00088     "when given as standard input to gnuplot (e.g. later "      \
00089     "or on a different computer). A finer control of the "      \
00090     "plotting options can be obtained by writing an "           \
00091     "executable script, e.g. my_gnuplot.pl, that "              \
00092     "executes gnuplot after setting the desired gnuplot "       \
00093     "options (e.g. set terminal pslatex color) "                \
00094     "and then setting CPL_PLOTTER to my_gnuplot.pl. "           \
00095     "The predefined plots include plotting of images. "         \
00096     "Images can be plotted not only with gnuplot, but also "    \
00097     "using the pnm format. This is controlled with the "        \
00098     "environment variable CPL_IMAGER. If CPL_IMAGER "           \
00099     "is set to a string that does not contain the word "        \
00100     "gnuplot, the recipe will generate the plot in pnm "        \
00101     "format. E.g. setting CPL_IMAGER to "                       \
00102     "'display - &' will produce a gray-scale image "            \
00103     "using the image viewer display."
00104 
00105 
00106 
00107 /*-----------------------------------------------------------------------------
00108                             Private Function prototypes
00109  -----------------------------------------------------------------------------*/
00110 
00111 static cpl_image ** isaac_spc_jitter_combine(const cpl_frameset *, const char *, 
00112         const char *, const char *, const char *);
00113 static cpl_imagelist * isaac_spc_jitter_load(const cpl_frameset *);
00114 static cpl_vector * isaac_spc_jitter_get_offsets(const cpl_frameset *);
00115 static int * isaac_spc_jitter_classif(const cpl_vector *, int *);
00116 static int off_comp(double, double, double);
00117 static cpl_imagelist * isaac_spc_jitter_saa_groups(cpl_imagelist *,
00118         cpl_vector *, int *, int, cpl_vector **);
00119 static int isaac_spc_jitter_wavecal(const char *, const cpl_image *,
00120                                     const char *, const cpl_frameset *);
00121 static cpl_imagelist * isaac_spc_jitter_nodded(cpl_imagelist *, cpl_vector *, 
00122         cpl_vector **);
00123 static cpl_imagelist * isaac_spc_jitter_distor(cpl_imagelist *, const char *, 
00124         const char *);
00125 static double isaac_spc_jitter_refine_offset(const cpl_image *,
00126                                              const cpl_image *);
00127 static cpl_table * isaac_spc_jitter_extract(const cpl_image *);
00128 static int isaac_spc_jitter_std(const char *, const char *, const cpl_frame *, 
00129         cpl_table *, double);
00130 static cpl_error_code isaac_spc_jitter_flat(cpl_imagelist *, const char *);
00131 static cpl_error_code isaac_spc_jitter_save(cpl_frameset *, const cpl_image *,
00132                                             const cpl_image *,
00133                                             const cpl_table *,
00134                                             const cpl_parameterlist *);
00135 
00136 cpl_recipe_define(isaac_spc_jitter, ISAAC_BINARY_VERSION,
00137                   "Lars Lundin", PACKAGE_BUGREPORT, "2002,2003, 2008", 
00138                   "ISAAC Spectro jitter recipe",
00139                   RECIPE_STRING " -- ISAAC spectro jitter recipe\n"
00140                   "The files listed in the Set Of Frames (sof-file) " 
00141                   "must be tagged:\n"
00142                   "Observation in nodding mode:\n"
00143                   "\traw-file.fits "ISAAC_SPC_JITTER_NODOBJ_RAW" or\n"
00144                   "\traw-file.fits "ISAAC_SPC_JITTER_NODSKY_RAW"\n"
00145                   "Observation in chopping mode:\n"
00146                   "\traw-file.fits "ISAAC_SPC_JITTER_CHOP_RAW" or\n"
00147                   "Calibration (standard star) in nodding mode:\n"
00148                   "\traw-file.fits "ISAAC_SPC_RESPFUNC_RAW" or\n"
00149                   "\traw-file.fits "ISAAC_SPC_RESPFUNC_OBJ_RAW" or\n"
00150                   "\traw-file.fits "ISAAC_SPC_RESPFUNC_SKY_RAW"\n"
00151                   "\traw-file.fits "ISAAC_SPC_RESPFUNC_FLUX_RAW"\n"
00152                   "Calibration (standard star) in chopping mode:\n"
00153                   "\traw-file.fits "ISAAC_SPC_JITTER_CHOP_CAL_RAW"\n"
00154                   "Calibration files:\n"
00155                   "\toh.fits "ISAAC_CALPRO_OH_CAT" or\n"
00156                   "\tflat-file.fits "ISAAC_CALIB_SPFLAT" or\n"
00157                   "\tflat-file.fits "ISAAC_CALIB_LW_SPFLAT" or\n"
00158                   "\tarc-file.fits "ISAAC_CALIB_ARC" or\n"
00159                   "\tarc-file.fits "ISAAC_CALIB_LW_ARC" or\n"
00160                   "\tstartrace-file.fits "ISAAC_CALIB_STARTRACE" or\n"
00161                   "\tstartrace-file.fits "ISAAC_CALIB_LW_STARTRACE" or\n"
00162                   "\tsed-file.fits "ISAAC_CALIB_SED" or\n"
00163                   "\tstdstars-file.fits "ISAAC_CALIB_STDSTARS"\n");
00164 
00165 /*-----------------------------------------------------------------------------
00166                             Static variables
00167  -----------------------------------------------------------------------------*/
00168 
00169 static struct {
00170     /* Inputs */
00171     int             arm;
00172     int             plot;
00173     int             oddeven;
00174     /* wavecal_in : 0 for physical model, 1 for sky, 2 for arc table */
00175     int             wavecal_in;
00176     int             wavecal_rej_bottom;
00177     int             wavecal_rej_top;
00178     int             wavecal_rej_left;
00179     int             wavecal_rej_right;
00180     int             max_offset;
00181     int             saa_refine;
00182     double          saa_rej_high;
00183     double          saa_rej_low;
00184     int             extr_spec_pos;
00185     int             extr_spec_width;
00186     int             extr_sky_hi_width;
00187     int             extr_sky_lo_width;
00188     int             extr_sky_hi_dist;
00189     int             extr_sky_lo_dist;
00190     int             std_mode;
00191     double          std_magnitude;
00192     /* Outputs */
00193     /* wavecal_out : 0 for physical model, 1 for sky, 2 for arc table */
00194     int             chopping;
00195     cpl_vector  *   throws;
00196     cpl_vector  *   intensities;
00197     char            filter[KEYSIZE];
00198     char            filter_ref[KEYSIZE];
00199     char          * starname;
00200     char          * sptype;
00201     int             wavecal_out;
00202     double          wavecal_cc;
00203     double          wavecal_a0;
00204     double          wavecal_a1;
00205     double          wavecal_a2;
00206     double          wavecal_a3;
00207 } isaac_spc_jitter_config;
00208 
00209 
00210 /*-----------------------------------------------------------------------------
00211                                 Functions code
00212  -----------------------------------------------------------------------------*/
00213 
00214 /*----------------------------------------------------------------------------*/
00222 /*----------------------------------------------------------------------------*/
00223 static
00224 cpl_error_code isaac_spc_jitter_fill_parameterlist(cpl_parameterlist * self)
00225 {
00226     const char * context = PACKAGE "." RECIPE_STRING;
00227     cpl_error_code err;
00228 
00229     cpl_ensure_code(self, CPL_ERROR_NULL_INPUT);
00230 
00231     /* Fill the parameters list */
00232 
00233 
00234     /* --oddeven */
00235     err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
00236                                         "oddeven", CPL_FALSE, NULL, context,
00237                                         "Flag to correct the oddeven column "
00238                                         "effect");
00239     cpl_ensure_code(!err, err);
00240 
00241     /* --wavecal */
00242     err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
00243                                           "wavecal", "sky", NULL, context,
00244                                           "Wavelength calibration method: "
00245                                           "sky, phy or arc");
00246     cpl_ensure_code(!err, err);
00247 
00248     /* --wavecal_rej */
00249     err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
00250                                           "wavecal_rej", "-1,-1,50,50",
00251                                           "wc_rej", context,
00252                                           "left right bottom top rejections");
00253     cpl_ensure_code(!err, err);
00254 
00255     /* --max_offset */
00256     err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00257                                        "max_offset", 50, NULL, context,
00258                                        "Maximum allowed offset from the "
00259                                        "physical model [pixel]");
00260     cpl_ensure_code(!err, err);
00261 
00262     /* --saa_refine */
00263     err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
00264                                         "saa_refine", CPL_TRUE, NULL, context,
00265                                         "Flag to refine the offsets");
00266     cpl_ensure_code(!err, err);
00267 
00268     /* --saa_rej */
00269     err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
00270                                           "saa_rej", "0.1,0.1", NULL, context,
00271                                           "Low and high rejection fractions "
00272                                           "(rounded down)");
00273     cpl_ensure_code(!err, err);
00274 
00275     /* --spec_pos */
00276     err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00277                                        "spec_pos", -1, NULL, context,
00278                                        "Spectrum position");
00279     cpl_ensure_code(!err, err);
00280 
00281     /* --spec_width */
00282     err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00283                                        "spec_width", 10, NULL, context,
00284                                        "Spectrum width");
00285     cpl_ensure_code(!err, err);
00286 
00287     /* --sky_hi_width */
00288     err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00289                                        "sky_hi_width", 10, NULL, context,
00290                                        "Sky width above the spectrum");
00291     cpl_ensure_code(!err, err);
00292 
00293     /* --sky_lo_width */
00294     err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00295                                        "sky_lo_width", 10, NULL, context,
00296                                        "Sky width below the spectrum");
00297     cpl_ensure_code(!err, err);
00298 
00299     /* --sky_hi_dist */
00300     err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00301                                        "sky_hi_dist", -1, NULL, context,
00302                                        "Sky distance above the spectrum");
00303     cpl_ensure_code(!err, err);
00304 
00305     /* --sky_lo_dist */
00306     err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00307                                        "sky_lo_dist", -1, NULL, context,
00308                                        "Sky distance below the spectrum");
00309     cpl_ensure_code(!err, err);
00310 
00311     /* --plot */ 
00312     err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
00313                                         "display", CPL_FALSE, NULL, context,
00314                                         "Ignored. Use --plot instead");
00315     cpl_ensure_code(!err, err);
00316 
00317     /* --plot */ 
00318     err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00319                                        "plot", 0, NULL, context,
00320                                        isaac_plot_manpage);
00321     cpl_ensure_code(!err, err);
00322 
00323     /* --std_mode */ 
00324     err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
00325                                         "std_mode", CPL_FALSE, "std", context,
00326                                         "Flag for standard star");
00327     cpl_ensure_code(!err, err);
00328 
00329     /* --std_magnitude */
00330     err = irplib_parameterlist_set_double(self, PACKAGE, RECIPE_STRING,
00331                                           "std_magnitude", -1.0, "mag",
00332                                           context, "Standard star magnitude");
00333     cpl_ensure_code(!err, err);
00334 
00335     return CPL_ERROR_NONE;
00336 }
00337 
00338 
00339 /*----------------------------------------------------------------------------*/
00347 /*----------------------------------------------------------------------------*/
00348 static int isaac_spc_jitter(cpl_frameset            * framelist,
00349                             const cpl_parameterlist * parlist)
00350 {
00351     cpl_errorstate prestate = cpl_errorstate_get();
00352     const char          *   sval;
00353     const char          *   flat;
00354     const char          *   arc;
00355     const char          *   startrace;
00356     const char          *   sed;
00357     const char          *   stdstars;
00358     const char          *   oh;
00359     const cpl_frame     *   cur_frame;
00360     cpl_frameset        *   rawframes = NULL;
00361     cpl_propertylist    *   plist = NULL;
00362     cpl_image           **  combined = NULL;
00363     cpl_table           *   extracted = NULL;
00364     
00365     bug_if(0);
00366 
00367     /* Initialise */
00368     isaac_spc_jitter_config.chopping = -1;
00369     isaac_spc_jitter_config.wavecal_out = -1;
00370     isaac_spc_jitter_config.wavecal_cc = -1.0;
00371     isaac_spc_jitter_config.throws = NULL;
00372     isaac_spc_jitter_config.intensities = NULL;
00373     isaac_spc_jitter_config.filter[0] = (char)0;
00374     isaac_spc_jitter_config.filter_ref[0] = (char)0;
00375     isaac_spc_jitter_config.starname = NULL;
00376     isaac_spc_jitter_config.sptype = NULL;
00377     isaac_spc_jitter_config.wavecal_in = -1;
00378     isaac_spc_jitter_config.arm = -1;
00379 
00380     /* Retrieve input parameters */
00381     /* --wavecal */
00382     sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
00383                                            "wavecal");
00384     bug_if(sval == NULL);
00385 
00386     if (!strcmp(sval, "phy")) isaac_spc_jitter_config.wavecal_in = 0;
00387     else if (!strcmp(sval, "sky")) isaac_spc_jitter_config.wavecal_in = 1;
00388     else if (!strcmp(sval, "arc")) isaac_spc_jitter_config.wavecal_in = 2;
00389 
00390     error_if(isaac_spc_jitter_config.wavecal_in < 0,
00391              CPL_ERROR_UNSUPPORTED_MODE, "Invalid value for wavecal option: "
00392              "%s", sval);
00393 
00394     /* Rejection parameters for wavelength calibration*/
00395     sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
00396                                            "wavecal_rej");
00397     bug_if(sval == NULL);
00398 
00399     skip_if (sscanf(sval, "%d,%d,%d,%d",
00400                     &isaac_spc_jitter_config.wavecal_rej_left,
00401                     &isaac_spc_jitter_config.wavecal_rej_right,
00402                     &isaac_spc_jitter_config.wavecal_rej_bottom,
00403                     &isaac_spc_jitter_config.wavecal_rej_top) != 4);
00404 
00405     /* Max offset in pixels */
00406     isaac_spc_jitter_config.max_offset
00407         = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00408                                        "max_offset");
00409 
00410     /* Oddeven */
00411     isaac_spc_jitter_config.oddeven
00412         = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
00413                                         "oddeven");
00414 
00415     /* Refine of offsets */
00416     isaac_spc_jitter_config.saa_refine
00417         = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
00418                                         "saa_refine");
00419     
00420     /* Rejection parameters for SAA */
00421     sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
00422                                            "saa_rej");
00423     bug_if(sval == NULL);
00424 
00425     skip_if (sscanf(sval, "%lg,%lg",
00426                     &isaac_spc_jitter_config.saa_rej_low,
00427                     &isaac_spc_jitter_config.saa_rej_high) != 2);
00428 
00429     /* --spec_pos */
00430     isaac_spc_jitter_config.extr_spec_pos
00431         = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00432                                        "spec_pos");
00433     /* --spec_width */
00434     isaac_spc_jitter_config.extr_spec_width
00435         = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00436                                        "spec_width");
00437     /* --sky_hi_width */
00438     isaac_spc_jitter_config.extr_sky_hi_width
00439         = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00440                                        "sky_hi_width");
00441     /* --sky_lo_width */
00442     isaac_spc_jitter_config.extr_sky_lo_width
00443         = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00444                                        "sky_lo_width");
00445     /* --sky_hi_dist */
00446     isaac_spc_jitter_config.extr_sky_hi_dist
00447         = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00448                                        "sky_hi_dist");
00449     /* --sky_lo_dist */
00450     isaac_spc_jitter_config.extr_sky_lo_dist
00451         = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00452                                        "sky_lo_dist");
00453     /* --plot */
00454     isaac_spc_jitter_config.plot
00455         = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00456                                        "plot");
00457     /* --std */
00458     isaac_spc_jitter_config.std_mode
00459         = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
00460                                        "std_mode");
00461     /* --mag */
00462     isaac_spc_jitter_config.std_magnitude
00463         = irplib_parameterlist_get_double(parlist, PACKAGE, RECIPE_STRING,
00464                                        "std_magnitude");
00465     
00466     /* Identify the RAW and CALIB frames in the input frameset */
00467     skip_if (isaac_dfs_set_groups(framelist));
00468 
00469     /* Retrieve raw frames */
00470     if ((rawframes = isaac_extract_frameset(framelist,
00471                     ISAAC_SPC_JITTER_CHOP_RAW)) != NULL) {
00472     } else if ((rawframes = isaac_extract_frameset(framelist,
00473                     ISAAC_SPC_JITTER_CHOP_CAL_RAW)) != NULL) {
00474     } else if ((rawframes = isaac_extract_frameset(framelist,
00475                     ISAAC_SPC_JITTER_NODOBJ_RAW)) != NULL) {
00476     } else if ((rawframes = isaac_extract_frameset(framelist,
00477                     ISAAC_SPC_RESPFUNC_RAW)) != NULL) {
00478         isaac_spc_jitter_config.std_mode = 1;
00479     } else if ((rawframes = isaac_extract_frameset(framelist,
00480                     ISAAC_SPC_RESPFUNC_OBJ_RAW)) != NULL) {
00481         isaac_spc_jitter_config.std_mode = 1;
00482     } else if ((rawframes = isaac_extract_frameset(framelist,
00483                     ISAAC_SPC_RESPFUNC_FLUX_RAW)) != NULL) {
00484         isaac_spc_jitter_config.std_mode = 1;
00485     } else {
00486 
00487         /* These frame types alone are not supported */
00488 
00489         error_if (cpl_frameset_find_const(framelist,
00490                                           ISAAC_SPC_JITTER_NODSKY_RAW),
00491                   CPL_ERROR_UNSUPPORTED_MODE, "Cannot reduce "
00492                   ISAAC_SPC_JITTER_NODSKY_RAW "-frames without object frames");
00493 
00494         error_if (cpl_frameset_find_const(framelist,
00495                                           ISAAC_SPC_RESPFUNC_SKY_RAW),
00496                   CPL_ERROR_UNSUPPORTED_MODE, "Cannot reduce "
00497                   ISAAC_SPC_RESPFUNC_SKY_RAW "-frames without object frames");
00498 
00499     }
00500 
00501     error_if (rawframes == NULL, CPL_ERROR_DATA_NOT_FOUND,
00502               "Cannot find the raw frames in the input list");
00503 
00504     /* Get the arm used (SW or LW) */
00505     cur_frame = cpl_frameset_get_frame_const(framelist, 0);
00506     skip_if(cur_frame == NULL);
00507     plist = cpl_propertylist_load(cpl_frame_get_filename(cur_frame), 0);
00508     skip_if(plist == NULL);
00509     sval = isaac_pfits_get_arm(plist);
00510     error_if (sval == NULL, CPL_ERROR_DATA_NOT_FOUND, "cannot get the arm");
00511 
00512     if (sval[0] == 'S')      isaac_spc_jitter_config.arm = 1;
00513     else if (sval[0] == 'L') isaac_spc_jitter_config.arm = 2;
00514     
00515     error_if (isaac_spc_jitter_config.arm < 0, CPL_ERROR_UNSUPPORTED_MODE,
00516               "Unsupported arm: %s", sval);
00517 
00518     /* Get the filter */
00519     sval = isaac_pfits_get_filter(plist);
00520     if (sval == NULL) {
00521         cpl_error_reset();
00522     } else {
00523         (void)strncpy(isaac_spc_jitter_config.filter, sval, KEYSIZE);
00524         isaac_spc_jitter_config.filter[KEYSIZE-1] = (char)0;
00525     }
00526     cpl_propertylist_empty(plist);
00527 
00528     /* Retrieve calibration data */
00529     arc = isaac_extract_filename(framelist, ISAAC_CALIB_ARC);
00530     if (arc == NULL)
00531         arc = isaac_extract_filename(framelist, ISAAC_CALIB_LW_ARC);
00532     flat = isaac_extract_filename(framelist, ISAAC_CALIB_SPFLAT);
00533     if (flat == NULL)
00534         flat = isaac_extract_filename(framelist, ISAAC_CALIB_LW_SPFLAT);
00535     startrace = isaac_extract_filename(framelist, ISAAC_CALIB_STARTRACE);
00536     if (startrace == NULL)
00537         startrace = isaac_extract_filename(framelist, ISAAC_CALIB_LW_STARTRACE);
00538     sed = isaac_extract_filename(framelist, ISAAC_CALIB_SED);
00539     stdstars = isaac_extract_filename(framelist, ISAAC_CALIB_STDSTARS);
00540     oh = isaac_extract_filename(framelist, ISAAC_CALPRO_OH_CAT);
00541 
00542     /* If arc calibration requested, arc file must be provided */
00543     error_if (arc == NULL && isaac_spc_jitter_config.wavecal_in == 2,
00544               CPL_ERROR_DATA_NOT_FOUND, "Missing an arc file for the "
00545               "arc-based wavelength calibration");
00546 
00547     cpl_msg_info(cpl_func, "Create the combined image");
00548     combined = isaac_spc_jitter_combine(rawframes, oh, flat, arc,
00549                                         startrace);
00550     skip_if (combined == NULL);
00551 
00552     cpl_msg_info(cpl_func, "Extract the spectrum");
00553     extracted = isaac_spc_jitter_extract(combined[0]);
00554     if (extracted == NULL || !cpl_errorstate_is_equal(prestate)) {
00555         cpl_msg_warning(cpl_func, "Cannot extract the spectrum");
00556         if (!cpl_errorstate_is_equal(prestate)) {
00557             cpl_errorstate_dump(prestate, CPL_FALSE,
00558                                 irplib_errorstate_dump_warning);
00559             cpl_errorstate_set(prestate);
00560         }
00561     } else if (isaac_spc_jitter_config.std_mode) {
00562         /* In standard star mode, compute the efficiency and the conversion */
00563         cpl_msg_info(cpl_func, "Compute flux calibration");
00564         cur_frame = cpl_frameset_get_frame_const(framelist, 0);
00565         if (isaac_spc_jitter_std(sed, stdstars, cur_frame, extracted, 
00566                                  isaac_spc_jitter_config.std_magnitude)) {
00567             cpl_msg_warning(cpl_func, "Cannot compute the flux calibration");
00568             if (!cpl_errorstate_is_equal(prestate)) {
00569                 cpl_errorstate_dump(prestate, CPL_FALSE,
00570                                     irplib_errorstate_dump_warning);
00571                 cpl_errorstate_set(prestate);
00572             }
00573         }
00574     }
00575     
00576     /* Write the products */
00577     cpl_msg_info(cpl_func, "Save the products");
00578     skip_if (isaac_spc_jitter_save(framelist, combined[0], combined[1],
00579                                    extracted, parlist));
00580 
00581     end_skip;
00582 
00583     if (combined != NULL) {
00584         cpl_image_delete(combined[0]);
00585         cpl_image_delete(combined[1]);
00586         cpl_free(combined);
00587     }
00588 
00589     cpl_table_delete(extracted);
00590 
00591     cpl_vector_delete(isaac_spc_jitter_config.intensities);
00592     cpl_vector_delete(isaac_spc_jitter_config.throws);
00593 
00594     cpl_free(isaac_spc_jitter_config.starname);
00595     cpl_free(isaac_spc_jitter_config.sptype);
00596 
00597     cpl_propertylist_delete(plist);
00598 
00599     cpl_frameset_delete(rawframes);
00600 
00601     return cpl_error_get_code();
00602 }
00603 
00604 /*----------------------------------------------------------------------------*/
00615 /*----------------------------------------------------------------------------*/
00616 static cpl_image ** isaac_spc_jitter_combine(const cpl_frameset * rawframes,
00617                                              const char         * oh,
00618                                              const char         * flat,
00619                                              const char         * arc,
00620                                              const char         * startrace)
00621 {
00622     int                     nilist;
00623     cpl_imagelist       *   ilist = NULL;
00624     cpl_vector          *   offsets = NULL;
00625     int                 *   groups = NULL;
00626     int                     ngroups = 0; /* Avoid uninit warning */
00627     cpl_imagelist       *   abba = NULL;
00628     cpl_vector          *   abba_off = NULL;
00629     cpl_imagelist       *   nodded = NULL;
00630     cpl_vector          *   nodded_off_y = NULL;
00631     double                  throw;
00632     cpl_vector          *   nodded_off_x = NULL;
00633     cpl_bivector        *   nodded_offsets = NULL;
00634     cpl_image           **  combined = NULL;
00635     int                     nima;
00636     int                     i;
00637     
00638     bug_if (rawframes == NULL);
00639 
00640     /* Load the images */
00641     cpl_msg_info(cpl_func, "Load the data"); 
00642     ilist = isaac_spc_jitter_load(rawframes);
00643     skip_if (ilist == NULL);
00644 
00645     nilist = cpl_imagelist_get_size(ilist);
00646    
00647     /* Apply the odd-even correction */
00648     if (isaac_spc_jitter_config.oddeven) {
00649         cpl_errorstate prestate = cpl_errorstate_get();
00650         cpl_imagelist * corrected = cpl_imagelist_new();
00651 
00652         cpl_msg_info(cpl_func, "Apply the odd-even effect correction");
00653         for (i=0; i < nilist; i++) {
00654             cpl_image * cur_im
00655                 = isaac_oddeven_correct(cpl_imagelist_get(ilist, i));
00656 
00657             cpl_msg_info(cpl_func, "Correcting frame %d/%d", i+1, nilist);
00658 
00659             if (cur_im == NULL) break;
00660             (void)cpl_imagelist_set(corrected, cur_im, i);
00661         }
00662 
00663         if (i == nilist) {
00664             /* Odd/even correction successful */
00665             cpl_imagelist_delete(ilist);
00666             ilist = corrected;
00667         } else {
00668             cpl_msg_warning(cpl_func, "Odd/even correction failed for "
00669                             "image %d/%d", i+1, nilist);
00670             cpl_imagelist_delete(corrected);
00671             if (!cpl_errorstate_is_equal(prestate)) {
00672                 cpl_errorstate_dump(prestate, CPL_FALSE, 
00673                                     irplib_errorstate_dump_warning);
00674                 cpl_errorstate_set(prestate);
00675             }
00676         }
00677     }
00678 
00679 
00680     if (isaac_spc_jitter_config.plot > 0) {
00681         cpl_plot_image("", "", "", cpl_imagelist_get(ilist, 0));
00682     }
00683 
00684     /* Apply the flatfield */
00685     if (flat != NULL) {
00686         cpl_errorstate prestate = cpl_errorstate_get();
00687         cpl_msg_info(cpl_func, "Apply the flatfield correction"); 
00688         if (isaac_spc_jitter_flat(ilist, flat)) {
00689             cpl_msg_warning(cpl_func, "cannot apply the flat field");
00690             if (!cpl_errorstate_is_equal(prestate)) {
00691                 cpl_errorstate_dump(prestate, CPL_FALSE, 
00692                                     irplib_errorstate_dump_warning);
00693                 cpl_errorstate_set(prestate);
00694             }
00695         }
00696     }
00697         
00698     if (isaac_spc_jitter_config.plot > 0) {
00699         cpl_plot_image("", "", "", cpl_imagelist_get(ilist, 0));
00700     }
00701     /* Get the offsets */
00702     cpl_msg_info(cpl_func, "Get the %d offsets", nilist);
00703     offsets = isaac_spc_jitter_get_offsets(rawframes);
00704 
00705     error_if (offsets == NULL, cpl_error_get_code(),
00706               "Could not get the offsets");
00707 
00708     /* Classify in groups the a and b images sequence */
00709     cpl_msg_info(cpl_func, "Classify in groups"); 
00710     groups = isaac_spc_jitter_classif(offsets, &ngroups);
00711     error_if (groups == NULL, cpl_error_get_code(),
00712               "Could not classify the data");
00713   
00714     /* Shift and add each group to one image */
00715     cpl_msg_info(cpl_func, "Shift and add each group to one image"); 
00716     abba = isaac_spc_jitter_saa_groups(ilist, offsets, groups, 
00717                                        ngroups, &abba_off);
00718     error_if (abba == NULL, cpl_error_get_code(), "Could not shift and add "
00719               "groups");
00720 
00721     /* Compute the wavelength calibration */
00722     cpl_msg_info(cpl_func, "Compute the wavelength calibration"); 
00723     error_if (isaac_spc_jitter_wavecal(arc, cpl_imagelist_get(abba, 0), oh,
00724                                        rawframes),
00725               cpl_error_get_code(), "Wavelength calibration failed");
00726 
00727    /* Create the nodded images */
00728     cpl_msg_info(cpl_func, "Create the nodded images"); 
00729     nodded = isaac_spc_jitter_nodded(abba, abba_off, &nodded_off_y);
00730     cpl_imagelist_delete(abba);
00731     abba = NULL;
00732 
00733     skip_if (nodded == NULL);
00734 
00735     /* Get the throw offsets from abba_off */
00736     nima = cpl_imagelist_get_size(nodded);
00737     isaac_spc_jitter_config.throws = cpl_vector_new(nima);
00738     if (isaac_spc_jitter_config.chopping == 0) {
00739         for (i=0; i<nima/2; i++) {
00740             throw = fabs(   (cpl_vector_get(abba_off, 2*i))-
00741                             (cpl_vector_get(abba_off, 2*i+1)));
00742             cpl_vector_set(isaac_spc_jitter_config.throws, 2*i, throw);
00743             cpl_vector_set(isaac_spc_jitter_config.throws, 2*i+1, throw);
00744         }
00745     } else {
00746         for (i=0; i<nima; i++) {
00747             throw = fabs(   (cpl_vector_get(abba_off, 2*i))-
00748                             (cpl_vector_get(abba_off, 2*i+1)));
00749             cpl_vector_set(isaac_spc_jitter_config.throws, i, throw);
00750         }
00751     }
00752     cpl_vector_delete(abba_off);
00753     abba_off = NULL;
00754     
00755     /* Get the spectra intensities in the nodded images */
00756     cpl_msg_info(cpl_func, "Compute the spectra intensities");
00757     cpl_msg_indent_more();
00758     isaac_spc_jitter_config.intensities = cpl_vector_new(nima);
00759     for (i=0; i<nima; i++) {
00760         cpl_errorstate prestate = cpl_errorstate_get();
00761         cpl_table    * extracted
00762             = isaac_spc_jitter_extract(cpl_imagelist_get(nodded, i));
00763         double         intensity;
00764 
00765 
00766         if (extracted == NULL || !cpl_errorstate_is_equal(prestate)) {
00767             cpl_msg_warning(cpl_func,"Cannot extract the spectrum from "
00768                             "nodded image %d", i+1);
00769             cpl_errorstate_dump(prestate, CPL_FALSE, 
00770                                 irplib_errorstate_dump_warning);
00771             cpl_errorstate_set(prestate);
00772             intensity = -1.0;
00773         } else {
00774             intensity = cpl_table_get_column_mean(extracted, 
00775                     "Extracted_spectrum_value");
00776             intensity *= cpl_table_get_nrow(extracted);
00777             cpl_table_delete(extracted);
00778             cpl_msg_info(cpl_func, "Spectrum intensity %d: %g", i+1,
00779                          intensity);
00780         }
00781         cpl_vector_set(isaac_spc_jitter_config.intensities, i, intensity);
00782     }
00783     cpl_msg_indent_less();
00784 
00785     if (arc || startrace) {
00786         cpl_imagelist * nodded_warped;
00787         cpl_msg_info(cpl_func, "Correct the distortion on nodded images"); 
00788         cpl_msg_indent_more();
00789         nodded_warped = isaac_spc_jitter_distor(nodded, arc, startrace);
00790         cpl_msg_indent_less();
00791 
00792         skip_if (nodded_warped == NULL);
00793 
00794         cpl_imagelist_delete(nodded);
00795         nodded = nodded_warped;
00796         nima = cpl_imagelist_get_size(nodded);
00797     }
00798 
00799 
00800     /* Refine the offsets if requested */
00801     if (isaac_spc_jitter_config.saa_refine) {
00802         double * pnodded_off_y = cpl_vector_get_data(nodded_off_y);
00803         cpl_msg_info(cpl_func, "Refine the %d offsets", nima);
00804         for (i=0; i < nima; i++) {
00805             const double new_offset
00806                 = isaac_spc_jitter_refine_offset(cpl_imagelist_get(nodded, 0),
00807                                                  cpl_imagelist_get(nodded, i));
00808             if (new_offset > 5000) {
00809                 cpl_msg_debug(cpl_func, "cannot refine the offset - keep %g", 
00810                               pnodded_off_y[i]);
00811             } else if (fabs(new_offset-pnodded_off_y[i]) < 
00812                        ISAAC_SPC_JITTER_OFFSET_ERR) {
00813                 cpl_msg_debug(cpl_func, "refined offset : %g (old was %g)",
00814                               new_offset, pnodded_off_y[i]);
00815                 pnodded_off_y[i] = new_offset;
00816             } else { 
00817                 cpl_msg_debug(cpl_func, 
00818                               "refined offset %g too different - keep %g",
00819                               new_offset, pnodded_off_y[i]);
00820             }
00821         }
00822     }
00823 
00824     /* Images Shift and add */
00825 
00826     /* Get the offsets in a bivector */
00827     nodded_off_x = cpl_vector_new(nima);
00828     bug_if(cpl_vector_fill(nodded_off_x, 0.0));
00829     nodded_offsets = cpl_bivector_wrap_vectors(nodded_off_x, nodded_off_y);
00830 
00831     if (nima == 1) {
00832 
00833         combined = cpl_malloc(2 * sizeof(cpl_image*)); 
00834         combined[1] = NULL; /* In case the unset fails */
00835 
00836         combined[0] = cpl_imagelist_unset(nodded, 0);
00837         bug_if (combined[0] == NULL);
00838 
00839         combined[1] = cpl_image_new(cpl_image_get_size_x(combined[0]),
00840                                     cpl_image_get_size_y(combined[0]),
00841                                     CPL_TYPE_INT);
00842         bug_if (combined[1] == NULL);
00843 
00844         /* Set all pixel values to 1 */
00845         bug_if(cpl_image_threshold(combined[1], 1.0, 1.0, 1.0, 1.0));
00846 
00847     } else {
00848         /* FIXME: Round-off instead */
00849         const int nrejlo = (int)(nima * isaac_spc_jitter_config.saa_rej_low);
00850         const int nrejhi = (int)(nima * isaac_spc_jitter_config.saa_rej_high);
00851 
00852         cpl_msg_info(cpl_func, "Apply the shift and add on the %d nodded "
00853                      "frames (Rejecting %d lowermost, %d uppermost)", nima,
00854                      nrejlo, nrejhi);
00855         combined = cpl_geom_img_offset_saa(nodded, nodded_offsets, 
00856                                            CPL_KERNEL_DEFAULT, nrejlo, nrejhi,
00857                                            CPL_GEOM_FIRST, NULL, NULL);
00858     }
00859 
00860     skip_if(combined == NULL);
00861 
00862     end_skip;
00863 
00864     cpl_free(groups);
00865     cpl_imagelist_delete(ilist);
00866     cpl_vector_delete(offsets);
00867     cpl_imagelist_delete(abba);
00868     cpl_vector_delete(abba_off);
00869     cpl_imagelist_delete(nodded);
00870     cpl_bivector_unwrap_vectors(nodded_offsets);
00871     cpl_vector_delete(nodded_off_x);
00872     cpl_vector_delete(nodded_off_y);
00873 
00874     return combined;
00875 }
00876  
00877 /*----------------------------------------------------------------------------*/
00885 /*----------------------------------------------------------------------------*/
00886 static cpl_error_code isaac_spc_jitter_flat(cpl_imagelist * self,
00887                                             const char    * flat)
00888 {
00889     cpl_image        * fim = NULL;
00890     cpl_image        * big_fim = NULL;
00891     const int          mx = cpl_image_get_size_x(cpl_imagelist_get(self, 0));
00892     const int          my = cpl_image_get_size_y(cpl_imagelist_get(self, 0));
00893     int                nx, ny;
00894 
00895     bug_if (self == NULL);
00896     bug_if (flat == NULL);
00897    
00898     /* Load the flat */
00899     fim = cpl_image_load(flat, CPL_TYPE_UNSPECIFIED, 0, 0);
00900     error_if(fim == NULL, cpl_error_get_code(), "Could not load the flat "
00901              "field from %s", flat);
00902    
00903     /* Get flat size */
00904     nx = cpl_image_get_size_x(fim);
00905     ny = cpl_image_get_size_y(fim);
00906 
00907     error_if(ny != my, CPL_ERROR_INCOMPATIBLE_INPUT, "Flat field Y-size "
00908              "%d is incompatible with image Y-size %d", ny, my);
00909 
00910     /* Handle the case where nx is smaller */
00911     if (nx != mx) {
00912         cpl_propertylist * plist
00913             = cpl_propertylist_load_regexp(flat, 0, "ESO DET WIN STARTX", 0);
00914         const int lx = (int)isaac_pfits_get_win_startx(plist);
00915 
00916         cpl_propertylist_delete(plist);
00917         skip_if (0);
00918 
00919         cpl_msg_info(cpl_func, "Windowing mode: flat between pixels %d "
00920                      "and %d", lx, ISAAC_MIN(mx, lx + nx - 1));
00921 
00922         if (lx > mx || lx < 1) {
00923             cpl_msg_warning(cpl_func, "Cannot apply out of bounds flat field, "
00924                             "lx=%d > mx=%d", lx, mx);
00925             cpl_image_delete(fim);
00926             fim = NULL;
00927         } else {
00928 
00929             /* Create the big flat image */
00930             big_fim = cpl_image_new(mx, my, cpl_image_get_type(fim));
00931 
00932             /* Set all pixel values to 1 */
00933             bug_if(cpl_image_threshold(big_fim, 1.0, 1.0, 1.0, 1.0));
00934 
00935             /* Copy the small flat in the big one */
00936             bug_if (cpl_image_copy(big_fim, fim, lx, 1));
00937 
00938             cpl_image_delete(fim);
00939             fim = big_fim;
00940             big_fim = NULL;
00941         }
00942     }
00943 
00944     if (fim != NULL) {
00945 
00946         /* Threshold all pixels below the "mid-point" of FLT_MIN and 1, and
00947            all pixels above the "mid-point" of 1 and FLT_MAX. */
00948         bug_if(cpl_image_threshold(fim, sqrt(FLT_MIN), sqrt(FLT_MAX),
00949                                    1.0, 1.0));
00950 
00951         /* Apply the division */
00952         error_if (cpl_imagelist_divide_image(self, fim),
00953                   cpl_error_get_code(), "Could not apply the flat field");
00954     }
00955 
00956     end_skip;
00957 
00958     cpl_image_delete(fim);
00959     cpl_image_delete(big_fim);
00960 
00961     return 0;
00962 }
00963 
00964 /*----------------------------------------------------------------------------*/
00971 /*----------------------------------------------------------------------------*/
00972 static cpl_imagelist * isaac_spc_jitter_load(const cpl_frameset * rawframes)
00973 {
00974     /* Load the propertylist of the first frame to get the data type */
00975     const cpl_frame  * cur_frame = cpl_frameset_get_frame_const(rawframes, 0);
00976     cpl_propertylist * plist
00977         = cpl_propertylist_load(cpl_frame_get_filename(cur_frame), 0);
00978     const char          *   sval;
00979     cpl_imagelist       *   self = NULL;
00980 
00981 
00982     skip_if (plist == NULL);
00983 
00984     sval = isaac_pfits_get_frame_type(plist);
00985     skip_if (sval == NULL);
00986 
00987     if (!strcmp(sval, "INT")) isaac_spc_jitter_config.chopping = 0;
00988     else if (!strcmp(sval, "CUBE1")) isaac_spc_jitter_config.chopping = 1;
00989     else {
00990         error_if(1, CPL_ERROR_UNSUPPORTED_MODE, "Unsupported frame type: %s",
00991                  sval);
00992     }
00993 
00994     cpl_propertylist_empty(plist);
00995 
00996     /* Load the data */
00997     self = cpl_imagelist_load_frameset(rawframes, CPL_TYPE_FLOAT, 1, 0);
00998 
00999     if (isaac_spc_jitter_config.chopping == 1) {
01000         cpl_imagelist * self_tmp
01001             = cpl_imagelist_load_frameset(rawframes, CPL_TYPE_FLOAT, 2, 0);
01002         const cpl_error_code error = cpl_imagelist_subtract(self, self_tmp);
01003 
01004         cpl_imagelist_delete(self_tmp);
01005         skip_if(error);
01006     }
01007 
01008     end_skip;
01009 
01010     cpl_propertylist_delete(plist);
01011 
01012     if (cpl_error_get_code()) {
01013         cpl_imagelist_delete(self);
01014         self = NULL;
01015     }
01016 
01017     return self;
01018 }
01019 
01020 /*----------------------------------------------------------------------------*/
01027 /*----------------------------------------------------------------------------*/
01028 static
01029 cpl_vector * isaac_spc_jitter_get_offsets(const cpl_frameset * rawframes)
01030 {
01031     const int          nraw = cpl_frameset_get_size(rawframes);
01032     cpl_vector       * offsets = cpl_vector_new(nraw);
01033     cpl_propertylist * plist = NULL;
01034     int                i;
01035 
01036     bug_if (rawframes == NULL);
01037     bug_if (nraw == 0);
01038     
01039 
01040     /* Get the rawframes Y offsets */
01041     for (i=0; i < nraw; i++) {
01042         const cpl_frame * cur_frame
01043             = cpl_frameset_get_frame_const(rawframes, i);
01044         const char * filename = cpl_frame_get_filename(cur_frame);
01045         double yoff;
01046 
01047         skip_if(filename == NULL);
01048 
01049         cpl_propertylist_delete(plist);
01050         plist = cpl_propertylist_load_regexp(filename, 0,
01051                                              "ESO SEQ CUMOFFSETY", 0);
01052 
01053         any_if("Could not load propertylist from %s", filename);
01054 
01055         yoff = cpl_propertylist_get_double(plist, "ESO SEQ CUMOFFSETY");
01056 
01057         any_if("Could not get the offset from %s", filename);
01058 
01059         bug_if(cpl_vector_set(offsets, i, yoff));
01060     }
01061 
01062     end_skip;
01063 
01064     cpl_propertylist_delete(plist);
01065 
01066     if (cpl_error_get_code()) {
01067         cpl_vector_delete(offsets);
01068         offsets = NULL;
01069     }
01070 
01071     return offsets;
01072 }
01073     
01074 /*----------------------------------------------------------------------------*/
01113 /*----------------------------------------------------------------------------*/
01114 static int * isaac_spc_jitter_classif(const cpl_vector * offsets,
01115                                       int              * pngroups)
01116 {
01117     const int      nraw   = cpl_vector_get_size(offsets);
01118     const double * pvect  = cpl_vector_get_data_const(offsets);
01119     const double   offmin = cpl_vector_get_min(offsets);
01120     const double   offmax = cpl_vector_get_max(offsets);
01121     const double   offset_thresh = 0.5 * (offmin + offmax);
01122     int          * groups = cpl_calloc(nraw, sizeof(int));
01123     int            last_group;
01124     int            i = 0;
01125 
01126 
01127     bug_if(offsets == NULL);
01128     bug_if(pngroups == NULL);
01129     *pngroups = 0;
01130 
01131     /* Separate the offsets in 2 categories */
01132     error_if (offmin >= offmax, CPL_ERROR_DATA_NOT_FOUND,
01133               "The %d offset(s) all have the same value: %g", nraw, pvect[0]);
01134 
01135     /* Identify the different A and B groups */
01136 
01137     /* Create a look up table to associate the ith obj with the jth frame */
01138     while (i < nraw) {
01139         int j = 0;
01140         /* Count the number of successive '+' or '-' (j) */
01141         while ((i+j < nraw) &&
01142                 (!off_comp(pvect[i], pvect[i+j], offset_thresh))) j++;
01143 
01144         if (i+j >= nraw) i = nraw;
01145         else {
01146             int l, k = 0;
01147             /* Check if there are j '-' or '+' (k) */
01148             while ((i+j+k < nraw)
01149                     && (!off_comp(pvect[i+j], pvect[i+j+k], offset_thresh))
01150                     && (k<j)) k++;
01151             last_group = 1;
01152             if (i+j+k < nraw) {
01153                 for (l=i+j+k; l<nraw; l++) {
01154                     if (off_comp(pvect[i+j], pvect[l], offset_thresh)) {
01155                         last_group = 0;
01156                         break;
01157                     }
01158                 }
01159             }
01160             if (last_group == 0) {
01161                 for (l=0; l<j; l++) groups[i+l]   = *pngroups + 1;
01162                 for (l=0; l<k; l++) groups[i+j+l] = *pngroups + 2;
01163                 *pngroups += 2;
01164                 i += j+k;
01165             } else {
01166                 for (l=0; l<j; l++)             groups[i+l]   = *pngroups + 1;
01167                 for (l=0; l<nraw - (i+j); l++)  groups[i+j+l] = *pngroups + 2;
01168                 *pngroups += 2;
01169                 i = nraw;
01170             }
01171         }
01172     }
01173 
01174     /* Nb of groups found should be even */
01175     error_if (*pngroups & 1, CPL_ERROR_ILLEGAL_INPUT, "Found an odd number "
01176               "(%d) of groups in the %d offsets", *pngroups, nraw);
01177 
01178     end_skip;
01179 
01180     if (cpl_error_get_code()) {
01181         cpl_free(groups);
01182         groups = NULL;
01183     }
01184 
01185     return groups;
01186 }
01187     
01188 /*----------------------------------------------------------------------------*/
01220 /*----------------------------------------------------------------------------*/
01221 static cpl_imagelist * isaac_spc_jitter_saa_groups(
01222         cpl_imagelist   *   ilist,
01223         cpl_vector      *   offsets,
01224         int             *   groups,
01225         int                 ngroups,
01226         cpl_vector      **  abba_off)
01227 {
01228     cpl_imagelist       *   abba; 
01229     cpl_imagelist       *   group_list; 
01230     cpl_image           *   tmp_ima;
01231     cpl_image           **  combined;
01232     cpl_bivector        *   group_off;
01233     double              *   pgroup_off;
01234     double              *   poffsets;
01235     double              *   pabba_off;
01236     int                     nima;
01237     int                     saa;
01238     int                     i, j, k;
01239 
01240     /* Test entries */
01241     if ((ilist == NULL) || (offsets == NULL) || (groups == NULL)) return NULL;
01242     
01243     /* Initialise */
01244     nima = cpl_imagelist_get_size(ilist);
01245     poffsets = cpl_vector_get_data(offsets);
01246 
01247     /* Create the output image list */
01248     abba = cpl_imagelist_new();
01249     *abba_off = cpl_vector_new(ngroups);
01250     pabba_off = cpl_vector_get_data(*abba_off);
01251     
01252     /* Loop on the groups */
01253     for (i=0; i<ngroups; i++) {
01254         /* Initialise */
01255         saa = 0;
01256         /* Create the group list of images */
01257         group_list = cpl_imagelist_new();
01258         k = 0;
01259         for (j=0; j<nima; j++) {
01260             if (i+1 == groups[j]) {
01261                 /* Get the first offset of the group in abba_off */
01262                 if (k==0) pabba_off[i] = poffsets[j];
01263                 /* To know if we need the saa (shift and add) */
01264                 if (fabs(pabba_off[i]-poffsets[j]) > 1e-3) saa = 1;
01265                 /* Copy the images of the group in group_list */
01266                 tmp_ima = cpl_image_duplicate(cpl_imagelist_get(ilist, j));
01267                 cpl_imagelist_set(group_list, tmp_ima, k);
01268                 tmp_ima = NULL;
01269                 k++;
01270             }
01271         }
01272 
01273         if (saa) {
01274             /* Get the offsets of the group in group_off */
01275             group_off = cpl_bivector_new(k);
01276             cpl_vector_fill(cpl_bivector_get_x(group_off), 0.0);
01277             pgroup_off = cpl_bivector_get_y_data(group_off);
01278             k = 0;
01279             for (j=0; j<nima; j++) {
01280                 if (i+1 == groups[j]) {
01281                     pgroup_off[k] = poffsets[j];
01282                     k++;
01283                 }
01284             }
01285             cpl_vector_subtract_scalar(cpl_bivector_get_y(group_off), 
01286                     pabba_off[i]);
01287             /* Shift and add */
01288             cpl_msg_debug(cpl_func, "Apply shift-and-add for group %d", i+1);
01289             if ((combined = cpl_geom_img_offset_saa(group_list,
01290                            group_off, CPL_KERNEL_DEFAULT, 0, 0,
01291                            CPL_GEOM_FIRST, NULL, NULL)) == NULL) {
01292                 cpl_msg_error(cpl_func, "Cannot shift and add group nb %d", i+1);
01293                 cpl_imagelist_delete(group_list);
01294                 cpl_bivector_delete(group_off);
01295                 cpl_imagelist_delete(abba);
01296                 cpl_vector_delete(*abba_off);
01297                 return NULL;
01298             }
01299             cpl_bivector_delete(group_off);
01300             cpl_image_delete(combined[1]);
01301             cpl_imagelist_set(abba, combined[0], i);
01302             cpl_free(combined);
01303         } else {
01304             /* Averaging */
01305             cpl_msg_debug(cpl_func, "Apply averaging for group %d", i+1);
01306             if ((tmp_ima = cpl_imagelist_collapse_create(group_list)) == NULL) {
01307                 cpl_msg_error(cpl_func, "Cannot average group nb %d", i+1);
01308                 cpl_imagelist_delete(group_list);
01309                 cpl_imagelist_delete(abba);
01310                 cpl_vector_delete(*abba_off);
01311                 return NULL;
01312             }
01313             cpl_imagelist_set(abba, tmp_ima, i);
01314         }
01315         cpl_imagelist_delete(group_list);
01316     }
01317     return abba;
01318 }
01319 
01320 /*----------------------------------------------------------------------------*/
01330 /*----------------------------------------------------------------------------*/
01331 static int isaac_spc_jitter_wavecal(const char         * arc,
01332                                     const cpl_image    * ima,
01333                                     const char         * oh,
01334                                     const cpl_frameset * raw)
01335 {
01336     cpl_table           *   arc_tab;
01337     double              *   phdisprel;
01338     const cpl_frame     *   cur_frame;
01339     const char          *   cur_fname;
01340     computed_disprel    *   disprel;
01341     int                     order;
01342     double                  slit_width;
01343 
01344     /* Get the wavelength from the arc file */
01345     if (isaac_spc_jitter_config.wavecal_in == 2) {
01346         if (arc == NULL) {
01347             cpl_msg_error(cpl_func, 
01348                     "Missing arc for the wavelength calibration");
01349             return -1;
01350         }
01351         cpl_msg_info(cpl_func, "Get the wavelength from the ARC file");
01352         if ((arc_tab = cpl_table_load(arc, 1, 0)) == NULL) {
01353             cpl_msg_error(cpl_func, "Cannot load the arc table");
01354             isaac_spc_jitter_config.wavecal_out = -1;
01355             return -1;
01356         }
01357         isaac_spc_jitter_config.wavecal_a0 =
01358             cpl_table_get_double(arc_tab, "WL_coefficients", 0, NULL);
01359         isaac_spc_jitter_config.wavecal_a1 = 
01360             cpl_table_get_double(arc_tab, "WL_coefficients", 1, NULL);
01361         isaac_spc_jitter_config.wavecal_a2 = 
01362             cpl_table_get_double(arc_tab, "WL_coefficients", 2, NULL);
01363         isaac_spc_jitter_config.wavecal_a3 = 
01364             cpl_table_get_double(arc_tab, "WL_coefficients", 3, NULL);
01365         cpl_table_delete(arc_tab);
01366         isaac_spc_jitter_config.wavecal_out = 2;
01367         isaac_spc_jitter_config.wavecal_cc = -1.0;
01368         return 0;
01369     }
01370 
01371     /* Get the reference frame */
01372     cur_frame = cpl_frameset_get_frame_const(raw, 0);
01373     cur_fname = cpl_frame_get_filename(cur_frame);
01374     
01375     /* Get the physical model */
01376     cpl_msg_info(cpl_func, "Compute the physical model");
01377     cpl_msg_indent_more();
01378     if ((phdisprel = isaac_get_disprel_estimate(cur_fname, 3)) == NULL) {
01379         cpl_msg_error(cpl_func, "cannot compute the physical model");
01380         isaac_spc_jitter_config.wavecal_out = -1;
01381         cpl_msg_indent_less();
01382         return -1;
01383     }
01384     cpl_msg_info(cpl_func, "f(x)=%g + %g*x + %g*x^2 + %g*x^3",
01385             phdisprel[0], phdisprel[1], phdisprel[2], phdisprel[3]);
01386     isaac_spc_jitter_config.wavecal_a0 = phdisprel[0];
01387     isaac_spc_jitter_config.wavecal_a1 = phdisprel[1];
01388     isaac_spc_jitter_config.wavecal_a2 = phdisprel[2];
01389     isaac_spc_jitter_config.wavecal_a3 = phdisprel[3];
01390     isaac_spc_jitter_config.wavecal_cc = -1.0;
01391     isaac_spc_jitter_config.wavecal_out = 0;
01392     cpl_msg_indent_less();
01393 
01394     /* Compute the wavelength using the sky lines */
01395     if (isaac_spc_jitter_config.wavecal_in == 1) {
01396         /* Compute the slit_width */
01397         if ((slit_width = isaac_get_slitwidth(cur_fname)) == -1) {
01398             cpl_msg_warning(cpl_func, "cannot get the slit width");
01399             cpl_free(phdisprel);
01400             return 0;
01401         }
01402         /* Get the order */
01403         if ((order = isaac_find_order(cur_fname)) == -1) {
01404             cpl_msg_warning(cpl_func, "cannot get the order");
01405             cpl_free(phdisprel);
01406             return 0;
01407         }
01408         /* Compute the wavelength */
01409         cpl_msg_info(cpl_func, "Compute the wavelength with the sky lines");
01410         cpl_msg_indent_more();
01411         if ((disprel = spectro_compute_disprel(ima,
01412                         isaac_spc_jitter_config.wavecal_rej_bottom,
01413                         isaac_spc_jitter_config.wavecal_rej_top,
01414                         isaac_spc_jitter_config.wavecal_rej_left,
01415                         isaac_spc_jitter_config.wavecal_rej_right,
01416                         isaac_spc_jitter_config.max_offset,
01417                         isaac_has_thermal(cur_fname) > 0,
01418                         "oh", oh, NULL, NULL, slit_width, order, 
01419                         (int)(cpl_msg_get_level() == CPL_MSG_DEBUG), 
01420                         phdisprel)) == NULL) {
01421             cpl_msg_error(cpl_func, "cannot compute the dispersion relation");
01422             cpl_free(phdisprel);
01423             cpl_msg_indent_less();
01424             return 0;
01425         }
01426         cpl_msg_info(cpl_func, "Cross correlation factor: %g", disprel->cc);
01427         cpl_msg_info(cpl_func, "f(x)=%g + %g*x + %g*x^2 + %g*x^3",
01428                 disprel->poly[0], disprel->poly[1], disprel->poly[2],
01429                 disprel->poly[3]);
01430         isaac_spc_jitter_config.wavecal_a0 = disprel->poly[0];
01431         isaac_spc_jitter_config.wavecal_a1 = disprel->poly[1];
01432         isaac_spc_jitter_config.wavecal_a2 = disprel->poly[2];
01433         isaac_spc_jitter_config.wavecal_a3 = disprel->poly[3];
01434         isaac_spc_jitter_config.wavecal_cc = disprel->cc;
01435         isaac_spc_jitter_config.wavecal_out = 1;
01436         if (disprel->poly != NULL) cpl_free(disprel->poly);
01437         cpl_free(disprel);
01438         cpl_msg_indent_less();
01439     }
01440     cpl_free(phdisprel);
01441     return 0;
01442 }
01443 
01444 /*----------------------------------------------------------------------------*/
01477 /*----------------------------------------------------------------------------*/
01478 static cpl_imagelist * isaac_spc_jitter_nodded(cpl_imagelist   *   abba,
01479                                                cpl_vector      *   abba_off,
01480                                                cpl_vector      **  nodded_off)
01481 {
01482     cpl_imagelist       *   nodded;
01483     cpl_image           *   tmp_ima;
01484     int                     nima;
01485     double              *   pabba_off;
01486     double              *   pnodded_off;
01487     double                  ref_off;
01488     int                     i;
01489 
01490     /* Test entries */
01491     if ((abba == NULL) || (abba_off == NULL)) return NULL;
01492 
01493     /* Initialise */
01494     nima = cpl_imagelist_get_size(abba);
01495     if (nima % 2) {
01496         cpl_msg_error(cpl_func, "Number of images should be even");
01497         return NULL;
01498     }
01499    
01500     /* Non-chopping case */
01501     if (isaac_spc_jitter_config.chopping == 0) {
01502         /* Create the offsets between the nodded images */
01503         *nodded_off = cpl_vector_duplicate(abba_off);
01504         /* The image list to contain the nodded images */
01505         nodded = cpl_imagelist_new();
01506         for (i=0; i<(nima/2); i++) {
01507             /* a-b */
01508             tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i));
01509             cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i+1));
01510             cpl_imagelist_set(nodded, tmp_ima, 2*i);
01511             /* b-a */
01512             tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i+1));
01513             cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i));
01514             cpl_imagelist_set(nodded, tmp_ima, 2*i+1);
01515         }
01516     /* Chopping case */
01517     } else if (isaac_spc_jitter_config.chopping == 1) {
01518         /* Create the offsets between the nodded images */
01519         *nodded_off = cpl_vector_new(nima/2);
01520         pnodded_off = cpl_vector_get_data(*nodded_off);
01521         pabba_off = cpl_vector_get_data(abba_off);
01522         /* The image list to contain the nodded images */
01523         nodded = cpl_imagelist_new();
01524         for (i=0; i<nima/2; i++) {
01525             if ((pabba_off[0]-pabba_off[1])*(pabba_off[2*i]-pabba_off[2*i+1])
01526                     > 0) {
01527                 /* ab sequence */
01528                 pnodded_off[i] = pabba_off[2*i];
01529                 tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i));
01530                 cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i+1)); 
01531                 cpl_image_divide_scalar(tmp_ima, 2.0);
01532                 cpl_imagelist_set(nodded, tmp_ima, i);
01533             } else {
01534                 /* ba sequence */
01535                 pnodded_off[i] = pabba_off[2*i+1];
01536                 tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i+1));
01537                 cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i)); 
01538                 cpl_image_divide_scalar(tmp_ima, 2.0);
01539                 cpl_imagelist_set(nodded, tmp_ima, i);
01540             }
01541         }
01542     } else {
01543         cpl_msg_error(cpl_func, "Unsupported chopping mode");
01544         return NULL;
01545     }
01546 
01547     /* Subtract the first offset to the others */
01548     ref_off = cpl_vector_get(*nodded_off, 0);
01549     cpl_vector_subtract_scalar(*nodded_off, ref_off);
01550     return nodded;
01551 }
01552 
01553 /*----------------------------------------------------------------------------*/
01562 /*----------------------------------------------------------------------------*/
01563 static cpl_imagelist * isaac_spc_jitter_distor(
01564         cpl_imagelist   *   ilist,
01565         const char      *   arc,
01566         const char      *   startrace) 
01567 {
01568     cpl_polynomial      *   arc_poly;
01569     cpl_polynomial      *   sttr_poly;
01570     cpl_table           *   tab;
01571     cpl_size                power[2];
01572     cpl_vector          *   profile;
01573     cpl_imagelist       *   warped_list;
01574     cpl_image           *   warped;
01575     int                     i;
01576     
01577     /* Test entries */
01578     if (ilist == NULL) return NULL;
01579     if ((arc == NULL) && (startrace == NULL)) return NULL;
01580 
01581     /* Get the arc polynomial */
01582     arc_poly = cpl_polynomial_new(2);
01583     if (arc != NULL) {
01584         cpl_msg_info(cpl_func, "Get the arc distortion from the file");
01585         if ((tab = cpl_table_load(arc, 1, 0)) == NULL) {
01586             cpl_msg_error(cpl_func, "cannot load the arc table");
01587             cpl_polynomial_delete(arc_poly);
01588             return NULL;
01589         }
01590         for (i=0; i<cpl_table_get_nrow(tab); i++) {
01591             if (cpl_table_get_column_type(tab, "Degree_of_x") == CPL_TYPE_INT) {
01592                 power[0] = cpl_table_get_int(tab, "Degree_of_x", i, NULL); 
01593                 power[1] = cpl_table_get_int(tab, "Degree_of_y", i, NULL); 
01594             } else {
01595                 power[0] = cpl_table_get_double(tab, "Degree_of_x", i, NULL); 
01596                 power[1] = cpl_table_get_double(tab, "Degree_of_y", i, NULL); 
01597             }
01598             cpl_polynomial_set_coeff(arc_poly, power,
01599                     cpl_table_get_double(tab, "poly2d_coef", i, NULL));
01600         }
01601         cpl_table_delete(tab);
01602     } else {
01603         cpl_msg_info(cpl_func, "Use the ID polynomial for the arc dist");
01604         power[0] = 1;
01605         power[1] = 0;
01606         cpl_polynomial_set_coeff(arc_poly, power, 1.0);
01607     }
01608  
01609     /* Get the startrace polynomial */
01610     sttr_poly = cpl_polynomial_new(2);
01611     if (startrace != NULL) {
01612         cpl_msg_info(cpl_func, "Get the startrace distortion from the file");
01613         if ((tab = cpl_table_load(startrace, 1, 0)) == NULL) {
01614             cpl_msg_error(cpl_func, "cannot load the startrace table");
01615             cpl_polynomial_delete(arc_poly);
01616             cpl_polynomial_delete(sttr_poly);
01617             return NULL;
01618         }
01619         for (i=0; i<cpl_table_get_nrow(tab); i++) {
01620             
01621             if (cpl_table_get_column_type(tab, "Degree_of_x") == CPL_TYPE_INT) {
01622                 power[0] = cpl_table_get_int(tab, "Degree_of_x", i, NULL); 
01623                 power[1] = cpl_table_get_int(tab, "Degree_of_y", i, NULL); 
01624             } else {
01625                 power[0] = cpl_table_get_double(tab, "Degree_of_x", i, NULL); 
01626                 power[1] = cpl_table_get_double(tab, "Degree_of_y", i, NULL); 
01627             }
01628             cpl_polynomial_set_coeff(sttr_poly, power,
01629                     cpl_table_get_double(tab, "poly2d_coef", i, NULL));
01630         }
01631         cpl_table_delete(tab);
01632     } else {
01633         cpl_msg_info(cpl_func, "Use the ID polynomial for the startrace dist");
01634         power[0] = 0;
01635         power[1] = 1;
01636         cpl_polynomial_set_coeff(sttr_poly, power, 1.0);
01637     }
01638    
01639     /* Create the kernel */
01640     profile = cpl_vector_new(CPL_KERNEL_DEF_SAMPLES);
01641     cpl_vector_fill_kernel_profile(profile, CPL_KERNEL_DEFAULT,
01642             CPL_KERNEL_DEF_WIDTH);
01643 
01644     /* Correct the images */
01645     warped_list = cpl_imagelist_new();
01646     for (i=0; i<cpl_imagelist_get_size(ilist); i++) {
01647         warped = cpl_image_duplicate(cpl_imagelist_get(ilist, i));
01648         if (cpl_image_warp_polynomial(warped, cpl_imagelist_get(ilist, i), 
01649                     arc_poly, sttr_poly, profile, CPL_KERNEL_DEF_WIDTH, profile,
01650                     CPL_KERNEL_DEF_WIDTH) != CPL_ERROR_NONE) {
01651             cpl_msg_error(cpl_func, "cannot correct the distortion");
01652             cpl_image_delete(warped);
01653             cpl_polynomial_delete(arc_poly);
01654             cpl_polynomial_delete(sttr_poly);
01655             cpl_vector_delete(profile);
01656             return NULL;
01657         }
01658         cpl_imagelist_set(warped_list, warped, i);
01659     }
01660     cpl_vector_delete(profile);
01661     cpl_polynomial_delete(arc_poly);
01662     cpl_polynomial_delete(sttr_poly);
01663     return warped_list;
01664 }
01665 
01666 /*----------------------------------------------------------------------------*/
01674 /*----------------------------------------------------------------------------*/
01675 static double isaac_spc_jitter_refine_offset(const cpl_image   *   ima1,
01676                                              const cpl_image   *   ima2)
01677 {
01678     double                  pos1, pos2;
01679 
01680     /* Test entries */
01681     if (ima1 == NULL) return 10000.0;
01682     if (ima2 == NULL) return 10000.0;
01683     
01684     /* Detect the spectra */
01685     if (irplib_spectrum_find_brightest(ima1, 0.0, NO_SHADOW, 0.0, 0, 
01686                 &pos1) == -1){
01687         return 10000.0;
01688     }
01689     if (irplib_spectrum_find_brightest(ima2, 0.0, NO_SHADOW, 0.0, 0,
01690                 &pos2) == -1){
01691         return 10000.0;
01692     }
01693     return pos1-pos2;
01694 }
01695 
01696 /*----------------------------------------------------------------------------*/
01703 /*----------------------------------------------------------------------------*/
01704 static cpl_table * isaac_spc_jitter_extract(const cpl_image * combined)
01705 {
01706     int                     lo_dist, hi_dist, lo_width, hi_width, spec_pos;
01707     int                     nx, ny;
01708     double                  pos;
01709     int                     low_side, up_side;
01710     int                     sky_pos[4];
01711     cpl_vector          *   sky;
01712     cpl_vector          *   spec;
01713     cpl_vector          *   wl;
01714     cpl_image           *   colfluximg;
01715     double              *   pspec;
01716     double              *   psky;
01717     double              *   pwl;
01718     cpl_table           *   out;
01719     cpl_bivector        *   toplot;
01720     int                     i;
01721 
01722     /* Test entries */
01723     if (combined == NULL) return NULL;
01724 
01725     /* Initialise */
01726     nx = cpl_image_get_size_x(combined);
01727     ny = cpl_image_get_size_y(combined);
01728     lo_dist = isaac_spc_jitter_config.extr_sky_lo_dist;
01729     hi_dist = isaac_spc_jitter_config.extr_sky_hi_dist;
01730     lo_width = isaac_spc_jitter_config.extr_sky_lo_width;
01731     hi_width = isaac_spc_jitter_config.extr_sky_hi_width;
01732     spec_pos = isaac_spc_jitter_config.extr_spec_pos;
01733 
01734     /* Detect the spectrum position if not passed */
01735     if (spec_pos < 0) {
01736         const int nthrow = cpl_vector_get_size(isaac_spc_jitter_config.throws);
01737 
01738         if (nthrow < 1) {
01739             cpl_msg_error(cpl_func, 
01740                     "Need a throw value to detect the spectra !!");
01741             cpl_ensure(0, CPL_ERROR_DATA_NOT_FOUND, NULL);
01742         }
01743         
01744         for (i=0; i < nthrow; i++){
01745             const int throw = (int)cpl_vector_get(isaac_spc_jitter_config.throws,
01746                                                   i);
01747             if (irplib_spectrum_find_brightest(combined, throw, TWO_SHADOWS,
01748                                                0.0, 0, &pos) == 0) break;
01749             if (irplib_spectrum_find_brightest(combined, throw, ONE_SHADOW,
01750                                                0.0, 0, &pos) == 0) break;
01751         }
01752         if (i == nthrow) {
01753             cpl_msg_error(cpl_func, "Could not detect the spectrum using %d "
01754                           "throw(s):", i);
01755 #if 0
01756             cpl_vector_dump(isaac_spc_jitter_config.throws, stderr);
01757             cpl_plot_image("", "", "", combined); 
01758 #endif
01759             cpl_ensure(0, CPL_ERROR_DATA_NOT_FOUND, NULL);
01760         }
01761         spec_pos = (int)pos;
01762         cpl_msg_info(cpl_func, "Spectrum detected at y = %d", spec_pos);
01763     }
01764 
01765     /* Set the parameters for the extraction */
01766 
01767     /* Spectrum position */
01768     low_side = spec_pos - (int)(isaac_spc_jitter_config.extr_spec_width/2);
01769     up_side = low_side + isaac_spc_jitter_config.extr_spec_width;
01770     if (up_side < low_side) {
01771         (void)cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
01772                                     "Spectrum zone invalid: low=%d > up=%d",
01773                                     low_side, up_side);
01774         return NULL;
01775     }
01776     if (low_side < 1) {
01777         (void)cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
01778                                     "Spectrum zone lower limit too low: "
01779                                     "%d < 1", low_side);
01780         return NULL;
01781     }
01782     if (up_side > ny) {
01783         (void)cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
01784                                     "Spectrum zone upper limit too high: "
01785                                     "%d > ny=%d", up_side, ny);
01786         return NULL;
01787     }
01788 
01789     /* Form a 1D single-row-image comprising the column fluxes of the zone */
01790     colfluximg = cpl_image_collapse_window_create(combined, 1, low_side,
01791                                                   nx, up_side, 0);
01792 
01793     if (cpl_image_count_rejected(colfluximg) == up_side - low_side + 1) {
01794         (void)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
01795                                     "Combined image has undefined flux "
01796                                     "from column %d to %d", low_side, up_side);
01797         cpl_image_delete(colfluximg);
01798         return NULL;
01799     }
01800 
01801     /* Residual Sky position */
01802     if (lo_dist < 0) lo_dist = 2*isaac_spc_jitter_config.extr_spec_width;
01803     if (hi_dist < 0) hi_dist = 2*isaac_spc_jitter_config.extr_spec_width;
01804     sky_pos[1] = spec_pos - lo_dist;
01805     sky_pos[0] = sky_pos[1] - lo_width;
01806     sky_pos[2] = spec_pos + hi_dist;
01807     sky_pos[3] = sky_pos[2] + hi_width;
01808 
01809     /* Get the sky */
01810     sky = cpl_vector_new(nx);
01811     psky = cpl_vector_get_data(sky);
01812     if (((sky_pos[0] < 1) || (lo_width == 0)) && 
01813             ((sky_pos[3] <= ny) && (hi_width > 0))) {
01814         for (i=0; i<nx; i++) {
01815             psky[i] = cpl_image_get_median_window(combined, i+1,
01816                     sky_pos[2], i+1, sky_pos[3]);
01817         }
01818     } else if (((sky_pos[3] > ny) || (hi_width == 0))
01819             && ((sky_pos[0] > 0) && (lo_width > 0))) {
01820         for (i=0; i<nx; i++) {
01821             psky[i] = cpl_image_get_median_window(combined, i+1,
01822                     sky_pos[0], i+1, sky_pos[1]);
01823         }
01824     } else if ((lo_width != 0) && (hi_width != 0)
01825             && (sky_pos[0] > 0) && (sky_pos[3] <= ny)) {
01826         for (i=0; i<nx; i++) {
01827             psky[i] = cpl_image_get_median_window(combined, i+1,
01828                     sky_pos[2], i+1, sky_pos[3]);
01829             psky[i] += cpl_image_get_median_window(combined, i+1,
01830                     sky_pos[0], i+1, sky_pos[1]);
01831             psky[i] /= 2.0;
01832         }
01833     } else {
01834         for (i=0; i<nx; i++) psky[i] = 0.0;
01835     }
01836 
01837     /* Estimate the spectrum */
01838     spec = cpl_vector_new(nx);
01839     pspec = cpl_vector_get_data(spec);
01840     for (i=0; i<nx; i++) {
01841         int is_bad = 0;
01842         const double colflux = cpl_image_get(colfluximg, i+1, 1, &is_bad);
01843 
01844         if (is_bad) {
01845             pspec[i] = 0.0;
01846             cpl_msg_warning(cpl_func, "Combined image has undefined flux in "
01847                             "column %d", i+1);
01848         } else {
01849             pspec[i] = colflux
01850                 - psky[i] * isaac_spc_jitter_config.extr_spec_width;
01851         }
01852     } 
01853     cpl_image_delete(colfluximg);
01854 
01855     /* Get the wavelength */
01856     wl = cpl_vector_new(nx);
01857     pwl = cpl_vector_get_data(wl);
01858     for (i=0; i<nx; i++) {
01859         pwl[i] = isaac_spc_jitter_config.wavecal_a0 +
01860             isaac_spc_jitter_config.wavecal_a1 * (i+1) +
01861             isaac_spc_jitter_config.wavecal_a2 * (i+1) * (i+1) +
01862             isaac_spc_jitter_config.wavecal_a3 * (i+1) * (i+1) * (i+1);
01863     }
01864 
01865     /* Plot the spectrum if requested */
01866     if (isaac_spc_jitter_config.plot > 0) {
01867         toplot = cpl_bivector_wrap_vectors(wl, spec);
01868         cpl_plot_bivector(NULL, "t 'Spectrum' w lines", NULL, toplot);
01869         cpl_bivector_unwrap_vectors(toplot);
01870         toplot = cpl_bivector_wrap_vectors(wl, sky);
01871         cpl_plot_bivector(NULL, "t 'Sky' w lines", NULL, toplot);
01872         cpl_bivector_unwrap_vectors(toplot);
01873     }
01874     
01875     /* Create and fill the output table */
01876     out = cpl_table_new(nx);
01877     cpl_table_new_column(out, "X_coordinate", CPL_TYPE_DOUBLE);
01878     cpl_table_new_column(out, "Extracted_spectrum_value", CPL_TYPE_DOUBLE);
01879     cpl_table_new_column(out, "Sky_spectrum", CPL_TYPE_DOUBLE);
01880     for (i=0; i<nx; i++) {
01881         cpl_table_set_double(out, "X_coordinate", i, pwl[i]);
01882         cpl_table_set_double(out, "Extracted_spectrum_value", i, pspec[i]);
01883         cpl_table_set_double(out, "Sky_spectrum", i, psky[i]);
01884     }
01885     cpl_vector_delete(wl);
01886     cpl_vector_delete(spec);
01887     cpl_vector_delete(sky);
01888     return out;
01889 }
01890 
01891 /*----------------------------------------------------------------------------*/
01902 /*----------------------------------------------------------------------------*/
01903 static int isaac_spc_jitter_std(const char      * seds_file,
01904                                 const char      * stdstars,
01905                                 const cpl_frame * frame,
01906                                 cpl_table       * tab,
01907                                 double          mag)
01908 {
01909     double                  surface = CPL_MATH_PI * 400 * 400;
01910     cpl_propertylist    *   plist;
01911     double                  dit, ra, dec, magnitude, cent_wl;
01912     isaac_band              band;
01913     const int               nelem = cpl_table_get_nrow(tab);
01914     cpl_vector          *   wl;
01915     cpl_vector          *   spec;
01916     cpl_bivector        *   spec_biv;
01917     cpl_bivector        *   sed;
01918     cpl_vector          *   efficiency;
01919     cpl_vector          *   mag_zero;
01920     cpl_vector          *   conversion;
01921     int                     i;
01922 
01923     /* Test entries */
01924     if (seds_file == NULL) return -1;
01925     if (stdstars == NULL) return -1;
01926     if (frame == NULL) return -1;
01927     if (tab == NULL) return -1;
01928     if (cpl_error_get_code()) return -1;
01929 
01930     /* Get the propertylist */
01931     if ((plist=cpl_propertylist_load(cpl_frame_get_filename(frame),0))==NULL) {
01932         cpl_msg_error(cpl_func, "Cannot load the property list");
01933         return -1;
01934     }
01935     
01936     /* Get DIT */
01937     dit = isaac_pfits_get_dit(plist);
01938     if (cpl_error_get_code()) {
01939         cpl_msg_error(cpl_func, "Cannot get DIT");
01940         cpl_propertylist_delete(plist); 
01941         return -1;
01942     }
01943     cpl_msg_info(cpl_func, "DIT:   %g", dit);
01944     
01945     /* Get band */
01946     if ((band = isaac_get_associated_filter(isaac_spc_jitter_config.filter)) 
01947             == ISAAC_BAND_UNKNOWN) {
01948         cpl_msg_error(cpl_func, "Cannot associate the filter to a BB one");
01949         cpl_propertylist_delete(plist); 
01950         return -1;
01951     }
01952     cpl_msg_info(cpl_func, "Band : %s", isaac_std_band_name(band));
01953 
01954     /* Get RA / DEC */
01955     ra = isaac_pfits_get_ra(plist);
01956     dec = isaac_pfits_get_dec(plist);
01957     if (cpl_error_get_code()) {
01958         cpl_msg_error(cpl_func, "Cannot get star position");
01959         cpl_propertylist_delete(plist); 
01960         return -1;
01961     }
01962     cpl_msg_info(cpl_func, "RA:  %g  DEC:  %g", ra, dec);
01963 
01964     /* Get magnitude */
01965     if (mag < 0) {
01966         /* Reference star */
01967         if (irplib_stdstar_find_star(stdstars, ra, dec,
01968         isaac_std_band_name(isaac_get_bbfilter(isaac_spc_jitter_config.filter)),
01969                                      "all", &magnitude,
01970                                      &isaac_spc_jitter_config.starname,
01971                                      &isaac_spc_jitter_config.sptype,
01972                                      NULL, NULL, NULL, 2.0)) {
01973             cpl_msg_error(cpl_func, "Cannot find the star in catalogs");
01974             cpl_propertylist_delete(plist); 
01975             return -1;
01976         }
01977     } else { 
01978         magnitude = mag;
01979     }
01980     cpl_propertylist_delete(plist); 
01981     (void)strncpy(isaac_spc_jitter_config.filter_ref, 
01982                   isaac_std_band_name(isaac_get_bbfilter
01983                                       (isaac_spc_jitter_config.filter)),
01984                   KEYSIZE-1);
01985     cpl_msg_info(cpl_func, "Magnitude: %g", magnitude);
01986     isaac_spc_jitter_config.std_magnitude = magnitude;
01987     
01988     /* Get band center */
01989     switch (band) {
01990         case ISAAC_BAND_Z:        cent_wl = CENT_WL_BAND_Z;  break;
01991         case ISAAC_BAND_SZ:       cent_wl = CENT_WL_BAND_SZ; break;
01992         case ISAAC_BAND_J:        cent_wl = CENT_WL_BAND_J;  break;
01993         case ISAAC_BAND_JBLOCK:   cent_wl = CENT_WL_BAND_J;  break;
01994         case ISAAC_BAND_SH:       cent_wl = CENT_WL_BAND_H;  break;
01995         case ISAAC_BAND_SK:       cent_wl = CENT_WL_BAND_K;  break;
01996         case ISAAC_BAND_SL:       cent_wl = CENT_WL_BAND_SL; break;
01997         case ISAAC_BAND_M:        cent_wl = CENT_WL_BAND_M;  break;
01998         default:
01999             cpl_msg_error(cpl_func, "Unsupported band: %s", 
02000                     isaac_std_band_name(band));
02001             return -1;
02002     }
02003     cpl_msg_info(cpl_func, "Center of band : %g microns", cent_wl);
02004    
02005     /* Get the SED */
02006     sed = irplib_stdstar_get_sed(seds_file, isaac_spc_jitter_config.sptype);
02007     if (sed == NULL) {
02008         cpl_msg_error(cpl_func, "Cannot get the SED");
02009         return -1;
02010     }
02011 
02012     /* Put the spectrum in a bivector */
02013     wl = cpl_vector_wrap(nelem, cpl_table_get_data_double(tab,
02014                 "X_coordinate"));
02015     spec = cpl_vector_wrap(nelem, cpl_table_get_data_double(tab,
02016                 "Extracted_spectrum_value"));
02017     spec_biv = cpl_bivector_wrap_vectors(wl, spec);
02018 
02019     /* Get the conversion */
02020     if ((conversion = irplib_stdstar_get_conversion(spec_biv, dit, surface,
02021                     4.5, magnitude)) == NULL) {
02022         cpl_msg_error(cpl_func, "Cannot get the conversion");
02023         cpl_bivector_unwrap_vectors(spec_biv);
02024         cpl_vector_unwrap(spec);
02025         cpl_vector_unwrap(wl);
02026         cpl_bivector_delete(sed);
02027         return -1;
02028     }
02029 
02030     /* Get the 0 magnitude spectrum */
02031     if ((mag_zero = irplib_stdstar_get_mag_zero(sed, 
02032                     cpl_bivector_get_x(spec_biv), cent_wl)) == NULL) {
02033         cpl_msg_error(cpl_func, "Cannot get the 0 magnitude spectrum");
02034         cpl_bivector_unwrap_vectors(spec_biv);
02035         cpl_vector_unwrap(spec);
02036         cpl_vector_unwrap(wl);
02037         cpl_bivector_delete(sed);
02038         cpl_vector_delete(conversion);
02039         return -1;
02040     }
02041     cpl_bivector_unwrap_vectors(spec_biv);
02042     cpl_vector_unwrap(spec);
02043     cpl_vector_unwrap(wl);
02044     cpl_bivector_delete(sed);
02045 
02046     /* Set the mag_zero 0 values to 1 */
02047     for (i=0; i<cpl_vector_get_size(mag_zero); i++) {
02048         if (cpl_vector_get(mag_zero, i) < 1e-19) {
02049             cpl_vector_set(mag_zero, i, 1.0);
02050         }
02051     }
02052 
02053     /* Get the efficiency */
02054     efficiency = cpl_vector_duplicate(conversion);
02055     if (cpl_vector_divide(efficiency, mag_zero) != CPL_ERROR_NONE) {
02056         cpl_msg_error(cpl_func, "Missing SED info in this wavelength range");
02057         cpl_vector_delete(conversion);
02058         cpl_vector_delete(mag_zero);
02059         cpl_vector_delete(efficiency);
02060         return -1;
02061     }
02062 
02063     /* Set the efficiency to 0 where the mag_zero is 1 */
02064     for (i=0; i<cpl_vector_get_size(mag_zero); i++) {
02065         if (cpl_vector_get(mag_zero, i) == 1.0) {
02066             cpl_vector_set(efficiency, i, 0.0);
02067         }
02068     }
02069     cpl_vector_delete(mag_zero);
02070 
02071     /* Create extra columns for the results */
02072     cpl_table_wrap_double(tab, cpl_vector_get_data(efficiency), "Efficiency");
02073     cpl_table_wrap_double(tab, cpl_vector_get_data(conversion), "Conversion");
02074     cpl_vector_unwrap(efficiency);
02075     cpl_vector_unwrap(conversion);
02076 
02077     /* Plot the spectra if requested */
02078     if (isaac_spc_jitter_config.plot > 0) {
02079         wl = cpl_vector_wrap(nelem, cpl_table_get_data_double(tab,
02080                     "X_coordinate"));
02081         spec = cpl_vector_wrap(nelem, cpl_table_get_data_double(tab,
02082                     "Conversion"));
02083         spec_biv = cpl_bivector_wrap_vectors(wl, spec);
02084         cpl_plot_bivector(NULL, "t 'Conversion' w lines", 
02085                 NULL, spec_biv);
02086         cpl_bivector_unwrap_vectors(spec_biv);
02087         cpl_vector_unwrap(spec);
02088         spec = cpl_vector_wrap(nelem, cpl_table_get_data_double(tab,
02089                     "Efficiency"));
02090         spec_biv = cpl_bivector_wrap_vectors(wl, spec);
02091         cpl_plot_bivector(NULL, "t 'Efficiency' w lines", NULL, spec_biv);
02092         cpl_bivector_unwrap_vectors(spec_biv);
02093         cpl_vector_unwrap(spec);
02094         cpl_vector_unwrap(wl);
02095     }
02096     
02097     return 0;
02098 }
02099 
02100 /*----------------------------------------------------------------------------*/
02111 /*----------------------------------------------------------------------------*/
02112 static
02113 cpl_error_code isaac_spc_jitter_save(cpl_frameset            * set,
02114                                      const cpl_image         * ima,
02115                                      const cpl_image         * contrib,
02116                                      const cpl_table         * tab,
02117                                      const cpl_parameterlist * parlist)
02118 {
02119     /* Get the QC params in qclist */
02120     cpl_propertylist    *   qclist = cpl_propertylist_new();
02121     cpl_propertylist    *   paflist = NULL;
02122     const cpl_frame     *   ref_frame;
02123     char                *   qc_str = NULL;
02124     const char          *   procat;
02125     const int               nintens
02126         = cpl_vector_get_size(isaac_spc_jitter_config.intensities);
02127     int                     i;
02128     cpl_propertylist * xtlist = cpl_propertylist_new();
02129 
02130     bug_if(cpl_propertylist_append_string(xtlist, "EXTNAME",
02131                                           "Contribution Map"));
02132     bug_if(contrib == NULL);
02133 
02134     /* Add QC parameters */
02135     /* FIXME: Fill this list where the numbers are available */
02136     if (isaac_spc_jitter_config.filter[0] != (char)0) 
02137         bug_if(cpl_propertylist_append_string(qclist, "ESO QC FILTER OBS",
02138                                               isaac_spc_jitter_config.filter));
02139 
02140     bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISPCO1",
02141                                           isaac_spc_jitter_config.wavecal_a0));
02142     cpl_propertylist_append_double(qclist, "ESO QC DISPCO2",
02143                                    isaac_spc_jitter_config.wavecal_a1);
02144     cpl_propertylist_append_double(qclist, "ESO QC DISPCO3",
02145                                    isaac_spc_jitter_config.wavecal_a2);
02146     cpl_propertylist_append_double(qclist, "ESO QC DISPCO4",
02147                                    isaac_spc_jitter_config.wavecal_a3);
02148     cpl_propertylist_append_double(qclist, "ESO QC WLEN",
02149                                    isaac_spc_jitter_config.wavecal_a0 +
02150                                    isaac_spc_jitter_config.wavecal_a1 * 512 +
02151                                    isaac_spc_jitter_config.wavecal_a2 * 512 *
02152                                    512 +
02153                                    isaac_spc_jitter_config.wavecal_a3 * 512 *
02154                                    512 * 512);
02155     bug_if(cpl_propertylist_append_double(qclist, "ESO QC DISP XCORR",
02156                                           isaac_spc_jitter_config.wavecal_cc));
02157     if (isaac_spc_jitter_config.wavecal_out == 0) {
02158         cpl_propertylist_append_string(qclist, "ESO QC WLMETHOD",
02159                 "physical model");
02160     } else if (isaac_spc_jitter_config.wavecal_out == 1) {
02161         cpl_propertylist_append_string(qclist, "ESO QC WLMETHOD",
02162                 "sky lines");
02163     } else if (isaac_spc_jitter_config.wavecal_out == 2) {
02164         cpl_propertylist_append_string(qclist, "ESO QC WLMETHOD",
02165                 "arc file");
02166     }
02167     for (i = 0; i < nintens; i++) {
02168         const double intens
02169             = cpl_vector_get(isaac_spc_jitter_config.intensities, i);
02170 
02171         qc_str = cpl_sprintf("ESO QC SPEC INTENS%d", i+1);
02172         cpl_propertylist_append_double(qclist, qc_str, intens);
02173         cpl_free(qc_str);
02174         qc_str = NULL;
02175     }
02176     
02177     /* In std mode */
02178     if (isaac_spc_jitter_config.std_mode == 1) {
02179         bug_if(cpl_propertylist_append_string(qclist, "ESO QC STDNAME",
02180                                               isaac_spc_jitter_config.starname ?
02181                                               isaac_spc_jitter_config.starname :
02182                                               ""));
02183         bug_if(cpl_propertylist_append_string(qclist, "ESO QC SPECTYPE",
02184                                               isaac_spc_jitter_config.sptype ?
02185                                               isaac_spc_jitter_config.sptype :
02186                                               ""));
02187         cpl_propertylist_append_double(qclist, "ESO QC STARMAG",
02188                                        isaac_spc_jitter_config.std_magnitude);
02189         if (isaac_spc_jitter_config.filter_ref[0] != (char)0) 
02190             cpl_propertylist_append_string(qclist, "ESO QC FILTER REF",
02191                                            isaac_spc_jitter_config.filter_ref);
02192     }
02193 
02194     /* Change WCS keywords to the computed wavelength solution */
02195     cpl_propertylist_update_double(qclist, "CRVAL1",
02196                                    isaac_spc_jitter_config.wavecal_a0);
02197     cpl_propertylist_update_double(qclist, "CRVAL2", 1.0);
02198     cpl_propertylist_update_double(qclist, "CRPIX1", 1.0);
02199     cpl_propertylist_update_double(qclist, "CRPIX2", 1.0);
02200     cpl_propertylist_update_double(qclist, "CDELT1", 
02201                                    isaac_spc_jitter_config.wavecal_a1);
02202     cpl_propertylist_update_double(qclist, "CDELT2", 1.0);
02203     cpl_propertylist_update_string(qclist, "CTYPE1", "LINEAR");
02204     cpl_propertylist_update_string(qclist, "CTYPE2", "LINEAR");
02205     if (cpl_propertylist_has(qclist, "CD1_1")) {
02206         cpl_propertylist_update_double(qclist, "CD1_1",
02207                                        isaac_spc_jitter_config.wavecal_a1);
02208     } else {
02209         cpl_propertylist_insert_after_double(qclist, "CTYPE2", "CD1_1",
02210                                              isaac_spc_jitter_config.wavecal_a1);
02211     }
02212     if (cpl_propertylist_has(qclist, "CD2_2")) {
02213         cpl_propertylist_update_double(qclist, "CD2_2", 1.0);
02214     } else {
02215         cpl_propertylist_insert_after_double(qclist, "CD1_1", "CD2_2", 1.0);
02216     }
02217 
02218     /* Write the image  */
02219     procat = isaac_spc_jitter_config.std_mode == 1 ?
02220         ISAAC_SPC_JITTER_COMB_STD : ISAAC_SPC_JITTER_COMB;
02221 
02222     irplib_dfs_save_image(set, parlist, set, ima, CPL_BPP_IEEE_FLOAT,
02223                           RECIPE_STRING, procat, qclist, NULL,
02224                           PACKAGE "/" PACKAGE_VERSION,
02225                           RECIPE_STRING "_combined" CPL_DFS_FITS);
02226 
02227     /* Append the contribution map */
02228     skip_if (cpl_image_save(contrib, RECIPE_STRING "_combined" CPL_DFS_FITS,
02229                             CPL_BPP_16_UNSIGNED, xtlist, CPL_IO_EXTEND));
02230 
02231     /* Write the table  */
02232     if (tab != NULL) {
02233         const char * procatt = isaac_spc_jitter_config.std_mode == 1 ?
02234             ISAAC_SPC_JITTER_EXTR_STD : ISAAC_SPC_JITTER_EXTR;
02235 
02236         irplib_dfs_save_table(set, parlist, set, tab, NULL, RECIPE_STRING,
02237                               procatt, qclist, NULL,
02238                               PACKAGE "/" PACKAGE_VERSION,
02239                               RECIPE_STRING "_extracted"  CPL_DFS_FITS);
02240     }
02241 
02242     /* Get the reference frame */
02243     ref_frame = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW);
02244 
02245     /* Get the keywords for the paf file from the reference file */
02246     paflist = cpl_propertylist_load_regexp(cpl_frame_get_filename(ref_frame),
02247                                            0, "^(ARCFILE|MJD-OBS|INSTRUME"
02248                                            "|ESO TPL ID|ESO TPL NEXP"
02249                                            "|ESO DPR CATG|ESO DPR TECH"
02250                                            "|ESO DPR TYPE|DATE-OBS"
02251                                            "|ESO INS GRAT NAME"
02252                                            "|ESO INS GRAT WLEN"
02253                                            "|ESO INS OPTI1 ID|ESO OBS ID"
02254                                            "|ESO OBS TARG NAME)$", 0);
02255     skip_if (paflist == NULL);
02256 
02257     /* Copy the QC in paflist */
02258     bug_if(cpl_propertylist_append(paflist, qclist));
02259     cpl_propertylist_empty(qclist);
02260 
02261     /* PRO.CATG */
02262     cpl_propertylist_update_string(paflist, CPL_DFS_PRO_CATG, procat);
02263 
02264     /* Save the PAF file */
02265     skip_if(cpl_dfs_save_paf("ISAAC", RECIPE_STRING, paflist,
02266                              RECIPE_STRING CPL_DFS_PAF));
02267 
02268     end_skip;
02269 
02270     cpl_propertylist_delete(xtlist);
02271     cpl_propertylist_delete(paflist);
02272     cpl_propertylist_delete(qclist);
02273     cpl_free(qc_str);
02274 
02275     return CPL_ERROR_NONE;
02276 }
02277 
02278 /*----------------------------------------------------------------------------*/
02287 /*----------------------------------------------------------------------------*/
02288 static int off_comp(double off1, double off2, double thresh)
02289 {
02290     return (off1 > thresh && off2 < thresh) || (off1 < thresh && off2 > thresh)
02291         ? 1 : 0;
02292 }
02293 
Generated on Mon Feb 17 15:04:44 2014 for ISAAC Pipeline Reference Manual by  doxygen 1.6.3