/*                                                                           *
 *   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:53:17 $
 * $Revision: 1.139 $
 */


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

/*---------------------------------------------------------------------------*/
/**
 * @defgroup xsh_compute_response   Compute Instrument Response (xsh_compute_response)
 * @ingroup drl_functions
 *
 */
/*---------------------------------------------------------------------------*/


/*----------------------------------------------------------------------------
  Includes
  ----------------------------------------------------------------------------*/
#include <gsl/gsl_spline.h>
#include <gsl/gsl_errno.h>

#include <gsl/gsl_bspline.h>
#include <gsl/gsl_multifit.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <gsl/gsl_statistics.h>



#include <xsh_dfs.h>
#include <xsh_error.h>
#include <xsh_msg.h>
#include <cpl.h>
#include <string.h>
#include <time.h>
#include <xsh_utils_table.h>
#include <xsh_data_star_flux.h>
#include <xsh_data_atmos_ext.h>
#include <xsh_data_spectrum.h>
#include <xsh_pfits.h>
#include <xsh_utils.h>
#include <xsh_utils_wrappers.h>
#include <xsh_drl.h>
#include <xsh_utils_efficiency.h>
#include <xsh_efficiency_response.h>
#include <xsh_utils_response.h>
#include <xsh_utils_vector.h>
/*----------------------------------------------------------------------------
  Function prototypes
  ----------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------
                              Implementation
 -----------------------------------------------------------------------------*/

#define  INTERPOL_WSTEP_NM 2
#define  FILTER_MEDIAN_HSIZE 3
/*
static double
find_high_abs_wave_max(HIGH_ABS_REGION * phigh)
{
  double max=0;
  for( ; phigh->lambda_min != 0. ; phigh++ ) {
    if(phigh->lambda_max>max) max=phigh->lambda_max>max;
  }
  return max;

}
*/

static int 
find_lambda_idx( double lambda, double * wave, int from, int to,
                 double step )
{
  int idx ;
  double * pwave ;

  for( idx = from, pwave = wave+from ; idx < to ; pwave++, idx++ ) {
    if ( *pwave >= (lambda-step/2) && *pwave < (lambda+step/2) ) {   
      return idx ;
    }
  }

  return -1 ;
}



/*
static int 
find_lambda_idx2( double lambda, double * wave, int from, int to,
                 double step )
{
  int idx ;
  double * pwave ;

  for( idx = from, pwave = wave+from ; idx < to ; pwave++, idx++ ) {
    
    //xsh_msg("Testing wave=%g thresh_lam_min=%g thresh_lam_max=%g",
    //    *pwave,(lambda-step/2),(lambda+step/2));
	    
    if ( *pwave >= (lambda-step/2) ) {
      if ( *pwave <= (lambda+step/2) ) {
	
	//xsh_msg("Found index %d wave=%g thresh_lam_min=%g thresh_lam_max=%g",
	//	idx,*pwave,(lambda-step/2),(lambda+step/2));
       
	 return idx ;
      }
    }
  }

  return -1 ;
}
*/


static int 
find_lambda_idx_min( double lambda, double * wave, int from, int to,
                 double step )
{
  int idx ;
  double * pwave ;

  for( idx = from, pwave = wave+from ; idx < to ; pwave++, idx++ ) {
    /*
    xsh_msg("Testing wave=%g thresh_lam_min=%g thresh_lam_max=%g",
	    *pwave,(lambda-step/2),(lambda+step/2));
	    */
    if ( *pwave > (lambda-step/2) ) {
      /*
	xsh_msg("Found index %d wave=%g thresh_lam_min=%g thresh_lam_max=%g",
		idx,*pwave,(lambda-step/2),(lambda+step/2));
      */
	 return idx ;
    }
  }

  return -1 ;
}



static int 
find_lambda_idx_max( double lambda, double * wave, int from, int to,
                 double step )
{
  int idx ;
  double * pwave ;

  for( idx = from, pwave = wave+from ; idx >= to ; pwave--, idx-- ) {
    /*
    xsh_msg("Testing wave=%g thresh_lam_min=%g thresh_lam_max=%g",
	    *pwave,(lambda-step/2),(lambda+step/2));
	    */
    if ( *pwave < (lambda+step/2) ) {
      /*
      xsh_msg("Found index %d wave=%g thresh_lam_min=%g thresh_lam_max=%g",
	      idx,*pwave,(lambda-step/2),(lambda+step/2));
      */
      return idx ;
    }
  }

  return -1 ;
}

static void 
find_lambda_idx_limit( double min, double max, double * spectrum,
                       int from, int to, double step,
                       int * if0, int * if1 )
{
  int idx ;
  double *pspec ;

  xsh_msg_dbg_high( "From: %d, To: %d, step: %lf, min: %lf, max: %lf",
		    from, to, step, min, max ) ;

  for( idx = from, pspec = spectrum+from ; idx < to ; pspec++, idx++ ) {
    xsh_msg_dbg_high( "    Search Min - Spectrum_lambda: %lf (%lf)", *pspec,
		      min-(step/2.) ) ;
    if ( *pspec >= (min-(step/2.))  ) break ;
  }
  *if0 = idx ;
  for( ; idx < to ; pspec++, idx++ ) {
    xsh_msg_dbg_high( "    Search Max - Spectrum_lambda: %lf", *pspec ) ;
    if ( *pspec > (max+(step/2.)) ) break ;
  }
  *if1 = idx-1 ;

  xsh_msg_dbg_low( "Lambda Min: %lf, Max: %lf (in [%lf,%lf[",
                   spectrum[*if0], spectrum[*if1], min, max ) ;
  if ( *if1 > to ) *if1 = to ;

  return ;
}

/** 
 * Interpolate atms extinction at same sampling step as ref std star 
 * 
 * @param star_list Table of ref star flux
 * @param[in] atmos_ext_tab atmospheric extinction table
 * @param[in] instrument instrument arm and lamp setting
 * @param[out] atmos_lambda interpolated wave array
 * @param[out] atmos_K      interpolated atmospheric extinction K
 * @return cpl error code
 */
static cpl_error_code 
xsh_interpolate_atm_ext(xsh_star_flux_list * star_list,
                        cpl_table*atmos_ext_tab,
                        xsh_instrument* instrument, 
                        double** atmos_lambda, 
                        double** atmos_K)
{

   int nrow=0;
   double* pk=0;
   double* pw=0;
   int j=0 ;
   int nlambda_star=0 ;
   double * lambda_star = NULL;

   XSH_ASSURE_NOT_NULL_MSG (star_list,"null input ref std flux table!");
   XSH_ASSURE_NOT_NULL_MSG (atmos_ext_tab,"null input atm ext table!");
 
   nlambda_star = star_list->size ;
   lambda_star = star_list->lambda ;
   
   /* Fill the atmos_lambda and K with only the subset of lambdas available
      in star list (the std star) */
   XSH_CALLOC( *atmos_lambda, double, nlambda_star ) ;
   XSH_CALLOC( *atmos_K, double, nlambda_star ) ;
   if(!cpl_table_has_column(atmos_ext_tab,XSH_ATMOS_EXT_LIST_COLNAME_K)){
     xsh_msg_warning("You are using an obsolete atm extinction line table");
     cpl_table_duplicate_column(atmos_ext_tab,XSH_ATMOS_EXT_LIST_COLNAME_K,
                                atmos_ext_tab,XSH_ATMOS_EXT_LIST_COLNAME_OLD);
   }
   cpl_table_cast_column(atmos_ext_tab,XSH_ATMOS_EXT_LIST_COLNAME_K,"K",CPL_TYPE_DOUBLE);
   cpl_table_cast_column(atmos_ext_tab,"LAMBDA","WAVE",CPL_TYPE_DOUBLE);
     
   nrow=cpl_table_get_nrow(atmos_ext_tab);
   pw=cpl_table_get_data_double(atmos_ext_tab,"WAVE");
   pk=cpl_table_get_data_double(atmos_ext_tab,"K");
 
   if( xsh_instrument_get_arm(instrument) != XSH_ARM_NIR){
      for( j = 0 ; j<nlambda_star ; j++) {
	//if(j<10) xsh_msg("atmo lambda=%g",lambda_star[j] );
         (*atmos_lambda)[j] = lambda_star[j] ;
         (*atmos_K)[j] = xsh_data_interpolate((*atmos_lambda)[j],nrow,pw,pk);
 
         //xsh_msg("w=%g k=%g",atmos_lambda[j],atmos_K[j]);
      }
   } else {
      for( j = 0 ; j<nlambda_star ; j++) {
 
         (*atmos_lambda)[j] = lambda_star[j] ;
         (*atmos_K)[j] = 0;
 
         //xsh_msg("w=%g k=%g",atmos_lambda[j],atmos_K[j]);
      }
   }
 
   cpl_table_erase_column(atmos_ext_tab,"WAVE");
   cpl_table_erase_column(atmos_ext_tab,"K");
 

  cleanup:
   return cpl_error_get_code();
}

/** 
 * Interpolate high absorbtion regions 
 * 
 * @param[in] star_list Table of ref star flux
 * @param[out] resp_list Table of response values
 * @param[in] HIGH_ABS_REGION  pointer to hight abs regions
 * @return cpl error code 
 */
static cpl_error_code 
xsh_interpolate_high_abs_regions(xsh_star_flux_list * star_list,
                                 xsh_star_flux_list * resp_list,
                                 HIGH_ABS_REGION * phigh)

{
   int kh=0;
   int min_idx=0;
   int max_idx=0;
   int start_idx=0;
   double min_flux=0;
   double max_flux=0;
   double delta_flux=0;
   double cur_flux=0;
   int ll=0;
   int min_step=5;
   int nlambda_star=0;
   double step_star=0;
   double * lambda_star = NULL;
   double lambda_star_min=0;
   double lambda_star_max=0;
   //int i=0;
   XSH_ASSURE_NOT_NULL_MSG (star_list,"null input ref std flux table!");
   XSH_ASSURE_NOT_NULL_MSG (resp_list,"null input response table!");

   nlambda_star = star_list->size ;
   lambda_star = star_list->lambda ;
   lambda_star_min = *lambda_star ;
   lambda_star_max = *(lambda_star+nlambda_star-1) ;
   step_star = (lambda_star_max-lambda_star_min)/(nlambda_star-1) ;

   if ( phigh != NULL ) {

      xsh_msg_dbg_medium( "Interpolate in High Absorption Regions" ) ;
      for( kh = 0 ; phigh->lambda_min != 0. ; kh++, phigh++ ) {
	start_idx=0;
         min_idx = find_lambda_idx( phigh->lambda_min, resp_list->lambda,
                                    start_idx, nlambda_star, step_star ) ;
         if(min_idx>=0) {
           start_idx=min_idx;
	 }
         max_idx = find_lambda_idx( phigh->lambda_max, resp_list->lambda,
                                    start_idx, nlambda_star, step_star ) ;  
         xsh_msg_dbg_medium( "Indexes[%d]: %d (lambda=%lf), %d (lambda=%lf)", 
                             kh,min_idx, phigh->lambda_min, max_idx, 
                             phigh->lambda_max ) ;
	 /*
	 for(i=0;i<resp_list->size;i++) {
	   xsh_msg("rsp list lambda=%g",resp_list->lambda[i]);
	 }
	 */
         xsh_msg_dbg_low( "Indexes[%d]: %d (lambda=%lf), %d (lambda=%lf)", 
                             kh,min_idx, phigh->lambda_min, max_idx, 
                             phigh->lambda_max ) ;
	 

         if(min_idx>=resp_list->size || max_idx>=resp_list->size) {
            xsh_msg("min_idx=%d max_idx=%d size=%d",
                    min_idx,max_idx,resp_list->size);
         }
         //xsh_msg("resp list size=%d min_idx=%d max_idx=%d",resp_list->size,min_idx,max_idx);

         /* decide if we need to 
            1) extrapolate toward lower wavelength
            2) interpolate between min-max wavelength
            3) extrapolate toward higher wavelength
	 */
         if( (min_idx==-1) && (max_idx == -1) ) {
           xsh_msg_debug("The high abs region is longer than the order length");
	   return cpl_error_get_code();
	 } else if(min_idx==-1) {
           min_idx=0;
	   min_flux = resp_list->flux[max_idx] ;   
	   max_flux = resp_list->flux[max_idx+min_step] ;
	 } else if (max_idx == -1) {
           max_idx=nlambda_star;
	   min_flux = resp_list->flux[min_idx-min_step] ;
	   max_flux = resp_list->flux[min_idx] ;
         } else {
           /* do nothing min_idx and max_idx are ok */
	   min_flux = resp_list->flux[min_idx] ;  
	   max_flux = resp_list->flux[max_idx] ;  
	 }

         xsh_msg_dbg_medium( "Min Flux: %le, Max Flux: %le", 
                             min_flux, max_flux ) ;
         delta_flux = (max_flux-min_flux)/(min_step) ;
         // Now interpolate 
         for ( ll = min_idx+1 ; ll < max_idx ; ll++ ) {
	   cur_flux=min_flux+delta_flux*(ll-min_idx);
            xsh_msg_dbg_low( " ==> Interpolate at %lf: %le replaced by %le",
                                resp_list->lambda[ll],
                                resp_list->flux[ll], cur_flux ) ;
            resp_list->flux[ll] = cur_flux ;
         }
      }
   }

  cleanup:


   return cpl_error_get_code();
}





static cpl_error_code 
xsh_interpolate_high_abs_regions2(xsh_star_flux_list * star_list,
                                 xsh_star_flux_list * resp_list,
                                 HIGH_ABS_REGION * phigh)

{
   int kh=0;
   int min_idx=0;
   int max_idx=0;
   double min_flux=0;
   double max_flux=0;
   double delta_flux=0;
   double cur_flux=0;
   int ll=0;
   int nlambda_star=0;
   double step_star=0;
   double * lambda_star = NULL;
   double lambda_star_min=0;
   double lambda_star_max=0;

   XSH_ASSURE_NOT_NULL_MSG (star_list,"null input ref std flux table!");
   XSH_ASSURE_NOT_NULL_MSG (resp_list,"null input response table!");

   nlambda_star = star_list->size ;
   lambda_star = star_list->lambda ;
   lambda_star_min = *lambda_star ;
   lambda_star_max = *(lambda_star+nlambda_star-1) ;
   step_star = (lambda_star_max-lambda_star_min)/(nlambda_star-1) ;

   if ( phigh != NULL ) {
     int i=0;
     const int nsampl=5;
     cpl_vector* wave=cpl_vector_new(2*nsampl);
     cpl_vector* flux=cpl_vector_new(2*nsampl);
     cpl_polynomial * poly=NULL;
     double mse=0;
     const int deg=4;
     double flux_interpol=0;
      xsh_msg_dbg_medium( "Interpolate in High Absorption Regions" ) ;
      for( kh = 0 ; phigh->lambda_min != 0. ; kh++, phigh++ ) {
         min_idx = find_lambda_idx_min( phigh->lambda_min, resp_list->lambda,
                                    max_idx, nlambda_star, step_star ) ;
         max_idx = find_lambda_idx_max( phigh->lambda_max, resp_list->lambda,
					nlambda_star-1, min_idx, step_star ) ;
         xsh_msg_dbg_medium( "Indexes[%d]: %d (lambda=%lf), %d (lambda=%lf)", 
                             kh,min_idx, phigh->lambda_min, max_idx, 
                             phigh->lambda_max ) ;
	 /*
         xsh_msg( "Indexes[%d]: %d (lambda=%lf), %d (lambda=%lf)", 
                             kh,min_idx, phigh->lambda_min, max_idx, 
                             phigh->lambda_max ) ;
	 */
         if(min_idx>=resp_list->size || max_idx>=resp_list->size) {
            xsh_msg("min_idx=%d max_idx=%d size=%d",
                    min_idx,max_idx,resp_list->size);
         }
         for(i=0;i<nsampl;i++) {
	   cpl_vector_set(wave,i,resp_list->lambda[min_idx+i-nsampl]);
	   cpl_vector_set(wave,i+nsampl,resp_list->lambda[max_idx+i]);
	   cpl_vector_set(flux,i,resp_list->flux[min_idx+i-nsampl]);
	   cpl_vector_set(flux,i+nsampl,resp_list->flux[max_idx+i]);
	 }
         //double* ws=NULL;
         //double* fs=NULL;
         //ws=cpl_vector_get_data(wave);
         //fs=cpl_vector_get_data(flux);
         
         poly=xsh_polynomial_fit_1d_create(wave,flux,deg,&mse);
	 for(i=min_idx;i<=max_idx;i++) {
	   //flux_interpol=xsh_spline_hermite(resp_list->lambda[i],ws,fs,nsampl,0);
           flux_interpol=cpl_polynomial_eval_1d(poly,resp_list->lambda[i],NULL);
           //xsh_msg("Interpol flux=%g",flux_interpol);
           resp_list->flux[i]=flux_interpol;
	 }
	 /*
         cpl_vector_dump(wave,stdout);
         cpl_vector_dump(flux,stdout);
         */
	 /* here new code for windowing:
          * we get a few (5) sampling points before min_idx and after max_idx  
	  * we fill 2 vectors with wave, flux values
          * we make a low order (2) polynomial fit
          * we then compute the data points between 
          * flux(idx_min) and flux(idx_max)
          * we finally replace the response values with the fitted values
          */
        
         min_flux = resp_list->flux[min_idx] ;
         max_flux = resp_list->flux[max_idx] ;
         xsh_msg_dbg_medium( "Min Flux: %le, Max Flux: %le", 
                             min_flux, max_flux ) ;
         delta_flux = (max_flux-min_flux)/(max_idx-min_idx) ;
         // Now interpolate 
         cur_flux = min_flux ;
         for ( ll = min_idx+1 ; ll < max_idx ; ll++ ) {
            cur_flux += delta_flux ;
            xsh_msg_dbg_medium( " ==> InSterpolate at %lf: %le replaced by %le",
                                resp_list->lambda[ll],
                                resp_list->flux[ll], cur_flux ) ;
            resp_list->flux[ll] = cur_flux ;
         }
      }
      xsh_free_vector(&wave);
      xsh_free_vector(&flux);

   }

  cleanup:


   return cpl_error_get_code();
}

/** 
 * Integrate the flux on the same sampling that the star_list, taking into
 * account the bad pixels, apply atmos correction, and divide by the star_list
 * table.
 * 
 * @param resp_list Table of response values
 * @param star_list Table of ref star flux
 * @param lambda_spectrum  array with lambda values
 * @param flux_spectrum    array with flux values
 * @param flux_added       array with integrated flux values
 * 
 * @return cpl error code
 */
static cpl_error_code
xsh_response_crea_ascii(xsh_star_flux_list * resp_list,
                        xsh_star_flux_list * star_list,
                        double * lambda_spectrum,
                        double * flux_spectrum,
                        double * flux_added)
{

   FILE * fout ;
   int i=0;
   int nlambda_star=0;
   int nlambda_spectrum=0;
   double * lambda_star = NULL;
   double * flux_star = NULL ;

   XSH_ASSURE_NOT_NULL_MSG (star_list,"null input ref std flux table!");
   XSH_ASSURE_NOT_NULL_MSG (resp_list,"null input response table!");

   nlambda_star = star_list->size ;
   lambda_star = star_list->lambda ;
   flux_star = star_list->flux ;

   fout = fopen( "summed.dat", "w" ) ;
   for( i = 0 ; i < nlambda_star ; i++ ) {
      fprintf( fout, "%lf %le\n", resp_list->lambda[i],
               flux_added[i] ) ;
   }
   fclose( fout ) ;

   fout = fopen( "response.dat", "w" ) ;
   for( i = 0 ; i < nlambda_star ; i++ ) {
      fprintf( fout, "%lf %le\n", resp_list->lambda[i],
               resp_list->flux[i] ) ;
   }
   fclose( fout ) ;

   fout = fopen( "spectrum.dat", "w" ) ;
   for ( i = 0 ; i < nlambda_spectrum ; i++ )
      fprintf( fout, "%lf %lf\n", lambda_spectrum[i], flux_spectrum[i] ) ;
   fclose( fout ) ;

   fout = fopen( "star.dat", "w" ) ;
   for ( i = 0 ; i < nlambda_star ; i++ )
      fprintf( fout, "%lf %le\n", lambda_star[i], flux_star[i] ) ;
   fclose( fout ) ;

  cleanup:
   return cpl_error_get_code();
}



static cpl_error_code
xsh_flux_integrate_and_corr_for_badpix(int npix_in_interval,
                            double * flux_spectrum,
                            int * qual_spectrum,
                            int if0,int if1,
                            int i,double** flux_added,int* npixels,int* nbad)

{

   double * pf0=NULL;
   double * pf1=NULL;
   double * pf=NULL;

   int * qf0=NULL;
   int * qf=NULL;
   int i_dif=if1-if0;
   XSH_ASSURE_NOT_NULL_MSG (flux_spectrum,"null flux_spectrum !");
   XSH_ASSURE_NOT_NULL_MSG (qual_spectrum,"null qual_spectrum !");

   if ( (npix_in_interval - i_dif)>0.9 ) {
     *nbad = npix_in_interval -i_dif ;
   }
   pf0 = flux_spectrum + if0 ;
   pf1 = flux_spectrum + if1 ;
   qf0 = qual_spectrum + if0 ;
   for( pf = pf0, qf = qf0 ; pf < pf1 ; pf++, qf++ ) {
      /* TBD: handle correctly the borders (for example with a step_spectrum
         of 0.2, and a step_star of 5, one should use only half of the
         flux on the edges
      */
      (*npixels)++ ;
      if ( *qf != QFLAG_GOOD_PIXEL ) {
         (*nbad)++ ;
      }
      else (*flux_added)[i] += *pf;
   }

   if ( nbad != 0 && (npix_in_interval-*nbad) > 0 ) {
      (*flux_added)[i] /= (double)(npix_in_interval-*nbad)/
         (double)npix_in_interval ;
   }
/*
   xsh_msg("factor=%g npix_in_interval=%d nbad=%d if1=%d if0=%d i_dif=%d ck=%d",
(double)(npix_in_interval-*nbad)/
	   (double)npix_in_interval,npix_in_interval,*nbad,if1,if0,i_dif,(npix_in_interval - i_dif));
*/
  cleanup:
   return cpl_error_get_code();
}

/**
 * This function corrects a spectrum for contributes due to atmospheric extinction, airmass,exptime,gain
 *
 * @param star_list Table of ref star flux
 * @param spectrum Table of observed star flux
 * @param atmos_K  atmospheric extinction curve
 * @param the_arm observing arm
 * @param airmass  airmass value
 * @param exptime  exptime (dit*ndit) value
 * @param gain     gain value
 * @param obj_list Table of observed star flux corrected by atmospheric extinction, airmass,exptime,gain
 *
 * @return cpl error code
 */
static cpl_error_code
xsh_spectrum_correct(
            xsh_star_flux_list * star_list,
            xsh_spectrum * spectrum,
            double * atmos_K,
            XSH_ARM  the_arm,
            double airmass,
            double exptime,
            double gain,
            xsh_star_flux_list ** obj_list)
{

   double lambda=0;
   double kvalue=0;


   double * flux_added = NULL ;
   double * lambda_star = NULL;
   double  * flux_star = NULL ;

   double * lambda_spectrum = NULL;
   double * plambda=NULL ;
   double * flux_spectrum = NULL ;
   //int * qual_spectrum = NULL ;

   int i=0;
   int  size=0;
   int nlambda_spectrum=0;
   double lambda_spectrum_min=0;
   double lambda_spectrum_max=0;
   double lambda_star_min=0;
   double lambda_star_max=0;
   double step_spectrum=0 ;
   double step_star=0 ;
   int npix_in_interval=0 ;
   int bin=1;
   int binx=1;
   int biny=1;
   cpl_frame* obj_integrated=NULL;

   check( nlambda_spectrum = xsh_spectrum_get_size( spectrum ) ) ;
   check( flux_spectrum = xsh_spectrum_get_flux( spectrum ) ) ;
   //check( qual_spectrum = xsh_spectrum_get_qual( spectrum ) ) ;
   check( lambda_spectrum_min = xsh_spectrum_get_lambda_min( spectrum ) ) ;
   check( lambda_spectrum_max = xsh_spectrum_get_lambda_max( spectrum ) ) ;
   check( step_spectrum = xsh_spectrum_get_lambda_step( spectrum ) ) ;

   /* In NIR, no binning ==> set 1x1 */
   if ( the_arm != XSH_ARM_NIR ) {
      /* we correct for biny: bin along wave direction */
     check(bin = xsh_pfits_get_biny( spectrum->flux_header )) ;
     check(binx = xsh_pfits_get_binx( spectrum->flux_header )) ;
     check(biny = xsh_pfits_get_biny( spectrum->flux_header )) ;
   }
   else {
      bin = 1 ;
      binx=1;
      biny=1;

   }

   flux_star = star_list->flux ;
   size = star_list->size ;
   lambda_star = star_list->lambda ;


   lambda_star_min = *lambda_star ;
   lambda_star_max = *(lambda_star+size-1) ;
   step_star = (lambda_star_max-lambda_star_min)/(size-1) ;

   xsh_msg( "Spectrum  - size %d Nlambda: %d, Min: %lf, Max: %lf, Step: %lf",
                    size,nlambda_spectrum, lambda_spectrum_min, lambda_spectrum_max,
                    step_spectrum ) ;
   xsh_msg_dbg_low( "           - BinX: %d, BinY: %d", binx, biny ) ;


   XSH_CALLOC( flux_added, double, size ) ;
   /* For each lambda in star_list
      if there is such a lambda in rec_list Then
      integrate (add) the flux from (lambda-delta/2) to (lambda+delta/2)
      calculate ratio rec_add_flux/star_flux
      endif
      EndFor
   */
   /* First create lambda_spectrum array */
   XSH_CALLOC( lambda_spectrum, double, nlambda_spectrum ) ;

   for( lambda = lambda_spectrum_min, plambda = lambda_spectrum, i = 0 ;
        i<nlambda_spectrum ;
        i++, plambda++, lambda += step_spectrum )
   {
      *plambda = lambda ;
   }

   /* Create response list (identical to star_list ?) */
   //xsh_msg("step_star=%g step_spectrum=%g", step_star,step_spectrum);

   npix_in_interval = step_star/step_spectrum ;
   xsh_msg_dbg_low( "Nb of pixels max in interval: %d", npix_in_interval ) ;

  /* for debug purposes uses stores results in a table */
  cpl_table* debug = NULL;
  double* pwav = NULL;
  double* pflux_obs = NULL;
  double* pflux_ref = NULL;
  double* pflux_corr=NULL;
  double* pkavalue = NULL;
  double* pobj_atm_corr = NULL;
  double* pobj_bin_cor = NULL;
  double cor_fct = 0;
  debug = cpl_table_new(size);

  cpl_table_new_column(debug, "wavelength", CPL_TYPE_DOUBLE);
  cpl_table_new_column(debug, "flux_obs", CPL_TYPE_DOUBLE);
  cpl_table_new_column(debug, "flux_ref", CPL_TYPE_DOUBLE);
  cpl_table_new_column(debug, "flux_obs_cor_gain_bin_exptime", CPL_TYPE_DOUBLE);

  cpl_table_new_column(debug, "kvalue", CPL_TYPE_DOUBLE);
  cpl_table_new_column(debug, "flux_obs_cor_atm", CPL_TYPE_DOUBLE);
  cpl_table_new_column(debug, "flux_obs_cor_obs2ref_bin_size", CPL_TYPE_DOUBLE);

  cpl_table_fill_column_window_double(debug, "wavelength", 0, size, 0.);
  cpl_table_fill_column_window_double(debug, "flux_obs", 0, size,0.);
  cpl_table_fill_column_window_double(debug, "flux_obs_cor_gain_bin_exptime", 0,size, 0.);
  cpl_table_fill_column_window_double(debug, "flux_ref", 0, size, 0.);
  cpl_table_fill_column_window_double(debug, "kvalue", 0, size, 0.);
  cpl_table_fill_column_window_double(debug, "flux_obs_cor_atm", 0, size,0.);
  cpl_table_fill_column_window_double(debug, "flux_obs_cor_obs2ref_bin_size", 0, size,0.);

  pwav = cpl_table_get_data_double(debug, "wavelength");
  pflux_obs = cpl_table_get_data_double(debug, "flux_obs");
  pflux_corr = cpl_table_get_data_double(debug, "flux_obs_cor_gain_bin_exptime");
  pflux_ref = cpl_table_get_data_double(debug, "flux_ref");
  pkavalue = cpl_table_get_data_double(debug, "kvalue");
  pobj_atm_corr = cpl_table_get_data_double(debug, "flux_obs_cor_atm");
  pobj_bin_cor = cpl_table_get_data_double(debug, "flux_obs_cor_obs2ref_bin_size");
  check(*obj_list = xsh_star_flux_list_create( size ));

  cor_fct = gain * bin * exptime;
  //xsh_msg("cor factor=%g",cor_fct);

   /* Loop over lamba_star */
   for ( i = 0 ; i < size ; i++ ) {
      /* correct for gain,bin,exptime */
      /* TODO: We should use only good pixels  */
      (*obj_list)->flux[i] =   flux_spectrum[i]/cor_fct ;
      (*obj_list)->lambda[i] = lambda_star[i] ;

      pwav[i]=lambda_star[i];
      pflux_corr[i]=(*obj_list)->flux[i];
      pflux_obs[i]=flux_spectrum[i];
      pflux_ref[i]=flux_star[i];

      /* Correct for atmos ext*/
      if ( atmos_K != NULL ) {
         kvalue = pow(10., -airmass*atmos_K[i]*0.4 ) ;
         (*obj_list)->flux[i] /= kvalue ;
         pobj_atm_corr[i]=(*obj_list)->flux[i];
         pkavalue[i]=kvalue;
         //xsh_msg("resp: %g kvalue %g k %g",(*obj_list)->flux[i],kvalue,atmos_K[i]);
      }

      /* Multiply by ratio star_binning/spectrum_binning */
      (*obj_list)->flux[i] *= step_star/step_spectrum ;
      pobj_bin_cor[i]=(*obj_list)->flux[i];

   }

   check(cpl_table_duplicate_column(debug,"response",debug,"flux_ref"));

   check(cpl_table_divide_columns(debug,"response","flux_obs_cor_obs2ref_bin_size"));
   //check(cpl_table_save(debug,NULL,NULL,"debug.fits",CPL_IO_DEFAULT));
   xsh_free_table(&debug);

   check(obj_integrated=xsh_star_flux_list_save(*obj_list,"obj_list_corrected.fits","TEST")) ;
   xsh_add_temporary_file("obj_list_corrected.fits");

  cleanup:

   XSH_FREE( lambda_spectrum ) ;
   XSH_FREE( flux_added ) ;
   xsh_free_frame(&obj_integrated);
   xsh_free_table(&debug);
   return cpl_error_get_code();

}

static xsh_star_flux_list *
xsh_response_calculate(
            xsh_star_flux_list * star_list,
            xsh_star_flux_list ** obj_list,
            xsh_spectrum * spectrum,
            cpl_table * atmos_ext_tab,
            XSH_ARM  the_arm,
            double * atmos_K,
            double airmass,
            double exptime,
            double gain)
{ 
   xsh_star_flux_list * resp_list=NULL;
   int npixels = 0;
   int nbad = 0 ;

   double lambda=0;
   double min=0;
   double max=0;
   double kvalue=0;


   double * lambda_resp = NULL ;
   double * flux_resp = NULL ;
   double * flux_added = NULL ;
   double * lambda_star = NULL;
   double  * flux_star = NULL ;

   double * lambda_spectrum = NULL;
   double * plambda=NULL ;
   double * flux_spectrum = NULL ;
   int * qual_spectrum = NULL ;

   int i=0;
   int if0=0;
   int if1=0;
   int  nlambda_star=0;
   int nlambda_spectrum=0;
   double lambda_spectrum_min=0;
   double lambda_spectrum_max=0;
   double lambda_star_min=0;
   double lambda_star_max=0;
   double step_spectrum=0 ;
   double step_star=0 ;
   int npix_in_interval=0 ;
   int bin=1;
   int binx=1;
   int biny=1;
   cpl_frame* resp_integrated=NULL;
   cpl_frame* obj_integrated=NULL;

   check( nlambda_spectrum = xsh_spectrum_get_size( spectrum ) ) ;
   check( flux_spectrum = xsh_spectrum_get_flux( spectrum ) ) ;
   check( qual_spectrum = xsh_spectrum_get_qual( spectrum ) ) ;
   check( lambda_spectrum_min = xsh_spectrum_get_lambda_min( spectrum ) ) ;
   check( lambda_spectrum_max = xsh_spectrum_get_lambda_max( spectrum ) ) ;
   check( step_spectrum = xsh_spectrum_get_lambda_step( spectrum ) ) ;

   /* In NIR, no binning ==> set 1x1 */
   if ( the_arm != XSH_ARM_NIR ) {
      /* we correct for biny: bin along wave direction */
      bin = xsh_pfits_get_biny( spectrum->flux_header ) ;
      binx = xsh_pfits_get_binx( spectrum->flux_header ) ;
      biny = xsh_pfits_get_biny( spectrum->flux_header ) ;
   }
   else {
      bin = 1 ;
      binx=1;
      biny=1;

   }
 
   flux_star = star_list->flux ;
   nlambda_star = star_list->size ;
   lambda_star = star_list->lambda ;
   lambda_star_min = *lambda_star ;
   lambda_star_max = *(lambda_star+nlambda_star-1) ;
   step_star = (lambda_star_max-lambda_star_min)/(nlambda_star-1) ;

   xsh_msg_dbg_low( "Spectrum  - Nlambda: %d, Min: %lf, Max: %lf, Step: %lf",
                    nlambda_spectrum, lambda_spectrum_min, lambda_spectrum_max,
                    step_spectrum ) ;
   xsh_msg_dbg_low( "           - BinX: %d, BinY: %d", binx, biny ) ;

   XSH_CALLOC( lambda_resp, double, nlambda_star ) ;
   XSH_CALLOC( flux_resp, double, nlambda_star ) ;
   XSH_CALLOC( flux_added, double, nlambda_star ) ;
   /* For each lambda in star_list
      if there is such a lambda in rec_list Then
      integrate (add) the flux from (lambda-delta/2) to (lambda+delta/2)
      calculate ratio rec_add_flux/star_flux
      endif
      EndFor
   */
   /* First create lambda_spectrum array */
   XSH_CALLOC( lambda_spectrum, double, nlambda_spectrum ) ;
    
   //xsh_msg("lambda min=%g lambda max=%g",lambda_spectrum_min,lambda_spectrum_max);

   for( lambda = lambda_spectrum_min, plambda = lambda_spectrum, i = 0 ;
        i<nlambda_spectrum ; 
        i++, plambda++, lambda += step_spectrum ) 
   {
      *plambda = lambda ;
   }
  
   /* Create response list (identical to star_list ?) */
   check( resp_list = xsh_star_flux_list_create( nlambda_star ) ) ;
   check( *obj_list = xsh_star_flux_list_create( nlambda_star ) ) ;
   //xsh_msg("step_star=%g step_spectrum=%g", step_star,step_spectrum);
  
   npix_in_interval = step_star/step_spectrum ;
   xsh_msg_dbg_low( "Nb of pixels max in interval: %d", npix_in_interval ) ;



  cpl_table* debug = NULL;
  double* pwav = NULL;
  double* pflux_spectrum = NULL;
  double* pflux_added = NULL;
  double* pflux_star = NULL;
  double* presp = NULL;
  double* pkavalue = NULL;
  double* presp_atm_corr = NULL;
  double* presp_bin_cor = NULL;
  double cor_fct=0;
  debug=cpl_table_new(nlambda_star);

  cpl_table_new_column(debug, "wavelength", CPL_TYPE_DOUBLE);
  cpl_table_new_column(debug, "flux_spectrum", CPL_TYPE_DOUBLE);
  cpl_table_new_column(debug, "flux_added", CPL_TYPE_DOUBLE);
  cpl_table_new_column(debug, "flux_star", CPL_TYPE_DOUBLE);
  cpl_table_new_column(debug, "resp", CPL_TYPE_DOUBLE);
  cpl_table_new_column(debug, "kvalue", CPL_TYPE_DOUBLE);
  cpl_table_new_column(debug, "resp_atm_corr", CPL_TYPE_DOUBLE);
  cpl_table_new_column(debug, "resp_bin_corr", CPL_TYPE_DOUBLE);

  cpl_table_fill_column_window_double(debug, "wavelength", 0, nlambda_star, 0.);
  cpl_table_fill_column_window_double(debug, "flux_spectrum", 0, nlambda_star,0.);
  cpl_table_fill_column_window_double(debug, "flux_added", 0, nlambda_star, 0.);
  cpl_table_fill_column_window_double(debug, "flux_star", 0, nlambda_star, 0.);
  cpl_table_fill_column_window_double(debug, "resp", 0, nlambda_star, 0.);
  cpl_table_fill_column_window_double(debug, "kvalue", 0, nlambda_star, 0.);
  cpl_table_fill_column_window_double(debug, "resp_atm_corr", 0, nlambda_star,0.);
  cpl_table_fill_column_window_double(debug, "resp_bin_corr", 0, nlambda_star,0.);

  pwav = cpl_table_get_data_double(debug,"wavelength");
  pflux_spectrum = cpl_table_get_data_double(debug,"flux_spectrum");
  pflux_added = cpl_table_get_data_double(debug,"flux_added");
  pflux_star = cpl_table_get_data_double(debug,"flux_star");
  presp = cpl_table_get_data_double(debug,"resp");
  pkavalue = cpl_table_get_data_double(debug,"kvalue");
  presp_atm_corr = cpl_table_get_data_double(debug,"resp_atm_corr");
  presp_bin_cor = cpl_table_get_data_double(debug,"resp_bin_corr");


  cor_fct=gain*bin*exptime;
   /* Loop over lamba_star */
   for ( i = 0 ; i < nlambda_star ; i++ ) {
      /* Now add spectrum flux in the star sampling interval */

      flux_added[i] = 0. ;
      min = lambda_star[i] - step_star/2 ;
      max = lambda_star[i] + step_star/2 ;

      xsh_msg_dbg_medium( "Lambda_star[%d] = %lf, Min = %lf, Max = %lf", i,
                          lambda_star[i], min, max ) ;

      find_lambda_idx_limit( min, max, lambda_spectrum, if0, nlambda_spectrum,
			     step_spectrum, &if0, &if1 ) ;

      xsh_msg_dbg_low( "    Actual nb of pixels in interval: %d/%d", if1-if0,
                       npix_in_interval ) ;

      /* correct integrated flux for bad pixels */
      /* initializes bad pix counter to 0 ! */
      nbad=0;
      xsh_flux_integrate_and_corr_for_badpix(npix_in_interval,flux_spectrum,
					     qual_spectrum,if0,if1,i,
					     &flux_added,&npixels,&nbad);

      /* initialize respons correcting also by gain (response in electrons) */
      resp_list->flux[i] = flux_star[i]/(flux_added[i]/cor_fct) ;
      resp_list->lambda[i] = lambda_star[i] ;


      (*obj_list)->flux[i] =   flux_added[i] ;
      (*obj_list)->lambda[i] = lambda_star[i] ;

      pwav[i]=resp_list->lambda[i];
      pflux_spectrum[i]=flux_spectrum[i];
      pflux_added[i]=flux_added[i];
      pflux_star[i]=flux_star[i];
      presp[i]=resp_list->flux[i];

      xsh_msg_dbg_low("  Flux Star = %le, Integrated = %lf (%d pixels, %d bad)",
                      flux_star[i], flux_added[i], npixels, nbad ) ;
      xsh_msg_dbg_low("   =====> Response at Lambda=%lf: %le",
                      lambda_star[i], resp_list->flux[i] ) ;

      /* Multiply by atmos ext
       * TODO: AMO here the check on atmos_ext_tab could be done out of the loop:
       * if missing error should be issued.
       * On the other hand if present there is no need to make the check in the loop.
       */
      if ( atmos_ext_tab != NULL ) {
         kvalue = pow(10., -airmass*atmos_K[i]*0.4 ) ;
         resp_list->flux[i] *= kvalue ;
         presp_atm_corr[i]=resp_list->flux[i];
         pkavalue[i]=kvalue;
           //xsh_msg("resp: %g kvalue %g k %g",resp_list->flux[i],kvalue,atmos_K[i]);
      }

      /* Multiply by ratio star_binning/spectrum_binning */
      resp_list->flux[i] *= step_star/step_spectrum ;
      presp_bin_cor[i]=resp_list->flux[i];
      if0 = if1 ;
   }
   /* cpl_table_save(debug,NULL,NULL,"debug.fits",CPL_IO_DEFAULT); */
   xsh_free_table(&debug);

   /* filter median response to smooth out local jumps */
   if(resp_list->size > 2*FILTER_MEDIAN_HSIZE) {
      xsh_star_flux_list_filter_median(resp_list,FILTER_MEDIAN_HSIZE);
   }

   resp_integrated=xsh_star_flux_list_save(resp_list,"resp_list_integrated.fits","TEST") ;
   xsh_add_temporary_file("resp_list_integrated.fits");
   obj_integrated=xsh_star_flux_list_save(*obj_list,"obj_list_integrated.fits","TEST") ;
   xsh_add_temporary_file("obj_list_integrated.fits");

   if ( xsh_debug_level_get() >= XSH_DEBUG_LEVEL_LOW ) {
      check(xsh_response_crea_ascii(resp_list,star_list,lambda_spectrum,
                                    flux_spectrum,flux_added));
   }

  cleanup:

   XSH_FREE( lambda_spectrum ) ;
   XSH_FREE( lambda_resp ) ;
   XSH_FREE( lambda_resp ) ;
   XSH_FREE( flux_resp ) ;
   XSH_FREE( flux_added ) ;
   xsh_free_frame(&resp_integrated);
   xsh_free_frame(&obj_integrated);
   xsh_free_table(&debug);

   if(cpl_error_get_code() == CPL_ERROR_NONE) {
      return resp_list;
   } else {
      return NULL;
   }
}

/*
static xsh_star_flux_list *
xsh_response_calculate2(
            xsh_star_flux_list * star_list,
            xsh_spectrum * spectrum,
            cpl_table * atmos_ext_tab,
            XSH_ARM  the_arm,
            double * atmos_K,
            double airmass,
            double exptime,
            double gain)
{ 
   xsh_star_flux_list * resp_list=NULL;

   double lambda=0;
   double min=0;
   double max=0;
   double kvalue=0;


   double * lambda_resp = NULL ;
   double * flux_resp = NULL ;
   double * flux_added = NULL ;
   double * lambda_star = NULL;
   double  * flux_star = NULL ;

   double * lambda_spectrum = NULL;
   double * plambda=NULL ;
   double * flux_spectrum = NULL ;
   int * qual_spectrum = NULL ;

   int i=0;
   int  nlambda_star=0;
   int nlambda_spectrum=0;
   double lambda_spectrum_min=0;
   double lambda_spectrum_max=0;
   double lambda_star_min=0;
   double lambda_star_max=0;
   double step_spectrum=0 ;
   double step_star=0 ;
   int npix_in_interval=0 ;
   int binx, biny ;

   check( nlambda_spectrum = xsh_spectrum_get_size( spectrum ) ) ;
   check( flux_spectrum = xsh_spectrum_get_flux( spectrum ) ) ;
   check( qual_spectrum = xsh_spectrum_get_qual( spectrum ) ) ;
   check( lambda_spectrum_min = xsh_spectrum_get_lambda_min( spectrum ) ) ;
   check( lambda_spectrum_max = xsh_spectrum_get_lambda_max( spectrum ) ) ;
   check( step_spectrum = xsh_spectrum_get_lambda_step( spectrum ) ) ;

   // In NIR, no binning ==> set 1x1 
   if ( the_arm != XSH_ARM_NIR ) {
      binx = xsh_pfits_get_binx( spectrum->flux_header ) ;
      biny = xsh_pfits_get_biny( spectrum->flux_header ) ;
   }
   else {
      binx = 1 ;
      biny = 1 ;
   }
 
   flux_star = star_list->flux ;
   nlambda_star = star_list->size ;
   lambda_star = star_list->lambda ;
   lambda_star_min = *lambda_star ;
   lambda_star_max = *(lambda_star+nlambda_star-1) ;
   step_star = (lambda_star_max-lambda_star_min)/(nlambda_star-1) ;

   xsh_msg_dbg_low( "Spectrum  - Nlambda: %d, Min: %lf, Max: %lf, Step: %lf",
                    nlambda_spectrum, lambda_spectrum_min, lambda_spectrum_max,
                    step_spectrum ) ;
   xsh_msg_dbg_low( "           - BinX: %d, BinY: %d", binx, biny ) ;

   XSH_CALLOC( lambda_resp, double, nlambda_star ) ;
   XSH_CALLOC( flux_resp, double, nlambda_star ) ;
   XSH_CALLOC( flux_added, double, nlambda_star ) ;
   // For each lambda in star_list
   //   if there is such a lambda in rec_list Then
   //     integrate (add) the flux from (lambda-delta/2) to (lambda+delta/2)
   //     calculate ratio rec_add_flux/star_flux
   //   endif
   // EndFor
   
   // First create lambda_spectrum array 
   XSH_CALLOC( lambda_spectrum, double, nlambda_spectrum ) ;
    
   //xsh_msg("lambda min=%g lambda max=%g",lambda_spectrum_min,lambda_spectrum_max);

   for( lambda = lambda_spectrum_min, plambda = lambda_spectrum, i = 0 ;
        i<nlambda_spectrum ; 
        i++, plambda++, lambda += step_spectrum ) 
   {
      *plambda = lambda ;
   }
  
   // Create response list (identical to star_list ?) 
   check( resp_list = xsh_star_flux_list_create( nlambda_star ) ) ;
   //xsh_msg("step_star=%g step_spectrum=%g", step_star,step_spectrum);
  
   npix_in_interval = step_star/step_spectrum ;
   xsh_msg_dbg_low( "Nb of pixels max in interval: %d", npix_in_interval ) ;

   int i_start=0;
   int i_end=0;
   int i1_inf=0;
   int i1_sup=0;
   int i2_inf=0;
   int i2_sup=0;

   // Loop over lamba_star 
   for ( i = 0 ; i < nlambda_star ; i++ ) {
      // Now add spectrum flux in the star sampling interval 

      flux_added[i] = 0. ;
      min = lambda_star[i] - step_star/2 ;
      max = lambda_star[i] + step_star/2 ;
      i_start=0;
      i_end=nlambda_spectrum ;
     
      xsh_util_get_infsup(lambda_star,min,i_start,i_end,&i1_inf,&i1_sup);
      xsh_util_get_infsup(lambda_star,max,i_start,i_end,&i2_inf,&i2_sup);

      flux_added[i]=xsh_spectrum_integrate(flux_spectrum,lambda_spectrum,
                                           i1_inf,i1_sup,i2_inf,i2_sup,
                                           lambda_star[i],step_star);

      // initialize respons correcting also by gain (response in electrons) 
      resp_list->flux[i] = flux_star[i]/(flux_added[i]/gain) ;
      resp_list->lambda[i] = lambda_star[i] ;

      // Multiply by atmos ext 
      if ( atmos_ext_tab != NULL ) {
         kvalue = pow(10., -airmass*atmos_K[i]*0.4 ) ;
         resp_list->flux[i] *= kvalue ;
         //xsh_msg("resp: %g kvalue %g k %g",resp_list->flux[i],kvalue,atmos_K[i]);
      }

      // Multiply by ratio star_binning/spectrum_binning 
      resp_list->flux[i] *= step_star/step_spectrum ;


   }

   xsh_star_flux_list_save(resp_list,"resp_list_integrated.fits","TEST") ;


   if ( xsh_debug_level_get() >= XSH_DEBUG_LEVEL_LOW ) {
      check(xsh_response_crea_ascii(resp_list,star_list,lambda_spectrum,
                                    flux_spectrum,flux_added));
   }
   
  cleanup:

   XSH_FREE( lambda_spectrum ) ;
   XSH_FREE( lambda_resp ) ;
   XSH_FREE( lambda_resp ) ;
   XSH_FREE( flux_resp ) ;
   XSH_FREE( flux_added ) ;

   if(cpl_error_get_code() == CPL_ERROR_NONE) {
      return resp_list;
   } else {
      return NULL;
   }
}
*/

/** 
 * Integrate the flux on the same sampling that the star_list, taking into
 * account the bad pixels, apply atmos correction, and divide by the star_list
 * table.
 * 
 * @param star_list Table of ref star flux
 * @param star_list Table of obs obj flux
 * @param spectrum 1./CPL/DOC/cpl_um_2.0.1.psD merged spectrum of standard star
 * @param atmos_ext_table Atmos Extinction table
 * @param airmass observed object airmass mean
 * @param exptime Exposure time
 * @param gain    detector's gain
 * @param instrument instrument arm and lamp setting
 * 
 * @return The computed response frame (table)
 */
static xsh_star_flux_list * 
do_compute( 
xsh_star_flux_list * star_list,
xsh_star_flux_list ** obj_list,
            xsh_spectrum * spectrum,
            cpl_table * atmos_ext_tab,
            HIGH_ABS_REGION * phigh,
            double airmass,
            double exptime,
            double gain,
            xsh_instrument * instrument )
{
   xsh_star_flux_list * resp_list = NULL ;

   int nlambda_star ;
   //double step_spectrum ;
   double step_star ;
   double * lambda_star = NULL;
   //double * flux_star = NULL ;
   double lambda_star_min, lambda_star_max ;
   //double * flux_spectrum = NULL ;
   //int * qual_spectrum = NULL ;
   //double lambda_spectrum_min, lambda_spectrum_max ;
   double * atmos_lambda = NULL ;
   double * atmos_K = NULL ; 
   XSH_ARM the_arm ;

   XSH_ASSURE_NOT_NULL( star_list ) ;
   XSH_ASSURE_NOT_NULL( spectrum ) ;
   /*
     get Nb of lambda, etc in spectrum.
   */
   //check( flux_spectrum = xsh_spectrum_get_flux( spectrum ) ) ;
   //check( qual_spectrum = xsh_spectrum_get_qual( spectrum ) ) ;
   //check( lambda_spectrum_min = xsh_spectrum_get_lambda_min( spectrum ) ) ;
   //check( lambda_spectrum_max = xsh_spectrum_get_lambda_max( spectrum ) ) ;
   //check( step_spectrum = xsh_spectrum_get_lambda_step( spectrum ) ) ;
   the_arm=xsh_instrument_get_arm(instrument);
   /*
     get Nb of lambda in star_list.
   */
   nlambda_star = star_list->size ;
   lambda_star = star_list->lambda ;
   //flux_star = star_list->flux ;
   lambda_star_min = *lambda_star ;
   lambda_star_max = *(lambda_star+nlambda_star-1) ;
   step_star = (lambda_star_max-lambda_star_min)/(nlambda_star-1) ;
   xsh_msg_dbg_low( "Star - Nlambda: %d, Min: %le, Max: %le, Step: %lf",
                    nlambda_star,
                    lambda_star_min, lambda_star_max, step_star ) ;

   check(xsh_interpolate_atm_ext(star_list,atmos_ext_tab,instrument, 
                                 &atmos_lambda,&atmos_K));

   check(resp_list=xsh_response_calculate(star_list,obj_list,spectrum,
                                          atmos_ext_tab,the_arm,atmos_K,
                                          airmass,exptime,gain));

   /* linear interpolation of high absorbtion regions (NIR and VIS only) */
   //PAPERO;
   //double wave_high_abs=find_high_abs_wave_max(phigh);
  for( ; phigh->lambda_min != 0. ; phigh++ ) {

    if(phigh->lambda_min < lambda_star_max &&
       phigh->lambda_max > lambda_star_min) {
      /*
      xsh_msg("plambda_min=%g lambda_star_max=%g plambda_max=%g lambda_star_min=%g",phigh->lambda_min,lambda_star_max,phigh->lambda_max,lambda_star_min);
      */
      check(xsh_interpolate_high_abs_regions(star_list,resp_list,phigh));
    }
  }
  cleanup:
   xsh_msg_dbg_medium( "End compute_response" ) ;
   XSH_FREE( atmos_lambda ) ;
   XSH_FREE( atmos_K ) ;

   return resp_list ;

}



cpl_error_code
xsh_response_merge_obj_std_info(cpl_frame* result,
                                xsh_star_flux_list * star_list,
                                xsh_star_flux_list * obj_list)
{

   cpl_table* table=NULL;
   const char* name=NULL;
   cpl_propertylist* plist=NULL;
   int nrow=0;
   int i=0;

   double* pobj=NULL;
   double* pref=NULL;
   double* pdiv=NULL;

   name=cpl_frame_get_filename(result);
   plist=cpl_propertylist_load(name,0);
   table=cpl_table_load(name,1,0);
   nrow=cpl_table_get_nrow(table);

   check(cpl_table_name_column(table,"FLUX", "RESPONSE"));
   cpl_table_new_column(table,"OBS",CPL_TYPE_DOUBLE);
   cpl_table_new_column(table,"REF",CPL_TYPE_DOUBLE);
   cpl_table_new_column(table,"REF_DIV_OBS",CPL_TYPE_DOUBLE);
   cpl_table_fill_column_window_double(table,"OBS",0,nrow,0);
   cpl_table_fill_column_window_double(table,"REF",0,nrow,0);
   cpl_table_fill_column_window_double(table,"REF_DIV_OBS",0,nrow,0);

   pobj=cpl_table_get_data_double(table,"OBS");
   pref=cpl_table_get_data_double(table,"REF");
   pdiv=cpl_table_get_data_double(table,"REF_DIV_OBS");

   for(i=0;i<nrow;i++) {
      pobj[i]=obj_list->flux[i];
      pref[i]=star_list->flux[i];
      pdiv[i]=pref[i]/pobj[i];
   }

   cpl_table_save(table,plist,NULL,name,CPL_IO_DEFAULT);

  cleanup:
   xsh_free_table(&table);
   xsh_free_propertylist(&plist);

   return cpl_error_get_code();
}


/**
 * Corrects the observed spectrum by gain, exptime, spectral bin size, atmospheric extinction, airmass.
 * at the same wavelengths as the ones at which it is sampled the ref std star
 *
 * @param obs_std_star Rectified frame (1D spectrum)
 * @param ref_std_star_list Ref std star structure
 * @param atmos_ext Atmospheric Extinction Frame
 * @param phigh pointer to high abs region structure
 * @param instrument Instrument structure
 *
 * @return structure with corrected observed std starspectrum
 */
static xsh_star_flux_list *
xsh_obs_std_correct(cpl_frame* obs_std_star, xsh_star_flux_list * ref_std_star_list,
    cpl_frame* atmos_ext, HIGH_ABS_REGION * phigh,xsh_instrument* instrument )
{

  xsh_star_flux_list * corr_obs_std_star_list=NULL;
  double dRA = 0;
  double dDEC = 0;
  double airmass = 0;
  double exptime=0;

  /* extract relevant info (STD RA,DEC,airmass, ID; bin x,y, gain, exptime/DIT) from observed spectrum */
  check(xsh_frame_sci_get_ra_dec_airmass(obs_std_star, &dRA, &dDEC,&airmass));

  const char* filename = NULL;
  cpl_propertylist* plist = NULL;
  //int bin = 1;
  double gain = 0;



  check(filename = cpl_frame_get_filename(obs_std_star));
  check(plist = cpl_propertylist_load(filename, 0));
  /* extract airmass from observed spectrum */
     airmass=xsh_pfits_get_airm_mean(plist);
  /* we get the bin along the dispersion direction */
  if (xsh_instrument_get_arm(instrument) == XSH_ARM_NIR) {
    /* we assume gain in units of ADU/e- as ESO standard */
    gain = 1. / 2.12;
    //bin = 1;
  } else {
    check_msg( gain = xsh_pfits_get_gain(plist), "Could not read gain factor");
    //bin = xsh_pfits_get_biny(plist);
  }
  check(exptime=xsh_pfits_get_exptime(plist));


  /* load atmospheric extinction frame */
  xsh_atmos_ext_list * atmos_ext_list = NULL;
  cpl_table* atmos_ext_tab = NULL;

  if (atmos_ext != NULL) {
    check( atmos_ext_list = xsh_atmos_ext_list_load( atmos_ext) );
    filename=cpl_frame_get_filename(atmos_ext);
    atmos_ext_tab=cpl_table_load(filename,1,0);
  } else {
    xsh_msg_warning(
        "Missing input %s_%s frame. Skip response and efficiency computation", XSH_ATMOS_EXT, xsh_instrument_arm_tostring(instrument));
  }


  double * atmos_lambda = NULL ;
  double * atmos_K = NULL ;

  check(xsh_interpolate_atm_ext(ref_std_star_list,atmos_ext_tab,instrument, &atmos_lambda,&atmos_K));

  XSH_ARM the_arm=xsh_instrument_get_arm(instrument);

  xsh_spectrum * obs_std_spectrum = NULL ; /**< 1d spectrum */
  check( obs_std_spectrum = xsh_spectrum_load( obs_std_star));
  check(xsh_spectrum_correct(ref_std_star_list,
			     obs_std_spectrum,atmos_K,the_arm,
			     airmass,exptime,gain,&corr_obs_std_star_list));


  cleanup:
  xsh_free_table(&atmos_ext_tab);
  xsh_atmos_ext_list_free(&atmos_ext_list);
  xsh_free_propertylist(&plist);
  XSH_FREE( atmos_lambda ) ;
  XSH_FREE( atmos_K ) ;

  xsh_spectrum_free( &obs_std_spectrum ) ;
  return corr_obs_std_star_list;
}
/*
static double
xsh_get_ref_std_star_wave_ref(cpl_table* tbl_ref,const double wavec,const double wstep)
{

  cpl_vector* vx=NULL;
  cpl_vector* vy=NULL;
  cpl_table* ext=NULL;

  XSH_GAUSSIAN_FIT gfit;
  // assumes wave core of 0.5 nm) 
  int rad=(int)(0.5/wstep+0.5);
  double wmax=wavec+rad*wstep;
  double wmin=wavec-rad*wstep;
  double wavefit=0;
  int nrows=0;
  xsh_msg("table selection wmin %g wmax %g",wmin,wmax);

  cpl_table_and_selected_double(tbl_ref,"LAMBDA",CPL_GREATER_THAN,wmin);
  cpl_table_and_selected_double(tbl_ref,"LAMBDA",CPL_LESS_THAN,wmax);
  ext=cpl_table_extract_selected(tbl_ref);
  nrows=cpl_table_get_nrow(tbl_ref);

  cpl_table_cast_column(tbl_ref,"LAMBDA","W",CPL_TYPE_DOUBLE);
  cpl_table_cast_column(tbl_ref,"FLUX","F",CPL_TYPE_DOUBLE);

  vx=cpl_vector_wrap(nrows,cpl_table_get_data_double(tbl_ref,"W"));
  vy=cpl_vector_wrap(nrows,cpl_table_get_data_double(tbl_ref,"F"));

  xsh_vector_fit_gaussian(vx,vy,&gfit);
  wavefit=gfit.peakpos;
  xsh_msg("wave ref fit=%g",wavefit);

  cpl_vector_unwrap(vx);
  cpl_vector_unwrap(vy);
  xsh_free_table(&ext);

  return wavefit;
}
*/
/*
static double
xsh_get_obs_std_star_wave_ref(cpl_frame* obs_std_star,const double wavec,
    const double wmin, const double wstep)
{

  cpl_vector* vx=NULL;
  cpl_vector* vy=NULL;
  XSH_GAUSSIAN_FIT gfit;
  xsh_spectrum* obs_spectrum=NULL;
  cpl_image* sub_ima=NULL;

  double* px=0;
  double* py=0;
  double* pima=NULL;

  double wavefit=0;
  // assumes wave core of 0.5 nm 
  int rad=(int)(0.5/wstep+0.5);
  int i=0;
  int xlo=(wavec-wmin)/wstep-rad;
  int xhi=xlo+2*rad;

  obs_spectrum=xsh_spectrum_load(obs_std_star);

  sub_ima=cpl_image_extract(obs_spectrum->flux,xlo,1,xhi,1);
  pima=cpl_image_get_data_double(sub_ima);

  vx=cpl_vector_new(2*rad);
  vy=cpl_vector_new(2*rad);
  px=cpl_vector_get_data(vx);
  py=cpl_vector_get_data(vy);



  int k=0;
  for(i=0;i<2*rad;i++){
    k=i-rad;
    px[i]=wavec+k*wstep;
    py[i]=pima[i];
  }

  xsh_vector_fit_gaussian(vx,vy,&gfit);

  wavefit=gfit.peakpos;

  xsh_msg("wave obs fit=%g",wavefit);

  xsh_free_vector(&vx);
  xsh_free_vector(&vy);
  xsh_spectrum_free(&obs_spectrum);
  xsh_free_image(&sub_ima);

  return wavefit;
}
*/
/* copy flux(wave) values from wmin to wmax in two output vectors */

static cpl_error_code
xsh_std_star_spectra_to_vector_range(xsh_star_flux_list * obs_std_star_list,
    const double wmin,
    const double wmax,
    cpl_vector** vec_wave,
    cpl_vector** vec_flux)
{
  double* pwave_in=NULL;
  double* pflux_in=NULL;

  double* pwave_ou=NULL;
  double* pflux_ou=NULL;

  int size=0;
  int i=0;
  int k=0;

  pwave_in=obs_std_star_list->lambda;
  pflux_in=obs_std_star_list->flux;
  size=obs_std_star_list->size;

  *vec_wave=cpl_vector_new(size);
  *vec_flux=cpl_vector_new(size);
  pwave_ou=cpl_vector_get_data(*vec_wave);
  pflux_ou=cpl_vector_get_data(*vec_flux);

  for(i=0;i<size;i++) {
    if(pwave_in[i]>=wmin && pwave_in[i]<= wmax) {
      pwave_ou[k]=pwave_in[i];
      pflux_ou[k]=pflux_in[i];
      k++;
    }
  }
  cpl_vector_set_size(*vec_wave,k);
  cpl_vector_set_size(*vec_flux,k);

  return cpl_error_get_code();
}

/*---------------------------------------------------------------------------*/
/**
 * @brief    Sort an array @a u1 of doubles, and permute an array @a u2
 *               in the same way as @a u1 is permuted.
 * @param[in,out]   u1   Pointer to the first array.
 * @param[in,out]   u2   Pointer to the second array.
 * @param    n           The common length of both arrays.
 *
 * @return   @c CPL_ERROR_NONE or the appropriate error code.
 *
 */
/*---------------------------------------------------------------------------*/
cpl_error_code xsh_sort_double_pairs(double *u1, double *u2, cpl_size n)
{
  cpl_vector * biu1=NULL;
  cpl_vector * biu2=NULL;
  cpl_bivector * bi_all=NULL;

  if (n < 1)
    return cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
  cpl_ensure_code(u1 != NULL, CPL_ERROR_NULL_INPUT);
  cpl_ensure_code(u2 != NULL, CPL_ERROR_NULL_INPUT);


  biu1=cpl_vector_wrap(n,u1);
  biu2=cpl_vector_wrap(n,u2);

  bi_all=cpl_bivector_wrap_vectors(biu1, biu2);
  cpl_bivector_sort(bi_all,bi_all, CPL_SORT_ASCENDING,CPL_SORT_BY_X);


  /* cleaning up */

  cpl_bivector_unwrap_vectors(bi_all);
  cpl_vector_unwrap(biu1);
  cpl_vector_unwrap(biu2);

  return CPL_ERROR_NONE;
}

/* selects a sub range in a star line spectrum */
static cpl_error_code
xsh_select_line_core(cpl_vector* wave,cpl_vector* flux,const double wguess,const double wrange,cpl_vector** xfit,cpl_vector** yfit)
{

   int size=0;
   double* pxfit=NULL;
   double* pyfit=NULL;
   double* pwave=NULL;
   double* pflux=NULL;
   int i=0;
   int k=0;

   size=cpl_vector_get_size(wave);
   *xfit=cpl_vector_new(size);
   *yfit=cpl_vector_new(size);
   pxfit=cpl_vector_get_data(*xfit);
   pyfit=cpl_vector_get_data(*yfit);

   pwave=cpl_vector_get_data(wave);
   pflux=cpl_vector_get_data(flux);

   k=0;
   for(i=0;i<size;i++) {
     if(pwave[i]>=(wguess-wrange) &&
        pwave[i]<=(wguess+wrange) ) {

       pxfit[k]=pwave[i];
       pyfit[k]=pflux[i];
       k++;
     }
   }
   check(cpl_vector_set_size(*xfit,k));
   check(cpl_vector_set_size(*yfit,k));

   cleanup:
  return cpl_error_get_code();
}

static cpl_error_code
xsh_line_balance(cpl_vector** x,cpl_vector** y,const double ymax)
{

  double* px=NULL;
  double* py=NULL;
  int k=0;
  int size=0;
  int i=0;

  px=cpl_vector_get_data(*x);
  py=cpl_vector_get_data(*y);

  size=cpl_vector_get_size(*x);

   for(i=0;i<size;i++) {
     if(py[i] <= ymax) {

       px[k]=px[i];
       py[k]=py[i];
       k++;
     }
   }
   cpl_vector_set_size(*x,k);
   cpl_vector_set_size(*y,k);

  cleanup:
  return cpl_error_get_code();
}


static double
xsh_std_star_spectra_correlate(xsh_star_flux_list * obs_std_star_list,
    xsh_star_flux_list * ref_std_star_list,xsh_rv_ref_wave_param* w)

{

  double wave_shift = 0;
  int naxis1 = 0;
  double wstep = 0;
  double wmin = 0;
  double wmax = 0;


  double* prw = 0;
  double* prf = 0;
  double* pow = 0;
  double* pof = 0;

  //double* pvrw = 0;
  double* pvrf = 0;
  //double* pvow = 0;
  double* pvof = 0;
  double hbox_wave=0.5;
  int hbox = (int)(hbox_wave/wstep+0.5);
  //int hbox = 500;
  int size=0;
  int k=0;
  int i=0;
  int box=2*hbox+1;


  naxis1 = xsh_pfits_get_naxis1(obs_std_star_list->header);
  wstep = xsh_pfits_get_cdelt1(obs_std_star_list->header);
  wmin = xsh_pfits_get_crval1(obs_std_star_list->header);
  wmax = wmin + naxis1 * wstep;



  wmin=w->wguess-hbox*wstep;
  wmax=w->wguess+(hbox+1)*wstep;

  //xsh_msg("hbox=%d",hbox);
  /* wrap the observed std star spectrum into a vector */
  cpl_vector* vec_wave_obs = NULL;
  cpl_vector* vec_flux_obs = NULL;
  cpl_vector* vec_wave_ref=NULL;
  cpl_vector* vec_flux_ref=NULL;
  cpl_vector* vec_slope_obs=NULL;
  cpl_vector* vec_slope_ref=NULL;
  cpl_vector* correl=NULL;

  /* we first extract the relevant wavelength range used for cross correlation, covering just one line */
  wmin=w->range_wmin;
  wmax=w->range_wmax;
  //xsh_msg("wmin=%g wmax=%g",wmin,wmax);
  xsh_std_star_spectra_to_vector_range(obs_std_star_list,wmin,wmax,&vec_wave_obs,&vec_flux_obs);
  xsh_std_star_spectra_to_vector_range(ref_std_star_list,wmin,wmax,&vec_wave_ref,&vec_flux_ref);

  /*
  check(cpl_vector_save(vec_flux_obs,"vec_flux_obs.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT));
  check(cpl_vector_save(vec_flux_ref,"vec_flux_ref.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT));
  */

  /* we fit a slope (or parabola) on the flat region of the spectrum */
  double wmin_max=w->ipol_wmin_max;
  double wmax_min=w->ipol_wmax_min;
  //xsh_msg("wmin_max=%g wmax_min=%g",wmin_max,wmax_min);
  vec_slope_obs=xsh_vector_fit_slope(vec_wave_obs,vec_flux_obs,wmin_max,wmax_min,2);
  vec_slope_ref=xsh_vector_fit_slope(vec_wave_ref,vec_flux_ref,wmin_max,wmax_min,2);

  /*
  check(cpl_vector_save(vec_slope_obs,"vec_slope_obs.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT));
  check(cpl_vector_save(vec_slope_ref,"vec_slope_ref.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT));
  */

  /* we divide the spectrum by the slope */
  cpl_vector_divide(vec_flux_obs,vec_slope_obs);
  cpl_vector_divide(vec_flux_ref,vec_slope_ref);
  xsh_free_vector(&vec_slope_obs);
  xsh_free_vector(&vec_slope_ref);

  cpl_vector_add_scalar(vec_flux_obs,2);
  cpl_vector_add_scalar(vec_flux_ref,2);
  /*
  check(cpl_vector_save(vec_flux_obs,"vec_flux_obs_corr.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT));
  check(cpl_vector_save(vec_flux_ref,"vec_flux_ref_corr.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT));
  check(cpl_vector_save(vec_wave_obs,"vec_wave_obs.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT));
  check(cpl_vector_save(vec_wave_ref,"vec_wave_ref.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT));

  */
  
  /* at this points both line spectra (on ref std star and on observed std) have same ranges and a "continuum" */

  /* we now restrict to the line core to limit the effects introduced by the wide line wings */

  double wave_range=w->ipol_hbox;
  cpl_vector* xfit_obs=NULL;
  cpl_vector* yfit_obs=NULL;
  cpl_vector* xfit_ref=NULL;
  cpl_vector* yfit_ref=NULL;
  double* pxfit=NULL;
  double* pyfit=NULL;
  double* pwave=NULL;
  double* pflux=NULL;


  xsh_select_line_core(vec_wave_obs,vec_flux_obs,w->wguess,wave_range,&xfit_obs,&yfit_obs);
  /*
  cpl_vector_save(xfit_obs,"xfit_obs.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
  cpl_vector_save(yfit_obs,"yfit_obs.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
  */
  xsh_select_line_core(vec_wave_ref,vec_flux_ref,w->wguess,wave_range,&xfit_ref,&yfit_ref);
  /*
  cpl_vector_save(xfit_ref,"xfit_ref.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
  cpl_vector_save(yfit_ref,"yfit_ref.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
  */
  /*
  xsh_free_vector(&vec_flux_obs);
  xsh_free_vector(&vec_wave_obs);
  */
 
  /*
  double ymax_obs=0;
  double ymax_ref=0;
  xsh_msg("ok0");
  k=cpl_vector_get_size(yfit_obs);
  pflux=cpl_vector_get_data(yfit_obs);
  xsh_msg("ok2 k=%d",k);
  ymax_obs=(pflux[0] <= pflux[k-1]) ? pflux[0] : pflux[k-1];

  k=cpl_vector_get_size(yfit_ref);
  pflux=cpl_vector_get_data(yfit_ref);
  ymax_ref=(pflux[0] <= pflux[k-1]) ? pflux[0] : pflux[k-1];
  */
  int size_x=k;
  int size_x_obs=0;
  int size_x_ref=0;
 
  /* we now make sure to have a symmetric distribution (because later we get the fit-centroid)
  xsh_line_balance(&xfit_ref,&yfit_ref,ymax_ref);
  pwave=cpl_vector_get_data(xfit_ref);
  pflux=cpl_vector_get_data(yfit_ref);

  k=0;
  for(i=0;i<size_x;i++) {
    if(pflux[i]<=ymax_ref) {

      pxfit[k]=pwave[i];
      pyfit[k]=pflux[i];
      k++;
    }
  }
  check(cpl_vector_set_size(xfit_ref,k));
  cpl_vector_set_size(yfit_ref,k);
  size_x_ref=k;
  */

  /* we now make sure to have a symmetric distribution (because later we get the fit-centroid)
  pwave=cpl_vector_get_data(xfit_obs);
  pflux=cpl_vector_get_data(yfit_obs);

  k=0;
  for(i=0;i<size_x;i++) {
    if(pflux[i]<=ymax_obs) {

      pxfit[k]=pwave[i];
      pyfit[k]=pflux[i];
      k++;
    }
  }
  xsh_msg(">>>k=%d ymax_obs=%g",k,ymax_obs);
  check(cpl_vector_set_size(xfit_obs,k));
  check(cpl_vector_set_size(yfit_obs,k));

  size_x_obs=k;
  */


  /* here we try to do median smoothing to have better fit */
  //cpl_vector* yfit_obs_med=cpl_vector_filter_median_create(yfit_obs,3);
  //check(cpl_vector_save(yfit_obs_med,"yfit_obs_med.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT));
  hbox=cpl_vector_get_size(vec_flux_ref);

  /* because lines cross correlation is not very accurate, here we try to make a poly (parabola)lation
   * fit to have more robust min determination */
  cpl_polynomial* poly_fit_obs=NULL;
  //xsh_msg("ok6");

  double mse=0;
  double* pindex=NULL;
  poly_fit_obs=xsh_polynomial_fit_1d_create(xfit_obs,yfit_obs,4,&mse);
  //xsh_msg("mse=%g",mse);
  cpl_vector* yfit_pol_obs=NULL;
  cpl_vector* yfit_index=NULL;
  size_x_obs=cpl_vector_get_size(xfit_obs);
  yfit_pol_obs=cpl_vector_new(size_x_obs);
  yfit_index=cpl_vector_new(size_x_obs);
  check(pyfit=cpl_vector_get_data(yfit_pol_obs));
  check(pxfit=cpl_vector_get_data(xfit_obs));
  check(pindex=cpl_vector_get_data(yfit_index));

  for(i=0;i<size_x_obs;i++) {
     pyfit[i]=cpl_polynomial_eval_1d(poly_fit_obs,pxfit[i],NULL);
     pindex[i]=i;
  }
  xsh_free_polynomial(&poly_fit_obs);
  //check(cpl_vector_save(yfit_pol_obs,"yfit_pol_obs.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT));
  double ymin=0;
  double xmin=0;

  /* we get the parabola min/max */
  xsh_sort_double_pairs(pyfit,pindex,size_x_obs);
  //cpl_vector_dump(yfit_index,stdout);
  //cpl_vector_dump(yfit_pol_obs,stdout);
  xmin=pxfit[(int)pindex[0]];
  ymin=pyfit[0];
  xsh_free_vector(&yfit_index);
  //xsh_msg("Obs line spectrum poly fit min wave pos=%g value=%g",xmin,ymin);
  //xsh_msg("ok7");

  /* makes Gaussian fit to obs spectrum
  cpl_vector* sigy_obs=NULL;
  cpl_vector* sigy_ref=NULL;

  sigy_obs=cpl_vector_duplicate(yfit_obs);
  cpl_vector_multiply_scalar(sigy_obs,0.1);

  sigy_ref=cpl_vector_duplicate(yfit_ref);
  cpl_vector_multiply_scalar(sigy_ref,0.1);


  double peakpos_obs=xmin;
  double sigma=1;
  double area=1;
  double offset=0;
  double red_chisq=0;
  cpl_matrix* covariance=NULL;

  check(cpl_vector_fit_gaussian(xfit_obs,NULL,yfit_obs,sigy_obs,CPL_FIT_CENTROID,&peakpos_obs,&sigma,&area,&offset,&mse,&red_chisq,&covariance));
  xsh_msg("sigma=%g area=%g offset=%g",sigma,area,offset);
  */
  double peakpos_obs=xmin;
  double peakpos_ref=w->wguess;
  xsh_msg("Pos guess: %g obs: %10.8g Pos ref: %10.8g diff=%10.8g",
	  w->wguess,peakpos_obs,peakpos_ref,peakpos_obs-peakpos_ref);
 

  xsh_msg("Now compute shift by spectra correlation");

  //PIPPO
  /* WE DECIDED NOT TO FIT THE MODEL FOR RV COMPUTATION, ONLY THE OBJECT AND TO MAKE A POLY FIT
   * BECAUSE THE FOLLOWING WAS NOT VERY ACCURATE: IN ANY CASE ONE WOULD HAVE TO FIT A GAUUSS TO
   * THE CORRELATION MAX
   *

  cpl_vector* flux_obs_fine=NULL;
  cpl_vector* flux_ref_fine=NULL;

  flux_obs_fine=xsh_vector_upsample(vec_flux_obs,10);
  flux_ref_fine=xsh_vector_upsample(vec_flux_ref,10);
  cpl_vector_save(flux_obs_fine,"flux_obs_fine.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
  cpl_vector_save(flux_ref_fine,"flux_ref_fine.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);

  cpl_size shift=0;
  hbox=5000;
  hbox=cpl_vector_get_size(vec_flux_ref);
  correl=cpl_vector_new(2*hbox+1);

  check(shift=cpl_vector_correlate(correl,vec_flux_obs,vec_flux_ref));
  //UFFA
  cpl_vector_save(correl,"correl.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);

  double* flux_o =cpl_vector_get_data(flux_obs_fine);
  double* flux_r =cpl_vector_get_data(flux_ref_fine);
  int width_i=2*hbox+1;
  int width_t=2*hbox+1;
  int half_search=(int)(0.5*hbox+1);
  double delta=0;
  double corr=0;
  double* xcorr=NULL;


  XSH_GAUSSIAN_FIT gfit;
  int size_o=0;
  size_o = cpl_vector_get_size(flux_obs_fine);
  double step=(wmax-wmin)/size_o;

  check(xsh_correl_spectra(flux_o,flux_r,size_o,hbox,step,0.1,0,&gfit));

  xsh_msg("sigma=%g",gfit.sigma);
  xsh_msg("computed shift[lognm]=%g",(gfit.peakpos-hbox*step));

  hbox=(int)3.*CPL_MATH_FWHM_SIG * gfit.sigma/step;
  xsh_msg("hsearch=%d",hbox);
  check(xsh_correl_spectra(flux_o,flux_r,size_o,hbox,step,0.1,0,&gfit));




  //check(xcorr=xsh_function1d_xcorrelate(line_i,width_i,line_t,width_t,half_search,0,&corr,&delta));
  //cpl_vector_save(xcorr,"xcorr.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
  xsh_msg("RV corr=%g delta=%g shift=%g",corr,delta,delta*wstep);

  xsh_free(xcorr);
  */
  /*
  check(correl_max=cpl_vector_get_max(correl));
  xsh_msg("correl_max=%g",correl_max);
  check(correl_pos=cpl_vector_find(correl,correl_max));
  xsh_msg("correl: shift=%d max=%g val(shift)=%g pos=%d",
      (int)shift,correl_max,cpl_vector_get(correl,shift+1),(int)correl_pos);
  wave_shift=delta*wstep;
  */
  wave_shift=peakpos_obs-peakpos_ref;
  //check(cpl_vector_save(correl,"correl.fits",CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT));

  cleanup:

  xsh_free_vector(&yfit_pol_obs);
  xsh_free_vector(&xfit_obs);
  xsh_free_vector(&yfit_obs);
  xsh_free_vector(&xfit_ref);
  xsh_free_vector(&yfit_ref);
  xsh_free_vector(&vec_wave_obs);
  xsh_free_vector(&vec_flux_obs);
  xsh_free_vector(&vec_wave_ref);
  xsh_free_vector(&vec_flux_ref);
  xsh_free_vector(&correl);

  return wave_shift;
}

/*
static xsh_star_flux_list *
xsh_bspline_interpol(xsh_star_flux_list * ref_std_star_list,
    HIGH_ABS_REGION * phigh, xsh_instrument* inst) {
  int i = 0;
  xsh_star_flux_list * result = NULL;
  const int n = ref_std_star_list->size;
  //double x[n], y[n];
  double* wave=NULL;
  double* response=NULL;
  double wmin=0;
  double wmax=0;
  double wstep=0;

  cpl_table* tab_data=NULL;
  
  wave = ref_std_star_list->lambda;
  response = ref_std_star_list->flux;

  wmin = *wave;
  wmax = *(wave + n - 1);
  wstep = (wmax - wmin) / (n - 1);

  int k=0;
  // store input values in a table 
  tab_data = cpl_table_new(n);
  cpl_table_new_column(tab_data, "wave", CPL_TYPE_DOUBLE);
  cpl_table_new_column(tab_data, "resp", CPL_TYPE_DOUBLE);
  cpl_table_fill_column_window_double(tab_data, "wave", 0, n, 0);
  cpl_table_fill_column_window_double(tab_data, "resp", 0, n, 0);


  double* px=NULL;
  double* py=NULL;
  px = cpl_table_get_data_double(tab_data, "wave");
  py = cpl_table_get_data_double(tab_data, "resp");
  // flag NAN or INF values 
  for (i = 0; i < n; i++) {
    if(isnan(response[i]) || isinf(response[i])) {
      // bad point: skip it 
    } else {
      px[k]=wave[i];
      py[k]=response[i];
      k++;
    }
  }
  int ndata=k+1;
  cpl_table_set_size(tab_data,ndata);

  if (phigh != NULL) {
    xsh_msg("Flag High Absorption Regions" );
    for (; phigh->lambda_min != 0.; phigh++) {
      xsh_msg("Flag [%g,%g]",phigh->lambda_min,phigh->lambda_max);
      for (i = 0; i < ndata; i++) {
        if (wave[i] >= phigh->lambda_min && wave[i] <= phigh->lambda_max) {
          cpl_table_set_invalid(tab_data,"wave", i);
        }
      }
    }
  }
  cpl_table_erase_invalid(tab_data);
  cpl_table_save(tab_data, NULL, NULL, "resp_data.fits", CPL_IO_DEFAULT);
  ndata=cpl_table_get_nrow(tab_data);

  printf("Found %d good points over %d total points",ndata,n);

  // compute median flux values 
  int hsize=200;
  int size=2*hsize+1;
  int nsampl=ndata/size-1;

  int j=0;
  int m=0;

  //double* psx=NULL;
  //double* psy=NULL;
  cpl_table* tab_sampl=NULL;
  //cpl_vector* sx=NULL;
  //cpl_vector* sy=NULL;
  double* pwav=NULL;
  double* pmed=NULL;
  // prepare table to store median flux values 

  tab_sampl = cpl_table_new(nsampl);
  cpl_table_new_column(tab_sampl, "wave", CPL_TYPE_DOUBLE);
  cpl_table_new_column(tab_sampl, "median", CPL_TYPE_DOUBLE);
  cpl_table_fill_column_window_double(tab_sampl, "wave", 0, nsampl, 0);
  cpl_table_fill_column_window_double(tab_sampl, "median", 0, nsampl, 0);
  pwav = cpl_table_get_data_double(tab_sampl, "wave");
  pmed = cpl_table_get_data_double(tab_sampl, "median");

  // pre set edge values  to be able to interpolate 
  pwav[0]=wave[0];
  pmed[0]=response[0];

  pwav[nsampl-1]=wave[n-1];
  pmed[nsampl-1]=response[n-1];

  cpl_vector* rx=NULL;
  cpl_vector* ry=NULL;
  double* prx=NULL;
  double* pry=NULL;

  rx=cpl_vector_new(size);
  ry=cpl_vector_new(size);
  prx=cpl_vector_get_data(rx);
  pry=cpl_vector_get_data(ry);
  px = cpl_table_get_data_double(tab_data, "wave");
  py = cpl_table_get_data_double(tab_data, "resp");

  for(i=1;i<n && m<nsampl-1;i+=size,m++) {
    for(j=-hsize;j<=hsize;j++) {
      k=j+hsize;
      prx[k]=px[k+i];
      pry[k]=py[k+i];
    }
    pwav[m]=cpl_vector_get_mean(rx);
    pmed[m]=cpl_vector_get_median(ry);
    //printf("sx[%d]=%g sy[%d]=%g\n", m,psx[m], m,psy[m]);
  }

  cpl_table_save(tab_sampl, NULL, NULL, "resp_sampl.fits", CPL_IO_DEFAULT);
  printf("nsampl=%d ",nsampl);
  pwav = cpl_table_get_data_double(tab_sampl, "wave");
  pmed = cpl_table_get_data_double(tab_sampl, "median");

  cpl_table* tab_resp_fit=NULL;
  {
  
    gsl_interp_accel* acc = gsl_interp_accel_alloc();
    gsl_spline* spline = gsl_spline_alloc(gsl_interp_cspline, nsampl);
    gsl_spline_init(spline, pwav, pmed, nsampl);

    // Use table to store results 
    double* pres=NULL;
    tab_resp_fit = cpl_table_new(n);
    cpl_table_new_column(tab_resp_fit, "wave", CPL_TYPE_DOUBLE);
    cpl_table_new_column(tab_resp_fit, "resp", CPL_TYPE_DOUBLE);
    cpl_table_fill_column_window_double(tab_resp_fit, "wave", 0, n, 0);
    cpl_table_fill_column_window_double(tab_resp_fit, "resp", 0, n, 0);
    pwav = cpl_table_get_data_double(tab_resp_fit, "wave");
    pres = cpl_table_get_data_double(tab_resp_fit, "resp");
    result = xsh_star_flux_list_create(n);
    double xi=0;
    double yi=0;

 
    // actual interpolation 
    for (i = 0; i < n; i++) {
      xi=wmin+i*wstep;
      yi = gsl_spline_eval(spline, xi, acc);
      result->lambda[i] = xi;
      result->flux[i] = yi;
      pwav[i] = xi;
      pres[i] = yi;
      printf("%g %g\n", xi, yi);
    }

    gsl_spline_free(spline);
    gsl_interp_accel_free(acc);

  }
  // save result 
  //cpl_table_s
}
*/

static xsh_star_flux_list *
xsh_bspline_fit_interpol(xsh_star_flux_list * ref_std_star_list,cpl_table* resp_fit_points,HIGH_ABS_REGION * phigh,xsh_instrument* inst)
{
  xsh_star_flux_list * res=NULL;
  cpl_table* tab=NULL;
  cpl_table* ext_data=NULL;
  cpl_table* ext_fit=NULL;
  const char* fname=NULL;
  double* lambda=NULL;
  double* wave=NULL;
  double* plambda=NULL;
  double* flux=NULL;
  double* xfit=NULL;
  double* yfit=NULL;
  double wrange=0;
  double wmin_data=0;
  double wmax_data=0;
  double wmin_fit=0;
  double wmax_fit=0;
  double wstp_fit=0;

  int i=0;
  int size_data=0;
  int size_fit=0;
  double med=0;
  int imin=0;
  int imax=0;
  int nsel=0;
  double * pflux=NULL;
 
  double flux_save=0;

  cpl_error_ensure(ref_std_star_list != NULL, CPL_ERROR_NULL_INPUT,return res,"NULL input refence std star list");
  cpl_error_ensure(resp_fit_points != NULL, CPL_ERROR_NULL_INPUT,return res,"NULL input table with response fit points");
  cpl_error_ensure(inst != NULL, CPL_ERROR_NULL_INPUT,return res,"NULL input instrument");

  //fname=cpl_frame_get_filename(resp_fit_points);
  //fit_points=cpl_table_load(fname,1,0);
  plambda=cpl_table_get_data_double(resp_fit_points,"LAMBDA");

  if (xsh_instrument_get_arm(inst) == XSH_ARM_UVB) {
    wrange=0.4;
  } else if (xsh_instrument_get_arm(inst) == XSH_ARM_VIS) {
    wrange=1.0;
  } else if (xsh_instrument_get_arm(inst) == XSH_ARM_NIR) {
    wrange=5.0;
  }

  size_data = ref_std_star_list->size ;
  wave = xsh_star_flux_list_get_lambda(ref_std_star_list) ;
  flux = xsh_star_flux_list_get_flux(ref_std_star_list) ;
  res=xsh_star_flux_list_duplicate(ref_std_star_list);

  tab=cpl_table_new(size_data);
  cpl_table_wrap_double(tab,wave,"wave");
  cpl_table_wrap_double(tab,flux,"response");
  check(wmin_data=cpl_table_get_column_min(tab,"wave"));
  check(wmax_data=cpl_table_get_column_max(tab,"wave"));
  xsh_msg("wmin_data=%g wmax_data=%g",wmin_data,wmax_data);
  size_fit=cpl_table_get_nrow(resp_fit_points);
  //cpl_table_save(resp_fit_points,NULL,NULL,"pippo.fits",CPL_IO_DEFAULT);
 
  pflux=cpl_table_get_data_double(tab,"response");
  /* remove points that have either value NAN or INF */
  for(i=0;i<size_data;i++) {
    if(isnan(pflux[i])) {
	cpl_table_set_invalid(tab,"response",i);
    }
    if(isinf(pflux[i])) {

	cpl_table_set_invalid(tab,"response",i);
    }
  }

  /* check that the sampling points are not falling in any of the high abs windows */
  if (phigh != NULL) {
     xsh_msg("Flag High Absorption Regions" );
     for (; phigh->lambda_min != 0.; phigh++) {
       xsh_msg("Flag [%g,%g]",phigh->lambda_min,phigh->lambda_max);
       for (i = 0; i < size_data; i++) {
         if (wave[i] >= phigh->lambda_min && wave[i] <= phigh->lambda_max) {
           cpl_table_set_invalid(tab,"wave", i);
         }
       }
     }
   }
  cpl_table_erase_invalid(tab);

  check(wmin_fit=cpl_table_get_column_min(resp_fit_points,"LAMBDA"));
  check(wmax_fit=cpl_table_get_column_max(resp_fit_points,"LAMBDA"));
  
  cpl_table_and_selected_double(resp_fit_points,"LAMBDA",CPL_NOT_LESS_THAN,wmin_data);
  cpl_table_and_selected_double(resp_fit_points,"LAMBDA",CPL_NOT_GREATER_THAN,wmax_data);
  ext_fit=cpl_table_extract_selected(resp_fit_points);
  cpl_table_save(tab,NULL,NULL,"resp_data.fits",CPL_IO_DEFAULT);
  check(wmin_fit=cpl_table_get_column_min(ext_fit,"LAMBDA"));
  check(wmax_fit=cpl_table_get_column_max(ext_fit,"LAMBDA"));
  xsh_msg("wmin_fit=%g wmax_fit=%g",wmin_fit,wmax_fit);

  size_fit=cpl_table_get_nrow(ext_fit);
  //xsh_msg("size_fit=%d wstp_fit=%g",size_fit,wstp_fit);
  imin=0;
  if(wmin_fit>wmin_data) {
    //xsh_msg("wmin_fit>wmin_data");
    //size_fit+=1;
    imin=1;
  }
  imax=size_fit-1;
  if(wmax_fit<wmax_data) {
    //xsh_msg("wmax_fit<wmax_data");
    size_fit+=1;
    imax=size_fit-1;
  }
  xsh_msg("size_fit=%d",size_fit);

  xsh_msg("imin=%d imax=%d",imin,imax);
  XSH_CALLOC( xfit, double, size_fit) ;
  XSH_CALLOC( yfit, double, size_fit) ;

  if(wmin_fit>wmin_data) {
    xsh_msg("wmin_fit>wmin_data");

    nsel=cpl_table_and_selected_double(tab,"wave",CPL_NOT_GREATER_THAN,wmin_data+wrange);
    if(nsel==0) {
       xsh_msg("Problem to get spline fit sampling points");
       xsh_msg("Possibly XSH_HIGH_ABS_WIN table wave ranges incompatible with RESP_FIT_POINTS_CAT table");
    }
    ext_data=cpl_table_extract_selected(tab);
    cpl_table_select_all(tab);
    check(med=cpl_table_get_column_median(ext_data,"response"));
    xfit[0]=wmin_data;
    yfit[0]=med;
    //xsh_msg("xfit=%g yfit=%g",wmin_data,med);
    xsh_free_table(&ext_data);

  }
  /*
  xsh_msg("wmin_data=%g",wmin_data);
  xsh_msg("wmin_fit=%g",wmin_fit);
  xsh_msg("wmax_data=%g",wmax_data);
  xsh_msg("wmax_fit=%g",wmax_fit);
  xsh_msg("imin=%d imax=%d",imin,imax);
  */
  for(i=imin;i<=imax;i++) {
    cpl_table_and_selected_double(tab,"wave",CPL_NOT_LESS_THAN,plambda[i]-wrange);
    nsel=cpl_table_and_selected_double(tab,"wave",CPL_NOT_GREATER_THAN,plambda[i]+wrange);
    xfit[i]=plambda[i];
    if(nsel>0) {
    check(ext_data=cpl_table_extract_selected(tab));
    //xsh_msg("wmin=%g wmax=%g",plambda[i]-wrange,plambda[i]+wrange);
    check(med=cpl_table_get_column_median(ext_data,"response"));
    yfit[i]=med;
    flux_save=med;
    //xsh_msg("xfit=%g yfit=%g",xfit[i],yfit[i]);
    xsh_free_table(&ext_data);
    } else {
    yfit[i]=flux_save;
    }
    cpl_table_select_all(tab);
  }
  cpl_table_select_all(tab);

  if(wmax_fit<wmax_data) {
 
    //xsh_msg("wmax_fit<wmax_data");
    cpl_table_and_selected_double(tab,"wave",CPL_NOT_LESS_THAN,wmax_data-wrange);
    ext_data=cpl_table_extract_selected(tab);
    cpl_table_select_all(tab);

    check(med=cpl_table_get_column_median(ext_data,"response"));

    xfit[size_fit-1]=wmax_data;

    yfit[size_fit-1]=med;
    //xsh_msg("xfit=%g yfit=%g",wmax_data,med);
    xsh_free_table(&ext_data);
  }

  /*
  tab=cpl_table_new(size_fit);
  cpl_table_wrap_double(tab,xfit,"xfit");
  check(cpl_table_wrap_double(tab,yfit,"yfit"));
  cpl_table_save(tab,NULL,NULL,"resp_data_fit.fits",CPL_IO_DEFAULT);
  */
  //xsh_msg("size_fit=%d size_data=%d",size_fit,size_data);
  check(res->flux=xsh_bspline_interpolate_data_at_pos(xfit,yfit,size_fit,res->lambda,size_data));
  //xsh_star_flux_list_save(res,"fit_response.fits", "TEST" ) ;

 cleanup:
  XSH_FREE(xfit);
  XSH_FREE(yfit);
  xsh_free_table(&ext_fit);
  cpl_table_unwrap(tab,"wave");
  cpl_table_unwrap(tab,"response");

  return res;
}
static xsh_star_flux_list *
xsh_bspline_fit_smooth(xsh_star_flux_list * ref_std_star_list,HIGH_ABS_REGION * phigh,xsh_instrument* inst)
{
  xsh_star_flux_list * result=NULL;
  size_t n = 0;
  size_t order = 4;
  size_t ncoeffs = 0;
  size_t nbreak = 0;

  size_t i, j;
  gsl_bspline_workspace *bw;
  gsl_vector *B;
  double dy;
  gsl_rng *r;
  gsl_vector *c, *w;
  gsl_vector * x, *y;
  gsl_matrix *X, *cov;
  gsl_multifit_linear_workspace *mw;
  double chisq=0, Rsq=0, dof=0;
  //double tss;
  //double wmin=0;
  //double wmax=0;
  //double wstep=0;
  double* wave = NULL;
  double* response = NULL;
  double* pwav = NULL;
  double* pfit = NULL;
  //int kh = 0;
  double dump_factor = 1.e10;
  //cpl_table* tab_response = NULL;
  cpl_table* tab_resp_fit = NULL;
  //const char* fname = NULL;

  /* set optimal number of coeffs for each arm */
  if (xsh_instrument_get_arm(inst) == XSH_ARM_UVB) {
    ncoeffs = 21;
  } else if (xsh_instrument_get_arm(inst) == XSH_ARM_VIS) {
    ncoeffs = 16;
  } else if (xsh_instrument_get_arm(inst) == XSH_ARM_NIR) {
    ncoeffs = 6;
  }
  nbreak = ncoeffs + 2 - order;

  n = ref_std_star_list->size ;
  wave = ref_std_star_list->lambda ;
  response = ref_std_star_list->flux ;
  //wmin = *wave ;
  //wmax = *(wave+n-1) ;
  //wstep = (wmax-wmin)/(n-1) ;

  gsl_rng_env_setup();
  r = gsl_rng_alloc(gsl_rng_default);

  /* allocate a cubic bspline workspace (ORDER = order) */
  bw = gsl_bspline_alloc(order, nbreak);
  B = gsl_vector_alloc(ncoeffs);

  x = gsl_vector_alloc(n);
  y = gsl_vector_alloc(n);
  X = gsl_matrix_alloc(n, ncoeffs);
  c = gsl_vector_alloc(ncoeffs);
  w = gsl_vector_alloc(n);
  cov = gsl_matrix_alloc(ncoeffs, ncoeffs);
  mw = gsl_multifit_linear_alloc(n, ncoeffs);

  //printf("#m=0,S=0\n");
  /* this is the data to be fitted */
  for (i = 0; i < n; ++i) {
    double sigma;
    double xi = (double) wave[i];
    double yi = (double) response[i];

    sigma = 0.001 * yi;
    dy = gsl_ran_gaussian(r, sigma);
    yi += dy;

    gsl_vector_set(x, i, xi);

    if(isnan(yi) || isinf(yi)) {
      gsl_vector_set(y, i, 0);
      gsl_vector_set(w, i, 1.0 / dump_factor);
      //xsh_msg("wave=%g y=%g w=%g",xi,yi,gsl_vector_get(w, i));
    } else {
      gsl_vector_set(y, i, yi);
      gsl_vector_set(w, i, 1.0 / (sigma * sigma));
      //xsh_msg("wave=%g y=%g w=%g",xi,yi,gsl_vector_get(w, i));
    }
    //printf("%f %g\n", xi, yi);
  }

  if (phigh != NULL) {

    xsh_msg("Flag High Absorption Regions" );
    for (; phigh->lambda_min != 0.; phigh++) {
      xsh_msg("Flag [%g,%g]",phigh->lambda_min,phigh->lambda_max);
      for (i = 0; i < n; i++) {
        if (wave[i] >= phigh->lambda_min && wave[i] <= phigh->lambda_max) {
          //gsl_vector_set(w, i, gsl_vector_get(w, i) / dump_factor);
          gsl_vector_set(w, i, 1.0 / dump_factor);
          //xsh_msg("w=%g",gsl_vector_get(w, i));
        }
      }
    }
  }

  /* use uniform breakpoints on [0, 15] */
  gsl_bspline_knots_uniform(wave[0], wave[n - 1], bw);

  /* construct the fit matrix X */
  for (i = 0; i < n; ++i) {
    double xi = gsl_vector_get(x, i);

    /* compute B_j(xi) for all j */
    gsl_bspline_eval(xi, B, bw);

    /* fill in row i of X */
    for (j = 0; j < ncoeffs; ++j) {
      double Bj = gsl_vector_get(B, j);
      gsl_matrix_set(X, i, j, Bj);
    }
  }

  /* do the fit */
  gsl_multifit_wlinear(X, w, y, c, cov, &chisq, mw);

  dof = n - ncoeffs;
  /*
  tss = gsl_stats_wtss(w->data, 1, y->data, 1, y->size);
  Rsq = 1.0 - chisq / tss;
  */
  printf("chisq/dof = %e, Rsq = %f\n", chisq / dof, Rsq);

  tab_resp_fit = cpl_table_new(n);
  cpl_table_new_column(tab_resp_fit, "wave", CPL_TYPE_DOUBLE);
  cpl_table_new_column(tab_resp_fit, "fit", CPL_TYPE_DOUBLE);
  cpl_table_fill_column_window_double(tab_resp_fit, "wave", 0, n, 0);
  cpl_table_fill_column_window_double(tab_resp_fit, "fit", 0, n, 0);
  pwav = cpl_table_get_data_double(tab_resp_fit, "wave");
  pfit = cpl_table_get_data_double(tab_resp_fit, "fit");
  result=xsh_star_flux_list_create(n);
  /* output the smoothed curve */
  {
    double xi, yi, yerr;
    //printf("#m=1,S=0\n");
    for (i = 0; i < n; i++) {
      xi = (double) wave[i];
      gsl_bspline_eval(xi, B, bw);
      gsl_multifit_linear_est(B, c, cov, &yi, &yerr);
      //printf("%f %g\n", xi, yi);
      pwav[i] = xi;
      pfit[i] = yi;
      result->lambda[i]=xi;
      result->flux[i]=yi;
    }
  }
  //cpl_table_save(tab_resp_fit, NULL, NULL, "resp_fit.fits", CPL_IO_DEFAULT);


  //cleanup:
  gsl_rng_free(r);
  gsl_bspline_free(bw);
  gsl_vector_free(B);
  gsl_vector_free(x);
  gsl_vector_free(y);
  gsl_matrix_free(X);
  gsl_vector_free(c);
  gsl_vector_free(w);
  gsl_matrix_free(cov);
  gsl_multifit_linear_free(mw);
  xsh_free_table(&tab_resp_fit);

  return result;
}



double *
xsh_bspline_interpolate_data_at_pos(double* wave, double* flux,const int size,
                                    double* pos, const int size_pos)
{
  double * result=NULL;
  double xi, yi;
  gsl_interp_accel *acc = gsl_interp_accel_alloc ();
  int i=0;

  gsl_spline *spline = gsl_spline_alloc (gsl_interp_cspline, size);

  gsl_spline_init (spline, wave, flux, size);


  result=cpl_calloc(size_pos, sizeof(double));
  //xsh_msg("ok1 wave sampl max=%g flux=%g",wave[size-1],flux[size-1]);
  //xsh_msg("ok2 pos sampl max=%g",pos[size_pos-1]);
  for (i = 0; i < size_pos; i ++) {
    xi = pos[i];
    //printf ("xi=%g\n", xi);
    //xsh_msg("ok3 wave sampl max=%g flux=%g",wave[size-1],flux[size-1]);
    yi = gsl_spline_eval (spline, xi, acc);
    //printf ("%g %g\n", xi, yi);
    result[i]=yi;
  }

  gsl_spline_free (spline);
  gsl_interp_accel_free (acc);

  return result;
}






double *
xsh_bspline_fit_smooth_data(double* wave, double* flux,const int size,
    HIGH_ABS_REGION * phigh,xsh_instrument* inst, const int fit_region)
{
  double * result=NULL;
  size_t n = 0;
  size_t order = 4;
  size_t ncoeffs = 0;
  size_t nbreak = 0;

  size_t i, j;
  gsl_bspline_workspace *bw;
  gsl_vector *B;
  double dy;
  gsl_rng *r;
  gsl_vector *c, *w;
  gsl_vector * x, *y;
  gsl_matrix *X, *cov;
  gsl_multifit_linear_workspace *mw;
  double chisq=0, Rsq=0, dof=0;
  //double tss;
  //double wmin=0;
  //double wmax=0;
  //double wstep=0;
  //double* wave = NULL;
  //double* response = NULL;
  double* pwav = NULL;
  double* pfit = NULL;
  //int kh = 0;
  double dump_factor_in = 1.e10;
  double dump_factor_ou = 1.e10;
  //cpl_table* tab_response = NULL;
  cpl_table* tab_resp_fit = NULL;
  //const char* fname = NULL;
  double dump_factor=1.e10;

  if(fit_region){
    dump_factor_in = 1.;
    dump_factor_ou = 1.e10;
  } else {
    dump_factor_in = 1.e10;
    dump_factor_ou = 1;
  }
  /* set optimal number of coeffs for each arm */
  if (xsh_instrument_get_arm(inst) == XSH_ARM_UVB) {
    ncoeffs = 21;
  } else if (xsh_instrument_get_arm(inst) == XSH_ARM_VIS) {
    ncoeffs = 16;
  } else if (xsh_instrument_get_arm(inst) == XSH_ARM_NIR) {
    ncoeffs = 6;
  }
  nbreak = ncoeffs + 2 - order;

  n = size ;
  //wave = lambda ;
  //response = flux ;
  //wmin = wave[0] ;
  //wmax = wave[n-1] ;
  //wstep = (wmax-wmin)/(n-1) ;

  gsl_rng_env_setup();
  r = gsl_rng_alloc(gsl_rng_default);

  /* allocate a cubic bspline workspace (ORDER = order) */
  bw = gsl_bspline_alloc(order, nbreak);
  B = gsl_vector_alloc(ncoeffs);

  x = gsl_vector_alloc(n);
  y = gsl_vector_alloc(n);
  X = gsl_matrix_alloc(n, ncoeffs);
  c = gsl_vector_alloc(ncoeffs);
  w = gsl_vector_alloc(n);
  cov = gsl_matrix_alloc(ncoeffs, ncoeffs);
  mw = gsl_multifit_linear_alloc(n, ncoeffs);

  //printf("#m=0,S=0\n");
  /* this is the data to be fitted */
  for (i = 0; i < n; ++i) {
    double sigma;
    double xi = wave[i];
    double yi = flux[i];
    sigma = 0.001 * yi;
    //sigma = 0.1 * sqrt(fabs(yi));
    dy = gsl_ran_gaussian(r, sigma);
    yi += dy;

    gsl_vector_set(x, i, xi);

    if(isnan(yi) || isinf(yi)) {
      gsl_vector_set(y, i, 0);
      gsl_vector_set(w, i, 1.0 / dump_factor);
      //xsh_msg("wave=%g y=%g w=%g",xi,yi,gsl_vector_get(w, i));
    } else {
      gsl_vector_set(y, i, yi);
      gsl_vector_set(w, i, 1.0 / (sigma * sigma));
      //xsh_msg("wave=%g y=%g w=%g",xi,yi,gsl_vector_get(w, i));
    }

    //printf("%f %g\n", xi, yi);
  }
  printf("Dump factor in %g out %g\n", dump_factor_in, dump_factor_ou);
  if (phigh != NULL) {

    xsh_msg("Flag High Absorption Regions" );
    for (; phigh->lambda_min != 0.; phigh++) {
      xsh_msg("Flag [%g,%g]",phigh->lambda_min,phigh->lambda_max);
      for (i = 0; i < n; i++) {

        if (wave[i] >= phigh->lambda_min && wave[i] <= phigh->lambda_max) {
          //xsh_msg("wave in %g",wave[i]);
          gsl_vector_set(w, i, gsl_vector_get(w, i) / dump_factor_in);
          //xsh_msg("inp wave=%g flux %g err=%g",wave[i],gsl_vector_get(y, i), gsl_vector_get(w, i) / dump_factor_in);
        } else {
          //xsh_msg("wave out %g",wave[i]);
          gsl_vector_set(w, i, gsl_vector_get(w, i) / dump_factor_ou);
          //xsh_msg("out wave %g flux %g err=%g",wave[i],gsl_vector_get(y, i), gsl_vector_get(w, i) / dump_factor_ou);
        }
      }
    }
  }

  /* use uniform breakpoints on [0, 15] */
  gsl_bspline_knots_uniform(wave[0], wave[n - 1], bw);

  /* construct the fit matrix X */
  for (i = 0; i < n; ++i) {
    double xi = gsl_vector_get(x, i);

    /* compute B_j(xi) for all j */
    gsl_bspline_eval(xi, B, bw);

    /* fill in row i of X */
    for (j = 0; j < ncoeffs; ++j) {
      double Bj = gsl_vector_get(B, j);
      gsl_matrix_set(X, i, j, Bj);
    }
  }

  /* do the fit */
  gsl_multifit_wlinear(X, w, y, c, cov, &chisq, mw);

  dof = n - ncoeffs;
  /*
  tss = gsl_stats_wtss(w->data, 1, y->data, 1, y->size);
  Rsq = 1.0 - chisq / tss;
  */
  printf("chisq/dof = %e, Rsq = %f\n", chisq / dof, Rsq);

  tab_resp_fit = cpl_table_new(n);
  cpl_table_new_column(tab_resp_fit, "wave", CPL_TYPE_DOUBLE);
  cpl_table_new_column(tab_resp_fit, "fit", CPL_TYPE_DOUBLE);
  cpl_table_fill_column_window_double(tab_resp_fit, "wave", 0, n, 0);
  cpl_table_fill_column_window_double(tab_resp_fit, "fit", 0, n, 0);
  pwav = cpl_table_get_data_double(tab_resp_fit, "wave");
  pfit = cpl_table_get_data_double(tab_resp_fit, "fit");
  result=cpl_calloc(n, sizeof(double));
  /* output the smoothed curve */
  {
    double xi, yi, yerr;
    //printf("#m=1,S=0\n");
    for (i = 0; i < n; i++) {
      xi = (double) wave[i];
      gsl_bspline_eval(xi, B, bw);
      gsl_multifit_linear_est(B, c, cov, &yi, &yerr);
      //printf("%f %g\n", xi, yi);
      pwav[i] = xi;
      pfit[i] = yi;
      //result->lambda[i]=xi;
      result[i]=yi;
    }
  }
  //cpl_table_save(tab_resp_fit, NULL, NULL, "resp_fit.fits", CPL_IO_DEFAULT);


  //cleanup:
  xsh_free_table(&tab_resp_fit);
  gsl_rng_free(r);
  gsl_bspline_free(bw);
  gsl_vector_free(B);
  gsl_vector_free(x);
  gsl_vector_free(y);
  gsl_matrix_free(X);
  gsl_vector_free(c);
  gsl_vector_free(w);
  gsl_matrix_free(cov);
  gsl_multifit_linear_free(mw);


  return result;
}





/* not uniform data distribution */
double *
xsh_bspline_fit_smooth_data2(double* wave, double* flux,const int size,
    HIGH_ABS_REGION * phigh,xsh_instrument* inst, const int fit_region)
{
  double * result=NULL;
  size_t n = 0;
  size_t order = 4;
  size_t ncoeffs = 0;
  size_t nbreak = 0;

  size_t i, j;
  gsl_bspline_workspace *bw;
  gsl_vector *B;
  gsl_vector *Bkpts;
  double dy;
  gsl_rng *r;
  gsl_vector *c, *w;
  gsl_vector * x, *y;
  gsl_matrix *X, *cov;
  gsl_multifit_linear_workspace *mw;
  double chisq=0, Rsq=0, dof=0;
  //double tss;
  //double wmin=0;
  //double wmax=0;
  //double wstep=0;
  //double* wave = NULL;
  //double* response = NULL;
  double* pwav = NULL;
  double* pfit = NULL;
  //int kh = 0;
  //double dump_factor_in = 1.e10;
  //double dump_factor_ou = 1.e10;
  //cpl_table* tab_response = NULL;
  cpl_table* tab_resp_fit = NULL;
  //const char* fname = NULL;
  double dump_factor=1.e10;
  double *Bkpts_ptr;

  /* set optimal number of coeffs for each arm */
  if (xsh_instrument_get_arm(inst) == XSH_ARM_UVB) {
    ncoeffs = 21;
  } else if (xsh_instrument_get_arm(inst) == XSH_ARM_VIS) {
    ncoeffs = 16;
  } else if (xsh_instrument_get_arm(inst) == XSH_ARM_NIR) {
    ncoeffs = 12;
  } else {
    xsh_msg("instrument arm not set");
    exit(0);
  }
  nbreak = ncoeffs + 2 - order;

  n = size ;
  //wave = lambda ;
  //response = flux ;
  //wmin = wave[0] ;
  //wmax = wave[n-1] ;
  //wstep = (wmax-wmin)/(n-1) ;
  gsl_rng_env_setup();
  r = gsl_rng_alloc(gsl_rng_default);

  /* allocate a cubic bspline workspace (ORDER = order) */
  bw = gsl_bspline_alloc(order, nbreak);

  B = gsl_vector_alloc(ncoeffs);

  Bkpts = gsl_vector_alloc(nbreak);


  x = gsl_vector_alloc(n);
  y = gsl_vector_alloc(n);
  X = gsl_matrix_alloc(n, ncoeffs);
  c = gsl_vector_alloc(ncoeffs);
  w = gsl_vector_alloc(n);

  cov = gsl_matrix_alloc(ncoeffs, ncoeffs);

  mw = gsl_multifit_linear_alloc(n, ncoeffs);


  //printf("#m=0,S=0\n");
  /* this is the data to be fitted */
  for (i = 0; i < n; ++i) {
    double sigma;
    double xi = wave[i];
    double yi = flux[i];

    //sigma = 0.1 * sqrt(fabs(yi));
    sigma = 0.001 * yi;
    dy = gsl_ran_gaussian(r, sigma);
    yi += dy;

    gsl_vector_set(x, i, xi);
    if(isnan(yi) || isinf(yi)) {
      gsl_vector_set(y, i, 0);
      gsl_vector_set(w, i, 1.0 / dump_factor);
      //xsh_msg("wave=%g y=%g w=%g",xi,yi,gsl_vector_get(w, i));
    } else {
      gsl_vector_set(y, i, yi);
      gsl_vector_set(w, i, 1.0 / (sigma * sigma));
      //xsh_msg("wave=%g y=%g w=%g",xi,yi,gsl_vector_get(w, i));
    }
    //gsl_vector_set(y, i, yi);
    //gsl_vector_set(w, i, 1.0 / (sigma * sigma));
    //xsh_msg("x=%g y=%g er=%g w=%g",xi,yi,sigma,1.0/(sigma*sigma));

    //printf("%f %g\n", xi, yi);
  }

  /*
  printf("Dump factor in %g out %g\n", dump_factor_in, dump_factor_ou);
  if (phigh != NULL) {

    xsh_msg("Flag High Absorption Regions" );
    for (kh = 0; phigh->lambda_min != 0.; phigh++) {
      xsh_msg("Flag [%g,%g]",phigh->lambda_min,phigh->lambda_max);
      for (i = 0; i < n; i++) {

        if (wave[i] >= phigh->lambda_min && wave[i] <= phigh->lambda_max) {
          //xsh_msg("wave in %g",wave[i]);
          gsl_vector_set(w, i, gsl_vector_get(w, i) / dump_factor_in);
          //xsh_msg("inp wave=%g flux %g err=%g",wave[i],gsl_vector_get(y, i), gsl_vector_get(w, i) / dump_factor_in);
        } else {
          //xsh_msg("wave out %g",wave[i]);
          gsl_vector_set(w, i, gsl_vector_get(w, i) / dump_factor_ou);
          //xsh_msg("out wave %g flux %g err=%g",wave[i],gsl_vector_get(y, i), gsl_vector_get(w, i) / dump_factor_ou);
        }
      }
    }
  }
*/

  /* use uniform breakpoints on [0, 15] */
  Bkpts_ptr=gsl_vector_ptr(Bkpts,0);
  int nfit_div_nbreak=n/nbreak;
  //xsh_msg("nbreak=%d nfit_div_nbreak=%d",nbreak,nfit_div_nbreak);

  for(i=0;i<nbreak;i++) {
      Bkpts_ptr[i]=wave[i*nfit_div_nbreak];
      /*
      xsh_msg("breaks=%g ival=%d wave=%g flux=%g",
          Bkpts_ptr[i],i*nfit_div_nbreak,wave[i*nfit_div_nbreak],flux[i*nfit_div_nbreak]);
      */
  }
  Bkpts_ptr[0]=wave[0];
  Bkpts_ptr[nbreak-1]=wave[n-1];
  gsl_bspline_knots(Bkpts, bw);


  /* construct the fit matrix X */
  for (i = 0; i < n; ++i) {
    double xi = gsl_vector_get(x, i);

    /* compute B_j(xi) for all j */
    gsl_bspline_eval(xi, B, bw);

    /* fill in row i of X */
    for (j = 0; j < ncoeffs; ++j) {
      double Bj = gsl_vector_get(B, j);
      gsl_matrix_set(X, i, j, Bj);
    }
  }


  /* do the fit */
  gsl_multifit_wlinear(X, w, y, c, cov, &chisq, mw);

  dof = n - ncoeffs;
  /*
  tss = gsl_stats_wtss(w->data, 1, y->data, 1, y->size);
  Rsq = 1.0 - chisq / tss;
  */
  printf("chisq/dof = %e, Rsq = %f\n", chisq / dof, Rsq);

  tab_resp_fit = cpl_table_new(n);
  cpl_table_new_column(tab_resp_fit, "wave", CPL_TYPE_DOUBLE);
  cpl_table_new_column(tab_resp_fit, "fit", CPL_TYPE_DOUBLE);
  cpl_table_fill_column_window_double(tab_resp_fit, "wave", 0, n, 0);
  cpl_table_fill_column_window_double(tab_resp_fit, "fit", 0, n, 0);
  pwav = cpl_table_get_data_double(tab_resp_fit, "wave");
  pfit = cpl_table_get_data_double(tab_resp_fit, "fit");
  result=cpl_calloc(n, sizeof(double));
  /* output the smoothed curve */
  {
    double xi, yi, yerr;
    //printf("#m=1,S=0\n");
    for (i = 0; i < n; i++) {
      xi = (double) wave[i];
      gsl_bspline_eval(xi, B, bw);
      gsl_multifit_linear_est(B, c, cov, &yi, &yerr);
      //printf("%f %g\n", xi, yi);
      pwav[i] = xi;
      pfit[i] = yi;
      //result->lambda[i]=xi;
      result[i]=yi;
    }
  }
  //cpl_table_save(tab_resp_fit, NULL, NULL, "resp_fit.fits", CPL_IO_DEFAULT);



  //cleanup:
  xsh_free_table(&tab_resp_fit);
  gsl_rng_free(r);
  gsl_bspline_free(bw);
  gsl_vector_free(B);
  gsl_vector_free(Bkpts);
  gsl_vector_free(x);
  gsl_vector_free(y);
  gsl_matrix_free(X);
  gsl_vector_free(c);
  gsl_vector_free(w);
  gsl_matrix_free(cov);
  gsl_multifit_linear_free(mw);


  return result;
}


/**
 * Compute the instrument response using the rectified frame and the
 * Standard star flux frame. The input should include also the
 * Master Response Function and the Athmospheric Extinction Curve. Also
 * should be produced the Efficiency frame.
 *
 * @param obbs_std_star Rectified frame (1D spectrum)
 * @param flux_std_star_cat Standard star flux catalog frame
 * @param atmos_ext Atmospheric Extinction Frame
 * @param instrument Instrument structure
 * @param exptime Exposure time
 * @param tell_corr apply telluric correction
 *
 * @return Frame of the computed response
 */

cpl_frame * xsh_compute_response2( cpl_frame * obs_std_star,
				   cpl_frame * flux_std_star_cat,
				   cpl_frame * atmos_ext,
				   cpl_frame* high_abs, 
				   cpl_frame* resp_fit_points,
                                  cpl_frame* tell_mod_cat,
				   xsh_instrument * instrument,
				   double exptime, 
                                  const int tell_corr )
{
  /* TODO: exptime should not appear in this function interface as it can be retrieved from input frame */
  cpl_frame* result = NULL;

  XSH_ASSURE_NOT_NULL( obs_std_star ) ;
  XSH_ASSURE_NOT_NULL( flux_std_star_cat ) ;
  XSH_ASSURE_NOT_NULL( instrument ) ;

  double dRA = 0;
  double dDEC = 0;
  double airmass = 0;

  double wmin = 0;
  double wmax = 0;
  double wstep = 0;
  int naxis1 = 0;
  double cdelt1 = 0;
  const char* filename = NULL;
  cpl_propertylist* plist = NULL;
  int is_complete=0;
  cpl_frame* ipol_ref_std_star_frame=NULL;
  xsh_star_flux_list * ref_std_star_list = NULL;
  cpl_frame* frm_tmp=NULL;
  xsh_star_flux_list * obs_std_star_list = NULL;
    xsh_spectrum* obs_spectrum;
  cpl_table* tbl_shift_std_spectrum=NULL;
  cpl_frame* shift_std_star_frame=NULL;
  const char* tbl_shift_std_fname="shift_flux_std_star.fits";
  HIGH_ABS_REGION * phigh = NULL;
  cpl_frame* ipol_shift_std_star_frame=NULL;
  xsh_star_flux_list * shift_std_star_list = NULL;
  xsh_star_flux_list * corr_obs_std_star_list = NULL;
  xsh_star_flux_list * response =NULL;
  xsh_star_flux_list * response_fit =NULL;
  xsh_rv_ref_wave_param* rv_ref_wave=NULL;
  char resp_obs_std_star_fname[256];
  cpl_frame* obs_std_star_resp=NULL;
  cpl_table* resp_fit_points_tbl=NULL;
  cpl_table* tbl_ref_std_spectrum = NULL;

  /* Get wmin,wmax,wstep to re-sample ref std spectrum at same step as observed one */

  filename = cpl_frame_get_filename(obs_std_star);
  plist = cpl_propertylist_load(filename, 0);

  naxis1 = xsh_pfits_get_naxis1(plist);
  cdelt1 = xsh_pfits_get_cdelt1(plist);
  wstep=cdelt1;
  wmin = xsh_pfits_get_crval1(plist);
  xsh_free_propertylist(&plist);

  /* Not to overwrite input spectrum save result on different filename */
  filename=cpl_frame_get_filename(obs_std_star);
  sprintf(resp_obs_std_star_fname,"resp_%s",xsh_get_basename(filename));
  obs_std_star_resp=cpl_frame_duplicate(obs_std_star);
  xsh_frame_spectrum_save(obs_std_star_resp,resp_obs_std_star_fname);
  xsh_add_temporary_file(resp_obs_std_star_fname);

  check(filename=cpl_frame_get_filename(flux_std_star_cat));
  plist=cpl_propertylist_load(filename,0);
  is_complete=cpl_propertylist_has(plist,"WRANGE");
  xsh_free_propertylist(&plist);


  wmax = wmin + cdelt1 * naxis1;
  //xsh_msg("wmin=%g wmax=%g wstep=%g",wmin,wmax,wstep);
  /* Search and eventually load STD star from reference catalog */

  /* get RA DEC from obs std, to be able to identify in the ref catalog the STD star spectrum*/
  check(xsh_frame_sci_get_ra_dec_airmass(obs_std_star_resp,&dRA,&dDEC,&airmass));
    xsh_std_star_id std_star_id=0;


  if (CPL_ERROR_NONE
      != xsh_parse_catalog_std_stars(flux_std_star_cat, dRA, dDEC,
          STAR_MATCH_DEPSILON, &tbl_ref_std_spectrum,&std_star_id)) {
    xsh_msg_warning(
        "Problem parsing input STD catalog. For robustness recipe goes on.");
    xsh_msg_warning("%s", cpl_error_get_message());
    cpl_error_reset();
    xsh_free_table(&tbl_ref_std_spectrum);
    return NULL;
  }

  /* for QC we save the ref STD spectrum in a FITS file to be used for comparison */
  cpl_frame* ref_std_star_frame=NULL;
  const char* tbl_ref_std_fname="ref_flux_std_star.fits";
  check(cpl_table_save(tbl_ref_std_spectrum,NULL,NULL,tbl_ref_std_fname,
                       CPL_IO_DEFAULT));
  xsh_add_temporary_file(tbl_ref_std_fname);

  check(ref_std_star_frame=xsh_frame_product(tbl_ref_std_fname,"FLUX_STD_STAR",
                                         CPL_FRAME_TYPE_TABLE,
                                         CPL_FRAME_GROUP_PRODUCT,
                                               CPL_FRAME_LEVEL_INTERMEDIATE));

  /* re-sample reference STD spectrum on the same sampling pixel base of the observed STD spectrum.
   * over the allowed wave ranges. This operation need to conserve flux.QC: verify that after
   * re-sampling the re-sampled spectrum overlaps the original one. The re-sampling should be given by a
   * (Hermite) spline fit of large enough degree
   *  */


  check(ipol_ref_std_star_frame=xsh_spectrum_interpolate_linear(ref_std_star_frame,wstep,wmin,wmax));


  check( ref_std_star_list = xsh_star_flux_list_load( ipol_ref_std_star_frame ) ) ;
  xsh_free_frame(&ipol_ref_std_star_frame);
  xsh_free_frame(&ref_std_star_frame);
  
  //xsh_star_flux_list_save( ref_std_star_list,"ref_std_star_list.fits", "TEST" ) ;
  if( xsh_instrument_get_arm(instrument) == XSH_ARM_UVB && is_complete!=0){
     check(xsh_star_flux_list_extrapolate_wave_end(ref_std_star_list,545.));
     frm_tmp=xsh_star_flux_list_save( ref_std_star_list,"extrapol_ref_std_star_list.fits", "TEST" ) ;
     xsh_free_frame(&frm_tmp);
  }

  //PIPPO: we moved here telluric correction.
  xsh_msg("tell_corr=%d tell_mod_cal=%p",tell_corr,tell_mod_cat);
  if(xsh_instrument_get_arm(instrument) != XSH_ARM_UVB && tell_corr == 1 && tell_mod_cat!= NULL) {
    xsh_msg("Telluric correction");
    cpl_table* tab_res=NULL;
    //int next=0;
    cpl_size  model_idx=0;

    check(obs_std_star_list = xsh_star_flux_list_load_spectrum(obs_std_star_resp)) ;
    //xsh_star_flux_list_save( obs_std_star_list,"obs_std_star_list.fits", "TEST" ) ;
    check( obs_spectrum = xsh_spectrum_load( obs_std_star_resp));
    check(tab_res=xsh_telluric_model_eval(tell_mod_cat,obs_spectrum,instrument,
					  &model_idx));
 
    //xsh_spectrum_free(&obs_spectrum);
 
    /*
    xsh_msg("response size %d table size %d",
	    response->size,cpl_table_get_nrow(tab_obs_tell_cor));
    xsh_msg("wstep=%g",wstep);
    tab_res=xsh_table_resample_uniform(tab_obs_tell_cor,"wave","ratio",wstep);
    xsh_msg("response size %d table size %d",
	    response->size,cpl_table_get_nrow(tab_res));
    */
    double* pwav=NULL;
    double* pflx=NULL;
    int i=0;
    //cpl_table_dump(tab_res,1,2,stdout);
    check(pwav = cpl_table_get_data_double(tab_res, "wavelength"));

    check(pflx = cpl_table_get_data_double(tab_res, "ratio"));
    /*
    xsh_msg("ok1 size_obs=%d size_mod_corr=%d",
	    obs_std_star_list->size,(int)cpl_table_get_nrow(tab_res));
    */
    for(i=0;i<obs_std_star_list->size;i++) {
      obs_std_star_list->lambda[i]=pwav[i];
      obs_std_star_list->flux[i]=pflx[i];
    }
    xsh_free_table(&tab_res);
    //frm_tmp=xsh_star_flux_list_save( obs_std_star_list,"obs_std_star_list_tell.fits", "TEST" ) ;
    xsh_free_frame(&frm_tmp);
    check(xsh_star_flux_list_to_frame(obs_std_star_list,obs_std_star_resp));
    } else {
     check(obs_std_star_list = xsh_star_flux_list_load_spectrum(obs_std_star_resp)) ;
     //frm_tmp=xsh_star_flux_list_save( obs_std_star_list,"obs_std_star_list.fits", "TEST" ) ;
    xsh_free_frame(&frm_tmp);

    }


  /* TODO: here we need to have the image converted in table
  check(ipol_obs_std_star_frame=xsh_spectrum_interpolate_linear(obs_std_star_resp,wstep/10,wmin,wmax));
  */


  /* TODO: shift the ref STD star spectrum by a value corresponding to the its radial velocity */
  rv_ref_wave=xsh_rv_ref_wave_param_create();

  /* get reference lambda from given ref std star */
  xsh_rv_ref_wave_init(std_star_id ,xsh_instrument_get_arm(instrument),rv_ref_wave);
  //xsh_msg("guess=%12.8g",rv_ref_wave->wguess);


  /* get corresponding lambda from observed std star */
  /* this method is not very robust to get the shift between spectra as:
   * 1) the observed spectrum is noisy
   * 2) the lines are in absorbtion and do not have a Gaussian shape
   * 3) some line have an inversion (a small max in the minimum area of the line)
   * Thus it is better to make a cross correlation between lines that allows to solve all problems
   */
  /*
  double wave_obs=0;
  wave_obs=xsh_get_obs_std_star_wave_ref(obs_std_star_resp,wave_guess,wmin,wstep);
   double wave_shift=0;
  double wave_ref=0;
  wave_ref=xsh_get_ref_std_star_wave_ref(tbl_ref_std_spectrum,wave_guess,wstep);
  xsh_msg("wave: guess %g ref %g shift %g",wave_guess,wave_ref,wave_guess-wave_ref);
  */
  //xsh_star_flux_list_save( obs_std_star_list,"obs_std_star_list.fits", "TEST" ) ;
  frm_tmp=xsh_star_flux_list_save( ref_std_star_list,"ref_flux_std_star.fits", "TEST" ) ;
  xsh_free_frame(&frm_tmp);
  double wave_shift=0;

  wave_shift=xsh_std_star_spectra_correlate(obs_std_star_list,ref_std_star_list,rv_ref_wave);

  //double offset=(wave_obs-wave_guess)/wave_guess;
  double offset=(wave_shift)/rv_ref_wave->wguess;
  xsh_msg("wave: guess[nm] %g RV shift[nm] %g offset[unitless]=%g",rv_ref_wave->wguess,wave_shift,offset);

  tbl_shift_std_spectrum=xsh_table_shift_rv(tbl_ref_std_spectrum,"LAMBDA",offset);

  xsh_free_table(&tbl_ref_std_spectrum);

  check(cpl_table_save(tbl_shift_std_spectrum,NULL,NULL,tbl_shift_std_fname,
                       CPL_IO_DEFAULT));
 
  //TODO: This tmp product has been left for SABINE to check the RV shift
  xsh_add_temporary_file(tbl_shift_std_fname);
  xsh_free_table(& tbl_shift_std_spectrum);
  check(shift_std_star_frame=xsh_frame_product(tbl_shift_std_fname,"FLUX_STD_STAR",
                                         CPL_FRAME_TYPE_TABLE,
                                         CPL_FRAME_GROUP_PRODUCT,
                                               CPL_FRAME_LEVEL_INTERMEDIATE));

 
  /* Define (possibly STD star dependent) arm dependent windows where the (either reference and observed)
   * STD star spectrum should not be sampled (these are usually narrow regions around line cores)
   * */


  check(phigh=xsh_fill_high_abs_regions(instrument,high_abs));

  check(ipol_shift_std_star_frame=xsh_spectrum_interpolate_linear(shift_std_star_frame,wstep,wmin,wmax));

  check( shift_std_star_list = xsh_star_flux_list_load( ipol_shift_std_star_frame ) ) ;
  xsh_free_frame(&ipol_shift_std_star_frame);
  xsh_free_frame(&shift_std_star_frame);

  //xsh_star_flux_list_save( shift_std_star_list,"shift_std_star_list.fits", "TEST" ) ;

  /* median-average over few pix (half-box of 2 pix radii, ie the number of pixels 'around'
   * the central pixel which define the neighbourhood of that pixel=> filter size is 2*radii+1)
   * the observed STD spectrum to remove residual CRH/BP.
   * DONE WITHIN xsh_obs_std_correct
   */

  /*
   * FOR VIS,NIR that are affected by telluric lines:
   * Then filter-max over half-box of 20 pix (to remove isolated telluric lines)
   * Then filter smooth over 50 pix, for smoothing. */
  /* TODO: for the moment not implemented also to be able to check how much bad pixels affects result */
  //xsh_star_flux_list * obs_std_star_list = NULL;

  /* correct observed spectrum for atmospheric absorbtion and airmass dimming effects, wavelength direction
   * bin size, gain, exptime */

  check( corr_obs_std_star_list = xsh_obs_std_correct(obs_std_star_resp, shift_std_star_list, atmos_ext, phigh,instrument ) ) ;
  xsh_free_frame(&obs_std_star_resp);
  //check(xsh_star_flux_list_save(corr_obs_std_star_list,"corr_obs_std_star_list.fits", "TEST" )) ;

  /* divide observed (corrected) spectrum by reference one at the allowed sampling pixels
   * QC: verify that the resulting spectrum is smooth */


  check(response=xsh_star_flux_list_duplicate(ref_std_star_list));
  //check(xsh_star_flux_list_fill_null_end(response));
  //check(xsh_star_flux_list_save(response,"dup_obs_std_star_list.fits", "TEST" )) ;

  //xsh_star_flux_list_filter_median(response,2);
  check(xsh_star_flux_list_divide(response,corr_obs_std_star_list));
  //check(xsh_star_flux_list_save(response,"std_div_obs_star.fits", "TEST" )) ;

  /* smooth over a pixel radii window equivalent to 5nm the resulting ration to get the response
   * QC: verify the resulting spectrum is smooth
   */
  check(xsh_star_flux_list_filter_median(response, 11 ));
  //check(xsh_star_flux_list_save(response,"med_response.fits", "TEST" )) ;
  //int hsize=(int)(0.25/wstep+0.5);
  /*
  int hsize=(int)(1./wstep+0.5);

  check(xsh_star_flux_list_filter_lowpass(response,CPL_LOWPASS_LINEAR, hsize ));
  */
  //check(frm_tmp=xsh_star_flux_list_save( response,"response_smooth.fits", "TEST" )) ;
  xsh_free_frame(&frm_tmp);

  /* interpolate response over pre-defined windows */
  //check(xsh_interpolate_high_abs_regions2(ref_std_star_list,response,phigh));
  //check(xsh_star_flux_list_save( response,"response_window.fits", "TEST" )) ;

  /* B-spline- fit response over flagging out pre-defined windows */

  //PAPERO: here was set telluric correction.
  if(resp_fit_points!=NULL) {
        if (CPL_ERROR_NONE
                        != xsh_parse_catalog_std_stars(resp_fit_points, dRA,
                                        dDEC, STAR_MATCH_DEPSILON,
                                        &resp_fit_points_tbl, &std_star_id)) {
            xsh_msg_warning(
                            "Problem parsing input STD catalog. For robustness recipe goes on.");
            xsh_msg_warning("%s", cpl_error_get_message());
            cpl_error_reset();
            xsh_free_table(&resp_fit_points_tbl);
            return NULL ;
        }
    xsh_msg("Determine response by cubic spline fit interpolation of points defined in input RESP_FIT_POINTS_CAT_%s",
            xsh_instrument_arm_tostring(instrument));
    //cpl_table_dump_structure(resp_fit_points_tbl,stdout);
    check(response_fit=xsh_bspline_fit_interpol(response,resp_fit_points_tbl,phigh,instrument));
  } else {
    xsh_msg("Determine response by cubic spline smooth interpolation of pipeline defined regions");
    response_fit=xsh_bspline_fit_smooth(response,phigh,instrument);
  }
 
  //response_fit=xsh_bspline_interpol(response,phigh,instrument);
  //exit(0);
  /*
  double* spline_fit=NULL; 
  int i=0;
  spline_fit=xsh_bspline_fit_smooth_data(response->lambda,response->flux,
				    response->size,phigh,instrument,0);

  for(i=0;i<response->size;i++) {
    ref_std_star_list->flux[i]=spline_fit[i];
  }
  */
  /* Final step: frame creation, merging info from star and object list */
  char tag[256];
  char fname[256];

  sprintf(tag,"RESPONSE_MERGE1D_%s_%s",xsh_instrument_mode_tostring(instrument),
                          xsh_instrument_arm_tostring(instrument));
  sprintf(fname,"%s.fits",tag);

  check( result = xsh_star_flux_list_save( response_fit, fname, tag ) ) ;
  check(xsh_response_merge_obj_std_info(result,ref_std_star_list, corr_obs_std_star_list));

  cleanup:
  //if(phigh!=NULL) cpl_free(phigh);
  xsh_rv_ref_wave_param_destroy(rv_ref_wave);
  xsh_free_table(&tbl_ref_std_spectrum);
  xsh_free_table(&resp_fit_points_tbl);
  xsh_star_flux_list_free(&ref_std_star_list);
  xsh_star_flux_list_free(&obs_std_star_list);
  xsh_star_flux_list_free(&shift_std_star_list);
  xsh_star_flux_list_free(&corr_obs_std_star_list);
  xsh_star_flux_list_free(&response);
  xsh_star_flux_list_free(&response_fit);

  return result;
}





/** 
 * Compute the instrument response using the rectified frame and the
 * Standard star flux frame. The input should include also the
 * Master Response Function and the Athmospheric Extinction Curve. Also
 * should be produced the Efficiency frame.
 * 
 * @param spectrum_frame Rectified frame (1D spectrum)
 * @param flux_std_star_cat_frame Standard star flux catalog frame
 * @param atmos_ext_frame Atmospheric Extinction Frame
 * @param instrument Instrument strcture
 * @param exptime Exposure time
 * 
 * @return Frame of the computed response
 */

cpl_frame * xsh_compute_response( cpl_frame * spectrum_frame,
				  cpl_frame * flux_std_star_cat_frame,
				  cpl_frame * atmos_ext_frame,
                                  cpl_frame* high_abs_frame,
				  xsh_instrument * instrument,
				  double exptime )
{
  cpl_frame * result = NULL ;	/**< computed response frame */
  xsh_star_flux_list * star_list = NULL ; /**< Std star flux */
  xsh_star_flux_list * obj_list = NULL ; /**< Std star flux */
  xsh_spectrum * spectrum = NULL ; /**< 1d spectrum */
  cpl_frame * tmp_spectrum_frame = NULL ; /**< 1d spectrum */
  xsh_star_flux_list * resp_list = NULL ;
  xsh_atmos_ext_list * atmos_ext_list = NULL ;
  char tag[256];
  char fname[256];

  cpl_frame* flux_std_star_frame=NULL;
  double dRA=0;
  double dDEC=0;
  cpl_table* tbl_ref_std_spectrum=NULL;
  const char* tbl_ref_std_fname="ref_flux_std_star.fits";
  cpl_frame* ipol_flux_std_star_frame=NULL;
  cpl_frame* resampl_flux_std_star_frame=NULL;
  //cpl_frame* smooth_flux_std_star_frame=NULL;

  double wmin=0;
  double wmax=0;
  int naxis1=0;
  double cdelt1=0;
  const char* filename=NULL;
  cpl_propertylist* plist=NULL;
  char * name=NULL;
  char * pcatg=NULL;
  cpl_table* atmos_ext_tab=NULL;
  double airmass=0;
  double gain=1.;
  //int bin=1;
   HIGH_ABS_REGION * phigh=NULL;
   
  XSH_ASSURE_NOT_NULL( spectrum_frame ) ;
  XSH_ASSURE_NOT_NULL( flux_std_star_cat_frame ) ;
  XSH_ASSURE_NOT_NULL( instrument ) ;
 

  xsh_msg("Compute instrument response");

  /* get RA DEC from observed object frame */
  xsh_frame_sci_get_ra_dec_airmass(spectrum_frame,&dRA,&dDEC,&airmass);
  /* extract matching ref STD star spectrum */
  xsh_std_star_id std_star_id=0;

  if(CPL_ERROR_NONE != xsh_parse_catalog_std_stars(flux_std_star_cat_frame,
                                                    dRA,dDEC,
                                                    STAR_MATCH_DEPSILON,
                                                    &tbl_ref_std_spectrum,&std_star_id)){
    xsh_msg_warning("Problem parsing input STD catalog. For robustness recipe goes on.");
    xsh_msg_warning("%s",cpl_error_get_message());
     cpl_error_reset();
     xsh_free_table(&tbl_ref_std_spectrum);
     return NULL;
  }

  /* required for further data reduction ! */
  check(cpl_table_save(tbl_ref_std_spectrum,NULL,NULL,tbl_ref_std_fname,
                       CPL_IO_DEFAULT));
  xsh_add_temporary_file(tbl_ref_std_fname);
  check(flux_std_star_frame=xsh_frame_product(tbl_ref_std_fname,"FLUX_STD_STAR",
                                        CPL_FRAME_TYPE_TABLE,
                                        CPL_FRAME_GROUP_PRODUCT,
                                              CPL_FRAME_LEVEL_INTERMEDIATE));

  filename=cpl_frame_get_filename(spectrum_frame);
  plist=cpl_propertylist_load(filename,0);
  naxis1=xsh_pfits_get_naxis1(plist);
  cdelt1=xsh_pfits_get_cdelt1(plist);
  wmin=xsh_pfits_get_crval1(plist);
  /* we get the bin along the dispersion direction */

  if( xsh_instrument_get_arm(instrument) == XSH_ARM_NIR){
     /* we assume gain in units of ADU/e- as ESO standard */
     gain=1./2.12;
     //bin=1; 
  } else {
     check_msg( gain = xsh_pfits_get_gain(plist),
                "Could not read gain factor");
     //bin=xsh_pfits_get_biny(plist);
  }

  xsh_free_propertylist(&plist);
  wmax=wmin+cdelt1*naxis1;

  check(ipol_flux_std_star_frame=xsh_spectrum_interpolate(flux_std_star_frame,
                                                          1,
                                                          wmin,wmax));

  /*

  check(smooth_flux_std_star_frame=xsh_spectrum_resample(flux_std_star_frame,
                                                          0.08,
                                                       wmin,wmax,instrument));


*/
  check(resampl_flux_std_star_frame=xsh_spectrum_resample(ipol_flux_std_star_frame,
                                                          INTERPOL_WSTEP_NM,
                                                       wmin,wmax,instrument));

  /* Load flux_std_star table */
  check( star_list = xsh_star_flux_list_load( resampl_flux_std_star_frame ) ) ;

  /* Load rect_frame */
  check( spectrum = xsh_spectrum_load( spectrum_frame));
  pcatg=cpl_sprintf("SPECTRUM_%s",xsh_instrument_arm_tostring( instrument));
  name=cpl_sprintf("%s.fits",pcatg);
  tmp_spectrum_frame=xsh_spectrum_save( spectrum,name,pcatg);
  xsh_add_temporary_file(name);
  cpl_free(pcatg);
  cpl_free(name);

  /* Load ATMOS EXT (if not NULL ) */
  if ( atmos_ext_frame != NULL ) {
    check( atmos_ext_list = xsh_atmos_ext_list_load( atmos_ext_frame ) ) ;
    xsh_msg( "ATMOS EXT Loaded" ) ;
    //check(xsh_atmos_ext_dump_ascii(atmos_ext_list,"pippo_atm_ext_list.asc"));
    check(filename=cpl_frame_get_filename(atmos_ext_frame));
    check(atmos_ext_tab=cpl_table_load(filename,1,0));
  } else {
    xsh_msg_warning("Missing input %s_%s frame. Skip response and efficiency computation",
        XSH_ATMOS_EXT,xsh_instrument_arm_tostring(instrument));
  }

  /* Compute */
  check(phigh=xsh_fill_high_abs_regions(instrument,high_abs_frame));
 
  check( resp_list = do_compute( star_list, &obj_list, spectrum, atmos_ext_tab, 
                                 phigh,airmass,exptime,gain,instrument ) ) ;

  //check(xsh_star_flux_list_dump_ascii(resp_list,"pippo_resp_list.asc"));

  /* Save the response frame */
  sprintf(tag,"RESPONSE_MERGE1D_%s_%s",xsh_instrument_mode_tostring(instrument),
                          xsh_instrument_arm_tostring(instrument));
  sprintf(fname,"%s.fits",tag);
  check( result = xsh_star_flux_list_save( resp_list, fname, tag ) ) ;
  xsh_msg("***********************************");
  check(xsh_response_merge_obj_std_info(result,star_list, obj_list));

 cleanup:
  if(high_abs_frame!=NULL) {
     cpl_free(phigh);
  }
  xsh_spectrum_free( &spectrum ) ;

  xsh_star_flux_list_free( &star_list ) ;
  xsh_star_flux_list_free( &obj_list ) ;
  xsh_star_flux_list_free( &resp_list ) ;
  xsh_free_table(&tbl_ref_std_spectrum);
  xsh_free_frame(&flux_std_star_frame);
  xsh_free_frame(&ipol_flux_std_star_frame);
  xsh_free_frame(&resampl_flux_std_star_frame);
  xsh_free_frame(&tmp_spectrum_frame);


  xsh_atmos_ext_list_free(&atmos_ext_list) ;
  xsh_free_propertylist(&plist);
  xsh_free_table(&atmos_ext_tab);

  return result ;
}

/** 
 * Compute the instrument response using the rectified frame and the
 * Standard star flux frame. The input should include also the
 * Master Response Function and the Athmospheric Extinction Curve. Also
 * should be produced the Efficiency frame.
 * 
 * @param spectrum_frame Rectified frame (1D spectrum)
 * @param flux_std_star_cat_frame Standard star flux catalog frame
 * @param atmos_ext_frame Atmospheric Extinction Frame
 * @param instrument Instrument strcture
 * @param exptime Exposure time
 * 
 * @return Frame of the computed response
 */

cpl_frame * xsh_compute_response_ord( cpl_frame * spectrum_frame,
				  cpl_frame * flux_std_star_cat_frame,
				  cpl_frame * atmos_ext_frame,
				  cpl_frame * high_abs_win_frame,
				  xsh_instrument * instrument,
				  double exptime )
{
  cpl_frame * result = NULL ;	/**< computed response frame */
  xsh_star_flux_list * star_list = NULL ; /**< Std star flux */
  xsh_star_flux_list * obj_list = NULL ; /**< obj star flux */
  xsh_spectrum * spectrum = NULL ; /**< 1d spectrum */
  cpl_frame * tmp_spectrum_frame = NULL ; /**< 1d spectrum */
  xsh_star_flux_list * resp_list = NULL ;
  xsh_atmos_ext_list * atmos_ext_list = NULL ;

  char tag[256];
  char fname[256];
  cpl_frame* flux_std_star_frame=NULL;
  double dRA=0;
  double dDEC=0;
  cpl_table* tbl_ref_std_spectrum=NULL;
  const char* tbl_ref_std_fname="ref_flux_std_star.fits";
  cpl_frame* ipol_flux_std_star_frame=NULL;
  double wmin=0;
  double wmax=0;
  int naxis1=0;
  double cdelt1=0;
  const char* filename=NULL;
  cpl_propertylist* plist=NULL;
  char * name=NULL;
  char * pcatg=NULL;
  cpl_table* atmos_ext_tab=NULL;
  double airmass=0;
  double gain=1.;
 
  int next=0;
  //int nord=0;
  int ext=0;
  //int bin=0;
  HIGH_ABS_REGION * phigh=NULL;
  //XSH_ARM the_arm;
  xsh_std_star_id std_star_id=0;

  XSH_ASSURE_NOT_NULL( spectrum_frame ) ;
  XSH_ASSURE_NOT_NULL( flux_std_star_cat_frame ) ;
  XSH_ASSURE_NOT_NULL( instrument ) ;
  XSH_ASSURE_NOT_NULL( fname ) ;

  xsh_msg("Compute instrument response");
  /* get RA DEC from observed object frame */
  xsh_frame_sci_get_ra_dec_airmass(spectrum_frame,&dRA,&dDEC,&airmass);

  /* extract matching ref STD star spectrum */
  if(CPL_ERROR_NONE != xsh_parse_catalog_std_stars(flux_std_star_cat_frame,
                                                    dRA,dDEC,
                                                    STAR_MATCH_DEPSILON,
                                                    &tbl_ref_std_spectrum,&std_star_id)){
    xsh_msg_warning("Problem parsing input STD catalog. For robustness recipe goes on.");
    xsh_msg_warning("%s",cpl_error_get_message());
     cpl_error_reset();
     xsh_free_table(&tbl_ref_std_spectrum);
     return NULL;
  }

  /* required for further data reduction ! */
  check(cpl_table_save(tbl_ref_std_spectrum,NULL,NULL,tbl_ref_std_fname,
                       CPL_IO_DEFAULT));
  xsh_add_temporary_file(tbl_ref_std_fname);

  check(flux_std_star_frame=xsh_frame_product(tbl_ref_std_fname,"FLUX_STD_STAR",
                                        CPL_FRAME_TYPE_TABLE,
                                        CPL_FRAME_GROUP_PRODUCT,
					      CPL_FRAME_LEVEL_INTERMEDIATE));
 
  /* Load ATMOS EXT (if not NULL ) */
  if ( atmos_ext_frame != NULL ) {
     check( atmos_ext_list = xsh_atmos_ext_list_load( atmos_ext_frame ) ) ;
     xsh_msg( "ATMOS EXT Loaded" ) ;
     //check(xsh_atmos_ext_dump_ascii(atmos_ext_list,"pippo_atm_ext_list.asc"));
     check(filename=cpl_frame_get_filename(atmos_ext_frame));
     check(atmos_ext_tab=cpl_table_load(filename,1,0));
  }
  //the_arm=xsh_instrument_get_arm(instrument);

  /* Load rect_frame */
  filename=cpl_frame_get_filename(spectrum_frame);
  next=cpl_frame_get_nextensions(spectrum_frame);
  //nord=next/3;

  plist=cpl_propertylist_load(filename,0);
  if( xsh_instrument_get_arm(instrument) == XSH_ARM_NIR){
    /* we assume gain in units of ADU/e- as ESO standard */
    gain=1./2.12;
    //bin=1; 
  } else {
    check_msg( gain = xsh_pfits_get_gain(plist),
	       "Could not read gain factor");
    //bin=xsh_pfits_get_biny(plist);
  }
  xsh_free_propertylist(&plist);

  check(phigh=xsh_fill_high_abs_regions(instrument,high_abs_win_frame));

  for(ext=0;ext<next;ext+=3) {

    xsh_free_propertylist(&plist);
    plist=cpl_propertylist_load(filename,ext);
    naxis1=xsh_pfits_get_naxis1(plist);
    cdelt1=xsh_pfits_get_cdelt1(plist);
    wmin=xsh_pfits_get_crval1(plist);
    wmax=wmin+cdelt1*naxis1;

    xsh_free_frame(&ipol_flux_std_star_frame);
    check(ipol_flux_std_star_frame=xsh_spectrum_interpolate(flux_std_star_frame,
							    INTERPOL_WSTEP_NM,
						    wmin,wmax));
    /* Load flux_std_star table */
    xsh_star_flux_list_free( &star_list ) ;
    check( star_list = xsh_star_flux_list_load( ipol_flux_std_star_frame ) ) ;

     xsh_spectrum_free( &spectrum ) ;
     check( spectrum=xsh_spectrum_load_order(spectrum_frame,instrument,ext)) ;
     pcatg=cpl_sprintf("SPECTRUM_%s",xsh_instrument_arm_tostring( instrument));
     name=cpl_sprintf("%s.fits",pcatg);
     xsh_free_frame(&tmp_spectrum_frame);

     tmp_spectrum_frame=xsh_spectrum_save_order( spectrum,name,pcatg,ext);
     xsh_add_temporary_file(name);

     cpl_free(pcatg);
     cpl_free(name);

     /* Compute */
     xsh_star_flux_list_free( &resp_list ) ;
     xsh_star_flux_list_free( &obj_list ) ;
     check(resp_list=do_compute( star_list, &obj_list, spectrum, atmos_ext_tab, 
                                 phigh,airmass, exptime, gain, instrument ) ) ;

  
     //check(xsh_star_flux_list_dump_ascii(resp_list,"pippo_resp_list.asc"));

     /* Save the response frame */
     sprintf(tag,"RESPONSE_ORDER1D_%s_%s",xsh_instrument_mode_tostring(instrument),
             xsh_instrument_arm_tostring(instrument));
     sprintf(fname,"%s.fits",tag);
     xsh_free_frame(&result);

     check(result=xsh_star_flux_list_save_order(resp_list,fname,tag,ext)) ;

  }

 cleanup:

  if(high_abs_win_frame!=NULL) {
     cpl_free(phigh);
  }
  xsh_spectrum_free( &spectrum ) ;
  xsh_star_flux_list_free( &star_list ) ;
  xsh_star_flux_list_free( &resp_list ) ;
  xsh_star_flux_list_free( &obj_list ) ;

  xsh_free_table(&tbl_ref_std_spectrum);
  xsh_free_frame(&flux_std_star_frame);
  xsh_free_frame(&ipol_flux_std_star_frame);
  xsh_free_frame(&tmp_spectrum_frame);

  xsh_atmos_ext_list_free(&atmos_ext_list) ;
  xsh_free_propertylist(&plist);
  xsh_free_table(&atmos_ext_tab);

  return result ;
}

/**@}*/
