/* $Id: kmo_combine-test.c,v 1.9 2013-10-08 11:18:56 aagudo Exp $
 *
 * This file is part of the KMOS Library
 * Copyright (C) 2002-2006 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, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 */

/*
 * $Author: aagudo $
 * $Date: 2013-10-08 11:18:56 $
 * $Revision: 1.9 $
 * $Name: not supported by cvs2svn $
 */

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

#include <string.h>

#include <cpl.h>
#include "kmclipm_constants.h"
#include "kmclipm_math.h"
#include "kmclipm_functions.h"

#include "kmo_dfs.h"
#include "kmo_test_create_data.h"


const char      *path_recipe        = "kmo_combine/";

const char      *valid_files[]      = {"pyramid_orig.fits",
                                       "pyramid_shift.fits",
                                       "pyramid_shift2.fits",
                                       "pyramid_shift_small.fits",
                                       "gauss_orig.fits",
                                       "gauss_shift.fits",
                                       "pyramid_orig_noise.fits",
                                       "pyramid_shift_noise.fits",
                                       "gauss_shift_sub.fits",
                                       "pyramid_shift3.fits"
                                       };

/**
    @defgroup kmo_combine   kmo_combine unit tests

    @{
*/

/**
    @brief test with data and mask
*/
static void test_combine(const char *sof_path,
                         const char *pars,
                         int ret_val)
{
    // create esorex-command
    char esorex_command[256];
    sprintf(esorex_command,
            "esorex --suppress-prefix=TRUE kmo_combine %s %s",
            pars, sof_path);

    kmo_get_pipe_command(esorex_command,
                         "log_kmo_combine.txt", sof_path, TRUE);

    // execute esorex-command
    if (ret_val == 0) {
        cpl_test_eq(0, system(esorex_command));
    } else {
        cpl_test_noneq(0, system(esorex_command));
    }
}

/**
    @brief
        Generates test data for kmo_combine.

    @param path Path where the generated test date should be saved to.
*/
static int kmo_generate_test_data_combine(const char *path)
{
    int         i                   = 0,
                shift_size          = 0;

    double      sigma               = 0.0;
    char        file_path[256],
                file_path_noise[256],
                file_path_far[256],
                file_ref[256],
                name1[256],
                name2[256],
                cmd[256];

    kmo_test_cat_strings(file_ref, test_global_path_ref_data, "ref_cube_arc.fits");

    cpl_imagelist       *cube_in = kmclipm_imagelist_load(file_ref,
                                                      CPL_TYPE_FLOAT, 1),
                        *cube_out = NULL;
    cpl_propertylist    *pl;
    cpl_image           *img;
    int                 ix = 0,
                        iy = 0;
    double              x_shift,
                        y_shift;
    float               *p = NULL;

    strcpy(name1, IFU_NAME_PREFIX);
    strcat(name1, "1");
    strcat(name1, IFU_NAME_POSTFIX);

    strcpy(name2, IFU_NAME_PREFIX);
    strcat(name2, "2");
    strcat(name2, IFU_NAME_POSTFIX);

    /* ----- valid test data ----- */
    //
    // create pyramid_orig.fits (center at (5,3), object in IFU1)
    //
    kmo_test_cat_strings(file_path, path, valid_files[0]);
    pl = kmclipm_propertylist_load(file_ref, 0);
    cpl_propertylist_save(pl, file_path, CPL_IO_DEFAULT);
    cpl_propertylist_delete(pl); pl = NULL;

    float o14[14] = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9};
    float o13[14] = {10,10,10,10,10,10,10,10,10,10,10,10,10,10};
    float o12[14] = {11,11,11,11,11,11,11,11,11,11,11,11,11,11};
    float o11[14] = {12,12,12,12,12,12,12,12,12,12,12,12,12,11};
    float o10[14] = {13,13,13,13,13,13,13,13,13,13,13,13,12,11};
    float  o9[14] = {14,14,14,14,14,14,14,14,14,14,14,13,12,11};
    float  o8[14] = {15,15,15,15,15,15,15,15,15,15,14,13,12,11};
    float  o7[14] = {16,16,16,16,16,16,16,16,16,15,14,13,12,11};
    float  o6[14] = {16,17,17,17,17,17,17,17,16,15,14,13,12,11};
    float  o5[14] = {16,17,18,18,18,18,18,17,16,15,14,13,12,11};
    float  o4[14] = {16,17,18,19,19,19,18,17,16,15,14,13,12,11};
    float  o3[14] = {16,17,18,19,20,19,18,17,16,15,14,13,12,11};
    float  o2[14] = {16,17,18,19,19,19,18,17,16,15,14,13,12,11};
    float  o1[14] = {16,17,18,18,18,18,18,17,16,15,14,13,12,11};

    cube_out = cpl_imagelist_new();
    for (i = 0; i < cpl_imagelist_get_size(cube_in); i++) {
        img = cpl_image_new(14, 14, CPL_TYPE_FLOAT);
        p = cpl_image_get_data_float(img);
        iy =  0; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = o1[ix];
        iy =  1; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = o2[ix];
        iy =  2; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = o3[ix];
        iy =  3; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = o4[ix];
        iy =  4; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = o5[ix];
        iy =  5; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = o6[ix];
        iy =  6; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = o7[ix];
        iy =  7; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = o8[ix];
        iy =  8; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = o9[ix];
        iy =  9; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = o10[ix];
        iy = 10; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = o11[ix];
        iy = 11; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = o12[ix];
        iy = 12; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = o13[ix];
        iy = 13; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = o14[ix];
        cpl_imagelist_set(cube_out, img, i);
    }

    pl = kmclipm_propertylist_load(file_ref, 1);
    cpl_propertylist_update_string(pl, name1, "XXX");
    cpl_propertylist_erase (pl, name2);
    cpl_imagelist_save(cube_out, file_path, CPL_BPP_IEEE_FLOAT, pl, CPL_IO_EXTEND);
    cpl_imagelist_delete(cube_out); cube_out = NULL;

    // adding noise toy pyramid_orig(_noise).fits
    kmo_test_cat_strings(file_path_noise, path, valid_files[6]);
    strcpy(cmd, "cp ");
    strcat(cmd, file_path);
    strcat(cmd, " ");
    strcat(cmd, file_path_noise);
    system(cmd);

    float n14[14] = { .9, .9, .9, .9, .9, .9, .9, .9, .9, .9, .9, .9, .9, .9};
    float n13[14] = {1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0};
    float n12[14] = {1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1};
    float n11[14] = {1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.1};
    float n10[14] = {1.3,1.3,1.3,1.3,1.3,1.3,1.3,1.3,1.3,1.3,1.3,1.3,1.2,1.1};
    float  n9[14] = {1.4,1.4,1.4,1.4,1.4,1.4,1.4,1.4,1.4,1.4,1.4,1.3,1.2,1.1};
    float  n8[14] = {1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.4,1.3,1.2,1.1};
    float  n7[14] = {1.6,1.6,1.6,1.6,1.6,1.6,1.6,1.6,1.6,1.5,1.4,1.3,1.2,1.1};
    float  n6[14] = {1.6,1.7,1.7,1.7,1.7,1.7,1.7,1.7,1.6,1.5,1.4,1.3,1.2,1.1};
    float  n5[14] = {1.6,1.7,1.8,1.8,1.8,1.8,1.8,1.7,1.6,1.5,1.4,1.3,1.2,1.1};
    float  n4[14] = {1.6,1.7,1.8,1.9,1.9,1.9,1.8,1.7,1.6,1.5,1.4,1.3,1.2,1.1};
    float  n3[14] = {1.6,1.7,1.8,1.9,2.0,1.9,1.8,1.7,1.6,1.5,1.4,1.3,1.2,1.1};
    float  n2[14] = {1.6,1.7,1.8,1.9,1.9,1.9,1.8,1.7,1.6,1.5,1.4,1.3,1.2,1.1};
    float  n1[14] = {1.6,1.7,1.8,1.8,1.8,1.8,1.8,1.7,1.6,1.5,1.4,1.3,1.2,1.1};

    cube_out = cpl_imagelist_new();
    for (i = 0; i < cpl_imagelist_get_size(cube_in); i++) {
        img = cpl_image_new(14, 14, CPL_TYPE_FLOAT);
        p = cpl_image_get_data_float(img);
        iy =  0; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = n1[ix];
        iy =  1; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = n2[ix];
        iy =  2; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = n3[ix];
        iy =  3; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = n4[ix];
        iy =  4; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = n5[ix];
        iy =  5; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = n6[ix];
        iy =  6; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = n7[ix];
        iy =  7; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = n8[ix];
        iy =  8; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = n9[ix];
        iy =  9; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = n10[ix];
        iy = 10; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = n11[ix];
        iy = 11; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = n12[ix];
        iy = 12; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = n13[ix];
        iy = 13; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = n14[ix];
        cpl_imagelist_set(cube_out, img, i);
    }

    kmclipm_update_property_string(pl, EXTNAME, "IFU.1.NOISE",
                                   "FITS extension name");
    cpl_imagelist_save(cube_out, file_path_noise, CPL_BPP_IEEE_FLOAT, pl,
                       CPL_IO_EXTEND);
    cpl_imagelist_delete(cube_out); cube_out = NULL;

    cpl_propertylist_delete(pl); pl = NULL;

    //
    // create pyramid_shift.fits (center at (8,4), object in IFU2)
    //
    kmo_test_cat_strings(file_path, path, valid_files[1]);
    kmo_test_cat_strings(file_path_noise, path, valid_files[7]);
    x_shift = 3;
    y_shift = 1;

    pl = kmclipm_propertylist_load(file_ref, 0);
    cpl_propertylist_save(pl, file_path, CPL_IO_DEFAULT);
    cpl_propertylist_save(pl, file_path_noise, CPL_IO_DEFAULT);
    cpl_propertylist_delete(pl); pl = NULL;

    float s14[14] = {10,10,10,10,10,10,10,10,10,10,10,10,10,10};
    float s13[14] = {11,11,11,11,11,11,11,11,11,11,11,11,11,11};
    float s12[14] = {12,12,12,12,12,12,12,12,12,12,12,12,12,12};
    float s11[14] = {13,13,13,13,13,13,13,13,13,13,13,13,13,13};
    float s10[14] = {13,14,14,14,14,14,14,14,14,14,14,14,14,14};
    float  s9[14] = {13,14,15,15,15,15,15,15,15,15,15,15,15,14};
    float  s8[14] = {13,14,15,16,16,16,16,16,16,16,16,16,15,14};
    float  s7[14] = {13,14,15,16,17,17,17,17,17,17,17,16,15,14};
    float  s6[14] = {13,14,15,16,17,18,18,18,18,18,17,16,15,14};
    float  s5[14] = {13,14,15,16,17,18,19,19,19,18,17,16,15,14};
    float  s4[14] = {13,14,15,16,17,18,19,0./0.,19,18,17,16,15,14};
    float  s3[14] = {13,14,15,16,17,18,19,19,19,18,17,16,15,14};
    float  s2[14] = {13,14,15,16,17,18,18,18,18,18,17,16,15,14};
    float  s1[14] = {13,14,15,16,17,17,17,17,17,17,17,16,15,14};

    cube_out = cpl_imagelist_new();
    shift_size = 14;
    for (i = 0; i < cpl_imagelist_get_size(cube_in); i++) {
        img = cpl_image_new(shift_size, shift_size, CPL_TYPE_FLOAT);
        p = cpl_image_get_data_float(img);
        iy =  0; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s1[ix];
        iy =  1; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s2[ix];
        iy =  2; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s3[ix];
        iy =  3; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s4[ix];
        iy =  4; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s5[ix];
        iy =  5; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s6[ix];
        iy =  6; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s7[ix];
        iy =  7; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s8[ix];
        iy =  8; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s9[ix];
        iy =  9; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s10[ix];
        iy = 10; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s11[ix];
        iy = 11; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s12[ix];
        iy = 12; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s13[ix];
        iy = 13; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s14[ix];
        cpl_imagelist_set(cube_out, img, i);
    }

    // save empty 1st ext shift (data)
    pl = kmclipm_propertylist_load(file_ref, 2);
    cpl_propertylist_update_string(pl, "EXTNAME", "IFU.1.DATA");
    cpl_propertylist_update_string(pl, name1, "YYY");
    cpl_propertylist_erase (pl, name2);
    cpl_propertylist_save(pl, file_path, CPL_IO_EXTEND);
    cpl_propertylist_save(pl, file_path_noise, CPL_IO_EXTEND);

    // save empty 1st ext shift (noise)
    cpl_propertylist_update_string(pl, "EXTNAME", "IFU.1.NOISE");
    cpl_propertylist_save(pl, file_path_noise, CPL_IO_EXTEND);

    cpl_propertylist_delete(pl); pl = NULL;

    // save 2nd ext shift (data)
    pl = kmclipm_propertylist_load(file_ref, 1);
    cpl_propertylist_update_string(pl, name2, "XXX");
    cpl_propertylist_erase (pl, name1);
    cpl_propertylist_update_string(pl, EXTNAME, "IFU.2.DATA");
    cpl_propertylist_update_double(pl, CRPIX1,
                                   cpl_propertylist_get_double(pl, CRPIX1)+x_shift);
    cpl_propertylist_update_double(pl, CRPIX2,
                                   cpl_propertylist_get_double(pl, CRPIX2)+y_shift);
    cpl_imagelist_save(cube_out, file_path, CPL_BPP_IEEE_FLOAT, pl, CPL_IO_EXTEND);
    cpl_imagelist_save(cube_out, file_path_noise, CPL_BPP_IEEE_FLOAT, pl, CPL_IO_EXTEND);
    cpl_imagelist_delete(cube_out); cube_out = NULL;

    // save 2nd ext shift (noise)
    float sn14[14] = {1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0};
    float sn13[14] = {1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1};
    float sn12[14] = {1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2};
    float sn11[14] = {1.3,1.3,1.3,1.3,1.3,1.3,1.3,1.3,1.3,1.3,1.3,1.3,1.3,1.3};
    float sn10[14] = {1.3,1.4,1.4,1.4,1.4,1.4,1.4,1.4,1.4,1.4,1.4,1.4,1.4,1.4};
    float  sn9[14] = {1.3,1.4,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.4};
    float  sn8[14] = {1.3,1.4,1.5,1.6,1.6,1.6,1.6,1.6,1.6,1.6,1.6,1.6,1.5,1.4};
    float  sn7[14] = {1.3,1.4,1.5,1.6,1.7,1.7,1.7,1.7,1.7,1.7,1.7,1.6,1.5,1.4};
    float  sn6[14] = {1.3,1.4,1.5,1.6,1.7,1.8,1.8,1.8,1.8,1.8,1.7,1.6,1.5,1.4};
    float  sn5[14] = {1.3,1.4,1.5,1.6,1.7,1.8,1.9,1.9,1.9,1.8,1.7,1.6,1.5,1.4};
    float  sn4[14] = {1.3,1.4,1.5,1.6,1.7,1.8,1.9,2.0,1.9,1.8,1.7,1.6,1.5,1.4};
    float  sn3[14] = {1.3,1.4,1.5,1.6,0./0.,1.8,1.9,1.9,1.9,1.8,1.7,1.6,1.5,1.4};
    float  sn2[14] = {1.3,1.4,1.5,1.6,1.7,1.8,1.8,1.8,1.8,1.8,1.7,1.6,1.5,1.4};
    float  sn1[14] = {1.3,1.4,1.5,1.6,1.7,1.7,1.7,1.7,1.7,1.7,1.7,1.6,1.5,1.4};

    cube_out = cpl_imagelist_new();
    for (i = 0; i < cpl_imagelist_get_size(cube_in); i++) {
        img = cpl_image_new(14, 14, CPL_TYPE_FLOAT);
        p = cpl_image_get_data_float(img);
        iy =  0; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = sn1[ix];
        iy =  1; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = sn2[ix];
        iy =  2; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = sn3[ix];
        iy =  3; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = sn4[ix];
        iy =  4; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = sn5[ix];
        iy =  5; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = sn6[ix];
        iy =  6; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = sn7[ix];
        iy =  7; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = sn8[ix];
        iy =  8; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = sn9[ix];
        iy =  9; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = sn10[ix];
        iy = 10; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = sn11[ix];
        iy = 11; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = sn12[ix];
        iy = 12; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = sn13[ix];
        iy = 13; for (ix = 0; ix < 14; ix++) p[ix+iy*14] = sn14[ix];
        cpl_imagelist_set(cube_out, img, i);
    }

    cpl_propertylist_update_string(pl, EXTNAME, "IFU.2.NOISE");
    cpl_imagelist_save(cube_out, file_path_noise, CPL_BPP_IEEE_FLOAT, pl,
                       CPL_IO_EXTEND);
    cpl_imagelist_delete(cube_out); cube_out = NULL;

    cpl_propertylist_delete(pl); pl = NULL;

    //
    // create pyramid_shift2.fits (center at (4,11), object in IFU2)
    //
    kmo_test_cat_strings(file_path, path, valid_files[2]);
    kmo_test_cat_strings(file_path_far, path, valid_files[9]);
    x_shift = -1;
    y_shift = 8;

    pl = kmclipm_propertylist_load(file_ref, 0);
    cpl_propertylist_save(pl, file_path, CPL_IO_DEFAULT);
    cpl_propertylist_save(pl, file_path_far, CPL_IO_DEFAULT);
    cpl_propertylist_delete(pl); pl = NULL;

    float s14_2[14] = {17,17,17,17,17,17,17,16,15,14,13,12,11,10};
    float s13_2[14] = {17,18,18,18,18,18,17,16,15,14,13,12,11,10};
    float s12_2[14] = {17,18,19,19,19,18,17,16,15,14,13,12,11,10};
    float s11_2[14] = {17,18,19,20,19,18,17,16,15,14,13,12,11,10};
    float s10_2[14] = {17,18,19,19,19,18,17,16,15,14,13,12,11,10};
    float  s9_2[14] = {17,18,18,18,18,18,17,16,15,14,13,12,11,10};
    float  s8_2[14] = {17,17,17,17,17,17,17,16,15,14,13,12,11,10};
    float  s7_2[14] = {16,16,16,16,16,16,16,16,15,14,13,12,11,10};
    float  s6_2[14] = {15,15,15,15,15,15,15,15,15,14,13,12,11,10};
    float  s5_2[14] = {14,14,14,14,14,14,14,14,14,14,13,12,11,10};
    float  s4_2[14] = {13,13,13,13,13,13,13,13,13,13,13,12,11,10};
    float  s3_2[14] = {12,12,12,12,12,12,12,12,12,12,12,12,11,10};
    float  s2_2[14] = {11,11,11,11,11,11,11,11,11,11,11,11,11,10};
    float  s1_2[14] = {10,10,10,10,10,10,10,10,10,10,10,10,10,10};


    cube_out = cpl_imagelist_new();
    shift_size = 14;
    for (i = 0; i < cpl_imagelist_get_size(cube_in); i++) {
        img = cpl_image_new(shift_size, shift_size, CPL_TYPE_FLOAT);
        p = cpl_image_get_data_float(img);
        iy =  0; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s1_2[ix];
        iy =  1; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s2_2[ix];
        iy =  2; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s3_2[ix];
        iy =  3; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s4_2[ix];
        iy =  4; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s5_2[ix];
        iy =  5; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s6_2[ix];
        iy =  6; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s7_2[ix];
        iy =  7; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s8_2[ix];
        iy =  8; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s9_2[ix];
        iy =  9; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s10_2[ix];
        iy = 10; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s11_2[ix];
        iy = 11; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s12_2[ix];
        iy = 12; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s13_2[ix];
        iy = 13; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s14_2[ix];
        cpl_imagelist_set(cube_out, img, i);
    }

    // save empty 1st ext shift
    pl = kmclipm_propertylist_load(file_ref, 2);
    cpl_propertylist_update_string(pl, "EXTNAME", "IFU.1.DATA");
    cpl_propertylist_update_string(pl, name1, "YYY");
    cpl_propertylist_erase (pl, name2);
    cpl_propertylist_save(pl, file_path, CPL_IO_EXTEND);
    cpl_propertylist_save(pl, file_path_far, CPL_IO_EXTEND);
    cpl_propertylist_delete(pl); pl = NULL;

    // save 2nd ext shift
    pl = kmclipm_propertylist_load(file_ref, 1);
    cpl_propertylist_update_string(pl, "EXTNAME", "IFU.2.DATA");
    cpl_propertylist_update_string(pl, name2, "XXX");
    cpl_propertylist_erase (pl, name1);
    cpl_propertylist_update_double(pl, CRPIX1,
                                   cpl_propertylist_get_double(pl, CRPIX1)+x_shift);
    cpl_propertylist_update_double(pl, CRPIX2,
                                   cpl_propertylist_get_double(pl, CRPIX2)+y_shift);
    cpl_imagelist_save(cube_out, file_path, CPL_BPP_IEEE_FLOAT, pl, CPL_IO_EXTEND);
    cpl_propertylist_update_double(pl, CRPIX1,
                                   cpl_propertylist_get_double(pl, CRPIX1)+x_shift-5);
    cpl_propertylist_update_double(pl, CRPIX2,
                                   cpl_propertylist_get_double(pl, CRPIX2)+y_shift+5);
    cpl_imagelist_save(cube_out, file_path_far, CPL_BPP_IEEE_FLOAT, pl, CPL_IO_EXTEND);
    cpl_imagelist_delete(cube_out); cube_out = NULL;
    cpl_propertylist_delete(pl); pl = NULL;

    //
    // create pyramid_shift_small.fits (center at (8,2), object in IFU2)
    //
    kmo_test_cat_strings(file_path, path, valid_files[3]);
    x_shift = 3;
    y_shift = -1;

    pl = kmclipm_propertylist_load(file_ref, 0);
    cpl_propertylist_save(pl, file_path, CPL_IO_DEFAULT);
    cpl_propertylist_delete(pl); pl = NULL;

    float s12s[12] = {10,10,10,10,10,10,10,10,10,10,10,10};
    float s11s[12] = {11,11,11,11,11,11,11,11,11,11,11,11};
    float s10s[12] = {12,12,12,12,12,12,12,12,12,12,12,12};
    float  s9s[12] = {13,13,13,13,13,13,13,13,13,13,13,13};
    float  s8s[12] = {13,14,14,14,14,14,14,14,14,14,14,14};
    float  s7s[12] = {13,14,15,15,15,15,15,15,15,15,15,15};
    float  s6s[12] = {13,14,15,16,16,16,16,16,16,16,16,16};
    float  s5s[12] = {13,14,15,16,17,17,17,17,17,17,17,16};
    float  s4s[12] = {13,14,15,16,17,18,18,18,18,18,17,16};
    float  s3s[12] = {13,14,15,16,17,18,19,19,19,18,17,16};
    float  s2s[12] = {13,14,15,16,17,18,19,20,19,18,17,16};
    float  s1s[12] = {13,14,15,16,17,18,19,19,19,18,17,16};

    cube_out = cpl_imagelist_new();
    shift_size = 12;
    for (i = 0; i < cpl_imagelist_get_size(cube_in); i++) {
        img = cpl_image_new(shift_size, shift_size, CPL_TYPE_FLOAT);
        p = cpl_image_get_data_float(img);
        iy =  0; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s1s[ix];
        iy =  1; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s2s[ix];
        iy =  2; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s3s[ix];
        iy =  3; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s4s[ix];
        iy =  4; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s5s[ix];
        iy =  5; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s6s[ix];
        iy =  6; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s7s[ix];
        iy =  7; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s8s[ix];
        iy =  8; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s9s[ix];
        iy =  9; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s10s[ix];
        iy = 10; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s11s[ix];
        iy = 11; for (ix = 0; ix < shift_size; ix++) p[ix+iy*shift_size] = s12s[ix];
        cpl_imagelist_set(cube_out, img, i);
    }

    // save empty 1st ext shift
    pl = kmclipm_propertylist_load(file_ref, 2);
    cpl_propertylist_update_string(pl, "EXTNAME", "IFU.1.DATA");
    cpl_propertylist_update_string(pl, name1, "YYY");
    cpl_propertylist_erase (pl, name2);
    cpl_propertylist_save(pl, file_path, CPL_IO_EXTEND);
    cpl_propertylist_delete(pl); pl = NULL;

    // save 2nd ext shift
    pl = kmclipm_propertylist_load(file_ref, 1);
    cpl_propertylist_update_string(pl, "EXTNAME", "IFU.2.DATA");
    cpl_propertylist_update_string(pl, name2, "XXX");
    cpl_propertylist_erase (pl, name1);
    cpl_propertylist_update_double(pl, CRPIX1,
                             cpl_propertylist_get_double(pl, CRPIX1)+x_shift);
    cpl_propertylist_update_double(pl, CRPIX2,
                             cpl_propertylist_get_double(pl, CRPIX2)+y_shift);
    cpl_imagelist_save(cube_out, file_path, CPL_BPP_IEEE_FLOAT, pl, CPL_IO_EXTEND);
    cpl_imagelist_delete(cube_out); cube_out = NULL;
    cpl_propertylist_delete(pl); pl = NULL;

    //
    // create gauss_orig.fits (center at (5,3), object in IFU1)
    //

    // load & save primary
    pl = kmclipm_propertylist_load(file_ref, 0);
    kmo_test_cat_strings(file_path, path, valid_files[4]);
    cpl_propertylist_save(pl, file_path, CPL_IO_DEFAULT);
    cpl_propertylist_delete(pl); pl = NULL;

    cube_out = cpl_imagelist_new();
    sigma = 2.0;
    for (i = 0; i < cpl_imagelist_get_size(cube_in); i++) {
        img = cpl_image_new(14, 14, CPL_TYPE_FLOAT);
        cpl_image_fill_gaussian(img, 5, 3,
                                CPL_MATH_2PI*sigma*sigma, sigma, sigma);
        cpl_imagelist_set(cube_out, img, i);
    }

    // save 1st orig
    pl = kmclipm_propertylist_load(file_ref, 1);
    cpl_propertylist_update_string(pl, name1, "XXX");
    cpl_propertylist_erase (pl, name2);
    cpl_imagelist_save(cube_out, file_path, CPL_BPP_IEEE_FLOAT, pl, CPL_IO_EXTEND);
    cpl_imagelist_delete(cube_out); cube_out = NULL;
    cpl_propertylist_delete(pl); pl = NULL;

    //
    // create gauss_shift.fits (center at (10,6), object in IFU2)
    //
    x_shift = 5;
    y_shift = 3;

    // load & save primary
    pl = kmclipm_propertylist_load(file_ref, 0);
    kmo_test_cat_strings(file_path, path, valid_files[5]);
    cpl_propertylist_save(pl, file_path, CPL_IO_DEFAULT);
    cpl_propertylist_delete(pl); pl = NULL;

    cube_out = cpl_imagelist_new();
    sigma = 2.0;
    for (i = 0; i < cpl_imagelist_get_size(cube_in); i++) {
        img = cpl_image_new(14, 14, CPL_TYPE_FLOAT);

        cpl_image_fill_gaussian(img, 5+x_shift, 3+y_shift,
                                CPL_MATH_2PI*sigma*sigma, sigma, sigma);
        cpl_imagelist_set(cube_out, img, i);
    }

    // save 1st ext shift
    pl = kmclipm_propertylist_load(file_ref, 2);
    cpl_propertylist_update_string(pl, "EXTNAME", "IFU.1.DATA");
    cpl_propertylist_update_string(pl, name1, "YYY");
    cpl_propertylist_erase (pl, name2);
    cpl_propertylist_save(pl, file_path, CPL_IO_EXTEND);
    cpl_propertylist_delete(pl); pl = NULL;

    // save 2nd ext shift
    pl = kmclipm_propertylist_load(file_ref, 1);
    cpl_propertylist_update_string(pl, "EXTNAME", "IFU.2.DATA");
    cpl_propertylist_update_string(pl, name2, "XXX");
    cpl_propertylist_erase (pl, name1);
    cpl_propertylist_update_double(pl, CRPIX1, cpl_propertylist_get_double(pl, CRPIX1)+x_shift);
    cpl_propertylist_update_double(pl, CRPIX2, cpl_propertylist_get_double(pl, CRPIX2)+y_shift);
    cpl_imagelist_save(cube_out, file_path, CPL_BPP_IEEE_FLOAT, pl, CPL_IO_EXTEND);
    cpl_imagelist_delete(cube_out); cube_out = NULL;
    cpl_propertylist_delete(pl); pl = NULL;

    //
    // create gauss_shift_sub.fits (center at (10.2,6.1), object in IFU2)
    //
    x_shift = 5.2;
    y_shift = 3.1;

    // load & save primary
    pl = kmclipm_propertylist_load(file_ref, 0);
    kmo_test_cat_strings(file_path, path, valid_files[8]);
    cpl_propertylist_save(pl, file_path, CPL_IO_DEFAULT);
    cpl_propertylist_delete(pl); pl = NULL;

    cube_out = cpl_imagelist_new();
    sigma = 2.0;
    for (i = 0; i < cpl_imagelist_get_size(cube_in); i++) {
        img = cpl_image_new(14, 14, CPL_TYPE_FLOAT);

        cpl_image_fill_gaussian(img, 5+x_shift, 3+y_shift,
                                CPL_MATH_2PI*sigma*sigma, sigma, sigma);
        cpl_imagelist_set(cube_out, img, i);
    }

    // save 1st ext shift
    pl = kmclipm_propertylist_load(file_ref, 2);
    cpl_propertylist_update_string(pl, "EXTNAME", "IFU.1.DATA");
    cpl_propertylist_update_string(pl, name1, "YYY");
    cpl_propertylist_erase (pl, name2);
    cpl_propertylist_save(pl, file_path, CPL_IO_EXTEND);
    cpl_propertylist_delete(pl); pl = NULL;

    // save 2nd ext shift
    pl = kmclipm_propertylist_load(file_ref, 1);
    cpl_propertylist_update_string(pl, "EXTNAME", "IFU.2.DATA");
    cpl_propertylist_update_string(pl, name2, "XXX");
    cpl_propertylist_erase (pl, name1);
    cpl_propertylist_update_double(pl, CRPIX1, cpl_propertylist_get_double(pl, CRPIX1)+x_shift);
    cpl_propertylist_update_double(pl, CRPIX2, cpl_propertylist_get_double(pl, CRPIX2)+y_shift);
    cpl_imagelist_save(cube_out, file_path, CPL_BPP_IEEE_FLOAT, pl, CPL_IO_EXTEND);
    cpl_imagelist_delete(cube_out); cube_out = NULL;
    cpl_propertylist_delete(pl); pl = NULL;

    cpl_imagelist_delete(cube_in); cube_in = NULL;

    return 0;
}

/**
  @brief    Test of kmo_combine recipe.
  @param    argc   the number of parameters
  @param    argv   the parameter list

  Call @c kmo_combine-test @c --generate when only the test data for this
  recipe should be generated.
  Call @c kmo_combine-test @c --no-gen when only the tests should be
  executed and no data should be generated.

 */
int main(int argc, char *argv[])
{
    float               tol         = 0.01;

    int                 tmp_int;

    cpl_image           *img        = NULL;

    cpl_propertylist    *h          = NULL;

    char                test_path[256],
                        file_path[256],
                        out_path[256];

    FILE *fh;

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

    /* ----- check if test data exists ----- */
    if (kmo_test_file_exists(test_global_path_test_data) == FALSE) {
        mkdir(test_global_path_test_data, 0777);

        kmo_test_create_pipeline_data();
    }

    strcpy(test_path, test_global_path_test_data);
    strcat(test_path, path_recipe);

    if (kmo_test_file_exists(test_path) == FALSE) {
        mkdir(test_path, 0777);
    }

    if ((argc == 1) || ((argc > 1) && (strcmp(argv[1], "--no-gen") != 0))) {
        cpl_test_zero(kmo_generate_test_data_combine(test_path));
    }

    if ((argc > 1) && (strcmp(argv[1], "--generate") == 0)) {
        // just generate the data
        return cpl_test_end(0);
    }

    /* ----- run the tests ----- */
    FILE *fd = fopen("log_kmo_combine.txt", "w");
    fprintf(fd, "%s\n", " ");
    fclose(fd);

    /* ----- valid tests ----- */
    const char *sof_path = "test_combine.sof",
               *user_path = "vectors.txt";

    //
    // method 'none'
    //

    // combine 2 files: pyramid orig/shift
    fh = fopen(sof_path, "w" );
    kmo_test_cat_strings(file_path, test_path, valid_files[0]);
    fprintf (fh, "%s\n", file_path);
    kmo_test_cat_strings(file_path, test_path, valid_files[1]);
    fprintf (fh, "%s\n", file_path);
    fclose(fh);

    test_combine(sof_path,
                 "--ifus=\"1;2\" --cmethod=\"sum\" --method=\"none\"",
                 0);

    strcpy(out_path, "combine_cube_arc_ifu1;2");
    cpl_test_abs(kmo_test_esorex_data(out_path, 0), 29.3865, tol);

    strcat(out_path, ".fits");
    h = kmclipm_propertylist_load(out_path, 1);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX1), 7.5, tol);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX2), 7.5, tol);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS1), 14);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS2), 14);
    cpl_propertylist_delete(h); h = NULL;

    //
    // method 'header'
    //

    // combine 2 files: pyramid orig/shift
    fh = fopen(sof_path, "w" );
    kmo_test_cat_strings(file_path, test_path, valid_files[0]);
    fprintf (fh, "%s\n", file_path);
    kmo_test_cat_strings(file_path, test_path, valid_files[1]);
    fprintf (fh, "%s\n", file_path);
    fclose(fh);

    test_combine(sof_path,
                 "--ifus=\"1;2\" --cmethod=\"sum\" --method=\"header\"",
                 0);

    strcpy(out_path, "combine_cube_arc_ifu1;2");
    cpl_test_abs(kmo_test_esorex_data(out_path, 0), 22.1888, tol);
    strcat(out_path, ".fits");
    h = kmclipm_propertylist_load(out_path, 1);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX1), 10.5, tol);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX2), 8.5, tol);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS1), 17);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS2), 15);
    cpl_propertylist_delete(h); h = NULL;

    // combine 2 files with noise: pyramid orig/shift
    fh = fopen(sof_path, "w" );
    kmo_test_cat_strings(file_path, test_path, valid_files[6]);
    fprintf (fh, "%s\n", file_path);
    kmo_test_cat_strings(file_path, test_path, valid_files[7]);
    fprintf (fh, "%s\n", file_path);
    fclose(fh);

    test_combine(sof_path,
                 "--ifus=\"1;2\" --cmethod=\"sum\" --method=\"header\"",
                 0);

    strcpy(out_path, "combine_cube_arc_ifu1;2");
    cpl_test_abs(kmo_test_esorex_data(out_path, 0), 23.6657, tol);
    strcat(out_path, ".fits");
    h = kmclipm_propertylist_load(out_path, 1);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX1), 10.5, tol);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX2), 8.5, tol);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS1), 17);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS2), 15);
    cpl_propertylist_delete(h); h = NULL;

    img = kmclipm_image_load(out_path, CPL_TYPE_FLOAT, 0, 1);
    cpl_test_abs(cpl_image_get(img, 10, 6, &tmp_int), 36, tol);
    cpl_image_delete(img); img = NULL;

    img = kmclipm_image_load(out_path, CPL_TYPE_FLOAT, 0, 2);
    cpl_test_abs(cpl_image_get(img, 10, 6, &tmp_int), 1.8, tol);
    cpl_image_delete(img); img = NULL;

    // combine 2 files: pyramid shift/orig (same result as above)
    fh = fopen(sof_path, "w" );
    kmo_test_cat_strings(file_path, test_path, valid_files[1]);
    fprintf (fh, "%s\n", file_path);
    kmo_test_cat_strings(file_path, test_path, valid_files[0]);
    fprintf (fh, "%s\n", file_path);
    fclose(fh);

    test_combine(sof_path,
                 "--ifus=\"2;1\" --cmethod=\"sum\" --method=\"header\"",
                 0);

    strcpy(out_path, "combine_cube_arc_ifu2;1");
    cpl_test_abs(kmo_test_esorex_data(out_path, 0), 22.1888, tol);
    strcat(out_path, ".fits");
    h = kmclipm_propertylist_load(out_path, 1);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX1), 10.5, tol);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX2), 8.5, tol);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS1), 17);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS2), 15);
    cpl_propertylist_delete(h); h = NULL;

    // combine 3 files: pyramid orig/shift/shift2
    fh = fopen(sof_path, "w" );
    kmo_test_cat_strings(file_path, test_path, valid_files[0]);
    fprintf (fh, "%s\n", file_path);
    kmo_test_cat_strings(file_path, test_path, valid_files[1]);
    fprintf (fh, "%s\n", file_path);
    kmo_test_cat_strings(file_path, test_path, valid_files[2]);
    fprintf (fh, "%s\n", file_path);
    fclose(fh);

    test_combine(sof_path,
                 "--ifus=\"1;2;2\" --cmethod=\"sum\" --method=\"header\"",
                 0);

    strcpy(out_path, "combine_cube_arc_ifu1;2;2");
    cpl_test_abs(kmo_test_esorex_data(out_path, 0), 23.1036, tol);
    strcat(out_path, ".fits");
    h = kmclipm_propertylist_load(out_path, 1);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX1), 10.5, tol);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX2), 15.5, tol);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS1), 18);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS2), 22);
    cpl_propertylist_delete(h); h = NULL;

    // combine 3 files: pyramid orig/shift/shift2
    // combine by name
    fh = fopen(sof_path, "w" );
    kmo_test_cat_strings(file_path, test_path, valid_files[0]);
    fprintf (fh, "%s\n", file_path);
    kmo_test_cat_strings(file_path, test_path, valid_files[1]);
    fprintf (fh, "%s\n", file_path);
    kmo_test_cat_strings(file_path, test_path, valid_files[2]);
    fprintf (fh, "%s\n", file_path);
    fclose(fh);

    test_combine(sof_path,
                 "--name=\"XXX\" --cmethod=\"sum\" --method=\"header\"",
                 0);

    strcpy(out_path, "combine_cube_arc_xxx");
    cpl_test_abs(kmo_test_esorex_data(out_path, 0), 23.1036, tol);
    strcat(out_path, ".fits");
    h = kmclipm_propertylist_load(out_path, 1);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX1), 10.5, tol);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX2), 15.5, tol);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS1), 18);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS2), 22);
    cpl_propertylist_delete(h); h = NULL;

    // combine 2 files: pyramid orig/shift
    // combine by name
    fh = fopen(sof_path, "w" );
    kmo_test_cat_strings(file_path, test_path, valid_files[0]);
    fprintf (fh, "%s\n", file_path);
    kmo_test_cat_strings(file_path, test_path, valid_files[1]);
    fprintf (fh, "%s\n", file_path);
    fclose(fh);

    test_combine(sof_path,
                 "--name=\"YYY\" --cmethod=\"sum\" --method=\"header\"",
                 0);

    // doesn't fail, produces no output

    // combine 2 files: pyramid orig/shift_small
    fh = fopen(sof_path, "w" );
    kmo_test_cat_strings(file_path, test_path, valid_files[0]);
    fprintf (fh, "%s\n", file_path);
    kmo_test_cat_strings(file_path, test_path, valid_files[3]);
    fprintf (fh, "%s\n", file_path);
    fclose(fh);

    test_combine(sof_path,
                 "--ifus=\"1;2\" --cmethod=\"sum\" --method=\"header\"",
                 0);

    strcpy(out_path, "combine_cube_arc_ifu1;2");
    cpl_test_abs(kmo_test_esorex_data(out_path, 0), 21.8627, tol);
    strcat(out_path, ".fits");
    h = kmclipm_propertylist_load(out_path, 1);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX1), 10.5, tol);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX2), 7.5, tol);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS1), 15);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS2), 14);
    cpl_propertylist_delete(h); h = NULL;

    // combine 2 files: pyramids don't overlap
    fh = fopen(sof_path, "w" );
    kmo_test_cat_strings(file_path, test_path, valid_files[1]);
    fprintf (fh, "%s\n", file_path);
    kmo_test_cat_strings(file_path, test_path, valid_files[9]);
    fprintf (fh, "%s\n", file_path);
    fclose(fh);

    test_combine(sof_path,
                 "--ifus=\"2;2\" --cmethod=\"sum\" --method=\"header\"",
                 0);

    strcpy(out_path, "combine_cube_arc_ifu2;2");
    cpl_test_abs(kmo_test_esorex_data(out_path, 0), 14.1633, tol);
    strcat(out_path, ".fits");
    h = kmclipm_propertylist_load(out_path, 1);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX1), 10.5, tol);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX2), 28.5, tol);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS1), 24);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS2), 34);
    cpl_propertylist_delete(h); h = NULL;

    //
    // method 'center'
    //

    // combine 2 files: gauss orig/shift
    fh = fopen(sof_path, "w" );
    kmo_test_cat_strings(file_path, test_path, valid_files[4]);
    fprintf (fh, "%s\n", file_path);
    kmo_test_cat_strings(file_path, test_path, valid_files[5]);
    fprintf (fh, "%s\n", file_path);
    fclose(fh);

    test_combine(sof_path,
                 "--ifus=\"1;2\" --cmethod=\"sum\" --method=\"center\"",
                 0);

    strcpy(out_path, "combine_cube_arc_ifu1;2");
    cpl_test_abs(kmo_test_esorex_data(out_path, 0), 0.160596, tol);
    strcat(out_path, ".fits");
    h = kmclipm_propertylist_load(out_path, 1);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX1), 12.5, tol);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX2), 10.5, tol);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS1), 19);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS2), 17);
    cpl_propertylist_delete(h); h = NULL;

    // combine 2 files (sub-pixel combining): gauss orig/shift
    fh = fopen(sof_path, "w" );
    kmo_test_cat_strings(file_path, test_path, valid_files[4]);
    fprintf (fh, "%s\n", file_path);
    kmo_test_cat_strings(file_path, test_path, valid_files[8]);
    fprintf (fh, "%s\n", file_path);
    fclose(fh);

    test_combine(sof_path,
                 "--ifus=\"1;2\" --cmethod=\"sum\" --method=\"center\"",
                 0);

    strcpy(out_path, "combine_cube_arc_ifu1;2");
    // this test fails because output fits contaions NaN values
//        cpl_test_abs(kmo_test_esorex_data(out_path, 0), 0.0974214, tol);
    strcat(out_path, ".fits");
    h = kmclipm_propertylist_load(out_path, 1);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX1), 12.5, tol);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX2), 10.5, tol);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS1), 18);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS2), 17);
    cpl_propertylist_delete(h); h = NULL;

    //
    // method 'user'
    //

    // combine 2 files: gauss shift/orig
    fh = fopen(sof_path, "w" );
    kmo_test_cat_strings(file_path, test_path, valid_files[5]);
    fprintf (fh, "%s\n", file_path);
    kmo_test_cat_strings(file_path, test_path, valid_files[4]);
    fprintf (fh, "%s\n", file_path);
    fclose(fh);

    fh = fopen(user_path, "w" );
    fprintf (fh, "-5  -3\n");
    fclose(fh);

    test_combine(sof_path,
                 "--ifus=\"2;1\" --cmethod=\"sum\" "
                 "--method=\"user\" --filename=\"vectors.txt\"",
                 0);

    strcpy(out_path, "combine_cube_arc_ifu2;1");
    switch(sizeof(void*)){
        case 4:
        // 32bit system
        cpl_test_abs(kmo_test_esorex_data(out_path, 0), 0.356464, tol*50);
        break;
        case 8:
        // 64bit system
        cpl_test_abs(kmo_test_esorex_data(out_path, 0), 0.356464, tol);
       break;
    }
    strcat(out_path, ".fits");
    h = kmclipm_propertylist_load(out_path, 1);
    switch(sizeof(void*)){
        case 4:
        // 32bit system
        cpl_test_abs(cpl_propertylist_get_double(h, CRPIX1), 17.5, tol);
        break;
        case 8:
        // 64bit system
        cpl_test_abs(cpl_propertylist_get_double(h, CRPIX1), 12.5, tol);
       break;
    }
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX2), 13.5, tol);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS1), 19);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS2), 17);
    cpl_propertylist_delete(h); h = NULL;

    // combine 3 files: pyramid orig/shift/shift2
    fh = fopen(sof_path, "w" );
    kmo_test_cat_strings(file_path, test_path, valid_files[0]);
    fprintf (fh, "%s\n", file_path);
    kmo_test_cat_strings(file_path, test_path, valid_files[1]);
    fprintf (fh, "%s\n", file_path);
    kmo_test_cat_strings(file_path, test_path, valid_files[2]);
    fprintf (fh, "%s\n", file_path);
    fclose(fh);

    fh = fopen(user_path, "w" );
    fprintf (fh, "3  1\n");
    fprintf (fh, "-1  8\n");
    fclose(fh);

    test_combine(sof_path,
                 "--ifus=\"1;2;2\" --cmethod=\"sum\" "
                 "--method=\"user\" --filename=\"vectors.txt\"",
                 0);

    strcpy(out_path, "combine_cube_arc_ifu1;2;2");
    switch(sizeof(void*)){
        case 4:
        // 32bit system
        cpl_test_abs(kmo_test_esorex_data(out_path, 0), 24.4501, tol);
        break;
        case 8:
        // 64bit system
        cpl_test_abs(kmo_test_esorex_data(out_path, 0), 24.1194, tol);
       break;
    }
    strcat(out_path, ".fits");
    h = kmclipm_propertylist_load(out_path, 1);
    cpl_test_abs(cpl_propertylist_get_double(h, CRPIX1), 10.5, tol);
    switch(sizeof(void*)){
        case 4:
        // 32bit system
        cpl_test_abs(cpl_propertylist_get_double(h, CRPIX2), 8.5, tol);
        break;
        case 8:
        // 64bit system
        cpl_test_abs(cpl_propertylist_get_double(h, CRPIX2), 7.5, tol);
       break;
    }
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS1), 18);
    cpl_test_eq(cpl_propertylist_get_int(h, NAXIS2), 22);
    cpl_propertylist_delete(h); h = NULL;

    /* ----- invalid tests ----- */
    //
    // method 'user'
    //

    // combine 2 files: gauss shift/orig
    // either --name or --ifus parameter missing
    fh = fopen(sof_path, "w" );
    kmo_test_cat_strings(file_path, test_path, valid_files[5]);
    fprintf (fh, "%s\n", file_path);
    kmo_test_cat_strings(file_path, test_path, valid_files[4]);
    fprintf (fh, "%s\n", file_path);
    fclose(fh);

    test_combine(sof_path,
                 "--ifus=\"1;2\" --cmethod=\"sum\" --method=\"user\"",
                 -1);

    // combine 1 file: gauss shift/orig
    // either --name or --ifus parameter missing
    fh = fopen(sof_path, "w" );
    kmo_test_cat_strings(file_path, test_path, valid_files[5]);
    fprintf (fh, "%s\n", file_path);
    fclose(fh);

    test_combine(sof_path,
                 "--ifus=\"1;2\" --cmethod=\"sum\" --method=\"user\"",
                 -1);

    return cpl_test_end(0);
}

/** @} */
