KMOS Pipeline Reference Manual  1.3.17
kmos_combine.c
00001 /* 
00002  * This file is part of the KMOS Pipeline
00003  * Copyright (C) 2002,2003 European Southern Observatory
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00020 #ifdef HAVE_CONFIG_H
00021 #include <config.h>
00022 #endif
00023 
00024 /*-----------------------------------------------------------------------------
00025  *                              Includes
00026  *----------------------------------------------------------------------------*/
00027 
00028 #include <string.h>
00029 #include <math.h>
00030 
00031 #include <cpl.h>
00032 #include <cpl_wcs.h>
00033 
00034 #include "kmo_debug.h"
00035 #include "kmo_utils.h"
00036 #include "kmo_dfs.h"
00037 #include "kmo_error.h"
00038 #include "kmo_priv_functions.h"
00039 #include "kmo_cpl_extensions.h"
00040 #include "kmo_constants.h"
00041 #include "kmo_priv_combine.h"
00042 
00043 /*-----------------------------------------------------------------------------
00044  *                          Functions prototypes
00045  *----------------------------------------------------------------------------*/
00046 
00047 static char * kmos_combine_create_used_ifus_string(const int *,const int *,int);
00048 static cpl_bivector * kmos_combine_parse_skipped(const char *) ;
00049 static int kmos_combine_is_skipped(const cpl_bivector *, int, int) ;
00050 
00051 static int kmos_combine_create(cpl_plugin *);
00052 static int kmos_combine_exec(cpl_plugin *);
00053 static int kmos_combine_destroy(cpl_plugin *);
00054 static int kmos_combine(cpl_parameterlist *, cpl_frameset *);
00055 
00056 /*-----------------------------------------------------------------------------
00057  *                          Static variables
00058  *----------------------------------------------------------------------------*/
00059 
00060 static char kmos_combine_description[] =
00061 "This recipe shifts several exposures of an object and combines them. Diffe-\n"
00062 "rent methods to match the exposures are described here (--method parameter).\n"
00063 "The output cube is larger than the input cubes, according to the shifts to\n"
00064 "be applied. Additionally a border of NaN values is added. The WCS is the\n"
00065 "same as for the first exposure.\n"
00066 "For each spatial/spectral pixel a new value is calculated (according the\n"
00067 "--cmethod parameter) and written into the output cube.\n"
00068 "Only exposures with the same WCS orientation can be combined (except\n"
00069 "-–method=”none”), north must point to the same direction. It is recommended\n"
00070 "to apply any rotation possibly after combining.\n"
00071 "\n"
00072 "The behavior of the selection of IFUs to combine differs for some templates\n"
00073 "and can be controlled with the parameters --name and --ifus.\n"
00074 "If the input data cubes stem from templates KMOS_spec_obs_mapping8 or\n"
00075 "KMOS_spec_obs_mapping24 all extensions from all input frames are combined\n"
00076 "into a single map by default (like in recipe kmo_sci_red). If just the area\n"
00077 "of a specific IFU should be combined, the parameter --ifus can be specified,\n"
00078 "or more easily --name.\n"
00079 "If the input data cubes stem from other templates like e.g.\n"
00080 "KMOS_spec_obs_freedither all extensions of all input frames are combined\n"
00081 "into several output frames by default. The input IFUs are grouped according\n"
00082 "to their targeted object name stored in the keywords ESO OCS ARMx NAME. If \n"
00083 "just a specific object should be combined, its name can be specified with \n"
00084 "--name. If arbitrary IFUs shoukd be comined, one can specify these with the\n"
00085 "parameter --ifus.\n"
00086 "\n"
00087 "The default mapping mode is done via the --name parameter, where the name of\n"
00088 "the object has to be provided. The recipe searches in input data cubes IFUs\n"
00089 "pointing to that object.\n"
00090 "\n"
00091 "---------------------------------------------------------------------------\n"
00092 "  Input files:\n"
00093 "\n"
00094 "   DO                  KMOS                                                \n"
00095 "   category            Type   Explanation                  Required #Frames\n"
00096 "   --------            -----  -----------                  -------- -------\n"
00097 "   <none or any>       F3I    data frame                       Y      2-n  \n"
00098 "\n"
00099 "  Output files:\n"
00100 "\n"
00101 "   DO                      KMOS\n"
00102 "   category                Type    Explanation\n"
00103 "   --------                -----   -----------\n"
00104 "   COMBINE_<ESO PRO CATG>  F3I     Combined data cube\n"
00105 "   EXP_MASK_<ESO PRO CATG> F3I     Exposure time mask\n"
00106 "   SCI_COMBINED_COLL               (optional) Collapsed combined cube\n"
00107 "                                   (set --collapse_combined)\n"
00108 "---------------------------------------------------------------------------\n"
00109 "\n";
00110 
00111 /*-----------------------------------------------------------------------------
00112  *                              Functions code
00113  *----------------------------------------------------------------------------*/
00114 
00115 /*----------------------------------------------------------------------------*/
00119 /*----------------------------------------------------------------------------*/
00120 
00123 /*----------------------------------------------------------------------------*/
00132 /*----------------------------------------------------------------------------*/
00133 int cpl_plugin_get_info(cpl_pluginlist *list)
00134 {
00135     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00136     cpl_plugin *plugin = &recipe->interface;
00137 
00138     cpl_plugin_init(plugin,
00139             CPL_PLUGIN_API,
00140             KMOS_BINARY_VERSION,
00141             CPL_PLUGIN_TYPE_RECIPE,
00142             "kmos_combine",
00143             "Combine reconstructed cubes",
00144             kmos_combine_description,
00145             "Alex Agudo Berbel, Y. Jung",
00146             "usd-help@eso.org",
00147             kmos_get_license(),
00148             kmos_combine_create,
00149             kmos_combine_exec,
00150             kmos_combine_destroy);
00151     cpl_pluginlist_append(list, plugin);
00152 
00153     return 0;
00154 }
00155 
00156 /*----------------------------------------------------------------------------*/
00164 /*----------------------------------------------------------------------------*/
00165 static int kmos_combine_create(cpl_plugin *plugin)
00166 {
00167     cpl_recipe *recipe;
00168     cpl_parameter *p;
00169 
00170     /* Check that the plugin is part of a valid recipe */
00171     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00172         recipe = (cpl_recipe *)plugin;
00173     else
00174         return -1;
00175 
00176     /* Create the parameters list in the cpl_recipe object */
00177     recipe->parameters = cpl_parameterlist_new();
00178 
00179     /* Fill the parameters list */
00180     /* --name */
00181     p = cpl_parameter_new_value("kmos.kmos_combine.name", CPL_TYPE_STRING,
00182             "Name of the object to combine.", "kmos.kmos_combine", "");
00183     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "name");
00184     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00185     cpl_parameterlist_append(recipe->parameters, p);
00186 
00187     /* --ifus */
00188     p = cpl_parameter_new_value("kmos.kmos_combine.ifus", CPL_TYPE_STRING,
00189             "The indices of the IFUs to combine. " "\"ifu1;ifu2;...\"", 
00190             "kmos.kmos_combine", "");
00191     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ifus");
00192     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00193     cpl_parameterlist_append(recipe->parameters, p);
00194 
00195     /* --method */
00196     p = cpl_parameter_new_value("kmos.kmos_combine.method", CPL_TYPE_STRING,
00197             "The shifting method:   "
00198             "'none': no shifting, combined directly, "
00199             "'header': shift according to WCS (default), "
00200             "'center': centering algorithm, "
00201             "'user': read shifts from file",
00202             "kmos.kmos_combine", "none");
00203     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "method");
00204     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00205     cpl_parameterlist_append(recipe->parameters, p);
00206 
00207     /* --fmethod */
00208     p = cpl_parameter_new_value("kmos.kmos_combine.fmethod", CPL_TYPE_STRING,
00209             "The fitting method (applies only when method='center'):   "
00210             "'gauss': fit a gauss function to collapsed image (default), "
00211             "'moffat': fit a moffat function to collapsed image",
00212             "kmos.kmos_combine", "gauss");
00213     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fmethod");
00214     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00215     cpl_parameterlist_append(recipe->parameters, p);
00216 
00217     /* --filename */
00218     p = cpl_parameter_new_value("kmos.kmos_combine.filename", CPL_TYPE_STRING,
00219             "The path to the file with the shift vectors (method='user')",
00220             "kmos.kmos_combine", "");
00221     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "filename");
00222     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00223     cpl_parameterlist_append(recipe->parameters, p);
00224 
00225     /* --flux */
00226     p = cpl_parameter_new_value("kmos.kmos_combine.flux", CPL_TYPE_BOOL,
00227             "Apply flux conservation: (TRUE (apply) or FALSE (don't apply)",
00228             "kmos.kmos_combine", FALSE);
00229     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux");
00230     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00231     cpl_parameterlist_append(recipe->parameters, p);
00232 
00233     /* --edge_nan */
00234     p = cpl_parameter_new_value("kmos.kmos_combine.edge_nan", CPL_TYPE_BOOL,
00235             "Set borders of cubes to NaN before combining them."
00236             "(TRUE (apply) or FALSE (don't apply)", "kmos.kmos_combine", FALSE);
00237     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "edge_nan");
00238     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00239     cpl_parameterlist_append(recipe->parameters, p);
00240 
00241     /* --skipped_frames */
00242     p = cpl_parameter_new_value("kmos.kmos_combine.skipped_frames", 
00243             CPL_TYPE_STRING,
00244             "Comma separated List of IFUs to skip for the combination. An IFU is specified with R:I."
00245             "R is the index (starting at 1) of the reconstructed frame, I the IFU number", 
00246             "kmos.kmos_combine", "");
00247     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skipped_frames");
00248     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00249     cpl_parameterlist_append(recipe->parameters, p);
00250 
00251     /* --suppress_extension */
00252     p = cpl_parameter_new_value("kmos.kmos_combine.suppress_extension",
00253             CPL_TYPE_BOOL, "Suppress arbitrary filename extension.",
00254             "kmos.kmos_combine", FALSE);
00255     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "suppress_extension");
00256     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00257     cpl_parameterlist_append(recipe->parameters, p);
00258 
00259     /* --collapse_combined */
00260     p = cpl_parameter_new_value("kmos.kmos_combine.collapse_combined",
00261             CPL_TYPE_BOOL, "Flag to collapse the combined images",
00262             "kmos.kmos_combine", FALSE);
00263     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "collapse_combined");
00264     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00265     cpl_parameterlist_append(recipe->parameters, p);
00266 
00267     return kmos_combine_pars_create(recipe->parameters, "kmos.kmos_combine",
00268             DEF_REJ_METHOD, FALSE);
00269 }
00270 
00271 /*----------------------------------------------------------------------------*/
00277 /*----------------------------------------------------------------------------*/
00278 static int kmos_combine_exec(cpl_plugin *plugin)
00279 {
00280     cpl_recipe  *recipe;
00281 
00282     /* Get the recipe out of the plugin */
00283     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00284         recipe = (cpl_recipe *)plugin;
00285     else return -1 ;
00286 
00287     return kmos_combine(recipe->parameters, recipe->frames);
00288 }
00289 
00290 /*----------------------------------------------------------------------------*/
00296 /*----------------------------------------------------------------------------*/
00297 static int kmos_combine_destroy(cpl_plugin *plugin)
00298 {
00299     cpl_recipe *recipe;
00300 
00301     /* Get the recipe out of the plugin */
00302     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00303         recipe = (cpl_recipe *)plugin;
00304     else return -1 ;
00305 
00306     cpl_parameterlist_delete(recipe->parameters);
00307     return 0 ;
00308 }
00309 
00310 /*----------------------------------------------------------------------------*/
00323 /*----------------------------------------------------------------------------*/
00324 static int kmos_combine(cpl_parameterlist *parlist, cpl_frameset *frameset)
00325 {
00326     const cpl_parameter *   par ;
00327     cpl_frameset        *   rawframes ;
00328     const char      * filename,* fmethod,* method,* ifus_txt,* cmethod,
00329                     * skipped_frames;
00330     double          cpos_rej, cneg_rej ;
00331     cpl_vector      *   ifus ;
00332     int                 citer, cmin, cmax, nr_frames, index,
00333                         data_cube_counter, noise_cube_counter, flux,
00334                         edge_nan, name_vec_size, found, suppress_extension,
00335                         suppress_index, ifu_nr, nv, collapse_combined,
00336                         mapping_id ;
00337     char            * tmp_str, * fn_combine, * fn_mask, * mapping_mode,
00338                     * name, ** name_vec, * name_loc ;
00339     const char      * frame_filename, * tmp_strc ;
00340     cpl_image       * exp_mask ;
00341     cpl_imagelist   ** data_cube_list, ** noise_cube_list, * cube_combined_data,
00342                     * cube_combined_noise ;
00343     cpl_propertylist    * main_header, **data_header_list, **noise_header_list,
00344                         * tmp_header, * pro_plist ;
00345     char                *   reflex_suffix ;
00346     cpl_bivector    *   skipped_bivector ;
00347     cpl_frame       *   frame ;
00348     cpl_size            ci ;
00349     main_fits_desc      desc;
00350     int             *   used_frame_idx ;
00351     int             *   used_ifus ;
00352     char            *   used_ifus_str ;
00353     enum extrapolationType  extrapol_enum = NONE_CLIPPING;
00354     int             i, j ;
00355 
00356     /* Check entries */
00357     if (parlist == NULL || frameset == NULL) {
00358         cpl_msg_error(__func__, "Null Inputs") ;
00359         cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
00360         return -1 ;
00361     }
00362 
00363     /* Get parameters */
00364     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.method");
00365     method = cpl_parameter_get_string(par) ;
00366     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.fmethod");
00367     fmethod = cpl_parameter_get_string(par) ;
00368     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.filename");
00369     filename = cpl_parameter_get_string(par) ;
00370     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.ifus");
00371     ifus_txt = cpl_parameter_get_string(par) ;
00372     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.name");
00373     name = (char*)cpl_parameter_get_string(par) ;
00374     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.flux");
00375     flux = cpl_parameter_get_bool(par) ;
00376     par = cpl_parameterlist_find_const(parlist, 
00377             "kmos.kmos_combine.skipped_frames");
00378     skipped_frames = cpl_parameter_get_string(par) ;
00379     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.edge_nan");
00380     edge_nan = cpl_parameter_get_bool(par) ;
00381     par = cpl_parameterlist_find_const(parlist,
00382             "kmos.kmos_combine.suppress_extension");
00383     suppress_extension = cpl_parameter_get_bool(par) ;
00384     kmos_combine_pars_load(parlist, "kmos.kmos_combine", &cmethod, &cpos_rej, 
00385             &cneg_rej, &citer, &cmin, &cmax, FALSE);
00386     par = cpl_parameterlist_find_const(parlist,
00387             "kmos.kmos_combine.collapse_combined");
00388     collapse_combined = cpl_parameter_get_bool(par);
00389 
00390     /* Check Parameters */
00391     if (strcmp(method, "none") && strcmp(method, "header") &&
00392             strcmp(method, "center") && strcmp(method, "user")) {
00393         cpl_msg_error(__func__,
00394             "shift methods must be 'none', 'header', 'center' or 'user'") ;
00395         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00396         return -1 ;
00397     }
00398     if (strcmp(ifus_txt, "") && strcmp(name, "")) {
00399         cpl_msg_error(__func__,
00400                 "name and IFU indices cannot be both provided") ;
00401         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00402         return -1 ;
00403     }
00404     if (!strcmp(method, "user") && !strcmp(filename, "")) {
00405         cpl_msg_error(__func__,
00406                 "path of file with shift information must be provided") ;
00407         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00408         return -1 ;
00409     }
00410 
00411     /* Identify the RAW and CALIB frames in the input frameset */
00412     if (kmo_dfs_set_groups(frameset, "kmos_combine") != 1) {
00413         cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
00414         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00415         return -1 ;
00416     }
00417 
00418     /* Parse the skipped frames option */
00419     skipped_bivector = NULL ;
00420     if (strcmp(skipped_frames, "")) {
00421         skipped_bivector = kmos_combine_parse_skipped(skipped_frames) ;
00422         if (skipped_bivector != NULL) 
00423             cpl_msg_info(__func__, "Skip the following frames: %s", 
00424                     skipped_frames);
00425     } 
00426 
00427     /* Get the frames to combine - Filter out OH_SPEC */
00428     rawframes = cpl_frameset_duplicate(frameset) ;
00429     cpl_frameset_erase(rawframes, "OH_SPEC") ;
00430 
00431     /* Check Nb of frames */
00432     nr_frames = cpl_frameset_get_size(rawframes);
00433     if (nr_frames < 2) {
00434         if (skipped_bivector!=NULL) cpl_bivector_delete(skipped_bivector) ;
00435         cpl_frameset_delete(rawframes) ;
00436         cpl_msg_error(__func__, "At least two frames must be provided") ;
00437         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00438         return -1 ;
00439     }
00440 
00441     /* Load IFUS if specified */
00442     if (strcmp(ifus_txt, "")) {
00443         ifus = kmo_identify_values(ifus_txt);
00444         if (ifus == NULL || cpl_vector_get_size(ifus) != nr_frames) {
00445             if (ifus != NULL) cpl_vector_delete(ifus);
00446             if (skipped_bivector!=NULL) cpl_bivector_delete(skipped_bivector) ;
00447             cpl_frameset_delete(rawframes) ;
00448             cpl_msg_error(__func__, "ifus size must match the science frames") ;
00449             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00450             return -1 ;
00451         }
00452     } else {
00453         ifus = NULL ;
00454     }
00455 
00456     /* Check for mapping mode */
00457     mapping_mode = NULL ;
00458     cpl_size fs_size = cpl_frameset_get_size(rawframes);
00459     for (ci = 0; ci < fs_size; ci++) {
00460         frame = cpl_frameset_get_position(rawframes, ci);
00461         tmp_header = kmclipm_propertylist_load(cpl_frame_get_filename(frame),0);
00462         if (cpl_propertylist_has(tmp_header, TPL_ID)) {
00463             tmp_strc = cpl_propertylist_get_string(tmp_header, TPL_ID);
00464             if (mapping_mode == NULL) {
00465                 if (!strcmp(tmp_strc, MAPPING8)) 
00466                     mapping_mode = cpl_sprintf("%s", tmp_strc);
00467                 if (!strcmp(tmp_strc, MAPPING24)) 
00468                     mapping_mode = cpl_sprintf("%s", tmp_strc);
00469             } else {
00470                 if (strcmp(tmp_strc, mapping_mode)) {
00471                     cpl_msg_warning(__func__,
00472                             "There are different TPL IDs in input: %s and %s",
00473                             tmp_strc, mapping_mode);
00474                 }
00475             }
00476         }
00477         cpl_propertylist_delete(tmp_header);
00478     }
00479 
00480     if (mapping_mode != NULL) {
00481         if (!strcmp(ifus_txt, "") && !strcmp(name, "")) {
00482             cpl_msg_info(__func__,"*****************************************");
00483             cpl_msg_info(__func__,"* A map with all IFUs will be generated *");
00484             cpl_msg_info(__func__,"*****************************************");
00485             extrapol_enum = BCS_NATURAL;
00486         } else {
00487             cpl_msg_info(__func__, "No Map as name / ifu is specified");
00488             cpl_free(mapping_mode);
00489             mapping_mode = NULL ;
00490         }
00491     }
00492 
00493     /* Mapping Id */
00494     mapping_id = -1 ;
00495     if (mapping_mode == NULL) {
00496         mapping_id = 0 ;
00497     } else {
00498         if (!strcmp(mapping_mode, MAPPING8)) mapping_id = 1 ;
00499         if (!strcmp(mapping_mode, MAPPING24)) mapping_id = 2 ;
00500     }
00501 
00502     /* Create name/ifu map... */
00503     name_vec = cpl_calloc(nr_frames*KMOS_NR_IFUS, sizeof(char*));
00504 
00505     /* No name / IFU specified - Non mapping mode */
00506     if (!strcmp(ifus_txt, "") && !strcmp(name, "") && mapping_mode==NULL) {
00507         /* All available names should be combined in one go */
00508         name_vec_size = 0;
00509         for (i = 0; i < nr_frames; i++) {
00510             tmp_str = cpl_sprintf("%d", i);
00511             frame = kmo_dfs_get_frame(rawframes, tmp_str);
00512             cpl_free(tmp_str);
00513             for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
00514                 found = 0;
00515                 tmp_str = kmo_get_name_from_ocs_ifu(frame, ifu_nr);
00516                 if (tmp_str != NULL) {
00517                     for (j = 0; j < name_vec_size; j++) {
00518                         if (!strcmp(name_vec[j], tmp_str)) {
00519                             found = TRUE;
00520                             break;
00521                         }
00522                     }
00523                     if (!found)     name_vec[name_vec_size++] = tmp_str;
00524                     else            cpl_free(tmp_str);
00525                 }
00526             }
00527         }
00528     } else {
00529         /* Standard behavior: either ifu_nr- or name- or mapping-case */
00530         name_vec_size = 1;
00531         if (mapping_mode != NULL) {
00532             name_vec[0] = cpl_sprintf("mapping");
00533         } else {
00534             if (ifus != NULL) {
00535                 char *tmptmp = NULL;
00536 
00537                 // replace all ; with _
00538                 char *found_char = NULL;
00539                 found_char = strstr(ifus_txt, ";");
00540                 while (found_char != NULL) {
00541                     strncpy(found_char, "_", 1);
00542                     found_char = strstr(ifus_txt, ";");
00543                 }
00544 
00545                 if (strlen(ifus_txt) > 10) {
00546                     tmptmp = kmo_shorten_ifu_string(ifus_txt);
00547                     cpl_msg_info(__func__, "Truncate to ..ifu%s..", tmptmp);
00548                 } else {
00549                     tmptmp = cpl_sprintf("%s", ifus_txt);
00550                 }
00551                 name_vec[0] = cpl_sprintf("IFU%s", tmptmp);
00552                 ifus_txt = "";
00553                 cpl_free(tmptmp); 
00554             } else {
00555                 name_vec[0] = cpl_sprintf("%s", name);
00556             }
00557         }
00558     }
00559    
00560     /* Load data and noise */
00561     data_cube_list = cpl_calloc(nr_frames*KMOS_NR_IFUS, 
00562             sizeof(cpl_imagelist*));
00563     data_header_list = cpl_calloc(nr_frames*KMOS_NR_IFUS, 
00564             sizeof(cpl_propertylist*));
00565     noise_cube_list = cpl_calloc(nr_frames*KMOS_NR_IFUS,
00566             sizeof(cpl_imagelist*));
00567     noise_header_list = cpl_calloc(nr_frames*KMOS_NR_IFUS,
00568             sizeof(cpl_propertylist*));
00569  
00570     /*
00571     if (ifus != NULL) cpl_vector_delete(ifus);
00572     cpl_frameset_delete(rawframes) ;
00573     cpl_free(data_cube_list);
00574     cpl_free(noise_cube_list);
00575     cpl_free(data_header_list);
00576     cpl_free(noise_header_list);
00577     for (i = 0; i < name_vec_size ; i++) cpl_free(name_vec[i]);
00578     cpl_free(name_vec);
00579     if (mapping_mode != NULL) cpl_free(mapping_mode) ;
00580     return 0 ;
00581     */
00582 
00583     /* Load all data (and noise if existent) cubes and store them */
00584     for (nv = 0; nv < name_vec_size; nv++) {
00585         name_loc = name_vec[nv];
00586 
00587         used_frame_idx = cpl_calloc(nr_frames*KMOS_NR_IFUS, sizeof(int)) ;
00588         used_ifus = cpl_calloc(nr_frames*KMOS_NR_IFUS, sizeof(int)) ;
00589         
00590         data_cube_counter = 0;
00591         noise_cube_counter = 0;
00592         for (i = 0; i < nr_frames; i++) {
00593             tmp_str = cpl_sprintf("%d", i);
00594             frame = kmo_dfs_get_frame(rawframes, tmp_str);
00595             frame_filename = cpl_frame_get_filename(frame);
00596             kmo_init_fits_desc(&desc);
00597             desc = kmo_identify_fits_header(frame_filename);
00598 
00599             if (mapping_mode != NULL) {
00600                 /* Mapping mode */
00601                 for (j = 1; j <= KMOS_NR_IFUS; j++) {
00602                     /* Loop over all IFUs */
00603                     if (desc.sub_desc[j-1].valid_data == TRUE &&
00604                             !kmos_combine_is_skipped(skipped_bivector,i+1,j)) {
00605                         /* Load data frames */
00606                         override_err_msg = TRUE;
00607                         data_cube_list[data_cube_counter] =
00608                             kmo_dfs_load_cube(rawframes, tmp_str, j,FALSE);
00609                         override_err_msg = FALSE;
00610                         if (data_cube_list[data_cube_counter] == NULL) {
00611                             cpl_error_reset();
00612                         } else {
00613                             if (edge_nan) kmo_edge_nan(
00614                                     data_cube_list[data_cube_counter], j);
00615                             data_header_list[data_cube_counter] =
00616                                 kmo_dfs_load_sub_header(rawframes, 
00617                                         tmp_str, j, FALSE);
00618                             cpl_propertylist_update_string(
00619                                     data_header_list[data_cube_counter],
00620                                     "ESO PRO FRNAME", frame_filename);
00621                             cpl_propertylist_update_int(
00622                                     data_header_list[data_cube_counter],
00623                                     "ESO PRO IFUNR", j);
00624                             used_frame_idx[data_cube_counter] = i+1 ;
00625                             used_ifus[data_cube_counter] = j ;
00626                             data_cube_counter++;
00627                         }
00628 
00629                         /* Load noise frames */
00630                         override_err_msg = TRUE;
00631                         noise_cube_list[noise_cube_counter] =
00632                             kmo_dfs_load_cube(rawframes, tmp_str, j, TRUE);
00633 
00634                         override_err_msg = FALSE;
00635                         if (noise_cube_list[noise_cube_counter] == NULL) {
00636                             // no noise found for this IFU
00637                             cpl_error_reset();
00638                         } else {
00639                             if (edge_nan) kmo_edge_nan(
00640                                     noise_cube_list[noise_cube_counter], j);
00641                             noise_header_list[noise_cube_counter] =
00642                                 kmo_dfs_load_sub_header(rawframes, tmp_str,
00643                                         j, TRUE);
00644                             noise_cube_counter++;
00645                         }
00646 
00647                         /* Check if number of data and noise frames match */
00648                         if (noise_cube_counter > 0) {
00649                             if (data_cube_counter != noise_cube_counter) {
00650                                 cpl_msg_error(__func__, "Noise missing") ;
00651                                 cpl_error_set(__func__,CPL_ERROR_ILLEGAL_INPUT);
00652                                 /* TODO - deallocate */
00653                                 return -1 ;
00654                             }
00655                         }
00656                     } 
00657                 }
00658             } else {
00659                 /* name/ifu mode (single) */
00660                 if (ifus != NULL)   ifu_nr = cpl_vector_get(ifus, i);
00661                 else ifu_nr = kmo_get_index_from_ocs_name(frame, name_loc);
00662                 if (ifu_nr > 0) {
00663                     index = kmo_identify_index(frame_filename, ifu_nr , FALSE);
00664                     if (desc.sub_desc[index-1].valid_data == TRUE &&
00665                             !kmos_combine_is_skipped(skipped_bivector,i+1,
00666                                 ifu_nr)) {
00667                         /* Load data frames */
00668                         override_err_msg = TRUE;
00669                         data_cube_list[data_cube_counter] =
00670                             kmo_dfs_load_cube(rawframes, tmp_str, ifu_nr, 
00671                                     FALSE);
00672                         override_err_msg = FALSE;
00673                         if (data_cube_list[data_cube_counter] == NULL) {
00674                             /* No data found for this IFU */
00675                             cpl_error_reset();
00676                             if (ifus != NULL)   cpl_msg_warning(cpl_func, 
00677                                     "IFU %d miѕsing in frame %s",
00678                                     ifu_nr, frame_filename);
00679                             else                cpl_msg_warning(cpl_func, 
00680                                     "Object %s missing in Frame %d (%s)",
00681                                     name_loc,  i+1, frame_filename) ;
00682                         } else {
00683                             if (edge_nan) kmo_edge_nan(
00684                                     data_cube_list[data_cube_counter], ifu_nr);
00685                             data_header_list[data_cube_counter] =
00686                                 kmo_dfs_load_sub_header(rawframes, tmp_str,
00687                                         ifu_nr, FALSE);
00688                             cpl_propertylist_update_string(
00689                                     data_header_list[data_cube_counter],
00690                                     "ESO PRO FRNAME", frame_filename);
00691                             cpl_propertylist_update_int(
00692                                     data_header_list[data_cube_counter],
00693                                     "ESO PRO IFUNR", ifu_nr);
00694                             used_frame_idx[data_cube_counter] = i+1 ;
00695                             used_ifus[data_cube_counter] = ifu_nr ;
00696                             data_cube_counter++;
00697                         }
00698 
00699                         /* Load noise frames */
00700                         override_err_msg = TRUE;
00701                         noise_cube_list[noise_cube_counter] =
00702                             kmo_dfs_load_cube(rawframes, tmp_str, ifu_nr, 
00703                                     TRUE);
00704                         override_err_msg = FALSE;
00705                         if (noise_cube_list[noise_cube_counter] == NULL) {
00706                             /* No noise found for this IFU */
00707                             cpl_error_reset();
00708                         } else {
00709                             if (edge_nan) kmo_edge_nan(
00710                                     noise_cube_list[noise_cube_counter],ifu_nr);
00711                             noise_header_list[noise_cube_counter] =
00712                                     kmo_dfs_load_sub_header(rawframes, 
00713                                             tmp_str, ifu_nr, TRUE);
00714                             noise_cube_counter++;
00715                         }
00716 
00717                         /* Check if number of data and noise frames match */
00718                         if (noise_cube_counter > 0) {
00719                             if (data_cube_counter != noise_cube_counter) {
00720                                 /* TODO - deallocate */
00721                                 cpl_msg_error(__func__, "Noise missing") ;
00722                                 cpl_error_set(__func__,CPL_ERROR_ILLEGAL_INPUT);
00723                                 return -1 ;
00724                             }
00725                         }
00726                     } 
00727                 } 
00728             }
00729             kmo_free_fits_desc(&desc);
00730             cpl_free(tmp_str);
00731         } 
00732  
00733         /* Create String for the output header - IFUs usage */
00734         used_ifus_str = kmos_combine_create_used_ifus_string(used_frame_idx, 
00735                 used_ifus, data_cube_counter);
00736         cpl_free(used_frame_idx) ;
00737         cpl_free(used_ifus) ;
00738 
00739         /* Combine data */
00740         exp_mask = NULL ;
00741         cube_combined_noise = NULL ;
00742         cube_combined_data = NULL ;
00743         if (kmo_priv_combine(data_cube_list, noise_cube_list, data_header_list,
00744                     noise_header_list, data_cube_counter, noise_cube_counter, 
00745                     name_loc, ifus_txt, method, "BCS", fmethod, filename, 
00746                     cmethod, cpos_rej, cneg_rej, citer, cmin, cmax, 
00747                     extrapol_enum, flux, &cube_combined_data, 
00748                     &cube_combined_noise, &exp_mask) != CPL_ERROR_NONE) {
00749             for (i = 0; i < data_cube_counter ; i++) 
00750                 cpl_imagelist_delete(data_cube_list[i]);
00751             for (i = 0; i < noise_cube_counter ; i++) 
00752                 cpl_imagelist_delete(noise_cube_list[i]);
00753             for (i = 0; i < data_cube_counter ; i++) 
00754                 cpl_propertylist_delete(data_header_list[i]);
00755             for (i = 0; i < noise_cube_counter ; i++) 
00756                 cpl_propertylist_delete(noise_header_list[i]);
00757             if (ifus != NULL) cpl_vector_delete(ifus);
00758             cpl_free(data_cube_list);
00759             cpl_free(noise_cube_list);
00760             cpl_free(data_header_list);
00761             cpl_free(noise_header_list);
00762             for (i = 0; i < name_vec_size ; i++) cpl_free(name_vec[i]);
00763             cpl_free(name_vec);
00764             cpl_free(used_ifus_str) ;
00765             cpl_frameset_delete(rawframes) ;
00766             if (mapping_mode != NULL) cpl_free(mapping_mode) ;
00767             cpl_msg_error(__func__, "Failed Combination") ;
00768             cpl_error_set(__func__,CPL_ERROR_ILLEGAL_INPUT);
00769             return -1 ;
00770         }
00771         for (i = 0; i < data_cube_counter ; i++) 
00772             cpl_imagelist_delete(data_cube_list[i]);
00773         for (i = 0; i < noise_cube_counter ; i++) 
00774             cpl_imagelist_delete(noise_cube_list[i]);
00775         
00776         /*
00777         for (i = 0; i < data_cube_counter ; i++) 
00778             cpl_propertylist_delete(data_header_list[i]);
00779         for (i = 0; i < noise_cube_counter ; i++) 
00780             cpl_propertylist_delete(noise_header_list[i]);
00781         if (ifus != NULL) cpl_vector_delete(ifus);
00782         cpl_free(data_cube_list);
00783         cpl_free(noise_cube_list);
00784         cpl_free(data_header_list);
00785         cpl_free(noise_header_list);
00786         for (i = 0; i < name_vec_size ; i++) cpl_free(name_vec[i]);
00787         cpl_free(name_vec);
00788         if (mapping_mode != NULL) cpl_free(mapping_mode) ;
00789         cpl_image_delete(exp_mask);
00790         cpl_imagelist_delete(cube_combined_noise);
00791         cpl_imagelist_delete(cube_combined_data);
00792         if (noise_header_list!=NULL && noise_cube_counter==0) 
00793             cpl_propertylist_delete(noise_header_list[0]) ;
00794         cpl_frameset_delete(rawframes) ;
00795         */
00796         /* Save data */
00797         if (!suppress_extension) {
00798             /* Setup output category COMBINE + ESO PRO CATG */
00799             main_header = kmo_dfs_load_primary_header(rawframes, "0");
00800             fn_combine = cpl_sprintf("%s_%s_%s", COMBINE,
00801                     cpl_propertylist_get_string(main_header, CPL_DFS_PRO_CATG),
00802                     name_vec[nv]);
00803             fn_mask = cpl_sprintf("%s_%s_%s", EXP_MASK,
00804                     cpl_propertylist_get_string(main_header, CPL_DFS_PRO_CATG),
00805                     name_vec[nv]);
00806             cpl_propertylist_delete(main_header);
00807         } else {
00808             fn_combine = cpl_sprintf("%s_%d", COMBINE, suppress_index);
00809             fn_mask = cpl_sprintf("%s_%d", EXP_MASK, suppress_index++);
00810         }
00811 
00812         /* Create PRO keys plist */
00813         pro_plist = cpl_propertylist_new() ;
00814         if (used_ifus_str != NULL) 
00815             cpl_propertylist_update_string(pro_plist, "ESO PRO USEDIFUS", 
00816                     used_ifus_str) ;
00817         cpl_propertylist_update_string(pro_plist, "ESO PRO SKIPPEDIFUS", 
00818                 skipped_frames) ;
00819 
00820         /* Add REFLEX SUFFIX keyword */
00821         reflex_suffix = kmos_get_reflex_suffix(mapping_id,
00822                 ifus_txt, name, name_loc) ;
00823         cpl_propertylist_update_string(pro_plist, "ESO PRO REFLEX SUFFIX", 
00824                 reflex_suffix) ;
00825         cpl_free(reflex_suffix) ;
00826 
00827         /* Save Headers first */
00828         frame = cpl_frameset_find(rawframes, NULL);
00829         kmo_dfs_save_main_header(frameset, fn_combine, "", frame, pro_plist, 
00830                 parlist, cpl_func);
00831         kmo_dfs_save_main_header(frameset, fn_mask, "", frame, pro_plist, 
00832                 parlist, cpl_func);
00833         cpl_propertylist_delete(pro_plist) ;
00834         cpl_free(used_ifus_str) ;
00835 
00836         /* Clean */
00837         if (data_header_list[0] != NULL) {
00838             if (cpl_propertylist_has(data_header_list[0], "ESO PRO FRNAME")) {
00839                 cpl_propertylist_erase(data_header_list[0], "ESO PRO FRNAME");
00840             }
00841             if (cpl_propertylist_has(data_header_list[0], "ESO PRO IFUNR")) {
00842                 cpl_propertylist_erase(data_header_list[0], "ESO PRO IFUNR");
00843             }
00844         }
00845         if (noise_header_list[0] != NULL) {
00846             if (cpl_propertylist_has(noise_header_list[0], "ESO PRO FRNAME")) {
00847                 cpl_propertylist_erase(noise_header_list[0], "ESO PRO FRNAME");
00848             }
00849             if (cpl_propertylist_has(noise_header_list[0], "ESO PRO IFUNR")) {
00850                 cpl_propertylist_erase(noise_header_list[0], "ESO PRO IFUNR");
00851             }
00852         }
00853         kmo_dfs_save_cube(cube_combined_data, fn_combine, "", 
00854                 data_header_list[0], 0./0.);
00855         cpl_imagelist_delete(cube_combined_data);
00856         kmo_dfs_save_cube(cube_combined_noise, fn_combine, "", 
00857                 noise_header_list[0], 0./0.);
00858         cpl_imagelist_delete(cube_combined_noise);
00859         cpl_free(fn_combine);
00860         
00861         cpl_propertylist_erase(data_header_list[0], CRPIX3);
00862         cpl_propertylist_erase(data_header_list[0], CRPIX3);
00863         cpl_propertylist_erase(data_header_list[0], CRVAL3);
00864         cpl_propertylist_erase(data_header_list[0], CDELT3);
00865         cpl_propertylist_erase(data_header_list[0], CD1_3);
00866         cpl_propertylist_erase(data_header_list[0], CD2_3);
00867         cpl_propertylist_erase(data_header_list[0], CD3_1);
00868         cpl_propertylist_erase(data_header_list[0], CD3_2);
00869         cpl_propertylist_erase(data_header_list[0], CD3_3);
00870         cpl_propertylist_erase(data_header_list[0], CTYPE3);
00871         kmo_dfs_save_image(exp_mask, fn_mask, "", data_header_list[0], 0./0.);
00872         cpl_free(fn_mask);
00873         cpl_image_delete(exp_mask);
00874 
00875         for (i = 0; i < data_cube_counter ; i++) 
00876             cpl_propertylist_delete(data_header_list[i]);
00877         for (i = 0; i < noise_cube_counter ; i++) 
00878             cpl_propertylist_delete(noise_header_list[i]);
00879         if (noise_header_list!=NULL && noise_cube_counter==0) 
00880             cpl_propertylist_delete(noise_header_list[0]) ;
00881     } 
00882     cpl_frameset_delete(rawframes) ;
00883     if (skipped_bivector!=NULL) cpl_bivector_delete(skipped_bivector) ;
00884     if (ifus != NULL) cpl_vector_delete(ifus);
00885     cpl_free(data_cube_list);
00886     cpl_free(noise_cube_list);
00887     cpl_free(data_header_list);
00888     cpl_free(noise_header_list);
00889     for (i = 0; i < name_vec_size ; i++) cpl_free(name_vec[i]);
00890     cpl_free(name_vec);
00891     cpl_free(mapping_mode) ;
00892 
00893     /* Collapse the combined cubes if requested */
00894     if (collapse_combined) {
00895         kmos_collapse_cubes(COMBINED_RECONS, frameset, parlist, 0.1, "",
00896                 DEF_REJ_METHOD, DEF_POS_REJ_THRES, DEF_NEG_REJ_THRES,
00897                 DEF_ITERATIONS, DEF_NR_MIN_REJ, DEF_NR_MAX_REJ) ;
00898     }
00899     return 0;
00900 }
00901 
00904 /*----------------------------------------------------------------------------*/
00910 /*----------------------------------------------------------------------------*/
00911 static char * kmos_combine_create_used_ifus_string(
00912         const int   *   used_frame_idx,
00913         const int   *   used_ifus,
00914         int             nb)
00915 {
00916     char        out[8192] ;
00917     char        tmp[7] ;
00918     int         i ;
00919 
00920     if (nb > 1000) return NULL ;
00921     for (i=0 ; i<nb ; i++) {
00922         /* Build the current string */
00923         if (used_frame_idx[i] < 10 && used_ifus[i] < 10) 
00924             if (i==0) sprintf(tmp, "%1d:%1d", used_frame_idx[i], used_ifus[i]);
00925             else sprintf(tmp, ",%1d:%1d", used_frame_idx[i], used_ifus[i]);
00926         else if (used_frame_idx[i] < 10 && used_ifus[i] >= 10) 
00927             if (i==0) sprintf(tmp, "%1d:%2d", used_frame_idx[i], used_ifus[i]);
00928             else sprintf(tmp, ",%1d:%2d", used_frame_idx[i], used_ifus[i]);
00929         else if (used_frame_idx[i] >= 10 && used_ifus[i] < 10) 
00930             if (i==0) sprintf(tmp, "%2d:%1d", used_frame_idx[i], used_ifus[i]);
00931             else sprintf(tmp, ",%2d:%1d", used_frame_idx[i], used_ifus[i]);
00932         else if (used_frame_idx[i] >= 10 && used_ifus[i] >= 10) 
00933             if (i==0) sprintf(tmp, "%2d:%2d", used_frame_idx[i], used_ifus[i]);
00934             else sprintf(tmp, ",%2d:%2d", used_frame_idx[i], used_ifus[i]);
00935         else return NULL ;
00936 
00937         if (i==0)   strcpy(out, tmp) ;
00938         else        strcat(out, tmp);
00939     }
00940 
00941     /* Warning : If larger than 51 char, it does not fit in the header card */
00942     if (strlen(out) > 51) return NULL ;
00943 
00944     return cpl_strdup(out) ;
00945 }
00946 
00947 /*----------------------------------------------------------------------------*/
00953 /*----------------------------------------------------------------------------*/
00954 static cpl_bivector * kmos_combine_parse_skipped(const char * str)
00955 {
00956     cpl_bivector    *   out ;
00957     cpl_vector      *   out_x ;
00958     cpl_vector      *   out_y ;
00959     char            *   my_str ;
00960     int                 nb_values ;
00961     char            *   s1 ;
00962     char            *   s2 ;
00963     int                 val1, val2, ret ;
00964     
00965     /* Check Entries */
00966     if (str == NULL) return NULL ;
00967 
00968     /* Initialise */
00969     nb_values = 0 ;
00970     my_str = cpl_strdup(str) ;
00971     
00972     /* Count the values */
00973     for (s2 = my_str; s2; ) {
00974         while (*s2 == ' ' || *s2 == '\t') s2++;
00975         s1 = strsep(&s2, ",") ;
00976         if (*s1) {
00977             if (sscanf(s1," %i:%i", &val1, &val2) == 2) {
00978                 nb_values ++ ;
00979             }
00980         }
00981     }
00982     cpl_free(my_str) ;
00983     if (nb_values == 0) return NULL ;
00984 
00985     /* Create the vector */
00986     out = cpl_bivector_new(nb_values) ;
00987     out_x = cpl_bivector_get_x(out) ;
00988     out_y = cpl_bivector_get_y(out) ;
00989     
00990     /* Fill the vector */
00991     nb_values = 0 ;
00992     my_str = cpl_strdup(str) ;
00993     for (s2 = my_str; s2; ) {
00994         while (*s2 == ' ' || *s2 == '\t') s2++;
00995         s1 = strsep(&s2, ",") ;
00996         if (*s1) {
00997             if (sscanf(s1," %i:%i", &val1, &val2) == 2) {
00998                 cpl_vector_set(out_x, nb_values, val1) ;
00999                 cpl_vector_set(out_y, nb_values, val2) ;
01000                 nb_values ++ ;
01001             }
01002         }
01003     }
01004     cpl_free(my_str) ;
01005     return out;
01006 }
01007 
01008 /*----------------------------------------------------------------------------*/
01016 /*----------------------------------------------------------------------------*/
01017 static int kmos_combine_is_skipped(
01018         const cpl_bivector  *   skipped, 
01019         int                     frame_idx,
01020         int                     ifu_nr) 
01021 {
01022     const cpl_vector    *   vec_x ;
01023     const cpl_vector    *   vec_y ;
01024     double                  val1, val2 ;
01025     int                     i ;
01026 
01027     /* Check entries */
01028     if (skipped == NULL) return 0;
01029 
01030     /* Initialise */
01031     vec_x = cpl_bivector_get_x_const(skipped) ;
01032     vec_y = cpl_bivector_get_y_const(skipped) ;
01033 
01034     /* Loop */
01035     for (i=0 ; i<cpl_bivector_get_size(skipped) ; i++) {
01036         val1 = cpl_vector_get(vec_x, i) ;
01037         val2 = cpl_vector_get(vec_y, i) ;
01038         if (fabs(val1-frame_idx)<1e-3 && fabs(val2-ifu_nr)<1e-3) return 1 ; 
01039     }
01040     return 0 ;
01041 }
01042