KMOS Pipeline Reference Manual  1.3.16
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, index_data, index_noise, 
00250                             nr_devices ;
00251     double                  cpos_rej, cneg_rej, radius, r, x_lo, y_lo,
00252                             x_hi, y_hi, cen_x, cen_y, loc_cen_x, loc_cen_y ;
00253     cpl_size                auto_cen_x, auto_cen_y ;
00254     cpl_imagelist       *   data_in ; 
00255     cpl_imagelist       *   noise_in ; 
00256     cpl_image           *   mask ;
00257     cpl_image           *   made_data_img ;
00258     cpl_vector          *   spec_data_out ;
00259     cpl_vector          *   spec_noise_out ;
00260     cpl_vector          *   fit_par ;
00261     cpl_propertylist    *   sub_header_data ;
00262     cpl_propertylist    *   sub_header_noise ;
00263     cpl_propertylist    *   sub_header_mask ;
00264     cpl_propertylist    *   fit_pl ;
00265     cpl_frame           *   op1_frame ;
00266     cpl_frame           *   op2_frame ;
00267     float               *   pmask ;
00268     main_fits_desc          desc1, desc2;
00269     int                     i, x, y ;
00270 
00271     /* Check entries */
00272     if (parlist == NULL || frameset == NULL) {
00273         cpl_msg_error(__func__, "Null Inputs") ;
00274         cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
00275         return -1 ;
00276     }
00277 
00278     /* Initialise */
00279     spec_data_out = spec_noise_out = NULL ;
00280 
00281     /* Get parameters */
00282     par = cpl_parameterlist_find_const(parlist, 
00283             "kmos.kmos_extract_spec.mask_method");
00284     mask_method = cpl_parameter_get_string(par) ;
00285     par = cpl_parameterlist_find_const(parlist,
00286                 "kmos.kmos_extract_spec.save_mask");
00287     save_mask = cpl_parameter_get_bool(par);
00288     if (!strcmp(mask_method, "integrated")) {
00289         par = cpl_parameterlist_find_const(parlist, 
00290                 "kmos.kmos_extract_spec.centre");
00291         centre_txt = cpl_parameter_get_string(par) ;
00292         centre = kmo_identify_ranges(centre_txt);
00293         if (cpl_vector_get_size(centre) != 2) {
00294             cpl_msg_error(__func__, "centre must have 2 values like a,b") ;
00295             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00296             return -1 ;
00297         }
00298         cen_x = cpl_vector_get(centre, 0);
00299         cen_y = cpl_vector_get(centre, 1);
00300         cpl_vector_delete(centre);
00301         par = cpl_parameterlist_find_const(parlist,
00302                 "kmos.kmos_extract_spec.radius");
00303         radius = cpl_parameter_get_double(par) ;
00304         if (radius < 0.0) {
00305             cpl_msg_error(__func__, "radius must be greater than 0.0") ;
00306             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00307             return -1 ;
00308         }
00309     } else if (strcmp(mask_method, "optimal") == 0) {
00310         kmos_combine_pars_load(parlist, "kmos.kmos_extract_spec", &cmethod,
00311                 &cpos_rej, &cneg_rej, &citer, &cmin, &cmax, FALSE);
00312     } else {
00313         cpl_msg_error(__func__, "Unsupported mask method: %s", mask_method) ;
00314         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00315         return -1 ;
00316     }
00317 
00318     /* Identify the RAW and CALIB frames in the input frameset */
00319     if (kmo_dfs_set_groups(frameset, "kmos_extract_spec") != 1) {
00320         cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
00321         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00322         return -1 ;
00323     }
00324     
00325     /* Check Inputs */
00326     if (cpl_frameset_get_size(frameset) != 1 &&
00327             cpl_frameset_get_size(frameset) != 2) {
00328         cpl_msg_error(__func__, "1 or 2 frames expected") ;
00329         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00330         return -1 ;
00331     }
00332 
00333     /* Load frames */
00334     op1_frame = kmo_dfs_get_frame(frameset, "0");
00335     kmo_init_fits_desc(&desc1);
00336     kmo_init_fits_desc(&desc2);
00337     desc1 = kmo_identify_fits_header(cpl_frame_get_filename(op1_frame));
00338     if (cpl_frameset_get_size(frameset) == 2) {
00339         op2_frame = kmo_dfs_get_frame(frameset, "1");
00340         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(op2_frame));
00341     } else {
00342         op2_frame = NULL ;
00343     }
00344     
00345    /* --- load, update & save primary header --- */
00346     kmo_dfs_save_main_header(frameset, EXTRACT_SPEC, "", op1_frame, NULL, 
00347             parlist, cpl_func);
00348     if (save_mask) {
00349         kmo_dfs_save_main_header(frameset, EXTRACT_SPEC_MASK, "", op1_frame, 
00350                 NULL, parlist, cpl_func);
00351     }
00352      
00353     /* Number of extensions to extract */
00354     if (desc1.ex_noise == TRUE) {
00355         nr_devices = desc1.nr_ext / 2;
00356     } else {
00357         nr_devices = desc1.nr_ext;
00358     }
00359 
00360     /* Loop on the devices */
00361     for (i = 1; i <= nr_devices ; i++) {
00362         if (desc1.ex_noise == FALSE) {
00363             devnr1 = desc1.sub_desc[i - 1].device_nr;
00364         } else {
00365             devnr1 = desc1.sub_desc[2 * i - 1].device_nr;
00366         }
00367 
00368         if (desc1.ex_badpix == FALSE) {
00369             index_data = kmo_identify_index_desc(desc1, devnr1, FALSE);
00370         } else {
00371             index_data = kmo_identify_index_desc(desc1, devnr1, 2);
00372         }
00373         if (desc1.ex_noise) {
00374             index_noise = kmo_identify_index_desc(desc1, devnr1, TRUE);
00375         }
00376         sub_header_data = kmo_dfs_load_sub_header(frameset, "0", devnr1, FALSE);
00377 
00378         /* Check if IFU is valid */
00379         valid_ifu = FALSE;
00380         if (desc1.sub_desc[index_data-1].valid_data == TRUE) {
00381             if ((strcmp(mask_method, "mask") != 0) ||
00382                 ((strcmp(mask_method, "mask") == 0) &&
00383                 (desc2.sub_desc[i - 1].valid_data == TRUE))) valid_ifu = TRUE;
00384         }
00385         if (desc1.ex_noise) {
00386             sub_header_noise = kmo_dfs_load_sub_header(frameset, "0", devnr1, 
00387                     TRUE);
00388         }
00389 
00390         if (valid_ifu) {
00391             // load data
00392             data_in = kmo_dfs_load_cube(frameset, "0", devnr1, FALSE);
00393 
00394             // load noise, if existing
00395             if (desc1.ex_noise && desc1.sub_desc[index_noise-1].valid_data) {
00396                 noise_in = kmo_dfs_load_cube(frameset, "0", devnr1, TRUE);
00397             } else {
00398                 noise_in = NULL ;
00399             }
00400 
00401             /* Create the mask */
00402             if (!strcmp(mask_method, "mask")) {
00403                 mask = kmo_dfs_load_image(frameset, "1", 
00404                         desc2.sub_desc[i - 1].device_nr, FALSE, FALSE, NULL);
00405             } else if (!strcmp(mask_method, "optimal")) {
00406                 kmclipm_make_image(data_in, NULL, &made_data_img, NULL, NULL,
00407                         cmethod, cpos_rej, cneg_rej, citer, cmax, cmin);
00408                 fit_par = kmo_fit_profile_2D(made_data_img, NULL, "gauss",
00409                         &mask, &fit_pl);
00410 
00411                 /* Update subheader with fit parameters */
00412                 cpl_propertylist_append(sub_header_data, fit_pl);
00413                 cpl_propertylist_delete(fit_pl);
00414 
00415                 /* Normalise mask */
00416                 cpl_image_subtract_scalar(mask, cpl_vector_get(fit_par, 0));
00417                 cpl_image_divide_scalar(mask, cpl_vector_get(fit_par, 1));
00418                 cpl_vector_delete(fit_par); 
00419                 cpl_image_delete(made_data_img);
00420             } else if (!strcmp(mask_method, "integrated")) {
00421                 if (cen_x < 1.0 || cen_y < 1.0) {
00422                     kmclipm_make_image(data_in, NULL, &made_data_img, NULL, 
00423                             NULL, "median", 3.0, 3.0, 3, 1, 1);
00424                     cpl_image_get_maxpos(made_data_img,&auto_cen_x,&auto_cen_y);
00425                     loc_cen_x = (double)auto_cen_x - 1.0 ;
00426                     loc_cen_y = (double)auto_cen_y - 1.0 ;
00427                     cpl_image_delete(made_data_img);
00428                 } else {
00429                     loc_cen_x = cen_x - 1.0 ;
00430                     loc_cen_y = cen_y - 1.0 ;
00431                 }
00432                 mask = cpl_image_new(desc1.naxis1, desc1.naxis2,CPL_TYPE_FLOAT);
00433                 kmo_image_fill(mask,0.0);
00434                 pmask = cpl_image_get_data_float(mask);
00435 
00436                 /* draw circle */
00437                 x_lo = floor(loc_cen_x - radius);
00438                 if (x_lo < 0) x_lo = 0;
00439                 y_lo = floor(loc_cen_y - radius);
00440                 if (y_lo < 0) y_lo = 0;
00441                 x_hi = ceil(loc_cen_x + radius);
00442                 if (x_hi > desc1.naxis1) x_hi = desc1.naxis1;
00443                 y_hi = ceil(loc_cen_y + radius);
00444                 if (y_hi > desc1.naxis2) y_hi = desc1.naxis2;
00445                 for (x = x_lo; x < x_hi; x++) {
00446                     for (y = y_lo; y < y_hi; y++) {
00447                         r = sqrt(pow(x - loc_cen_x,2) + pow(y - loc_cen_y,2));
00448                         if (r <= radius) pmask[x + y * desc1.naxis1] = 1.0;
00449                     }
00450                 }            
00451             }
00452 
00453             /* Process & save data */
00454             kmo_priv_extract_spec(data_in, noise_in, mask, &spec_data_out,
00455                     &spec_noise_out);
00456 
00457             sub_header_mask = cpl_propertylist_duplicate(sub_header_data);
00458 
00459             /* Change WCS here (CRPIX3 goes to CRPIX1 etc...) */
00460             sub_header_data = kmo_priv_update_header(sub_header_data);
00461 
00462             kmclipm_vector *ddd = kmclipm_vector_create(spec_data_out);
00463             kmo_dfs_save_vector(ddd, EXTRACT_SPEC, "", sub_header_data, 0./0.);
00464             kmclipm_vector_delete(ddd); 
00465             if (save_mask) {
00466                 /* Delete WCS for 3rd dimension since mask is 2D */
00467                 cpl_propertylist_erase(sub_header_mask, CRPIX3);
00468                 cpl_propertylist_erase(sub_header_mask, CRVAL3);
00469                 cpl_propertylist_erase(sub_header_mask, CDELT3);
00470                 cpl_propertylist_erase(sub_header_mask, CTYPE3);
00471                 cpl_propertylist_erase(sub_header_mask, CD1_3);
00472                 cpl_propertylist_erase(sub_header_mask, CD2_3);
00473                 cpl_propertylist_erase(sub_header_mask, CD3_3);
00474                 cpl_propertylist_erase(sub_header_mask, CD3_1);
00475                 cpl_propertylist_erase(sub_header_mask, CD3_2);
00476                 kmo_dfs_save_image(mask, EXTRACT_SPEC_MASK, "", 
00477                         sub_header_mask, 0.);
00478             }
00479             cpl_propertylist_delete(sub_header_mask);
00480 
00481             /* Process & save noise, if existing */
00482             if (desc1.ex_noise) {
00483                 kmclipm_vector *nnn = NULL;
00484                 if (spec_noise_out != NULL) {
00485                     nnn = kmclipm_vector_create(spec_noise_out);
00486                 }
00487                 sub_header_noise = kmo_priv_update_header(sub_header_noise);
00488 
00489                 kmo_dfs_save_vector(nnn, EXTRACT_SPEC, "", sub_header_noise, 
00490                         0./0.);
00491                 kmclipm_vector_delete(nnn); 
00492             }
00493             cpl_imagelist_delete(data_in); 
00494             cpl_imagelist_delete(noise_in);
00495             cpl_image_delete(mask);
00496         } else {
00497             /* Invalid IFU */
00498             kmo_dfs_save_sub_header(EXTRACT_SPEC, "", sub_header_data);
00499             if (desc1.ex_noise) {
00500                 kmo_dfs_save_sub_header(EXTRACT_SPEC, "", sub_header_noise);
00501             }
00502         }
00503         cpl_propertylist_delete(sub_header_data); 
00504         if (desc1.ex_noise) cpl_propertylist_delete(sub_header_noise);
00505     }
00506     kmo_free_fits_desc(&desc1);
00507     kmo_free_fits_desc(&desc2);
00508     return 0 ;
00509 }
00510