KMOS Pipeline Reference Manual  1.3.11
kmos_extract_spec.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 
00033 #include "kmo_utils.h"
00034 #include "kmo_dfs.h"
00035 #include "kmo_error.h"
00036 #include "kmo_priv_extract_spec.h"
00037 #include "kmo_priv_functions.h"
00038 #include "kmo_cpl_extensions.h"
00039 #include "kmo_constants.h"
00040 #include "kmo_priv_fit_profile.h"
00041 #include "kmo_debug.h"
00042 
00043 /*-----------------------------------------------------------------------------
00044  *                          Functions prototypes
00045  *----------------------------------------------------------------------------*/
00046 
00047 static int kmos_extract_spec_create(cpl_plugin *);
00048 static int kmos_extract_spec_exec(cpl_plugin *);
00049 static int kmos_extract_spec_destroy(cpl_plugin *);
00050 static int kmos_extract_spec(cpl_parameterlist *, cpl_frameset *);
00051 
00052 /*-----------------------------------------------------------------------------
00053  *                          Static variables
00054  *----------------------------------------------------------------------------*/
00055 
00056 static char kmos_extract_spec_description[] =
00057 "This recipe extracts a spectrum from a datacube. The datacube is with or \n"
00058 "without noise). The output will be a similarly formatted FITS file.\n"
00059 "\n"
00060 "---------------------------------------------------------------------------\n"
00061 "  Input files:\n"
00062 "\n"
00063 "   DO                    KMOS                                              \n"
00064 "   category              Type   Explanation                Required #Frames\n"
00065 "   --------              -----  -----------                -------- -------\n"
00066 "   <none or any>         F3I    The datacubes                 Y        1   \n"
00067 "   <none or any>         F2I    The mask                      N       0,1  \n"
00068 "\n"
00069 "  Output files:\n"
00070 "\n"
00071 "   DO                    KMOS\n"
00072 "   category              Type   Explanation\n"
00073 "   --------              -----  -----------\n"
00074 "   EXTRACT_SPEC          F1I    Extracted spectrum                         \n"
00075 "   EXTRACT_SPEC_MASK     F2I    (optional, if --save_mask=true and         \n"
00076 "                            --mask_method='optimal': The calculated mask)  \n"
00077 "---------------------------------------------------------------------------\n"
00078 "\n";
00079 
00080 /*-----------------------------------------------------------------------------
00081  *                              Functions code
00082  *----------------------------------------------------------------------------*/
00083 
00084 /*----------------------------------------------------------------------------*/
00088 /*----------------------------------------------------------------------------*/
00089 
00092 /*----------------------------------------------------------------------------*/
00101 /*----------------------------------------------------------------------------*/
00102 int cpl_plugin_get_info(cpl_pluginlist *list)
00103 {
00104     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00105     cpl_plugin *plugin = &recipe->interface;
00106 
00107     cpl_plugin_init(plugin,
00108             CPL_PLUGIN_API,
00109             KMOS_BINARY_VERSION,
00110             CPL_PLUGIN_TYPE_RECIPE,
00111             "kmos_extract_spec",
00112             "Extract a spectrum from a cube",
00113             kmos_extract_spec_description,
00114             "Alex Agudo Berbel, Y. Jung",
00115             "usd-help@eso.org",
00116             kmos_get_license(),
00117             kmos_extract_spec_create,
00118             kmos_extract_spec_exec,
00119             kmos_extract_spec_destroy);
00120 
00121     cpl_pluginlist_append(list, plugin);
00122     return 0;
00123 }
00124 
00125 /*----------------------------------------------------------------------------*/
00133 /*----------------------------------------------------------------------------*/
00134 static int kmos_extract_spec_create(cpl_plugin *plugin)
00135 {
00136     cpl_recipe *recipe;
00137     cpl_parameter *p;
00138 
00139     /* Check that the plugin is part of a valid recipe */
00140     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00141         recipe = (cpl_recipe *)plugin;
00142     else
00143         return -1;
00144 
00145     /* Create the parameters list in the cpl_recipe object */
00146     recipe->parameters = cpl_parameterlist_new();
00147 
00148     /* Fill the parameters list */
00149     /* --mask_method */
00150     p = cpl_parameter_new_value("kmos.kmos_extract_spec.mask_method",
00151             CPL_TYPE_STRING, "Method used : mask, integrated or optimal",
00152             "kmos.kmos_extract_spec", "integrated");
00153     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "mask_method");
00154     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00155     cpl_parameterlist_append(recipe->parameters, p);
00156 
00157     /* --centre */
00158     p = cpl_parameter_new_value("kmos.kmos_extract_spec.centre",
00159             CPL_TYPE_STRING, "The centre of the circular mask (pixel)",
00160             "kmos.kmos_extract_spec", "7.5,7.5");
00161     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "centre");
00162     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00163     cpl_parameterlist_append(recipe->parameters, p);
00164 
00165     /* --radius */
00166     p = cpl_parameter_new_value("kmos.kmos_extract_spec.radius",
00167             CPL_TYPE_DOUBLE, "The radius of the circular mask (pixel)",
00168             "kmos.kmos_extract_spec", 3.0);
00169     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "radius");
00170     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00171     cpl_parameterlist_append(recipe->parameters, p);
00172 
00173     /* --save_mask */
00174     p = cpl_parameter_new_value("kmos.kmos_extract_spec.save_mask",
00175             CPL_TYPE_BOOL, "Flag to save the mask", "kmos.kmos_extract_spec",
00176             FALSE);
00177     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "save_mask");
00178     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00179     cpl_parameterlist_append(recipe->parameters, p);
00180 
00181     return kmos_combine_pars_create(recipe->parameters,
00182             "kmos.kmos_extract_spec", DEF_REJ_METHOD, FALSE);
00183 }
00184 
00185 /*----------------------------------------------------------------------------*/
00191 /*----------------------------------------------------------------------------*/
00192 static int kmos_extract_spec_exec(cpl_plugin *plugin)
00193 {
00194     cpl_recipe  *recipe;
00195 
00196     /* Get the recipe out of the plugin */
00197     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00198         recipe = (cpl_recipe *)plugin;
00199     else return -1;
00200 
00201     return kmos_extract_spec(recipe->parameters, recipe->frames);
00202 }
00203 
00204 /*----------------------------------------------------------------------------*/
00210 /*----------------------------------------------------------------------------*/
00211 static int kmos_extract_spec_destroy(cpl_plugin *plugin)
00212 {
00213     cpl_recipe *recipe;
00214 
00215     /* Get the recipe out of the plugin */
00216     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00217         recipe = (cpl_recipe *)plugin;
00218     else return -1 ;
00219 
00220     cpl_parameterlist_delete(recipe->parameters);
00221     return 0 ;
00222 }
00223 
00224 /*----------------------------------------------------------------------------*/
00238 /*----------------------------------------------------------------------------*/
00239 static int kmos_extract_spec(
00240         cpl_parameterlist   *   parlist, 
00241         cpl_frameset        *   frameset)
00242 {
00243     const cpl_parameter *   par ;
00244     const char          *   mask_method ;
00245     const char          *   cmethod ;
00246     const char          *   centre_txt ;
00247     cpl_vector          *   centre ;
00248     int                     cmin, cmax, valid_ifu, citer, save_mask,
00249                             devnr1, devnr2, index_data, index_noise ;
00250     double                  cpos_rej, cneg_rej, radius, r, x_lo, y_lo,
00251                             x_hi, y_hi, cen_x, cen_y ;
00252     cpl_imagelist       *   data_in ; 
00253     cpl_imagelist       *   noise_in ; 
00254     cpl_image           *   mask ;
00255     cpl_image           *   made_data_img ;
00256     cpl_vector          *   spec_data_out ;
00257     cpl_vector          *   spec_noise_out ;
00258     cpl_vector          *   fit_par ;
00259     cpl_propertylist    *   sub_header_data ;
00260     cpl_propertylist    *   sub_header_noise ;
00261     cpl_propertylist    *   sub_header_mask ;
00262     cpl_propertylist    *   fit_pl ;
00263     cpl_frame           *   op1_frame ;
00264     cpl_frame           *   op2_frame ;
00265     float               *   pmask ;
00266     main_fits_desc          desc1, desc2;
00267     int                     i, x, y ;
00268 
00269     /* Check entries */
00270     if (parlist == NULL || frameset == NULL) {
00271         cpl_msg_error(__func__, "Null Inputs") ;
00272         cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
00273         return -1 ;
00274     }
00275 
00276     /* Initialise */
00277     spec_data_out = spec_noise_out = NULL ;
00278 
00279     /* Get parameters */
00280     par = cpl_parameterlist_find_const(parlist, 
00281             "kmos.kmos_extract_spec.mask_method");
00282     mask_method = cpl_parameter_get_string(par) ;
00283 
00284     if (!strcmp(mask_method, "integrated")) {
00285         par = cpl_parameterlist_find_const(parlist, 
00286                 "kmos.kmos_extract_spec.centre");
00287         centre_txt = cpl_parameter_get_string(par) ;
00288         centre = kmo_identify_ranges(centre_txt);
00289         if (cpl_vector_get_size(centre) != 2) {
00290             cpl_msg_error(__func__, "centre must have 2 values like a,b") ;
00291             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00292             return -1 ;
00293         }
00294         cen_x = cpl_vector_get(centre, 0);
00295         cen_y = cpl_vector_get(centre, 1);
00296         cpl_vector_delete(centre);
00297         if (cen_x < 0.0 || cen_y < 0.0) {
00298             cpl_msg_error(__func__, "centre must be greater than 0.0") ;
00299             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00300             return -1 ;
00301         }
00302         par = cpl_parameterlist_find_const(parlist,
00303                 "kmos.kmos_extract_spec.radius");
00304         radius = cpl_parameter_get_double(par) ;
00305         if (radius < 0.0) {
00306             cpl_msg_error(__func__, "radius must be greater than 0.0") ;
00307             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00308             return -1 ;
00309         }
00310     } else if (strcmp(mask_method, "optimal") == 0) {
00311         kmos_combine_pars_load(parlist, "kmos.kmos_extract_spec", &cmethod,
00312                 &cpos_rej, &cneg_rej, &citer, &cmin, &cmax, FALSE);
00313         par = cpl_parameterlist_find_const(parlist,
00314                     "kmos.kmos_extract_spec.save_mask");
00315         save_mask = cpl_parameter_get_bool(par);
00316     } else {
00317         cpl_msg_error(__func__, "Unsupported mask method: %s", mask_method) ;
00318         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00319         return -1 ;
00320     }
00321 
00322     /* Identify the RAW and CALIB frames in the input frameset */
00323     if (kmo_dfs_set_groups(frameset, "kmos_extract_spec") != 1) {
00324         cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
00325         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00326         return -1 ;
00327     }
00328     
00329     /* Check Inputs */
00330     if (cpl_frameset_get_size(frameset) != 1 &&
00331             cpl_frameset_get_size(frameset) != 2) {
00332         cpl_msg_error(__func__, "1 or 2 frames expected") ;
00333         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00334         return -1 ;
00335     }
00336 
00337     /* Load frames */
00338     op1_frame = kmo_dfs_get_frame(frameset, "0");
00339     kmo_init_fits_desc(&desc1);
00340     kmo_init_fits_desc(&desc2);
00341     desc1 = kmo_identify_fits_header(cpl_frame_get_filename(op1_frame));
00342     if (cpl_frameset_get_size(frameset) == 2) {
00343         op2_frame = kmo_dfs_get_frame(frameset, "1");
00344         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(op2_frame));
00345     } else {
00346         op2_frame = NULL ;
00347     }
00348 
00349     /* --- load, update & save primary header --- */
00350     kmo_dfs_save_main_header(frameset, EXTRACT_SPEC, "", op1_frame, NULL, 
00351             parlist, cpl_func);
00352     if (save_mask) {
00353         kmo_dfs_save_main_header(frameset, EXTRACT_SPEC_MASK, "", op1_frame, 
00354                 NULL, parlist, cpl_func);
00355     }
00356 
00357     /* Create mask for integrated-method */
00358     if (!strcmp(mask_method, "integrated")) {
00359         mask = cpl_image_new(desc1.naxis1, desc1.naxis2, CPL_TYPE_FLOAT);
00360         kmo_image_fill(mask,0.0);
00361         pmask = cpl_image_get_data_float(mask);
00362 
00363         /* draw circle */
00364         x_lo = floor(cen_x - radius);
00365         if (x_lo < 0) x_lo = 0;
00366         y_lo = floor(cen_y - radius);
00367         if (y_lo < 0) y_lo = 0;
00368         x_hi = ceil(cen_x + radius);
00369         if (x_hi > desc1.naxis1) x_hi = desc1.naxis1;
00370         y_hi = ceil(cen_y + radius);
00371         if (y_hi > desc1.naxis2) y_hi = desc1.naxis2;
00372         for (x = x_lo; x < x_hi; x++) {
00373             for (y = y_lo; y < y_hi; y++) {
00374                 r = sqrt(pow(x - cen_x,2) + pow(y - cen_y,2));
00375                 if (r <= radius) pmask[x + y * desc1.naxis1] = 1.0;
00376             }
00377         }            
00378     }
00379     
00380     /* Loop on detectors */
00381     for (i = 1; i <= KMOS_NR_IFUS ; i++) {
00382         if (desc1.ex_noise == FALSE) {
00383             devnr1 = desc1.sub_desc[i - 1].device_nr;
00384         } else {
00385             devnr1 = desc1.sub_desc[2 * i - 1].device_nr;
00386         }
00387         /* Mask doesn't contain any noise extensions */
00388         if (strcmp(mask_method, "mask") == 0) {
00389             devnr2 = desc2.sub_desc[i - 1].device_nr;
00390         }
00391 
00392         if (desc1.ex_badpix == FALSE) {
00393             index_data = kmo_identify_index_desc(desc1, devnr1, FALSE);
00394         } else {
00395             index_data = kmo_identify_index_desc(desc1, devnr1, 2);
00396         }
00397         if (desc1.ex_noise) {
00398             index_noise = kmo_identify_index_desc(desc1, devnr1, TRUE);
00399         }
00400         sub_header_data = kmo_dfs_load_sub_header(frameset, "0", devnr1, FALSE);
00401 
00402         /* Check if IFU is valid */
00403         valid_ifu = FALSE;
00404         if (desc1.sub_desc[index_data-1].valid_data == TRUE) {
00405             if ((strcmp(mask_method, "mask") != 0) ||
00406                 ((strcmp(mask_method, "mask") == 0) &&
00407                 (desc2.sub_desc[i - 1].valid_data == TRUE))) valid_ifu = TRUE;
00408         }
00409         if (desc1.ex_noise) {
00410             sub_header_noise = kmo_dfs_load_sub_header(frameset, "0", devnr1, 
00411                     TRUE);
00412         }
00413 
00414         if (valid_ifu) {
00415             // load data
00416             data_in = kmo_dfs_load_cube(frameset, "0", devnr1, FALSE);
00417 
00418             // load noise, if existing
00419             if (desc1.ex_noise && desc1.sub_desc[index_noise-1].valid_data) {
00420                 noise_in = kmo_dfs_load_cube(frameset, "0", devnr1, TRUE);
00421             } else {
00422                 noise_in = NULL ;
00423             }
00424 
00425             // create or load mask (for integrated-method already
00426             // done outside the for-loop)
00427             if (!strcmp(mask_method, "mask")) {
00428                 mask = kmo_dfs_load_image(frameset, "1", devnr2, FALSE, 
00429                         FALSE, NULL);
00430             } else if (!strcmp(mask_method, "optimal")) {
00431                 kmclipm_make_image(data_in, NULL, &made_data_img, NULL, NULL,
00432                         cmethod, cpos_rej, cneg_rej, citer, cmax, cmin);
00433                 fit_par = kmo_fit_profile_2D(made_data_img, NULL, "gauss",
00434                         &mask, &fit_pl);
00435 
00436                 /* Update subheader with fit parameters */
00437                 cpl_propertylist_append(sub_header_data, fit_pl);
00438                 cpl_propertylist_delete(fit_pl);
00439 
00440                 /* Normalise mask */
00441                 cpl_image_subtract_scalar(mask, cpl_vector_get(fit_par, 0));
00442                 cpl_image_divide_scalar(mask, cpl_vector_get(fit_par, 1));
00443                 cpl_vector_delete(fit_par); 
00444                 cpl_image_delete(made_data_img);
00445             }
00446 
00447             /* Process & save data */
00448             kmo_priv_extract_spec(data_in, noise_in, mask, &spec_data_out,
00449                     &spec_noise_out);
00450 
00451             sub_header_mask = cpl_propertylist_duplicate(sub_header_data);
00452 
00453             /* Change WCS here (CRPIX3 goes to CRPIX1 etc...) */
00454             sub_header_data = kmo_priv_update_header(sub_header_data);
00455 
00456             kmclipm_vector *ddd = kmclipm_vector_create(spec_data_out);
00457             kmo_dfs_save_vector(ddd, EXTRACT_SPEC, "", sub_header_data, 0./0.);
00458             kmclipm_vector_delete(ddd); 
00459             if (save_mask) {
00460                 /* Delete WCS for 3rd dimension since mask is 2D */
00461                 cpl_propertylist_erase(sub_header_mask, CRPIX3);
00462                 cpl_propertylist_erase(sub_header_mask, CRVAL3);
00463                 cpl_propertylist_erase(sub_header_mask, CDELT3);
00464                 cpl_propertylist_erase(sub_header_mask, CTYPE3);
00465                 cpl_propertylist_erase(sub_header_mask, CD1_3);
00466                 cpl_propertylist_erase(sub_header_mask, CD2_3);
00467                 cpl_propertylist_erase(sub_header_mask, CD3_3);
00468                 cpl_propertylist_erase(sub_header_mask, CD3_1);
00469                 cpl_propertylist_erase(sub_header_mask, CD3_2);
00470                 kmo_dfs_save_image(mask, EXTRACT_SPEC_MASK, "", 
00471                         sub_header_mask, 0.);
00472             }
00473             cpl_propertylist_delete(sub_header_mask);
00474 
00475             /* Process & save noise, if existing */
00476             if (desc1.ex_noise) {
00477                 kmclipm_vector *nnn = NULL;
00478                 if (spec_noise_out != NULL) {
00479                     nnn = kmclipm_vector_create(spec_noise_out);
00480                 }
00481                 sub_header_noise = kmo_priv_update_header(sub_header_noise);
00482 
00483                 kmo_dfs_save_vector(nnn, EXTRACT_SPEC, "", sub_header_noise, 
00484                         0./0.);
00485                 kmclipm_vector_delete(nnn); 
00486             }
00487             cpl_imagelist_delete(data_in); 
00488             cpl_imagelist_delete(noise_in);
00489             if (strcmp(mask_method, "integrated")) cpl_image_delete(mask);
00490         } else {
00491             /* Invalid IFU */
00492             kmo_dfs_save_sub_header(EXTRACT_SPEC, "", sub_header_data);
00493             if (desc1.ex_noise) {
00494                 kmo_dfs_save_sub_header(EXTRACT_SPEC, "", sub_header_noise);
00495             }
00496         }
00497         cpl_propertylist_delete(sub_header_data); 
00498         if (desc1.ex_noise) cpl_propertylist_delete(sub_header_noise);
00499     }
00500     if (!strcmp(mask_method, "integrated")) cpl_image_delete(mask);
00501     kmo_free_fits_desc(&desc1);
00502     kmo_free_fits_desc(&desc2);
00503     return 0 ;
00504 }
00505