/*                                                                              *
 *   This file is part of the ESO UVES Pipeline                                 *
 *   Copyright (C) 2004,2005 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: 2009-06-05 05:49:02 $
 * $Revision: 1.5 $
 * $Name: not supported by cvs2svn $
 * $Log: not supported by cvs2svn $
 * Revision 1.4  2007/05/23 06:43:23  jmlarsen
 * Removed unused variables
 *
 * Revision 1.3  2007/04/12 11:41:09  jmlarsen
 * Check CPL+QFITS version numbers
 *
 * Revision 1.2  2007/03/30 07:07:56  jmlarsen
 * Added commented out profiling test of xmemory
 *
 * Revision 1.1  2007/03/15 12:27:18  jmlarsen
 * Moved unit tests to ./uves/tests and ./flames/tests
 *
 * Revision 1.2  2007/02/27 14:04:14  jmlarsen
 * Move unit test infrastructure to IRPLIB
 *
 * Revision 1.1  2007/02/21 12:38:26  jmlarsen
 * Renamed _test -> -test
 *
 * Revision 1.23  2007/01/29 12:17:54  jmlarsen
 * Support setting verbosity from command line
 *
 * Revision 1.22  2006/11/24 09:39:35  jmlarsen
 * Factored out termination code
 *
 * Revision 1.21  2006/11/22 08:04:59  jmlarsen
 * Added uves_dfs unit test module
 *
 * Revision 1.20  2006/11/16 09:49:25  jmlarsen
 * Fixed doxygen bug
 *
 * Revision 1.19  2006/11/08 14:04:03  jmlarsen
 * Doxybugfix
 *
 * Revision 1.18  2006/11/06 15:30:54  jmlarsen
 * Added missing includes
 *
 * Revision 1.17  2006/11/03 15:02:06  jmlarsen
 * Added test of uves_align
 *
 * Revision 1.16  2006/09/11 13:59:01  jmlarsen
 * Renamed identifier reserved by POSIX
 *
 * Revision 1.15  2006/08/24 11:46:18  jmlarsen
 * Fixed typo
 *
 * Revision 1.14  2006/08/24 07:18:17  amodigli
 * fixed doxygen warnings
 *
 * Revision 1.13  2006/08/24 06:39:57  jmlarsen
 * Reduced maximum line length
 *
 * Revision 1.12  2006/08/17 14:11:25  jmlarsen
 * Use assure_mem macro to check for memory allocation failure
 *
 * Revision 1.11  2006/08/14 12:13:27  jmlarsen
 * Reset irplib error handler
 *
 * Revision 1.10  2006/08/14 07:45:41  amodigli
 * doxigen doc
 *
 * Revision 1.9  2006/03/03 13:54:11  jmlarsen
 * Changed syntax of check macro
 *
 * Revision 1.8  2006/02/03 07:47:53  jmlarsen
 * Moved recipe implementations to ./uves directory
 *
 * Revision 1.7  2006/01/31 08:26:56  jmlarsen
 * Disabled recipe run tests
 *
 * Revision 1.6  2006/01/25 16:14:14  jmlarsen
 * Changed interface of gauss.fitting routine
 *
 * Revision 1.5  2005/12/16 14:22:22  jmlarsen
 * Removed midas test data; Added sof files
 *
 * Revision 1.4  2005/11/18 10:54:43  jmlarsen
 * Minor changes
 *
 * Revision 1.3  2005/11/14 13:18:44  jmlarsen
 * Minor update
 *
 * Revision 1.2  2005/11/11 13:18:54  jmlarsen
 * Reorganized code, renamed source files
 *
 * Revision 1.1  2005/11/10 16:33:41  jmlarsen
 * Added weighted extraction, test of gauss. fit
 *
 */

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

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

#include <uves_utils_cpl.h>
#include <uves_utils.h>
#include <uves_utils_wrappers.h>
#include <uves_error.h>

#include <cpl_test.h>

#include <cpl.h>

#include <float.h>
/*-----------------------------------------------------------------------------
                                Defines
 -----------------------------------------------------------------------------*/

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


/*----------------------------------------------------------------------------*/
/**
 * @defgroup uves_test  UVES library unit tests
 */
/*----------------------------------------------------------------------------*/
/**@{*/
/**
@brief this function test the gaussian fitting
*/
static cpl_error_code
test_gaussian_fitting(void)
{
    cpl_image *image = NULL;
    cpl_image *noise = NULL;

    int sizex = 200;
    int sizey = 100;
    int center_x = 85;   /* Position should be well inside image */
    int center_y = 55;
    int norm[2] = {1, 1000};
    int background[3] = {-3, 2, 900};
    int sigma_x[2] = {2, 15};
    int sigma_y[2] = {6, 10};

    int n_norm = sizeof(norm) / sizeof(int);
    int n_back = sizeof(background) / sizeof(int);
    int n_sx   = sizeof(sigma_x) / sizeof(int);
    int n_sy   = sizeof(sigma_y) / sizeof(int);
    int i_norm, i_back, i_sx, i_sy;


    double tolerance_xy = 1;  /* Test to this precision (pixels) */
    double tolerance_z  = 1;  /* Test to this precision (height/flux) */


    /* Loop over combinations of center/sigma/norm/background */
    for (i_norm = 0; i_norm < n_norm; i_norm++)
    for (i_back = 0; i_back < n_back; i_back++)
    for (i_sx   = 0; i_sx   < n_sx  ; i_sx++)
    for (i_sy   = 0; i_sy   < n_sy  ; i_sy++)
	{
	    cpl_image *noisep[2] = {NULL, NULL};
	    int n_noise   = sizeof(noisep) / sizeof(cpl_image *);
	    int i_noise;

	    /* Create test image + poisson noise */
	    uves_free_image(&image);
	    uves_free_image(&noise);
	    image = cpl_image_new(sizex, sizey, CPL_TYPE_DOUBLE);
	    noise = cpl_image_new(sizex, sizey, CPL_TYPE_DOUBLE);
	    assure_mem( image );
	    assure_mem( noise );
	    
	    check(( cpl_image_fill_gaussian(image,
					    center_x, center_y,
					    norm[i_norm],
					    sigma_x[i_sx], sigma_y[i_sy]),
		    cpl_image_add_scalar(image, background[i_back])),
		   "Error creating test image");

	    /* Set noise := sqrt(image - background) 
	     * Add constant, so that noise
	     * is always positive (which is required
	     * by the fitting algorithm)
	     */
	    check(( cpl_image_fill_gaussian(noise,
					    center_x, center_y,
					    norm[i_norm],
					    sigma_x[i_sx], sigma_y[i_sy]),
		    cpl_image_power(noise, 0.5),
		    cpl_image_add_scalar(noise, .0001)),
		   "Error creating noise image");
	 

	    noisep[0] = noise;
	    noisep[1] = NULL;
	    for (i_noise = 0; i_noise < n_noise; i_noise++)
		{
		    double x0, y_0, sx, sy;
		    double height;       /* Height minus background */
		    double norm_fit;
		    
		    uves_msg_debug(" In: Center = (%.2f, %.2f) "
			     "Sigma = (%.2f, %.2f) Norm = %.2f Bkg = %.2f",
			     (double) center_x, (double) center_y,
			     (double) sigma_x[i_sx], (double) sigma_y[i_sy],
			     (double) norm[i_norm], (double) background[i_back]);
		    
		    check( uves_fit_gaussian_2d_image(image, noisep[i_noise],
						1, 1,
						sizex, sizey,
						&x0, &y_0, &sx, &sy,
						&height,
						NULL, NULL),
			   "2d fitting routine failed");
		    
		    /* Fitted height is norm / (2pi sx sy) */
		    norm_fit = height * 2 * M_PI * sx * sy;
		    
		    uves_msg_debug("Fit: Center = (%.2f, %.2f) "
			     "Sigma = (%.2f, %.2f) Norm = %.2f Height = %.2e",
			     x0, y_0,
			     sx, sy,
			     norm_fit, height);
		    
		    assure( fabs(center_x - x0) < tolerance_xy, 
                            CPL_ERROR_ILLEGAL_OUTPUT, 
			    "x-center deviates more than %f pixel(s)", 
                            tolerance_xy);
		    assure( fabs(center_y - y_0) < tolerance_xy, 
                            CPL_ERROR_ILLEGAL_OUTPUT, 
			    "y-center deviates more than %f pixel(s)", 
                            tolerance_xy);
		    assure( fabs(sigma_x[i_sx] - sx) < tolerance_xy, 
                            CPL_ERROR_ILLEGAL_OUTPUT,
			    "sigma_x deviates more than %f pixel(s)", 
                            tolerance_xy);
		    assure( fabs(sigma_y[i_sy] - sy) < tolerance_xy, 
                            CPL_ERROR_ILLEGAL_OUTPUT,
			    "sigma_y deviates more than %f pixel(s)", 
                             tolerance_xy);
		    
		    /* The function doesn't return the background level,
		       but this is implicitly checked when comparing the 
		       inferred height */
		    assure( fabs(norm[i_norm] - norm_fit) < tolerance_z, 
			    CPL_ERROR_ILLEGAL_OUTPUT,
			    "Norm deviates more than %f", tolerance_z);

		}
	}
  cleanup:
    uves_free_image(&image);
    uves_free_image(&noise);
    
    return cpl_error_get_code();
}

   
#if 0

#define QFITS_MEMORY_MAXPTRS     200003
#define PTR_HASH(ptr) (((unsigned long int) ptr) % QFITS_MEMORY_MAXPTRS)

//#define LOOP 100000
#define LOOP 1000

static void
realloc_cpl(void *p)
{
    int i;
    for (i = LOOP; i >=0; i--) p = cpl_realloc(p, 16);
    return;
}

static void
realloc_system(void *p)
{
    long i;
    int j;
    for (j = 0; j < 5000; j++)
    for (i = LOOP; i >=0; i--) p = realloc(p, 16);
    return;
}

static void
test_xmemory(void)
{
    int i;
    int j;
/*    int N[] = {
        15, 15, 15, 15, 15, 
        15, 15, 15, 15, 15,
        15, 15, 15, 15, 15, 
        15, 15, 15, 15, 15};*/
    const int N = 15;
    const int size[] = {
        99440, 99820, 99820, 99820, 99820,
        99820, 99820, 99820, 99820, 99800,
        99820, 99820, 99820, 99820, 99820,
        99820, 99820, 99820, 99820, 99800,
        99820, 99820, 99820, 99820, 99820,
        99820, 99820, 99820, 99820, 99800,
        99820, 99820, 99820, 99820, 99800,
        99820, 99820, 99820, 99820, 99800,
        99820, 99820, 99820, 99820, 99800,
        99820, 99820, 99820, 99820, 99800,
        99820, 99820};

    for (j = 0; j < sizeof(size)/sizeof(int); j++)
        {
            for (i = 0; i < N; i++)
                {
                    cpl_malloc(16);
                }

            cpl_malloc(size[j]);
            cpl_malloc(size[j]);
        }

    void *p1 = cpl_malloc(16);
    void *p2 = malloc(16);
    
    realloc_cpl   (p1);
    realloc_system(p2);

    const char *p = NULL;
    printf("%c", *p);

    return;

    int M = sizeof(size)/sizeof(int);

#if 0
    for (j = 0; j < M; j++)
        {
            unsigned long alloc = 0;
            void *p;
            for (i = 0; i < N; i++)
                {
                    p = cpl_malloc(16);
                    alloc += 16;                    
                    
                    fprintf(stderr, "%x, %d, %d  alloc=%d\n", p, p, PTR_HASH(p), alloc);
                }

            fprintf(stderr, "-----------------------%d\n", j);

            for (i = 0; i < 2; i++)
                {
                    p = cpl_malloc(size[j]);
                    alloc += size[j];
                    fprintf(stderr, "%d %x, %d, %d  alloc=%d\n", size, p, p, PTR_HASH(p), alloc);
                }
            fprintf(stderr, "-----------------------\n");
        }
#endif
}
#endif

/*----------------------------------------------------------------------------*/
/**
  @brief   Various tests of low-level library functions

  Currently, only 2d gaussian fitting (@c uves_fit_gaussian_2d which calls
  @c uves_fit_gaussian_1d_image which
  calls @c irplib_fit_gaussian_1d which calls Levenberg-Marquardt routine) is 
  tested.
**/
/*----------------------------------------------------------------------------*/

int main(void)
{
    /* Initialize CPL + UVES messaging */
    cpl_test_init(PACKAGE_BUGREPORT, CPL_MSG_WARNING);

    check( uves_check_version(),
           "Dependency libraries version check failed");

    /* test_xmemory(); */

    check( test_gaussian_fitting(),
	   "Test of gaussian fitting failed");

  cleanup:
    return cpl_test_end(0);
}


/**@}*/
