/*******************************************************************************
 * JMMC project ( http://www.jmmc.fr ) - Copyright (C) CNRS.
 ******************************************************************************/
/**
 * @file
 * Function to allocate/free OI structures
 */

#define _POSIX_SOURCE 1

/*
 * System Headers 
 */
#include <string.h>
#include <math.h>

/*
 * Local Headers
 */
#include "amdlib.h"
#include "amdlibProtected.h"

/*
 * Local function declarations
 */
static void amdlibFreePhotometry(amdlibPHOTOMETRY *photometry);
static void amdlibFreeVis(amdlibVIS *vis);
static void amdlibFreeVis2(amdlibVIS2 *vis2);
static void amdlibFreeVis3(amdlibVIS3 *vis3);
static void amdlibFreeWavelength(amdlibWAVELENGTH *wave);
static void amdlibFreeOiTarget(amdlibOI_TARGET *target);
static amdlibCOMPL_STAT amdlibReallocatePhotometry(amdlibPHOTOMETRY *photometry,
                                                   const int        nbFrames,
                                                   const int        nbBases,
                                                   const int        nbWlen);
static amdlibCOMPL_STAT amdlibReallocateVis(amdlibVIS *vis,
                                            const int nbFrames,
                                            const int nbBases,
                                            const int nbWlen);
static amdlibCOMPL_STAT amdlibReallocateVis2(amdlibVIS2 *vis2,
                                             const int  nbFrames,
                                             const int  nbBases,
                                             const int  nbWlen);
static amdlibCOMPL_STAT amdlibReallocateVis3(amdlibVIS3 *vis3,
                                             const int nbFrames,
                                             const int nbClosures,
                                             const int nbWlen);



/*
 * Public functions
 */
/**
 * Release memory allocated to store photometry, and reset the structure members
 * to zero.
 *
 * @param photometry pointer to amdlibPHOTOMETRY structure.
 */
void amdlibReleasePhotometry(amdlibPHOTOMETRY *photometry)
{
    amdlibLogTrace("amdlibReleasePhotometry()");
   
    amdlibFreePhotometry(photometry);
    memset (photometry, '\0', sizeof(amdlibPHOTOMETRY));
}

/**
 * Release memory allocated to store visibilities, and reset the structure
 * members to zero.
 *
 * @param vis pointer to amdlibVIS structure.
 */
void amdlibReleaseVis(amdlibVIS *vis)
{
    amdlibLogTrace("amdlibReleaseVis()");
    
    amdlibFreeVis(vis);
    memset (vis, '\0', sizeof(amdlibVIS));
}

/**
 * Release memory allocated to store squared visibilities, and reset the
 * structure members to zero.
 *
 * @param vis2 pointer to amdlibVIS2 structure.
 */
void amdlibReleaseVis2(amdlibVIS2 *vis2)
{
    amdlibLogTrace("amdlibReleaseVis2()");
    
    amdlibFreeVis2(vis2);
    memset (vis2, '\0', sizeof(amdlibVIS2));
}

/**
 * Release memory allocated to store phase closures, and reset the structure
 * members to zero.
 *
 * @param vis3 pointer to amdlibVIS3 structure.
 */
void amdlibReleaseVis3(amdlibVIS3 *vis3)
{
    amdlibLogTrace("amdlibReleaseVis3()");
    
    amdlibFreeVis3(vis3);
    memset (vis3, '\0', sizeof(amdlibVIS3));
}


/**
 * Release memory allocated to store wavelenghts, and reset the structure
 * members to zero.
 *
 * @param wave pointer to amdlibWAVELENGTH structure.
 */
void amdlibReleaseWavelength(amdlibWAVELENGTH *wave)
{
    amdlibLogTrace("amdlibReleaseWavelength()"); 
    amdlibFreeWavelength(wave);
    memset (wave, '\0', sizeof(amdlibWAVELENGTH));
}

/**
 * Release memory allocated to store observed targets, and reset the structure
 * members to zero.
 *
 * @param target pointer to amdlibOI_TARGET structure.
 */
void amdlibReleaseOiTarget(amdlibOI_TARGET *target)
{
    amdlibLogTrace("amdlibReleaseOiTarget()");
    
    amdlibFreeOiTarget(target);
    memset (target, '\0', sizeof(amdlibOI_TARGET));
}

/*
 * Protected functions
 */
/**
 * Allocate memory for storing photometry. 
 *
 * @param photometry pointer to amdlibPHOTOMETRY structure.
 * @param nbFrames number of frames 
 * @param nbBases number of baselines 
 * @param nbWlen number of spectral channels 
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibAllocatePhotometry(amdlibPHOTOMETRY *photometry,
                                          const int        nbFrames,
                                          const int        nbBases,
                                          const int        nbWlen)
{
    int dimArray;
    int i; /* loop */
    void *pointer;
    int nbSamples;

    amdlibLogTrace("amdlibAllocatePhotometry()");
    
    /* First free previous allocated memory */
    if (photometry->thisPtr == photometry)
    {
        amdlibFreePhotometry(photometry);
    }

    /* Init & Update thisPtr */
    photometry->thisPtr =  memset(photometry, '\0', sizeof(*photometry));
    /* Set array size */
    photometry->nbFrames = nbFrames;
    photometry->nbBases  = nbBases;
    photometry->nbWlen   = nbWlen;

    /* Allocate table pointer list  */
    nbSamples = nbFrames * nbBases;
    if (nbSamples<1)
    {
        amdlibLogError("Null-size photometry allocation in amdlibAllocatePhotometry()");
        return amdlibFAILURE;
    }
    photometry->table = calloc(nbSamples, sizeof(*(photometry->table)));
    if (photometry->table == NULL)
    {
        amdlibFreePhotometry(photometry);
        return amdlibFAILURE;
    }

    /* Allocate 'PiMultPj' in each table entry (double) as a whole */
    dimArray = sizeof(double) * nbWlen;
    photometry->table[0].PiMultPj = (double *)calloc(nbSamples, dimArray);
    if (photometry->table[0].PiMultPj == NULL)
    {
        amdlibFreePhotometry(photometry);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = photometry->table[0].PiMultPj; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        photometry->table[i].PiMultPj = pointer;
    }

    /* Allocate 'fluxRatPiPj' in each table entry (double) as a whole */
    dimArray = sizeof(double) * nbWlen;
    photometry->table[0].fluxRatPiPj = (double *)calloc(nbSamples, dimArray);
    if (photometry->table[0].fluxRatPiPj == NULL)
    {
        amdlibFreePhotometry(photometry);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = photometry->table[0].fluxRatPiPj; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        photometry->table[i].fluxRatPiPj = pointer;
    }

    /* Allocate 'sigma2FluxRatPiPj' in each table entry (double) as a whole */
    dimArray = sizeof(double) * nbWlen;
    photometry->table[0].sigma2FluxRatPiPj = (double *)calloc(nbSamples,
                                                              dimArray);
    if (photometry->table[0].sigma2FluxRatPiPj == NULL)
    {
        amdlibFreePhotometry(photometry);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = photometry->table[0].sigma2FluxRatPiPj; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        photometry->table[i].sigma2FluxRatPiPj = pointer;
    }

    /* Allocate 'fluxSumPiPj' in each table entry (double) as a whole */
    dimArray = sizeof(double) * nbWlen;
    photometry->table[0].fluxSumPiPj = (double *)calloc(nbSamples, dimArray);
    if (photometry->table[0].fluxSumPiPj == NULL)
    {
        amdlibFreePhotometry(photometry);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = photometry->table[0].fluxSumPiPj; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        photometry->table[i].fluxSumPiPj = pointer;
    }

    /* Allocate 'sigma2FluxSumPiPj' in each table entry (double) as a whole */
    dimArray = sizeof(double) * nbWlen;
    photometry->table[0].sigma2FluxSumPiPj = (double *)calloc(nbSamples,
                                                              dimArray);
    if (photometry->table[0].sigma2FluxSumPiPj == NULL)
    {
        amdlibFreePhotometry(photometry);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = photometry->table[0].sigma2FluxSumPiPj; 
         i<nbSamples;
         i++, pointer += dimArray)
    {
        photometry->table[i].sigma2FluxSumPiPj = pointer;
    }

    /* Return */
    return amdlibSUCCESS;
}

/**
 * Append amdlibPHOTOMETRY data structure. 
 *
 * @param srcPhotometry pointer to source data structure 
 * @param dstPhotometry pointer to destination data structure (append to) 
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibAppendPhotometry(amdlibPHOTOMETRY *dstPhotometry, 
                                        amdlibPHOTOMETRY *srcPhotometry, 
                                        amdlibERROR_MSG   errMsg)
{
    int sentry;
    int dentry;
    int oldNbFrames = dstPhotometry->nbFrames ;    
    int newNbFrames = oldNbFrames + srcPhotometry->nbFrames;
    size_t arraySize = srcPhotometry->nbWlen * sizeof(double);
    
    amdlibLogTrace("amdlibAppendPhotometry()");
    /* Perform simple checks */
    if (dstPhotometry->nbBases != srcPhotometry->nbBases)
    {
        amdlibSetErrMsg("Different number of bases");
        return amdlibFAILURE;
    }
    if (dstPhotometry->nbWlen != srcPhotometry->nbWlen)
    {
        amdlibSetErrMsg("Different numbers of "
                        "wavelengths (%d and %d) ", srcPhotometry->nbWlen,
                        dstPhotometry->nbWlen);
        return amdlibFAILURE;
    }

    /* Reallocate memory to store additional data */
    if (amdlibReallocatePhotometry(dstPhotometry, newNbFrames, 
                                   srcPhotometry->nbBases,
                                   srcPhotometry->nbWlen) != amdlibSUCCESS)
    {
        amdlibSetErrMsg("Could not reallocate memory for photometry");
        return amdlibFAILURE;        
    }
    

    /* Append fields allocated dynamically */
    dentry = oldNbFrames * dstPhotometry->nbBases;
    for (sentry = 0; 
         sentry < srcPhotometry->nbFrames * srcPhotometry->nbBases; 
         sentry++)
    {
        memcpy(dstPhotometry->table[dentry].fluxSumPiPj,
               srcPhotometry->table[sentry].fluxSumPiPj, arraySize);
        memcpy(dstPhotometry->table[dentry].sigma2FluxSumPiPj,
               srcPhotometry->table[sentry].sigma2FluxSumPiPj, arraySize);

        memcpy(dstPhotometry->table[dentry].fluxRatPiPj, 
               srcPhotometry->table[sentry].fluxRatPiPj, arraySize);
        memcpy(dstPhotometry->table[dentry].sigma2FluxRatPiPj,
               srcPhotometry->table[sentry].sigma2FluxRatPiPj, arraySize);

        memcpy(dstPhotometry->table[dentry].PiMultPj, 
               srcPhotometry->table[sentry].PiMultPj, arraySize);

        dentry++;
    }
    
    return amdlibSUCCESS;
}

/**
 * Insert an amdlibPHOTOMETRY data structure in another (larger) one. 
 *
 * @param srcPhotometry pointer to source data structure 
 * @param dstPhotometry pointer to destination data structure (insert in)
 * @param index index in structure where to insert 
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibInsertPhotometry(amdlibPHOTOMETRY *dstPhotometry, 
                                        amdlibPHOTOMETRY *srcPhotometry,
                                        int insertIndex,
                                        amdlibERROR_MSG   errMsg)
{
    int sentry;
    int dentry;
    int dstNbFrames = dstPhotometry->nbFrames ;    
    int finalIndex = insertIndex + srcPhotometry->nbFrames;
    size_t arraySize = srcPhotometry->nbWlen * sizeof(double);
    
    amdlibLogTrace("amdlibInsertPhotometry()");
    /* Perform simple checks */
    if (insertIndex<0 || insertIndex>=dstPhotometry->nbFrames)
    {
        amdlibSetErrMsg("Invalid insertion index %d for amdlibInsertPhotometry",insertIndex);
        return amdlibFAILURE;
    }
    if (dstPhotometry->nbBases != srcPhotometry->nbBases)
    {
        amdlibSetErrMsg("Different number of bases");
        return amdlibFAILURE;
    }
    if (dstPhotometry->nbWlen != srcPhotometry->nbWlen)
    {
        amdlibSetErrMsg("Different numbers of "
                        "wavelengths (%d and %d) ", srcPhotometry->nbWlen,
                        dstPhotometry->nbWlen);
        return amdlibFAILURE;
    }
    if (dstNbFrames < finalIndex)
    {
        amdlibSetErrMsg("Number of frames (%d) in destination structure"
                        "too small to enable insertion of %d frames at position %d", 
                        dstNbFrames,srcPhotometry->nbFrames,insertIndex);
        return amdlibFAILURE;
    }

    /* Insert src in dst at frame insertIndex */
    dentry = insertIndex * dstPhotometry->nbBases;
    for (sentry = 0; 
         sentry < srcPhotometry->nbFrames * srcPhotometry->nbBases; 
         sentry++)
    {
        memcpy(dstPhotometry->table[dentry].fluxSumPiPj,
               srcPhotometry->table[sentry].fluxSumPiPj, arraySize);
        memcpy(dstPhotometry->table[dentry].sigma2FluxSumPiPj,
               srcPhotometry->table[sentry].sigma2FluxSumPiPj, arraySize);

        memcpy(dstPhotometry->table[dentry].fluxRatPiPj, 
               srcPhotometry->table[sentry].fluxRatPiPj, arraySize);
        memcpy(dstPhotometry->table[dentry].sigma2FluxRatPiPj,
               srcPhotometry->table[sentry].sigma2FluxRatPiPj, arraySize);

        memcpy(dstPhotometry->table[dentry].PiMultPj, 
               srcPhotometry->table[sentry].PiMultPj, arraySize);

        dentry++;
    }
    
    return amdlibSUCCESS;
}

/**
 * Merge photometries.
 *
 * This function merges photometries and stores the result in the first one.
 *
 * @param phot1 pointer to first photometry structure.
 * @param phot2 pointer to second photometry structure (to merge).
 * @param isInverted boolean indicating in which order the structures have to 
 * be merged.
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibMergePhotometry(amdlibPHOTOMETRY *phot1,
                                       amdlibPHOTOMETRY *phot2,
                                       amdlibBOOLEAN    isInverted,
                                       amdlibERROR_MSG  errMsg)
{
    amdlibPHOTOMETRY mergedPhot = {NULL};
    amdlibPHOTOMETRY *p1, *p2;

    amdlibLogTrace("amdlibMergePhotometry()");
    
    /* Check phot1 and phot2 have same number of baselines */
    if (phot1->nbBases != phot2->nbBases)
    {
        amdlibSetErrMsg("Different number of baselines (%d and %d)", 
                        phot1->nbBases, phot2->nbBases);
        return amdlibFAILURE;
    }
    
    if (isInverted == amdlibTRUE)
    {
        p1 = phot2;
        p2 = phot1;
    }
    else
    {
        p1 = phot1;
        p2 = phot2;
    }

    /* Allocate memory for dstPhot */
    if (amdlibAllocatePhotometry(&mergedPhot, p1->nbFrames, p1->nbBases, 
                                 p1->nbWlen + p2->nbWlen) != amdlibSUCCESS)
    {
        amdlibSetErrMsg("Could not allocate memory for photometry ");
        return amdlibFAILURE;
    }

    if (amdlibCopyPhotFrom(&mergedPhot, p1, 0, p1->nbWlen,
                           errMsg) != amdlibSUCCESS)
    {
        return amdlibFAILURE;
    }
    
    if (amdlibCopyPhotFrom(&mergedPhot, p2, p1->nbWlen, p2->nbWlen,
                           errMsg) != amdlibSUCCESS)
    {
        return amdlibFAILURE;
    }
    
    free(phot1->table[0].fluxSumPiPj);
    free(phot1->table[0].sigma2FluxSumPiPj);
    free(phot1->table[0].fluxRatPiPj);
    free(phot1->table[0].sigma2FluxRatPiPj);
    free(phot1->table[0].PiMultPj);
    free(phot1->table);
    phot1->nbWlen = mergedPhot.nbWlen;
    phot1->nbFrames = mergedPhot.nbFrames;
    phot1->table = mergedPhot.table;
    
    return amdlibSUCCESS;
}

/**
 * Duplicate photometry if index = 0 or add information relative to wavelengths
 * in first structure else.
 *
 * @param dstPhot pointer to first photometry structure.
 * @param srcPhot pointer to second photometry structure (to be copied).
 * @param index index on the location to place information.
 * @param nbOfElem number of elements to store.
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibCopyPhotFrom(amdlibPHOTOMETRY *dstPhot,
                                    amdlibPHOTOMETRY *srcPhot,
                                    int              index,
                                    int              nbOfElem,
                                    amdlibERROR_MSG  errMsg)
{
    int i, j;
    amdlibLogTrace("amdlibCopyPhotFrom()");
    
    if ((dstPhot->thisPtr == NULL) && (index != 0))
    {
        amdlibSetErrMsg("Could not copy non-initialized data from index %d", 
                        index);
        return amdlibFAILURE;
    }

    if (srcPhot->thisPtr == NULL)
    {
        /* Nothing to do */
        return amdlibSUCCESS;
    }

    if (index == 0)
    {
        for (i=0; i < srcPhot->nbFrames * srcPhot->nbBases; i++)
        {
            for (j=0; j < srcPhot->nbWlen; j++)
            {
                dstPhot->table[i].fluxSumPiPj[j] = 
                    srcPhot->table[i].fluxSumPiPj[j];
                dstPhot->table[i].sigma2FluxSumPiPj[j] = 
                    srcPhot->table[i].sigma2FluxSumPiPj[j];
                dstPhot->table[i].fluxRatPiPj[j] = 
                    srcPhot->table[i].fluxRatPiPj[j];
                dstPhot->table[i].sigma2FluxRatPiPj[j] = 
                    srcPhot->table[i].sigma2FluxRatPiPj[j];
                dstPhot->table[i].PiMultPj[j] = 
                    srcPhot->table[i].PiMultPj[j];
            }
        }
    }
    else
    {
        if (dstPhot->nbFrames != srcPhot->nbFrames)
        {
            amdlibSetErrMsg("Different number of frames! (%d and %d)",
                            dstPhot->nbFrames, srcPhot->nbFrames);
            return amdlibFAILURE;
        }
        if (dstPhot->nbBases != srcPhot->nbBases)
        {
            amdlibSetErrMsg("Different of bases (%d and %d)",
                            dstPhot->nbBases, srcPhot->nbBases);
            return amdlibFAILURE;        
        }
        for (i=0; i < srcPhot->nbFrames * srcPhot->nbBases; i++)
        {
            for (j = 0; j < nbOfElem; j++)
            {
                dstPhot->table[i].fluxSumPiPj[index+j] = 
                    srcPhot->table[i].fluxSumPiPj[j];
                
                dstPhot->table[i].sigma2FluxSumPiPj[index+j] = 
                    srcPhot->table[i].sigma2FluxSumPiPj[j];

                dstPhot->table[i].fluxRatPiPj[index+j] = 
                    srcPhot->table[i].fluxRatPiPj[j];

                dstPhot->table[i].sigma2FluxRatPiPj[index+j] = 
                    srcPhot->table[i].sigma2FluxRatPiPj[j];

                dstPhot->table[i].PiMultPj[index+j] = 
                    srcPhot->table[i].PiMultPj[j];
            }
        }
    }
    return amdlibSUCCESS;
}

/**
 * Display photometry structure.
 *
 * @param photometry pointer to amdlibPHOTOMETRY structure.
 */
void amdlibDisplayPhotometry(amdlibPHOTOMETRY *photometry)
{
    int nbFrames, nbBases, nbWlen;
    int iFrame, iBase, iCell, iWave;
    amdlibPHOTOMETRY_TABLE_ENTRY cell;
    double fluxSumPiPj;
    double sigma2FluxSumPiPj;
    double fluxRatPiPj;
    double sigma2FluxRatPiPj;
    double PiMultPj;
    
    amdlibLogTrace("amdlibDisplayPhotometry()");

    /* Display number of frames */
    nbFrames = photometry->nbFrames;
    printf("nbFrames = %d\n", nbFrames);
    
    /* Display number of base */
    nbBases = photometry->nbBases;
    printf("nbBases = %d\n", nbBases);

    /* Display number of wavelength */
    nbWlen = photometry->nbWlen;
    printf("nbWlen = %d\n", nbWlen);

    /* Display different arrays[nbFrames][nbBases][nbWlen] */
    for (iFrame = 0; iFrame < nbFrames; iFrame++)
    {
        for (iBase = 0; iBase < nbBases; iBase++)
        {
            /* Set cell[iFrame][iBase] */
            iCell = iFrame * nbBases + iBase;
            cell =  photometry->table[iCell];
            printf("---> cell frame/base[%d][%d]\n", iFrame, iBase);
            
            /* Display arrays[nbWlen] */
            for (iWave = 0; iWave < nbWlen; iWave++)
            {
                /* fluxSumPiPj */
                fluxSumPiPj = cell.fluxSumPiPj[iWave];
                printf("fluxSumPiPj[%d][%d][%d] = %f - ", iFrame, iBase, iWave, 
                                                        fluxSumPiPj);
                /* sigma2FluxSumPiPj */
                sigma2FluxSumPiPj = cell.sigma2FluxSumPiPj[iWave];
                printf("sigma2FluxSumPiPj[%d][%d][%d] = %f\n", iFrame, iBase, 
                                                    iWave, sigma2FluxSumPiPj);

                /* fluxRatPiPj */
                fluxRatPiPj = cell.fluxRatPiPj[iWave];
                printf("fluxRatPiPj[%d][%d][%d] = %f - ", iFrame, iBase, 
                                                        iWave, fluxRatPiPj);
                
                /* sigma2FluxRatPiPj */
                sigma2FluxRatPiPj = cell.sigma2FluxRatPiPj[iWave];
                printf("sigma2FluxRatPiPj[%d][%d][%d] = %f\n", iFrame, iBase, 
                                                    iWave, sigma2FluxRatPiPj);

                /* PiMultPj */
                PiMultPj = cell.PiMultPj[iWave];
                printf("PiMultPj[%d][%d][%d] = %f\n", iFrame, iBase, iWave, 
                                                        PiMultPj);
            }
        }
    }
}

/**
 * Split amdlibPHOTOMETRY input data structure into 3 structures, 1 per spectral
 * band. Each new structure only contains information relative to its associated
 * spectral band .
 *
 * @param srcPhot pointer on photometry structure to split.
 * @param dstPhot array of splitted photometry structures.
 * @param idxFirstWlen array containing the indexes of the first wavelength
 *        belonging to each spectral band.
 * @param nbWlen array containing the number of wavelengths per spectral band.
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibSplitPhot(amdlibPHOTOMETRY *srcPhot,
                                 amdlibPHOTOMETRY *dstPhot,
                                 int              *idxFirstWlen,
                                 int              *nbWlen,
                                 amdlibERROR_MSG  errMsg)
{
    int band, index, i, j;

    amdlibLogTrace("amdlibSplitPhot()");
    for (band=amdlibJ_BAND; band <= amdlibK_BAND; band++)
    {
        if (nbWlen[band] == 0)
        {
            dstPhot[band].thisPtr = NULL;
        }
        else
        {
            /* Allocate memory for dstPhot */
            if (amdlibAllocatePhotometry(&dstPhot[band], srcPhot->nbFrames, 
                                         srcPhot->nbBases, 
                                         nbWlen[band]) != amdlibSUCCESS)
            {
                amdlibSetErrMsg("Could not allocate memory for photometry ");
                return amdlibFAILURE;
            }
            for (i=0; i < srcPhot->nbFrames * srcPhot->nbBases; i++)
            {
                index = idxFirstWlen[band];
                for (j=0; j < nbWlen[band]; j++)
                {
                    dstPhot[band].table[i].fluxSumPiPj[j] = 
                        srcPhot->table[i].fluxSumPiPj[index];
                    dstPhot[band].table[i].sigma2FluxSumPiPj[j] = 
                        srcPhot->table[i].sigma2FluxSumPiPj[index];
                    dstPhot[band].table[i].fluxRatPiPj[j] = 
                        srcPhot->table[i].fluxRatPiPj[index];
                    dstPhot[band].table[i].sigma2FluxRatPiPj[j] = 
                        srcPhot->table[i].sigma2FluxRatPiPj[index];
                    dstPhot[band].table[i].PiMultPj[j] = 
                        srcPhot->table[i].PiMultPj[index];
                    index++;
                }
            }

        }
    }
    return amdlibSUCCESS;
}

/**
 * Allocate memory for storing visibilities. 
 *
 * @param vis pointer to amdlibVIS structure.
 * @param nbFrames number of frames 
 * @param nbBases number of baselines 
 * @param nbWlen number of spectral channels 
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibAllocateVis(amdlibVIS *vis,
                                   const int nbFrames,
                                   const int nbBases,
                                   const int nbWlen)
{
    int dimArray;
    int i; /* loop */
    void *pointer;
    int nbSamples;
    int band;

    amdlibLogTrace("amdlibAllocateVis()");
    
    /* First free previous allocated memory */
    if (vis->thisPtr == vis)
    {
        amdlibFreeVis(vis);
    }

    /* Init & Update thisPtr */
    vis->thisPtr =  memset(vis, '\0', sizeof(*vis));
    /* Set array size */
    vis->nbFrames = nbFrames;
    vis->nbBases = nbBases;
    vis->nbWlen   = nbWlen;

    /* Allocate table pointer list  */
    nbSamples = nbFrames * nbBases;
    vis->table = calloc(nbSamples, sizeof(*(vis->table)));
    if (vis->table == NULL)
    {
        amdlibFreeVis(vis);
        return amdlibFAILURE;
    }

    /* Allocate 'vis' in each table entry (amdlibCOMPLEX) as a whole */
    dimArray = sizeof(amdlibCOMPLEX) * nbWlen;
    vis->table[0].vis = (amdlibCOMPLEX *)calloc(nbSamples, dimArray);
    if (vis->table[0].vis == NULL)
    {
        amdlibFreeVis(vis);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis->table[0].vis; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        vis->table[i].vis = pointer;
    }

    /* Allocate 'sigma2Vis' in each table entry (amdlibCOMPLEX) as a whole */
    dimArray = sizeof(amdlibCOMPLEX) * nbWlen;
    vis->table[0].sigma2Vis = (amdlibCOMPLEX *)calloc(nbSamples, dimArray);
    if (vis->table[0].sigma2Vis == NULL)
    {
        amdlibFreeVis(vis);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis->table[0].sigma2Vis; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        vis->table[i].sigma2Vis = pointer;
    }

    /* Allocate 'visCovRI' in each table entry (double) as a whole */
    dimArray = sizeof(double) * nbWlen;
    vis->table[0].visCovRI = (double *)calloc(nbSamples, dimArray);
    if (vis->table[0].visCovRI == NULL)
    {
        amdlibFreeVis(vis);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis->table[0].visCovRI; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        vis->table[i].visCovRI = pointer;
    }

    /* Allocate 'diffVisAmp' in each table entry (double) as a whole */
    dimArray = sizeof(double) * nbWlen;
    vis->table[0].diffVisAmp = (double *)calloc(nbSamples, dimArray);
    if (vis->table[0].diffVisAmp == NULL)
    {
        amdlibFreeVis(vis);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis->table[0].diffVisAmp; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        vis->table[i].diffVisAmp = pointer;
    }

    /* Allocate 'diffVisAmpErr' in each table entry (double) as a whole */
    dimArray = sizeof(double) * nbWlen;
    vis->table[0].diffVisAmpErr = (double *)calloc(nbSamples, dimArray);
    if (vis->table[0].diffVisAmpErr == NULL)
    {
        amdlibFreeVis(vis);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis->table[0].diffVisAmpErr; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        vis->table[i].diffVisAmpErr = pointer;
    }

    /* Allocate 'diffVisPhi' in each table entry (double) as a whole */
    dimArray = sizeof(double) * nbWlen;
    vis->table[0].diffVisPhi = (double *)calloc(nbSamples, dimArray);
    if (vis->table[0].diffVisPhi == NULL)
    {
        amdlibFreeVis(vis);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis->table[0].diffVisPhi; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        vis->table[i].diffVisPhi = pointer;
    }

    /* Allocate 'diffVisPhiErr' in each table entry (double) as a whole */
    dimArray = sizeof(double) * nbWlen;
    vis->table[0].diffVisPhiErr = (double *)calloc(nbSamples, dimArray);
    if (vis->table[0].diffVisPhiErr == NULL)
    {
        amdlibFreeVis(vis);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis->table[0].diffVisPhiErr; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        vis->table[i].diffVisPhiErr = pointer;
    }
    
    /* Set all band flags to false */
    for (i=0; i < nbSamples; i++)
    {
        for (band = 0; band < amdlibNB_BANDS; band++)
        {
            vis->table[i].bandFlag[band] = amdlibFALSE;
        }
    }
    
    /* Allocate 'flag' in each table entry (boolean) as a whole */
    dimArray = sizeof(amdlibBOOLEAN) * nbWlen;
    vis->table[0].flag = (amdlibBOOLEAN *)calloc(nbSamples, dimArray);
    if (vis->table[0].flag == NULL)
    {
        amdlibFreeVis(vis);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis->table[0].flag; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        vis->table[i].flag = pointer;
    }

    /* Return */
    return amdlibSUCCESS;
}



/**
 * Append amdlibVIS data structure. 
 *
 * @param srcVis pointer to source data structure 
 * @param dstVis pointer to destination data structure  (append to) 
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibAppendVis(amdlibVIS       *dstVis, 
                                 amdlibVIS       *srcVis, 
                                 amdlibERROR_MSG errMsg)
{
    int sentry;
    int dentry;
    int band = 0;
    size_t visSize = srcVis->nbWlen * sizeof(amdlibCOMPLEX);
    size_t doubleArraySize = srcVis->nbWlen * sizeof(double);
    int oldNbFrames = dstVis->nbFrames;
    
    amdlibLogTrace("amdlibAppendVis()");
    /* Perform simple checks */
    if (dstVis->nbBases != srcVis->nbBases)
    {
        amdlibSetErrMsg("Different number of bases (%d and %d)",
                        srcVis->nbBases, dstVis->nbBases);
        return amdlibFAILURE;
    }
    if (dstVis->nbWlen != srcVis->nbWlen)
    {
        amdlibSetErrMsg("Different number of wavelengths (%d and %d)",
                        srcVis->nbWlen, dstVis->nbWlen);
        return amdlibFAILURE;
    }

    
    /* Reallocate memory to store additional data */
    if (amdlibReallocateVis(dstVis, oldNbFrames + srcVis->nbFrames,
                            srcVis->nbBases, srcVis->nbWlen) != amdlibSUCCESS)
    {
        amdlibSetErrMsg("Could not reallocate memory for visibility structure");
        return amdlibFAILURE;
    }
    
    /* Append fields allocated dynamically */
    dentry = oldNbFrames * dstVis->nbBases;
    for (sentry = 0; sentry < srcVis->nbFrames * srcVis->nbBases; sentry++)
    {
        dstVis->table[dentry].targetId = srcVis->table[sentry].targetId;

        dstVis->table[dentry].time = srcVis->table[sentry].time;

        dstVis->table[dentry].dateObsMJD = srcVis->table[sentry].dateObsMJD;

        dstVis->table[dentry].expTime = srcVis->table[sentry].expTime;

        dstVis->table[dentry].uCoord = srcVis->table[sentry].uCoord;

        dstVis->table[dentry].vCoord = srcVis->table[sentry].vCoord;

        dstVis->table[dentry].stationIndex[0] =
            srcVis->table[sentry].stationIndex[0];

        dstVis->table[dentry].stationIndex[1] =
            srcVis->table[sentry].stationIndex[1];

        for (band=0; band < amdlibNB_BANDS; band++)
        {
            dstVis->table[dentry].bandFlag[band] = 
                srcVis->table[sentry].bandFlag[band];
            dstVis->table[dentry].frgContrastSnrArray[band] = 
                srcVis->table[sentry].frgContrastSnrArray[band];
        }
        dstVis->table[dentry].frgContrastSnr = 
            srcVis->table[sentry].frgContrastSnr;
        
        memcpy(dstVis->table[dentry].vis, srcVis->table[sentry].vis, visSize);
        memcpy(dstVis->table[dentry].sigma2Vis,
               srcVis->table[sentry].sigma2Vis, visSize);

        memcpy(dstVis->table[dentry].visCovRI, srcVis->table[sentry].visCovRI, 
               doubleArraySize);
        memcpy(dstVis->table[dentry].diffVisAmp, 
               srcVis->table[sentry].diffVisAmp, doubleArraySize);
        memcpy(dstVis->table[dentry].diffVisAmpErr, 
               srcVis->table[sentry].diffVisAmpErr, doubleArraySize);
        memcpy(dstVis->table[dentry].diffVisPhi, 
               srcVis->table[sentry].diffVisPhi, doubleArraySize);
        memcpy(dstVis->table[dentry].diffVisPhiErr,
               srcVis->table[sentry].diffVisPhiErr, doubleArraySize);
        
        memcpy(dstVis->table[dentry].flag, srcVis->table[sentry].flag, 
               srcVis->nbWlen * sizeof(amdlibBOOLEAN));

        dentry++;
    }

    return amdlibSUCCESS;
}


/**
 * Insert amdlibVIS data structure. 
 *
 * @param srcVis pointer to source data structure 
 * @param dstVis pointer to destination data structure  (insert at) 
 * @param insertIndex 
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibInsertVis(amdlibVIS       *dstVis, 
                                 amdlibVIS       *srcVis,
                                 int insertIndex,
                                 amdlibERROR_MSG errMsg)
{
    int sentry;
    int dentry;
    int band = 0;
    size_t visSize = srcVis->nbWlen * sizeof(amdlibCOMPLEX);
    size_t doubleArraySize = srcVis->nbWlen * sizeof(double);
    int dstNbFrames = dstVis->nbFrames;
    int finalIndex = insertIndex + srcVis->nbFrames;
    
    amdlibLogTrace("amdlibInsertVis()");
    /* Perform simple checks */
    if (insertIndex<0 || insertIndex>=dstVis->nbFrames)
    {
        amdlibSetErrMsg("Invalid insertion index %d for amdlibInsertVis",insertIndex);
        return amdlibFAILURE;
    }
    if (dstVis->nbBases != srcVis->nbBases)
    {
        amdlibSetErrMsg("Different number of bases (%d and %d)",
                        srcVis->nbBases, dstVis->nbBases);
        return amdlibFAILURE;
    }
    if (dstVis->nbWlen != srcVis->nbWlen)
    {
        amdlibSetErrMsg("Different number of wavelengths (%d and %d)",
                        srcVis->nbWlen, dstVis->nbWlen);
        return amdlibFAILURE;
    }
    if (dstNbFrames < finalIndex)
    {
        amdlibSetErrMsg("Number of frames (%d) in destination structure"
                        "too small to enable insertion of %d frames at position %d", 
                        dstNbFrames,srcVis->nbFrames,insertIndex);
        return amdlibFAILURE;
    }

    strcpy(dstVis->dateObs, srcVis->dateObs);
    /* Insert src in dst at frame insertIndex */
    dentry = insertIndex * dstVis->nbBases;
    for (sentry = 0; sentry < srcVis->nbFrames * srcVis->nbBases; sentry++)
    {
        dstVis->table[dentry].targetId = srcVis->table[sentry].targetId;

        dstVis->table[dentry].time = srcVis->table[sentry].time;

        dstVis->table[dentry].dateObsMJD = srcVis->table[sentry].dateObsMJD;

        dstVis->table[dentry].expTime = srcVis->table[sentry].expTime;

        dstVis->table[dentry].uCoord = srcVis->table[sentry].uCoord;

        dstVis->table[dentry].vCoord = srcVis->table[sentry].vCoord;

        dstVis->table[dentry].stationIndex[0] =
            srcVis->table[sentry].stationIndex[0];

        dstVis->table[dentry].stationIndex[1] =
            srcVis->table[sentry].stationIndex[1];

        memcpy(dstVis->table[dentry].vis, srcVis->table[sentry].vis, visSize);
        memcpy(dstVis->table[dentry].sigma2Vis,
               srcVis->table[sentry].sigma2Vis, visSize);

        memcpy(dstVis->table[dentry].visCovRI, srcVis->table[sentry].visCovRI, 
               doubleArraySize);
        memcpy(dstVis->table[dentry].diffVisAmp, 
               srcVis->table[sentry].diffVisAmp, doubleArraySize);
        memcpy(dstVis->table[dentry].diffVisAmpErr, 
               srcVis->table[sentry].diffVisAmpErr, doubleArraySize);
        memcpy(dstVis->table[dentry].diffVisPhi, 
               srcVis->table[sentry].diffVisPhi, doubleArraySize);
        memcpy(dstVis->table[dentry].diffVisPhiErr,
               srcVis->table[sentry].diffVisPhiErr, doubleArraySize);

        for (band=0; band < amdlibNB_BANDS; band++)
        {
            dstVis->table[dentry].frgContrastSnrArray[band] = 
                srcVis->table[sentry].frgContrastSnrArray[band];
            dstVis->table[dentry].bandFlag[band] = 
                srcVis->table[sentry].bandFlag[band];
        }

        dstVis->table[dentry].frgContrastSnr = 
            srcVis->table[sentry].frgContrastSnr;
        
        memcpy(dstVis->table[dentry].flag, srcVis->table[sentry].flag, 
               srcVis->nbWlen * sizeof(amdlibBOOLEAN));

        dentry++;
    }
    return amdlibSUCCESS;
}


/**
 * Merge OI-VIS. 
 *
 * @param vis1 pointer to first OI-VIS structure.
 * @param vis2 pointer to second OI-VIS structure (to merge).
 * @param isInverted boolean indicating in which order the structures have to 
 * be merged.
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibMergeVis(amdlibVIS       *vis1,
                                amdlibVIS       *vis2,
                                amdlibBOOLEAN   isInverted,
                                amdlibERROR_MSG errMsg)
{
    amdlibVIS mergedVis = {NULL};
    amdlibVIS *v1, *v2;

    amdlibLogTrace("amdlibMergeVis()");
    
    /* Check phot1 and phot2 have same number of baselines */
    if (vis1->nbBases != vis2->nbBases)
    {
        amdlibSetErrMsg("Different number of baselines (%d and %d)", 
                        vis1->nbBases, vis2->nbBases);
        return amdlibFAILURE;
    } 

    if (isInverted == amdlibTRUE)
    {
        v1 = vis2;
        v2 = vis1;
    }
    else
    {
        v1 = vis1;
        v2 = vis2;
    }
    
    /* Allocate memory for mergedVis */
    mergedVis.thisPtr = NULL;
    if (amdlibAllocateVis(&mergedVis, v1->nbFrames, v1->nbBases, 
                          v1->nbWlen + v2->nbWlen) != amdlibSUCCESS)
    {
        amdlibSetErrMsg("Could not allocate memory for merged OI-VIS structure");
        return amdlibFAILURE;
    }
    
    if (amdlibCopyVisFrom(&mergedVis, v1, 0, v1->nbWlen, 
                          errMsg) != amdlibSUCCESS)
    {
        return amdlibFAILURE;
    }

    if (amdlibCopyVisFrom(&mergedVis, v2, v1->nbWlen, v2->nbWlen,
                          errMsg) != amdlibSUCCESS)
    {
        return amdlibFAILURE;
    }

    free(vis1->table[0].vis);
    free(vis1->table[0].sigma2Vis);
    free(vis1->table[0].visCovRI);
    free(vis1->table[0].diffVisAmp);
    free(vis1->table[0].diffVisAmpErr);
    free(vis1->table[0].diffVisPhi);
    free(vis1->table[0].diffVisPhiErr);
    free(vis1->table[0].flag);
    free(vis1->table);
    vis1->nbWlen = mergedVis.nbWlen;
    vis1->nbFrames = mergedVis.nbFrames;
    vis1->table = mergedVis.table;

    return amdlibSUCCESS;
}

/**
 * Split amdlibVIS input data structure into 3 structures, 1 per spectral
 * band. Each new structure only contains information relative to its associated
 * spectral band .
 *
 * @param srcVis pointer on visibility structure to split.
 * @param dstVis array of splitted visibility structures.
 * @param idxFirstWlen array containing the indexes of the first wavelength
 *        belonging to each spectral band.
 * @param nbWlen array containing the number of wavelengths per spectral band.
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibSplitVis(amdlibVIS        *srcVis,
                                amdlibVIS        *dstVis,
                                int              *idxFirstWlen,
                                int              *nbWlen,
                                amdlibERROR_MSG  errMsg)
{
    int band, index, i, j;

    amdlibLogTrace("amdlibSplitVis()");
    for (band=amdlibJ_BAND; band <= amdlibK_BAND; band++)
    {
        if (nbWlen[band] == 0)
        {
            dstVis[band].thisPtr = NULL;
        }
        else
        {
            /* Allocate memory for dstVis */
            if (amdlibAllocateVis(&dstVis[band], srcVis->nbFrames, 
                                  srcVis->nbBases, 
                                  nbWlen[band]) != amdlibSUCCESS)
            {
                amdlibSetErrMsg("Could not allocate memory for oivis");
                return amdlibFAILURE;
            }
            
            strcpy(dstVis[band].dateObs, srcVis->dateObs);
            for (i=0; i < srcVis->nbFrames * srcVis->nbBases; i++)
            {
                dstVis[band].table[i].targetId = srcVis->table[i].targetId;
                dstVis[band].table[i].time = srcVis->table[i].time;
                dstVis[band].table[i].dateObsMJD = srcVis->table[i].dateObsMJD;
                dstVis[band].table[i].expTime = srcVis->table[i].expTime;
                dstVis[band].table[i].uCoord = srcVis->table[i].uCoord;
                dstVis[band].table[i].vCoord = srcVis->table[i].vCoord;
                dstVis[band].table[i].stationIndex[0] = 
                    srcVis->table[i].stationIndex[0];
                dstVis[band].table[i].stationIndex[1] = 
                    srcVis->table[i].stationIndex[1];

                for (j=amdlibJ_BAND; j <= amdlibK_BAND; j++)
                {
                    dstVis[band].table[i].bandFlag[j] = 
                        srcVis->table[i].bandFlag[j];
                    dstVis[band].table[i].frgContrastSnrArray[j] = 
                        srcVis->table[i].frgContrastSnrArray[j];
                }
                dstVis[band].table[i].frgContrastSnr = 
                    srcVis->table[i].frgContrastSnr;

                index = idxFirstWlen[band];
                for (j=0; j < nbWlen[band]; j++)
                {
                    dstVis[band].table[i].vis[j].re = 
                        srcVis->table[i].vis[index].re;
                    dstVis[band].table[i].vis[j].im = 
                        srcVis->table[i].vis[index].im;
                    dstVis[band].table[i].sigma2Vis[j].re = 
                        srcVis->table[i].sigma2Vis[index].re;
                    dstVis[band].table[i].sigma2Vis[j].im = 
                        srcVis->table[i].sigma2Vis[index].im;
                    dstVis[band].table[i].visCovRI[j] = 
                        srcVis->table[i].visCovRI[index];
                    dstVis[band].table[i].diffVisAmp[j] = 
                        srcVis->table[i].diffVisAmp[index];
                    dstVis[band].table[i].diffVisAmpErr[j] = 
                        srcVis->table[i].diffVisAmpErr[index];
                    dstVis[band].table[i].diffVisPhi[j] = 
                        srcVis->table[i].diffVisPhi[index];
                    dstVis[band].table[i].diffVisPhiErr[j] = 
                        srcVis->table[i].diffVisPhiErr[index];
                    dstVis[band].table[i].flag[j] = 
                        srcVis->table[i].flag[index];
                    index++;
                }
            }

        }
    }
    return amdlibSUCCESS;
}

/**
 * Duplicate visibility if index = 0 or add information relative to wavelengths
 * in first structure else.
 *
 * @param dstVis pointer to first visibility structure.
 * @param srcVis pointer to second visibility structure (to be copied).
 * @param index index on the location to place information.
 * @param nbOfElem number of elements to store.
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibCopyVisFrom(amdlibVIS       *dstVis,
                                   amdlibVIS       *srcVis,
                                   int             index,
                                   int             nbOfElem,
                                   amdlibERROR_MSG errMsg)
{
    int i, j;
    amdlibLogTrace("amdlibCopyVisFrom()");
    
    if ((dstVis->thisPtr == NULL) && (index != 0))
    {
        amdlibSetErrMsg("Could not copy non-initialized data from index %d",
                        index);
        return amdlibFAILURE;
    }

    if (srcVis->thisPtr == NULL)
    {
        /* Nothing to do */
        return amdlibSUCCESS;
    }

    if (index == 0)
    {
        strcpy(dstVis->dateObs, srcVis->dateObs);
        for (i=0; i < srcVis->nbFrames * srcVis->nbBases; i++)
        {
            dstVis->table[i].targetId = srcVis->table[i].targetId;
            dstVis->table[i].time = srcVis->table[i].time;
            dstVis->table[i].dateObsMJD = srcVis->table[i].dateObsMJD;
            dstVis->table[i].expTime = srcVis->table[i].expTime;
            dstVis->table[i].uCoord = srcVis->table[i].uCoord;
            dstVis->table[i].vCoord = srcVis->table[i].vCoord;
            dstVis->table[i].stationIndex[0] = 
                srcVis->table[i].stationIndex[0];
            dstVis->table[i].stationIndex[1] = 
                srcVis->table[i].stationIndex[1];

            for (j=amdlibJ_BAND; j <= amdlibK_BAND; j++)
            {
                dstVis->table[i].bandFlag[j] = srcVis->table[i].bandFlag[j];
                dstVis->table[i].frgContrastSnrArray[j] = 
                    srcVis->table[i].frgContrastSnrArray[j];
            }
            dstVis->table[i].frgContrastSnr = 
                srcVis->table[i].frgContrastSnr;

            for (j=0; j < srcVis->nbWlen; j++)
            {
                dstVis->table[i].vis[j].re = srcVis->table[i].vis[j].re;
                dstVis->table[i].vis[j].im = srcVis->table[i].vis[j].im;
                dstVis->table[i].sigma2Vis[j].re = 
                    srcVis->table[i].sigma2Vis[j].re;
                dstVis->table[i].sigma2Vis[j].im = 
                    srcVis->table[i].sigma2Vis[j].im;
                dstVis->table[i].visCovRI[j] = srcVis->table[i].visCovRI[j];
                dstVis->table[i].diffVisAmp[j] = 
                    srcVis->table[i].diffVisAmp[j];
                dstVis->table[i].diffVisAmpErr[j] = 
                    srcVis->table[i].diffVisAmpErr[j];
                dstVis->table[i].diffVisPhi[j] = 
                    srcVis->table[i].diffVisPhi[j];
                dstVis->table[i].diffVisPhiErr[j] = 
                    srcVis->table[i].diffVisPhiErr[j];
                dstVis->table[i].flag[j] = srcVis->table[i].flag[j];
            }
        }
    }
    else
    {
        if (dstVis->nbFrames != srcVis->nbFrames)
        {
            amdlibSetErrMsg("Different number of frames! (%d and %d)", 
                            dstVis->nbFrames, srcVis->nbFrames);
            return amdlibFAILURE;
        }
        if (dstVis->nbBases != srcVis->nbBases)
        {
            amdlibSetErrMsg("Different number of bases (%d and %d)",
                            dstVis->nbBases, srcVis->nbBases);
            return amdlibFAILURE;        
        }
        for (i=0; i < srcVis->nbFrames * srcVis->nbBases; i++)
        {
            
            
            for (j=amdlibK_BAND; j >=amdlibJ_BAND; j--)
            {
                if (dstVis->table[i].bandFlag[j] == amdlibTRUE)
                {
                    break;
                }
                else if (srcVis->table[i].bandFlag[j] == amdlibTRUE)
                {
                    dstVis->table[i].frgContrastSnr = 
                        srcVis->table[i].frgContrastSnr;
                    continue;
                }
            }
            for (j=amdlibJ_BAND; j <= amdlibK_BAND; j++)
            {
                if ((srcVis->table[i].bandFlag[j] == amdlibTRUE) &&
                    (dstVis->table[i].bandFlag[j]) == amdlibFALSE)
                {
                    dstVis->table[i].bandFlag[j] = amdlibTRUE;
                    dstVis->table[i].frgContrastSnrArray[j] = 
                        srcVis->table[i].frgContrastSnrArray[j];
                }
            }
            dstVis->table[i].frgContrastSnr = srcVis->table[i].frgContrastSnr;            
            for (j = 0; j < nbOfElem; j++)
            {
                dstVis->table[i].vis[index+j].re = 
                    srcVis->table[i].vis[j].re;
                dstVis->table[i].vis[index+j].im = 
                    srcVis->table[i].vis[j].im;
                
                dstVis->table[i].sigma2Vis[index+j].re = 
                    srcVis->table[i].sigma2Vis[j].re;
                dstVis->table[i].sigma2Vis[index+j].im = 
                    srcVis->table[i].sigma2Vis[j].im;

                dstVis->table[i].visCovRI[index+j] = 
                    srcVis->table[i].visCovRI[j];
                dstVis->table[i].diffVisAmp[index+j] = 
                    srcVis->table[i].diffVisAmp[j];
                dstVis->table[i].diffVisAmpErr[index+j] = 
                    srcVis->table[i].diffVisAmpErr[j];
                dstVis->table[i].diffVisPhi[index+j] = 
                    srcVis->table[i].diffVisPhi[j];
                dstVis->table[i].diffVisPhiErr[index+j] = 
                    srcVis->table[i].diffVisPhiErr[j];
                dstVis->table[i].flag[index+j] = 
                    srcVis->table[i].flag[j];
            }
        }
    }
    return amdlibSUCCESS;
}

/**
 * Display visibility structure.
 *
 * @param vis pointer to amdlibVIS structure.
 */
void amdlibDisplayVis(amdlibVIS *vis)
{
    int nbFrames, nbBases, nbWlen;
    int iFrame, iBase, iCell, iWave, iBand;
    amdlibVIS_TABLE_ENTRY cell;
    double visRe;
    double visIm;
    double sigma2VisRe;
    double sigma2VisIm;
    double visCovRI;
    double diffVisAmp;
    double diffVisAmpErr;
    double diffVisPhi;
    double diffVisPhiErr;
    double bandFrgContrastSnr;
    amdlibBOOLEAN  bandFlag;
    
    amdlibLogTrace("amdlibDisplayVis()");

    /* Display number of frames */
    nbFrames = vis->nbFrames;
    printf("nbFrames = %d\n", nbFrames);
    
    /* Display number of base */
    nbBases = vis->nbBases;
    printf("nbBases = %d\n", nbBases);

    /* Display number of wavelength */
    nbWlen = vis->nbWlen;
    printf("nbWlen = %d\n", nbWlen);

    /* Display different arrays[nbFrames][nbBases][nbWlen] */
    for (iFrame = 0; iFrame < nbFrames; iFrame++)
    {
        for (iBase = 0; iBase < nbBases; iBase++)
        {
            /* Set cell[iFrame][iBase] */
            iCell = iFrame * nbBases + iBase;
            cell =  vis->table[iCell];
            printf("---> cell frame/base[%d][%d]\n", iFrame, iBase);
            printf("time = %lf\n",cell.time);
            printf("dateObsMJD = %lf\n",cell.dateObsMJD);
            printf("expTime = %lf\n",cell.expTime);
            printf("uCoord = %lf\n",cell.uCoord);
            printf("vCoord = %lf\n",cell.vCoord);
            printf("stationIndex = %d %d\n",cell.stationIndex[0],cell.stationIndex[1]);
            printf("frgContrastSnr = %lf\n",cell.frgContrastSnr);

            /* Display arrays[nbWlen] */
            for (iWave = 0; iWave < nbWlen; iWave++)
            {
                /* vis re */
                visRe = cell.vis[iWave].re;
                printf("visRe[%d][%d][%d] = %f - ", iFrame, iBase, iWave, 
                                                    visRe);
                /* sigma2Vis re */
                sigma2VisRe = cell.sigma2Vis[iWave].re;
                printf("sigma2VisRe[%d][%d][%d] = %f\n", iFrame, iBase, iWave, 
                       sigma2VisRe);
                
                /* vis im */
                visIm = cell.vis[iWave].im;
                printf("visIm[%d][%d][%d] = %f - ", iFrame, iBase, iWave, 
                                                    visIm);
                
                /* sigma2Vis im */
                sigma2VisIm = cell.sigma2Vis[iWave].im;
                printf("sigma2VisIm[%d][%d][%d] = %f\n", iFrame, iBase, iWave, 
                                                            sigma2VisIm);
                /* visCovRI */
                visCovRI = cell.visCovRI[iWave];
                printf("visCovRI[%d][%d][%d] = %f\n", iFrame, iBase, iWave, 
                                                        visCovRI);

                /* diffVisAmp */
                diffVisAmp = cell.diffVisAmp[iWave];
                printf("diffVisAmp[%d][%d][%d] = %f - ", iFrame, iBase, iWave, 
                                                        diffVisAmp);

                /* diffVisAmpErr */
                diffVisAmpErr = cell.diffVisAmpErr[iWave];
                printf("diffVisAmpErr[%d][%d][%d] = %f\n", iFrame, iBase, iWave,                                                           diffVisAmpErr);

                /* diffVisPhi */
                diffVisPhi = cell.diffVisPhi[iWave];
                printf("diffVisPhi[%d][%d][%d] = %f - ", iFrame, iBase, iWave, 
                                                        diffVisPhi);

                /* diffVisPhiErr */
                diffVisPhiErr = cell.diffVisPhiErr[iWave];
                printf("diffVisPhiErr[%d][%d][%d] = %f\n", iFrame, iBase, iWave,                                                           diffVisPhiErr);
            }
            
            /* Display arrays[amdlibNB_BAND] */
            for (iBand = 0; iBand < amdlibNB_BANDS; iBand++)
            {
                /* frgContrastSnrArray */
                bandFrgContrastSnr = cell.frgContrastSnrArray[iBand];
                printf("bandFrgContrastSnr[%d][%d][%d] = %f - ", iFrame, iBase, 
                                                                iBand, 
                                                        bandFrgContrastSnr);

                /* bandFlag */
                bandFlag = cell.bandFlag[iBand];
                printf("bandFlag[%d][%d][%d] = %d\n", iFrame, iBase, iBand, 
                                                        bandFlag);
            }
        }
    }
}

/**
 * Allocate memory for storing squared visibilities. 
 *
 * @param vis2 pointer to amdlibVIS2 structure.
 * @param nbFrames number of frames 
 * @param nbBases number of baselines 
 * @param nbWlen number of spectral channels 
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibAllocateVis2(amdlibVIS2 *vis2,
                                    const int  nbFrames,
                                    const int  nbBases,
                                    const int  nbWlen)
{
    int dimArray;
    int i; /* loop */
    void *pointer;
    int nbSamples;

    amdlibLogTrace("amdlibAllocateVis2()");
    
    /* First free previous allocated memory */
    if (vis2->thisPtr == vis2) 
    {
        amdlibFreeVis2(vis2);
    }

    /* Update thisPtr */
    vis2->thisPtr=memset(vis2, '\0', sizeof(*vis2));

    /* Set array size */
    vis2->nbFrames = nbFrames;
    vis2->nbBases = nbBases;
    vis2->nbWlen = nbWlen;

    /* Allocate table pointer list  */
    nbSamples =  nbFrames * nbBases;
    vis2->table = calloc(nbSamples, sizeof(*(vis2->table)));
    if (vis2->table == NULL)
    {
        amdlibFreeVis2(vis2);
        return amdlibFAILURE;
    }

    /* Allocate 'vis2' in each table entry  as a whole */
    dimArray = sizeof(double) * nbWlen;
    vis2->table[0].vis2 = (double *)calloc(nbSamples, dimArray);
    if (vis2->table[0].vis2 == NULL)
    {
        amdlibFreeVis2(vis2);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis2->table[0].vis2; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        vis2->table[i].vis2 = pointer;
    }

    /* Allocate 'vis2Error' in each table entry (amdlibCOMPLEX) as a whole */
    dimArray = sizeof(double) * nbWlen;
    vis2->table[0].vis2Error = (double *)calloc(nbSamples, dimArray);
    if (vis2->table[0].vis2Error == NULL)
    {
        amdlibFreeVis2(vis2);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis2->table[0].vis2Error; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        vis2->table[i].vis2Error = pointer;
    }

    /* Allocate 'flag' in each table entry (boolean) as a whole */
    dimArray = sizeof(amdlibBOOLEAN) * nbWlen;
    vis2->table[0].flag = (amdlibBOOLEAN *)calloc(nbSamples, dimArray);
    if (vis2->table[0].flag == NULL)
    {
        amdlibFreeVis2(vis2);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis2->table[0].flag; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        vis2->table[i].flag = pointer;
    }

    /* Return */
    return amdlibSUCCESS;
}


/**
 * Append amdlibVIS2 data structure. 
 *
 * @param srcVis2 pointer to source data structure 
 * @param dstVis2 pointer to destination data structure  (append to) 
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibAppendVis2 (amdlibVIS2 *dstVis2, 
                                   amdlibVIS2 *srcVis2, 
                                   amdlibERROR_MSG   errMsg)
{
    int sentry;
    int dentry;
    size_t vis2Size = srcVis2->nbWlen * sizeof(double);
    int oldNbFrames = dstVis2->nbFrames;
    
    amdlibLogTrace("amdlibAppendVis2()");
    /* Perform simple checks */
    if (dstVis2->nbBases != srcVis2->nbBases)
    {
        amdlibSetErrMsg("Different number of bases (%d and %d)",
                        srcVis2->nbBases, dstVis2->nbBases);
        return amdlibFAILURE;
    }
    if (dstVis2->nbWlen != srcVis2->nbWlen)
    {
        amdlibSetErrMsg("Different number of wavelengths (%d and %d)",
                        srcVis2->nbWlen, dstVis2->nbWlen);
        return amdlibFAILURE;
    }

    /* Reallocate memory to store additional data */
    if (amdlibReallocateVis2(dstVis2, oldNbFrames + srcVis2->nbFrames,
                             dstVis2->nbBases, 
                             dstVis2->nbWlen) != amdlibSUCCESS)
    {
        amdlibSetErrMsg("Could not reallocate memory for visibility structure");
        return amdlibFAILURE;
    }

    /* Append fields allocated dynamically */
    dentry = oldNbFrames * dstVis2->nbBases;
    for (sentry = 0; sentry < srcVis2->nbFrames * srcVis2->nbBases; sentry++)
    {
        dstVis2->table[dentry].targetId = srcVis2->table[sentry].targetId;
        
        dstVis2->table[dentry].time = srcVis2->table[sentry].time;

        dstVis2->table[dentry].dateObsMJD = srcVis2->table[sentry].dateObsMJD;
        
        dstVis2->table[dentry].expTime = srcVis2->table[sentry].expTime;
        
        dstVis2->table[dentry].uCoord = srcVis2->table[sentry].uCoord;
        
        dstVis2->table[dentry].vCoord = srcVis2->table[sentry].vCoord;
        
        dstVis2->table[dentry].stationIndex[0] =
            srcVis2->table[sentry].stationIndex[0];
        
        dstVis2->table[dentry].stationIndex[1] =
            srcVis2->table[sentry].stationIndex[1];
        
        memcpy (dstVis2->table[dentry].vis2, 
                srcVis2->table[sentry].vis2, vis2Size);
        memcpy (dstVis2->table[dentry].vis2Error,
                srcVis2->table[sentry].vis2Error, vis2Size);
        
        memcpy(dstVis2->table[dentry].flag, srcVis2->table[sentry].flag, 
               srcVis2->nbWlen * sizeof(amdlibBOOLEAN));

        dentry++;
    }
    /* Update dst fixed size fields */
    dstVis2->vis12 = srcVis2->nbFrames * srcVis2->vis12 + 
        oldNbFrames * dstVis2->vis12;
    dstVis2->vis23 = srcVis2->nbFrames * srcVis2->vis23 + 
        oldNbFrames * dstVis2->vis23;
    dstVis2->vis31 = srcVis2->nbFrames * srcVis2->vis31 + 
        oldNbFrames * dstVis2->vis31;
    
    dstVis2->sigmaVis12 = srcVis2->nbFrames * srcVis2->sigmaVis12 + 
        oldNbFrames * dstVis2->sigmaVis12;
    dstVis2->sigmaVis23 = srcVis2->nbFrames * srcVis2->sigmaVis23 + 
        oldNbFrames * dstVis2->sigmaVis23;
    dstVis2->sigmaVis31 = srcVis2->nbFrames * srcVis2->sigmaVis31 + 
        oldNbFrames * dstVis2->sigmaVis31;


    dstVis2->vis12 /= dstVis2->nbFrames;
    dstVis2->vis23 /= dstVis2->nbFrames;
    dstVis2->vis31 /= dstVis2->nbFrames;
    dstVis2->sigmaVis12 /= dstVis2->nbFrames;
    dstVis2->sigmaVis23 /= dstVis2->nbFrames;
    dstVis2->sigmaVis31 /= dstVis2->nbFrames;
    
    return amdlibSUCCESS;
}


/**
 * Insert amdlibVIS2 data structure. 
 *
 * @param srcVis2 pointer to source data structure 
 * @param dstVis2 pointer to destination data structure  (insert to) 
 * @param insertIndex
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibInsertVis2 (amdlibVIS2 *dstVis2, 
                                   amdlibVIS2 *srcVis2, 
                                   int insertIndex,
                                   amdlibERROR_MSG   errMsg)
{
    int sentry;
    int dentry;
    size_t vis2Size = srcVis2->nbWlen * sizeof(double);
    int dstNbFrames = dstVis2->nbFrames;
    int finalIndex = insertIndex + srcVis2->nbFrames;
    
    amdlibLogTrace("amdlibInsertVis2()");
    /* Perform simple checks */
    if (insertIndex<0 || insertIndex>=dstVis2->nbFrames)
    {
        amdlibSetErrMsg("Invalid insertion index %d for amdlibInsertVis2",insertIndex);
        return amdlibFAILURE;
    }
    if (dstVis2->nbBases != srcVis2->nbBases)
    {
        amdlibSetErrMsg("Different number of bases (%d and %d)",
                        srcVis2->nbBases, dstVis2->nbBases);
        return amdlibFAILURE;
    }
    if (dstVis2->nbWlen != srcVis2->nbWlen)
    {
        amdlibSetErrMsg("Different number of wavelengths (%d and %d)",
                        srcVis2->nbWlen, dstVis2->nbWlen);
        return amdlibFAILURE;
    }
    if (dstNbFrames < finalIndex)
    {
        amdlibSetErrMsg("Number of frames (%d) in destination structure"
                        "too small to enable insertion of %d frames at position %d", 
                        dstNbFrames,srcVis2->nbFrames,insertIndex);
        return amdlibFAILURE;
    }

    strcpy(dstVis2->dateObs, srcVis2->dateObs);
    /* Insert src in dst at frame insertIndex */
    dentry = insertIndex * dstVis2->nbBases;
    for (sentry = 0; sentry < srcVis2->nbFrames * srcVis2->nbBases; sentry++)
    {
        dstVis2->table[dentry].targetId = srcVis2->table[sentry].targetId;
        
        dstVis2->table[dentry].time = srcVis2->table[sentry].time;

        dstVis2->table[dentry].dateObsMJD = srcVis2->table[sentry].dateObsMJD;
        
        dstVis2->table[dentry].expTime = srcVis2->table[sentry].expTime;
        
        memcpy (dstVis2->table[dentry].vis2, 
                srcVis2->table[sentry].vis2, vis2Size);
        memcpy (dstVis2->table[dentry].vis2Error,
                srcVis2->table[sentry].vis2Error, vis2Size);
        
        dstVis2->table[dentry].uCoord = srcVis2->table[sentry].uCoord;
        
        dstVis2->table[dentry].vCoord = srcVis2->table[sentry].vCoord;
        
        dstVis2->table[dentry].stationIndex[0] =
            srcVis2->table[sentry].stationIndex[0];
        dstVis2->table[dentry].stationIndex[1] =
            srcVis2->table[sentry].stationIndex[1];
        
        memcpy(dstVis2->table[dentry].flag, srcVis2->table[sentry].flag, 
               srcVis2->nbWlen * sizeof(amdlibBOOLEAN));

        dentry++;
    }
    /* Update dst fixed size fields by averaging past and added values*/
    dstVis2->vis12 = srcVis2->nbFrames * srcVis2->vis12 + 
        insertIndex * dstVis2->vis12;
    dstVis2->vis23 = srcVis2->nbFrames * srcVis2->vis23 + 
        insertIndex * dstVis2->vis23;
    dstVis2->vis31 = srcVis2->nbFrames * srcVis2->vis31 + 
        insertIndex * dstVis2->vis31;
    
    dstVis2->sigmaVis12 = srcVis2->nbFrames * srcVis2->sigmaVis12 + 
        insertIndex * dstVis2->sigmaVis12;
    dstVis2->sigmaVis23 = srcVis2->nbFrames * srcVis2->sigmaVis23 + 
        insertIndex * dstVis2->sigmaVis23;
    dstVis2->sigmaVis31 = srcVis2->nbFrames * srcVis2->sigmaVis31 + 
        insertIndex * dstVis2->sigmaVis31;


    dstVis2->vis12 /= (srcVis2->nbFrames+insertIndex);
    dstVis2->vis23 /= (srcVis2->nbFrames+insertIndex);
    dstVis2->vis31 /= (srcVis2->nbFrames+insertIndex);
    dstVis2->sigmaVis12 /= (srcVis2->nbFrames+insertIndex);
    dstVis2->sigmaVis23 /= (srcVis2->nbFrames+insertIndex);
    dstVis2->sigmaVis31 /= (srcVis2->nbFrames+insertIndex);
    
    return amdlibSUCCESS;
}

/**
 * Merge OI-VIS2. 
 *
 * @param vis1 pointer to first OI-VIS2 structure.
 * @param vis2 pointer to second OI-VIS2 structure (to merge).
 * @param isInverted boolean indicating in which order the structures have to 
 * be merged.
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibMergeVis2(amdlibVIS2      *vis1,
                                 amdlibVIS2      *vis2,
                                 amdlibBOOLEAN   isInverted,
                                 amdlibERROR_MSG errMsg)
{
    amdlibVIS2 mergedVis2 = {NULL};
    amdlibVIS2 *v1, *v2;

    amdlibLogTrace("amdlibMergeVis2()");
    
    /* Check phot1 and phot2 have same number of baselines */
    if (vis1->nbBases != vis2->nbBases)
    {
        amdlibSetErrMsg("Different number of baselines (%d and %d)",
                        vis1->nbBases, vis2->nbBases);
        return amdlibFAILURE;
    }
    

    if (isInverted == amdlibTRUE)
    {
        v1 = vis2;
        v2 = vis1;
    }
    else
    {
        v1 = vis1;
        v2 = vis2;
    }

    /* Allocate memory for mergedPhot */
    mergedVis2.thisPtr = NULL;
    if (amdlibAllocateVis2(&mergedVis2, vis1->nbFrames, vis1->nbBases, 
                           vis1->nbWlen + vis2->nbWlen) != amdlibSUCCESS)
    {
        amdlibSetErrMsg("Could not allocate memory for merged OI-VIS2 structure");
        return amdlibFAILURE;
    }
    if (amdlibCopyVis2From(&mergedVis2, v1, 0, v1->nbWlen, 
                           errMsg) != amdlibSUCCESS)
    {
        return amdlibFAILURE;
    }

    if (amdlibCopyVis2From(&mergedVis2, v2, v1->nbWlen, v2->nbWlen,
                           errMsg) != amdlibSUCCESS)
    {
        return amdlibFAILURE;
    }
        
    free(vis1->table[0].vis2);
    free(vis1->table[0].vis2Error);
    free(vis1->table[0].flag);

    free(vis1->table);
    vis1->nbWlen = mergedVis2.nbWlen;
    vis1->nbFrames = mergedVis2.nbFrames;
    vis1->table = mergedVis2.table;
    
    return amdlibSUCCESS;
}

/**
 * Split amdlibVIS2 input data structure into 3 structures, 1 per spectral
 * band. Each new structure only contains information relative to its associated
 * spectral band .
 *
 * @param srcVis2 pointer on squared visibility structure to split.
 * @param dstVis2 array of splitted squared visibility structures.
 * @param idxFirstWlen array containing the indexes of the first wavelength
 *        belonging to each spectral band.
 * @param nbWlen array containing the number of wavelengths per spectral band.
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibSplitVis2(amdlibVIS2       *srcVis2,
                                 amdlibVIS2       *dstVis2,
                                 int              *idxFirstWlen,
                                 int              *nbWlen,
                                 amdlibERROR_MSG  errMsg)
{
    int band, index, i, j;

    amdlibLogTrace("amdlibSplitVis2()");
    for (band=amdlibJ_BAND; band <= amdlibK_BAND; band++)
    {
        if (nbWlen[band] == 0)
        {
            dstVis2[band].thisPtr = NULL;
        }
        else
        {
            /* Allocate memory for dstVis2 */
            if (amdlibAllocateVis2(&dstVis2[band], srcVis2->nbFrames, 
                                   srcVis2->nbBases, 
                                   nbWlen[band]) != amdlibSUCCESS)
            {
                amdlibSetErrMsg("Could not allocate memory for oivis2 ");
                return amdlibFAILURE;
            }

            strcpy(dstVis2[band].dateObs, srcVis2->dateObs);
            dstVis2[band].vis12 = srcVis2->vis12;
            dstVis2[band].vis23 = srcVis2->vis23;
            dstVis2[band].vis31 = srcVis2->vis31;
            dstVis2[band].sigmaVis12 = srcVis2->sigmaVis12;
            dstVis2[band].sigmaVis23 = srcVis2->sigmaVis23;
            dstVis2[band].sigmaVis31 = srcVis2->sigmaVis31;
            for (i=0; i < dstVis2[band].nbFrames * dstVis2[band].nbBases; i++)
            {
                dstVis2[band].table[i].targetId = srcVis2->table[i].targetId;
                dstVis2[band].table[i].time = srcVis2->table[i].time;
                dstVis2[band].table[i].dateObsMJD = 
                    srcVis2->table[i].dateObsMJD;
                dstVis2[band].table[i].expTime = srcVis2->table[i].expTime;
                dstVis2[band].table[i].uCoord = srcVis2->table[i].uCoord;
                dstVis2[band].table[i].vCoord = srcVis2->table[i].vCoord;
                dstVis2[band].table[i].stationIndex[0] = 
                    srcVis2->table[i].stationIndex[0];
                dstVis2[band].table[i].stationIndex[1] = 
                    srcVis2->table[i].stationIndex[1];

                index = idxFirstWlen[band];
                for (j=0; j < nbWlen[band]; j++)
                {
                    dstVis2[band].table[i].vis2[j] = 
                        srcVis2->table[i].vis2[index];
                    dstVis2[band].table[i].vis2Error[j] = 
                        srcVis2->table[i].vis2Error[index];
                    
                    dstVis2[band].table[i].flag[j] = 
                        srcVis2->table[i].flag[index];
                    index++;
                }
                
            }
        }
    }
    return amdlibSUCCESS;

}

/**
 * Duplicate OI-VIS2 if index = 0 or add information relative to wavelengths
 * in first structure else.
 *
 * @param dstVis2 pointer to first OI-VIS2 structure.
 * @param srcVis2 pointer to second OI-VIS2 structure (to be copied).
 * @param index index on the location to place information.
 * @param nbOfElem number of elements to store.
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibCopyVis2From(amdlibVIS2       *dstVis2,
                                    amdlibVIS2       *srcVis2,
                                    int              index,
                                    int              nbOfElem,
                                    amdlibERROR_MSG  errMsg)
{
    int i, j;
    amdlibLogTrace("amdlibCopyVis2From()");
    
    if ((dstVis2->thisPtr == NULL) && (index != 0))
    {
        amdlibSetErrMsg("Could not copy non-initialized data from index %d", 
                        index);
        return amdlibFAILURE;
    }

    if (srcVis2->thisPtr == NULL)
    {
        /* Nothing to do */
        return amdlibSUCCESS;
    }

    if (index == 0)
    {
        strcpy(dstVis2->dateObs, srcVis2->dateObs);
        dstVis2->vis12 = srcVis2->vis12;
        dstVis2->vis23 = srcVis2->vis23;
        dstVis2->vis31 = srcVis2->vis31;
        dstVis2->sigmaVis12 = srcVis2->sigmaVis12;
        dstVis2->sigmaVis23 = srcVis2->sigmaVis23;
        dstVis2->sigmaVis31 = srcVis2->sigmaVis31;
        for (i=0; i < dstVis2->nbFrames * dstVis2->nbBases; i++)
        {
            dstVis2->table[i].targetId = srcVis2->table[i].targetId;
            dstVis2->table[i].time = srcVis2->table[i].time;
            dstVis2->table[i].dateObsMJD = srcVis2->table[i].dateObsMJD;
            dstVis2->table[i].expTime = srcVis2->table[i].expTime;
            dstVis2->table[i].uCoord = srcVis2->table[i].uCoord;
            dstVis2->table[i].vCoord = srcVis2->table[i].vCoord;
            dstVis2->table[i].stationIndex[0] = 
                srcVis2->table[i].stationIndex[0];
            dstVis2->table[i].stationIndex[1] = 
                srcVis2->table[i].stationIndex[1];

            for (j=0; j < srcVis2->nbWlen; j++)
            {
                dstVis2->table[i].vis2[j] = srcVis2->table[i].vis2[j];
                dstVis2->table[i].vis2Error[j] = srcVis2->table[i].vis2Error[j];
                dstVis2->table[i].flag[j] = srcVis2->table[i].flag[j];
            }
        }
    }
    else
    {
        if (dstVis2->nbFrames != srcVis2->nbFrames)
        {
            amdlibSetErrMsg("Different number of frames! (%d and %d)", 
                            dstVis2->nbFrames, srcVis2->nbFrames);
            return amdlibFAILURE;
        }
        if (dstVis2->nbBases != srcVis2->nbBases)
        {
            amdlibSetErrMsg("Different number of bases (%d and %d)",
                            dstVis2->nbBases, srcVis2->nbBases);
            return amdlibFAILURE;        
        }
        for (i=0; i < srcVis2->nbFrames * srcVis2->nbBases; i++)
        {
            dstVis2->table[i].targetId = srcVis2->table[i].targetId;
            dstVis2->table[i].time = srcVis2->table[i].time;
            dstVis2->table[i].dateObsMJD = srcVis2->table[i].dateObsMJD;
            dstVis2->table[i].expTime = srcVis2->table[i].expTime;
            dstVis2->table[i].uCoord = srcVis2->table[i].uCoord;
            dstVis2->table[i].vCoord = srcVis2->table[i].vCoord;
            dstVis2->table[i].stationIndex[0]=srcVis2->table[i].stationIndex[0];
            dstVis2->table[i].stationIndex[1]=srcVis2->table[i].stationIndex[1];
            for (j=0; j < nbOfElem; j++)
            {
                dstVis2->table[i].vis2[index+j] = srcVis2->table[i].vis2[j];
                dstVis2->table[i].vis2Error[index+j] = 
                    srcVis2->table[i].vis2Error[j];
                dstVis2->table[i].flag[index+j] = srcVis2->table[i].flag[j];
            }
        }
    }
    return amdlibSUCCESS;
}

/**
 * Display squared visibility structure.
 *
 * @param vis2 pointer to amdlibVIS2 structure.
 */
void amdlibDisplayVis2(amdlibVIS2 *vis2)
{
    int nbFrames, nbBases, nbWlen;
    int iFrame, iBase, iCell, iWave;
    amdlibDOUBLE vis12;
    amdlibDOUBLE vis23;
    amdlibDOUBLE vis31;
    amdlibDOUBLE sigmaVis12;
    amdlibDOUBLE sigmaVis23;
    amdlibDOUBLE sigmaVis31;
    amdlibVIS2_TABLE_ENTRY cell;
    double visibility2;
    double visibility2Error;

    amdlibLogTrace("amdlibDisplayVis2()");

    /* Display number of frames */
    nbFrames = vis2->nbFrames;
    printf("nbFrames = %d\n", nbFrames);
    
    /* Display number of base */
    nbBases = vis2->nbBases;
    printf("nbBases = %d\n", nbBases);

    /* Display number of wavelength */
    nbWlen = vis2->nbWlen;
    printf("nbWlen = %d\n", nbWlen);

    /* Display mean visibility with corresponding error */
    vis12 = vis2->vis12;
    vis23 = vis2->vis23;
    vis31= vis2->vis31;
    sigmaVis12 = vis2->sigmaVis12;
    sigmaVis23 = vis2->sigmaVis23;
    sigmaVis31= vis2->sigmaVis31;
    printf("vis12 = %f - sigmaVis12 = %f\n", vis12, sigmaVis12);
    printf("vis23 = %f - sigmaVis23 = %f\n", vis23, sigmaVis23);
    printf("vis31 = %f - sigmaVis31 = %f\n", vis31, sigmaVis31);

    /* Display different arrays[nbFrames][nbBases][nbWlen] */
    for (iFrame = 0; iFrame < nbFrames; iFrame++)
    {
        for (iBase = 0; iBase < nbBases; iBase++)
        {
            /* Set cell[iFrame][iBase] */
            iCell = iFrame * nbBases + iBase;
            cell =  vis2->table[iCell];
            printf("---> cell frame/base[%d][%d]\n", iFrame, iBase);

            /* Display arrays[nbWlen] */
            for (iWave = 0; iWave < nbWlen; iWave++)
            {
                /* vis2 */
                visibility2 = cell.vis2[iWave];
                printf("vis2[%d][%d][%d] = %f - ", iFrame, iBase, iWave, 
                                                    visibility2);

                /* vis2Error */
                visibility2Error = cell.vis2Error[iWave];
                printf("vis2Error[%d][%d][%d] = %f\n", iFrame, iBase, iWave, 
                                                        visibility2Error);
            }
        }
    }
}

/**
 * Allocate memory for storing phase closures. 
 *
 * @param vis3 pointer to amdlibVIS3 structure.
 * @param nbFrames number of frames 
 * @param nbClosures number of phase closures 
 * @param nbWlen number of spectral channels 
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibAllocateVis3(amdlibVIS3 *vis3,
                                    const int nbFrames,
                                    const int nbClosures,
                                    const int nbWlen)
{
    int dimArray;
    int i; /* loop */
    void *pointer;
    int nbSamples;

    amdlibLogTrace("amdlibAllocateVis3()");
    
    /* First free previous allocated memory */
    if (vis3->thisPtr == vis3) 
    {
        amdlibFreeVis3(vis3);
    }

    /* Update thisPtr */
    vis3->thisPtr= memset(vis3, '\0', sizeof(*vis3));;

    /* Set array size */
    vis3->nbFrames = nbFrames;
    vis3->nbClosures = nbClosures;
    vis3->nbWlen = nbWlen;

    /* Allocate table pointer list  */
    nbSamples=nbFrames * nbClosures;
    vis3->table = calloc(nbSamples, sizeof(*(vis3->table)));
    if (vis3->table == NULL)
    {
        amdlibFreeVis3(vis3);
        return amdlibFAILURE;
    }

    /* Allocate 'vis3Amplitude' in each table entry (double) as a whole */
    dimArray = sizeof(double) * nbWlen;
    vis3->table[0].vis3Amplitude = (double *)calloc(nbSamples, dimArray);
    if (vis3->table[0].vis3Amplitude == NULL)
    {
        amdlibFreeVis3(vis3);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis3->table[0].vis3Amplitude; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        vis3->table[i].vis3Amplitude = pointer;
    }

    /* Allocate 'vis3AmplitudeError' in each table entry (double) as a whole */
    dimArray = sizeof(double) * nbWlen;
    vis3->table[0].vis3AmplitudeError = (double *)calloc(nbSamples, dimArray);
    if (vis3->table[0].vis3AmplitudeError == NULL)
    {
        amdlibFreeVis3(vis3);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis3->table[0].vis3AmplitudeError; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        vis3->table[i].vis3AmplitudeError=pointer;
    }
    /* Allocate 'vis3Phi' in each table entry (double) as a whole */
    dimArray = sizeof(double) * nbWlen;
    vis3->table[0].vis3Phi = (double *)calloc(nbSamples, dimArray);
    if (vis3->table[0].vis3Phi == NULL)
    {
        amdlibFreeVis3(vis3);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis3->table[0].vis3Phi; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        vis3->table[i].vis3Phi = pointer;
    }

    /* Allocate 'vis3PhiError' in each table entry (amdlibCOMPLEX) as a whole */
    dimArray = sizeof(double) * nbWlen;
    vis3->table[0].vis3PhiError = (double *)calloc(nbSamples, dimArray);
    if (vis3->table[0].vis3PhiError == NULL)
    {
        amdlibFreeVis3(vis3);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis3->table[0].vis3PhiError; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        vis3->table[i].vis3PhiError = pointer;
    }
    
    /* Allocate 'flag' in each table entry (boolean) as a whole */
    dimArray = sizeof(amdlibBOOLEAN) * nbWlen;
    vis3->table[0].flag = (amdlibBOOLEAN *)calloc(nbSamples, dimArray);
    if (vis3->table[0].flag == NULL)
    {
        amdlibFreeVis3(vis3);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis3->table[0].flag; 
         i < nbSamples; 
         i++, pointer += dimArray)
    {
        vis3->table[i].flag = pointer;
    }

    /* Return */
    return amdlibSUCCESS;
}


/**
 * Append amdlibVIS3 data structure. 
 *
 * @param srcVis3 pointer to source data structure 
 * @param dstVis3 pointer to destination data structure  (append to) 
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibAppendVis3(amdlibVIS3      *dstVis3, 
                                  amdlibVIS3      *srcVis3, 
                                  amdlibERROR_MSG errMsg)
{
    int sentry;
    int dentry;
    size_t arraySize = srcVis3->nbWlen * sizeof(double);
    int oldNbFrames = dstVis3->nbFrames;
    
    amdlibLogTrace("amdlibAppendVis3()");
    /* Perform simple checks */
    if (dstVis3->nbWlen != srcVis3->nbWlen)
    {
        amdlibSetErrMsg("Different number of wavelengths (%d and %d)",
                        srcVis3->nbWlen, dstVis3->nbWlen);
        return amdlibFAILURE;
    }
    if (dstVis3->nbClosures != srcVis3->nbClosures)
    {
        amdlibSetErrMsg("Different number of closures (%d and %d)",
                        srcVis3->nbClosures, dstVis3->nbClosures);
        return amdlibFAILURE;
    }

    /* Reallocate memory to store additional data */
    if (amdlibReallocateVis3(dstVis3, 
                             oldNbFrames + srcVis3->nbFrames,
                             srcVis3->nbClosures, 
                             srcVis3->nbWlen) != amdlibSUCCESS)
    {
        amdlibSetErrMsg("Could not reallocate memory for visibility structure");
        return amdlibFAILURE;
    }
    
    /* Append fields allocated dynamically */
    dentry = oldNbFrames * dstVis3->nbClosures;
    for (sentry = 0; sentry < srcVis3->nbFrames * srcVis3->nbClosures; sentry++)
    {
        dstVis3->table[dentry].targetId = srcVis3->table[sentry].targetId;
        
        dstVis3->table[dentry].time = srcVis3->table[sentry].time;
        
        dstVis3->table[dentry].dateObsMJD = srcVis3->table[sentry].dateObsMJD;
        
        dstVis3->table[dentry].expTime = srcVis3->table[sentry].expTime;
        
        dstVis3->table[dentry].u1Coord = srcVis3->table[sentry].u1Coord;
        dstVis3->table[dentry].v1Coord = srcVis3->table[sentry].v1Coord;
        dstVis3->table[dentry].u2Coord = srcVis3->table[sentry].u2Coord;
        dstVis3->table[dentry].v2Coord = srcVis3->table[sentry].v2Coord;
        
        dstVis3->table[dentry].stationIndex[0] =
            srcVis3->table[sentry].stationIndex[0];
        dstVis3->table[dentry].stationIndex[1] =
            srcVis3->table[sentry].stationIndex[1];
        dstVis3->table[dentry].stationIndex[2] =
            srcVis3->table[sentry].stationIndex[2];
        
        memcpy(dstVis3->table[dentry].vis3Amplitude, 
               srcVis3->table[sentry].vis3Amplitude, arraySize);
        memcpy(dstVis3->table[dentry].vis3AmplitudeError,
               srcVis3->table[sentry].vis3AmplitudeError, arraySize);
        
        memcpy(dstVis3->table[dentry].vis3Phi,
               srcVis3->table[sentry].vis3Phi, arraySize);
        memcpy(dstVis3->table[dentry].vis3PhiError,
               srcVis3->table[sentry].vis3PhiError, arraySize);
       
        memcpy(dstVis3->table[dentry].flag, srcVis3->table[sentry].flag, 
               srcVis3->nbWlen * sizeof(amdlibBOOLEAN));

        dentry++;
    }
    
    /* Update fixed size fields */
    dstVis3->averageClosure = srcVis3->nbFrames * srcVis3->averageClosure + 
        oldNbFrames * dstVis3->averageClosure;
    
    dstVis3->averageClosure /= dstVis3->nbFrames;

    dstVis3->averageClosureError = srcVis3->nbFrames * srcVis3->averageClosureError + 
    oldNbFrames * dstVis3->averageClosureError;
    
    dstVis3->averageClosureError /= dstVis3->nbFrames;
     
    return amdlibSUCCESS;
}

/**
 * Insert amdlibVIS3 data structure. 
 *
 * @param srcVis3 pointer to source data structure 
 * @param dstVis3 pointer to destination data structure  (insert to) 
 * @param insertIndex
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibInsertVis3(amdlibVIS3      *dstVis3, 
                                  amdlibVIS3      *srcVis3, 
                                  int insertIndex,
                                  amdlibERROR_MSG errMsg)
{
    int sentry;
    int dentry;
    size_t vis3Size = srcVis3->nbWlen * sizeof(double);
    int dstNbFrames = dstVis3->nbFrames;
    int finalIndex = insertIndex + srcVis3->nbFrames;
    
    amdlibLogTrace("amdlibInsertVis3()");
    /* Perform simple checks */
    if (insertIndex<0 || insertIndex>=dstVis3->nbFrames)
    {
        amdlibSetErrMsg("Invalid insertion index %d for amdlibInsertVis3",insertIndex);
        return amdlibFAILURE;
    }
    if (dstVis3->nbWlen != srcVis3->nbWlen)
    {
        amdlibSetErrMsg("Different number of wavelengths (%d and %d)",
                        srcVis3->nbWlen, dstVis3->nbWlen);
        return amdlibFAILURE;
    }
    if (dstVis3->nbClosures != srcVis3->nbClosures)
    {
        amdlibSetErrMsg("Different number of closures (%d and %d)",
                        srcVis3->nbClosures, dstVis3->nbClosures);
        return amdlibFAILURE;
    }
    if (dstNbFrames < finalIndex)
    {
        amdlibSetErrMsg("Number of frames (%d) in destination structure"
                        "too small to enable insertion of %d frames at position %d", 
                        dstNbFrames,srcVis3->nbFrames,insertIndex);
        return amdlibFAILURE;
    }

    strcpy(dstVis3->dateObs, srcVis3->dateObs);
    /* Insert src in dst at frame insertIndex */
    dentry = insertIndex * dstVis3->nbClosures;
    for (sentry = 0; sentry < srcVis3->nbFrames * srcVis3->nbClosures; sentry++)
    {
        dstVis3->table[dentry].targetId = srcVis3->table[sentry].targetId;
        
        dstVis3->table[dentry].time = srcVis3->table[sentry].time;
        
        dstVis3->table[dentry].dateObsMJD = srcVis3->table[sentry].dateObsMJD;
        
        dstVis3->table[dentry].expTime = srcVis3->table[sentry].expTime;

        memcpy(dstVis3->table[dentry].vis3Amplitude, 
               srcVis3->table[sentry].vis3Amplitude, vis3Size);
        memcpy(dstVis3->table[dentry].vis3AmplitudeError,
               srcVis3->table[sentry].vis3AmplitudeError, vis3Size);
        
        memcpy(dstVis3->table[dentry].vis3Phi,
               srcVis3->table[sentry].vis3Phi, vis3Size);
        memcpy(dstVis3->table[dentry].vis3PhiError,
               srcVis3->table[sentry].vis3PhiError, vis3Size);
        
        dstVis3->table[dentry].u1Coord = srcVis3->table[sentry].u1Coord;
        dstVis3->table[dentry].v1Coord = srcVis3->table[sentry].v1Coord;
        dstVis3->table[dentry].u2Coord = srcVis3->table[sentry].u2Coord;
        dstVis3->table[dentry].v2Coord = srcVis3->table[sentry].v2Coord;
        
        dstVis3->table[dentry].stationIndex[0] =
            srcVis3->table[sentry].stationIndex[0];
        dstVis3->table[dentry].stationIndex[1] =
            srcVis3->table[sentry].stationIndex[1];
        dstVis3->table[dentry].stationIndex[2] =
            srcVis3->table[sentry].stationIndex[2];
        
        memcpy(dstVis3->table[dentry].flag, srcVis3->table[sentry].flag, 
               srcVis3->nbWlen * sizeof(amdlibBOOLEAN));

        dentry++;
    }
    
    /* Update fixed size fields */
    dstVis3->averageClosure = srcVis3->nbFrames * srcVis3->averageClosure + 
        insertIndex * dstVis3->averageClosure;
    dstVis3->averageClosure /= (srcVis3->nbFrames+insertIndex);

    dstVis3->averageClosureError = srcVis3->nbFrames * srcVis3->averageClosureError + 
        insertIndex * dstVis3->averageClosureError;
    dstVis3->averageClosureError /= (srcVis3->nbFrames+insertIndex);
     
    return amdlibSUCCESS;
}


/**
 * Merge amdlibVIS3. 
 *
 * @param vis1 pointer to first OI-VIS3 structure.
 * @param vis2 pointer to second OI-VIS3 structure (to merge).
 * @param isInverted boolean indicating in which order the structures have to 
 * be merged.
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibMergeVis3(amdlibVIS3      *vis1,
                                 amdlibVIS3      *vis2,
                                 amdlibBOOLEAN   isInverted,
                                 amdlibERROR_MSG errMsg)
{
    amdlibVIS3 mergedVis3 = {NULL};
    amdlibVIS3 *v1, *v2;

    amdlibLogTrace("amdlibMergeVis3()");
    
    /* Check phot1 and phot2 have same number of baselines */
    if (vis1->nbClosures != vis2->nbClosures)
    {
        amdlibSetErrMsg("Different number of closures (%d and %d)",
                        vis1->nbClosures, vis2->nbClosures);
        return amdlibFAILURE;
    }
    
    /* Allocate memory for mergedPhot */
    mergedVis3.thisPtr = NULL;
    if (amdlibAllocateVis3(&mergedVis3, vis1->nbFrames, vis1->nbClosures, 
                           vis1->nbWlen + vis2->nbWlen) != amdlibSUCCESS)
    {
        amdlibSetErrMsg("Could not allocate memory for merged OI-VIS3 structure");
        return amdlibFAILURE;
    }

    if (isInverted == amdlibTRUE)
    {
        v1 = vis2;
        v2 = vis1;
    }
    else
    {
        v1 = vis1;
        v2 = vis2;
    }
    
    if (amdlibCopyVis3From(&mergedVis3, v1, 0, v1->nbWlen, 
                           errMsg) != amdlibSUCCESS)
    {
        return amdlibFAILURE;
    }

    if (amdlibCopyVis3From(&mergedVis3, v2, v1->nbWlen, v2->nbWlen,
                           errMsg) != amdlibSUCCESS)
    {
        return amdlibFAILURE;
    }
    

    free(vis1->table[0].vis3Amplitude);
    free(vis1->table[0].vis3AmplitudeError);
    free(vis1->table[0].vis3Phi);
    free(vis1->table[0].vis3PhiError);
    free(vis1->table[0].flag);

    free(vis1->table);
    vis1->nbWlen = mergedVis3.nbWlen;
    vis1->nbFrames = mergedVis3.nbFrames;
    vis1->table = mergedVis3.table;
    
    return amdlibSUCCESS;
}

/**
 * Split amdlibVIS3 input data structure into 3 structures, 1 per spectral
 * band. Each new structure only contains information relative to its associated
 * spectral band .
 *
 * @param srcVis3 pointer on closure phases structure to split.
 * @param dstVis3 array of splitted closure phases structures.
 * @param idxFirstWlen array containing the indexes of the first wavelength
 *        belonging to each spectral band.
 * @param nbWlen array containing the number of wavelengths per spectral band.
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibSplitVis3(amdlibVIS3       *srcVis3,
                                 amdlibVIS3       *dstVis3,
                                 int              *idxFirstWlen,
                                 int              *nbWlen,
                                 amdlibERROR_MSG  errMsg)
{
    int band, index, i, j;

    amdlibLogTrace("amdlibSplitVis3()");
    
    for (band=amdlibJ_BAND; band <= amdlibK_BAND; band++)
    {
        if (nbWlen[band] == 0)
        {
            dstVis3[band].thisPtr = NULL;
        }
        else
        {
            /* Allocate memory for dstVis3 */
            if (amdlibAllocateVis3(&dstVis3[band], srcVis3->nbFrames, 
                                   srcVis3->nbClosures, 
                                   nbWlen[band]) != amdlibSUCCESS)
            {
                amdlibSetErrMsg("Could not allocate memory for oivis3");
                return amdlibFAILURE;
            }

            strcpy(dstVis3[band].dateObs, srcVis3->dateObs);
            dstVis3[band].averageClosure = srcVis3->averageClosure;
            dstVis3[band].averageClosureError = srcVis3->averageClosureError;

            /* Copy values in destVis3[band] */
            for (i=0; i < srcVis3->nbFrames * srcVis3->nbClosures; i++)
            {
                dstVis3[band].table[i].targetId = srcVis3->table[i].targetId;
                dstVis3[band].table[i].time = srcVis3->table[i].time;
                dstVis3[band].table[i].dateObsMJD = 
                    srcVis3->table[i].dateObsMJD;
                dstVis3[band].table[i].expTime = srcVis3->table[i].expTime;
                dstVis3[band].table[i].u1Coord = srcVis3->table[i].u1Coord;
                dstVis3[band].table[i].u2Coord = srcVis3->table[i].u2Coord;
                dstVis3[band].table[i].v1Coord = srcVis3->table[i].v1Coord;
                dstVis3[band].table[i].v2Coord = srcVis3->table[i].v2Coord;
                dstVis3[band].table[i].stationIndex[0] = 
                    srcVis3->table[i].stationIndex[0];
                dstVis3[band].table[i].stationIndex[1] = 
                    srcVis3->table[i].stationIndex[1];
                dstVis3[band].table[i].stationIndex[2] = 
                    srcVis3->table[i].stationIndex[2];

                index = idxFirstWlen[band];
                for (j=0; j < nbWlen[band]; j++)
                {
                    dstVis3[band].table[i].vis3Amplitude[j] = 
                        srcVis3->table[i].vis3Amplitude[index];
                    dstVis3[band].table[i].vis3AmplitudeError[j] = 
                        srcVis3->table[i].vis3AmplitudeError[index];
                    dstVis3[band].table[i].vis3Phi[j] = 
                        srcVis3->table[i].vis3Phi[index];
                    dstVis3[band].table[i].vis3PhiError[j] = 
                        srcVis3->table[i].vis3PhiError[index];
                    dstVis3[band].table[i].flag[j] = 
                        srcVis3->table[i].flag[index];
                    index ++;
                }
            }
        }
    }
   
    return amdlibSUCCESS;
}

/**
 * Duplicate OI-VIS3 if index = 0 or add information relative to wavelengths
 * in first structure else.
 *
 * @param dstVis3 pointer to first OI-VIS3 structure.
 * @param srcVis3 pointer to second OI-VIS3 structure (to be copied).
 * @param index index on the location to place information.
 * @param nbOfElem number of elements to store.
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibCopyVis3From(amdlibVIS3       *dstVis3,
                                    amdlibVIS3       *srcVis3,
                                    int              index,
                                    int              nbOfElem,
                                    amdlibERROR_MSG  errMsg)
{
    int i, j;
    amdlibLogTrace("amdlibCopyVis3From()");
    
    if ((dstVis3->thisPtr == NULL) && (index != 0))
    {
        amdlibSetErrMsg("Could not copy non-initialized data from index %d",
                        index);
        return amdlibFAILURE;
    }

    if (srcVis3->thisPtr == NULL)
    {
        /* Nothing to do */
        return amdlibSUCCESS;
    }

    if (index == 0)
    {
        strcpy(dstVis3->dateObs, srcVis3->dateObs);
        dstVis3->averageClosure = srcVis3->averageClosure;
        dstVis3->averageClosureError = srcVis3->averageClosureError;

        /* Copy values in mergedVis3 */
        for (i=0; i < srcVis3->nbFrames * srcVis3->nbClosures; i++)
        {
            dstVis3->table[i].targetId = srcVis3->table[i].targetId;
            dstVis3->table[i].time = srcVis3->table[i].time;
            dstVis3->table[i].dateObsMJD = srcVis3->table[i].dateObsMJD;
            dstVis3->table[i].expTime = srcVis3->table[i].expTime;
            dstVis3->table[i].u1Coord = srcVis3->table[i].u1Coord;
            dstVis3->table[i].u2Coord = srcVis3->table[i].u2Coord;
            dstVis3->table[i].v1Coord = srcVis3->table[i].v1Coord;
            dstVis3->table[i].v2Coord = srcVis3->table[i].v2Coord;
            dstVis3->table[i].stationIndex[0] = 
                srcVis3->table[i].stationIndex[0];
            dstVis3->table[i].stationIndex[1] = 
                srcVis3->table[i].stationIndex[1];
            dstVis3->table[i].stationIndex[2] = 
                srcVis3->table[i].stationIndex[2];

            for (j=0; j < srcVis3->nbWlen; j++)
            {
                dstVis3->table[i].vis3Amplitude[j] = 
                    srcVis3->table[i].vis3Amplitude[j];
                dstVis3->table[i].vis3AmplitudeError[j] = 
                    srcVis3->table[i].vis3AmplitudeError[j];
                dstVis3->table[i].vis3Phi[j] = srcVis3->table[i].vis3Phi[j];
                dstVis3->table[i].vis3PhiError[j] = 
                    srcVis3->table[i].vis3PhiError[j];
                dstVis3->table[i].flag[j] = srcVis3->table[i].flag[j];
            }
        }
    }
    else
    {
        if (dstVis3->nbFrames != srcVis3->nbFrames)
        {
            amdlibSetErrMsg("Different number of frames! (%d and %d)",
                            dstVis3->nbFrames, srcVis3->nbFrames);
            return amdlibFAILURE;
        }
        if (dstVis3->nbClosures != srcVis3->nbClosures)
        {
            amdlibSetErrMsg("Different number of bases (%d and %d)",
                            dstVis3->nbClosures, srcVis3->nbClosures);
            return amdlibFAILURE;        
        }
        for (i=0; i < dstVis3->nbFrames * dstVis3->nbClosures; i++)
        {
            for (j=0; j < nbOfElem; j++)
            {
                dstVis3->table[i].vis3Amplitude[index+j] = 
                    srcVis3->table[i].vis3Amplitude[j];
                dstVis3->table[i].vis3AmplitudeError[index+j] = 
                    srcVis3->table[i].vis3AmplitudeError[j];
                dstVis3->table[i].vis3Phi[index+j] = 
                    srcVis3->table[i].vis3Phi[j];
                dstVis3->table[i].vis3PhiError[index+j] = 
                    srcVis3->table[i].vis3PhiError[j];
                dstVis3->table[i].flag[index+j] = srcVis3->table[i].flag[j];
            }
        }
    }
    return amdlibSUCCESS;
}

/**
 * Display phase closure structure.
 *
 * @param vis3 pointer to amdlibVIS3 structure.
 */
void amdlibDisplayVis3(amdlibVIS3 *vis3)
{
    int nbFrames, nbClosures, nbWlen;
    int iFrame, iClosure, iCell, iWave;
    amdlibDOUBLE averageClosure;
    amdlibDOUBLE averageClosureError;
    amdlibVIS3_TABLE_ENTRY cell;
    double vis3Amplitude;
    double vis3AmplitudeError;
    double vis3Phi;
    double vis3PhiError;

    amdlibLogTrace("amdlibDisplayVis3()");

    /* Display number of frames */
    nbFrames = vis3->nbFrames;
    printf("nbFrames = %d\n", nbFrames);
    
    /* Display number of closure phase */
    nbClosures = vis3->nbClosures;
    printf("nbClosures = %d\n", nbClosures);

    /* Display number of wavelength */
    nbWlen = vis3->nbWlen;
    printf("nbWlen = %d\n", nbWlen);

    /* Display mean visibility with corresponding error */
    averageClosure = vis3->averageClosure;
    averageClosureError = vis3->averageClosureError;
    printf("averageClosure = %f - ", averageClosure);
    printf("averageClosureError = %f\n", averageClosureError);

    /* Display different arrays[nbFrames][nbBases][nbWlen] */
    for (iFrame = 0; iFrame < nbFrames; iFrame++)
    {
        for (iClosure = 0; iClosure < nbClosures; iClosure++)
        {
            /* Set cell[iFrame][iBase] */
            iCell = iFrame * nbClosures + iClosure;
            cell =  vis3->table[iCell];
            printf("---> cell frame/base[%d][%d]\n", iFrame, iClosure);

            /* Display arrays[nbWlen] */
            for (iWave = 0; iWave < nbWlen; iWave++)
            {
                /* vis3Amplitude */
                vis3Amplitude = cell.vis3Amplitude[iWave];
                printf("vis3Amplitude[%d][%d][%d] = %f - ", iFrame, iClosure, 
                       iWave, vis3Amplitude);

                /* vis3AmplitudeError */
                vis3AmplitudeError = cell.vis3AmplitudeError[iWave];
                printf("vis3AmplitudeError[%d][%d][%d] = %f\n", iFrame,
                       iClosure, iWave, vis3AmplitudeError);
                /* vis3Phi */
                vis3Phi = cell.vis3Phi[iWave];
                printf("vis3Phi[%d][%d][%d] = %f - ", iFrame, iClosure, 
                       iWave, vis3Phi);
                
                /* vis3PhiError */
                vis3PhiError = cell.vis3PhiError[iWave];
                printf("vis3PhiError[%d][%d][%d] = %f\n", iFrame, iClosure, 
                       iWave, vis3PhiError);
            }
        }
    }
}

/**
 * Allocate memory for storing wavelenghts. 
 *
 * @param wave pointer to amdlibWAVELENGTH structure.
 * @param nbWlen number of spectral channels 
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibAllocateWavelength(amdlibWAVELENGTH *wave,
                                          const int        nbWlen,
                                          amdlibERROR_MSG  errMsg)
{
    amdlibLogTrace("amdlibAllocateWavelength()");
    
    /* First free previous allocated memory */
    if (wave->thisPtr == wave)
    {
        amdlibFreeWavelength(wave);
    }

    /* Init data structure */
    wave->thisPtr = memset(wave, '\0', sizeof(*wave));
    /* Set array size */
    wave->nbWlen = nbWlen;

    /* Allocate table pointer list  */
    wave->wlen = calloc(nbWlen, sizeof(amdlibDOUBLE));
    if (wave->wlen == NULL)
    {
        amdlibFreeWavelength(wave);
        amdlibSetErrMsg("%s wavelength array : %ld required", 
                        amdlibERR_ALLOC_MEM, (long)(nbWlen * sizeof(amdlibDOUBLE)));
        return amdlibFAILURE;
    }

    wave->bandwidth = calloc(nbWlen, sizeof(amdlibDOUBLE));
    if (wave->bandwidth == NULL)
    {
        amdlibFreeWavelength(wave);
        amdlibSetErrMsg("%s bandwidth array : %ld required", 
                        amdlibERR_ALLOC_MEM, (long)(nbWlen * sizeof(amdlibDOUBLE)));
        return amdlibFAILURE;
    }
    /* Return */
    return amdlibSUCCESS;
}

/**
 * Check if input wavelenghts are similar. 
 *
 * @param wave1 pointer to first amdlibWAVELENGTH structure.
 * @param wave2 pointer to second amdlibWAVELENGTH structure.
 * @param errMsg error description message returned if function fails or if
 * wavelengths differ.
 *
 * @return
 * amdlibTRUE if both structures are identical, amdlibFALSE if they are not.
 */
amdlibBOOLEAN amdlibCompareWavelengths(amdlibWAVELENGTH *wave1,
                                       amdlibWAVELENGTH *wave2,
                                       amdlibERROR_MSG  errMsg)
{
    int l;
    
    amdlibLogTrace("amdlibCompareWavelengths()");
    
    if ((wave1 == NULL) || (wave2 == NULL))
    {
        amdlibSetErrMsg("Invalid input parameter: NULL value");
        return amdlibFALSE;
    }
    
    if (wave1->nbWlen != wave2->nbWlen)
    {
        amdlibSetErrMsg("Different number of wavelengths");
        return amdlibFALSE;
    }
        
    for (l = 0; l < wave1->nbWlen; l++)
    {
        if (wave1->wlen[l] != wave2->wlen[l])
        {
            amdlibSetErrMsg("Different values in wlen array found");
            return amdlibFALSE;
        }
    }
    
    for (l = 0; l < wave1->nbWlen; l++)
    {
        if (wave1->bandwidth[l] != wave2->bandwidth[l])
        {
            amdlibSetErrMsg("Different in bandwidth array found");
            return amdlibFALSE;
        }
    }

    return amdlibTRUE;
}

/**
 * Merge wavelength structures.
 *
 * This function merges input wavelength structures and store the result in the
 * first one.
 *
 * @param wave1 pointer to first amdlibWAVELENGTH structure.
 * @param wave2 pointer to second amdlibWAVELENGTH structure (to merge).
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibMergeWavelengths(amdlibWAVELENGTH *wave1,
                                        amdlibWAVELENGTH *wave2,
                                        amdlibERROR_MSG  errMsg)
{
    amdlibWAVELENGTH *w1, *w2;
    amdlibWAVELENGTH merge = {NULL};
    amdlibDOUBLE upperBound1, upperBound2, lowerBound1, lowerBound2;
    int isIncresing1, isIncresing2;
    int i, j;
    
    amdlibLogTrace("amdlibMergeWavelengths()");
    /* Check wavelengths are sorted both increasing or both decreasing */
    if (wave1->wlen[wave1->nbWlen-1] - wave1->wlen[0] > 0)
    {
        upperBound1 = wave1->wlen[wave1->nbWlen-1];
        lowerBound1 = wave1->wlen[0];
        isIncresing1 = 1;
    }
    else
    {
        upperBound1 = wave1->wlen[0];
        lowerBound1 = wave1->wlen[wave1->nbWlen-1];
        isIncresing1 = 0;
    }
    if (wave2->wlen[wave2->nbWlen-1] - wave2->wlen[0] > 0)
    {
        upperBound2 = wave2->wlen[wave2->nbWlen-1];
        lowerBound2 = wave2->wlen[0];
        isIncresing2 = 1;
    }
    else
    {
        upperBound2 = wave2->wlen[0];
        lowerBound2 = wave2->wlen[wave2->nbWlen-1];
        isIncresing2 = 0;
    }

    if (isIncresing1 != isIncresing2)
    {
        amdlibSetErrMsg("Wavelengths are not sorted in the same order");
        return amdlibFAILURE;
    }

    /* Order the structures to be copied */
    if (upperBound1 < upperBound2)
    {
        /* Check there is no cover in wavelengths */
        if (upperBound1 >= lowerBound2)
        {
            amdlibSetErrMsg("Wavelengths are incompatible");
            return amdlibFAILURE;
        }
        w1 = wave2;
        w2 = wave1;
    }
    else
    {
        /* Check there is no cover in wavelengths */
        if (upperBound2 >= lowerBound1)
        {
            amdlibSetErrMsg("Wavelengths are incompatible");
            return amdlibFAILURE;
        }
        w1 = wave1;
        w2 = wave2;
    }

    /* Allocate memory for merged structure */
    if (amdlibAllocateWavelength(&merge, w1->nbWlen + w2->nbWlen, errMsg) != 
                                                                amdlibSUCCESS)
    {
        return amdlibFAILURE;
    }

    /* Copy good values into result structure */
    i = 0;
    while (i < w1->nbWlen)
    {
        merge.wlen[i] = w1->wlen[i];
        merge.bandwidth[i] = w1->bandwidth[i];
        i++;
    }
    for (j = 0; j < w2->nbWlen; j++)
    {
        merge.wlen[i+j] = w2->wlen[j];
        merge.bandwidth[i+j] = w2->bandwidth[j];
    }
    
    wave1->nbWlen = merge.nbWlen;
    free(wave1->wlen);
    free(wave1->bandwidth);
    wave1->wlen = merge.wlen;
    wave1->bandwidth = merge.bandwidth;
    
    return amdlibSUCCESS;
}

/**
 * Split amdlibWAVELENGTH input data structure into 3 structures, 1 per spectral
 * band. Each new structure only contains information relative to its associated
 * spectral band .
 *
 * @param srcWave pointer on wavelength structure to split.
 * @param dstWave array of splitted wavelength structures.
 * @param idxFirstWlen array containing the indexes of the first wavelength
 *        belonging to each spectral band.
 * @param nbWlen array containing the number of wavelengths per spectral band.
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibSplitWavelength(amdlibWAVELENGTH *srcWave,
                                       amdlibWAVELENGTH *dstWave,
                                       int              *idxFirstWlen,
                                       int              *nbWlen,
                                       amdlibERROR_MSG  errMsg)
{
    int band, index, j;

    amdlibLogTrace("amdlibSplitWavelength()");
    
    for (band=amdlibJ_BAND; band <= amdlibK_BAND; band++)
    {
        if (nbWlen[band] == 0)
        {
            dstWave[band].thisPtr = NULL;
        }
        else
        {
            /* Allocate memory for dstWave */
            if (amdlibAllocateWavelength(&dstWave[band], nbWlen[band], errMsg) 
                                                            != amdlibSUCCESS)
            {
                return amdlibFAILURE;
            }

            index = idxFirstWlen[band];
            for (j=0; j < nbWlen[band]; j++)
            {
                dstWave[band].wlen[j] = srcWave->wlen[index];
                dstWave[band].bandwidth[j] = srcWave->bandwidth[index];
                index ++;
            }
        }
    }
   
    return amdlibSUCCESS;
}

/**
 * Display spectral dispersion structure.
 *
 * @param wavelength pointer to amdlibWAVELENGTH structure.
 */
void amdlibDisplayWavelength(amdlibWAVELENGTH *wavelength)
{
    int nbWlen, i;
    
    amdlibLogTrace("amdlibDisplayWavelength()");

    /* Display number of wavelength */
    nbWlen = wavelength->nbWlen;
    printf("nbWlen = %d\n", nbWlen);

    /* Display wavelength array  and corresponding bandwidth array */
    for (i = 0; i < nbWlen; i++)
    {
        printf("nbWlen[%d] = %f - ", i, wavelength->wlen[i]);
        printf("bandWidth[%d] = %f\n", i, wavelength->bandwidth[i]);
    }
}

/**
 * Allocate memory for storing observed targets. 
 *
 * @param target pointer to amdlibOI_TARGET structure.
 * @param nbElements number of observed targets 
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibAllocateOiTarget(amdlibOI_TARGET *target,
                                        const int       nbElements)
{
    amdlibLogTrace("amdlibAllocateOiTarget()");
        
    /* First free previous allocated memory */
    if (target->thisPtr == target)
    {
        amdlibFreeOiTarget(target);
    }

    /* Init data structure */
    target->thisPtr = memset(target, '\0', sizeof(*target));
    /* Set array size */
    target->nbTargets = nbElements;

    /* Allocate table pointer list  */
    if (nbElements > 0) 
    {
        target->element = calloc(nbElements, sizeof(*(target->element)));
        if (target->element == NULL)
        {
            amdlibFreeOiTarget(target);
            return amdlibFAILURE;
        }
    }
    /* Return */
    return amdlibSUCCESS;
}

/**
 * Merge structures containing information on different bands. 
 *
 * @param wave pointer on merged wavelength data structure.
 * @param imdWave pointer on wavelength data structure to merge.
 * @param phot pointer on merged photometry data structure.
 * @param imdPhot pointer on photometry data structure to merge.
 * @param vis pointer on merged OI-VIS data structure.
 * @param imdVis pointer on OI-VIS data structure to merge.
 * @param vis2 pointer on merged OI-VIS2 data structure.
 * @param imdVis2 pointer on OI-VIS2 data structure to merge.
 * @param vis3 pointer on merged OI-VIS3 data structure.
 * @param imdVis3 pointer on OI-VIS3 data structure to merge.
 * @param opd pointer on merged piston data structure.
 * @param imdOpd pointer on piston data structure to merge.
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibMergeOiStructures(amdlibWAVELENGTH *wave, 
                                         amdlibWAVELENGTH *imdWave,
                                         amdlibPHOTOMETRY *phot, 
                                         amdlibPHOTOMETRY *imdPhot,
                                         amdlibVIS        *vis, 
                                         amdlibVIS        *imdVis,
                                         amdlibVIS2       *vis2, 
                                         amdlibVIS2       *imdVis2,
                                         amdlibVIS3       *vis3, 
                                         amdlibVIS3       *imdVis3,
                                         amdlibPISTON     *opd,
                                         amdlibPISTON     *imdOpd,
                                         amdlibERROR_MSG  errMsg)
{
    amdlibBOOLEAN isInverted = amdlibFALSE;
    int i;
    
    amdlibLogTrace("amdlibMergeOiStructures()");
    /* Merge wavelength data structures */
    if (wave->thisPtr == NULL)
    {
        if (imdWave->thisPtr == NULL)
        {
            amdlibSetErrMsg("No wavelength structures");
            return amdlibFAILURE;
        }
        else
        {
            /* Copy imdWave in wave */
            if (amdlibAllocateWavelength(wave, imdWave->nbWlen, errMsg) != 
                                                                amdlibSUCCESS)
            {
                return amdlibFAILURE;
            }
            for (i = 0; i < wave->nbWlen; i++)
            {
                wave->wlen[i] = imdWave->wlen[i];
                wave->bandwidth[i] = imdWave->bandwidth[i];
            }
        }
    }
    else
    {
        if(imdWave->thisPtr != NULL)
        {
            if (amdlibMergeWavelengths(wave, imdWave, errMsg) != amdlibSUCCESS)
            {
                return amdlibFAILURE;
            }
            if (wave->wlen[0] == imdWave->wlen[0])
            {
                isInverted = amdlibTRUE;
            }
        }
    }
    
    /* Merge photometries */
    if (phot->thisPtr == NULL)
    {
        if (imdPhot->thisPtr == NULL)
        {
            amdlibSetErrMsg("No photometry structures");
            return amdlibFAILURE;
        }
        else
        {
            /* Allocate memory for phot */
            if (amdlibAllocatePhotometry(phot, imdPhot->nbFrames, 
                                         imdPhot->nbBases, 
                                         imdPhot->nbWlen) != amdlibSUCCESS)
            {
                amdlibSetErrMsg("Could not allocate memory for photometry");
                return amdlibFAILURE;
            }

            /* Copy imdPhot in phot */
            if (amdlibCopyPhotFrom(phot, imdPhot, 0, imdPhot->nbWlen,
                                   errMsg) != amdlibSUCCESS)
            {
                return amdlibFAILURE;
            }
        }
    }
    else
    {
        if (imdPhot->thisPtr != NULL)
        {
            if (amdlibMergePhotometry(phot, imdPhot, isInverted,
                                      errMsg) != amdlibSUCCESS)
            {
                return amdlibFAILURE;
            }
        }
    }

    /* Merge vis */
    if (vis->thisPtr == NULL)
    {
        if (imdVis->thisPtr == NULL)
        {
            amdlibSetErrMsg("No vis structures");
            return amdlibFAILURE;
        }
        else
        {
            /* Copy imdVis in vis */
            if (amdlibAllocateVis(vis, imdVis->nbFrames,
                                  imdVis->nbBases, 
                                  imdVis->nbWlen) != amdlibSUCCESS)
            {
                amdlibSetErrMsg("Could not allocate memory for vis");
                return amdlibFAILURE;            
            }
            if (amdlibCopyVisFrom(vis, imdVis, 0, imdVis->nbWlen, 
                                  errMsg) != amdlibSUCCESS)
            {
                return amdlibFAILURE;
            }
        }
    }
    else
    {
        if (imdVis->thisPtr != NULL)
        {
            if (amdlibMergeVis(vis, imdVis, isInverted, 
                               errMsg) != amdlibSUCCESS)
            {
                return amdlibFAILURE;
            }
        }
    }

    /* Merge vis2 */
    if (vis2->thisPtr == NULL)
    {
        if (imdVis2->thisPtr == NULL)
        {
            amdlibLogWarning("No vis2 structures");
        }
        else
        {
            /* Copy imdVis2 in vis2 */
            if (amdlibAllocateVis2(vis2, imdVis2->nbFrames, imdVis2->nbBases,
                                   imdVis2->nbWlen) != amdlibSUCCESS)
            {
                amdlibSetErrMsg("Could not allocate memory for vis2");
                return amdlibFAILURE; 
            }
            if (amdlibCopyVis2From(vis2, imdVis2, 0, imdVis2->nbWlen, 
                                   errMsg) != amdlibSUCCESS)
            {
                return amdlibFAILURE;
            }
            
        }
    }
    else
    {
        if (imdVis2->thisPtr != NULL)
        {
            if (amdlibMergeVis2(vis2, imdVis2, isInverted, 
                                errMsg) != amdlibSUCCESS)
            {
                return amdlibFAILURE;
            }
        }
    }

    /* Merge vis3 */
    if (vis3->thisPtr == NULL)
    {
        if (imdVis3->thisPtr == NULL)
        {
            amdlibLogWarning("No vis3 structures");
        }
        else
        {
            /* Copy imdVis3 in vis3 */
            if (amdlibAllocateVis3(vis3, imdVis3->nbFrames, imdVis3->nbClosures,
                                   imdVis3->nbWlen) != amdlibSUCCESS)
            {
                amdlibSetErrMsg("Could not allocate memory for vis3");
                return amdlibFAILURE; 
            }
            if (amdlibCopyVis3From(vis3, imdVis3, 0, imdVis3->nbWlen, 
                                   errMsg) != amdlibSUCCESS)
            {
                return amdlibFAILURE;
            }
        }
    }
    else
    {
        if (imdVis3->thisPtr != NULL)
        {
            if (amdlibMergeVis3(vis3, imdVis3, isInverted, 
                                errMsg) != amdlibSUCCESS)
            {
                return amdlibFAILURE;
            }
        }
    }

    if (opd->thisPtr == NULL)
    {
        if (imdOpd->thisPtr == NULL)
        {
            amdlibLogWarning("No opd structures");
        }
        else
        {
            /* Copy imdOpd in opd */
            if (amdlibAllocatePiston(opd, imdOpd->nbFrames, 
                                     imdOpd->nbBases) != amdlibSUCCESS)
           {
                amdlibSetErrMsg("Could not allocate memory for opd");
                return amdlibFAILURE; 
            }
            for (i=0; i < amdlibNB_BANDS; i++)
            {
                opd->bandFlag[i] = imdOpd->bandFlag[i];
                memcpy(opd->pistonOPDArray[i], imdOpd->pistonOPDArray[i],
                       opd->nbFrames * opd->nbBases * sizeof(amdlibDOUBLE));
                memcpy(opd->sigmaPistonArray[i], imdOpd->sigmaPistonArray[i],
                       opd->nbFrames * opd->nbBases * sizeof(amdlibDOUBLE));
            }
            memcpy(opd->pistonOPD, imdOpd->pistonOPD, 
                   opd->nbFrames * opd->nbBases * sizeof(amdlibDOUBLE));
            memcpy(opd->sigmaPiston, imdOpd->sigmaPiston, 
                   opd->nbFrames * opd->nbBases * sizeof(amdlibDOUBLE));
        }
    }
    else
    {
        if (imdOpd->thisPtr != NULL)
        {
            if (amdlibMergePiston(opd, imdOpd, 
                                  errMsg) != amdlibSUCCESS)
            {
                return amdlibFAILURE;
            }
        }
    }

    return amdlibSUCCESS;
}

/**
 * Split oi-data into structures containing information on different bands. 
 *
 * @param wave pointer on input wavelength data structure.
 * @param imdWave array of result wavelength data structures.
 * @param phot pointer on input photometry data structure.
 * @param imdPhot array of result photometry data structures.
 * @param vis pointer on input OI-VIS data structure.
 * @param imdVis array of result OI-VIS data structures.
 * @param vis2 pointer on input OI-VIS2 data structure.
 * @param imdVis2 array of result OI-VIS2 data structures.
 * @param vis3 pointer on input OI-VIS3 data structure.
 * @param imdVis3 array of result OI-VIS3 data structures.
 * @param opd pointer on input piston data structure.
 * @param imdOpd array of result piston data structures.
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibSplitOiStructures(amdlibWAVELENGTH *wave, 
                                         amdlibWAVELENGTH *imdWave,
                                         amdlibPHOTOMETRY *phot, 
                                         amdlibPHOTOMETRY *imdPhot,
                                         amdlibVIS        *vis, 
                                         amdlibVIS        *imdVis,
                                         amdlibVIS2       *vis2, 
                                         amdlibVIS2       *imdVis2,
                                         amdlibVIS3       *vis3, 
                                         amdlibVIS3       *imdVis3,
                                         amdlibPISTON     *opd,
                                         amdlibPISTON     *imdOpd,
                                         amdlibERROR_MSG  errMsg)
{
    int idxFirstWlen[amdlibNB_BANDS] = {-1, -1, -1};
    int nbWlen[amdlibNB_BANDS] = {0, 0, 0};
    int i, band;
    
    amdlibLogTrace("amdlibSplitOiStructures()");
    for (i=0; i < wave->nbWlen; i++)
    {
        band = amdlibGetBand(wave->wlen[i]);
        if (band == amdlibUNKNOWN_BAND)
        {
            amdlibSetErrMsg("Unknown spectral band for wavelength %f", 
                            wave->wlen[i]);
            return amdlibFAILURE;
        }
        if (idxFirstWlen[band] == -1)
        {
            idxFirstWlen[band] = i;
        }
        nbWlen[band]++;
    }
    
    if (amdlibSplitPhot(phot, imdPhot, idxFirstWlen, nbWlen, 
                        errMsg) != amdlibSUCCESS)
    {
        return amdlibFAILURE;
    }
    
    if (amdlibSplitVis(vis, imdVis, idxFirstWlen, nbWlen, 
                       errMsg) != amdlibSUCCESS)
    {
        return amdlibFAILURE;
    }

    if (amdlibSplitVis2(vis2, imdVis2, idxFirstWlen, nbWlen, 
                        errMsg) != amdlibSUCCESS)
    {
        return amdlibFAILURE;
    }

    if (vis3->nbClosures != 0)
    {
        if (amdlibSplitVis3(vis3, imdVis3, idxFirstWlen, nbWlen, 
                            errMsg) != amdlibSUCCESS)
        {
            return amdlibFAILURE;
        }
    }
    else
    {
        amdlibLogWarning("No vis3 structures");
    }


    if (amdlibSplitPiston(opd, imdOpd, nbWlen, errMsg) != amdlibSUCCESS)
    {
        return amdlibFAILURE;
    }

    if (amdlibSplitWavelength(wave, imdWave, idxFirstWlen, nbWlen, 
                              errMsg) != amdlibSUCCESS)
    {
        return amdlibFAILURE;
    }

    return amdlibSUCCESS;
}

    
/*
 * Local functions
 */
/**
 * Free memory allocated for photometry. 
 *
 * @param photometry pointer to amdlibPHOTOMETRY structure.
 */
void amdlibFreePhotometry(amdlibPHOTOMETRY *photometry)
{
    amdlibLogTrace("amdlibFreePhotometry()");

    /* Check thisPtr and do nothing if unitialized */
    if (photometry->thisPtr != photometry)
    {
        return;
    }
    if (photometry->table != NULL)
    {
        /* There were 5 array defined allocated as a whole */
        if (photometry->table[0].PiMultPj != NULL)
        {
            free(photometry->table[0].PiMultPj);
        }
        if (photometry->table[0].fluxRatPiPj != NULL)
        {
            free(photometry->table[0].fluxRatPiPj);
        }
        if (photometry->table[0].sigma2FluxRatPiPj != NULL)
        {
            free(photometry->table[0].sigma2FluxRatPiPj);
        }
        if (photometry->table[0].fluxSumPiPj != NULL)
        {
            free(photometry->table[0].fluxSumPiPj);
        }
        if (photometry->table[0].sigma2FluxSumPiPj != NULL)
        {
            free(photometry->table[0].sigma2FluxSumPiPj);
        }
    }

    /* Free the table[...] array */
    free(photometry->table);
    photometry->table   = NULL;
    photometry->thisPtr = NULL;
}

/**
 * Reallocate memory to store photometry. 
 *
 * @param photometry pointer to amdlibPHOTOMETRY structure.
 * @param nbFrames number of frames 
 * @param nbBases number of baselines 
 * @param nbWlen number of spectral channels 
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibReallocatePhotometry(amdlibPHOTOMETRY *photometry,
                                            const int        nbFrames,
                                            const int        nbBases,
                                            const int        nbWlen)
{
    int arraySize = nbWlen * sizeof(double);
    int nbSamples = nbFrames * nbBases;
    int i;
    void *pointer;
    
    photometry->table = realloc(photometry->table, 
                                nbSamples * 
                                sizeof(amdlibPHOTOMETRY_TABLE_ENTRY));
    if (photometry->table == NULL)
    {
        return amdlibFAILURE;
    }
    
    photometry->table[0].fluxSumPiPj = 
        realloc(photometry->table[0].fluxSumPiPj, nbSamples * arraySize);
    if (photometry->table[0].fluxSumPiPj == NULL)
    {
        return amdlibFAILURE;
    }
    for (i = 0, pointer = photometry->table[0].fluxSumPiPj; 
         i < nbSamples; i++, pointer += arraySize)
    {
        photometry->table[i].fluxSumPiPj = pointer;
    }
    
    photometry->table[0].sigma2FluxSumPiPj = 
        realloc(photometry->table[0].sigma2FluxSumPiPj, 
                nbFrames * nbBases * arraySize);
    if (photometry->table[0].sigma2FluxSumPiPj == NULL)
    {
        return amdlibFAILURE;
    }
    for (i = 0, pointer = photometry->table[0].sigma2FluxSumPiPj; 
         i < nbSamples; i++, pointer += arraySize)
    {
        photometry->table[i].sigma2FluxSumPiPj = pointer;
    }

    photometry->table[0].fluxRatPiPj = 
        realloc(photometry->table[0].fluxRatPiPj, 
                nbFrames * nbBases * arraySize);
    if (photometry->table[0].fluxRatPiPj == NULL)
    {
        return amdlibFAILURE;
    }
    for (i = 0, pointer = photometry->table[0].fluxRatPiPj; 
         i < nbSamples; i++, pointer += arraySize)
    {
        photometry->table[i].fluxRatPiPj = pointer;
    }

    photometry->table[0].sigma2FluxRatPiPj = 
        realloc(photometry->table[0].sigma2FluxRatPiPj, 
                nbFrames * nbBases * arraySize);
    if (photometry->table[0].sigma2FluxRatPiPj == NULL)
    {
        return amdlibFAILURE;
    }
    for (i = 0, pointer = photometry->table[0].sigma2FluxRatPiPj; 
         i < nbSamples; i++, pointer += arraySize)
    {
        photometry->table[i].sigma2FluxRatPiPj = pointer;
    }

    photometry->table[0].PiMultPj = 
        realloc(photometry->table[0].PiMultPj, 
                nbFrames * nbBases * arraySize);
    if (photometry->table[0].PiMultPj == NULL)
    {
        return amdlibFAILURE;
    }
    for (i = 0, pointer = photometry->table[0].PiMultPj; 
         i < nbSamples; i++, pointer += arraySize)
    {
        photometry->table[i].PiMultPj = pointer;
    }

    photometry->nbFrames = nbFrames;
    return amdlibSUCCESS;
}

/**
 * Free memory allocated for visibilities. 
 *
 * @param vis pointer to amdlibVIS structure.
 */
void amdlibFreeVis(amdlibVIS *vis)
{
    amdlibLogTrace("amdlibFreeVis()");
    
    /* Check thisPtr and do nothing if unitialized */
    if (vis->thisPtr != vis)
    {
        return;
    }
    if (vis->table != NULL)
    {
        /* There were 3 array defined allocated as a whole */
        if (vis->table[0].vis != NULL)
        {
            free(vis->table[0].vis);
        }
        if (vis->table[0].sigma2Vis != NULL)
        {
            free(vis->table[0].sigma2Vis);
        }
        if (vis->table[0].visCovRI != NULL)
        {
            free(vis->table[0].visCovRI);
        }
        if (vis->table[0].diffVisAmp != NULL)
        {
            free(vis->table[0].diffVisAmp);
        }
        if (vis->table[0].diffVisAmpErr != NULL)
        {
            free(vis->table[0].diffVisAmpErr);
        }
        if (vis->table[0].diffVisPhi != NULL)
        {
            free(vis->table[0].diffVisPhi);
        }
        if (vis->table[0].diffVisPhiErr != NULL)
        {
            free(vis->table[0].diffVisPhiErr);
        }
        if (vis->table[0].flag != NULL)
        {
            free(vis->table[0].flag);
        }
    }
    
    /* Free the table[...] array */
    free(vis->table);
    vis->table   = NULL;
    vis->thisPtr = NULL;
}

/**
 * Reallocate memory for storing visibilities. 
 *
 * @param vis pointer to amdlibVIS structure.
 * @param nbFrames number of frames 
 * @param nbBases number of baselines 
 * @param nbWlen number of spectral channels 
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibReallocateVis(amdlibVIS *vis,
                                     const int nbFrames,
                                     const int nbBases,
                                     const int nbWlen)
{
    int arraySize = nbWlen * sizeof(amdlibCOMPLEX);
    int nbSamples = nbFrames * nbBases;
    int i;
    void *pointer;
    
    vis->table = realloc(vis->table, 
                         nbSamples * sizeof(amdlibVIS_TABLE_ENTRY));
    if (vis->table == NULL)
    {
        return amdlibFAILURE;
    }

    vis->table[0].vis = realloc(vis->table[0].vis, nbSamples * arraySize);
    if (vis->table[0].vis == NULL)
    {
        return amdlibFAILURE;
    }
    for (i = 0, pointer = vis->table[0].vis; 
         i < nbSamples; 
         i++, pointer += arraySize)
    {
        vis->table[i].vis = pointer;
    }

    vis->table[0].sigma2Vis = realloc(vis->table[0].sigma2Vis, 
                                      nbSamples * arraySize);

    if (vis->table[0].sigma2Vis == NULL)
    {
        return amdlibFAILURE;
    }
    for (i = 0, pointer = vis->table[0].sigma2Vis; 
         i < nbSamples; 
         i++, pointer += arraySize)
    {
        vis->table[i].sigma2Vis = pointer;
    }

    arraySize =  nbWlen * sizeof(double);
    vis->table[0].visCovRI = realloc(vis->table[0].visCovRI, 
                                     nbSamples * arraySize);
    if (vis->table[0].visCovRI == NULL)
    {
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis->table[0].visCovRI; 
         i < nbSamples; 
         i++, pointer += arraySize)
    {
        vis->table[i].visCovRI = pointer;
    }

    vis->table[0].diffVisAmp = realloc(vis->table[0].diffVisAmp, 
                                     nbSamples * arraySize);
    if (vis->table[0].diffVisAmp == NULL)
    {
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis->table[0].diffVisAmp; 
         i < nbSamples; 
         i++, pointer += arraySize)
    {
        vis->table[i].diffVisAmp = pointer;
    }
    vis->table[0].diffVisAmpErr = realloc(vis->table[0].diffVisAmpErr, 
                                     nbSamples * arraySize);
    if (vis->table[0].diffVisAmpErr == NULL)
    {
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis->table[0].diffVisAmpErr; 
         i < nbSamples; 
         i++, pointer += arraySize)
    {
        vis->table[i].diffVisAmpErr = pointer;
    }

    vis->table[0].diffVisPhi = realloc(vis->table[0].diffVisPhi, 
                                     nbSamples * arraySize);
    if (vis->table[0].diffVisPhi == NULL)
    {
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis->table[0].diffVisPhi; 
         i < nbSamples; 
         i++, pointer += arraySize)
    {
        vis->table[i].diffVisPhi = pointer;
    }
    
    vis->table[0].diffVisPhiErr = realloc(vis->table[0].diffVisPhiErr, 
                                     nbSamples * arraySize);
    if (vis->table[0].diffVisPhiErr == NULL)
    {
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis->table[0].diffVisPhiErr; 
         i < nbSamples; 
         i++, pointer += arraySize)
    {
        vis->table[i].diffVisPhiErr = pointer;
    }

    arraySize = nbWlen * sizeof(amdlibBOOLEAN);
    vis->table[0].flag = realloc(vis->table[0].flag, nbSamples * arraySize);
    if (vis->table[0].flag == NULL)
    {
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis->table[0].flag; 
         i < nbSamples; 
         i++, pointer += arraySize)
    {
        vis->table[i].flag = pointer;
    }

    vis->nbFrames = nbFrames;
    return amdlibSUCCESS;
}

/**
 * Free memory allocated for squared visibilities. 
 *
 * @param vis2 pointer to amdlibVIS2 structure.
 */
void amdlibFreeVis2(amdlibVIS2 *vis2)
{
    amdlibLogTrace("amdlibFreeVis2()");
    
    /* Check thisPtr and do nothing if unitialized*/
    if (vis2->thisPtr != vis2) 
    {
        return;
    }
    if (vis2->table != NULL)
    { /* there were 2 arrays defined allocated as a whole */
        if (vis2->table[0].vis2 != NULL)
        {
            free(vis2->table[0].vis2);
        }
        if (vis2->table[0].vis2Error != NULL)
        {
            free(vis2->table[0].vis2Error);
        }
        if (vis2->table[0].flag != NULL)
        {
            free(vis2->table[0].flag);
        }
    }

    /* Free the table[...] array */
    free(vis2->table);
    vis2->table = NULL;
    vis2->thisPtr = NULL;
}

/**
 * Reallocate memory for storing squared visibilities. 
 *
 * @param vis2 pointer to amdlibVIS2 structure.
 * @param nbFrames number of frames 
 * @param nbBases number of baselines 
 * @param nbWlen number of spectral channels 
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibReallocateVis2(amdlibVIS2 *vis2,
                                      const int  nbFrames,
                                      const int  nbBases,
                                      const int  nbWlen)
{
    int arraySize = nbWlen * sizeof(double);
    int nbSamples = nbFrames * nbBases;
    int i;
    void *pointer;
    
    vis2->table = realloc(vis2->table, 
                          nbSamples * sizeof(amdlibVIS2_TABLE_ENTRY));
    if (vis2->table == NULL)
    {
        return amdlibFAILURE;
    }

    vis2->table[0].vis2 = realloc(vis2->table[0].vis2, nbSamples * arraySize);
    if (vis2->table[0].vis2 == NULL)
    {
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis2->table[0].vis2; 
         i < nbSamples; 
         i++, pointer += arraySize)
    {
        vis2->table[i].vis2 = pointer;
    }

    vis2->table[0].vis2Error = realloc(vis2->table[0].vis2Error,
                                       nbSamples * arraySize);
    if (vis2->table[0].vis2Error == NULL)
    {
        amdlibFreeVis2(vis2);
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis2->table[0].vis2Error; 
         i < nbSamples; 
         i++, pointer += arraySize)
    {
        vis2->table[i].vis2Error = pointer;
    }

    arraySize = nbWlen * sizeof(amdlibBOOLEAN);
    vis2->table[0].flag = realloc(vis2->table[0].flag, nbSamples * arraySize);
    if (vis2->table[0].flag == NULL)
    {
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis2->table[0].flag; 
         i < nbSamples; 
         i++, pointer += arraySize)
    {
        vis2->table[i].flag = pointer;
    }

    vis2->nbFrames = nbFrames;
    return amdlibSUCCESS;
}

/**
 * Free memory allocated for phase closures. 
 *
 * @param vis3 pointer to amdlibVIS3 structure.
 */
void amdlibFreeVis3(amdlibVIS3 *vis3)
{
    amdlibLogTrace("amdlibFreeVis3()");
    
    /* Check thisPtr and do nothing if unitialized*/
    if (vis3->thisPtr != vis3) 
    {
        return;
    }
    if (vis3->table != NULL)
    {
        if (vis3->table[0].vis3Amplitude != NULL)
        {
            free(vis3->table[0].vis3Amplitude);
        }
        if (vis3->table[0].vis3AmplitudeError != NULL)
        {
            free(vis3->table[0].vis3AmplitudeError);
        }
        if (vis3->table[0].vis3Phi != NULL)
        {
            free(vis3->table[0].vis3Phi);
        }
        if (vis3->table[0].vis3PhiError != NULL)
        {
            free(vis3->table[0].vis3PhiError);
        }
        if (vis3->table[0].flag != NULL)
        {
            free(vis3->table[0].flag);
        }
    }
    /* free the table[...] array */
    free(vis3->table);
    vis3->table = NULL;
    vis3->thisPtr = NULL;
}

/**
 * Reallocate memory for storing phase closures. 
 *
 * @param vis3 pointer to amdlibVIS3 structure.
 * @param nbFrames number of frames 
 * @param nbClosures number of phase closures 
 * @param nbWlen number of spectral channels 
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibReallocateVis3(amdlibVIS3 *vis3,
                                      const int nbFrames,
                                      const int nbClosures,
                                      const int nbWlen)
{
    int arraySize = nbWlen * sizeof(double);
    int nbSamples = nbFrames * nbClosures;
    int i;
    void *pointer;

    vis3->table = realloc(vis3->table, nbSamples * sizeof(*(vis3->table)));
    if (vis3->table == NULL)
    {
        return amdlibFAILURE;
    }

    vis3->table[0].vis3Amplitude = realloc(vis3->table[0].vis3Amplitude,
                                           nbSamples * arraySize);
    if (vis3->table[0].vis3Amplitude == NULL)
    {
        return amdlibFAILURE;
    }
    for (i = 0, pointer = vis3->table[0].vis3Amplitude; 
         i < nbSamples; 
         i++, pointer += arraySize)
    {
        vis3->table[i].vis3Amplitude = pointer;
    }

    vis3->table[0].vis3AmplitudeError = 
        realloc(vis3->table[0].vis3AmplitudeError, nbSamples * arraySize);
    if (vis3->table[0].vis3AmplitudeError == NULL)
    {
        return amdlibFAILURE;
    }
    for (i = 0, pointer = vis3->table[0].vis3AmplitudeError; 
         i < nbSamples; 
         i++, pointer += arraySize)
    {
        vis3->table[i].vis3AmplitudeError = pointer;
    }
    
    vis3->table[0].vis3Phi = realloc(vis3->table[0].vis3Phi,
                                     nbSamples * arraySize);
    if (vis3->table[0].vis3Phi == NULL)
    {
        return amdlibFAILURE;
    }
    for (i = 0, pointer = vis3->table[0].vis3Phi; 
         i < nbSamples; 
         i++, pointer += arraySize)
    {
        vis3->table[i].vis3Phi = pointer;
    }

    vis3->table[0].vis3PhiError = realloc(vis3->table[0].vis3PhiError,
                                          nbSamples * arraySize);
    if (vis3->table[0].vis3PhiError == NULL)
    {
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis3->table[0].vis3PhiError; 
         i < nbSamples; 
         i++, pointer += arraySize)
    {
        vis3->table[i].vis3PhiError = pointer;
    }

    arraySize = nbWlen * sizeof(amdlibBOOLEAN);
    vis3->table[0].flag = realloc(vis3->table[0].flag, nbSamples * arraySize);
    if (vis3->table[0].flag == NULL)
    {
        return amdlibFAILURE;
    }
    /* Then dispatch the other pointers accordingly */
    for (i = 0, pointer = vis3->table[0].flag; 
         i < nbSamples; 
         i++, pointer += arraySize)
    {
        vis3->table[i].flag = pointer;
    }

    vis3->nbFrames = nbFrames;
    return amdlibSUCCESS;
}

/**
 * Free memory allocated for wavelenghts. 
 *
 * @param wave pointer to amdlibWAVELENGTH structure.
 */
void amdlibFreeWavelength(amdlibWAVELENGTH *wave)
{
    amdlibLogTrace("amdlibFreeWavelength()");
    
    /* Check thisPtr and do nothing if unitialized*/
    if (wave->thisPtr != wave)
    {
        return;
    }
    if (wave->wlen != NULL)
    {
        free(wave->wlen);
    }
    if (wave->bandwidth != NULL)
    {
        free(wave->bandwidth);
    }

    wave->wlen = NULL;
    wave->bandwidth = NULL;
    wave->thisPtr = NULL;
}


/**
 * Free memory allocated for observed targets. 
 *
 * @param target pointer to amdlibOI_TARGET structure.
 */

void amdlibFreeOiTarget(amdlibOI_TARGET *target)
{
    amdlibLogTrace("amdlibFreeOiTarget()");
    
    /* Check thisPtr and do nothing if unitialized*/
    if (target->thisPtr != target)
    {
        return;
    }
    if (target->element != NULL) 
    {
        free(target->element);
    }
    memset (target, '\0', sizeof(*target));
}

