/*                                                                           *
 *   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_size=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 bin size:
         * bin along wave direction* bin along spatial direction
         */
        check(binx = xsh_pfits_get_binx( spectrum->flux_header )) ;
        check(biny = xsh_pfits_get_biny( spectrum->flux_header )) ;
        bin_size=binx*biny;
    }


    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 * exptime * bin_size;
    //xsh_msg("cor factor=%g",cor_fct);
    xsh_msg("cor lambda sampling: %g %g %g",step_star/step_spectrum,step_star,step_spectrum );
    /* 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;
    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");
    }
    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* pvrf = 0;
  double* pvof = 0;
     */
    //double* pvrw = 0;

    //double* pvow = 0;

    double hbox_wave=0.5;
    int hbox = (int)(hbox_wave/wstep+0.5);
    //int hbox = 500;


    int i=0;
    /*
  int k=0;
  int box=2*hbox+1;
  int size=0;
     */
    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;
  k=cpl_vector_get_size(yfit_obs);
  pflux=cpl_vector_get_data(yfit_obs);
  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_ref=0;
     */
    int size_x_obs=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;

    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);

    /* 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 wstp_fit=0;
     */
    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;


    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 reference 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");
    int resp_fit_points_n=cpl_table_get_nrow(resp_fit_points);
    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) &&
                     (wave[i] >= wmin_data && wave[i] <= wmax_data) ){
                    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);
     */
    int n_invalid=0;
    int n_rows=cpl_table_get_nrow(tab);
    //xsh_print_rec_status(0);
    imax = (imax <= resp_fit_points_n-1) ? imax : resp_fit_points_n-1;
    for(i=imin;i<=imax;i++) {
        check(cpl_table_and_selected_double(tab,"wave",CPL_NOT_LESS_THAN,plambda[i]-wrange));
        check(nsel=cpl_table_and_selected_double(tab,"wave",CPL_NOT_GREATER_THAN,plambda[i]+wrange));
        check(n_invalid=cpl_table_count_invalid(tab,"wave"));
        //xsh_msg("lambda start: %g end:%g",plambda[i]-wrange,plambda[i]+wrange);
        n_invalid=cpl_table_count_invalid(tab,"response");
        //xsh_msg("n_sel=%d n_rows=%d n_wave=%d",nsel, n_rows,n_invalid);

        xfit[i]=plambda[i];
        //xsh_msg("n_sel=%d n_rows=%d n_resp=%d",nsel, n_rows,n_invalid);
        check(ext_data=cpl_table_extract_selected(tab));
        nsel=cpl_table_get_nrow(ext_data);
        n_invalid=cpl_table_count_invalid(ext_data,"response");
        //xsh_msg("n_sel=%d n_rows=%d n_wave=%d",nsel, n_rows,n_invalid);
        if(nsel>0 && n_invalid < nsel) {

            //n_invalid=cpl_table_count_invalid(ext_data,"response");
            //xsh_msg("2n_resp=%d",n_invalid);
            //n_invalid=cpl_table_count_invalid(ext_data,"wave");
            //xsh_msg("2n_wave=%d",n_invalid);
            //n_rows=cpl_table_get_nrow(ext_data);
            //xsh_msg("2n_rows=%d",n_rows);
            //xsh_msg("ext_data nrows: %d",cpl_table_get_nrow(ext_data));
            //xsh_msg("wmin=%g wmax=%g",plambda[i]-wrange,plambda[i]+wrange);
            //cpl_table_dump_structure(ext_data,stdout);
            //xsh_print_rec_status(1);
            check(med=cpl_table_get_column_median(ext_data,"response"));
            //xsh_print_rec_status(2);
            yfit[i]=med;
            flux_save=med;
            //xsh_msg("xfit=%g yfit=%g",xfit[i],yfit[i]);

        } else {
            yfit[i]=flux_save;
        }
        //xsh_print_rec_status(16);
        check(cpl_table_select_all(tab));
        //xsh_print_rec_status(17);
        xsh_free_table(&ext_data);
    }

    //xsh_print_rec_status(18);
    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);
    /* as xsh_bspline_interpolate_data_at_pos allocates memory for flux vector
     * and we store it in an already allocated structure we need to deallocate
     * the corresponding memory first: better would be to replace the res->flux
     * values by the newly computed ones
     */
    cpl_free(res->flux);
    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);
    xsh_free_table(&ext_data);
    cpl_table_unwrap(tab,"wave");
    cpl_table_unwrap(tab,"response");
    cpl_free(tab);
    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* w_data, double* f_data,
                                    const int n_data,
                                    double* w_pos, const int n_pos)
{
    double * result=NULL;
    double xi, yi;
    int i_min = 0;
    int i_max = n_pos;
    gsl_interp_accel *acc = gsl_interp_accel_alloc ();
    int i=0;
    xsh_msg("w_pos[0]=%g w_data[0]=%g",w_pos[0],w_data[0]);
    xsh_msg("w_pos[n_pos-1]=%g w_data[n_data-1]=%g",w_pos[n_pos-1],w_data[n_data-1]);
    cpl_ensure(w_pos[0] >= w_data[0], CPL_ERROR_ILLEGAL_INPUT,NULL);
    cpl_ensure(w_pos[n_pos-1] <= w_data[n_data-1], CPL_ERROR_ILLEGAL_INPUT,NULL);

    gsl_spline *spline = gsl_spline_alloc (gsl_interp_cspline, n_data);

    gsl_spline_init (spline, w_data, f_data, n_data);


    result=cpl_calloc(n_pos, sizeof(double));

    if(w_pos[0] == w_data[0]) {
        result[0] = f_data[0];
        i_min = 1;
    }

    if(w_pos[n_pos-1] == w_data[n_data-1]) {
        result[n_pos-1] = f_data[n_data-1];
        i_max = n_pos-1;
    }

    for (i = i_min; i < i_max; i ++) {
        xi = w_pos[i];
        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");
        abort();
    }
    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=NULL;
    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(shift_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);
    //abort();
    /*
  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,shift_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 ;
}

/**@}*/
