KMOS Pipeline Reference Manual  1.1.0
kmo_combine.c
00001 /* $Id: kmo_combine.c,v 1.23 2013/02/26 11:12:32 aagudo Exp $
00002  *
00003  * This file is part of the KMOS Pipeline
00004  * Copyright (C) 2002,2003 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: aagudo $
00023  * $Date: 2013/02/26 11:12:32 $
00024  * $Revision: 1.23 $
00025  * $Name: HEAD $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 #include <string.h>
00033 #include <math.h>
00034 
00035 #include <cpl.h>
00036 #include <cpl_wcs.h>
00037 
00038 #include "kmo_debug.h"
00039 #include "kmo_utils.h"
00040 #include "kmo_dfs.h"
00041 #include "kmo_error.h"
00042 #include "kmo_priv_functions.h"
00043 #include "kmo_cpl_extensions.h"
00044 #include "kmo_constants.h"
00045 #include "kmo_priv_combine.h"
00046 
00047 static int kmo_combine_create(cpl_plugin *);
00048 static int kmo_combine_exec(cpl_plugin *);
00049 static int kmo_combine_destroy(cpl_plugin *);
00050 static int kmo_combine(cpl_parameterlist *, cpl_frameset *);
00051 
00052 static char kmo_combine_description[] =
00053 "This recipe shifts several exposures of an object and combines them. The diffe-\n"
00054 "rent methods to match the exposures are described below (--method parameter).\n"
00055 "The output cube is larger than the input cubes, according to the shifts to be\n"
00056 "applied. Additionally a border of NaN values is added. The WCS is the same as\n"
00057 "for the first exposure.\n"
00058 "For each spatial/spectral pixel a new value will be calculated (according the\n"
00059 "--cmethod parameter) and written into the output cube.\n"
00060 "Only exposures with equal orientation regarding the WCS can be combined (except\n"
00061 "-–method=”none”), north must point to the same direction. It is recommended to\n"
00062 "apply any rotation possibly after combining.\n"
00063 "The default mapping mode is done via the --name parameter, where the name of\n"
00064 "the object has to be provided. The recipe searches in all input data cubes IFUs\n"
00065 "pointing to that object.\n"
00066 "\n"
00067 "BASIC PARAMETERS:\n"
00068 "-----------------\n"
00069 "--name\n"
00070 "--ifus\n"
00071 "Since an object can be present only once per exposure and since it can be\n"
00072 "located in different IFUs for the existing exposures, there are two modes to\n"
00073 "identify the objects:\n"
00074 "   * Combine by object names (default)\n"
00075 "   In this case the object name must be provided via the --name parameter. The\n"
00076 "   object name will be searched for in all primary headers of all provided frames\n"
00077 "   in the keyword ESO OCS ARMx NAME.\n"
00078 "\n"
00079 "   * Combine by index (advanced)\n"
00080 "   In this case the --ifus parameter must be provided. The parameter must have\n"
00081 "   the same number of entries as frames are provided, e.g. \"3;1;24\" for 3 expo-\n"
00082 "   sures. The index doesn't reference the extension in the frame but the real\n"
00083 "   index of the IFU as defined in the EXTNAME keyword (e.g. 'IFU.3.DATA').\n"
00084 "\n"
00085 "--method\n"
00086 "There are following sources to get the shift parameters from:\n"
00087 "   * 'none' (default)\n"
00088 "   The cubes are directly recombined, not shifting at all. The ouput frame will\n"
00089 "   have the same dimensions as the input cubes.\n"
00090 "   If the size differs a warning will be emitted and the cubes will be aligned\n"
00091 "   to the lower left corner. If the orientation differs a warning will be emit-\n"
00092 "   ted, but the cubes are combined anyway.\n"
00093 "\n"
00094 "   * 'header'\n"
00095 "   The shifts are calculated according to the WCS information stored in the\n"
00096 "   header of every IFU. The output frame will get larger, except the object is\n"
00097 "   at the exact same position for all exposures. The size of the exposures can\n"
00098 "   differ, but the orientation must be the same for all exposures.\n"
00099 "\n"
00100 "   * 'center'\n"
00101 "   The shifts are calculated using a centering algorithm. The cube will be col-\n"
00102 "   lapsed and a 2D profile will be fitted to it to identify the centre. With \n"
00103 "   the parameter --fmethod the function to fit can be provided. The size of the\n"
00104 "   exposures can differ, but the orientation must be the same for all exposures.\n"
00105 "\n"
00106 "   * 'user'\n"
00107 "   Read the shifts from a user specified file. The path of the file must be pro-\n"
00108 "   vided using the --filename parameter. For every exposure (except the first one)\n"
00109 "   two shift values are expected per line, they have to be separated with simple\n"
00110 "   spaces. The values indicate pixel shifts and are referenced to the first\n"
00111 "   frame. The 1st value is the shift in x-direction to the left, the 2nd the\n"
00112 "   shift in y-direction upwards. The size of the exposures can differ, but the\n"
00113 "   orientation must be the same for all exposures.\n"
00114 "\n"
00115 "ADVANCED PARAMETERS\n"
00116 "-------------------\n"
00117 "--fmethod\n"
00118 "see --method='center'\n"
00119 "The type of function that should be fitted spatially to the collapsed image.\n"
00120 "This fit is used to create a mask to extract the spectrum of the object. Valid\n"
00121 "values are “gauss” and “moffat”.\n"
00122 "\n"
00123 "--filename\n"
00124 "see --method='user'\n"
00125 "\n"
00126 "--cpos_rej\n"
00127 "--cneg_rej\n"
00128 "--citer\n"
00129 "see --cmethod='ksigma'\n"
00130 "\n"
00131 "--cmax\n"
00132 "--cmin\n"
00133 "see --cmethod='min_max'\n"
00134 "\n"
00135 "--flux\n"
00136 "Specify if flux conservation should be applied.\n"
00137 "\n"
00138 "-------------------------------------------------------------------------------\n"
00139 "  Input files:\n"
00140 "\n"
00141 "   DO                      KMOS                                                \n"
00142 "   category                Type   Explanation                  Required #Frames\n"
00143 "   --------                -----  -----------                  -------- -------\n"
00144 "   <none or any>           F3I    data frame                       Y      2-n  \n"
00145 "\n"
00146 "  Output files:\n"
00147 "\n"
00148 "   DO                      KMOS\n"
00149 "   category                Type   Explanation\n"
00150 "   --------                -----  -----------\n"
00151 "   COMBINE_<ESO PRO CATG>  F3I    Combined data cube\n"
00152 "-------------------------------------------------------------------------------\n"
00153 "\n";
00154 
00171 int cpl_plugin_get_info(cpl_pluginlist *list)
00172 {
00173     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00174     cpl_plugin *plugin = &recipe->interface;
00175 
00176     cpl_plugin_init(plugin,
00177                         CPL_PLUGIN_API,
00178                         KMOS_BINARY_VERSION,
00179                         CPL_PLUGIN_TYPE_RECIPE,
00180                         "kmo_combine",
00181                         "Combine reconstructed cubes",
00182                         kmo_combine_description,
00183                         "Alex Agudo Berbel",
00184                         "agudo@mpe.mpg.de",
00185                         kmos_get_license(),
00186                         kmo_combine_create,
00187                         kmo_combine_exec,
00188                         kmo_combine_destroy);
00189 
00190     cpl_pluginlist_append(list, plugin);
00191 
00192     return 0;
00193 }
00194 
00202 static int kmo_combine_create(cpl_plugin *plugin)
00203 {
00204     cpl_recipe *recipe;
00205     cpl_parameter *p;
00206 
00207     /* Check that the plugin is part of a valid recipe */
00208     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00209         recipe = (cpl_recipe *)plugin;
00210     else
00211         return -1;
00212 
00213     /* Create the parameters list in the cpl_recipe object */
00214     recipe->parameters = cpl_parameterlist_new();
00215 
00216     /* Fill the parameters list */
00217     /* --name */
00218     p = cpl_parameter_new_value("kmos.kmo_combine.name",
00219                                 CPL_TYPE_STRING,
00220                                 "Name of the object to combine.",
00221                                 "kmos.kmo_combine",
00222                                 "");
00223     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "name");
00224     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00225     cpl_parameterlist_append(recipe->parameters, p);
00226 
00227     /* --ifus */
00228     p = cpl_parameter_new_value("kmos.kmo_combine.ifus",
00229                                 CPL_TYPE_STRING,
00230                                 "The indices of the IFUs to combine. "
00231                                 "\"ifu1;ifu2;...\"",
00232                                 "kmos.kmo_combine",
00233                                 "");
00234     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ifus");
00235     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00236     cpl_parameterlist_append(recipe->parameters, p);
00237 
00238     /* --method */
00239     p = cpl_parameter_new_value("kmos.kmo_combine.method",
00240                                 CPL_TYPE_STRING,
00241                                 "The shifting method:   "
00242                                 "'none': no shifting, combined directly "
00243                                                                   "(default), "
00244                                 "'header': shift according to WCS, "
00245                                 "'center': centering algorithm, "
00246                                 "'user': read shifts from file",
00247                                 "kmos.kmo_combine",
00248                                 "none");
00249     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "method");
00250     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00251     cpl_parameterlist_append(recipe->parameters, p);
00252 
00253     /* --fmethod */
00254     p = cpl_parameter_new_value("kmos.kmo_combine.fmethod",
00255                                 CPL_TYPE_STRING,
00256                                 "The fitting method (applies only when "
00257                                 "method='center'):   "
00258                                 "'gauss': fit a gauss function to collapsed "
00259                                 "image (default), "
00260                                 "'moffat': fit a moffat function to collapsed"
00261                                 " image",
00262                                 "kmos.kmo_combine",
00263                                 "gauss");
00264     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fmethod");
00265     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00266     cpl_parameterlist_append(recipe->parameters, p);
00267 
00268     /* --filename */
00269     p = cpl_parameter_new_value("kmos.kmo_combine.filename",
00270                                 CPL_TYPE_STRING,
00271                                 "The path to the file with the shift vectors."
00272                                 "(Applies only to method='user')",
00273                                 "kmos.kmo_combine",
00274                                 "");
00275     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "filename");
00276     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00277     cpl_parameterlist_append(recipe->parameters, p);
00278 
00279     /* --flux */
00280     p = cpl_parameter_new_value("kmos.kmo_shift.flux",
00281                                 CPL_TYPE_BOOL,
00282                                 "Apply flux conservation: "
00283                                 "(TRUE (apply) or "
00284                                 "FALSE (don't apply)",
00285                                 "kmos.kmo_combine",
00286                                 FALSE);
00287     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux");
00288     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00289     cpl_parameterlist_append(recipe->parameters, p);
00290 
00291     return kmo_combine_pars_create(recipe->parameters,
00292                                    "kmos.kmo_combine",
00293                                    DEF_REJ_METHOD,
00294                                    FALSE);
00295 }
00296 
00302 static int kmo_combine_exec(cpl_plugin *plugin)
00303 {
00304     cpl_recipe  *recipe;
00305 
00306     /* Get the recipe out of the plugin */
00307     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00308         recipe = (cpl_recipe *)plugin;
00309     else return -1 ;
00310 
00311     return kmo_combine(recipe->parameters, recipe->frames);
00312 }
00313 
00319 static int kmo_combine_destroy(cpl_plugin *plugin)
00320 {
00321     cpl_recipe *recipe;
00322 
00323     /* Get the recipe out of the plugin */
00324     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00325         recipe = (cpl_recipe *)plugin;
00326     else return -1 ;
00327 
00328     cpl_parameterlist_delete(recipe->parameters);
00329     return 0 ;
00330 }
00331 
00332 //int kmo_tolerance_round(double x, double tol)
00333 //{
00334 //    int ret = 0;
00335 
00336 //    KMO_TRY
00337 //    {
00338 //        if (fabs(x - floor(x)) < tol) {
00339 //            // value is slightly greater than the real int value
00340 //            ret = floor(x);
00341 //        } else {
00342 //            if (fabs(x - floor(x+tol)) < tol) {
00343 //                // value is slightly greater than the real int value
00344 //                ret = floor(x+tol);
00345 //            } else {
00346 //                // error: sub pixel shift
00347 //                KMO_TRY_ASSURE(1 == 0,
00348 //                               CPL_ERROR_ILLEGAL_INPUT,
00349 //                               "Please apply only whole pixel shifts here "
00350 //                               "and no subpixel shifts!");
00351 //            }
00352 //        }
00353 //    }
00354 //    KMO_CATCH
00355 //    {
00356 //        KMO_CATCH_MSG();
00357 
00358 //        ret = 0;
00359 //    }
00360 
00361 //    return ret;
00362 //}
00363 
00378 static int kmo_combine(cpl_parameterlist *parlist, cpl_frameset *frameset)
00379 {
00380     const char       *method             = NULL,
00381                      *cmethod            = NULL,
00382                      *fmethod            = NULL,
00383                      *filename           = NULL,
00384                      *frame_filename     = NULL,
00385                      *ifus_txt           = NULL;
00386 
00387     char             *tmp_str            = NULL,
00388                      *name               = NULL;
00389 
00390     cpl_imagelist    **data_cube_list    = NULL,
00391                      **noise_cube_list   = NULL,
00392                      *cube_combined_data = NULL,
00393                      *cube_combined_noise= NULL;
00394 
00395     cpl_vector       *ifus               = NULL;
00396 
00397     int              ret_val             = 0,
00398                      nr_frames           = 0,
00399                      index               = 0,
00400                      data_cube_counter   = 0,
00401                      noise_cube_counter  = 0,
00402                      ifu_nr              = 0,
00403                      citer               = 0,
00404                      cmin                = 0,
00405                      cmax                = 0,
00406                      flux                = FALSE;
00407 
00408     double           cpos_rej            = 0.0,
00409                      cneg_rej            = 0.0;
00410 
00411     cpl_propertylist *main_header        = NULL,
00412                      **data_header_list  = NULL,
00413                      **noise_header_list = NULL;
00414 
00415     cpl_frame        *frame              = NULL;
00416 
00417     main_fits_desc   desc;
00418 
00419     enum extrapolationType extrapol_enum = NONE_CLIPPING;
00420 
00421     KMO_TRY
00422     {
00423         /* --- check input --- */
00424         KMO_TRY_ASSURE((parlist != NULL) &&
00425                        (frameset != NULL),
00426                        CPL_ERROR_NULL_INPUT,
00427                        "Not all input data is provided!");
00428 
00429         nr_frames = cpl_frameset_get_size(frameset);
00430 
00431         KMO_TRY_ASSURE(nr_frames >= 2,
00432                        CPL_ERROR_NULL_INPUT,
00433                        "At least two frames must be provided to combine!");
00434 
00435         KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_combine") == 1,
00436                        CPL_ERROR_ILLEGAL_INPUT,
00437                        "Cannot identify RAW and CALIB frames!");
00438 
00439         cpl_msg_info("", "--- Parameter setup for kmo_combine -------");
00440 
00441         KMO_TRY_EXIT_IF_NULL(
00442             method = kmo_dfs_get_parameter_string(parlist,
00443                                            "kmos.kmo_combine.method"));
00444 
00445         KMO_TRY_EXIT_IF_NULL(
00446             fmethod = kmo_dfs_get_parameter_string(parlist,
00447                                            "kmos.kmo_combine.fmethod"));
00448 
00449         KMO_TRY_ASSURE((strcmp(method, "none") == 0) ||
00450                        (strcmp(method, "header") == 0) ||
00451                        (strcmp(method, "center") == 0) ||
00452                        (strcmp(method, "user") == 0),
00453                        CPL_ERROR_ILLEGAL_INPUT,
00454                        "Following shift methods are available : 'none', "
00455                        "'header', 'center' or 'user'");
00456 
00457         if (strcmp(method, "user") == 0) {
00458             filename = kmo_dfs_get_parameter_string(parlist,
00459                                                    "kmos.kmo_combine.filename");
00460             KMO_TRY_CHECK_ERROR_STATE();
00461 
00462             KMO_TRY_ASSURE(strcmp(filename, "") != 0,
00463                            CPL_ERROR_ILLEGAL_INPUT,
00464                            "path of file with shift information must be "
00465                            "provided!");
00466 
00467             KMO_TRY_EXIT_IF_ERROR(
00468                 kmo_dfs_print_parameter_help(parlist,
00469                                              "kmos.kmo_combine.filename"));
00470         }
00471 
00472         KMO_TRY_EXIT_IF_ERROR(
00473             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_combine.method"));
00474 
00475         ifus_txt = kmo_dfs_get_parameter_string(parlist,
00476                                                   "kmos.kmo_combine.ifus");
00477         KMO_TRY_CHECK_ERROR_STATE();
00478 
00479         name = (char*)kmo_dfs_get_parameter_string(parlist, "kmos.kmo_combine.name");
00480         KMO_TRY_CHECK_ERROR_STATE();
00481 
00482         if (strcmp(ifus_txt, "") != 0) {
00483             KMO_TRY_ASSURE(strcmp(name, "") == 0,
00484                            CPL_ERROR_ILLEGAL_INPUT,
00485                            "name parameter must be NULL if IFU indices are "
00486                            "provided!");
00487 
00488             KMO_TRY_EXIT_IF_NULL(
00489                 ifus = kmo_identify_values(ifus_txt));
00490 
00491             KMO_TRY_ASSURE(cpl_vector_get_size(ifus) == nr_frames,
00492                            CPL_ERROR_ILLEGAL_INPUT,
00493                            "ifus parameter must have the same number of values "
00494                            "than frames provided ) (%lld!=%d)",
00495                            cpl_vector_get_size(ifus), nr_frames);
00496         }
00497 
00498         if (strcmp(name, "") != 0) {
00499             KMO_TRY_ASSURE(strcmp(ifus_txt, "") == 0,
00500                            CPL_ERROR_ILLEGAL_INPUT,
00501                            "ifus parameter must be NULL if name is provided!");
00502         }
00503 
00504         flux = kmo_dfs_get_parameter_bool(parlist,
00505                                           "kmos.kmo_shift.flux");
00506         KMO_TRY_CHECK_ERROR_STATE();
00507         KMO_TRY_EXIT_IF_ERROR(
00508             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_shift.flux"));
00509 
00510         KMO_TRY_ASSURE((flux == TRUE) || (flux == FALSE),
00511                        CPL_ERROR_ILLEGAL_INPUT,
00512                        "flux must be TRUE or FALSE!");
00513 
00514         if ((strcmp(name, "") == 0) && (strcmp(ifus_txt, "") == 0)) {
00515             cpl_msg_info("","**************************************************");
00516             cpl_msg_info("","*  A map containing all IFUs will be generated!  *");
00517             cpl_msg_info("","**************************************************");
00518             name = cpl_sprintf("mapping");
00519             extrapol_enum = BCS_NATURAL;
00520         }
00521 
00522         KMO_TRY_EXIT_IF_ERROR(
00523             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_combine.ifus"));
00524 
00525         KMO_TRY_EXIT_IF_ERROR(
00526             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_combine.name"));
00527 
00528         KMO_TRY_EXIT_IF_ERROR(
00529             kmo_combine_pars_load(parlist,
00530                                   "kmos.kmo_combine",
00531                                   &cmethod,
00532                                   &cpos_rej,
00533                                   &cneg_rej,
00534                                   &citer,
00535                                   &cmin,
00536                                   &cmax,
00537                                   FALSE));
00538 
00539         cpl_msg_info("", "-------------------------------------------");
00540 
00541         // load data and noise
00542         KMO_TRY_EXIT_IF_NULL(
00543             data_cube_list = cpl_calloc(nr_frames*KMOS_NR_IFUS,
00544                                         sizeof(cpl_imagelist*)));
00545 
00546         KMO_TRY_EXIT_IF_NULL(
00547             data_header_list = cpl_calloc(nr_frames*KMOS_NR_IFUS,
00548                                           sizeof(cpl_propertylist*)));
00549 
00550         KMO_TRY_EXIT_IF_NULL(
00551             noise_cube_list = cpl_calloc(nr_frames*KMOS_NR_IFUS,
00552                                          sizeof(cpl_imagelist*)));
00553 
00554         KMO_TRY_EXIT_IF_NULL(
00555             noise_header_list = cpl_calloc(nr_frames*KMOS_NR_IFUS,
00556                                            sizeof(cpl_propertylist*)));
00557 
00558         //
00559         // load all data (and noise if existent) cubes and store them
00560         //
00561         data_cube_counter = 0;
00562         noise_cube_counter = 0;
00563         for (int i = 0; i < nr_frames; i++) {
00564             KMO_TRY_EXIT_IF_NULL(
00565                 tmp_str = cpl_sprintf("%d", i));
00566 
00567             KMO_TRY_EXIT_IF_NULL(
00568                 frame = kmo_dfs_get_frame(frameset, tmp_str));
00569 
00570             KMO_TRY_EXIT_IF_NULL(
00571                 frame_filename = cpl_frame_get_filename(frame));
00572 
00573             kmo_init_fits_desc(&desc);
00574 
00575             desc = kmo_identify_fits_header(frame_filename);
00576             KMO_TRY_CHECK_ERROR_STATE_MSG("Provided fits file doesn't seem to "
00577                                           "be in KMOS-format!");
00578 
00579             KMO_TRY_ASSURE(desc.fits_type == f3i_fits,
00580                            CPL_ERROR_ILLEGAL_INPUT,
00581                            "Frame No. %d hasn't correct data type "
00582                            "(must be of type F3I)!", i+1);
00583 
00584             if (strcmp(name, "mapping") == 0) {
00585                 // we are in mapping mode
00586                 for (int j = 1; j <= KMOS_NR_IFUS; j++) {
00587                     //loop over all IFUs
00588                     if (desc.sub_desc[j-1].valid_data == TRUE) {
00589                         // load data frames
00590                         override_err_msg = TRUE;
00591                         data_cube_list[data_cube_counter] =
00592                             kmo_dfs_load_cube(frameset, tmp_str, j, FALSE);
00593                         override_err_msg = FALSE;
00594                         if (data_cube_list[data_cube_counter] == NULL) {
00595                             // no data found for this IFU
00596                             cpl_error_reset();
00597                         } else {
00598                             KMO_TRY_EXIT_IF_NULL(
00599                                 data_header_list[data_cube_counter] =
00600                                     kmo_dfs_load_sub_header(frameset, tmp_str, j, FALSE));
00601                             cpl_propertylist_update_string(data_header_list[data_cube_counter],
00602                                                     "ESO PRO FRNAME",
00603                                                     frame_filename);
00604                             cpl_propertylist_update_int(data_header_list[data_cube_counter],
00605                                                     "ESO PRO IFUNR",
00606                                                     j);
00607                             data_cube_counter++;
00608                         }
00609 
00610                         // load noise frames
00611                         override_err_msg = TRUE;
00612                         noise_cube_list[noise_cube_counter] =
00613                             kmo_dfs_load_cube(frameset, tmp_str, j, TRUE);
00614                         override_err_msg = FALSE;
00615                         if (noise_cube_list[noise_cube_counter] == NULL) {
00616                             // no noise found for this IFU
00617                             cpl_error_reset();
00618                         } else {
00619                             KMO_TRY_EXIT_IF_NULL(
00620                                 noise_header_list[noise_cube_counter] =
00621                                     kmo_dfs_load_sub_header(frameset, tmp_str, j, TRUE));
00622                             noise_cube_counter++;
00623                         }
00624 
00625                         // check for every iteration if number of data and noise
00626                         // frames is the same
00627                         if (noise_cube_counter > 0) {
00628                             KMO_TRY_ASSURE(data_cube_counter == noise_cube_counter,
00629                                            CPL_ERROR_ILLEGAL_INPUT,
00630                                            "Frame No. %d (%s) has no noise frame "
00631                                            "while the preceeding ones had!",
00632                                            i+1, frame_filename);
00633                         }
00634                     } // end if valid_data
00635                 }
00636             } else {
00637                 if (ifus != NULL) {
00638                     ifu_nr = cpl_vector_get(ifus, i);
00639                     KMO_TRY_CHECK_ERROR_STATE();
00640                 } else {
00641                     ifu_nr = kmo_get_index_from_ocs_name(frame, name);
00642                     KMO_TRY_CHECK_ERROR_STATE();
00643                 }
00644 
00645                 if (ifu_nr > 0) {
00646                     index = kmo_identify_index(frame_filename, ifu_nr , FALSE);
00647                     KMO_TRY_CHECK_ERROR_STATE();
00648 
00649                     if (desc.sub_desc[index-1].valid_data == TRUE) {
00650                         // load data frames
00651                         override_err_msg = TRUE;
00652                         data_cube_list[data_cube_counter] =
00653                             kmo_dfs_load_cube(frameset, tmp_str, ifu_nr, FALSE);
00654                         override_err_msg = FALSE;
00655                         if (data_cube_list[data_cube_counter] == NULL) {
00656                             // no data found for this IFU
00657                             cpl_error_reset();
00658                             if (ifus != NULL) {
00659                                 cpl_msg_warning(cpl_func, "Frame No. %d (%s) "
00660                                                 "doesn't contain IFU No. %d!", i+1,
00661                                                 frame_filename, ifu_nr);
00662                             } else {
00663                                 cpl_msg_warning(cpl_func, "Frame No. %d (%s) "
00664                                                 "doesn't contain IFU with object "
00665                                                 "name '%s'!", i+1,
00666                                                 frame_filename, name);
00667                             }
00668                         } else {
00669                             KMO_TRY_EXIT_IF_NULL(
00670                                 data_header_list[data_cube_counter] =
00671                                     kmo_dfs_load_sub_header(frameset, tmp_str,
00672                                                             ifu_nr, FALSE));
00673                         cpl_propertylist_update_string(data_header_list[data_cube_counter],
00674                                                 "ESO PRO FRNAME",
00675                                                 frame_filename);
00676                         cpl_propertylist_update_int(data_header_list[data_cube_counter],
00677                                                 "ESO PRO IFUNR",
00678                         ifu_nr);
00679                             data_cube_counter++;
00680                         }
00681 
00682                         // load noise frames
00683                         override_err_msg = TRUE;
00684                         noise_cube_list[noise_cube_counter] =
00685                             kmo_dfs_load_cube(frameset, tmp_str, ifu_nr, TRUE);
00686                         override_err_msg = FALSE;
00687                         if (noise_cube_list[noise_cube_counter] == NULL) {
00688                             // no noise found for this IFU
00689                             cpl_error_reset();
00690                         } else {
00691                             KMO_TRY_EXIT_IF_NULL(
00692                                 noise_header_list[noise_cube_counter] =
00693                                     kmo_dfs_load_sub_header(frameset, tmp_str,
00694                                                             ifu_nr, TRUE));
00695                             noise_cube_counter++;
00696                         }
00697 
00698                         // check for every iteration if number of data and noise
00699                         // frames is the same
00700                         if (noise_cube_counter > 0) {
00701                             KMO_TRY_ASSURE(data_cube_counter == noise_cube_counter,
00702                                            CPL_ERROR_ILLEGAL_INPUT,
00703                                            "Frame No. %d (%s) has no noise frame "
00704                                            "while the preceeding ones had!",
00705                                            i+1, frame_filename);
00706                         }
00707                     } // end if valid_data
00708                 } // end if (ifu_nr > 0)
00709             }
00710 
00711             kmo_free_fits_desc(&desc);
00712             cpl_free(tmp_str); tmp_str = NULL;
00713         } // for i = nr_frames
00714         KMO_TRY_CHECK_ERROR_STATE();
00715 
00716         //
00717         // combine data
00718         //
00719         KMO_TRY_EXIT_IF_ERROR(
00720             kmo_priv_combine(data_cube_list,
00721                              noise_cube_list,
00722                              data_header_list,
00723                              noise_header_list,
00724                              data_cube_counter,
00725                              noise_cube_counter,
00726                              name,
00727                              ifus_txt,
00728                              method,
00729                              "BCS",
00730                              fmethod,
00731                              filename,
00732                              cmethod,
00733                              cpos_rej,
00734                              cneg_rej,
00735                              citer,
00736                              cmin,
00737                              cmax,
00738                              extrapol_enum,
00739                              flux,
00740                              &cube_combined_data,
00741                              &cube_combined_noise));
00742 
00743         //
00744         // save data
00745         //
00746         /* save data and noise (if existing) */
00747         // --- load, update & save primary header ---
00748 
00749         // setup output category COMBINE + ESO PRO CATG
00750         KMO_TRY_EXIT_IF_NULL(
00751             main_header = kmo_dfs_load_primary_header(frameset, "0"));
00752         KMO_TRY_EXIT_IF_NULL(
00753             tmp_str = cpl_sprintf("%s_%s",
00754                               COMBINE,
00755                               cpl_propertylist_get_string(main_header,
00756                                                           CPL_DFS_PRO_CATG)));
00757         cpl_propertylist_delete(main_header); main_header = NULL;
00758 
00759         frame = cpl_frameset_get_first(frameset);
00760         KMO_TRY_EXIT_IF_ERROR(
00761             kmo_dfs_save_main_header(frameset, tmp_str, "", frame, NULL,
00762                                      parlist, cpl_func));
00763 
00764         if (data_header_list[0] != NULL) {
00765             if (cpl_propertylist_has(data_header_list[0], "ESO PRO FRNAME")) {
00766                 cpl_propertylist_erase(data_header_list[0], "ESO PRO FRNAME");
00767             }
00768             if (cpl_propertylist_has(data_header_list[0], "ESO PRO IFUNR")) {
00769                 cpl_propertylist_erase(data_header_list[0], "ESO PRO IFUNR");
00770             }
00771         }
00772         KMO_TRY_CHECK_ERROR_STATE();
00773 
00774         KMO_TRY_EXIT_IF_ERROR(
00775             kmo_dfs_save_cube(cube_combined_data, tmp_str, "",
00776                               data_header_list[0], 0./0.));
00777 
00778         KMO_TRY_EXIT_IF_ERROR(
00779             kmo_dfs_save_cube(cube_combined_noise, tmp_str, "",
00780                               noise_header_list[0], 0./0.));
00781 
00782         cpl_free(tmp_str); tmp_str = NULL;
00783         if (strcmp(name, "mapping") == 0) {
00784             cpl_free(name); name = NULL;
00785         }
00786     }
00787     KMO_CATCH
00788     {
00789         KMO_CATCH_MSG();
00790         ret_val = -1;
00791     }
00792 
00793     cpl_propertylist_delete(main_header); main_header = NULL;
00794     cpl_vector_delete(ifus); ifus = NULL;
00795     cpl_imagelist_delete(cube_combined_data); cube_combined_data = NULL;
00796     cpl_imagelist_delete(cube_combined_noise); cube_combined_noise = NULL;
00797 
00798     if (data_cube_list != NULL) {
00799         for (int i = 0; i < nr_frames*KMOS_NR_IFUS; i++) {
00800             cpl_imagelist_delete(data_cube_list[i]); data_cube_list[i] = NULL;
00801         }
00802         cpl_free(data_cube_list); data_cube_list = NULL;
00803     }
00804 
00805     if (noise_cube_list != NULL) {
00806         for (int i = 0; i < nr_frames*KMOS_NR_IFUS; i++) {
00807             cpl_imagelist_delete(noise_cube_list[i]); noise_cube_list[i] = NULL;
00808         }
00809         cpl_free(noise_cube_list); noise_cube_list = NULL;
00810     }
00811 
00812     if (data_header_list != NULL) {
00813         for (int i = 0; i < nr_frames*KMOS_NR_IFUS; i++) {
00814             cpl_propertylist_delete(data_header_list[i]);
00815             data_header_list[i] = NULL;
00816         }
00817         cpl_free(data_header_list); data_header_list = NULL;
00818     }
00819 
00820     if (noise_header_list != NULL) {
00821         for (int i = 0; i < nr_frames*KMOS_NR_IFUS; i++) {
00822             cpl_propertylist_delete(noise_header_list[i]);
00823             noise_header_list[i] = NULL;
00824         }
00825         cpl_free(noise_header_list); noise_header_list = NULL;
00826     }
00827 
00828     return ret_val;
00829 }
00830