/* $Id: kmo_priv_flat-test.c,v 1.15 2013-10-11 07:59:36 aagudo Exp $
 *
 * This file is part of the KMOS Library
 * Copyright (C) 2007-2008 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-11 07:59:36 $
 * $Revision: 1.15 $
 * $Name: not supported by cvs2svn $
 */

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

#include <math.h>

#include <cpl_plot.h>
#include "kmclipm_functions.h"
#include "kmclipm_constants.h"

#include "kmo_test_create_data.h"
#include "kmo_priv_flat.h"
#include "kmo_cpl_extensions.h"
#include "kmo_debug.h"
#include "kmo_cpl_extensions.h"

/**
    @defgroup kmo_priv_flat_test   kmo_priv_flat unit tests

    @{
*/

/**
    @brief   test for kmo_create_bad_pix_flat_thresh()
*/
void test_kmo_create_bad_pix_flat_thresh()
{
    cpl_image       *img1    = NULL,
                    *img2    = NULL;
    float           tol      = 0.01;

    kmo_test_verbose_off();
    cpl_test_null(kmo_create_bad_pix_flat_thresh(NULL, -1, 25));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    img1 = cpl_image_new(12, 12, CPL_TYPE_FLOAT);
    cpl_image_set(img1, 5, 5, 1000.0);
    cpl_image_set(img1, 6, 5, 1000.0);
    cpl_image_set(img1, 7, 5, 2.0);
    cpl_image_set(img1, 8, 5, 2.0);
    cpl_image_set(img1, 5, 6, 1000.0);
    cpl_image_set(img1, 6, 6, 1000.0);
    cpl_image_set(img1, 7, 6, 1000.0);
    cpl_image_set(img1, 8, 6, 2.0);
    cpl_image_set(img1, 5, 7, 1000.0);
    cpl_image_set(img1, 6, 7, 2.0);
    cpl_image_set(img1, 7, 7, 2.0);
    cpl_image_set(img1, 8, 7, 2.0);
    cpl_image_set(img1, 5, 8, 1000.0);
    cpl_image_set(img1, 6, 8, 1000.0);
    cpl_image_set(img1, 7, 8, 1000.0);
    cpl_image_set(img1, 8, 8, 1000.0);

    cpl_test_null(kmo_create_bad_pix_flat_thresh(img1, -1, 25));
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    cpl_test_nonnull(img2 = kmo_create_bad_pix_flat_thresh(img1, 6, 25));
    cpl_test_abs(cpl_image_get_mean(img2), 1, tol);
    cpl_test_eq(cpl_image_count_rejected(img2), 0);
    cpl_image_delete(img2);
    cpl_test_error(CPL_ERROR_NONE);

    cpl_image_reject(img1, 2, 2);
    cpl_test_nonnull(img2 = kmo_create_bad_pix_flat_thresh(img1, 6, 25));
    cpl_test_abs(cpl_image_get_mean(img2), 1, tol);
    cpl_test_eq(cpl_image_count_rejected(img2), 1);
    cpl_image_delete(img2);
    cpl_test_error(CPL_ERROR_NONE);

    cpl_image_delete(img1);

}

/**
    @brief   test for kmo_polyfit_edge()
*/
void test_kmo_polyfit_edge()
{
    kmo_test_verbose_off();
    cpl_test_null(kmo_polyfit_edge(NULL, NULL, 3));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    kmclipm_vector *x = kmclipm_vector_load("ref_data/cut_yrow.fits", 0);
    cpl_test_null(kmo_polyfit_edge(x, NULL, 3));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    kmclipm_vector *y = kmclipm_vector_load("ref_data/cut_edge.fits", 0);

    cpl_vector *f = NULL;
    cpl_test_nonnull(f = kmo_polyfit_edge(x, y, 3));
    cpl_test_abs(502.18, cpl_vector_get_mean(f), 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(x);
    kmclipm_vector_delete(y);
    cpl_vector_delete(f);
}

/**
    @brief   test for kmo_edge_trace()
*/
void test_kmo_edge_trace()
{
    kmo_test_verbose_off();
    kmo_edge_trace(NULL, NULL, NULL, -1, -1);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_image *data = kmclipm_image_load("ref_data/well_formed_ifus.fits",
                                     CPL_TYPE_FLOAT, 0, 0);
    kmo_edge_trace(data, NULL, NULL, -1, -1);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    kmclipm_vector *ddd = kmclipm_vector_load("ref_data/yrow.fits", 0);
cpl_vector *yrow = kmclipm_vector_create_non_rejected(ddd);
kmclipm_vector_delete(ddd);
    kmo_edge_trace(data, yrow, NULL, -1, -1);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *edge = NULL;
    kmo_edge_trace(data, yrow, &edge, -1, -1);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    edge = cpl_vector_new(22);
    kmo_edge_trace(data, yrow, &edge, -1, -1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

    kmo_edge_trace(data, yrow, &edge, 1, -1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    kmo_edge_trace(data, yrow, &edge, 2008, 1);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(2008.8, cpl_vector_get_mean(edge), 0.01);

    cpl_image_delete(data);
    cpl_vector_delete(edge);
    cpl_vector_delete(yrow);
}

/**
    @brief   test for kmo_calc_calib_frames()
*/
void test_kmo_calc_calib_frames()
{
    kmo_test_verbose_off();
    kmo_calc_calib_frames(NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    int n = 8, m = 14;
    cpl_vector **slit_ids = (cpl_vector**)cpl_malloc(n*sizeof(cpl_vector*));
    int i = 0, j = 0;
    for (i = 0; i < n; i++) {
        slit_ids[i] = cpl_vector_new(2*m);
        for (j = 0; j < m; j++) {
            cpl_vector_set(slit_ids[i], 2*j, j+1);
            cpl_vector_set(slit_ids[i], 2*j+1, j+1);
        }
    }
    kmo_calc_calib_frames(slit_ids, NULL, 0, NULL, NULL, NULL, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    FILE *fp = fopen("ref_data/edgepars_matrix.bin","rb");
    cpl_matrix **edgepars = (cpl_matrix**)cpl_malloc(n*sizeof(cpl_matrix*));
    for (i = 0; i < n; i++) {
        edgepars[i] = cpl_matrix_new(2*m, 4);
        double *ddd = cpl_matrix_get_data(edgepars[i]);
        fread(ddd, sizeof(double), 4*2*m, fp);
    }
    fclose(fp);
    kmo_calc_calib_frames(slit_ids, edgepars, 0, NULL, NULL, NULL, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_image *data = kmclipm_image_load("ref_data/well_formed_ifus.fits",
                                     CPL_TYPE_FLOAT, 0, 0);
    kmo_calc_calib_frames(slit_ids, edgepars, 0, data, NULL, NULL, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_image *noise = cpl_image_duplicate(data);
    cpl_image_fill_noise_uniform(noise, 0.0, 1.0);
    kmo_calc_calib_frames(slit_ids, edgepars, 0, data, noise, NULL, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_image *bad = cpl_image_duplicate(data);
    kmo_image_fill(bad, 1.0);
    kmo_calc_calib_frames(slit_ids, edgepars, 0, data, noise, bad, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_image *xcal = cpl_image_duplicate(data);
    kmo_image_fill(xcal, 0.0);
    kmo_calc_calib_frames(slit_ids, edgepars, 0, data, noise, bad, xcal, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_image *ycal = cpl_image_duplicate(data);
    kmo_image_fill(ycal, 0.0);
    kmo_calc_calib_frames(slit_ids, edgepars, 0, data, noise, bad, xcal, ycal);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    kmo_calc_calib_frames(slit_ids, edgepars, 1, data, noise, bad, xcal, ycal);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(0.616954, cpl_image_get_mean(xcal), 0.1);
    cpl_test_abs(0.72347, cpl_image_get_mean(ycal), 0.1);
    cpl_test_abs(10371.3, cpl_image_get_mean(data), 0.1);
    cpl_test_abs(0.52, cpl_image_get_mean(noise), 0.1);
    cpl_test_abs(1, cpl_image_get_mean(bad), 0.1);

    cpl_image_delete(xcal);
    cpl_image_delete(ycal);
    cpl_image_delete(bad);
    for (i = 0; i < n; i++) {
        cpl_vector_delete(slit_ids[i]);
        cpl_matrix_delete(edgepars[i]);
    }
    cpl_free(slit_ids);
    cpl_free(edgepars);
    cpl_image_delete(data);
    cpl_image_delete(noise);
}

/**
    @brief   test for kmo_curvature_qc()
*/
void test_kmo_curvature_qc()
{
    kmo_test_verbose_off();
    kmo_curvature_qc(NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    int n = 8, m = 14;
    FILE *fp = fopen("ref_data/edgepars_matrix.bin","rb");
    cpl_matrix **edgepars = (cpl_matrix**)cpl_malloc(n*sizeof(cpl_matrix*));
    int i = 0;
    for (i = 0; i < n; i++) {
        edgepars[i] = cpl_matrix_new(2*m, 4);
        double *ddd = cpl_matrix_get_data(edgepars[i]);
        fread(ddd, sizeof(double), 4*2*m, fp);
    }
    fclose(fp);
    kmo_curvature_qc(edgepars, NULL, NULL, NULL, NULL, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    double gapmean = -1, gapsdv = -1, gapmaxdev = -1, slitmean = -1, slitsdv = -1, slitmaxdev  = -1;
    kmo_curvature_qc(edgepars, &gapmean, NULL, NULL, NULL, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    kmo_curvature_qc(edgepars, &gapmean, &gapsdv, NULL, NULL, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    kmo_curvature_qc(edgepars, &gapmean, &gapsdv, &gapmaxdev, NULL, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    kmo_curvature_qc(edgepars, &gapmean, &gapsdv, &gapmaxdev, &slitmean, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    kmo_curvature_qc(edgepars, &gapmean, &gapsdv, &gapmaxdev, &slitmean, &slitsdv, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    kmo_test_verbose_on();
    kmo_curvature_qc(edgepars, &gapmean, &gapsdv, &gapmaxdev, &slitmean, &slitsdv, &slitmaxdev);
    cpl_test_abs(4.90468, gapmean, 0.01);
    cpl_test_abs(0.130222, gapsdv, 0.01);
    cpl_test_abs(0.342574, gapmaxdev, 0.01);
    cpl_test_abs(12.8883, slitmean, 0.01);
    cpl_test_abs(0.131986, slitsdv, 0.01);
    cpl_test_abs(0.403824, slitmaxdev, 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    for (i = 0; i < n; i++) {
        cpl_matrix_delete(edgepars[i]);
    }
    cpl_free(edgepars);
}

/**
    @brief   test for kmo_edgepars_to_table()
*/
void test_kmo_edgepars_to_table()
{
    kmo_test_verbose_off();
    cpl_test_null(kmo_edgepars_to_table(NULL, NULL));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    int n = 8, m = 14;
    cpl_vector **slit_ids = (cpl_vector**)cpl_malloc(n*sizeof(cpl_vector*));
    int i = 0, j = 0;
    for (i = 0; i < n; i++) {
        slit_ids[i] = cpl_vector_new(2*m);
        for (j = 0; j < m; j++) {
            cpl_vector_set(slit_ids[i], 2*j, j+1);
            cpl_vector_set(slit_ids[i], 2*j+1, j+1);
        }
    }
    cpl_test_null(kmo_edgepars_to_table(slit_ids, NULL));
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    kmo_test_verbose_on();

    FILE *fp = fopen("ref_data/edgepars_matrix.bin","rb");
    cpl_matrix **edgepars = (cpl_matrix**)cpl_malloc(n*sizeof(cpl_matrix*));
    for (i = 0; i < n; i++) {
        edgepars[i] = cpl_matrix_new(2*m, 4);
        double *ddd = cpl_matrix_get_data(edgepars[i]);
        fread(ddd, sizeof(double), 4*2*m, fp);
    }
    fclose(fp);
    cpl_table **edge_par = NULL;
    cpl_test_nonnull(edge_par = kmo_edgepars_to_table(slit_ids, edgepars));
    cpl_test_error(CPL_ERROR_NONE);
    double checksum = 0;
    checksum += cpl_table_get_column_mean(edge_par[0], "ID");
    checksum += cpl_table_get_column_mean(edge_par[0], "A0");
    checksum += cpl_table_get_column_mean(edge_par[0], "A1");
    checksum += cpl_table_get_column_mean(edge_par[0], "A2");
    checksum += cpl_table_get_column_mean(edge_par[0], "A3");
    checksum += cpl_table_get_column_mean(edge_par[1], "ID");
    checksum += cpl_table_get_column_mean(edge_par[1], "A0");
    checksum += cpl_table_get_column_mean(edge_par[1], "A1");
    checksum += cpl_table_get_column_mean(edge_par[1], "A2");
    checksum += cpl_table_get_column_mean(edge_par[1], "A3");
    checksum += cpl_table_get_column_mean(edge_par[2], "ID");
    checksum += cpl_table_get_column_mean(edge_par[2], "A0");
    checksum += cpl_table_get_column_mean(edge_par[2], "A1");
    checksum += cpl_table_get_column_mean(edge_par[2], "A2");
    checksum += cpl_table_get_column_mean(edge_par[2], "A3");
    checksum += cpl_table_get_column_mean(edge_par[3], "ID");
    checksum += cpl_table_get_column_mean(edge_par[3], "A0");
    checksum += cpl_table_get_column_mean(edge_par[3], "A1");
    checksum += cpl_table_get_column_mean(edge_par[3], "A2");
    checksum += cpl_table_get_column_mean(edge_par[3], "A3");
    checksum += cpl_table_get_column_mean(edge_par[4], "ID");
    checksum += cpl_table_get_column_mean(edge_par[4], "A0");
    checksum += cpl_table_get_column_mean(edge_par[4], "A1");
    checksum += cpl_table_get_column_mean(edge_par[4], "A2");
    checksum += cpl_table_get_column_mean(edge_par[4], "A3");
    checksum += cpl_table_get_column_mean(edge_par[5], "ID");
    checksum += cpl_table_get_column_mean(edge_par[5], "A0");
    checksum += cpl_table_get_column_mean(edge_par[5], "A1");
    checksum += cpl_table_get_column_mean(edge_par[5], "A2");
    checksum += cpl_table_get_column_mean(edge_par[5], "A3");
    checksum += cpl_table_get_column_mean(edge_par[6], "ID");
    checksum += cpl_table_get_column_mean(edge_par[6], "A0");
    checksum += cpl_table_get_column_mean(edge_par[6], "A1");
    checksum += cpl_table_get_column_mean(edge_par[6], "A2");
    checksum += cpl_table_get_column_mean(edge_par[6], "A3");
    checksum += cpl_table_get_column_mean(edge_par[7], "ID");
    checksum += cpl_table_get_column_mean(edge_par[7], "A0");
    checksum += cpl_table_get_column_mean(edge_par[7], "A1");
    checksum += cpl_table_get_column_mean(edge_par[7], "A2");
    checksum += cpl_table_get_column_mean(edge_par[7], "A3");
    cpl_test_abs(8177.27, checksum, 0.01);

    for (i = 0; i < KMOS_IFUS_PER_DETECTOR; i++) {
        cpl_table_delete(edge_par[i]); edge_par[i] = NULL;
    }
    cpl_free(edge_par);
    for (i = 0; i < n; i++) {
        cpl_vector_delete(slit_ids[i]);
        cpl_matrix_delete(edgepars[i]);
    }
    cpl_free(slit_ids);
    cpl_free(edgepars);
}

/**
    @brief   test for kmo_flat_interpolate_edge_parameters()
*/
void test_kmo_flat_interpolate_edge_parameters()
{
    double checksum = 0;
    int n = 8, m = 14;
    FILE *fp = fopen("ref_data/edgepars_matrix.bin","rb");
    cpl_matrix **edgepars = (cpl_matrix**)cpl_malloc(n*sizeof(cpl_matrix*));
    int i = 0;
    for (i = 0; i < n; i++) {
        edgepars[i] = cpl_matrix_new(2*m, 4);
        double *ddd = cpl_matrix_get_data(edgepars[i]);
        fread(ddd, sizeof(double), 4*2*m, fp);

        checksum += cpl_matrix_get_mean(edgepars[i]);
    }
    fclose(fp);

    cpl_test_abs(2029.32, checksum, 0.01);
    kmo_flat_interpolate_edge_parameters(edgepars, 4.0, 1, 1, 1);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(2029.32, checksum, 0.01);

    for (i = 0; i < n; i++) {
        cpl_matrix_delete(edgepars[i]);
    }
    cpl_free(edgepars);
}

/**
    @brief   test for kmo_chebyshev_coefficients()
*/
void test_kmo_chebyshev_coefficients()
{
    double in[4] = {1764.78, -0.00416616, 4.09266e-05, -1.74782e-07},
            out[4];
    kmo_chebyshev_coefficients(in, out, 4, 1);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(1764.78, out[0], 0.01);
    cpl_test_abs(-0.00416629, out[1], 1e-5);
    cpl_test_abs(2.04633e-05, out[2], 1e-7);
    cpl_test_abs(-4.36956e-08, out[3], 1e-10);
}

/**
    @brief   test for kmo_split_frame()
*/
void test_kmo_split_frame()
{
    cpl_image       *xcal   = NULL;
    int             *bounds = NULL;

    /* --- invalid tests --- */
    kmo_test_verbose_off();
    cpl_test_null(bounds = kmo_split_frame(NULL));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    xcal = cpl_image_new(2, 2, CPL_TYPE_FLOAT);
    cpl_test_null(bounds = kmo_split_frame(xcal));
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cpl_image_delete(xcal); xcal = NULL;
    kmo_test_verbose_on();

    /* --- valid tests --- */
    xcal = cpl_image_new(KMOS_DETECTOR_SIZE, KMOS_DETECTOR_SIZE, CPL_TYPE_FLOAT);
    cpl_image_multiply_scalar(xcal, 0.0);
    int ix = 0, iy = 0;
    for (ix = 1; ix <= KMOS_DETECTOR_SIZE; ix++) {
        for (iy = 1; iy <= KMOS_DETECTOR_SIZE; iy++) {
            if (!((ix==3) && (iy==1)) &&
                !((ix==4) && (iy==1)) &&
                !((ix==5) && (iy==1)) &&
                !((ix==6) && (iy==1)) &&
                !((ix==5) && (iy==5)) &&
                !((ix==6) && (iy==5)) &&
                !((ix==7) && (iy==5)) &&
                !((ix==8) && (iy==5)))
            {
                cpl_image_reject(xcal, ix, iy);
            }
        }
    }
    cpl_image_set(xcal, 3, 1, 1.1);
    cpl_image_set(xcal, 4, 1, 2.1);
    cpl_image_set(xcal, 5, 1, 3.1);
    cpl_image_set(xcal, 6, 1, 4.1);
    cpl_image_set(xcal, 5, 5, 1.4);
    cpl_image_set(xcal, 6, 5, 2.4);
    cpl_image_set(xcal, 7, 5, 3.4);
    cpl_image_set(xcal, 8, 5, 4.4);

    cpl_test_nonnull(bounds = kmo_split_frame(xcal));
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_eq(2, bounds[0]);
    cpl_test_eq(5, bounds[1]);
    cpl_test_eq(-1, bounds[2]);
    cpl_test_eq(-1, bounds[3]);
    cpl_test_eq(-1, bounds[4]);
    cpl_test_eq(-1, bounds[5]);
    cpl_test_eq(4, bounds[6]);
    cpl_test_eq(7, bounds[7]);
    cpl_test_eq(-1, bounds[8]);
    cpl_test_eq(-1, bounds[9]);
    cpl_test_eq(-1, bounds[10]);
    cpl_test_eq(-1, bounds[11]);
    cpl_test_eq(-1, bounds[12]);
    cpl_test_eq(-1, bounds[13]);
    cpl_test_eq(-1, bounds[14]);
    cpl_test_eq(-1, bounds[15]);

    cpl_image_delete(xcal); xcal = NULL;
    cpl_free(bounds);
}

/**
    @brief   test for kmo_imagelist_get_saturated()
*/
void test_kmo_imagelist_get_saturated()
{
    cpl_imagelist   *list   = NULL;
    cpl_image       *img    = NULL;

    /* --- invalid tests --- */
    kmo_test_verbose_off();
    cpl_test_eq(-1, kmo_imagelist_get_saturated(NULL, -1.0, -1.0));
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    list = cpl_imagelist_new();
    cpl_test_eq(-1, kmo_imagelist_get_saturated(list, -1.0, -1.0));
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cpl_test_eq(-1, kmo_imagelist_get_saturated(list, 1000, -1.0));
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    /* --- valid tests --- */
    img = cpl_image_new(2, 2, CPL_TYPE_FLOAT);
    cpl_image_set(img, 1, 1, 10000);
    cpl_image_set(img, 1, 2, 10000);
    cpl_image_set(img, 2, 1, 10000);
    cpl_image_set(img, 2, 2, 1);
    cpl_imagelist_set(list, img, 0);

    img = cpl_image_new(2, 2, CPL_TYPE_FLOAT);
    cpl_image_set(img, 1, 1, 10000);
    cpl_image_set(img, 1, 2, 10000);
    cpl_image_set(img, 2, 1, 1);
    cpl_image_set(img, 2, 2, 1);
    cpl_imagelist_set(list, img, 1);

    img = cpl_image_new(2, 2, CPL_TYPE_FLOAT);
    cpl_image_set(img, 1, 1, 10000);
    cpl_image_set(img, 1, 2, 1);
    cpl_image_set(img, 2, 1, 1);
    cpl_image_set(img, 2, 2, 1);
    cpl_imagelist_set(list, img, 2);

    cpl_test_eq(2, kmo_imagelist_get_saturated(list, 1000, 2));
    cpl_test_error(CPL_ERROR_NONE);

    cpl_imagelist_delete(list);
}

/**
    @brief   test for kmo_create_line_profile()
*/
void test_kmo_create_line_profile()
{
    kmo_test_verbose_off();
    cpl_test_null(kmo_create_line_profile(NULL, -1, -1));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_image *profile = kmclipm_image_load ("ref_data/line_prof.fits", CPL_TYPE_FLOAT, 0, 0);
    cpl_test_null(kmo_create_line_profile(profile, 10, 5));
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    kmclipm_vector *midline = NULL;
    cpl_test_nonnull(midline = kmo_create_line_profile(profile, 80, 120));
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(1106.87, kmclipm_vector_get_mean(midline), 0.01);
    cpl_test_eq(1, kmclipm_vector_is_rejected(midline, 0));
    cpl_test_eq(1, kmclipm_vector_is_rejected(midline, 1));
    cpl_test_eq(1, kmclipm_vector_is_rejected(midline, 2));
    cpl_test_eq(1, kmclipm_vector_is_rejected(midline, 3));
    cpl_test_eq(0, kmclipm_vector_is_rejected(midline, 4));
    cpl_test_eq(0, kmclipm_vector_is_rejected(midline, 2043));
    cpl_test_eq(1, kmclipm_vector_is_rejected(midline, 2044));
    cpl_test_eq(1, kmclipm_vector_is_rejected(midline, 2045));
    cpl_test_eq(1, kmclipm_vector_is_rejected(midline, 2046));
    cpl_test_eq(1, kmclipm_vector_is_rejected(midline, 2047));

    kmclipm_vector_delete(midline);
    cpl_image_delete(profile);
}

/**
    @brief   test for kmo_get_slitedges()
*/
void test_kmo_get_slitedges()
{
    kmclipm_vector *pos, *midline;

    kmo_test_verbose_off();
    cpl_test_null(kmo_get_slitedges(NULL, 0));
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    kmo_test_verbose_on();

    midline = kmclipm_vector_load("ref_data/midline.fits", 0);
    cpl_test_nonnull(pos = kmo_get_slitedges(midline, 1106.87));
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(881.8, kmclipm_vector_get_mean(pos), 0.1);
    kmclipm_vector_delete(midline);
    kmclipm_vector_delete(pos);

    midline = kmclipm_vector_load("ref_data/midline_sv1_blank.fits", 0);
    cpl_test_nonnull(pos = kmo_get_slitedges(midline, 200));
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(696.5, kmclipm_vector_get_mean(pos), 0.1);
    kmclipm_vector_delete(midline);
    kmclipm_vector_delete(pos);

    midline = kmclipm_vector_load("ref_data/midline_sv2.fits", 0);
    kmclipm_vector_reject(midline, 0);
    kmclipm_vector_reject(midline, 1);
    kmclipm_vector_reject(midline, 2);
    kmclipm_vector_reject(midline, 3);
    kmclipm_vector_reject(midline, 2044);
    kmclipm_vector_reject(midline, 2045);
    kmclipm_vector_reject(midline, 2046);
    kmclipm_vector_reject(midline, 2047);
    cpl_test_nonnull(pos = kmo_get_slitedges(midline, 5500));
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(1015.4, kmclipm_vector_get_mean(pos), 0.1);
    cpl_test_eq(226, kmclipm_vector_get_size(pos));
    kmclipm_vector_delete(midline);
    kmclipm_vector_delete(pos);

    midline = kmclipm_vector_load("ref_data/midline_sv2.fits", 0);
    kmclipm_vector_reject(midline, 0);
    kmclipm_vector_reject(midline, 1);
    kmclipm_vector_reject(midline, 2);
    kmclipm_vector_reject(midline, 3);
    kmclipm_vector_reject(midline, 2044);
    kmclipm_vector_reject(midline, 2045);
    kmclipm_vector_reject(midline, 2046);
    kmclipm_vector_reject(midline, 2047);
    cpl_test_nonnull(pos = kmo_get_slitedges(midline, 4000));
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(1015.0, kmclipm_vector_get_mean(pos), 0.1);
    cpl_test_eq(224, kmclipm_vector_get_size(pos));
    kmclipm_vector_delete(midline);
    kmclipm_vector_delete(pos);

    midline = kmclipm_vector_load("ref_data/midline_sv2_gap_first.fits", 0);
    kmclipm_vector_reject(midline, 0);
    kmclipm_vector_reject(midline, 1);
    kmclipm_vector_reject(midline, 2);
    kmclipm_vector_reject(midline, 3);
    kmclipm_vector_reject(midline, 2044);
    kmclipm_vector_reject(midline, 2045);
    kmclipm_vector_reject(midline, 2046);
    kmclipm_vector_reject(midline, 2047);
    cpl_test_nonnull(pos = kmo_get_slitedges(midline, 4000));
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(1019.6, kmclipm_vector_get_mean(pos), 0.1);
    cpl_test_eq(223, kmclipm_vector_get_size(pos));
    kmclipm_vector_delete(midline);
    kmclipm_vector_delete(pos);

    midline = kmclipm_vector_load("ref_data/midline_sv2_gap_last.fits", 0);
    kmclipm_vector_reject(midline, 0);
    kmclipm_vector_reject(midline, 1);
    kmclipm_vector_reject(midline, 2);
    kmclipm_vector_reject(midline, 3);
    kmclipm_vector_reject(midline, 2044);
    kmclipm_vector_reject(midline, 2045);
    kmclipm_vector_reject(midline, 2046);
    kmclipm_vector_reject(midline, 2047);
    cpl_test_nonnull(pos = kmo_get_slitedges(midline, 4000));
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(1010.6, kmclipm_vector_get_mean(pos), 0.1);
    cpl_test_eq(223, kmclipm_vector_get_size(pos));
    kmclipm_vector_delete(midline);
    kmclipm_vector_delete(pos);

    midline = kmclipm_vector_load("ref_data/midline_sv2_gap_first_last.fits", 0);
    kmclipm_vector_reject(midline, 0);
    kmclipm_vector_reject(midline, 1);
    kmclipm_vector_reject(midline, 2);
    kmclipm_vector_reject(midline, 3);
    kmclipm_vector_reject(midline, 2044);
    kmclipm_vector_reject(midline, 2045);
    kmclipm_vector_reject(midline, 2046);
    kmclipm_vector_reject(midline, 2047);
    cpl_test_nonnull(pos = kmo_get_slitedges(midline, 4000));
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(1015, kmclipm_vector_get_mean(pos), 0.1);
    cpl_test_eq(222, kmclipm_vector_get_size(pos));
    kmclipm_vector_delete(midline);
    kmclipm_vector_delete(pos);
}

/**
    @brief   test for kmo_analize_slitedges()
*/
void test_kmo_analize_slitedges()
{
    kmclipm_vector  *midline        = NULL,
                    *t_value        = NULL,
                    *t_level        = NULL,
                    *pos            = NULL;
    int             t_pos           = 0;

    {
        // blank, noisy, no slitlets
        midline = kmclipm_vector_load("ref_data/midline_sv1_blank.fits", 0);
        // estimated threshold, arbitrary edges due to noise
        cpl_test_null(pos = kmo_analize_slitedges(midline, 173,
                                                  &t_value, &t_level, &t_pos));
        // too low & too high threshold, no edges
        cpl_test_null(pos = kmo_analize_slitedges(midline, 100,
                                                  &t_value, &t_level, &t_pos));
        cpl_test_null(pos = kmo_analize_slitedges(midline, 5000,
                                                  &t_value, &t_level, &t_pos));
        kmclipm_vector_delete(midline);
    }
    {
        // first: gap, last: slit
        midline = kmclipm_vector_load("ref_data/midline_sv2_gap_first.fits", 0);
        cpl_test_null(pos = kmo_analize_slitedges(midline, 173,
                                                  &t_value, &t_level, &t_pos));
        kmclipm_vector_delete(midline);
    }
    {
        // first: slit, last: gap
        midline = kmclipm_vector_load("ref_data/midline_sv2_gap_last.fits", 0);
        cpl_test_null(pos = kmo_analize_slitedges(midline, 173,
                                                  &t_value, &t_level, &t_pos));
        kmclipm_vector_delete(midline);
    }
    {
        // first: gap, last: gap
        midline = kmclipm_vector_load("ref_data/midline_sv2_gap_first_last.fits", 0);
        cpl_test_null(pos = kmo_analize_slitedges(midline, 173,
                                                  &t_value, &t_level, &t_pos));
        kmclipm_vector_delete(midline);
    }
    {
        // first: slit, last: slit (normal case)
        midline = kmclipm_vector_load("ref_data/midline_sv2.fits", 0);
        cpl_test_nonnull(pos = kmo_analize_slitedges(midline, 5500,
                                                     &t_value, &t_level, &t_pos));
        cpl_test_abs(1015.0, kmclipm_vector_get_mean(pos), 0.1);
        cpl_test_eq(224, kmclipm_vector_count_non_rejected(pos));
        cpl_test_eq(224, kmclipm_vector_get_size(pos));
        cpl_test_eq(0, kmclipm_vector_is_rejected(pos, 0));
        cpl_test_eq(0, kmclipm_vector_is_rejected(pos, kmclipm_vector_get_size(pos)-1));
        kmclipm_vector_delete(t_value);
        kmclipm_vector_delete(t_level);
        kmclipm_vector_delete(pos);
        kmclipm_vector_delete(midline);
    }
}

/**
    @brief   test for kmo_analize_slitedges_advanced()
*/
void test_kmo_analize_slitedges_advanced()
{
    kmclipm_vector  *midline        = NULL,
                    *pos            = NULL;
    int             cut_first       = 0,
                    cut_last        = 0;

    {
        // blank, noisy, no slitlets
        midline = kmclipm_vector_load("ref_data/midline_sv1_blank.fits", 0);
        // estimated threshold, arbitrary edges due to noise
        cpl_test_null(pos = kmo_analize_slitedges_advanced(midline, 173, &cut_first, &cut_last));
        // too low & too high threshold, no edges
        cpl_test_null(pos = kmo_analize_slitedges_advanced(midline, 100, &cut_first, &cut_last));
        cpl_test_null(pos = kmo_analize_slitedges_advanced(midline, 5000, &cut_first, &cut_last));
        kmclipm_vector_delete(midline);
    }
    {
        // first: slit, last: slit (normal case)
        midline = kmclipm_vector_load("ref_data/midline_sv2.fits", 0);
        cpl_test_nonnull(pos = kmo_analize_slitedges_advanced(midline, 5500, &cut_first, &cut_last));
        cpl_test_abs(1014.8, kmclipm_vector_get_mean(pos), 0.1);
        cpl_test_eq(220, kmclipm_vector_count_non_rejected(pos));
        cpl_test_eq(226, kmclipm_vector_get_size(pos));
        cpl_test_eq(0, kmclipm_vector_is_rejected(pos, 0));
        cpl_test_eq(0, kmclipm_vector_is_rejected(pos, kmclipm_vector_get_size(pos)-1));
        kmclipm_vector_delete(pos);
        kmclipm_vector_delete(midline);
    }
    {
        // first: gap, last: slit
        midline = kmclipm_vector_load("ref_data/midline_sv2_gap_first.fits", 0);
        cpl_test_nonnull(pos = kmo_analize_slitedges_advanced(midline, 5500, &cut_first, &cut_last));
        cpl_test_abs(1023.9, kmclipm_vector_get_mean(pos), 0.1);
        cpl_test_eq(218, kmclipm_vector_count_non_rejected(pos));
        cpl_test_eq(225, kmclipm_vector_get_size(pos));
        cpl_test_eq(1, kmclipm_vector_is_rejected(pos, 0));
        cpl_test_eq(0, kmclipm_vector_is_rejected(pos, kmclipm_vector_get_size(pos)-1));
        kmclipm_vector_delete(pos);
        kmclipm_vector_delete(midline);
    }
    {
        // first: slit, last: gap
        midline = kmclipm_vector_load("ref_data/midline_sv2_gap_last.fits", 0);
        cpl_test_nonnull(pos = kmo_analize_slitedges_advanced(midline, 5500, &cut_first, &cut_last));
        cpl_test_abs(1005.6, kmclipm_vector_get_mean(pos), 0.1);
        cpl_test_eq(218, kmclipm_vector_count_non_rejected(pos));
        cpl_test_eq(225, kmclipm_vector_get_size(pos));
        cpl_test_eq(0, kmclipm_vector_is_rejected(pos, 0));
        cpl_test_eq(1, kmclipm_vector_is_rejected(pos, kmclipm_vector_get_size(pos)-1));
        kmclipm_vector_delete(pos);
        kmclipm_vector_delete(midline);
    }
    {
        // first: gap, last: gap
        midline = kmclipm_vector_load("ref_data/midline_sv2_gap_first_last.fits", 0);
        cpl_test_nonnull(pos = kmo_analize_slitedges_advanced(midline, 5500, &cut_first, &cut_last));
        cpl_test_abs(1014.75, kmclipm_vector_get_mean(pos), 0.1);
        cpl_test_eq(216, kmclipm_vector_count_non_rejected(pos));
        cpl_test_eq(224, kmclipm_vector_get_size(pos));
        cpl_test_eq(1, kmclipm_vector_is_rejected(pos, 0));
        cpl_test_eq(1, kmclipm_vector_is_rejected(pos, kmclipm_vector_get_size(pos)-1));
        kmclipm_vector_delete(pos);
        kmclipm_vector_delete(midline);
    }
}

/**
    @brief   test for kmo_analyze_flat()
*/
void test_kmo_analyze_flat()
{
    int             i;
    cpl_image       *data,
                    *badpix;
    cpl_array       **array,
                    *ifu_inactive;  // 0: active
                                    // 1: inactive ICS
                                    // 2: inactive pipeline

    {
        //
        // test with blank images
        //

        //
        // all_blank.fits
        //
        data = kmclipm_image_load("ref_data/all_blank.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_null(array[0]);
        cpl_test_null(array[1]);
        cpl_test_null(array[2]);
        cpl_test_null(array[3]);
        cpl_test_null(array[4]);
        cpl_test_null(array[5]);
        cpl_test_null(array[6]);
        cpl_test_null(array[7]);
        // ifus out : 2 2 2 2 2 2 2 2
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        cpl_free(array);

        //
        // noise_img.fits
        //
        data = kmclipm_image_load("ref_data/noise_img.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_null(array[0]);
        cpl_test_null(array[1]);
        cpl_test_null(array[2]);
        cpl_test_null(array[3]);
        cpl_test_null(array[4]);
        cpl_test_null(array[5]);
        cpl_test_null(array[6]);
        cpl_test_null(array[7]);
        // ifus out : 2 2 2 2 2 2 2 2
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        cpl_free(array);

        //
        // flat_det_sv1_blank.fits
        //
        data = kmclipm_image_load("ref_data/flat_det_sv1_blank.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 1 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_array_set_int(ifu_inactive, 1, 1);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_null(array[0]);
        cpl_test_null(array[1]);
        cpl_test_null(array[2]);
        cpl_test_null(array[3]);
        cpl_test_null(array[4]);
        cpl_test_null(array[5]);
        cpl_test_null(array[6]);
        cpl_test_null(array[7]);
        // ifus out : 2 1 2 2 2 2 2 2
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(1, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        cpl_free(array);
    }

    {
        //
        // test with IFU7 vignetted, IFU8 blank
        //
        data = kmclipm_image_load("ref_data/flat_det_sv1.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_abs(148.1, cpl_array_get_mean(array[0]), 0.1);
        cpl_test_abs(395.1, cpl_array_get_mean(array[1]), 0.1);
        cpl_test_abs(643.1, cpl_array_get_mean(array[2]), 0.1);
        cpl_test_abs(890.1, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1138.5, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1386.7, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1634.6, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_null(array[7]);
        // ifus out : 0 0 0 0 0 0 0 2
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);
    }

    {
        //
        // test with IFU5 vignetted
        //
        data = kmclipm_image_load("ref_data/flat_det_sv2.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_abs(136.4, cpl_array_get_mean(array[0]), 0.1);
        cpl_test_abs(386.9, cpl_array_get_mean(array[1]), 0.1);
        cpl_test_abs(638.2, cpl_array_get_mean(array[2]), 0.1);
        cpl_test_abs(888.5, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1140.5, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1391.8, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1643.3, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_abs(1894.7, cpl_array_get_mean(array[7]), 0.1);
        // ifus out : 0 0 0 0 0 0 0 0
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);

        // ifu_inactive in : 0 1 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_array_set_int(ifu_inactive, 1, 1);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_abs(136.4, cpl_array_get_mean(array[0]), 0.1);
        cpl_test_null(array[1]);
        cpl_test_abs(638.2, cpl_array_get_mean(array[2]), 0.1);
        cpl_test_abs(888.5, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1140.5, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1391.8, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1643.3, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_abs(1894.7, cpl_array_get_mean(array[7]), 0.1);
        // ifus out : 0 1 0 0 0 0 0 0
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(1, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);
    }
    {
        //
        // test with IFU5 vignetted, IFU 2 blackened out
        //
        data = kmclipm_image_load("ref_data/flat_det_sv2_ifu2_black.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 1 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_array_set_int(ifu_inactive, 2, 1);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_abs(136.4, cpl_array_get_mean(array[0]), 0.1);
        cpl_test_null(array[1]);
        cpl_test_null(array[2]);
        cpl_test_abs(888.5, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1140.5, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1391.8, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1643.3, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_abs(1894.7, cpl_array_get_mean(array[7]), 0.1);
        // ifus out : 0 2 1 0 0 0 0 0
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(1, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);
    }
    {
        //
        // test with IFU5 vignetted, IFU 1 blackened out
        //
        data = kmclipm_image_load("ref_data/flat_det_sv2_ifu1_black.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 1 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_array_set_int(ifu_inactive, 2, 1);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_null(array[0]);
        cpl_test_abs(386.9, cpl_array_get_mean(array[1]), 0.1);
        cpl_test_null(array[2]);
        cpl_test_abs(888.5, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1140.5, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1391.8, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1643.3, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_abs(1894.7, cpl_array_get_mean(array[7]), 0.1);
        // ifus out : 2 0 1 0 0 0 0 0
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(1, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);
    }
    {
        //
        // test with IFU5 vignetted, IFU 8 blackened out
        //
        data = kmclipm_image_load("ref_data/flat_det_sv2_ifu8_black.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 1 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_array_set_int(ifu_inactive, 2, 1);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_abs(136.4, cpl_array_get_mean(array[0]), 0.1);
        cpl_test_abs(386.9, cpl_array_get_mean(array[1]), 0.1);
        cpl_test_null(array[2]);
        cpl_test_abs(888.5, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1140.5, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1391.8, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1643.3, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_null(array[7]);
        // ifus out : 0 0 1 0 0 0 0 2
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(1, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);
    }
    {
        //
        // test with IFU5 vignetted, IFU 2,3 blackened out
        //
        data = kmclipm_image_load("ref_data/flat_det_sv2_ifu2_3_black.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 1 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_array_set_int(ifu_inactive, 3, 1);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_abs(136.4, cpl_array_get_mean(array[0]), 0.1);
        cpl_test_null(array[1]);
        cpl_test_null(array[2]);
        cpl_test_null(array[3]);
        cpl_test_abs(1140.5, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1391.8, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1643.3, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_abs(1894.7, cpl_array_get_mean(array[7]), 0.1);
        // ifus out : 0 2 2 1 0 0 0 0
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(1, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);
    }
    {
        //
        // test with IFU5 vignetted, IFU 1,8 blackened out
        //
        data = kmclipm_image_load("ref_data/flat_det_sv2_ifu1_8_black.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 1 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_array_set_int(ifu_inactive, 3, 1);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_null(array[0]);
        cpl_test_abs(386.9, cpl_array_get_mean(array[1]), 0.1);
        cpl_test_abs(638.2, cpl_array_get_mean(array[2]), 0.1);
        cpl_test_null(array[3]);
        cpl_test_abs(1140.5, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1391.8, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1643.3, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_null(array[7]);
        // ifus out : 2 0 0 1 0 0 0 2
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(1, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);
    }
    {
        //
        // test with IFU5 vignetted, IFU 1,2,3,4,6,7,8 blackened out
        //
        data = kmclipm_image_load("ref_data/flat_det_sv2_ifu1_2_3_4_6_7_8_black.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 1 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_array_set_int(ifu_inactive, 3, 1);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_null(array[0]);
        cpl_test_null(array[1]);
        cpl_test_null(array[2]);
        cpl_test_null(array[3]);
        cpl_test_abs(1140.4, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_null(array[5]);
        cpl_test_null(array[6]);
        cpl_test_null(array[7]);
        // ifus out : 2 2 2 1 0 2 2 2
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(1, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);
    }
    {
        //
        // test with IFU3 vignetted
        //
        data = kmclipm_image_load("ref_data/flat_det_sv2_2.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_abs(136.6, cpl_array_get_mean(array[0]), 0.1);
        cpl_test_abs(387.1, cpl_array_get_mean(array[1]), 0.1);
        cpl_test_null(array[2]);
        cpl_test_abs(889.1, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1140.9, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1392.5, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1643.9, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_abs(1895.5, cpl_array_get_mean(array[7]), 0.1);
        // ifus out : 0 0 2 0 0 0 0 0
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);
    }
    {
        //
        // test with cut_left_right
        //
        data = kmclipm_image_load("ref_data/cut_left_right_222edges.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_null(array[0]);
        cpl_test_abs(367.6, cpl_array_get_mean(array[1]), 0.1);
        cpl_test_abs(616.8, cpl_array_get_mean(array[2]), 0.1);
        cpl_test_abs(866.0, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1115.2, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1364.4, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1613.5, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_null(array[7]);
        // ifus out : 2 0 0 0 0 0 0 2
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);
    }
    {
        //
        // test with cut_left_right, 166 slitlets --> all deactivated
        //
        data = kmclipm_image_load("ref_data/cut_left_right_220edges.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        kmo_test_verbose_off();
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        kmo_test_verbose_on();
        cpl_test_null(array[0]);
        cpl_test_null(array[1]);
        cpl_test_null(array[2]);
        cpl_test_null(array[3]);
        cpl_test_null(array[4]);
        cpl_test_null(array[5]);
        cpl_test_null(array[6]);
        cpl_test_null(array[7]);
        // ifus out : 2 2 2 2 2 2 2 2
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);

        //
        // test with cut_left_right, 214 slitlets --> all deactivated
        //
        data = kmclipm_image_load("ref_data/out_of_zoom.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        kmo_test_verbose_off();
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        kmo_test_verbose_on();
        cpl_test_null(array[0]);
        cpl_test_null(array[1]);
        cpl_test_null(array[2]);
        cpl_test_null(array[3]);
        cpl_test_null(array[4]);
        cpl_test_null(array[5]);
        cpl_test_null(array[6]);
        cpl_test_null(array[7]);
        // ifus out : 2 2 2 2 2 2 2 2
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);
    }
    {
        //
        // test with shift left one slitlet cut, 196 slitlets
        //
        data = kmclipm_image_load("ref_data/shift_left_one_slitlet_cut.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        kmo_test_verbose_off();
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        kmo_test_verbose_on();
        cpl_test_null(array[0]);
        cpl_test_abs(370.6, cpl_array_get_mean(array[1]), 0.1);
        cpl_test_abs(619.8, cpl_array_get_mean(array[2]), 0.1);
        cpl_test_abs(869.0, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1118.2, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1367.4, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1616.5, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_abs(1865.7, cpl_array_get_mean(array[7]), 0.1);
        // ifus out : 2 0 0 0 0 0 0 0
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);

        data = kmclipm_image_load("ref_data/shift_left_one_slitlet_cut_IFU1_8_missing.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 1 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_array_set_int(ifu_inactive, 6, 1);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_null(array[0]);
        cpl_test_abs(370.6, cpl_array_get_mean(array[1]), 0.1);
        cpl_test_abs(619.8, cpl_array_get_mean(array[2]), 0.1);
        cpl_test_abs(869.0, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1118.2, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1367.4, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_null(array[6]);
        cpl_test_null(array[7]);
        // ifus out : 2 0 0 0 0 0 1 2
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(1, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);

        data = kmclipm_image_load("ref_data/shift_left_one_slitlet_cut_IFU3_present.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_null(array[0]);
        cpl_test_null(array[1]);
        cpl_test_abs(619.8, cpl_array_get_mean(array[2]), 0.1);
        cpl_test_null(array[3]);
        cpl_test_null(array[4]);
        cpl_test_null(array[5]);
        cpl_test_null(array[6]);
        cpl_test_null(array[7]);
        // ifus out : 2 2 0 2 2 2 2 2
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);

        data = kmclipm_image_load("ref_data/shift_left_one_slitlet_cut_IFU6_7_missing.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_null(array[0]);
        cpl_test_abs(370.6, cpl_array_get_mean(array[1]), 0.1);
        cpl_test_abs(619.8, cpl_array_get_mean(array[2]), 0.1);
        cpl_test_abs(869.0, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1118.2, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_null(array[5]);
        cpl_test_null(array[6]);
        cpl_test_abs(1865.7, cpl_array_get_mean(array[7]), 0.1);
        // ifus out : 2 0 0 0 0 2 2 0
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);
    }
    {
        //
        // test with shift right one slitlet cut, 196 slitlets
        //
        data = kmclipm_image_load("ref_data/shift_right_one_slitlet_cut.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);

        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_abs(185.4, cpl_array_get_mean(array[0]), 0.1);
        cpl_test_abs(434.6, cpl_array_get_mean(array[1]), 0.1);
        cpl_test_abs(683.8, cpl_array_get_mean(array[2]), 0.1);
        cpl_test_abs(933.0, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1182.2, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1431.4, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1680.5, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_null(array[7]);
        // ifus out : 0 0 0 0 0 0 0 2
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);

        data = kmclipm_image_load("ref_data/shift_right_one_slitlet_cut_IFU1_missing.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        kmo_test_verbose_off();
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        kmo_test_verbose_on();
        cpl_test_null(array[0]);
        cpl_test_abs(434.6, cpl_array_get_mean(array[1]), 0.1);
        cpl_test_abs(683.8, cpl_array_get_mean(array[2]), 0.1);
        cpl_test_abs(933.0, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1182.2, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1431.4, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1680.5, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_null(array[7]);
        // ifus out : 2 0 0 0 0 0 0 2
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);

        data = kmclipm_image_load("ref_data/shift_right_one_slitlet_cut_IFU2_missing.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_abs(185.4, cpl_array_get_mean(array[0]), 0.1);
        cpl_test_null(array[1]);
        cpl_test_abs(683.8, cpl_array_get_mean(array[2]), 0.1);
        cpl_test_abs(933.0, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1182.2, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1431.4, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1680.5, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_null(array[7]);
        // ifus out : 0 2 0 0 0 0 0 2
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);
    }
    {
        //
        // test with large shifts, slitlets cut on one side
        //
        data = kmclipm_image_load("ref_data/shift_right_slitlets_cut.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_abs(238.4, cpl_array_get_mean(array[0]), 0.1);
        cpl_test_abs(487.6, cpl_array_get_mean(array[1]), 0.1);
        cpl_test_abs(736.8, cpl_array_get_mean(array[2]), 0.1);
        cpl_test_abs(986.0, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1235.2, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1484.4, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1733.5, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_null(array[7]);
        // ifus out : 0 0 0 0 0 0 0 2
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);

        data = kmclipm_image_load("ref_data/shift_left_slitlets_cut.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_null(array[0]);
        cpl_test_abs(314.6, cpl_array_get_mean(array[1]), 0.1);
        cpl_test_abs(563.8, cpl_array_get_mean(array[2]), 0.1);
        cpl_test_abs(813.0, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1062.2, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1311.4, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1560.5, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_abs(1809.6, cpl_array_get_mean(array[7]), 0.1);
        // ifus out : 2 0 0 0 0 0 0 0
        cpl_test_eq(2, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);
    }
    {
        // valid test (strong rotation, midline of 100)
        data = kmclipm_image_load("ref_data/strong_rotation_100high.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_abs(138.7, cpl_array_get_mean(array[0]), 0.1);
        cpl_test_abs(388.8, cpl_array_get_mean(array[1]), 0.1);
        cpl_test_abs(638.9, cpl_array_get_mean(array[2]), 0.1);
        cpl_test_abs(889.1, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1139.3, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1389.4, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1639.5, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_abs(1889.7, cpl_array_get_mean(array[7]), 0.1);
        // ifus out : 0 0 0 0 0 0 0 0
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);

        // valid test (strong rotation, midline of size 2)
        data = kmclipm_image_load("ref_data/strong_rotation_2high.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_abs(138.7, cpl_array_get_mean(array[0]), 0.1);
        cpl_test_abs(388.8, cpl_array_get_mean(array[1]), 0.1);
        cpl_test_abs(638.9, cpl_array_get_mean(array[2]), 0.1);
        cpl_test_abs(889.1, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1139.3, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1389.4, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1639.5, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_abs(1889.7, cpl_array_get_mean(array[7]), 0.1);
        // ifus out : 0 0 0 0 0 0 0 0
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);

        // valid test (strong rotation, midline of 40)
        data = kmclipm_image_load("ref_data/strong_rotation_40high.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_abs(138.7, cpl_array_get_mean(array[0]), 0.1);
        cpl_test_abs(388.8, cpl_array_get_mean(array[1]), 0.1);
        cpl_test_abs(638.9, cpl_array_get_mean(array[2]), 0.1);
        cpl_test_abs(889.1, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1139.3, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1389.4, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1639.5, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_abs(1889.7, cpl_array_get_mean(array[7]), 0.1);
        // ifus out : 0 0 0 0 0 0 0 0
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);
    }
    {
        // valid test with 224 slitlet edges
        data = kmclipm_image_load("ref_data/well_formed_ifus.fits", CPL_TYPE_FLOAT, 0, 0);
        badpix = cpl_image_duplicate(data);
        kmo_image_fill(badpix, 1);
        // ifu_inactive in : 0 0 0 0 0 0 0 0
        ifu_inactive = cpl_array_new(8, CPL_TYPE_INT);
        kmo_array_fill_int(ifu_inactive, 0);
        cpl_test_nonnull(array = kmo_analyze_flat(data, badpix, ifu_inactive));
        cpl_test_abs(142.4, cpl_array_get_mean(array[0]), 0.1);
        cpl_test_abs(391.6, cpl_array_get_mean(array[1]), 0.1);
        cpl_test_abs(640.8, cpl_array_get_mean(array[2]), 0.1);
        cpl_test_abs(890.0, cpl_array_get_mean(array[3]), 0.1);
        cpl_test_abs(1139.1, cpl_array_get_mean(array[4]), 0.1);
        cpl_test_abs(1388.3, cpl_array_get_mean(array[5]), 0.1);
        cpl_test_abs(1637.5, cpl_array_get_mean(array[6]), 0.1);
        cpl_test_abs(1886.7, cpl_array_get_mean(array[7]), 0.1);
        // ifus out : 0 0 0 0 0 0 0 0
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 0, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 1, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 2, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 3, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 4, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 5, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 6, NULL));
        cpl_test_eq(0, cpl_array_get_int(ifu_inactive, 7, NULL));
        cpl_image_delete(data);
        cpl_image_delete(badpix);
        cpl_array_delete(ifu_inactive);
        for (i = 0; i < 8; i++) cpl_array_delete(array[i]);
        cpl_free(array);
    }
}

/**
    @brief   test for kmo_calc_curvature()
*/
void test_kmo_calc_curvature()
{
    kmo_test_verbose_off();
    kmo_calc_curvature(NULL, NULL, NULL, NULL, 0, NULL, NULL,
                       NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_image *data = kmclipm_image_load("ref_data/well_formed_ifus.fits",
                                     CPL_TYPE_FLOAT, 0, 0);
    kmo_calc_curvature(data, NULL, NULL, NULL, 0, NULL, NULL,
                       NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_image *noise = cpl_image_duplicate(data);
    cpl_image_fill_noise_uniform(noise, 0.0, 1.0);
    kmo_calc_curvature(data, noise, NULL, NULL, 0, NULL, NULL,
                       NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_array* ifu = cpl_array_new(8, CPL_TYPE_INT);
    kmo_array_fill_int(ifu, 0);
    kmo_calc_curvature(data, noise, ifu, NULL, 0, NULL, NULL,
                       NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_image *bad = cpl_image_duplicate(data);
    kmo_image_fill(bad, 1.0);
    kmo_calc_curvature(data, noise, ifu, bad, 0, NULL, NULL,
                       NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_image *xcal = NULL, *ycal = NULL;
    kmo_calc_curvature(data, noise, ifu, bad, 0, &xcal, &ycal,
                       NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    double gapmean, gapsdv, gapmaxdev, slitmean, slitsdv, slitmaxdev;
    kmo_calc_curvature(data, noise, ifu, bad, 0, &xcal, &ycal, &gapmean, &gapsdv,
                       &gapmaxdev, &slitmean, &slitsdv, &slitmaxdev, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_table **edge_par = NULL;
    kmo_calc_curvature(data, noise, ifu, bad, 0, &xcal, &ycal, &gapmean, &gapsdv,
                       &gapmaxdev, &slitmean, &slitsdv, &slitmaxdev, &edge_par);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

    kmo_test_verbose_on();

    cpl_test_abs(7997.86, cpl_image_get_mean(data), 0.01);
    cpl_test_abs(0.500227, cpl_image_get_mean(noise), 0.1);
    cpl_test_abs(1, cpl_image_get_mean(bad), 0.01);
    kmo_calc_curvature(data, noise, ifu, bad, 1, &xcal, &ycal, &gapmean, &gapsdv,
                       &gapmaxdev, &slitmean, &slitsdv, &slitmaxdev, &edge_par);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(0.739485, cpl_image_get_mean(xcal), 0.01*6);
    cpl_test_abs(0.463688, cpl_image_get_mean(ycal), 0.01*16);
    cpl_test_abs(10373.4, cpl_image_get_mean(data), 0.01*20);
    cpl_test_abs(0.504425, cpl_image_get_mean(noise), 0.1);
    cpl_test_abs(1, cpl_image_get_mean(bad), 0.01);
    cpl_test_abs(4.90468, gapmean, 0.01);
    cpl_test_abs(0.130222, gapsdv, 0.01);
    cpl_test_abs(0.342252, gapmaxdev, 0.01*2);
    cpl_test_abs(12.8883, slitmean, 0.01);
    cpl_test_abs(0.131986, slitsdv, 0.01);
    cpl_test_abs(0.40414, slitmaxdev, 0.01);

    double checksum = 0;
    checksum += cpl_table_get_column_mean(edge_par[0], "ID");
    checksum += cpl_table_get_column_mean(edge_par[0], "A0");
    checksum += cpl_table_get_column_mean(edge_par[0], "A1");
    checksum += cpl_table_get_column_mean(edge_par[0], "A2");
    checksum += cpl_table_get_column_mean(edge_par[0], "A3");
    checksum += cpl_table_get_column_mean(edge_par[1], "ID");
    checksum += cpl_table_get_column_mean(edge_par[1], "A0");
    checksum += cpl_table_get_column_mean(edge_par[1], "A1");
    checksum += cpl_table_get_column_mean(edge_par[1], "A2");
    checksum += cpl_table_get_column_mean(edge_par[1], "A3");
    checksum += cpl_table_get_column_mean(edge_par[2], "ID");
    checksum += cpl_table_get_column_mean(edge_par[2], "A0");
    checksum += cpl_table_get_column_mean(edge_par[2], "A1");
    checksum += cpl_table_get_column_mean(edge_par[2], "A2");
    checksum += cpl_table_get_column_mean(edge_par[2], "A3");
    checksum += cpl_table_get_column_mean(edge_par[3], "ID");
    checksum += cpl_table_get_column_mean(edge_par[3], "A0");
    checksum += cpl_table_get_column_mean(edge_par[3], "A1");
    checksum += cpl_table_get_column_mean(edge_par[3], "A2");
    checksum += cpl_table_get_column_mean(edge_par[3], "A3");
    checksum += cpl_table_get_column_mean(edge_par[4], "ID");
    checksum += cpl_table_get_column_mean(edge_par[4], "A0");
    checksum += cpl_table_get_column_mean(edge_par[4], "A1");
    checksum += cpl_table_get_column_mean(edge_par[4], "A2");
    checksum += cpl_table_get_column_mean(edge_par[4], "A3");
    checksum += cpl_table_get_column_mean(edge_par[5], "ID");
    checksum += cpl_table_get_column_mean(edge_par[5], "A0");
    checksum += cpl_table_get_column_mean(edge_par[5], "A1");
    checksum += cpl_table_get_column_mean(edge_par[5], "A2");
    checksum += cpl_table_get_column_mean(edge_par[5], "A3");
    checksum += cpl_table_get_column_mean(edge_par[6], "ID");
    checksum += cpl_table_get_column_mean(edge_par[6], "A0");
    checksum += cpl_table_get_column_mean(edge_par[6], "A1");
    checksum += cpl_table_get_column_mean(edge_par[6], "A2");
    checksum += cpl_table_get_column_mean(edge_par[6], "A3");
    checksum += cpl_table_get_column_mean(edge_par[7], "ID");
    checksum += cpl_table_get_column_mean(edge_par[7], "A0");
    checksum += cpl_table_get_column_mean(edge_par[7], "A1");
    checksum += cpl_table_get_column_mean(edge_par[7], "A2");
    checksum += cpl_table_get_column_mean(edge_par[7], "A3");
//    cpl_test_abs(8177.27, checksum, 0.01);
    cpl_test_abs(8177.24, checksum, 0.01*2);

    int i = 0;
    for (i = 0; i < KMOS_IFUS_PER_DETECTOR; i++) {
        cpl_table_delete(edge_par[i]); edge_par[i] = NULL;
    }
    cpl_free(edge_par);
    cpl_image_delete(xcal);
    cpl_image_delete(ycal);
    cpl_array_delete(ifu);
    cpl_image_delete(bad);
    cpl_image_delete(data);
    cpl_image_delete(noise);
}

/**
    @brief   Test of helper functions for kmo_flat
*/
int main()
{
    cpl_test_init("<kmos-spark@mpe.mpg.de>", CPL_MSG_WARNING);

    test_kmo_create_bad_pix_flat_thresh();
    test_kmo_calc_calib_frames();
    test_kmo_polyfit_edge();
    test_kmo_edge_trace();
    test_kmo_curvature_qc();
    test_kmo_edgepars_to_table();
    test_kmo_flat_interpolate_edge_parameters();
    test_kmo_chebyshev_coefficients();
    test_kmo_split_frame();
    test_kmo_imagelist_get_saturated();
    test_kmo_create_line_profile();
    test_kmo_get_slitedges();
    test_kmo_analize_slitedges();
    test_kmo_analize_slitedges_advanced();
    test_kmo_analyze_flat();
    //test_kmo_calc_edge_pars();  // missing
    test_kmo_calc_curvature();

    return cpl_test_end(0);
}

/** @} */
