/*                                                                            *
 *   This file is part of the ESO X-shooter Pipeline                          *
 *   Copyright (C) 2006 European Southern Observatory                         *
 *                                                                            *
 *   This library is free software; you can redistribute it and/or modify     *
 *   it under the terms of the GNU General Public License as published by     *
 *   the Free Software Foundation; either version 2 of the License, or        *
 *   (at your option) any later version.                                      *
 *                                                                            *
 *   This program is distributed in the hope that it will be useful,          *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of           *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
 *   GNU General Public License for more details.                             *
 *                                                                            *
 *   You should have received a copy of the GNU General Public License        *
 *   along with this program; if not, write to the Free Software              *
 *   Foundation, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA     *
 *                                                                            */

/*
 * $Author: amodigli $
 * $Date: 2013-08-29 10:51:41 $
 * $Revision: 1.277 $
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/*----------------------------------------------------------------------------*/
/**
 * @defgroup xsh_slit_stare   xsh_scired_slit_stare
 * @ingroup recipes
 *
 * This recipe ...
 * See man-page for details.
 */
/*----------------------------------------------------------------------------*/
/**@{*/

/*-----------------------------------------------------------------------------
  Includes
  ----------------------------------------------------------------------------*/


/* DRL steps */

/* Error handling */
#include <xsh_error.h>
/* Utility fonctions */
#include <xsh_utils.h>
#include <xsh_utils_scired_slit.h>
#include <xsh_msg.h>
/* DFS functions */
#include <xsh_dfs.h>
#include <xsh_pfits.h>
/* DRL functions */
#include <xsh_utils_image.h>
#include <xsh_utils_scired_slit.h>
#include <xsh_data_instrument.h>
#include <xsh_data_spectrum1D.h>
#include <xsh_data_spectrum.h>
#include <xsh_drl_check.h>
#include <xsh_drl.h>
#include <xsh_model_utils.h>
#include <xsh_model_arm_constants.h>

/* Library */
#include <cpl.h>
/* CRH Remove */

/*-----------------------------------------------------------------------------
  Defines
  ----------------------------------------------------------------------------*/

#define RECIPE_ID "xsh_scired_slit_stare"
#define RECIPE_AUTHOR "P.Goldoni, L.Guglielmi, R. Haigron, F. Royer, D. Bramich, A. Modigliani"
#define RECIPE_CONTACT "amodigli@eso.org"

/*-----------------------------------------------------------------------------
  Functions prototypes
  ----------------------------------------------------------------------------*/

/*
 *   Plugin initalization, execute and cleanup handlers
 */


static int xsh_scired_slit_stare_create(cpl_plugin *);
static int xsh_scired_slit_stare_exec(cpl_plugin *);
static int xsh_scired_slit_stare_destroy(cpl_plugin *);

/* The actual executor function */
static cpl_error_code xsh_scired_slit_stare(cpl_parameterlist *, cpl_frameset *);

/*-----------------------------------------------------------------------------
  Static variables
  ----------------------------------------------------------------------------*/
static char xsh_scired_slit_stare_description_short[] =
"Reduce science exposure in SLIT configuration and stare mode";

static char xsh_scired_slit_stare_description[] =
"This recipe reduces science exposure in SLIT configuration and stare mode\n\
Input Frames : \n\
  - A set of n Science frames ( n == 1 or >=3, \
Tag = OBJECT_SLIT_STARE_UVB)\n\
  - A spectral format table (Tag = SPECTRAL_FORMAT_TAB_arm)\n\
  - [UVB,VIS] A master bias frame (Tag = MASTER_BIAS_arm)\n\
  - [OPTIONAL]A master dark frame (Tag = MASTER_DARK_arm)\n\
  - A master flat frame (Tag = MASTER_FLAT_SLIT_arm)\n\
  - An order table frame(Tag = ORDER_TAB_EDGES_SLIT_arm)\n\
  - [OPTIONAL] A table with dispersion coefficients (Tag = DISP_TAB_arm,\n\
    required in poly mode\n\
  - [poly mode] A wave solution frame(Tag = WAVE_TAB_2D_arm)\n\
  - [physical model mode] A model cfg table (Format = TABLE, Tag = XSH_MOD_CFG_TAB_arm)\n\
  - [OPTIONAL] A table specifying multiplying factor for break points \n\
    (Tag = SKY_SUB_BKPTS_arm) to generate\n\
  - [OPTIONAL] A non-linear badpixel map (Tag = BP_MAP_NL_arm)\n\
  - [OPTIONAL] A reference badpixel map (Tag = BP_MAP_RP_arm)\n\
  - [OPTIONAL,physmod mode] A table listing sky line positions (Tag = SKY_LINE_LIST_arm)\n\
    this is used to be able to control quality of sky subtraction, for example\n\
    projecting guess positions on the product SCI_SLIT_STARE_SUB_SKY_arm\n\
  - [OPTIONAL] The instrument response table (Tag = RESPONSE_ORDER1D_SLIT_arm)\n\
  - [OPTIONAL] An atmospheric extinction table (Tag = ATMOS_EXT_arm)\n\
  - [OPTIONAL] A telluric mask (Tag = TELL_MASK_arm)\n\
Products : \n\
  - PREFIX_ORDER2D_arm extracted spectrum, order-by-order, 2D\n\
  - PREFIX_ORDER1D_arm extracted spectrum, order-by-order, 1D\n\
  - PREFIX_MERGE2D_arm merged spectrum, 2D\n\
  - PREFIX_MERGE1D_arm merged spectrum, 1D\n\
  - SKY_SLIT_MERGE2D_arm merged spectrum sky, 2D\n\
  - PREFIX_SUB_BACK_SLIT_arm sci frame bias, (dark), inter-order bkg subtracted\n\
  - PREFIX_WAVE_MAP_arm, wave map image\n\
  - PREFIX_SLIT_MAP_arm, slit map image\n\
  - PREFIX_DIVFF_arm as PREFIX_SUB_BACK_SLIT_arm, flat fielded\n\
  - PREFIX_SUB_SKY_arm, as PREFIX_DIVFF_arm, sky subtracted\n\
  - PREFIX_SKY_arm, 2D sky frame\n\
  - PREFIX_SKY_ORD1D_arm, 1D sky image (order-by-order)\n\
  - PREFIX_BACK_SLIT_arm, inter order background image \n\
  - where PREFIX is SCI, FLUX, TELL if input raw DPR.TYPE contains OBJECT or FLUX or TELLURIC\n\
  - [OPTIONAL, if response and atm ext are provided]  PREFIX_FLUX_ORDER2D_arm (2 dimension)\n\
  - [OPTIONAL, if response and atm ext are provided]  PREFIX_FLUX_ORDER1D_arm (1 dimension)\n\
  - [OPTIONAL, if response and atm ext are provided]  PREFIX_FLUX_MERGE2D_arm (2 dimension)\n\
  - [OPTIONAL, if response and atm ext are provided]  PREFIX_FLUX_MERGE1D_arm (1 dimension)\n\
  - PREFIX_ON_arm bias (dark) subtracted sci frame";

/*-----------------------------------------------------------------------------
  Functions code
  ----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/**
   @brief    Build the list of available plugins, for this module.
   @param    list    the plugin list
   @return   0 if everything is ok, -1 otherwise

   Create the recipe instance and make it available to the application using the
   interface. This function is exported.
*/
/*----------------------------------------------------------------------------*/

int cpl_plugin_get_info(cpl_pluginlist *list) {
  cpl_recipe *recipe = NULL;
  cpl_plugin *plugin = NULL;

  recipe = cpl_calloc(1, sizeof(*recipe));
  if ( recipe == NULL ){
    return -1;
  }

  plugin = &recipe->interface ;

  cpl_plugin_init(plugin,
                  CPL_PLUGIN_API,                    /* Plugin API */
                  XSH_BINARY_VERSION,             /* Plugin version */
                  CPL_PLUGIN_TYPE_RECIPE,            /* Plugin type */
                  RECIPE_ID,                         /* Plugin name */
                  xsh_scired_slit_stare_description_short, /* Short help */
                  xsh_scired_slit_stare_description,       /* Detailed help */
                  RECIPE_AUTHOR,                     /* Author name */
                  RECIPE_CONTACT,                    /* Contact address */
                  xsh_get_license(),                 /* Copyright */
                  xsh_scired_slit_stare_create,
                  xsh_scired_slit_stare_exec,
                  xsh_scired_slit_stare_destroy);

  cpl_pluginlist_append(list, plugin);

  return (cpl_error_get_code() != CPL_ERROR_NONE);
}

/*----------------------------------------------------------------------------*/
/**
   @brief    Setup the recipe options
   @param    plugin  the plugin
   @return   0 if everything is ok

   Create the recipe instance and make it available to the application using the
   interface.

*/
/*----------------------------------------------------------------------------*/

static int xsh_scired_slit_stare_create(cpl_plugin *plugin){
  cpl_recipe *recipe = NULL;

  /* First param (conv_kernel) should be initialized correctly ! */
  xsh_remove_crh_single_param crh_single = { 0.1, 20, 2.0, 4} ;
  xsh_rectify_param rectify = { "tanh",
                                CPL_KERNEL_DEFAULT, 
                                2,
                                -1.0, 
                                -1.0,
                                1,
				0, 0. }; 

  xsh_subtract_sky_single_param sky_single = {3000, 3000,7,20, 5., -1, -1,
                                              MEDIAN_METHOD, FINE,20, 0.5,
                                             0.0, 0.0,
                                             0.0, 0.0} ;

  /* 2nd and 3rd params should be initialized correctly */
  xsh_localize_obj_param loc_obj = 
    {10, 0.1, 0, 0, LOC_MANUAL_METHOD, 0, 2.0,3,3, FALSE};

  xsh_opt_extract_param opt_extract_par = 
     { 5, 10, 10, 0.01, 10.0, 1., 2, 2, GAUSS_METHOD }; 
  xsh_stack_param stack_param = {"median",5.,5.};
  xsh_interpolate_bp_param ipol_par = {30 };
  /* Parameters init */
  opt_extract_par.oversample = 5;
  opt_extract_par.box_hsize = 10;
  opt_extract_par.chunk_size = 50;
  opt_extract_par.lambda_step = 0.02;
  opt_extract_par.clip_kappa = 3;
  opt_extract_par.clip_frac = 0.4;
  opt_extract_par.clip_niter = 2;
  opt_extract_par.niter = 1;
  opt_extract_par.method = GAUSS_METHOD;
  /* Reset library state */
  xsh_init();

  /* Check input */
  assure( plugin != NULL, CPL_ERROR_NULL_INPUT, "Null plugin");

  /* Get the recipe out of the plugin */
  assure( cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE,
          CPL_ERROR_TYPE_MISMATCH,
          "Plugin is not a recipe");

  recipe = (cpl_recipe *)plugin;

  /* Create the parameter list in the cpl_recipe object */
  recipe->parameters = cpl_parameterlist_new();
  assure( recipe->parameters != NULL,
          CPL_ERROR_ILLEGAL_OUTPUT,
          "Memory allocation failed!");

  /* Set generic parameters (common to all recipes) */
  check( xsh_parameters_generic( RECIPE_ID, recipe->parameters ) ) ;
  xsh_parameters_decode_bp(RECIPE_ID,recipe->parameters,-1);
  check( xsh_parameters_pre_overscan( RECIPE_ID, recipe->parameters ) ) ;
  check(xsh_parameters_stack_create(RECIPE_ID,recipe->parameters,stack_param));

  /* subtract_background_params */
  check(xsh_parameters_background_create(RECIPE_ID,recipe->parameters));

  /* remove_crh_single */
  check(xsh_parameters_remove_crh_single_create(RECIPE_ID,recipe->parameters,
						crh_single )) ;

  /* xsh_rectify */
  check(xsh_parameters_rectify_create(RECIPE_ID,recipe->parameters,
					    rectify )) ;

  /* xsh_localize_object */
  check(xsh_parameters_localize_obj_create(RECIPE_ID,recipe->parameters,
					   loc_obj )) ;

  /* xsh_remove_sky_single */
  check(xsh_parameters_subtract_sky_single_create(RECIPE_ID,recipe->parameters,
						  sky_single )) ;

  /* trivial extract (Just temporary) 
  check(xsh_parameters_extract_create(RECIPE_ID,
				      recipe->parameters,
				      extract_par,LOCALIZATION_METHOD )) ;
  */

  check(xsh_parameters_interpolate_bp_create(RECIPE_ID,
                recipe->parameters,ipol_par)) ;

  /* optimal extract */
  check( xsh_parameters_new_boolean( recipe->parameters, RECIPE_ID,
    "do-optextract", FALSE, 
    "TRUE if we do the optimal extraction"));

  check( xsh_parameters_opt_extract_create( RECIPE_ID, recipe->parameters,
    opt_extract_par));

  check( xsh_parameters_new_boolean( recipe->parameters, RECIPE_ID,
    "cut-uvb-spectrum", TRUE, 
    "TRUE if recipe cuts the UVB spectrum at 556 nm (dichroich)"));


  /* Flag for generation of data in SDP format. */
  check( xsh_parameters_new_boolean( recipe->parameters, RECIPE_ID,
    "generate-SDP-format", FALSE,
    "TRUE if additional files should be generated in Science Data Product"
    " (SDP) format."));

  /* Flag for adding dummy ASSO[NCM]i keywords. */
  check( xsh_parameters_new_int( recipe->parameters, RECIPE_ID,
    "dummy-association-keys", 0,
    "Sets the number of dummy (empty) ASSONi, ASSOCi and ASSOMi keywords to"
    " create."));

 cleanup:
  if ( cpl_error_get_code() != CPL_ERROR_NONE ){
    xsh_error_dump(CPL_MSG_ERROR);
    return 1;
  }
  else {
    return 0;
  }
}

/*----------------------------------------------------------------------------*/
/**
   @brief    Execute the plugin instance given by the interface
   @param    plugin  the plugin
   @return   0 if everything is ok
*/
/*----------------------------------------------------------------------------*/

static int xsh_scired_slit_stare_exec(cpl_plugin *plugin) {
  cpl_recipe *recipe = NULL;

  /* Check parameter */

  assure( plugin != NULL, CPL_ERROR_NULL_INPUT, "Null plugin" );

  /* Get the recipe out of the plugin */
  assure( cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE,
          CPL_ERROR_TYPE_MISMATCH, "Plugin is not a recipe");

  recipe = (cpl_recipe *)plugin;

  /* Check recipe */
  xsh_scired_slit_stare(recipe->parameters, recipe->frames);

 cleanup:
  if ( cpl_error_get_code() != CPL_ERROR_NONE ) {
    xsh_error_dump(CPL_MSG_ERROR);
    xsh_error_reset();
    return 1;
  }
  else {
    return 0;
  }
}

/*----------------------------------------------------------------------------*/
/**
   @brief    Destroy what has been created by the 'create' function
   @param    plugin  the plugin
   @return   0 if everything is ok
*/
/*----------------------------------------------------------------------------*/
static int xsh_scired_slit_stare_destroy(cpl_plugin *plugin)
{
  cpl_recipe *recipe = NULL;

  /* reset error state before detroying recipe */
  xsh_error_reset(); 
  /* Check parameter */
  assure( plugin != NULL, CPL_ERROR_NULL_INPUT, "Null plugin" );

  /* Get the recipe out of the plugin */
  assure( cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE,
	  CPL_ERROR_TYPE_MISMATCH, "Plugin is not a recipe");

  recipe = (cpl_recipe *)plugin;

  xsh_free_parameterlist(&recipe->parameters);

 cleanup:
  if (cpl_error_get_code() != CPL_ERROR_NONE)
    {
      return 1;
    }
  else
    {
      return 0;
    }
}

static cpl_error_code 
xsh_params_monitor(xsh_rectify_param * rectify_par,
                   xsh_localize_obj_param * loc_obj_par,
                   xsh_opt_extract_param *opt_extract_par,
                   int sub_sky_nbkpts1,
                   int sub_sky_nbkpts2)
{

  xsh_msg_dbg_low("rectify params: radius=%g bin_lambda=%g bin_space=%g",
	  rectify_par->rectif_radius,rectify_par->rectif_bin_lambda,
	  rectify_par->rectif_bin_space);

  xsh_msg_dbg_low("localize params: chunk_nb=%d nod_step=%g",
	  loc_obj_par->loc_chunk_nb,loc_obj_par->nod_step);

  xsh_msg_dbg_low("opt extract params: chunk_size=%d lambda_step=%g box_hsize=%d",
	  opt_extract_par->chunk_size,opt_extract_par->lambda_step,
	  opt_extract_par->box_hsize);

  xsh_msg_dbg_low("sky params: nbkpts1=%d nbkpts2=%d",
	  sub_sky_nbkpts1,sub_sky_nbkpts2);

  return cpl_error_get_code();

}

/*----------------------------------------------------------------------------*/
/**
   @brief    Interpret the command line options and execute the data processing
   @param    parameters     the parameters list
   @param    frameset   the frames list

   In case of failure the cpl_error_code is set.
*/
/*----------------------------------------------------------------------------*/
static cpl_error_code 
xsh_scired_slit_stare(cpl_parameterlist* parameters,
				  cpl_frameset* frameset)
{

  const int recipe_tags_size = 4;
  const char* recipe_tags[4] = {XSH_OBJECT_SLIT_STARE,
                                               XSH_SKY_SLIT,
                                               XSH_STD_TELL_SLIT_STARE,
				               XSH_STD_FLUX_SLIT_STARE};

  /* Input frames */
  cpl_frameset *raws = NULL;
  cpl_frameset *calib = NULL;
  cpl_frameset *usedframes = NULL;
  /* Beware, do not "free" the following input frames, they are part
     of the input frameset */
  cpl_frame *bpmap = NULL;
  cpl_frame *master_bias = NULL;
  cpl_frame *master_dark = NULL;
  cpl_frame *master_flat = NULL;
  cpl_frame *order_tab_edges = NULL;
  cpl_frame *wave_tab = NULL ;
  cpl_frame *model_config_frame = NULL ;
  cpl_frame *wavemap_frame = NULL ;
  cpl_frame *slitmap_frame = NULL ;
  cpl_frame *disp_tab_frame = NULL;

  cpl_frame *spectralformat_frame = NULL ;
  cpl_frame *tellmask_frame = NULL;

  /* Parameters */
  xsh_background_param* backg_par = NULL;
  xsh_rectify_param * rectify_par = NULL ;
  xsh_stack_param* stack_par=NULL;

  xsh_remove_crh_single_param * crh_single_par = NULL ;
  xsh_localize_obj_param * loc_obj_par = NULL ;

  int sub_sky_nbkpts1 = SUBTRACT_SKY_SINGLE_NBKPTS ; /**< Nb of breakpoints 
						      for the first call to
						      subtract_sky_single */
  int sub_sky_nbkpts2 = SUBTRACT_SKY_SINGLE_NBKPTS ; /**< Nb of breakpoints 
						      for the second call to
						      subtract_sky_single */

  int do_compute_map = 0;

  int recipe_use_model = 0;

  int do_flatfield = 1;
  int do_optextract = 0;
  int do_sub_sky = FALSE;       /**< if 0 DO NOT subtract sky single */
  int generate_sdp_format = 0;
  xsh_extract_param extract_par = { LOCALIZATION_METHOD };

  xsh_opt_extract_param *opt_extract_par = NULL;
  xsh_subtract_sky_single_param *sky_par = NULL;

  xsh_instrument* instrument = NULL;
  int nb_raw_frames ;
  char rec_name[256];

  /* Intermediate frames */
  cpl_frame * crhm_frame = NULL ;	/**< Output of remove_crh */
  //cpl_frame * rmbias = NULL;	/**< Output of subtract bias */
  cpl_frame * rmdark = NULL;	/**< Output of subtract dark */
  cpl_frame * rmbkg = NULL ;	/**< Output of subtract background */
  cpl_frame * div_frame = NULL ; /**< Output of xsh_divide_flat */


  cpl_frame * sub_sky_frame = NULL ; /**< Output of xsh_subtract_sky_single */
  cpl_frame * sub_sky2_frame = NULL ; /**< Output of xsh_subtract_sky_single
				       Second pass (with localization table) */
  cpl_frame * rect_frame = NULL ; /**< Output of xsh_rectfiy */
  cpl_frame * loc_table_frame = NULL ; /**< Output of xsh_localize_object */
  cpl_frame * clean_frame = NULL ; /**< Output of remove_crh_single */
  cpl_frame * rect2_frame = NULL ;
  cpl_frame * rect2_frame_eso = NULL ;
  cpl_frame * rect2_frame_tab = NULL ;


  cpl_frame * rect2_sky_frame = NULL ;
  cpl_frame * rect2_sky_frame_eso = NULL ;
  cpl_frame * rect2_sky_frame_tab = NULL ;

  /* Output Frames (results)*/
  cpl_frame * sky_frame = NULL ; 
  cpl_frame * sky_frame_eso = NULL ; 
  cpl_frame * res_1D_frame = NULL ;	
  cpl_frame * res_2D_frame = NULL ;
  cpl_frame * res_2D_sky_frame = NULL ;
	
  cpl_frame * fluxcal_rect_1D_frame = NULL ;	
  cpl_frame * fluxcal_rect_2D_frame = NULL ;	
  cpl_frame * fluxcal_1D_frame = NULL ;	
  cpl_frame * fluxcal_2D_frame = NULL ;	

  cpl_frame * ext_frame = NULL ;
  cpl_frame * ext_frame_eso = NULL ;

  cpl_frame *orderext1d_frame = NULL;
  cpl_frame *orderoxt1d_frame = NULL;
  cpl_frame *orderoxt1d_eso_frame = NULL;

  cpl_frame *mergeext1d_frame = NULL;
  cpl_frame *mergeoxt1d_frame = NULL;
  cpl_frame *fluxcal_rect_opt1D_frame = NULL;
  cpl_frame *fluxcal_merg_opt1D_frame = NULL;
  cpl_frame* ext_sky_frame=NULL;
  cpl_frame* res_1D_sky_frame=NULL;

  cpl_frame * fluxframe = NULL;
  cpl_frame * uncalframe = NULL;





  cpl_frame* grid_backg=NULL;
  cpl_frame* frame_backg=NULL;
  cpl_frame* sky_frame_ima=NULL;
  char prefix[256];
  char fname[256];
  char tag[256];

  const char* ftag=NULL;

  cpl_frame* single_frame_sky_sub_tab_frame=NULL;
/*
  char sky_name[256];
*/
  cpl_frame* clean_obj=NULL;
  char *rec_prefix = NULL;
  char sky_prefix[256];
  cpl_frame* sky_list_frame=NULL;
  cpl_frame* qc_sky_frame=NULL;
  cpl_propertylist* plist=NULL;

  xsh_pre* pre_sci=NULL;

  cpl_frame* response_frame=NULL;
  cpl_frame* frm_atmext=NULL;
  int pre_overscan_corr=0;
  cpl_frame *qc_subex_frame = NULL;
  cpl_frame *qc_s2ddiv1d_frame = NULL;
  cpl_frame *qc_model_frame = NULL;
  cpl_frame *qc_weight_frame = NULL;
  int merge_par=0;
  xsh_interpolate_bp_param *ipol_bp=NULL;
  cpl_frameset* crh_clean_lacosmic = NULL;
  cpl_frameset *sub_bias_set = NULL;
  cpl_frameset *sub_dark_set = NULL;
  cpl_frame* sky_map_frm = NULL;
  cpl_frame* sky_orders_chunks =NULL;
  int cut_uvb_spectrum=0;

  /**************************************************************************/
  /* DFS management */
  /**************************************************************************/
  check( xsh_begin( frameset, parameters, &instrument, &raws, &calib,
                    recipe_tags, recipe_tags_size,
                    RECIPE_ID, XSH_BINARY_VERSION,
                    xsh_scired_slit_stare_description_short ) ) ;




  /*
  assure( instrument->mode == XSH_MODE_SLIT, CPL_ERROR_ILLEGAL_INPUT,
	  "Instrument NOT in Slit Mode" ) ;
  */
  xsh_recipe_params_check(parameters,instrument,RECIPE_ID);
  if(instrument->arm == XSH_ARM_NIR) {
    xsh_instrument_nir_corr_if_JH(raws,instrument);
  }
  /**************************************************************************/
  /* Recipe frames */
  /**************************************************************************/

  check( nb_raw_frames = cpl_frameset_get_size( raws ) ) ;
  xsh_msg_dbg_low("nb_raw_frames=%d",nb_raw_frames);

  if(nb_raw_frames>1) {
    check(xsh_frameset_check_uniform_exptime(raws,instrument));
  }

  check( pre_overscan_corr = xsh_parameters_get_int( parameters, RECIPE_ID,
                                                       "pre-overscan-corr"));


  check(xsh_slit_stare_get_calibs(calib,instrument, &spectralformat_frame,
                                  &master_bias,&master_dark,&master_flat,
                                  &order_tab_edges,&model_config_frame,
                                  &wave_tab,&sky_list_frame,&sky_orders_chunks,
                                  &qc_sky_frame,
                                  &bpmap,&single_frame_sky_sub_tab_frame,
                                  &wavemap_frame,&slitmap_frame,RECIPE_ID,
				  &recipe_use_model,pre_overscan_corr));
  
  /* scired extra frames */
  if((response_frame=xsh_find_frame_with_tag(calib,XSH_RESPONSE_MERGE1D_SLIT,
                                             instrument)) == NULL ) {
  check(response_frame=xsh_find_frame_with_tag(calib,XSH_MRESPONSE_MERGE1D_SLIT,
                                               instrument));
  }
  if(response_frame != NULL) {
     frm_atmext=xsh_find_frame_with_tag(calib,XSH_ATMOS_EXT,instrument);
     if( frm_atmext==NULL ) {
        xsh_msg_error("Provide atmospheric extinction frame");
        return CPL_ERROR_DATA_NOT_FOUND;
     }
  }
   
  tellmask_frame = xsh_find_frame_with_tag(calib,XSH_TELL_MASK, instrument);
  /**************************************************************************/
  /* Recipe parameters */
  /**************************************************************************/
  check(xsh_slit_stare_get_params(parameters,RECIPE_ID, &pre_overscan_corr,
                                  &backg_par,&loc_obj_par,
                                  &rectify_par,&crh_single_par,&sub_sky_nbkpts1,
                                  &do_flatfield,&sub_sky_nbkpts2,&sky_par,
                                  &do_optextract,
                                  &opt_extract_par,
                                  &generate_sdp_format));
  cut_uvb_spectrum=xsh_parameters_cut_uvb_spectrum_get(RECIPE_ID,parameters);
  backg_par->method=TRUE;
  rectify_par->conserve_flux=FALSE;
  check(ipol_bp = xsh_parameters_interpolate_bp_get(RECIPE_ID,parameters));

  check( stack_par = xsh_stack_frames_get( RECIPE_ID, parameters));

  check(xsh_rectify_params_set_defaults(parameters,RECIPE_ID,instrument,rectify_par));

  check( do_sub_sky = xsh_parameters_subtract_sky_single_get_true( RECIPE_ID,
    parameters));
  if ( (do_sub_sky && !do_compute_map) && 
       (wavemap_frame == NULL || slitmap_frame == NULL) ) {
     xsh_msg_warning( "sky-subtract is true but wave,slits maps missing create them");
    do_compute_map = TRUE;
 
       }

  /* adjust relevant parameter to binning */
  if ( xsh_instrument_get_arm(instrument) != XSH_ARM_NIR) {
     check(xsh_stare_params_bin_scale(raws,backg_par,
                                opt_extract_par,
                                &sub_sky_nbkpts1,&sub_sky_nbkpts2));
  }

  /* parameters dependent input */
  if ( do_compute_map && recipe_use_model==FALSE){
     check_msg(disp_tab_frame = xsh_find_disp_tab( calib, instrument), 
               "compute-map=TRUE, physmodel mode, you must give a DISP_TAB_ARM input");
  }

  check(xsh_params_monitor(rectify_par,loc_obj_par,opt_extract_par,
			   sub_sky_nbkpts1,sub_sky_nbkpts2));

  /**************************************************************************/
  /* Recipe code */
  /**************************************************************************/
  /* prepare RAW frames in XSH format */
  check(xsh_prepare(raws, bpmap, master_bias, XSH_OBJECT_SLIT_STARE,
		    instrument,pre_overscan_corr,CPL_TRUE));




  /* subtract bias from each raw frame, checking if overscan correction was already made */
  cpl_frame* frm = NULL;
  cpl_frame* sub = NULL;

  int i = 0;
  int nraws = 0;
  if (master_bias != NULL) {

    xsh_msg( "Subtract bias");
    sub_bias_set = cpl_frameset_new();
    nraws = cpl_frameset_get_size(raws);

    for (i = 0; i < nraws; i++) {
      sprintf(prefix, "SCI_SUB_%d_", i);
      frm = cpl_frameset_get_frame(raws, i);
      //xsh_free_frame(&sub);
      sub = xsh_check_subtract_bias(frm, master_bias, instrument, prefix,
          pre_overscan_corr, 0);
      cpl_frameset_insert(sub_bias_set, sub);
    }
  } else {
    sub_bias_set = cpl_frameset_duplicate(raws);
  }
  //rmbias=cpl_frameset_get_frame(sub_bias_set,0);

  /* subtract dark from each raw frame */
  if (master_dark != NULL) {
       xsh_msg( "Subtract dark");

       sub_dark_set = cpl_frameset_new();
       nraws = cpl_frameset_get_size(sub_bias_set);

       for (i = 0; i < nraws; i++) {
         sprintf(prefix, "SCI_%d_SUBTRACT", i);
         frm = cpl_frameset_get_frame(sub_bias_set, i);
         //xsh_free_frame(&sub);
         sub = xsh_check_subtract_dark(frm, master_dark, instrument, prefix);
         cpl_frameset_insert(sub_dark_set, sub);
       }

     } else {
       sub_dark_set = cpl_frameset_duplicate(sub_bias_set);
     }
     xsh_free_frameset(&sub_bias_set);
     rmdark=cpl_frameset_get_frame(sub_dark_set,0);

  check( rec_prefix = xsh_set_recipe_file_prefix( raws,
    "xsh_scired_slit_stare"));
  sprintf(prefix,"%s_",rec_prefix);
  sky_map_frm = xsh_find_frame_with_tag(calib,XSH_SKY_MAP, instrument);
  crh_clean_lacosmic = xsh_frameset_crh_single(sub_dark_set, crh_single_par,
                  sky_map_frm, instrument, rec_prefix, "OBJ");



  /* pre CRH removal (method multi) as scired may have more than 2 in frames */
  ftag = XSH_GET_TAG_FROM_ARM( XSH_SLIT_STARE_REMOVE_CRH, instrument);
  check( crhm_frame = xsh_check_remove_crh_multiple( crh_clean_lacosmic, ftag,
   stack_par,NULL, instrument, NULL, NULL));

  check(xsh_slit_stare_get_maps(calib,
                                do_compute_map,recipe_use_model,rec_prefix,
                                instrument,model_config_frame,crhm_frame,
                                disp_tab_frame,order_tab_edges,
                                &wavemap_frame, &slitmap_frame));

  if( backg_par->method ) {
     /* subtract inter-order background */
     xsh_msg("Subtract inter-order background");
     check(rmbkg = xsh_subtract_background( crhm_frame,
                                            order_tab_edges,
                                            backg_par, instrument,rec_prefix,
                                            &grid_backg,&frame_backg,1,0,1));

  } else {
    cpl_frame* frm_tmp=NULL;
     rmbkg = cpl_frame_duplicate( rmdark );
     pre_sci=xsh_pre_load(rmbkg,instrument);
     sprintf(tag,"%sNO_SUB_BACK_%s",prefix,
             xsh_instrument_arm_tostring(instrument));
     sprintf(fname,"%s.fits",tag);
     frm_tmp=xsh_pre_save(pre_sci,fname,tag,0);
     cpl_frame_set_filename(rmbkg,fname);
     cpl_frame_set_tag(rmbkg,tag);
     xsh_free_frame(&frm_tmp);
     xsh_pre_free(&pre_sci);
  }

  /* In case CRH single or localize auto do preliminary sky subtraction */
  xsh_slit_stare_correct_crh_and_sky(loc_obj_par,crh_single_par,rectify_par,
                                     do_sub_sky,rec_prefix,rmbkg,
                                     order_tab_edges, slitmap_frame, 
                                     wavemap_frame,sky_map_frm,model_config_frame,
                                     single_frame_sky_sub_tab_frame,instrument,
                                     sub_sky_nbkpts1, sky_par,sky_list_frame,sky_orders_chunks,
                                     &sky_frame,&sky_frame_eso,&sky_frame_ima,
                                     wave_tab,disp_tab_frame,
                                     spectralformat_frame,nb_raw_frames,
                                     &loc_table_frame,&clean_frame,&clean_obj,0);

  /* now we divide by the flat for proper sky subtraction */
  check( div_frame = xsh_check_divide_flat( do_flatfield, clean_obj,
    master_flat, instrument, rec_prefix));
  xsh_free_frame(&sky_frame);
  xsh_free_frame(&sky_frame_eso);
  xsh_free_frame(&sky_frame_ima);
  check( sub_sky2_frame = xsh_check_subtract_sky_single( do_sub_sky,
                                                         div_frame,
                                                         order_tab_edges,
                                                         slitmap_frame,
                                                         wavemap_frame,
                                                         loc_table_frame,
                                                         single_frame_sky_sub_tab_frame,
                                                         instrument,
                                                         sub_sky_nbkpts2,
                                                         sky_par,
                                                         sky_list_frame,sky_orders_chunks,
                                                         &sky_frame,
                                                         &sky_frame_eso,
                                                         &sky_frame_ima,
                                                         rec_prefix,
                                                         0));

  xsh_msg( "Prepare S2D products" ) ; 
  xsh_msg( "Rectify") ;
  sprintf(rec_name,"%s_%s_%s.fits",rec_prefix,XSH_ORDER2D,
	  xsh_instrument_arm_tostring( instrument));

  check( rect2_frame = xsh_rectify( sub_sky2_frame, order_tab_edges,
                                    wave_tab, model_config_frame, instrument, 
                                    rectify_par,spectralformat_frame, 
                                    disp_tab_frame,rec_name, 
                                    &rect2_frame_eso,&rect2_frame_tab,
				    rec_prefix));
 
  if(sky_frame_ima) {
    /* rectify sky frame for QC */
    sprintf(sky_prefix,xsh_set_recipe_sky_file_prefix(rec_prefix));
    sprintf(rec_name,"%s_%s_%s.fits",sky_prefix,XSH_ORDER2D,
	    xsh_instrument_arm_tostring( instrument));

    check( rect2_sky_frame = xsh_rectify( sky_frame_ima, order_tab_edges,
					  wave_tab, model_config_frame, 
					  instrument,rectify_par,
					  spectralformat_frame,disp_tab_frame,
					  rec_name,&rect2_sky_frame_eso,
					  &rect2_sky_frame_tab,rec_prefix));

    xsh_add_temporary_file(cpl_frame_get_filename(rect2_sky_frame_eso));
    /* the following frame is re-created by next function */
    xsh_free_frame(&rect2_sky_frame_eso);
    check(ext_sky_frame = xsh_extract_clean(rect2_sky_frame, loc_table_frame,
					     instrument, &extract_par,ipol_bp,
					     &rect2_sky_frame_eso,rec_prefix ));
   
    check( res_1D_sky_frame = xsh_merge_ord( ext_sky_frame, instrument,
					      merge_par,sky_prefix));

  }

  xsh_msg( "Extract" ) ;
  check(ext_frame=xsh_extract_clean(rect2_frame, loc_table_frame,
				    instrument, &extract_par,ipol_bp,
				    &ext_frame_eso,rec_prefix)) ;
  
  xsh_msg( "Merge orders with 1D frame" ) ;
  check( res_1D_frame = xsh_merge_ord( ext_frame, instrument,
				       merge_par,rec_prefix));
  check( xsh_mark_tell( res_1D_frame, tellmask_frame));
  
  


  xsh_msg( "Calling xsh_merge_ord with 2D frame" ) ;
  if(  rect2_sky_frame ) {
     check( res_2D_sky_frame = xsh_merge_ord( rect2_sky_frame, instrument,
					      merge_par,sky_prefix));
  }
  check( res_2D_frame = xsh_merge_ord( rect2_frame, instrument,
				       merge_par,rec_prefix));



  xsh_msg("Prepare S1D products" ) ;
  /* doing optimal extraction */
  if ( do_optextract){
    xsh_msg( "Optimal extraction");
    check( xsh_opt_extract( sub_sky2_frame, order_tab_edges,
			    wave_tab, model_config_frame, wavemap_frame, 
			    slitmap_frame, loc_table_frame, 
			    spectralformat_frame, master_flat, instrument,
			    opt_extract_par, rec_prefix,
			    &orderext1d_frame, &orderoxt1d_frame,
                            &orderoxt1d_eso_frame,
			    &qc_subex_frame,
			    &qc_s2ddiv1d_frame,
			    &qc_model_frame,
			    &qc_weight_frame));

    check( mergeext1d_frame = xsh_merge_ord( orderext1d_frame, instrument,
					     merge_par,rec_prefix));
    check( mergeoxt1d_frame = xsh_merge_ord( orderoxt1d_frame, instrument,
					     merge_par,rec_prefix));

    check( xsh_mark_tell( mergeext1d_frame, tellmask_frame));
    check( xsh_mark_tell( mergeoxt1d_frame, tellmask_frame));
  }

  if(response_frame != NULL && frm_atmext != NULL) {

    check(xsh_flux_calibrate(rect2_frame_eso,ext_frame_eso,frm_atmext,
			     response_frame,merge_par,instrument,rec_prefix,
			     &fluxcal_rect_2D_frame,&fluxcal_rect_1D_frame,
			     &fluxcal_2D_frame,&fluxcal_1D_frame));

    if ( do_optextract){

    check(xsh_flux_calibrate1D(orderoxt1d_eso_frame,frm_atmext,
			     response_frame,merge_par,instrument,rec_prefix,
			     &fluxcal_rect_opt1D_frame,
                             &fluxcal_merg_opt1D_frame));

    }

  }


  //xsh_msg( "Calling xsh_mark_tell (TBW)" ) ;
  //  check( tell_frame = xsh_mark_tell(merge_frame, tell_mask, tell_params )) ;

  //xsh_msg( "Calling xsh_calibrate_flux (TBW)" ) ;
  //check( res_2d_frame = xsh_calibrate_flux( tell_frame, response, ??? ) ) ;

  if(model_config_frame!=NULL && wavemap_frame != NULL&& slitmap_frame != NULL) {

     check(xsh_compute_resampling_accuracy(wavemap_frame,slitmap_frame,order_tab_edges,model_config_frame,res_2D_frame,instrument));
     check(xsh_compute_resampling_accuracy(wavemap_frame,slitmap_frame,order_tab_edges,model_config_frame,rect2_frame_eso,instrument));

     check(xsh_compute_wavelength_resampling_accuracy(wavemap_frame,order_tab_edges,model_config_frame,res_1D_frame,instrument));
     check(xsh_compute_wavelength_resampling_accuracy(wavemap_frame,order_tab_edges,model_config_frame,ext_frame_eso,instrument));

     xsh_add_afc_info(model_config_frame,wavemap_frame);
     xsh_add_afc_info(model_config_frame,slitmap_frame);

     if(fluxcal_rect_2D_frame != NULL) {

        check(xsh_compute_resampling_accuracy(wavemap_frame,slitmap_frame,order_tab_edges,model_config_frame,fluxcal_rect_2D_frame,instrument));
        check(xsh_compute_resampling_accuracy(wavemap_frame,slitmap_frame,order_tab_edges,model_config_frame,fluxcal_2D_frame,instrument));

        check(xsh_compute_wavelength_resampling_accuracy(wavemap_frame,order_tab_edges,model_config_frame,fluxcal_rect_1D_frame,instrument));
        check(xsh_compute_wavelength_resampling_accuracy(wavemap_frame,order_tab_edges,model_config_frame,fluxcal_1D_frame,instrument));

     }

     if(res_2D_sky_frame) {
       check(xsh_compute_resampling_accuracy(wavemap_frame,slitmap_frame,order_tab_edges,model_config_frame,res_2D_sky_frame,instrument));
     }

     if ( do_sub_sky == 1 ) {
       check(xsh_compute_wavelength_resampling_accuracy(wavemap_frame,order_tab_edges,model_config_frame,sky_frame_eso,instrument));
     }
  }

  if(cut_uvb_spectrum) {
  if(instrument->arm == XSH_ARM_UVB) {
      xsh_image_cut_dichroic_uvb(rect2_frame_eso);
      xsh_spectrum_orders_cut_dichroic_uvb(ext_frame_eso,instrument);
      xsh_spectrum_cut_dichroic_uvb(res_1D_frame);
      xsh_spectrum_cut_dichroic_uvb(res_2D_frame);

      if(res_2D_sky_frame) {
          xsh_spectrum_cut_dichroic_uvb(res_2D_sky_frame);
          xsh_spectrum_cut_dichroic_uvb(res_1D_sky_frame);
      }

      if ( do_optextract){
          xsh_spectrum_cut_dichroic_uvb(mergeext1d_frame);
          xsh_spectrum_cut_dichroic_uvb(mergeoxt1d_frame);
      }

      if(fluxcal_rect_2D_frame != NULL) {
          xsh_image_cut_dichroic_uvb(fluxcal_rect_2D_frame);
          xsh_spectrum_orders_cut_dichroic_uvb(fluxcal_rect_1D_frame,instrument);
          xsh_spectrum_cut_dichroic_uvb(fluxcal_2D_frame);
          xsh_spectrum_cut_dichroic_uvb(fluxcal_1D_frame);
          if ( do_optextract){
              xsh_spectrum_cut_dichroic_uvb(fluxcal_rect_opt1D_frame);
              xsh_spectrum_cut_dichroic_uvb(fluxcal_merg_opt1D_frame);
          }

      }

  }
  }
  xsh_monitor_spectrum1D_flux(res_1D_frame,instrument);

  /* saving products */   

  xsh_msg( "Save products" ) ;
  usedframes = cpl_frameset_duplicate(frameset);

  sprintf(prefix,"%s_ORDER2D",rec_prefix);
  check( xsh_add_product_image(rect2_frame_eso, frameset, parameters,
			       RECIPE_ID, instrument,prefix));
  xsh_add_product_orders_spectrum(ext_frame_eso, frameset, parameters,
			       RECIPE_ID, instrument,NULL);

  check( xsh_add_product_spectrum( res_2D_frame, frameset, parameters, 
				   RECIPE_ID, instrument, NULL));


  check( xsh_add_product_spectrum( res_1D_frame, frameset, parameters, 
				   RECIPE_ID, instrument, &uncalframe));

  if(res_2D_sky_frame) {
    check( xsh_add_product_spectrum( res_2D_sky_frame, frameset, parameters, 
				     RECIPE_ID, instrument, NULL));
    check( xsh_add_product_spectrum( res_1D_sky_frame, frameset, parameters,
				     RECIPE_ID, instrument, NULL));
  }

  check( xsh_add_product_image( rmbkg, frameset, parameters, 
				RECIPE_ID, instrument,NULL));

  if (do_compute_map){
     //sprintf(prefix,"%s_WAVE_MAP",rec_prefix);


    check(xsh_add_product_image( wavemap_frame, frameset,
      parameters, RECIPE_ID, instrument, NULL));

    //check(sprintf(prefix,"%s_SLIT_MAP",rec_prefix));

    check(xsh_add_product_image( slitmap_frame, frameset,
      parameters, RECIPE_ID, instrument,NULL));
  }
  if(do_flatfield) {

  check( xsh_add_product_image( div_frame, frameset, parameters, 
				    RECIPE_ID, instrument,NULL));
  }

  if ( do_optextract){
    check( xsh_add_product_table( orderext1d_frame, frameset,parameters, 
                                        RECIPE_ID, instrument,NULL));
    check( xsh_add_product_table( orderoxt1d_frame, frameset,parameters, 
                                        RECIPE_ID, instrument,NULL));
    check( xsh_add_product_spectrum( mergeext1d_frame, frameset, parameters,
                                     RECIPE_ID, instrument, NULL));
    check( xsh_add_product_spectrum( mergeoxt1d_frame, frameset, 
      parameters, RECIPE_ID, instrument, NULL));
    check( xsh_add_product_image( qc_subex_frame, frameset, parameters, 
				    RECIPE_ID, instrument,
				    cpl_frame_get_tag(qc_subex_frame)));
    check( xsh_add_product_image( qc_s2ddiv1d_frame, frameset, parameters, 
				    RECIPE_ID, instrument,
				    cpl_frame_get_tag(qc_s2ddiv1d_frame)));
    check( xsh_add_product_image( qc_model_frame, frameset, parameters, 
				    RECIPE_ID, instrument,
				    cpl_frame_get_tag(qc_model_frame)));
    check( xsh_add_product_image( qc_weight_frame, frameset, parameters, 
				    RECIPE_ID, instrument,
				    cpl_frame_get_tag(qc_weight_frame)));
  }
  if ( do_sub_sky == 1 ) {
    check( xsh_add_product_pre( sub_sky2_frame, frameset, parameters,
				RECIPE_ID, instrument));
    check( xsh_add_product_image( sky_frame_ima, frameset, parameters,
				  RECIPE_ID, instrument,NULL));
    check( xsh_add_product_orders_spectrum( sky_frame_eso, frameset,
                                  parameters, RECIPE_ID, instrument,NULL));
  }
  if(frame_backg != NULL) {
     check( xsh_add_product_image( frame_backg, frameset, parameters, 
                                RECIPE_ID, instrument,NULL));
  }
  if(crhm_frame != NULL) {
    sprintf(tag,"%s_ON",rec_prefix);
     check( xsh_add_product_image( crhm_frame, frameset, parameters, 
                                   RECIPE_ID, instrument,tag));

  }

  if(qc_sky_frame != NULL) {
    check( xsh_add_product_table(qc_sky_frame, frameset,parameters, 
                                       RECIPE_ID, instrument,NULL));
  
  }

  if(fluxcal_rect_2D_frame != NULL) {
     check( xsh_add_product_image( fluxcal_rect_2D_frame, frameset, parameters, 
                                   RECIPE_ID, instrument,NULL));

     check( xsh_add_product_orders_spectrum( fluxcal_rect_1D_frame, frameset, parameters,
                                   RECIPE_ID, instrument,NULL));

     check( xsh_add_product_spectrum( fluxcal_2D_frame, frameset, parameters, 
                                      RECIPE_ID, instrument, NULL));
     check( xsh_add_product_spectrum( fluxcal_1D_frame, frameset, parameters, 
                                      RECIPE_ID, instrument, &fluxframe));

     if ( do_optextract){

        check( xsh_add_product_image( fluxcal_rect_opt1D_frame, frameset,
                                      parameters, RECIPE_ID, instrument,
                                      NULL));

        check( xsh_add_product_spectrum( fluxcal_merg_opt1D_frame, frameset, 
                                         parameters, RECIPE_ID, instrument,
                                         NULL));

     }
  }
  
  if (generate_sdp_format) {
    cpl_frame * fluxframe_copy = fluxframe;
    cpl_frame * uncalframe_copy = uncalframe;
    if (fluxframe != NULL) {
      check( cpl_frameset_insert(usedframes, fluxframe) );
      fluxframe = NULL;  /* prevent direct deletion in cleanup section,
                            will be deleted together with usedframes. */
    }
    if (uncalframe != NULL) {
      check( cpl_frameset_insert(usedframes, uncalframe) );
      uncalframe = NULL;  /* prevent direct deletion in cleanup section,
                             will be deleted together with usedframes. */
    }
    check( xsh_add_sdp_product_spectrum(fluxframe_copy, uncalframe_copy,
                    frameset, usedframes, parameters, RECIPE_ID, instrument) );
    /* Restore usedframes to what it was before in case we want to reuse it */
    if (fluxframe_copy != NULL) {
      check( cpl_frameset_erase_frame(usedframes, fluxframe_copy) );
    }
    if (uncalframe_copy != NULL) {
      check( cpl_frameset_erase_frame(usedframes, uncalframe_copy) );
    }
  }

  cleanup:

    xsh_end( RECIPE_ID, frameset, parameters );

    XSH_FREE( rec_prefix);
    XSH_FREE( backg_par);
    XSH_FREE(ipol_bp);
    XSH_FREE( crh_single_par);
    XSH_FREE( rectify_par);
    XSH_FREE( stack_par);
    XSH_FREE( sky_par);
    XSH_FREE( loc_obj_par);
    XSH_FREE( opt_extract_par);
    xsh_instrument_free(&instrument);

    xsh_free_frameset(&usedframes);
    xsh_free_frameset(&raws);
    xsh_free_frameset(&calib);
    xsh_free_frame( &crhm_frame);
    xsh_free_frame( &qc_sky_frame);
    xsh_free_frame(&res_1D_sky_frame);
    xsh_free_frame(&ext_sky_frame);
    xsh_free_frameset(&crh_clean_lacosmic);

    if(do_compute_map) {
       xsh_free_frame( &wavemap_frame);
       xsh_free_frame( &slitmap_frame);
    }

    xsh_free_frameset(&sub_bias_set);
    xsh_free_frameset(&sub_dark_set);
    //xsh_free_frame(&rmbias);

    //xsh_free_frame(&rmdark);
    xsh_free_frame(&rmbkg);
    xsh_free_frame(&div_frame);
    xsh_free_frame(&sub_sky_frame);

    xsh_free_frame(&bpmap);
    xsh_free_frame(&sub_sky2_frame);
    xsh_free_frame(&sky_frame);
    xsh_free_frame(&sky_frame_eso);
    xsh_free_frame(&sky_frame_ima);

    xsh_free_frame(&rect_frame) ;
    xsh_free_frame(&rect2_frame_eso) ;
    xsh_free_frame(&rect2_frame_tab) ;

    xsh_free_frame(&rect2_sky_frame) ;
    xsh_free_frame(&rect2_sky_frame_eso) ;
    xsh_free_frame(&rect2_sky_frame_tab) ;


    xsh_free_frame( &orderext1d_frame);
    xsh_free_frame( &orderoxt1d_frame);
    xsh_free_frame( &mergeext1d_frame);
    xsh_free_frame( &mergeoxt1d_frame);

    xsh_free_frame(&loc_table_frame) ;
    xsh_free_frame( &clean_frame);
    xsh_free_frame( &clean_obj);
    xsh_free_frame( &ext_frame);
    xsh_free_frame( &ext_frame_eso);

    xsh_free_frame(&res_1D_frame) ;
    xsh_free_frame(&res_2D_frame) ;

    xsh_free_frame(&res_2D_sky_frame) ;

    xsh_free_frame(&fluxcal_rect_1D_frame) ;
    xsh_free_frame(&fluxcal_rect_2D_frame) ;
    xsh_free_frame(&fluxcal_1D_frame) ;
    xsh_free_frame(&fluxcal_2D_frame) ;

   //xsh_free_frame(&frm_atmext) ;
    xsh_free_frame(&rect2_frame) ;
    xsh_free_frame(&grid_backg) ;
    xsh_free_frame(&frame_backg) ;
    xsh_free_propertylist(&plist);
    xsh_free_frame( &qc_subex_frame);
    xsh_free_frame(&qc_s2ddiv1d_frame);
    xsh_free_frame(&qc_model_frame);
    xsh_free_frame(&qc_weight_frame);

    xsh_free_frame(&fluxframe);
    xsh_free_frame(&uncalframe);

    return CPL_ERROR_NONE;
}

/**@}*/
