/* $Id: kmo_priv_sky_tweak-test.c,v 1.4 2013-09-13 09:10:28 erw Exp $

 *
 * $Author: erw $
 * $Date: 2013-09-13 09:10:28 $
 * $Revision: 1.4 $
 * $Name: not supported by cvs2svn $
 */

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

#include <cpl.h>
#include <stdio.h>
#include <math.h>
#include "kmo_priv_sky_tweak.h"
#include "kmo_priv_lcorr.h"
#include "kmo_test_create_data.h"
#include "kmclipm_priv_splines.h"
#include "kmclipm_functions.h"

double bessj0(double x)
{
    double ax,z;
    double xx,y,ans,ans1,ans2;

    if ((ax=fabs(x)) < 8.0) {
        y=x*x;
        ans1=57568490574.0+y*(-13362590354.0+y*(651619640.7
                +y*(-11214424.18+y*(77392.33017+y*(-184.9052456)))));
        ans2=57568490411.0+y*(1029532985.0+y*(9494680.718
                +y*(59272.64853+y*(267.8532712+y*1.0))));
        ans=ans1/ans2;
    } else {
        z=8.0/ax;
        y=z*z;
        xx=ax-0.785398164;
        ans1=1.0+y*(-0.1098628627e-2+y*(0.2734510407e-4
                +y*(-0.2073370639e-5+y*0.2093887211e-6)));
        ans2 = -0.1562499995e-1+y*(0.1430488765e-3
                +y*(-0.6911147651e-5+y*(0.7621095161e-6
                        -y*0.934935152e-7)));
        ans=sqrt(0.636619772/ax)*(cos(xx)*ans1-z*sin(xx)*ans2);
    }
    return ans;
}

double func(double x[])
{
    return 0.6-bessj0((x[1]-0.5)*(x[1]-0.5)+
            (x[2]-0.6)*(x[2]-0.6)+
            (x[3]-0.7)*(x[3]-0.7));
}

void test_amoeba() {
#define MP 4
#define NP 3
#define FTOL 1.0e-6

    int i,nfunc,j,ndim=NP;
    double *x,*y,**p;

    x=vector(NP+1);
    y=vector(MP+1);
    p=matrix(MP+1,NP+1);
    for (i=1;i<=MP;i++) {
        for (j=1;j<=NP;j++)
            x[j]=p[i][j]=(i == (j+1) ? 1.0 : 0.0);
        y[i]=func(x);
    }
    amoeba(p,y,ndim,FTOL,func,&nfunc);
/*
    printf("\nNumber of function evaluations: %3d\n",nfunc);
    printf("Vertices of final 3-d simplex and\n");
    printf("function values at the vertices:\n\n");
    printf("%3s %10s %12s %12s %14s\n\n",
            "i","x[i]","y[i]","z[i]","function");
    for (i=1;i<=MP;i++) {
        printf("%3d ",i);
        for (j=1;j<=NP;j++) printf("%12.6f ",p[i][j]);
        printf("%12.6f\n",y[i]);
    }
    printf("\nTrue minimum is at (0.5,0.6,0.7)\n");
*/
    double ftol = 0.00001;
    double pref [MP][NP] = {
            { 0.490676 ,    0.605329 ,    0.717564 },
            { 0.474908 ,    0.597644 ,    0.687566 },
            { 0.530208 ,    0.590894 ,    0.684829 },
            { 0.507350 ,    0.633569 ,    0.698854 } };
    cpl_test_eq(nfunc, 37);
    for (i=1;i<=MP;i++) {
        for (j=1;j<=NP;j++) {
            cpl_test_abs(p[i][j], pref[i-1][j-1], ftol);
        }
        cpl_test_abs(y[i], -0.4, ftol);
    }

    free_matrix(p,MP+1);
    free_vector(y);
    free_vector(x);
}

void test_kmo_get_thermal_background(cpl_bivector *spectrum) {

    cpl_bivector *result = NULL;
    cpl_vector *ref = NULL,
               *th_bkg = NULL;
    const cpl_vector *x_spectrum,
                     *y_spectrum,
                     *x_result,
                     *y_result;
    float ftol = 1e-3;
    char *ref_filename = "ref_data/sky_tweak_bgd_subtr_ref.fits";
    int remove_it;

    x_spectrum = cpl_bivector_get_x_const(spectrum);
    y_spectrum = cpl_bivector_get_y_const(spectrum);
    ref = cpl_vector_load(ref_filename, 0);
    th_bkg = cpl_vector_duplicate(y_spectrum);
    cpl_vector_subtract(th_bkg, ref);

    remove_it = 1;
    result = kmo_get_thermal_background(spectrum, remove_it);

    x_result = cpl_bivector_get_x_const(result);
    y_result = cpl_bivector_get_y_const(result);

    cpl_test_eq(cpl_bivector_get_size(spectrum), cpl_bivector_get_size(result));
    cpl_test_vector_abs(x_spectrum, x_result, ftol);
    cpl_test_vector_abs(ref, y_spectrum, ftol);
    cpl_test_vector_abs(th_bkg, y_result, ftol);

    if (ref != NULL) { cpl_vector_delete(ref); }
    if (th_bkg != NULL) { cpl_vector_delete(th_bkg); }
    if (result != NULL) { cpl_bivector_delete(result); }
}

void test_kmo_priv_sky_tweak_get_spectra (cpl_imagelist *obj, cpl_imagelist *sky,
        cpl_vector *lambda) {

    cpl_error_code error;
    cpl_bivector *obj_spectrum,
                 *sky_spectrum;

    cpl_image *mask = NULL;
    float min_frac = .3;

    mask = kmo_lcorr_create_object_mask(obj, min_frac, NULL, NULL);
    error = kmo_priv_sky_tweak_get_spectra(obj, sky, lambda, mask, 1,
                                            &obj_spectrum, &sky_spectrum);

    cpl_test_eq(error, CPL_ERROR_NONE);
    cpl_image_delete(mask);
    cpl_bivector_delete(obj_spectrum);
    cpl_bivector_delete(sky_spectrum);
}


void test_kmo_priv_sky_tweak_correct_vibrational_trans (cpl_imagelist *obj, cpl_imagelist *sky,
        cpl_vector *lambda) {

    cpl_error_code error;
    cpl_bivector *obj_spectrum,
                 *sky_spectrum,
                 *vscales;

    cpl_image *mask = NULL;
    float min_frac = .3;
//    int line_full_width = 8;

    mask = kmo_lcorr_create_object_mask(obj, min_frac, NULL, NULL);
    error = kmo_priv_sky_tweak_get_spectra(obj, sky, lambda, mask, 1,
                                            &obj_spectrum, &sky_spectrum);
    cpl_test_eq(error, CPL_ERROR_NONE);

    vscales = kmo_priv_sky_tweak_correct_vibrational_trans (
                        obj_spectrum, sky_spectrum/*, line_full_width*/);

    cpl_image_delete(mask);
    cpl_bivector_delete(obj_spectrum);
    cpl_bivector_delete(sky_spectrum);
    cpl_bivector_delete(vscales);
}

void test_kmo_priv_sky_tweak(cpl_imagelist *object, cpl_imagelist *sky, cpl_propertylist *header) {

    cpl_imagelist *result = NULL;
    float min_frac = .3;
    int tbsub = 1;

    result = kmo_priv_sky_tweak(object, sky, header, min_frac, tbsub);

    if (result != NULL) { cpl_imagelist_delete(result); }
}

/**
    @brief   Test of helper functions for kmo_reconstruct
 */
int main(){

    cpl_imagelist  *obj_cube = NULL,
                   *sky_cube = NULL;
    cpl_bivector *obj_spectrum = NULL;
    cpl_propertylist *obj_header = NULL;
    cpl_vector *lambda = NULL;
    int ix;

    cpl_test_init("kmos-spark@mpe.mpg.de", CPL_MSG_WARNING);
    kmo_test_verbose_off();

    obj_header = cpl_propertylist_load("ref_data/lcorr_obj_cube.fits",0);
    obj_cube = cpl_imagelist_load("ref_data/lcorr_obj_cube.fits", CPL_TYPE_FLOAT, 0);
    obj_spectrum = kmo_lcorr_extract_spectrum(obj_cube, obj_header, 0.8, NULL);
    cpl_imagelist_delete(obj_cube);
    cpl_propertylist_delete(obj_header);

    test_amoeba();
    test_kmo_get_thermal_background(obj_spectrum);

    obj_cube = cpl_imagelist_load("ref_data/sky_tweak_obj_cube.fits", CPL_TYPE_FLOAT, 0);
    sky_cube = cpl_imagelist_load("ref_data/sky_tweak_sky_cube.fits", CPL_TYPE_FLOAT, 0);
    obj_header = cpl_propertylist_load("ref_data/sky_tweak_obj_cube.fits",0);

    for (ix=0; ix<cpl_imagelist_get_size(obj_cube); ix++) {
        kmclipm_reject_nan(cpl_imagelist_get(obj_cube, ix));
    }
    for (ix=0; ix<cpl_imagelist_get_size(sky_cube); ix++) {
        kmclipm_reject_nan(cpl_imagelist_get(sky_cube, ix));
    }
    lambda = kmo_lcorr_create_lambda_vector(obj_header);
    test_kmo_priv_sky_tweak_get_spectra(obj_cube, sky_cube, lambda);
    test_kmo_priv_sky_tweak_correct_vibrational_trans(obj_cube, sky_cube, lambda);
    test_kmo_priv_sky_tweak(obj_cube, sky_cube, obj_header);



    cpl_bivector_delete(obj_spectrum);
    cpl_propertylist_delete(obj_header);
    cpl_imagelist_delete(obj_cube);
    cpl_imagelist_delete(sky_cube);
    cpl_vector_delete(lambda);

//    printf("Testing sky_tweak done\n");
    return cpl_test_end(0);
}
