#ifndef SINFO_CUBE_CONSTRUCT_H
#define SINFO_CUBE_CONSTRUCT_H
/*
 * This file is part of the ESO SINFONI Pipeline
 * Copyright (C) 2004,2005 European Southern Observatory
 *
 * This program 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
 */
/*******************************************************************************
* E.S.O. - VLT project
*
* "@(#) $Id: sinfo_cube_construct.h,v 1.4 2007/06/06 07:10:45 amodigli Exp $"
*
* who       when      what
* --------  --------  ----------------------------------------------
* schreib  06/10/00  created
*/

/************************************************************************
 * ned_cube_construct.h
 * routines needed to construct a 3D-data cube
 *----------------------------------------------------------------------
 */

/*
 * header files
 */

#include "sinfo_new_cube_ops.h"

/*
 * function prototypes
 */

/**
   @name   sinfo_new_convolve_ns_image_by_gauss()
   @memo convolves a north-south-test image with a Gaussian
                        with user given integer half width by using the
                        routine sinfo_function1d_filter_lowpass().
   @param lineImage  North-south-test image
   @param hw          kernel half width of the Gaussian response function
   @result  north-south-test image convolved with a Gaussian
 */

cpl_image * 
sinfo_new_convolve_ns_image_by_gauss( cpl_image * lineImage,int hw);

/**
   @name  sinfo_north_south_test()
   @memo determines the distances of the slitlets
   @param ns_image   north-south image
   @param n_slitlets number of slitlets
   @param halfWidth  half width of the box in which the lines
                                    are fit by a sinfo_gaussian
   @param fwhm       first guess of the full width at half maximum
   @param minDiff    amplitude threshold for Gaussian: 
                    below this intensity the fit will not 
                    be carried through
   @param estimated_dist estimated average distance of spectra
   @param devtol     maximal pixel deviation of slitlet distances
   @result            array of the distances of the slitlets from each other
*/

float * 
sinfo_north_south_test( cpl_image * ns_image,
                          int        n_slitlets,
                          int        halfWidth,
                          float      fwhm,
                          float      minDiff,
                          float      estimated_dist,
                          float      devtol,
              int        top,
              int        bottom ) ;


/**
   @name     sinfo_new_make_cube()
   @memo     makes a data cube out of a resampled source image
   @param    calibImage:  resampled source image
   @param    distances:   distances of the slitlets from each other
                          output of function ns_test
   @param     correct_diff_dist: dummy array with 32 elements
   @return    resulting source data cube
   @note      correct_diff_dist: differences of the slitlets from
                                           distance 32 given in the correct
                                           Spiffi sequence. The first slitlet
                                           is the reference, therefore element
                                           23 is set 0.
   @doc      makes a data cube out of a resampled source image
             this SPIFFI specific routine takes into account the
             Spiffi slitlet order on the detector.
             Also shifts the resulting image rows by one pixel if
             necessary according to the distances array gained from
             the north-south test routine.
             Can do the same with the bad pixel map image to generate a
             bad pixel mask cube.
 */

cpl_imagelist * 
sinfo_new_make_cube ( cpl_image * calibImage,
                     float    * distances,
                     float    * correct_diff_dist ) ;

/**
   @name sinfo_new_make_cube_spi()
   @param  calibImage  resampled source image
   @param  slit_edges  absolute beginning and ending positions of
                                     slitlet, output of sinfo_fitSlits().
   @param  shift       sub_pixel shifts referred to the reference slit
                                     sinfo_edge
   @result  resulting source data cube
   @doc     makes a data cube out of a resampled source image
            this SPIFFI specific routine takes into account the
            Spiffi slitlet order on the detector.
            This routine takes fitted slitlet positions into account.
            Can do the same with the bad pixel map image to generate a
            bad pixel mask cube.
*/

cpl_imagelist * 
sinfo_new_make_cube_spi ( cpl_image *  calibImage,
                        float    ** slit_edges,
                        float    *  shift ) ;


/**
   @name   sinfo_new_make_cube_dist()
   @memo   makes a data cube out of a resampled source image
   @param  calibImage  resampled source image
   @param  firstCol    floating point value of the first column of
                                     the first slitlet in the resampled image,
                                     determined "by hand"
   @param  distances   distances of the slitlets from each other
                                     output of function ns_test
   @param  shift       dummy array with 32 elements
   @result              resulting source data cube
   @note       shift differences of the slitlets from
                               distance 32 given in the correct
                               Spiffi row sequence. The first slitlet
                               is the reference, therefore element
                               23 is set 0.
   @doc        makes a data cube out of a resampled source image
                        this SPIFFI specific routine takes into account the
                        Spiffi slitlet order on the detector.
                        Also shifts the resulting image rows by one pixel if
                        necessary according to the distances array gained from
                        the north-south test routine.
                Can do the same with the bad pixel map image to generate a
                bad pixel mask cube.
*/

cpl_imagelist * 
sinfo_new_make_cube_dist ( cpl_image * calibImage,
                         float      firstCol,
                         float    * distances,
                         float    * shift ) ;


/**
   @name   sinfo_new_make_3D_cube_dist()
   @param  calibImage  resampled source image
   @param  firstCol    floating point value of the first column of
                                     the first slitlet in the resampled image,
                                     determined "by hand"
   @param  distances   distances of the slitlets from each other
                                     output of function ns_test
   @param  shift       dummy array with 32 elements
   @return resulting source data cube
   @note   shift differences of the slitlets from
                               distance 32 given in the correct
                               Spiffi row sequence. The first slitlet
                               is the reference, therefore element
                               23 is set 0.
   @doc       makes a data cube out of a resampled source image
                        this 3D specific routine takes into account the
                        3D slitlet order on the detector.
                        Also shifts the resulting image rows by one pixel if
                        necessary according to the distances array gained from
                        the north-south test routine.
              Can do the same with the bad pixel map image to generate a
              bad pixel mask cube.
*/

cpl_imagelist * 
sinfo_new_make_3D_cube_dist ( cpl_image * calibImage,
                           float      firstCol,
                           float    * distances,
                           float    * shift ) ;


/**
  @name   sinfo_new_make_3D_cube()
  @param  calibImage  resampled source image
  @param  kpixshift   integer pixel shifts of the resulting image
                                     plane rows.
  @param  kpixfirst   first valid pixel
  @result resulting source data cube
  @doc    makes a data cube out of a resampled source image
          this MPE 3D specific routine takes into account the
          3D slitlet order on the detector.
          Also shifts the resulting image row by an integer pixel shift if
          necessary according to the input kpixshift array 
          Can do the same with the bad pixel map image to generate a
          bad pixel mask cube.
*/

cpl_imagelist * 
sinfo_new_make_3D_cube ( cpl_image * calibImage,
                       int      * kpixshift,
                       int        kpixfirst ) ;


/**
   @name     sinfo_new_determine_mask_cube()
   @memo converts resampled bad pixels to real bad pixels in data cubes.
   @param    sourceMaskCube  bad pixel mask cube generated by using
                              the bad pixel mask frame (0: bad, 1: good)
                              and going through the same reduction steps 
                              as with the observation frame.
   @param lowLimit        low limit of pixel value (about -0.7)
   @param highLimit       high limit of bad pixel value (about 0.7)
   @result resulting bad pixel data cube (bad pixels: 0, good pixels: 1).
*/

cpl_imagelist * 
sinfo_new_determine_mask_cube ( cpl_imagelist * sourceMaskCube,
                              float     lowLimit,
                              float     highLimit ) ;


/**
   @name     sinfo_new_interpol_cube()
   @param    sourceCube  reconstructed source cube from sinfo_makeCube
                                     without fine tuning of rows
   @param    maskCube    bad pixel mask cube, bad pixel are marked
                          with 0., good and interpolated pixels with 1.
                          this maskCube is changed within the routine
                          if a bad pixel was interpolated.
   @param    n_neighbors number of neighbors in one spectral direction
                          with which the bad pixel will be interpolated (7)
   @param    max_radius  maximal pixel radius within an image plane
                          inside which valid pixels are searched to
                          be used for interpolation. If there aren't
                          found 9 good neighboring pixels within this
                          radius the loop is left. (5)
   @result   resulting interpolated data cube.
             changed maskCube at the positions of the interpolated pixels
   @doc      Bad pixel interpolation 3D like (saturated pixels exist):
             interpolates the bad pixels of the source cube by
             using the nearest neighbors.
             first it is checked if the bad pixel is interpolatable:
             it is only interpolatable if the number of good pixels
             in its spectrum of length 2*n_neighbors+1 exceeds 3 and
             if there is at least one good pixel on either side of the
             central pixel.
             Afterwards good neighboring pixels are searched within the
             image plane of the bad pixel by using an increasing pixel radius.
             Good pixels mean, the corresponding spectral pixels of the
             bad pixel and its spatial neighboring pixel must have
             at least 2 valid pixel pairs to be able to be used for
             the interpolation. The search is stopped if 9 valid neighboring
             pixels are found.
             Now normalize the found spectral values, collect the valid pixels
             (there must be at least 18) and take the sinfo_median of the valid
             pixels with which the bad pixel is replaced.
*/

cpl_imagelist * 
sinfo_new_interpol_cube ( cpl_imagelist * sourceCube,
                         cpl_imagelist * maskCube,
                         int       n_neighbors,   /* 7 */
                         int       max_radius ) ; /* 5 */


/**
   @name     sinfo_new_fine_tune_cube()
   @param    cube  cube, output of sinfo_makeCube
   @param  correct_diff_dist  differences of the slitlets from
                              distance 32 given in the correct
                              Spiffi row sequence. The first slitlet
                              is the reference, therefore element
                              23 is set 0.
                              Output of sinfo_makeCube!
   @result resulting data cube having the exact row positions
   @doc    fine tunes each row in the right position according
           to the distances of the slitlets to each other
           (output of the north-south test).
           This means that the rows must be realigned by a
           fraction of a pixel to accomodate non-integer slit
           length. The fractional realignment is done by using
           tanh interpolation.
           Each row is rescaled so that the total flux is conserved.
*/


cpl_imagelist * 
sinfo_new_fine_tune_cube( cpl_imagelist * cube,
                         float   * correct_diff_dist,
                         int       n_order) ;


/**
   @name   sinfo_new_fine_tune_cube_by_FFT()
   @param  cube:  cube, output of sinfo_makeCube
   @param  correct_diff_dist: differences of the slitlets from
                  distance 32 given in the correct
                  Spiffi row sequence. The first slitlet
                  is the reference, therefore element
                  23 is set 0.
                  Output of sinfo_makeCube!
   @param  resulting data cube having the exact row positions
   @doc    fine tunes each row in the right position according
                        to the distances of the slitlets to each other
                        (output of the north-south test).
                        This means that the rows must be realigned by a
                        fraction of a pixel to accomodate non-integer slit
                        length. The fractional realignment is done by using
                        the FFT algorithm four1() of N.R.
*/


cpl_imagelist * 
sinfo_new_fine_tune_cube_by_FFT( cpl_imagelist * cube,
                                float   * correct_diff_dist ) ;

/**
   @name    sinfo_new_fine_tune_cube_by_spline()
   @param   cube:  cube, output of sinfo_makeCube
   @param   correct_diff_dist: differences of the slitlets from
                        distance 32 given in the correct
                        Spiffi row sequence. The first slitlet
                        is the reference, therefore element
                        23 is set 0.
                        Output of sinfo_makeCube!
   @result  resulting data cube having the exact row positions
   @doc     fine tunes each row in the right position according
                        to the distances of the slitlets to each other
                        (output of the north-south test).
                        This means that the rows must be realigned by a
                        fraction of a pixel to accomodate non-integer slit
                        length. The fractional realignment is done by using
                        the spline interpolation algorithm splint in connection
                        with the algorithm spline of N.R.
                        This algorithms assume that each row is a tabulated
                        function. The first derivatives of the interpolating
                        function at the first and last point must be given.
                        These are set higher than 1xe^30, so the routine
                        sets the corresponding boundary condition for a natural
                        spline, with zero second derivative on that boundary.
                        Each row is rescaled so that the total flux is
                        conserved.
 */


cpl_imagelist * 
sinfo_new_fine_tune_cube_by_spline ( cpl_imagelist * cube,
                                 float   * correct_diff_dist ) ;

/**
   @name  sinfo_new_calibrate_ns_test()
   @param ns_image:   north-south image
   @param n_slitlets: number of slitlets
   @param halfWidth:  half width of the box in which the lines
                                    are fit by a sinfo_gaussian
   @param fwhm:       first guess of the full width at half maximum
   @param minDiff:    minimum amplitude below which the fit
                                    will not be carried through
   @param estimated_dist: estimated average distance of spectra
   @param devtol:     maximal pixel deviation of the distances from
                                    slitlet center
   @return      array of the distances of the slitlets from each other
   @doc determines the distances of the spectra from the center
                        of the slitlets to be able to find the correct angle of
                        the north-south entrance slit.
*/


float * 
sinfo_new_calibrate_ns_test( cpl_image * ns_image,
                           int        n_slitlets,
                           int        halfWidth,
                           float      fwhm,
                           float      minDiff,
                           float      estimated_dist,
                           float      devtol,
               int        bottom,
               int        top ) ;


cpl_image * 
sinfo_new_make_true_resamp(cpl_image * calibImage, cpl_image* wavemap);


#endif /*!SINFO_CUBE_CONSTRUCT_H*/
