isaac_spc_jitter.c

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

Generated on Wed Mar 9 15:43:10 2011 for ISAAC Pipeline Reference Manual by  doxygen 1.5.8