/* $Id: amber_detector.c,v 1.16 2013-09-16 14:56:43 agabasch Exp $
 *
 * This file is part of the AMBER Pipeline
 * Copyright (C) 2002,iFrom03 European Southern Observatory
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/*
 * $Author: agabasch $
 * $Date: 2013-09-16 14:56:43 $
 * $Revision: 1.16 $
 * $Name: not supported by cvs2svn $
 */

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

/* AMDLIB usage switch */
#define USE_AMDLIB YES

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

#include <math.h>
#include <cpl.h>
#include <string.h>
#include "amdrs.h"
#include "amber_dfs.h"

#include "amdms.h"   /* amdms library detector calibration */

/* PAF file and QC log */
#include "giqclog.h"
/* #include "giutils.h" */

#ifdef USE_AMDLIB	

/* amdlib structures */
amdlibERROR_MSG       errMsg;
amdlibBAD_PIXEL_MAP   badPixels;
amdlibFLAT_FIELD_MAP  flatField;
amdlibP2VM_INPUT_DATA p2vmData;
amdlibP2VM_MATRIX     p2vm;

#endif

cpl_parameterlist *   gparlist; 
cpl_frameset      *   gframelist;
cpl_propertylist  *   pHeader;


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

static int amber_detector_create(cpl_plugin *) ;
static int amber_detector_exec(cpl_plugin *) ;
static int amber_detector_destroy(cpl_plugin *) ;
static int amber_detector(cpl_parameterlist *, cpl_frameset *) ;
cpl_propertylist * DetectorCreateProductHeader( const char * fctid,
		char * szRawFile, cpl_frame * pFrameProduct );

/*-----------------------------------------------------------------------------
                            Static variables
 -----------------------------------------------------------------------------*/

/*
static struct {
	 Inputs
	int         bool_option ;
	char        str_option[512] ;

	 Outputs
	double      qc_param ;
} amber_detector_config ;
 */

static char amber_detector_man[] =
		"This recipe is creating the master flatfield and the bad pixel map\n"
		"\n";

/*-----------------------------------------------------------------------------
                                Functions code
 -----------------------------------------------------------------------------*/


/*----------------------------------------------------------------------------*/
/**
  @brief    Append the properties in one list to another
  @param    self   The PAF propertylist to append to
  @param    other  The propertylist whose elements are copied or NULL
  @return   CPL_ERROR_NONE or the relevant #_cpl_error_code_ on error

  If other is NULL or empty nothing happens

  Comments are copied as well, but it is (currently) undefined how this works
  for non-unique properties.

  In addition the hierarchical keys will be changed according to the PAF rules:

  No ESO as first part
  No blank separator but a .
 */
/*----------------------------------------------------------------------------*/
static cpl_error_code amber_propertylist_append(cpl_propertylist * self,
		const cpl_propertylist * other)
{

	int i, c;
	char szPAF[2048];
	char szTMP[2048];

	if (other == NULL) return CPL_ERROR_NONE;

	/*visir_assure_code(self, CPL_ERROR_NULL_INPUT);*/

	for (i=0; i < cpl_propertylist_get_size(other); i++)
	{
		const cpl_property * prop = cpl_propertylist_get((cpl_propertylist *)
				other, i);
		const char * name    = cpl_property_get_name(prop);
		/*const char * comment = cpl_property_get_comment(prop);*/

		cpl_error_code err;

		/* Change the key to PAF syntax */
		strcpy( szPAF, name );

		/* Get rid of ESO (HAR, what a joke!) */
		if( !strncmp( szPAF, "ESO", 3 ) )
		{
			strcpy( szTMP, &szPAF[4] );
			strcpy( szPAF, szTMP );
		}

		/* Substitute spaces by points (YEAH!) */
		for( c=0; c<(int)strlen(szPAF); c++ )
			if( szPAF[c] == ' ' )
				szPAF[c] = '.';

		strcpy( (char *)name, szPAF );

		/* Append prop to self */

		switch (cpl_property_get_type(prop)) {
		case CPL_TYPE_CHAR:
			err = cpl_propertylist_append_char(self, name,
					cpl_property_get_char(prop));
		case CPL_TYPE_BOOL:
			err = cpl_propertylist_append_bool(self, name,
					cpl_property_get_bool(prop));
			break;
		case CPL_TYPE_INT:
			err = cpl_propertylist_append_int(self, name,
					cpl_property_get_int(prop));
			break;
		case CPL_TYPE_LONG:
			err = cpl_propertylist_append_long(self, name,
					cpl_property_get_long(prop));
			break;
		case CPL_TYPE_FLOAT:
			err = cpl_propertylist_append_float(self, name,
					cpl_property_get_float(prop));
			break;
		case CPL_TYPE_DOUBLE:
			err = cpl_propertylist_append_double(self, name,
					cpl_property_get_double(prop));
			break;
		case CPL_TYPE_STRING:
			err = cpl_propertylist_append_string(self, name,
					cpl_property_get_string(prop));
			break;

			/* Avoid compiler warnings but do nothing */
		case CPL_TYPE_FLAG_ARRAY:
		case CPL_TYPE_INVALID:
		case CPL_TYPE_UCHAR:
		case CPL_TYPE_UINT:
		case CPL_TYPE_ULONG:
		case CPL_TYPE_POINTER:
		case CPL_TYPE_FLOAT_COMPLEX:
		case CPL_TYPE_DOUBLE_COMPLEX:
		case CPL_TYPE_BITMASK:
		case CPL_TYPE_COMPLEX:
		case CPL_TYPE_LONG_LONG:
		case CPL_TYPE_SHORT:
		case CPL_TYPE_SIZE:
		case CPL_TYPE_USHORT:
		case CPL_TYPE_UNSPECIFIED:
			/*case CPL_TYPE_COMPLEX: not anymode in CPL 3.0 */
			break;
			/*default:
            visir_assure_code(0, CPL_ERROR_UNSUPPORTED_MODE);*/
		}

		/*visir_assure_code(!err, err);

        if (comment && cpl_propertylist_set_comment(self, name, comment))
            visir_assure_code(0, cpl_error_get_code());*/
	}

	return CPL_ERROR_NONE;
}


cpl_propertylist * DetectorCreateProductHeader( const char * fctid, char * szRawFile, cpl_frame * pFrameProduct )
{
	int  iStatus = 0;
	char szMessage[1024];

	cpl_frameset * frameSetTmp;
	cpl_frame    * frameTmp;
	/*cpl_propertylist *  pHeader;*/

	/* For DFS fill Header function later */;
	/*   pHeader = cpl_propertylist_new();   */

	/*
	 * Create the Product file, start with filling the header
	 *
	 * Attention: for the time of this workaround for cpl 3D tables the amdlib must
	 * be patched to NOT create OWN files, but APPEND to existing ones!!
	 *
	 * see comment below
	 *
	 */


	/*
	 * Workaround for cpl_dfs_setup_product_header picking the wrong Header in this CPL release and
	 * also might pick the wrong in the future! It uses the first RAW frame, but this recipe can handle
	 * many raw frames. Hence:
	 *
	 * Read the Header of the RAW file to be written as a product and send it to the function
	 */
	pHeader = cpl_propertylist_load(  szRawFile, 0 );

	/* Create a set of frames with just this frame, so header will be correct */
	frameSetTmp = cpl_frameset_new();
	frameTmp    = cpl_frame_new();

	cpl_frame_set_filename( frameTmp, szRawFile );
	cpl_frame_set_type( frameTmp, CPL_FRAME_TYPE_TABLE );
	cpl_frame_set_tag( frameTmp, "AMBER_DETECTOR" );
	cpl_frame_set_group( frameTmp, CPL_FRAME_GROUP_RAW );
	cpl_frame_set_level( frameTmp, CPL_FRAME_LEVEL_NONE );
	cpl_frameset_insert( frameSetTmp, frameTmp );

	/* Add the necessary DFS fits header information to the product */
#if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 8, 0)
	if( cpl_dfs_setup_product_header(  pHeader,
			pFrameProduct,
			frameSetTmp,
			gparlist,
			"amber_detector", /* const char *  recid,  */
			PACKAGE "/" PACKAGE_VERSION, /* const char *  pipeline_id,  */
			"AMBER",  /* const char *  dictionary_id */
			NULL
	)  != CPL_ERROR_NONE )
	{
		/* Error */
		sprintf( szMessage, "Error in setting up the product header." );
		cpl_msg_info( fctid, "%s", szMessage );
		iStatus = 16;
	}
#else 
	if( cpl_dfs_setup_product_header(  pHeader,
			pFrameProduct,
			frameSetTmp,
			gparlist,
			"amber_detector", /* const char *  recid,  */
			PACKAGE "/" PACKAGE_VERSION, /* const char *  pipeline_id,  */
			"AMBER"  /* const char *  dictionary_id */
	)  != CPL_ERROR_NONE )
	{
		/* Error */
		sprintf( szMessage, "Error in setting up the product header." );
		cpl_msg_info( fctid, "%s", szMessage );
		iStatus = 16;
	}
#endif
	/* Destroy tmpFrameset and implicitly its contents */
	cpl_frameset_delete( frameSetTmp );
	/*cpl_frame_delete( frameTmp );*/

	return pHeader;
} 

/*----------------------------------------------------------------------------*/
/**
  @brief    Build the list of available plugins, for this module. 
  @param    list    the plugin list
  @return   0 if everything is ok

  This function is exported.
 */
/*----------------------------------------------------------------------------*/
int cpl_plugin_get_info(cpl_pluginlist * list)
{
	cpl_recipe  *   recipe = cpl_calloc(1, sizeof(*recipe)) ;
	cpl_plugin  *   plugin = &recipe->interface ;

	cpl_plugin_init(plugin,
			CPL_PLUGIN_API,
			AMBER_BINARY_VERSION,
			CPL_PLUGIN_TYPE_RECIPE,
			"amber_detector",
			"AMBER raw data detector",
			amber_detector_man,
			"Tom Licha",
			PACKAGE_BUGREPORT,
			"GP",
			amber_detector_create,
			amber_detector_exec,
			amber_detector_destroy) ;

	cpl_pluginlist_append(list, plugin) ;

	return 0;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Setup the recipe options    
  @param    plugin  the plugin
  @return   0 if everything is ok

  Create the recipe instance and make it available to the application using the 
  interface. 
 */
/*----------------------------------------------------------------------------*/
static int amber_detector_create(cpl_plugin * plugin)
{
	cpl_recipe * recipe = (cpl_recipe *)plugin ;
	cpl_parameter * p ;

	/* Create the parameters list in the cpl_recipe object */
	recipe->parameters = cpl_parameterlist_new() ;

	/* Fill the parameters list */
#ifdef USE_PARAMETERS_HERE    
	/* --stropt */
	p = cpl_parameter_new_value("amber.amber_detector.str_option",
			CPL_TYPE_STRING, "the string option", "amber.amber_detector",NULL);
	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stropt") ;
	cpl_parameterlist_append(recipe->parameters, p) ;

#endif     
	/* binning int */
	p = cpl_parameter_new_value("amber.amber_detector.int_maxframes",
			CPL_TYPE_INT, "maximum Frames to be processed", "amber.amber_detector", 500 ) ;
	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "maxFrames") ;
	cpl_parameterlist_append(recipe->parameters, p) ;

	/* Return */
	return 0;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Execute the plugin instance given by the interface
  @param    plugin  the plugin
  @return   0 if everything is ok
 */
/*----------------------------------------------------------------------------*/
static int amber_detector_exec(cpl_plugin * plugin)
{
	cpl_recipe * recipe = (cpl_recipe *)plugin ;
	return amber_detector(recipe->parameters, recipe->frames) ;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Destroy what has been created by the 'create' function
  @param    plugin  the plugin
  @return   0 if everything is ok
 */
/*----------------------------------------------------------------------------*/
static int amber_detector_destroy(cpl_plugin * plugin)
{
	cpl_recipe  *   recipe = (cpl_recipe *)plugin ;
	cpl_parameterlist_delete(recipe->parameters) ;
	return 0 ;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Get the command line options and execute the data reduction
  @param    parlist     the parameters list
  @param    framelist   the frames list
  @return   0 if everything is ok
 */
/*----------------------------------------------------------------------------*/
static int amber_detector(
		cpl_parameterlist     *   parlist,
		cpl_frameset    *   framelist)
{

	/* CPL structures */
	/*	cpl_frameset  * cur_set=NULL;*/
	cpl_frame     * cur_frame=NULL;
	cpl_parameter * cur_param;

	char   szMessage[1024];
	char * pszFilename=NULL;
	char * pszFileTag=NULL;

	/*
	cpl_frame        *  pFrame   = NULL;
	cpl_propertylist *  pHeader  = NULL;
	 */
	cpl_propertylist *  pCValues = NULL;

	cpl_frame        * pFrameBPM = NULL;
	/*	cpl_frame        * pFrameFFM = NULL;*/

	int  iStatus           = 0;
	int  iFrameCountDark   = 0;
	int  iFrameCountFlat   = 0;

	cpl_frameset_iterator * it = NULL;

	int  i                 = 0;

	int    iBadPix   = 0;
	int    iGoodPix  = 0;
	double dBadRatio = 0.F;

	int    iMaxFrames = 0;

	char szInputDark[7][1024];
	char szInputFlat[7][1024];
	char szProduct[1024];

	const char * pszARCFILE;

	char szTemp[1024];
	int iFrom = 0;
	int iTo   = 0;
	/* amdsm control structures */
	amdmsALGO_STAT_ENV       * statEnv = NULL;
	amdmsALGO_PROPERTIES_ENV * ppEnv = NULL;
	amdmsALGO_BAD_PIXEL_ENV  * badpixelEnv = NULL;
	amdmsFITS_FLAGS            flags;
	const char * fctid = "amber_detector";

	/*
	cur_set     = NULL;
	cur_frame   = NULL;
	pszFilename = NULL;
	pszFileTag  = NULL;
	 */

	cpl_propertylist * qc_properties = NULL;
	cpl_image        * pImage        = NULL;
	AmPaf            * qc            = NULL;
	cpl_propertylist * qclog         = NULL;
	cpl_propertylist * qcFromProduct = NULL;
	cpl_propertylist * qcFromRawfile = NULL;

	amber_dfs_set_groups(framelist);
	cur_param = cpl_parameterlist_find( parlist, "amber.amber_detector.int_maxframes" );
	iMaxFrames = cpl_parameter_get_int( cur_param );

	/* This variable will control how many frames are taken into account.
	 * It should be >= 500 to get highest precision and not smaller than 21
	 * because the first 20 frames will be skipped anyway due to the readout
	 *  mode of the detector */

	iFrom = 20;
	iTo   = iFrom + iMaxFrames;




	cpl_msg_info( fctid, "Start of DataReduction");




	sprintf( szMessage, "Using frames from %d to %d", iFrom, iTo );
	cpl_msg_info( fctid, "%s", szMessage );


	/*
    Walk through the whole Set of Frames SOF and search for DETECTOR_FFM and DETECTOR_DARK
    Seven of each are needed
	 */

	it = cpl_frameset_iterator_new(framelist);


	while((cur_frame = cpl_frameset_iterator_get(it)))
	{
		/* Get Filename and Classification Tag */
		pszFilename = (char *)cpl_frame_get_filename( cur_frame );
		pszFileTag  = (char *)cpl_frame_get_tag( cur_frame );


		/* Check Tag and Filename */
		if( pszFilename && pszFileTag )
		{
			/* DETECTOR_FFM */
			if( iFrameCountFlat < 7 && !strcmp( pszFileTag, "AMBER_DETECTOR_FFM" ) )
			{

				strcpy( szInputFlat[iFrameCountFlat], pszFilename );
				iFrameCountFlat++;

				sprintf( szMessage, "DETECTOR_FFM %d %s", iFrameCountFlat, pszFilename );
				cpl_msg_info( fctid, "%s", szMessage );
			}

			/* DETECTOR_DARK */
			if( iFrameCountDark < 7 && !strcmp( pszFileTag, "AMBER_DETECTOR_DARK" ) )
			{

				strcpy( szInputDark[iFrameCountDark], pszFilename );
				iFrameCountDark++;

				sprintf( szMessage, "DETECTOR_DARK %d %s", iFrameCountDark, pszFilename );
				cpl_msg_info( fctid, "%s", szMessage );
			}
		}

		/* Get next frame from SOF */
		cpl_frameset_iterator_advance(it, 1);

	} /* while more frames */
	cpl_frameset_iterator_delete(it);

	if( iFrameCountFlat!=7 || iFrameCountDark!=7 )
	{
		iStatus = 1;

		sprintf( szMessage, "Found %d of DARK and %d of FLAT frames.", iFrameCountDark, iFrameCountFlat );
		cpl_msg_info( fctid, "%s", szMessage );
		sprintf( szMessage, "Error: Please input 7 of each." );
		cpl_msg_info( fctid, "%s", szMessage );
	}

	if( !iStatus )
	{
		/*------------------------------------------------------------------------------------------------------------*/
		/* Generating particle event maps, electronic bias maps, pixel bias maps, and pixel statistics maps for darks */
		for( i=0; i<7 && !iStatus; i++ )
		{
			sprintf( szMessage, "amdmsCreateStatisticsAlgo for Darks #%d", i+1 );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsCreateStatisticsAlgo( &statEnv );

			statEnv->cf = 4.70;                                /* gain factor */
			statEnv->events.peFlag = amdmsTRUE;                /* variance limits for particle event */
			statEnv->events.peLimit =  72.;                    /* variance limits for particle event: (40e-/Gain)^2 */
			statEnv->ebNIter = 5;                              /* limits for electronic bias calculation */
			statEnv->ebLower = 50;                             /* limits for electronic bias calculation */
			statEnv->ebUpper = 50;                             /* limits for electronic bias calculation */
			statEnv->ebHFlag = amdmsTRUE;                      /* in both directions */
			statEnv->ebVFlag = amdmsTRUE;                      /* in both directions */

			statEnv->env.detNX = 512;                          /* detector width in pixels */
			statEnv->env.detNY = 512;                          /* detector height in pixels */

			statEnv->env.calib.corrFlag = amdmsNO_CORRECTION;  /*  flags for requested compensations */

			/* Filtering */
			statEnv->env.filter.ioiFlag   = amdmsTRUE;
			statEnv->env.filter.ioiFrom   = iFrom;               /* Frames filter */
			statEnv->env.filter.ioiTo     = iTo;                 /* Frames filter */
			statEnv->env.filter.aoiFlag   = amdmsTRUE;
			statEnv->env.filter.aoiX      =   0;
			statEnv->env.filter.aoiY      =   0;
			statEnv->env.filter.aoiWidth  = 512;
			statEnv->env.filter.aoiHeight = 512;

			sprintf( szMessage, "amdmsAddFileToList: %s", szInputDark[i] );
			cpl_msg_info( fctid, "%s", szMessage );

			/* Prepare Input */
			flags.content = amdmsIMAGING_DATA_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(statEnv->env.inFiles),  szInputDark[i],  flags);

			/* Prepare Output */
			sprintf( szTemp, "dark_%01d_pem.fits", i );
			flags.content = amdmsPARTICLE_EVENT_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(statEnv->env.outFiles),  szTemp,  flags);

			sprintf( szTemp, "dark_%01d_ebm.fits", i );
			flags.content = amdmsELECTRONIC_BIAS_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(statEnv->env.outFiles),  szTemp,  flags);

			sprintf( szTemp, "dark_%01d_pbm.fits", i );
			flags.content = amdmsPIXEL_BIAS_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(statEnv->env.outFiles),  szTemp,  flags);

			sprintf( szTemp, "dark_%01d_psm.fits", i );
			flags.content = amdmsPIXEL_STAT_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(statEnv->env.outFiles),  szTemp,  flags);

			sprintf( szMessage, "amdmsDoPixelStatistics" );
			cpl_msg_info( fctid, "%s", szMessage );
			iStatus = amdmsDoPixelStatistics( statEnv );
			if( iStatus == amdmsSUCCESS )
				iStatus = 0;

			sprintf( szMessage, "Generating particle event maps: Status = %d", iStatus );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsDestroyStatisticsAlgo( &statEnv );
		} /* All 7 darks */


		/*------------------------------------------------------------------------------------------------------------*/
		/* Generating particle event maps, electronic bias maps, pixel bias maps, and pixel statistics maps for flats */
		for( i=0; i<7 && !iStatus; i++ )
		{
			sprintf( szMessage, "amdmsCreateStatisticsAlgo for Flats #%d", i+1 );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsCreateStatisticsAlgo( &statEnv );

			statEnv->cf = 4.70;                            /* gain factor */
			statEnv->events.peFlag = amdmsTRUE;            /* variance limits for particle event */
			statEnv->events.peLimit =   453.;              /* variance limits for particle event: (100e-/Gain)^2 or greater  */
			statEnv->ebNIter = 5;                          /* limits for electronic bias calculation */
			statEnv->ebLower = 50;                         /* limits for electronic bias calculation */
			statEnv->ebUpper = 50;                         /* limits for electronic bias calculation */
			statEnv->ebHFlag = amdmsTRUE;                  /* in both directions */
			statEnv->ebVFlag = amdmsTRUE;                  /* in both directions */

			statEnv->env.detNX = 512;                      /* detector width in pixels */
			statEnv->env.detNY = 512;                      /* detector height in pixels */

			statEnv->env.calib.corrFlag = amdmsPIXEL_BIAS_CORRECTION
					| amdmsELECTRONIC_BIAS_CORRECTION;  /*  flags for requested compensations */

			/* Filtering */
			statEnv->env.filter.ioiFlag   = amdmsTRUE;
			statEnv->env.filter.ioiFrom   = iFrom;             /* Frames filter */
			statEnv->env.filter.ioiTo     = iTo;               /* Frames filter */
			statEnv->env.filter.aoiFlag   = amdmsTRUE;
			statEnv->env.filter.aoiX      =   0;
			statEnv->env.filter.aoiY      =   0;
			statEnv->env.filter.aoiWidth  = 512;
			statEnv->env.filter.aoiHeight = 512;

			sprintf( szMessage, "amdmsAddFileToList: %s", szInputFlat[i] );
			cpl_msg_info( fctid, "%s", szMessage );

			/* Prepare Input */
			flags.content = amdmsIMAGING_DATA_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(statEnv->env.inFiles),  szInputFlat[i],  flags);


			/* Prepare Map Input */
			sprintf( szTemp, "dark_%01d_pbm.fits", i );
			flags.content = amdmsPIXEL_BIAS_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(statEnv->env.calib.mapFiles),  szTemp,  flags );

			sprintf( szTemp, "dark_%01d_ebm.fits", i );
			flags.content = amdmsELECTRONIC_BIAS_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(statEnv->env.calib.mapFiles),  szTemp,  flags );



			/* Prepare Output */
			sprintf( szTemp, "flat_%01d_pem.fits", i );
			flags.content = amdmsPARTICLE_EVENT_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(statEnv->env.outFiles),  szTemp,  flags);

			sprintf( szTemp, "flat_%01d_psm.fits", i );
			flags.content = amdmsPIXEL_STAT_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(statEnv->env.outFiles),  szTemp,  flags);

			sprintf( szTemp, "flat_%01d_pnm.fits", i );
			flags.content = amdmsPHOTON_NOISE_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(statEnv->env.outFiles),  szTemp,  flags);

			sprintf( szMessage, "amdmsDoPixelStatistics" );
			cpl_msg_info( fctid, "%s", szMessage );
			iStatus = amdmsDoPixelStatistics( statEnv );
			if( iStatus == amdmsSUCCESS )
				iStatus = 0;
			else
				iStatus = 666; /* Error from amdmslib */

			sprintf( szMessage, "Generating particle event maps: Status = %d", iStatus );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsDestroyStatisticsAlgo( &statEnv );
		} /* All 7 flats */


		/*---------------------------------------*/
		/* Generating dark current map for darks */
		if( !iStatus )
		{
			sprintf( szMessage, "amdmsCreatePropertiesAlgo dark current maps for dark" );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsCreatePropertiesAlgo( &ppEnv );

			ppEnv->nDelStart = 0;                              /* definition of data point */
			ppEnv->nDelMiddle = 1;                             /* definition of data point */
			ppEnv->nDelEnd = 0;                                /* definition of data point */

			ppEnv->env.detNX = 512;                            /* detector width in pixels */
			ppEnv->env.detNY = 512;                            /* detector height in pixels */

			ppEnv->env.calib.corrFlag = amdmsNO_CORRECTION;    /*  flags for requested compensations */

			/* Filtering */
			ppEnv->env.filter.aoiFlag   = amdmsTRUE;
			ppEnv->env.filter.aoiX      = 310;
			ppEnv->env.filter.aoiY      =  64;
			ppEnv->env.filter.aoiWidth  =  50;
			ppEnv->env.filter.aoiHeight = 384;


			/* Prepare Input (from the seven dark maps from above) */
			for( i=0; i<7; i++ )
			{
				sprintf( szTemp, "dark_%01d_psm.fits", i );
				flags.content = amdmsPIXEL_STAT_CONTENT;
				flags.format  = amdmsTABLE_FORMAT;
				flags.type    = amdmsFLOAT_TYPE;
				amdmsAddFileToList( &(ppEnv->env.inFiles),  szTemp,  flags);
			}

			/* Prepare Output */
			sprintf( szTemp, "dcm.fits" );
			flags.content = amdmsDARK_CURRENT_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(ppEnv->env.outFiles),  szTemp,  flags);

			sprintf( szMessage, "amdmsDoProperties" );
			cpl_msg_info( fctid, "%s", szMessage );
			iStatus = amdmsDoProperties( ppEnv );
			if( iStatus == amdmsSUCCESS )
				iStatus = 0;
			else
				iStatus = 666; /* Error from amdmslib */

			sprintf( szMessage, "Generating dark current maps for dark: Status = %d", iStatus );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsDestroyPropertiesAlgo( &ppEnv );
		} /* Status still OK */


		/*--------------------------*/
		/* Generating bad pixel map */
		if( !iStatus )
		{
			/* a) Darks --------------------------------------------------------------------*/
			sprintf( szMessage, " amdmsCreateBadPixelAlgo bad pixel map 1 of 6" );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsCreateBadPixelAlgo( &badpixelEnv );

			badpixelEnv->env.detNX = 512;                      /* detector width in pixels */
			badpixelEnv->env.detNY = 512;                      /* detector height in pixels */

			badpixelEnv->nIter = 1;

			badpixelEnv->fuzzyCount = 2;
			badpixelEnv->fuzzyLimit = 1.0;

			/* Filtering */
			badpixelEnv->env.filter.aoiFlag   = amdmsFALSE;

			/*
      badpixelEnv->env.filter.aoiX      = 310;
      badpixelEnv->env.filter.aoiY      =  64;
      badpixelEnv->env.filter.aoiWidth  =  50;
      badpixelEnv->env.filter.aoiHeight = 384;  
			 */

			badpixelEnv->env.calib.corrFlag = amdmsNO_CORRECTION;    /*  flags for requested compensations */

			/* Stripes Setup */
			badpixelEnv->env.stripes.nHStripes = 1;
			badpixelEnv->env.stripes.hStripes[0].pos = 1;
			badpixelEnv->env.stripes.hStripes[0].size = 512;
			badpixelEnv->env.stripes.hStripes[0].flags = amdmsUSE_PS_VAR_PIXEL; /* temporal flux variance */

			badpixelEnv->env.stripes.nVStripes = 1;
			badpixelEnv->env.stripes.vStripes[0].pos = 1;
			badpixelEnv->env.stripes.vStripes[0].size = 512;
			badpixelEnv->env.stripes.vStripes[0].flags = amdmsUSE_PS_VAR_PIXEL; /* temporal flux variance */

			/* recalculate pos values */
			amdmsRecalcStripes(&(badpixelEnv->env.stripes), 0, 0);

			/* Limits */
			badpixelEnv->limits.nLimits = 2;
			badpixelEnv->limits.limits[0].flag = amdmsUSE_PS_VAR_PIXEL; /* temporal flux variance */
			badpixelEnv->limits.limits[0].type = amdmsABS_UPPER_LIMIT;  /* bad if value less than limit */
			badpixelEnv->limits.limits[0].value = 0.18;                 /* (2e-/Gain)^2 */
			badpixelEnv->limits.limits[0].ref = 5.5;                    /* (11e-/Gain)^2 */
			badpixelEnv->limits.limits[1].flag = amdmsUSE_PS_VAR_PIXEL; /* temporal flux variance */
			badpixelEnv->limits.limits[1].type = amdmsABS_LOWER_LIMIT;  /* bad if value greater than limit */
			badpixelEnv->limits.limits[1].value =  255.;                /* (75e-/Gain)2 */
			badpixelEnv->limits.limits[1].ref =  5.5;                   /* (11e-/Gain)^2 */

			/* Prepare Input (from the seven dark maps from above) */
			for( i=0; i<7; i++ )
			{
				sprintf( szTemp, "dark_%01d_psm.fits", i );
				flags.content = amdmsPIXEL_STAT_CONTENT;
				flags.format  = amdmsTABLE_FORMAT;
				flags.type    = amdmsFLOAT_TYPE;
				amdmsAddFileToList( &(badpixelEnv->env.inFiles),  szTemp,  flags);
			}

			/* Prepare Output */
			sprintf( szTemp, "bpm.fits" );
			flags.content = amdmsBAD_PIXEL_CONTENT;
			flags.format  = amdmsCUBE_FORMAT;
			flags.type    = amdmsBYTE_TYPE;
			amdmsAddFileToList( &(badpixelEnv->env.outFiles),  szTemp,  flags);

			sprintf( szTemp, "bpm_btbl.fits" );
			flags.content = amdmsBAD_PIXEL_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsBYTE_TYPE;
			amdmsAddFileToList( &(badpixelEnv->env.outFiles),  szTemp,  flags);

			sprintf( szMessage, "amdmsDoBadPixel" );
			cpl_msg_info( fctid, "%s", szMessage );
			iStatus = amdmsDoBadPixel( badpixelEnv );
			if( iStatus == amdmsSUCCESS )
				iStatus = 0;
			else
				iStatus = 666; /* Error from amdmslib */

			sprintf( szMessage, "Generating bad pixel maps for dark: Status = %d", iStatus );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsDestroyBadPixelAlgo( &badpixelEnv );

			/* b) Flats --------------------------------------------------------------------*/
			sprintf( szMessage, " amdmsCreateBadPixelAlgo bad pixel map 2 of 6" );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsCreateBadPixelAlgo( &badpixelEnv );

			badpixelEnv->env.detNX = 512;                      /* detector width in pixels */
			badpixelEnv->env.detNY = 512;                      /* detector height in pixels */

			badpixelEnv->env.calib.corrFlag = amdmsNO_CORRECTION;    /*  flags for requested compensations */

			/* Filtering */
			badpixelEnv->env.filter.aoiFlag   = amdmsTRUE;
			badpixelEnv->env.filter.aoiX      = 310;
			badpixelEnv->env.filter.aoiY      =  64;
			badpixelEnv->env.filter.aoiWidth  =  50;
			badpixelEnv->env.filter.aoiHeight = 384;

			/* Stripes Setup */
			badpixelEnv->env.stripes.nHStripes = 1;
			badpixelEnv->env.stripes.hStripes[0].pos = 1;
			badpixelEnv->env.stripes.hStripes[0].size = 512;
			badpixelEnv->env.stripes.hStripes[0].flags = amdmsUSE_PS_VAR_PIXEL; /* temporal flux variance */

			badpixelEnv->env.stripes.nVStripes = 1;
			badpixelEnv->env.stripes.vStripes[0].pos = 1;
			badpixelEnv->env.stripes.vStripes[0].size = 16;
			badpixelEnv->env.stripes.vStripes[0].flags = amdmsUSE_PS_VAR_PIXEL; /* temporal flux variance */

			/* recalculate pos values */
			amdmsRecalcStripes(&(badpixelEnv->env.stripes), 0, 0);

			/* Limits */
			badpixelEnv->limits.nLimits = 2;
			badpixelEnv->limits.limits[0].flag = amdmsUSE_PS_VAR_PIXEL; /* temporal flux variance */
			badpixelEnv->limits.limits[0].type = amdmsABS_UPPER_LIMIT;  /* bad if value less than limit */
			badpixelEnv->limits.limits[0].value = 0.18;                 /* (2e-/Gain)^2 */
			badpixelEnv->limits.limits[0].ref = 5.5;                    /* (11e-/Gain)^2 */
			badpixelEnv->limits.limits[1].flag = amdmsUSE_PS_VAR_PIXEL; /* temporal flux variance */
			badpixelEnv->limits.limits[1].type = amdmsABS_LOWER_LIMIT;  /* bad if value greater than limit */
			badpixelEnv->limits.limits[1].value =  255.;                /* (75e-/Gain)^2 */
			badpixelEnv->limits.limits[1].ref =  5.5;                   /* (11e-/Gain)^2 */


			/* Prepare Input (from the seven dark maps from above) */
			for( i=0; i<7; i++ )
			{
				sprintf( szTemp, "flat_%01d_psm.fits", i );
				flags.content = amdmsPIXEL_STAT_CONTENT;
				flags.format  = amdmsTABLE_FORMAT;
				flags.type    = amdmsFLOAT_TYPE;
				amdmsAddFileToList( &(badpixelEnv->env.inFiles),  szTemp,  flags);
			}

			/* Prepare Map Input */
			sprintf( szTemp, "bpm.fits" );
			flags.content = amdmsBAD_PIXEL_CONTENT;
			flags.format  = amdmsCUBE_FORMAT;
			flags.type    = amdmsBYTE_TYPE;
			amdmsAddFileToList( &(badpixelEnv->env.calib.mapFiles),  szTemp,  flags );


			/* Prepare Output */
			sprintf( szTemp, "bpm.fits" );
			flags.content = amdmsBAD_PIXEL_CONTENT;
			flags.format  = amdmsCUBE_FORMAT;
			flags.type    = amdmsBYTE_TYPE;
			amdmsAddFileToList( &(badpixelEnv->env.outFiles),  szTemp,  flags);

			sprintf( szTemp, "bpm_btbl.fits" );
			flags.content = amdmsBAD_PIXEL_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsBYTE_TYPE;
			amdmsAddFileToList( &(badpixelEnv->env.outFiles),  szTemp,  flags);

			sprintf( szMessage, "amdmsDoBadPixel" );
			cpl_msg_info( fctid, "%s", szMessage );
			iStatus = amdmsDoBadPixel( badpixelEnv );
			if( iStatus == amdmsSUCCESS )
				iStatus = 0;
			else
				iStatus = 666; /* Error from amdmslib */

			sprintf( szMessage, "Generating bad pixel maps for flat: Status = %d", iStatus );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsDestroyBadPixelAlgo( &badpixelEnv );

			/* c) ---------------------------------------------------------------------*/
			sprintf( szMessage, " amdmsCreateBadPixelAlgo bad pixel map 3 of 6" );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsCreateBadPixelAlgo( &badpixelEnv );

			badpixelEnv->env.detNX = 512;                      /* detector width in pixels */
			badpixelEnv->env.detNY = 512;                      /* detector height in pixels */

			badpixelEnv->env.calib.corrFlag = amdmsNO_CORRECTION;    /*  flags for requested compensations */

			/* Filtering */
			badpixelEnv->env.filter.aoiFlag   = amdmsTRUE;
			badpixelEnv->env.filter.aoiX      = 310;
			badpixelEnv->env.filter.aoiY      =  64;
			badpixelEnv->env.filter.aoiWidth  =  50;
			badpixelEnv->env.filter.aoiHeight = 384;

			/* Stripes Setup */
			badpixelEnv->env.stripes.nHStripes = 1;
			badpixelEnv->env.stripes.hStripes[0].pos = 1;
			badpixelEnv->env.stripes.hStripes[0].size = 512;
			badpixelEnv->env.stripes.hStripes[0].flags = amdmsUSE_PHOTON_NOISE;

			badpixelEnv->env.stripes.nVStripes = 9;
			badpixelEnv->env.stripes.vStripes[0].pos = 1;
			badpixelEnv->env.stripes.vStripes[0].size = 16;
			badpixelEnv->env.stripes.vStripes[0].flags = amdmsUSE_NOTHING;
			badpixelEnv->env.stripes.vStripes[1].pos = 1;
			badpixelEnv->env.stripes.vStripes[1].size = 34;
			badpixelEnv->env.stripes.vStripes[1].flags = amdmsUSE_NOTHING;
			badpixelEnv->env.stripes.vStripes[2].pos = 1;
			badpixelEnv->env.stripes.vStripes[2].size = 90;
			badpixelEnv->env.stripes.vStripes[2].flags = amdmsUSE_PHOTON_NOISE;
			badpixelEnv->env.stripes.vStripes[3].pos = 1;
			badpixelEnv->env.stripes.vStripes[3].size = 20;
			badpixelEnv->env.stripes.vStripes[3].flags = amdmsUSE_NOTHING;
			badpixelEnv->env.stripes.vStripes[4].pos = 1;
			badpixelEnv->env.stripes.vStripes[4].size = 100;
			badpixelEnv->env.stripes.vStripes[4].flags = amdmsUSE_PHOTON_NOISE;
			badpixelEnv->env.stripes.vStripes[5].pos = 1;
			badpixelEnv->env.stripes.vStripes[5].size = 25;
			badpixelEnv->env.stripes.vStripes[5].flags = amdmsUSE_NOTHING;
			badpixelEnv->env.stripes.vStripes[6].pos = 1;
			badpixelEnv->env.stripes.vStripes[6].size = 85;
			badpixelEnv->env.stripes.vStripes[6].flags = amdmsUSE_PHOTON_NOISE;
			badpixelEnv->env.stripes.vStripes[7].pos = 1;
			badpixelEnv->env.stripes.vStripes[7].size = 50;
			badpixelEnv->env.stripes.vStripes[7].flags = amdmsUSE_NOTHING;
			badpixelEnv->env.stripes.vStripes[8].pos = 1;
			badpixelEnv->env.stripes.vStripes[8].size = 92;
			badpixelEnv->env.stripes.vStripes[8].flags = amdmsUSE_PHOTON_NOISE;

			/* recalculate pos values */
			amdmsRecalcStripes(&(badpixelEnv->env.stripes), 0, 0);


			/* Limits */
			badpixelEnv->limits.nLimits = 2;
			badpixelEnv->limits.limits[0].flag = amdmsUSE_PHOTON_NOISE; /* temporal flux variance */
			badpixelEnv->limits.limits[0].type = amdmsABS_UPPER_LIMIT;  /* bad if value less than limit */
			badpixelEnv->limits.limits[0].value = 0.5;
			badpixelEnv->limits.limits[0].ref = 1.0;
			badpixelEnv->limits.limits[1].flag = amdmsUSE_PHOTON_NOISE; /* temporal flux variance */
			badpixelEnv->limits.limits[1].type = amdmsABS_LOWER_LIMIT;  /* bad if value greater than limit */
			badpixelEnv->limits.limits[1].value =  2.25;
			badpixelEnv->limits.limits[1].ref = 1.0;


			/* Prepare Input (from the seven dark maps from above) */
			for( i=0; i<7; i++ )
			{
				sprintf( szTemp, "flat_%01d_pnm.fits", i );
				flags.content = amdmsPHOTON_NOISE_CONTENT;
				flags.format  = amdmsTABLE_FORMAT;
				flags.type    = amdmsFLOAT_TYPE;
				amdmsAddFileToList( &(badpixelEnv->env.inFiles),  szTemp,  flags);
			}

			/* Prepare Map Input */
			sprintf( szTemp, "bpm.fits" );
			flags.content = amdmsBAD_PIXEL_CONTENT;
			flags.format  = amdmsCUBE_FORMAT;
			flags.type    = amdmsBYTE_TYPE;
			amdmsAddFileToList( &(badpixelEnv->env.calib.mapFiles),  szTemp,  flags );


			/* Prepare Output */
			sprintf( szTemp, "bpm.fits" );
			flags.content = amdmsBAD_PIXEL_CONTENT;
			flags.format  = amdmsCUBE_FORMAT;
			flags.type    = amdmsBYTE_TYPE;
			amdmsAddFileToList( &(badpixelEnv->env.outFiles),  szTemp,  flags);

			sprintf( szTemp, "bpm_btbl.fits" );
			flags.content = amdmsBAD_PIXEL_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsBYTE_TYPE;
			amdmsAddFileToList( &(badpixelEnv->env.outFiles),  szTemp,  flags);

			sprintf( szMessage, "amdmsDoBadPixel" );
			cpl_msg_info( fctid, "%s", szMessage );
			iStatus = amdmsDoBadPixel( badpixelEnv );
			if( iStatus == amdmsSUCCESS )
				iStatus = 0;
			else
				iStatus = 666; /* Error from amdmslib */

			sprintf( szMessage, "Generating bad pixel maps for flat: Status = %d", iStatus );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsDestroyBadPixelAlgo( &badpixelEnv );

			/* d) -----------------------------------------------------------------------*/
			sprintf( szMessage, " amdmsCreateBadPixelAlgo bad pixel map 4 of 6" );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsCreateBadPixelAlgo( &badpixelEnv );

			badpixelEnv->env.detNX = 512;                      /* detector width in pixels */
			badpixelEnv->env.detNY = 512;                      /* detector height in pixels */

			badpixelEnv->env.calib.corrFlag = amdmsNO_CORRECTION;    /*  flags for requested compensations */

			/* Filtering */
			badpixelEnv->env.filter.aoiFlag   = amdmsTRUE;
			badpixelEnv->env.filter.aoiX      = 310;
			badpixelEnv->env.filter.aoiY      =  64;
			badpixelEnv->env.filter.aoiWidth  =  50;
			badpixelEnv->env.filter.aoiHeight = 384;

			/* Stripes Setup */
			badpixelEnv->env.stripes.nHStripes = 1;
			badpixelEnv->env.stripes.hStripes[0].pos = 1;
			badpixelEnv->env.stripes.hStripes[0].size = 512;
			badpixelEnv->env.stripes.hStripes[0].flags = amdmsUSE_FIT_A1;

			badpixelEnv->env.stripes.nVStripes = 1;
			badpixelEnv->env.stripes.vStripes[0].pos = 1;
			badpixelEnv->env.stripes.vStripes[0].size = 512;
			badpixelEnv->env.stripes.vStripes[0].flags = amdmsUSE_FIT_A1;

			/* recalculate pos values */
			amdmsRecalcStripes(&(badpixelEnv->env.stripes), 0, 0);

			/* Limits */
			badpixelEnv->limits.nLimits = 2;
			badpixelEnv->limits.limits[0].flag = amdmsUSE_FIT_A1;
			badpixelEnv->limits.limits[0].type = amdmsABS_UPPER_LIMIT;  /* bad if value less than limit */
			badpixelEnv->limits.limits[0].value = -16.;                 /* -75e-/Gain */
			badpixelEnv->limits.limits[0].ref = 0.0;
			badpixelEnv->limits.limits[1].flag = amdmsUSE_FIT_A1;
			badpixelEnv->limits.limits[1].type = amdmsABS_LOWER_LIMIT;  /* bad if value greater than limit */
			badpixelEnv->limits.limits[1].value =  16.;                 /* +75e-/Gain */
			badpixelEnv->limits.limits[1].ref = 0.0;

			/* Prepare Input  */
			sprintf( szTemp, "dcm.fits" );
			flags.content = amdmsDARK_CURRENT_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(badpixelEnv->env.inFiles),  szTemp,  flags);

			/* Prepare Map Input */
			sprintf( szTemp, "bpm.fits" );
			flags.content = amdmsBAD_PIXEL_CONTENT;
			flags.format  = amdmsCUBE_FORMAT;
			flags.type    = amdmsBYTE_TYPE;
			amdmsAddFileToList( &(badpixelEnv->env.calib.mapFiles),  szTemp,  flags );


			/* Prepare Output */
			sprintf( szTemp, "bpm.fits" );
			flags.content = amdmsBAD_PIXEL_CONTENT;
			flags.format  = amdmsCUBE_FORMAT;
			flags.type    = amdmsBYTE_TYPE;
			amdmsAddFileToList( &(badpixelEnv->env.outFiles),  szTemp,  flags);

			sprintf( szTemp, "bpm_btbl.fits" );
			flags.content = amdmsBAD_PIXEL_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsBYTE_TYPE;
			amdmsAddFileToList( &(badpixelEnv->env.outFiles),  szTemp,  flags);

			sprintf( szMessage, "amdmsDoBadPixel" );
			cpl_msg_info( fctid, "%s", szMessage );
			iStatus = amdmsDoBadPixel( badpixelEnv );
			if( iStatus == amdmsSUCCESS )
				iStatus = 0;
			else
				iStatus = 666; /* Error from amdmslib */

			sprintf( szMessage, "Generating bad pixel maps for flat: Status = %d", iStatus );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsDestroyBadPixelAlgo( &badpixelEnv );

			/* e) -----------------------------------------------------------------------*/
			sprintf( szMessage, " amdmsCreateBadPixelAlgo bad pixel map 5 of 6" );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsCreateBadPixelAlgo( &badpixelEnv );

			badpixelEnv->env.detNX = 512;                      /* detector width in pixels */
			badpixelEnv->env.detNY = 512;                      /* detector height in pixels */

			badpixelEnv->env.calib.corrFlag = amdmsNO_CORRECTION;    /*  flags for requested compensations */

			/* Filtering */
			badpixelEnv->env.filter.aoiFlag   = amdmsTRUE;
			badpixelEnv->env.filter.aoiX      = 310;
			badpixelEnv->env.filter.aoiY      =  64;
			badpixelEnv->env.filter.aoiWidth  =  50;
			badpixelEnv->env.filter.aoiHeight = 384;

			/* Stripes Setup */
			badpixelEnv->env.stripes.nHStripes = 1;
			badpixelEnv->env.stripes.hStripes[0].pos = 1;
			badpixelEnv->env.stripes.hStripes[0].size = 512;
			badpixelEnv->env.stripes.hStripes[0].flags = amdmsUSE_FIT_CHI_SQR;

			badpixelEnv->env.stripes.nVStripes = 1;
			badpixelEnv->env.stripes.vStripes[0].pos = 1;
			badpixelEnv->env.stripes.vStripes[0].size = 512;
			badpixelEnv->env.stripes.vStripes[0].flags = amdmsUSE_FIT_CHI_SQR;

			/* recalculate pos values */
			amdmsRecalcStripes(&(badpixelEnv->env.stripes), 0, 0);

			/* Limits */
			badpixelEnv->limits.nLimits = 1;
			badpixelEnv->limits.limits[0].flag = amdmsUSE_FIT_CHI_SQR;
			badpixelEnv->limits.limits[0].type = amdmsABS_LOWER_LIMIT;  /* bad if value greater than limit */
			badpixelEnv->limits.limits[0].value = 5.0;
			badpixelEnv->limits.limits[0].ref = 0.0;


			/* Prepare Input  */
			sprintf( szTemp, "dcm.fits" );
			flags.content = amdmsDARK_CURRENT_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(badpixelEnv->env.inFiles),  szTemp,  flags);

			/* Prepare Map Input */
			sprintf( szTemp, "bpm.fits" );
			flags.content = amdmsBAD_PIXEL_CONTENT;
			flags.format  = amdmsCUBE_FORMAT;
			flags.type    = amdmsBYTE_TYPE;
			amdmsAddFileToList( &(badpixelEnv->env.calib.mapFiles),  szTemp,  flags );


			/* Prepare Output */
			sprintf( szTemp, "bpm.fits" );
			flags.content = amdmsBAD_PIXEL_CONTENT;
			flags.format  = amdmsCUBE_FORMAT;
			flags.type    = amdmsBYTE_TYPE;
			amdmsAddFileToList( &(badpixelEnv->env.outFiles),  szTemp,  flags);

			sprintf( szTemp, "bpm_btbl.fits" );
			flags.content = amdmsBAD_PIXEL_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsBYTE_TYPE;
			amdmsAddFileToList( &(badpixelEnv->env.outFiles),  szTemp,  flags);

			sprintf( szMessage, "amdmsDoBadPixel" );
			cpl_msg_info( fctid, "%s", szMessage );
			iStatus = amdmsDoBadPixel( badpixelEnv );
			if( iStatus == amdmsSUCCESS )
				iStatus = 0;
			else
				iStatus = 666; /* Error from amdmslib */

			sprintf( szMessage, "Generating bad pixel maps for flat: Status = %d", iStatus );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsDestroyBadPixelAlgo( &badpixelEnv );

			/* f) Finish --------------------------------------------------------------------*/
			sprintf( szMessage, " amdmsCreateBadPixelAlgo bad pixel map 6 of 6" );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsCreateBadPixelAlgo( &badpixelEnv );

			badpixelEnv->env.detNX = 512;                      /* detector width in pixels */
			badpixelEnv->env.detNY = 512;                      /* detector height in pixels */

			badpixelEnv->env.calib.corrFlag = amdmsNO_CORRECTION;    /*  flags for requested compensations */

			/* Filtering */
			badpixelEnv->env.filter.aoiFlag   = amdmsTRUE;
			badpixelEnv->env.filter.aoiX      = 310;
			badpixelEnv->env.filter.aoiY      =  64;
			badpixelEnv->env.filter.aoiWidth  =  50;
			badpixelEnv->env.filter.aoiHeight = 384;

			/* Windowing */
			badpixelEnv->winFlag = amdmsTRUE;
			badpixelEnv->winInnerSize = 2;
			badpixelEnv->winOuterSize = 5;

			/* Stripes Setup */
			badpixelEnv->env.stripes.nHStripes = 1;
			badpixelEnv->env.stripes.hStripes[0].pos = 1;
			badpixelEnv->env.stripes.hStripes[0].size = 512;
			badpixelEnv->env.stripes.hStripes[0].flags = amdmsUSE_PS_MEAN_PIXEL;

			badpixelEnv->env.stripes.nVStripes = 9;
			badpixelEnv->env.stripes.vStripes[0].pos = 1;
			badpixelEnv->env.stripes.vStripes[0].size = 16;
			badpixelEnv->env.stripes.vStripes[0].flags = amdmsUSE_NOTHING;
			badpixelEnv->env.stripes.vStripes[1].pos = 1;
			badpixelEnv->env.stripes.vStripes[1].size = 34;
			badpixelEnv->env.stripes.vStripes[1].flags = amdmsUSE_NOTHING;
			badpixelEnv->env.stripes.vStripes[2].pos = 1;
			badpixelEnv->env.stripes.vStripes[2].size = 90;
			badpixelEnv->env.stripes.vStripes[2].flags = amdmsUSE_PS_MEAN_PIXEL;
			badpixelEnv->env.stripes.vStripes[3].pos = 1;
			badpixelEnv->env.stripes.vStripes[3].size = 20;
			badpixelEnv->env.stripes.vStripes[3].flags = amdmsUSE_NOTHING;
			badpixelEnv->env.stripes.vStripes[4].pos = 1;
			badpixelEnv->env.stripes.vStripes[4].size = 100;
			badpixelEnv->env.stripes.vStripes[4].flags = amdmsUSE_PS_MEAN_PIXEL;
			badpixelEnv->env.stripes.vStripes[5].pos = 1;
			badpixelEnv->env.stripes.vStripes[5].size = 25;
			badpixelEnv->env.stripes.vStripes[5].flags = amdmsUSE_NOTHING;
			badpixelEnv->env.stripes.vStripes[6].pos = 1;
			badpixelEnv->env.stripes.vStripes[6].size = 85;
			badpixelEnv->env.stripes.vStripes[6].flags = amdmsUSE_PS_MEAN_PIXEL;
			badpixelEnv->env.stripes.vStripes[7].pos = 1;
			badpixelEnv->env.stripes.vStripes[7].size = 50;
			badpixelEnv->env.stripes.vStripes[7].flags = amdmsUSE_NOTHING;
			badpixelEnv->env.stripes.vStripes[8].pos = 1;
			badpixelEnv->env.stripes.vStripes[8].size = 92;
			badpixelEnv->env.stripes.vStripes[8].flags = amdmsUSE_PS_MEAN_PIXEL;

			/* recalculate pos values */
			amdmsRecalcStripes(&(badpixelEnv->env.stripes), 0, 0);

			/* Limits */
			badpixelEnv->limits.nLimits = 2;
			badpixelEnv->limits.limits[0].flag = amdmsUSE_PS_MEAN_PIXEL;
			badpixelEnv->limits.limits[0].type = amdmsSIGMA_UPPER_LIMIT;
			badpixelEnv->limits.limits[0].value = -5.0;
			badpixelEnv->limits.limits[0].ref = 0.0;
			badpixelEnv->limits.limits[1].flag = amdmsUSE_PS_MEAN_PIXEL;
			badpixelEnv->limits.limits[1].type = amdmsSIGMA_LOWER_LIMIT;
			badpixelEnv->limits.limits[1].value = 5.0;
			badpixelEnv->limits.limits[1].ref = 0.0;


			/* Prepare Input  */
			for( i=0; i<7; i++ )
			{
				sprintf( szTemp, "flat_%01d_psm.fits", i );
				flags.content = amdmsPIXEL_STAT_CONTENT;
				flags.format  = amdmsTABLE_FORMAT;
				flags.type    = amdmsFLOAT_TYPE;
				amdmsAddFileToList( &(badpixelEnv->env.inFiles),  szTemp,  flags);
			}

			/* Prepare Map Input */
			sprintf( szTemp, "bpm.fits" );
			flags.content = amdmsBAD_PIXEL_CONTENT;
			flags.format  = amdmsCUBE_FORMAT;
			flags.type    = amdmsBYTE_TYPE;
			amdmsAddFileToList( &(badpixelEnv->env.calib.mapFiles),  szTemp,  flags );


			/* Prepare Output */
			sprintf( szTemp, "bpm.fits" );
			flags.content = amdmsBAD_PIXEL_CONTENT;
			flags.format  = amdmsCUBE_FORMAT;
			flags.type    = amdmsBYTE_TYPE;
			amdmsAddFileToList( &(badpixelEnv->env.outFiles),  szTemp,  flags);

			sprintf( szTemp, "bpm_btbl.fits" );
			flags.content = amdmsBAD_PIXEL_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsBYTE_TYPE;
			amdmsAddFileToList( &(badpixelEnv->env.outFiles),  szTemp,  flags);

			iStatus = amdmsDoBadPixel( badpixelEnv );
			if( iStatus == amdmsSUCCESS )
				iStatus = 0;
			else
				iStatus = 666; /* Error from amdmslib */

			sprintf( szMessage, "Final stage -> Generating bad pixel maps for flat: Status = %d", iStatus );
			cpl_msg_info( fctid, "%s", szMessage );



			amdmsDestroyBadPixelAlgo( &badpixelEnv );


		}

		/*----------------------------------------*/
		/* Generating pixel statistic maps for flats */
		for( i=0; i<7 && !iStatus; i++ )
		{
			sprintf( szMessage, "amdmsCreateStatisticsAlgo for Flats #%d", i+1 );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsCreateStatisticsAlgo( &statEnv );

			statEnv->cf = 4.70;                            /* gain factor */
			statEnv->env.detNX = 512;                      /* detector width in pixels */
			statEnv->env.detNY = 512;                      /* detector height in pixels */

			statEnv->env.calib.corrFlag = amdmsPIXEL_BIAS_CORRECTION
					| amdmsELECTRONIC_BIAS_CORRECTION;  /*  flags for requested compensations */

			/* Filtering */
			statEnv->env.filter.ioiFlag   = amdmsTRUE;
			statEnv->env.filter.ioiFrom   = iFrom;               /* Frames filter */
			statEnv->env.filter.ioiTo     = iTo;                 /* Frames filter */
			statEnv->env.filter.aoiFlag   = amdmsTRUE;
			statEnv->env.filter.aoiX      = 310;
			statEnv->env.filter.aoiY      =  64;
			statEnv->env.filter.aoiWidth  =  50;
			statEnv->env.filter.aoiHeight = 384;


			sprintf( szMessage, "amdmsAddFileToList: %s", szInputFlat[i] );
			cpl_msg_info( fctid, "%s", szMessage );

			/* Prepare Input */
			flags.content = amdmsIMAGING_DATA_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(statEnv->env.inFiles),  szInputFlat[i],  flags);


			/* Prepare Map Input */
			sprintf( szTemp, "bpm.fits" );
			flags.content = amdmsBAD_PIXEL_CONTENT;
			flags.format  = amdmsCUBE_FORMAT;
			flags.type    = amdmsBYTE_TYPE;
			amdmsAddFileToList( &(statEnv->env.calib.mapFiles),  szTemp,  flags );

			sprintf( szTemp, "flat_%0d_pem.fits", i );
			flags.content = amdmsPARTICLE_EVENT_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(statEnv->env.calib.mapFiles),  szTemp,  flags );

			sprintf( szTemp, "dark_%0d_pbm.fits", i );
			flags.content = amdmsPIXEL_BIAS_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(statEnv->env.calib.mapFiles),  szTemp,  flags );

			sprintf( szTemp, "dark_%0d_ebm.fits", i );
			flags.content = amdmsELECTRONIC_BIAS_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(statEnv->env.calib.mapFiles),  szTemp,  flags );



			/* Prepare Output */
			sprintf( szTemp, "flat_%01d_psm.fits", i );
			flags.content = amdmsPIXEL_STAT_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(statEnv->env.outFiles),  szTemp,  flags);

			sprintf( szTemp, "flat_%01d_pnm.fits", i );
			flags.content = amdmsPHOTON_NOISE_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(statEnv->env.outFiles),  szTemp,  flags);

			sprintf( szMessage, "amdmsDoPixelStatistics" );
			cpl_msg_info( fctid, "%s", szMessage );
			iStatus = amdmsDoPixelStatistics( statEnv );
			if( iStatus == amdmsSUCCESS )
				iStatus = 0;
			else
				iStatus = 666; /* Error from amdmslib */

			sprintf( szMessage, "Generating pixel statistics: Status = %d", iStatus );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsDestroyStatisticsAlgo( &statEnv );
		} /* All 7 flats */

		/*----------------------------------------*/
		/* Generating flatfield map for expos     */
		if( !iStatus )
		{
			sprintf( szMessage, "amdmsCreatePropertiesAlgo flatfield map" );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsCreatePropertiesAlgo( &ppEnv );

			ppEnv->nDelStart = 0;                              /* definition of data point */
			ppEnv->nDelMiddle = 1;                             /* definition of data point */
			ppEnv->nDelEnd = 0;                                /* definition of data point */

			ppEnv->env.detNX = 512;                            /* detector width in pixels */
			ppEnv->env.detNY = 512;                            /* detector height in pixels */

			ppEnv->env.calib.corrFlag = amdmsNO_CORRECTION;    /*  flags for requested compensations     */

			ppEnv->nuicFlag           = amdmsTRUE;             /*  non uniform illumination compensation */

			/* Filtering */
			ppEnv->env.filter.aoiFlag   = amdmsTRUE;
			ppEnv->env.filter.aoiX      = 310;
			ppEnv->env.filter.aoiY      =  64;
			ppEnv->env.filter.aoiWidth  =  50;
			ppEnv->env.filter.aoiHeight = 384;

			/* Stripes Setup */
			ppEnv->env.stripes.nHStripes = 1;
			ppEnv->env.stripes.hStripes[0].pos = 1;
			ppEnv->env.stripes.hStripes[0].size = 512;
			ppEnv->env.stripes.hStripes[0].flags = amdmsUSE_FLATFIELD;

			ppEnv->env.stripes.nVStripes = 9;
			ppEnv->env.stripes.vStripes[0].pos = 1;
			ppEnv->env.stripes.vStripes[0].size = 16;
			ppEnv->env.stripes.vStripes[0].flags = amdmsUSE_NOTHING;
			ppEnv->env.stripes.vStripes[1].pos = 1;
			ppEnv->env.stripes.vStripes[1].size = 34;
			ppEnv->env.stripes.vStripes[1].flags = amdmsUSE_NOTHING;
			ppEnv->env.stripes.vStripes[2].pos = 1;
			ppEnv->env.stripes.vStripes[2].size = 90;
			ppEnv->env.stripes.vStripes[2].flags = amdmsUSE_FLATFIELD;
			ppEnv->env.stripes.vStripes[3].pos = 1;
			ppEnv->env.stripes.vStripes[3].size = 20;
			ppEnv->env.stripes.vStripes[3].flags = amdmsUSE_NOTHING;
			ppEnv->env.stripes.vStripes[4].pos = 1;
			ppEnv->env.stripes.vStripes[4].size = 100;
			ppEnv->env.stripes.vStripes[4].flags = amdmsUSE_FLATFIELD;
			ppEnv->env.stripes.vStripes[5].pos = 1;
			ppEnv->env.stripes.vStripes[5].size = 25;
			ppEnv->env.stripes.vStripes[5].flags = amdmsUSE_NOTHING;
			ppEnv->env.stripes.vStripes[6].pos = 1;
			ppEnv->env.stripes.vStripes[6].size = 85;
			ppEnv->env.stripes.vStripes[6].flags = amdmsUSE_FLATFIELD;
			ppEnv->env.stripes.vStripes[7].pos = 1;
			ppEnv->env.stripes.vStripes[7].size = 50;
			ppEnv->env.stripes.vStripes[7].flags = amdmsUSE_NOTHING;
			ppEnv->env.stripes.vStripes[8].pos = 1;
			ppEnv->env.stripes.vStripes[8].size = 92;
			ppEnv->env.stripes.vStripes[8].flags = amdmsUSE_FLATFIELD;

			/* recalculate pos values */
			amdmsRecalcStripes(&(ppEnv->env.stripes), 0, 0);

			/* Prepare Input */
			for( i=0; i<7; i++ )
			{
				sprintf( szTemp, "flat_%01d_psm.fits", i );
				flags.content = amdmsPIXEL_STAT_CONTENT;
				flags.format  = amdmsTABLE_FORMAT;
				flags.type    = amdmsFLOAT_TYPE;
				amdmsAddFileToList( &(ppEnv->env.inFiles),  szTemp,  flags);
			}

			/* Prepare Map Input */
			sprintf( szTemp, "bpm.fits" );
			flags.content = amdmsBAD_PIXEL_CONTENT;
			flags.format  = amdmsCUBE_FORMAT;
			flags.type    = amdmsBYTE_TYPE;
			amdmsAddFileToList( &(ppEnv->env.calib.mapFiles),  szTemp,  flags );

			/* Prepare Output */
			sprintf( szTemp, "ffm.fits" );
			flags.content = amdmsFLATFIELD_CONTENT;
			flags.format  = amdmsCUBE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(ppEnv->env.outFiles),  szTemp,  flags);

			sprintf( szTemp, "ffm_btbl.fits" );
			flags.content = amdmsFLATFIELD_CONTENT;
			flags.format  = amdmsTABLE_FORMAT;
			flags.type    = amdmsFLOAT_TYPE;
			amdmsAddFileToList( &(ppEnv->env.outFiles),  szTemp,  flags);


			sprintf( szMessage, "amdmsDoProperties" );
			cpl_msg_info( fctid, "%s", szMessage );
			iStatus = amdmsDoProperties( ppEnv );
			if( iStatus == amdmsSUCCESS )
				iStatus = 0;
			else
				iStatus = 666; /* Error from amdmslib */

			sprintf( szMessage, "Generating flat field map: Status = %d", iStatus );
			cpl_msg_info( fctid, "%s", szMessage );

			amdmsDestroyPropertiesAlgo( &ppEnv );
		}

		/*--------------------------------------------*/
		/* Add the two final products to the list for CPL   */
		if( !iStatus )
		{
			/* Create DFS Products */
			strcpy( szProduct, "amber_eso_bpm.fits" );

			pFrameBPM = cpl_frame_new();
			cpl_frame_set_filename( pFrameBPM, szProduct );
			cpl_frame_set_type    ( pFrameBPM, CPL_FRAME_TYPE_IMAGE );
			cpl_frame_set_tag     ( pFrameBPM, "AMBER_BADPIX" );
			cpl_frame_set_group   ( pFrameBPM, CPL_FRAME_GROUP_PRODUCT );
			cpl_frame_set_level   ( pFrameBPM, CPL_FRAME_LEVEL_FINAL );

			pImage = cpl_image_load( "bpm.fits", CPL_TYPE_FLOAT, 0, 0 );
			qc_properties = DetectorCreateProductHeader( fctid, szInputDark[0], pFrameBPM );

			/* Retrive QC values from header of amdms product */
			pCValues = cpl_propertylist_load( "bpm.fits", 0 );
			if( pCValues )
			{
				iBadPix  = cpl_propertylist_get_int( pCValues, "BADPIX" );
				iGoodPix = cpl_propertylist_get_int( pCValues, "GOODPIX" );
				cpl_propertylist_delete( pCValues );
			}


			/* Add QC parameters */
			sprintf( szMessage, "ESO QC BADPIX = %d", iBadPix );
			cpl_msg_info( fctid, "%s", szMessage );
			cpl_propertylist_append_int( qc_properties, "ESO QC BADPIX", iBadPix );

			sprintf( szMessage, "ESO QC GOODPIX = %d", iGoodPix );
			cpl_msg_info( fctid, "%s", szMessage );
			cpl_propertylist_append_int( qc_properties, "ESO QC GOODPIX", iGoodPix );


			if( iGoodPix )
			{
				dBadRatio = 100.0 * (double)iBadPix / ( (double)iGoodPix + (double)iBadPix );
			}

			sprintf( szMessage, "ESO QC BADRATIO = %.2f", dBadRatio );
			cpl_msg_info( fctid, "%s", szMessage );
			cpl_propertylist_append_float( qc_properties, "ESO QC BADRATIO", dBadRatio );
			cpl_propertylist_set_comment( qc_properties, "ESO QC BADRATIO", "Percentage of bad Pixels vs all Pixels");

			cpl_image_save( pImage, szProduct, CPL_BPP_IEEE_FLOAT, qc_properties, CPL_IO_DEFAULT );
			cpl_frameset_insert( framelist, pFrameBPM );
			cpl_image_delete( pImage );

			/* Writing QC1 Parameters to log */

			qcFromRawfile= cpl_propertylist_load(pszFilename, 0 );
			qc = amber_qclog_open( 0 );

			if( qc )
			{
				qclog = amber_paf_get_properties( qc );

				/* Read original ARCFILE entry and copy to PAF-File */
				pszARCFILE = cpl_propertylist_get_string( qcFromRawfile, "ARCFILE" );

				/* Add mandatory keys */
				cpl_propertylist_append_string( qclog, "ARCFILE", pszARCFILE );

				/* Take the whole header including QC parameters */
				qcFromProduct = qc_properties;

				/* copy to PAF */
				amber_propertylist_append( qclog, qcFromProduct);

				/* Finished... */

				amber_qclog_close(qc);





			} /* if qc */

			/* Cleanup */
			cpl_propertylist_delete( qc_properties);
			cpl_propertylist_delete( qcFromRawfile);

			sprintf( szMessage, "First product is Bad Pixel Map: Status = %d", iStatus );
			cpl_msg_info( fctid, "%s", szMessage );

			/*---------------------------------------------------------*/
			strcpy( szProduct, "amber_eso_ffm.fits" );

			pFrameBPM = cpl_frame_new();
			cpl_frame_set_filename( pFrameBPM, szProduct );
			cpl_frame_set_type    ( pFrameBPM, CPL_FRAME_TYPE_IMAGE );
			cpl_frame_set_tag     ( pFrameBPM, "AMBER_FLATFIELD" );
			cpl_frame_set_group   ( pFrameBPM, CPL_FRAME_GROUP_PRODUCT );
			cpl_frame_set_level   ( pFrameBPM, CPL_FRAME_LEVEL_FINAL );

			pImage = cpl_image_load( "ffm.fits", CPL_TYPE_FLOAT, 0, 0 );
			qc_properties = DetectorCreateProductHeader( fctid, szInputFlat[0], pFrameBPM );
			cpl_image_save( pImage, szProduct, CPL_BPP_IEEE_FLOAT, qc_properties, CPL_IO_DEFAULT );
			cpl_frameset_insert( framelist, pFrameBPM );
			cpl_image_delete( pImage );

			cpl_propertylist_delete( qc_properties);

			sprintf( szMessage, "Second product is Flat Field Map: Status = %d", iStatus );
			cpl_msg_info( fctid, "%s", szMessage );

		} /* STatus still OK */


	}


	cpl_msg_info( fctid, "End of DataReduction");

	cpl_error_reset();

	return iStatus;
}
