KMOS Pipeline Reference Manual  1.3.16
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     char            * tmp_str, * fn_combine, * fn_mask, * mapping_mode,
00337                     * name, ** name_vec ;
00338     const char      * frame_filename, * tmp_strc ;
00339     cpl_image       * exp_mask ;
00340     cpl_imagelist   ** data_cube_list, ** noise_cube_list, * cube_combined_data,
00341                     * cube_combined_noise ;
00342     cpl_propertylist    * main_header, **data_header_list, **noise_header_list,
00343                         * tmp_header, * pro_plist ;
00344     cpl_bivector    *   skipped_bivector ;
00345     cpl_frame       *   frame ;
00346     cpl_size            ci ;
00347     main_fits_desc      desc;
00348     int             *   used_frame_idx ;
00349     int             *   used_ifus ;
00350     char            *   used_ifus_str ;
00351     enum extrapolationType  extrapol_enum = NONE_CLIPPING;
00352     int             i, j ;
00353 
00354     /* Check entries */
00355     if (parlist == NULL || frameset == NULL) {
00356         cpl_msg_error(__func__, "Null Inputs") ;
00357         cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
00358         return -1 ;
00359     }
00360 
00361     /* Get parameters */
00362     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.method");
00363     method = cpl_parameter_get_string(par) ;
00364     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.fmethod");
00365     fmethod = cpl_parameter_get_string(par) ;
00366     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.filename");
00367     filename = cpl_parameter_get_string(par) ;
00368     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.ifus");
00369     ifus_txt = cpl_parameter_get_string(par) ;
00370     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.name");
00371     name = (char*)cpl_parameter_get_string(par) ;
00372     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.flux");
00373     flux = cpl_parameter_get_bool(par) ;
00374     par = cpl_parameterlist_find_const(parlist, 
00375             "kmos.kmos_combine.skipped_frames");
00376     skipped_frames = cpl_parameter_get_string(par) ;
00377     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_combine.edge_nan");
00378     edge_nan = cpl_parameter_get_bool(par) ;
00379     par = cpl_parameterlist_find_const(parlist,
00380             "kmos.kmos_combine.suppress_extension");
00381     suppress_extension = cpl_parameter_get_bool(par) ;
00382     kmos_combine_pars_load(parlist, "kmos.kmos_combine", &cmethod, &cpos_rej, 
00383             &cneg_rej, &citer, &cmin, &cmax, FALSE);
00384     par = cpl_parameterlist_find_const(parlist,
00385             "kmos.kmos_combine.collapse_combined");
00386     collapse_combined = cpl_parameter_get_bool(par);
00387 
00388     /* Check Parameters */
00389     if (strcmp(method, "none") && strcmp(method, "header") &&
00390             strcmp(method, "center") && strcmp(method, "user")) {
00391         cpl_msg_error(__func__,
00392             "shift methods must be 'none', 'header', 'center' or 'user'") ;
00393         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00394         return -1 ;
00395     }
00396     if (strcmp(ifus_txt, "") && strcmp(name, "")) {
00397         cpl_msg_error(__func__,
00398                 "name and IFU indices cannot be both provided") ;
00399         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00400         return -1 ;
00401     }
00402     if (!strcmp(method, "user") && !strcmp(filename, "")) {
00403         cpl_msg_error(__func__,
00404                 "path of file with shift information must be provided") ;
00405         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00406         return -1 ;
00407     }
00408 
00409     /* Identify the RAW and CALIB frames in the input frameset */
00410     if (kmo_dfs_set_groups(frameset, "kmos_combine") != 1) {
00411         cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
00412         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00413         return -1 ;
00414     }
00415 
00416     /* Parse the skipped frames option */
00417     skipped_bivector = NULL ;
00418     if (strcmp(skipped_frames, "")) {
00419         skipped_bivector = kmos_combine_parse_skipped(skipped_frames) ;
00420         if (skipped_bivector != NULL) 
00421             cpl_msg_info(__func__, "Skip the following frames: %s", 
00422                     skipped_frames);
00423     } 
00424 
00425     /* Get the frames to combine - Filter out OH_SPEC */
00426     rawframes = cpl_frameset_duplicate(frameset) ;
00427     cpl_frameset_erase(rawframes, "OH_SPEC") ;
00428 
00429     /* Check Nb of frames */
00430     nr_frames = cpl_frameset_get_size(rawframes);
00431     if (nr_frames < 2) {
00432         if (skipped_bivector!=NULL) cpl_bivector_delete(skipped_bivector) ;
00433         cpl_frameset_delete(rawframes) ;
00434         cpl_msg_error(__func__, "At least two frames must be provided") ;
00435         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00436         return -1 ;
00437     }
00438 
00439     /* Load IFUS if specified */
00440     if (strcmp(ifus_txt, "")) {
00441         ifus = kmo_identify_values(ifus_txt);
00442         if (ifus == NULL || cpl_vector_get_size(ifus) != nr_frames) {
00443             if (ifus != NULL) cpl_vector_delete(ifus);
00444             if (skipped_bivector!=NULL) cpl_bivector_delete(skipped_bivector) ;
00445             cpl_frameset_delete(rawframes) ;
00446             cpl_msg_error(__func__, "ifus size must match the science frames") ;
00447             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00448             return -1 ;
00449         }
00450     } else {
00451         ifus = NULL ;
00452     }
00453 
00454     /* Check for mapping mode */
00455     mapping_mode = NULL ;
00456     cpl_size fs_size = cpl_frameset_get_size(rawframes);
00457     for (ci = 0; ci < fs_size; ci++) {
00458         frame = cpl_frameset_get_position(rawframes, ci);
00459         tmp_header = kmclipm_propertylist_load(cpl_frame_get_filename(frame),0);
00460         if (cpl_propertylist_has(tmp_header, TPL_ID)) {
00461             tmp_strc = cpl_propertylist_get_string(tmp_header, TPL_ID);
00462             if (mapping_mode == NULL) {
00463                 if (!strcmp(tmp_strc, MAPPING8)) 
00464                     mapping_mode = cpl_sprintf("%s", tmp_strc);
00465                 if (!strcmp(tmp_strc, MAPPING24)) 
00466                     mapping_mode = cpl_sprintf("%s", tmp_strc);
00467             } else {
00468                 if (strcmp(tmp_strc, mapping_mode)) {
00469                     cpl_msg_warning(__func__,
00470                             "There are different TPL IDs in input: %s and %s",
00471                             tmp_strc, mapping_mode);
00472                 }
00473             }
00474         }
00475         cpl_propertylist_delete(tmp_header);
00476     }
00477 
00478     if (mapping_mode != NULL) {
00479         if (!strcmp(ifus_txt, "") && !strcmp(name, "")) {
00480             cpl_msg_info(__func__,"*****************************************");
00481             cpl_msg_info(__func__,"* A map with all IFUs will be generated *");
00482             cpl_msg_info(__func__,"*****************************************");
00483             extrapol_enum = BCS_NATURAL;
00484         } else {
00485             cpl_msg_info(__func__, "No Map as name / ifu is specified");
00486             cpl_free(mapping_mode);
00487             mapping_mode = NULL ;
00488         }
00489     }
00490 
00491     /* Create name/ifu map... */
00492     name_vec = cpl_calloc(nr_frames*KMOS_NR_IFUS, sizeof(char*));
00493 
00494     /* No name / IFU specified - Non mapping mode */
00495     if (!strcmp(ifus_txt, "") && !strcmp(name, "") && mapping_mode==NULL) {
00496         /* All available names should be combined in one go */
00497         name_vec_size = 0;
00498         for (i = 0; i < nr_frames; i++) {
00499             tmp_str = cpl_sprintf("%d", i);
00500             frame = kmo_dfs_get_frame(rawframes, tmp_str);
00501             cpl_free(tmp_str);
00502             for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
00503                 found = 0;
00504                 tmp_str = kmo_get_name_from_ocs_ifu(frame, ifu_nr);
00505                 if (tmp_str != NULL) {
00506                     for (j = 0; j < name_vec_size; j++) {
00507                         if (!strcmp(name_vec[j], tmp_str)) {
00508                             found = TRUE;
00509                             break;
00510                         }
00511                     }
00512                     if (!found)     name_vec[name_vec_size++] = tmp_str;
00513                     else            cpl_free(tmp_str);
00514                 }
00515             }
00516         }
00517     } else {
00518         /* Standard behavior: either ifu_nr- or name- or mapping-case */
00519         name_vec_size = 1;
00520         if (mapping_mode != NULL) {
00521             name_vec[0] = cpl_sprintf("mapping");
00522         } else {
00523             if (ifus != NULL) {
00524                 char *tmptmp = NULL;
00525 
00526                 // replace all ; with _
00527                 char *found_char = NULL;
00528                 found_char = strstr(ifus_txt, ";");
00529                 while (found_char != NULL) {
00530                     strncpy(found_char, "_", 1);
00531                     found_char = strstr(ifus_txt, ";");
00532                 }
00533 
00534                 if (strlen(ifus_txt) > 10) {
00535                     tmptmp = kmo_shorten_ifu_string(ifus_txt);
00536                     cpl_msg_info(__func__, "Truncate to ..ifu%s..", tmptmp);
00537                 } else {
00538                     tmptmp = cpl_sprintf("%s", ifus_txt);
00539                 }
00540                 name_vec[0] = cpl_sprintf("IFU%s", tmptmp);
00541                 ifus_txt = "";
00542                 cpl_free(tmptmp); 
00543             } else {
00544                 name_vec[0] = cpl_sprintf("%s", name);
00545             }
00546         }
00547     }
00548    
00549     /* Load data and noise */
00550     data_cube_list = cpl_calloc(nr_frames*KMOS_NR_IFUS, 
00551             sizeof(cpl_imagelist*));
00552     data_header_list = cpl_calloc(nr_frames*KMOS_NR_IFUS, 
00553             sizeof(cpl_propertylist*));
00554     noise_cube_list = cpl_calloc(nr_frames*KMOS_NR_IFUS,
00555             sizeof(cpl_imagelist*));
00556     noise_header_list = cpl_calloc(nr_frames*KMOS_NR_IFUS,
00557             sizeof(cpl_propertylist*));
00558  
00559     /*
00560     if (ifus != NULL) cpl_vector_delete(ifus);
00561     cpl_frameset_delete(rawframes) ;
00562     cpl_free(data_cube_list);
00563     cpl_free(noise_cube_list);
00564     cpl_free(data_header_list);
00565     cpl_free(noise_header_list);
00566     for (i = 0; i < name_vec_size ; i++) cpl_free(name_vec[i]);
00567     cpl_free(name_vec);
00568     if (mapping_mode != NULL) cpl_free(mapping_mode) ;
00569     return 0 ;
00570     */
00571 
00572     /* Load all data (and noise if existent) cubes and store them */
00573     for (nv = 0; nv < name_vec_size; nv++) {
00574         name = name_vec[nv];
00575 
00576         used_frame_idx = cpl_calloc(nr_frames*KMOS_NR_IFUS, sizeof(int)) ;
00577         used_ifus = cpl_calloc(nr_frames*KMOS_NR_IFUS, sizeof(int)) ;
00578         
00579         data_cube_counter = 0;
00580         noise_cube_counter = 0;
00581         for (i = 0; i < nr_frames; i++) {
00582             tmp_str = cpl_sprintf("%d", i);
00583             frame = kmo_dfs_get_frame(rawframes, tmp_str);
00584             frame_filename = cpl_frame_get_filename(frame);
00585             kmo_init_fits_desc(&desc);
00586             desc = kmo_identify_fits_header(frame_filename);
00587 
00588             if (mapping_mode != NULL) {
00589                 /* Mapping mode */
00590                 for (j = 1; j <= KMOS_NR_IFUS; j++) {
00591                     /* Loop over all IFUs */
00592                     if (desc.sub_desc[j-1].valid_data == TRUE &&
00593                             !kmos_combine_is_skipped(skipped_bivector,i+1,j)) {
00594                         /* Load data frames */
00595                         override_err_msg = TRUE;
00596                         data_cube_list[data_cube_counter] =
00597                             kmo_dfs_load_cube(rawframes, tmp_str, j,FALSE);
00598                         override_err_msg = FALSE;
00599                         if (data_cube_list[data_cube_counter] == NULL) {
00600                             cpl_error_reset();
00601                         } else {
00602                             if (edge_nan) kmo_edge_nan(
00603                                     data_cube_list[data_cube_counter], j);
00604                             data_header_list[data_cube_counter] =
00605                                 kmo_dfs_load_sub_header(rawframes, 
00606                                         tmp_str, j, FALSE);
00607                             cpl_propertylist_update_string(
00608                                     data_header_list[data_cube_counter],
00609                                     "ESO PRO FRNAME", frame_filename);
00610                             cpl_propertylist_update_int(
00611                                     data_header_list[data_cube_counter],
00612                                     "ESO PRO IFUNR", j);
00613                             used_frame_idx[data_cube_counter] = i+1 ;
00614                             used_ifus[data_cube_counter] = j ;
00615                             data_cube_counter++;
00616                         }
00617 
00618                         /* Load noise frames */
00619                         override_err_msg = TRUE;
00620                         noise_cube_list[noise_cube_counter] =
00621                             kmo_dfs_load_cube(rawframes, tmp_str, j, TRUE);
00622 
00623                         override_err_msg = FALSE;
00624                         if (noise_cube_list[noise_cube_counter] == NULL) {
00625                             // no noise found for this IFU
00626                             cpl_error_reset();
00627                         } else {
00628                             if (edge_nan) kmo_edge_nan(
00629                                     noise_cube_list[noise_cube_counter], j);
00630                             noise_header_list[noise_cube_counter] =
00631                                 kmo_dfs_load_sub_header(rawframes, tmp_str,
00632                                         j, TRUE);
00633                             noise_cube_counter++;
00634                         }
00635 
00636                         /* Check if number of data and noise frames match */
00637                         if (noise_cube_counter > 0) {
00638                             if (data_cube_counter != noise_cube_counter) {
00639                                 cpl_msg_error(__func__, "Noise missing") ;
00640                                 cpl_error_set(__func__,CPL_ERROR_ILLEGAL_INPUT);
00641                                 /* TODO - deallocate */
00642                                 return -1 ;
00643                             }
00644                         }
00645                     } 
00646                 }
00647             } else {
00648                 /* name/ifu mode (single) */
00649                 if (ifus != NULL)   ifu_nr = cpl_vector_get(ifus, i);
00650                 else        ifu_nr = kmo_get_index_from_ocs_name(frame, name);
00651                 if (ifu_nr > 0) {
00652                     index = kmo_identify_index(frame_filename, ifu_nr , FALSE);
00653                     if (desc.sub_desc[index-1].valid_data == TRUE &&
00654                             !kmos_combine_is_skipped(skipped_bivector,i+1,
00655                                 ifu_nr)) {
00656                         /* Load data frames */
00657                         override_err_msg = TRUE;
00658                         data_cube_list[data_cube_counter] =
00659                             kmo_dfs_load_cube(rawframes, tmp_str, ifu_nr, 
00660                                     FALSE);
00661                         override_err_msg = FALSE;
00662                         if (data_cube_list[data_cube_counter] == NULL) {
00663                             /* No data found for this IFU */
00664                             cpl_error_reset();
00665                             if (ifus != NULL)   cpl_msg_warning(cpl_func, 
00666                                     "IFU %d miѕsing in frame %s",
00667                                     ifu_nr, frame_filename);
00668                             else                cpl_msg_warning(cpl_func, 
00669                                     "Object %s missing in Frame %d (%s)",
00670                                     name,  i+1, frame_filename) ;
00671                         } else {
00672                             if (edge_nan) kmo_edge_nan(
00673                                     data_cube_list[data_cube_counter], ifu_nr);
00674                             data_header_list[data_cube_counter] =
00675                                 kmo_dfs_load_sub_header(rawframes, tmp_str,
00676                                         ifu_nr, FALSE);
00677                             cpl_propertylist_update_string(
00678                                     data_header_list[data_cube_counter],
00679                                     "ESO PRO FRNAME", frame_filename);
00680                             cpl_propertylist_update_int(
00681                                     data_header_list[data_cube_counter],
00682                                     "ESO PRO IFUNR", ifu_nr);
00683                             used_frame_idx[data_cube_counter] = i+1 ;
00684                             used_ifus[data_cube_counter] = ifu_nr ;
00685                             data_cube_counter++;
00686                         }
00687 
00688                         /* Load noise frames */
00689                         override_err_msg = TRUE;
00690                         noise_cube_list[noise_cube_counter] =
00691                             kmo_dfs_load_cube(rawframes, tmp_str, ifu_nr, 
00692                                     TRUE);
00693                         override_err_msg = FALSE;
00694                         if (noise_cube_list[noise_cube_counter] == NULL) {
00695                             /* No noise found for this IFU */
00696                             cpl_error_reset();
00697                         } else {
00698                             if (edge_nan) kmo_edge_nan(
00699                                     noise_cube_list[noise_cube_counter],ifu_nr);
00700                             noise_header_list[noise_cube_counter] =
00701                                     kmo_dfs_load_sub_header(rawframes, 
00702                                             tmp_str, ifu_nr, TRUE);
00703                             noise_cube_counter++;
00704                         }
00705 
00706                         /* Check if number of data and noise frames match */
00707                         if (noise_cube_counter > 0) {
00708                             if (data_cube_counter != noise_cube_counter) {
00709                                 /* TODO - deallocate */
00710                                 cpl_msg_error(__func__, "Noise missing") ;
00711                                 cpl_error_set(__func__,CPL_ERROR_ILLEGAL_INPUT);
00712                                 return -1 ;
00713                             }
00714                         }
00715                     } 
00716                 } 
00717             }
00718             kmo_free_fits_desc(&desc);
00719             cpl_free(tmp_str);
00720         } 
00721  
00722         /* Create String for the output header - IFUs usage */
00723         used_ifus_str = kmos_combine_create_used_ifus_string(used_frame_idx, 
00724                 used_ifus, data_cube_counter);
00725         cpl_free(used_frame_idx) ;
00726         cpl_free(used_ifus) ;
00727 
00728         /* Combine data */
00729         exp_mask = NULL ;
00730         cube_combined_noise = NULL ;
00731         cube_combined_data = NULL ;
00732         if (kmo_priv_combine(data_cube_list, noise_cube_list, data_header_list,
00733                     noise_header_list, data_cube_counter, noise_cube_counter, 
00734                     name, ifus_txt, method, "BCS", fmethod, filename, cmethod, 
00735                     cpos_rej, cneg_rej, citer, cmin, cmax, extrapol_enum, flux,
00736                     &cube_combined_data, &cube_combined_noise, 
00737                     &exp_mask) != CPL_ERROR_NONE) {
00738             for (i = 0; i < data_cube_counter ; i++) 
00739                 cpl_imagelist_delete(data_cube_list[i]);
00740             for (i = 0; i < noise_cube_counter ; i++) 
00741                 cpl_imagelist_delete(noise_cube_list[i]);
00742             for (i = 0; i < data_cube_counter ; i++) 
00743                 cpl_propertylist_delete(data_header_list[i]);
00744             for (i = 0; i < noise_cube_counter ; i++) 
00745                 cpl_propertylist_delete(noise_header_list[i]);
00746             if (ifus != NULL) cpl_vector_delete(ifus);
00747             cpl_free(data_cube_list);
00748             cpl_free(noise_cube_list);
00749             cpl_free(data_header_list);
00750             cpl_free(noise_header_list);
00751             for (i = 0; i < name_vec_size ; i++) cpl_free(name_vec[i]);
00752             cpl_free(name_vec);
00753             cpl_free(used_ifus_str) ;
00754             cpl_frameset_delete(rawframes) ;
00755             if (mapping_mode != NULL) cpl_free(mapping_mode) ;
00756             cpl_msg_error(__func__, "Failed Combination") ;
00757             cpl_error_set(__func__,CPL_ERROR_ILLEGAL_INPUT);
00758             return -1 ;
00759         }
00760         for (i = 0; i < data_cube_counter ; i++) 
00761             cpl_imagelist_delete(data_cube_list[i]);
00762         for (i = 0; i < noise_cube_counter ; i++) 
00763             cpl_imagelist_delete(noise_cube_list[i]);
00764         
00765         /*
00766         for (i = 0; i < data_cube_counter ; i++) 
00767             cpl_propertylist_delete(data_header_list[i]);
00768         for (i = 0; i < noise_cube_counter ; i++) 
00769             cpl_propertylist_delete(noise_header_list[i]);
00770         if (ifus != NULL) cpl_vector_delete(ifus);
00771         cpl_free(data_cube_list);
00772         cpl_free(noise_cube_list);
00773         cpl_free(data_header_list);
00774         cpl_free(noise_header_list);
00775         for (i = 0; i < name_vec_size ; i++) cpl_free(name_vec[i]);
00776         cpl_free(name_vec);
00777         if (mapping_mode != NULL) cpl_free(mapping_mode) ;
00778         cpl_image_delete(exp_mask);
00779         cpl_imagelist_delete(cube_combined_noise);
00780         cpl_imagelist_delete(cube_combined_data);
00781         if (noise_header_list!=NULL && noise_cube_counter==0) 
00782             cpl_propertylist_delete(noise_header_list[0]) ;
00783         cpl_frameset_delete(rawframes) ;
00784         */
00785         /* Save data */
00786         if (!suppress_extension) {
00787             /* Setup output category COMBINE + ESO PRO CATG */
00788             main_header = kmo_dfs_load_primary_header(rawframes, "0");
00789             fn_combine = cpl_sprintf("%s_%s_%s", COMBINE,
00790                     cpl_propertylist_get_string(main_header, CPL_DFS_PRO_CATG),
00791                     name_vec[nv]);
00792             fn_mask = cpl_sprintf("%s_%s_%s", EXP_MASK,
00793                     cpl_propertylist_get_string(main_header, CPL_DFS_PRO_CATG),
00794                     name_vec[nv]);
00795             cpl_propertylist_delete(main_header);
00796         } else {
00797             fn_combine = cpl_sprintf("%s_%d", COMBINE, suppress_index);
00798             fn_mask = cpl_sprintf("%s_%d", EXP_MASK, suppress_index++);
00799         }
00800 
00801         /* Create PRO keys plist */
00802         pro_plist = cpl_propertylist_new() ;
00803         cpl_propertylist_update_string(pro_plist, "ESO PRO USEDIFUS", 
00804                 used_ifus_str) ;
00805         cpl_propertylist_update_string(pro_plist, "ESO PRO SKIPPEDIFUS", 
00806                 skipped_frames) ;
00807 
00808         /* Save Headers first */
00809         frame = cpl_frameset_find(rawframes, NULL);
00810         kmo_dfs_save_main_header(frameset, fn_combine, "", frame, pro_plist, 
00811                 parlist, cpl_func);
00812         kmo_dfs_save_main_header(frameset, fn_mask, "", frame, pro_plist, 
00813                 parlist, cpl_func);
00814         cpl_propertylist_delete(pro_plist) ;
00815         cpl_free(used_ifus_str) ;
00816 
00817         /* Clean */
00818         if (data_header_list[0] != NULL) {
00819             if (cpl_propertylist_has(data_header_list[0], "ESO PRO FRNAME")) {
00820                 cpl_propertylist_erase(data_header_list[0], "ESO PRO FRNAME");
00821             }
00822             if (cpl_propertylist_has(data_header_list[0], "ESO PRO IFUNR")) {
00823                 cpl_propertylist_erase(data_header_list[0], "ESO PRO IFUNR");
00824             }
00825         }
00826         if (noise_header_list[0] != NULL) {
00827             if (cpl_propertylist_has(noise_header_list[0], "ESO PRO FRNAME")) {
00828                 cpl_propertylist_erase(noise_header_list[0], "ESO PRO FRNAME");
00829             }
00830             if (cpl_propertylist_has(noise_header_list[0], "ESO PRO IFUNR")) {
00831                 cpl_propertylist_erase(noise_header_list[0], "ESO PRO IFUNR");
00832             }
00833         }
00834         kmo_dfs_save_cube(cube_combined_data, fn_combine, "", 
00835                 data_header_list[0], 0./0.);
00836         cpl_imagelist_delete(cube_combined_data);
00837         kmo_dfs_save_cube(cube_combined_noise, fn_combine, "", 
00838                 noise_header_list[0], 0./0.);
00839         cpl_imagelist_delete(cube_combined_noise);
00840         cpl_free(fn_combine);
00841         
00842         cpl_propertylist_erase(data_header_list[0], CRPIX3);
00843         cpl_propertylist_erase(data_header_list[0], CRPIX3);
00844         cpl_propertylist_erase(data_header_list[0], CRVAL3);
00845         cpl_propertylist_erase(data_header_list[0], CDELT3);
00846         cpl_propertylist_erase(data_header_list[0], CD1_3);
00847         cpl_propertylist_erase(data_header_list[0], CD2_3);
00848         cpl_propertylist_erase(data_header_list[0], CD3_1);
00849         cpl_propertylist_erase(data_header_list[0], CD3_2);
00850         cpl_propertylist_erase(data_header_list[0], CD3_3);
00851         cpl_propertylist_erase(data_header_list[0], CTYPE3);
00852         kmo_dfs_save_image(exp_mask, fn_mask, "", data_header_list[0], 0./0.);
00853         cpl_free(fn_mask);
00854         cpl_image_delete(exp_mask);
00855 
00856         for (i = 0; i < data_cube_counter ; i++) 
00857             cpl_propertylist_delete(data_header_list[i]);
00858         for (i = 0; i < noise_cube_counter ; i++) 
00859             cpl_propertylist_delete(noise_header_list[i]);
00860         if (noise_header_list!=NULL && noise_cube_counter==0) 
00861             cpl_propertylist_delete(noise_header_list[0]) ;
00862     } 
00863     cpl_frameset_delete(rawframes) ;
00864     if (skipped_bivector!=NULL) cpl_bivector_delete(skipped_bivector) ;
00865     if (ifus != NULL) cpl_vector_delete(ifus);
00866     cpl_free(data_cube_list);
00867     cpl_free(noise_cube_list);
00868     cpl_free(data_header_list);
00869     cpl_free(noise_header_list);
00870     for (i = 0; i < name_vec_size ; i++) cpl_free(name_vec[i]);
00871     cpl_free(name_vec);
00872     cpl_free(mapping_mode) ;
00873 
00874     /* Collapse the combined cubes if requested */
00875     if (collapse_combined) {
00876         kmos_collapse_cubes(COMBINED_RECONS, frameset, parlist, 0.1, "",
00877                 DEF_REJ_METHOD, DEF_POS_REJ_THRES, DEF_NEG_REJ_THRES,
00878                 DEF_ITERATIONS, DEF_NR_MIN_REJ, DEF_NR_MAX_REJ) ;
00879     }
00880     return 0;
00881 }
00882 
00885 /*----------------------------------------------------------------------------*/
00891 /*----------------------------------------------------------------------------*/
00892 static char * kmos_combine_create_used_ifus_string(
00893         const int   *   used_frame_idx,
00894         const int   *   used_ifus,
00895         int             nb)
00896 {
00897     char        out[8192] ;
00898     char        tmp[7] ;
00899     int         i ;
00900 
00901     if (nb > 1000) return NULL ;
00902     for (i=0 ; i<nb ; i++) {
00903         /* Build the current string */
00904         if (used_frame_idx[i] < 10 && used_ifus[i] < 10) 
00905             if (i==0) sprintf(tmp, "%1d:%1d", used_frame_idx[i], used_ifus[i]);
00906             else sprintf(tmp, ",%1d:%1d", used_frame_idx[i], used_ifus[i]);
00907         else if (used_frame_idx[i] < 10 && used_ifus[i] >= 10) 
00908             if (i==0) sprintf(tmp, "%1d:%2d", used_frame_idx[i], used_ifus[i]);
00909             else sprintf(tmp, ",%1d:%2d", used_frame_idx[i], used_ifus[i]);
00910         else if (used_frame_idx[i] >= 10 && used_ifus[i] < 10) 
00911             if (i==0) sprintf(tmp, "%2d:%1d", used_frame_idx[i], used_ifus[i]);
00912             else sprintf(tmp, ",%2d:%1d", used_frame_idx[i], used_ifus[i]);
00913         else if (used_frame_idx[i] >= 10 && used_ifus[i] >= 10) 
00914             if (i==0) sprintf(tmp, "%2d:%2d", used_frame_idx[i], used_ifus[i]);
00915             else sprintf(tmp, ",%2d:%2d", used_frame_idx[i], used_ifus[i]);
00916         else return NULL ;
00917 
00918         if (i==0)   strcpy(out, tmp) ;
00919         else        strcat(out, tmp);
00920     }
00921 
00922     /* Warning : If larger than 51 char, it does not fit in the header card */
00923     if (strlen(out) > 51) return NULL ;
00924 
00925     return cpl_strdup(out) ;
00926 }
00927 
00928 /*----------------------------------------------------------------------------*/
00934 /*----------------------------------------------------------------------------*/
00935 static cpl_bivector * kmos_combine_parse_skipped(const char * str)
00936 {
00937     cpl_bivector    *   out ;
00938     cpl_vector      *   out_x ;
00939     cpl_vector      *   out_y ;
00940     char            *   my_str ;
00941     int                 nb_values ;
00942     char            *   s1 ;
00943     char            *   s2 ;
00944     int                 val1, val2, ret ;
00945     
00946     /* Check Entries */
00947     if (str == NULL) return NULL ;
00948 
00949     /* Initialise */
00950     nb_values = 0 ;
00951     my_str = cpl_strdup(str) ;
00952     
00953     /* Count the values */
00954     for (s2 = my_str; s2; ) {
00955         while (*s2 == ' ' || *s2 == '\t') s2++;
00956         s1 = strsep(&s2, ",") ;
00957         if (*s1) {
00958             if (sscanf(s1," %i:%i", &val1, &val2) == 2) {
00959                 nb_values ++ ;
00960             }
00961         }
00962     }
00963     cpl_free(my_str) ;
00964     if (nb_values == 0) return NULL ;
00965 
00966     /* Create the vector */
00967     out = cpl_bivector_new(nb_values) ;
00968     out_x = cpl_bivector_get_x(out) ;
00969     out_y = cpl_bivector_get_y(out) ;
00970     
00971     /* Fill the vector */
00972     nb_values = 0 ;
00973     my_str = cpl_strdup(str) ;
00974     for (s2 = my_str; s2; ) {
00975         while (*s2 == ' ' || *s2 == '\t') s2++;
00976         s1 = strsep(&s2, ",") ;
00977         if (*s1) {
00978             if (sscanf(s1," %i:%i", &val1, &val2) == 2) {
00979                 cpl_vector_set(out_x, nb_values, val1) ;
00980                 cpl_vector_set(out_y, nb_values, val2) ;
00981                 nb_values ++ ;
00982             }
00983         }
00984     }
00985     cpl_free(my_str) ;
00986     return out;
00987 }
00988 
00989 /*----------------------------------------------------------------------------*/
00997 /*----------------------------------------------------------------------------*/
00998 static int kmos_combine_is_skipped(
00999         const cpl_bivector  *   skipped, 
01000         int                     frame_idx,
01001         int                     ifu_nr) 
01002 {
01003     const cpl_vector    *   vec_x ;
01004     const cpl_vector    *   vec_y ;
01005     double                  val1, val2 ;
01006     int                     i ;
01007 
01008     /* Check entries */
01009     if (skipped == NULL) return 0;
01010 
01011     /* Initialise */
01012     vec_x = cpl_bivector_get_x_const(skipped) ;
01013     vec_y = cpl_bivector_get_y_const(skipped) ;
01014 
01015     /* Loop */
01016     for (i=0 ; i<cpl_bivector_get_size(skipped) ; i++) {
01017         val1 = cpl_vector_get(vec_x, i) ;
01018         val2 = cpl_vector_get(vec_y, i) ;
01019         if (fabs(val1-frame_idx)<1e-3 && fabs(val2-ifu_nr)<1e-3) return 1 ; 
01020     }
01021     return 0 ;
01022 }
01023