KMOS Pipeline Reference Manual  1.1.0
kmo_rotate.c
00001 /* $Id: kmo_rotate.c,v 1.10 2013/01/09 13:54:20 aagudo Exp $
00002  *
00003  * This file is part of the KMOS Pipeline
00004  * Copyright (C) 2002,2003 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: aagudo $
00023  * $Date: 2013/01/09 13:54:20 $
00024  * $Revision: 1.10 $
00025  * $Name: HEAD $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 #include <string.h>
00033 
00034 #include <cpl.h>
00035 
00036 #include <kmo_debug.h>
00037 #include <kmo_utils.h>
00038 #include <kmo_dfs.h>
00039 #include <kmo_error.h>
00040 #include <kmo_priv_functions.h>
00041 #include <kmo_cpl_extensions.h>
00042 #include <kmo_constants.h>
00043 #include <kmo_priv_rotate.h>
00044 
00045 static int kmo_rotate_create(cpl_plugin *);
00046 static int kmo_rotate_exec(cpl_plugin *);
00047 static int kmo_rotate_destroy(cpl_plugin *);
00048 static int kmo_rotate(cpl_parameterlist *, cpl_frameset *);
00049 
00050 static char kmo_rotate_description[] =
00051 "This recipe rotates a cube spatially (CCW). If the rotation angle isn't\n"
00052 "a multiple of 90 degrees, the output cube will be interpolated and get larger\n"
00053 "accordingly.\n"
00054 "By default all IFUs will be rotated.\n"
00055 "\n"
00056 "BASIC PARAMETERS:\n"
00057 "-----------------\n"
00058 "--rotations\n"
00059 "This parameter must be supplied. It contains the amount of rotation to apply.\n"
00060 "The unit is in degrees. If it contains one value (e.g. “3.5”) all IFUs are\n"
00061 "rotated by the same amount. If 24 values are supplied each IFU is rotated\n"
00062 "individually (e.g. “2.3;15.7;…;-3.3”).\n"
00063 "\n"
00064 "--imethod\n"
00065 "The interpolation method to apply when rotating an angle not being a multiple\n"
00066 "of 90. There are two methods available:\n"
00067 "   * BCS: Bicubic spline\n"
00068 "   * NN:  Nearest Neighbor (currently disabled)\n"
00069 "\n"
00070 "--ifu\n"
00071 "If a single IFU should be rotated, it can be defined using the --ifu parameter\n"
00072 "(--rotations parameter contains only one value).\n"
00073 "\n"
00074 "ADVANCED PARAMETERS\n"
00075 "-------------------\n"
00076 "--flux\n"
00077 "Specify if flux conservation should be applied.\n"
00078 "\n"
00079 "--extrapolate\n"
00080 "By default the output frame grows when rotating an angle not being a multiple\n"
00081 "of 90. In this case none of the input data is lost. When it is desired to keep\n"
00082 "the same size as the input frame this parameter can be set to TRUE and the\n"
00083 "data will be clipped.\n"
00084 "\n"
00085 "-------------------------------------------------------------------------------\n"
00086 "  Input files:\n"
00087 "\n"
00088 "   DO                    KMOS                                                  \n"
00089 "   category              Type   Explanation                    Required #Frames\n"
00090 "   --------              -----  -----------                    -------- -------\n"
00091 "   <none or any>         F3I    data frame                         Y       1   \n"
00092 "\n"
00093 "  Output files:\n"
00094 "\n"
00095 "   DO                    KMOS\n"
00096 "   category              Type   Explanation\n"
00097 "   --------              -----  -----------\n"
00098 "   ROTATE                F3I    Rotated data cube\n"
00099 "-------------------------------------------------------------------------------\n"
00100 "\n";
00101 
00118 int cpl_plugin_get_info(cpl_pluginlist *list)
00119 {
00120     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00121     cpl_plugin *plugin = &recipe->interface;
00122 
00123     cpl_plugin_init(plugin,
00124                         CPL_PLUGIN_API,
00125                         KMOS_BINARY_VERSION,
00126                         CPL_PLUGIN_TYPE_RECIPE,
00127                         "kmo_rotate",
00128                         "Rotate a cube spatially",
00129                         kmo_rotate_description,
00130                         "Alex Agudo Berbel",
00131                         "agudo@mpe.mpg.de",
00132                         kmos_get_license(),
00133                         kmo_rotate_create,
00134                         kmo_rotate_exec,
00135                         kmo_rotate_destroy);
00136 
00137     cpl_pluginlist_append(list, plugin);
00138 
00139     return 0;
00140 }
00141 
00149 static int kmo_rotate_create(cpl_plugin *plugin)
00150 {
00151     cpl_recipe *recipe;
00152     cpl_parameter *p;
00153 
00154     /* Check that the plugin is part of a valid recipe */
00155     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00156         recipe = (cpl_recipe *)plugin;
00157     else
00158         return -1;
00159 
00160     /* Create the parameters list in the cpl_recipe object */
00161     recipe->parameters = cpl_parameterlist_new();
00162 
00163     /* Fill the parameters list */
00164     /* --imethod */
00165     p = cpl_parameter_new_value("kmos.kmo_rotate.imethod",
00166                                 CPL_TYPE_STRING,
00167                                 "Method to use for interpolation: "
00168                                 "[\"BCS\" (bicubic spline, default), "
00169                                 "\"NN\" (nearest neighbor), not implemented yet]",
00170                                 "kmos.kmo_rotate",
00171                                 "BCS");
00172     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "imethod");
00173     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00174     cpl_parameterlist_append(recipe->parameters, p);
00175 
00176     /* --extrapolate */
00177     p = cpl_parameter_new_value("kmos.kmo_rotate.extrapolate",
00178                                 CPL_TYPE_INT,
00179                                 "Applies only when rotation angle is different "
00180                                 "from multiples of 90 degrees: "
00181                                 "'0': Output IFU will be larger than the input "
00182                                 "(Default), "
00183                                 "'1': The size of input and output IFU remains "
00184                                 "the same. Data will be clipped.",
00185                                 "kmos.kmo_rotate",
00186                                 0);
00187     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extrapolate");
00188     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00189     cpl_parameterlist_append(recipe->parameters, p);
00190 
00191     /* --rotations */
00192     p = cpl_parameter_new_value("kmos.kmo_rotate.rotations",
00193                                 CPL_TYPE_STRING,
00194                                 "The rotations for all specified IFUs. "
00195                                 "\"rot1;rot2;...\" (degrees)",
00196                                 "kmos.kmo_rotate",
00197                                 "");
00198     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rotations");
00199     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00200     cpl_parameterlist_append(recipe->parameters, p);
00201 
00202     /* --ifu */
00203     p = cpl_parameter_new_value("kmos.kmo_rotate.ifu",
00204                                 CPL_TYPE_INT,
00205                                 "The IFU to rotate [1 to 24] or rotate all IFUs "
00206                                 "[0, default].",
00207                                 "kmos.kmo_rotate",
00208                                 0);
00209     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ifu");
00210     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00211     cpl_parameterlist_append(recipe->parameters, p);
00212 
00213     /* --flux */
00214     p = cpl_parameter_new_value("kmos.kmo_rotate.flux",
00215                                 CPL_TYPE_BOOL,
00216                                 "Apply flux conservation: "
00217                                 "(TRUE (apply) or "
00218                                 "FALSE (don't apply)",
00219                                 "kmos.kmo_rotate",
00220                                 TRUE);
00221     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux");
00222     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00223     cpl_parameterlist_append(recipe->parameters, p);
00224 
00225     return 0;
00226 }
00227 
00233 static int kmo_rotate_exec(cpl_plugin *plugin)
00234 {
00235     cpl_recipe  *recipe;
00236 
00237     /* Get the recipe out of the plugin */
00238     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00239         recipe = (cpl_recipe *)plugin;
00240     else return -1 ;
00241 
00242     return kmo_rotate(recipe->parameters, recipe->frames);
00243 }
00244 
00250 static int kmo_rotate_destroy(cpl_plugin *plugin)
00251 {
00252     cpl_recipe *recipe;
00253 
00254     /* Get the recipe out of the plugin */
00255     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00256         recipe = (cpl_recipe *)plugin;
00257     else return -1 ;
00258 
00259     cpl_parameterlist_delete(recipe->parameters);
00260     return 0 ;
00261 }
00262 
00277 static int kmo_rotate(cpl_parameterlist *parlist, cpl_frameset *frameset)
00278 {
00279     const char       *method             = NULL,
00280                      *rotations_txt      = NULL;
00281 
00282     cpl_imagelist    *data               = NULL,
00283                      *noise              = NULL;
00284 
00285     cpl_vector       *rotations          = NULL,
00286                      *rotations2         = NULL;
00287 
00288     int              ret_val             = 0,
00289                      nr_devices          = 0,
00290                      i                   = 0,
00291                      valid_ifu           = FALSE,
00292                      flux                = 0,
00293                      size                = 0,
00294                      ifu                 = 0,
00295                      extrapolate         = 0,
00296                      devnr               = 0,
00297                      index_data          = 0,
00298                      index_noise         = 0;
00299 
00300     enum extrapolationType extrapol_enum = 0;
00301 
00302     const double     *protations2        = NULL;
00303 
00304     cpl_propertylist *sub_header_data    = NULL,
00305                      *sub_header_noise   = NULL;
00306 
00307     cpl_frame        *frame              = NULL;
00308 
00309     main_fits_desc   desc1;
00310 
00311     KMO_TRY
00312     {
00313         kmo_init_fits_desc(&desc1);
00314 
00315         /* --- check input --- */
00316         KMO_TRY_ASSURE((parlist != NULL) &&
00317                        (frameset != NULL),
00318                        CPL_ERROR_NULL_INPUT,
00319                        "Not all input data is provided!");
00320 
00321         KMO_TRY_ASSURE(cpl_frameset_get_size(frameset) == 1,
00322                        CPL_ERROR_NULL_INPUT,
00323                        "A cube must be provided!");
00324 
00325         KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_rotate") == 1,
00326                        CPL_ERROR_ILLEGAL_INPUT,
00327                        "Cannot identify RAW and CALIB frames!");
00328 
00329         cpl_msg_info("", "--- Parameter setup for kmo_rotate --------");
00330 
00331         KMO_TRY_EXIT_IF_NULL(
00332             method = kmo_dfs_get_parameter_string(parlist,
00333                                            "kmos.kmo_rotate.imethod"));
00334         KMO_TRY_EXIT_IF_ERROR(
00335             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_rotate.imethod"));
00336 
00337         extrapolate = kmo_dfs_get_parameter_int(parlist,
00338                                                 "kmos.kmo_rotate.extrapolate");
00339         KMO_TRY_CHECK_ERROR_STATE();
00340 
00341         if (extrapolate == 1) {
00342             extrapol_enum = NONE_NANS;
00343         } else if (extrapolate == 0) {
00344             extrapol_enum = RESIZE_NANS;
00345         } else {
00346             KMO_TRY_ASSURE(1 == 0,
00347                            CPL_ERROR_ILLEGAL_INPUT,
00348                            "extrapolate must be 1 or 0!");
00349         }
00350 
00351         KMO_TRY_EXIT_IF_ERROR(
00352             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_rotate.extrapolate"));
00353 
00354         rotations_txt = kmo_dfs_get_parameter_string(parlist,
00355                                                   "kmos.kmo_rotate.rotations");
00356         KMO_TRY_CHECK_ERROR_STATE();
00357         KMO_TRY_EXIT_IF_ERROR(
00358             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_rotate.rotations"));
00359 
00360         KMO_TRY_ASSURE(strcmp(rotations_txt, "") != 0,
00361                        CPL_ERROR_ILLEGAL_INPUT,
00362                        "At least one value for --rotations parameter must be "
00363                        "provided!");
00364 
00365         rotations = kmo_identify_values(rotations_txt);
00366         KMO_TRY_CHECK_ERROR_STATE();
00367 
00368         size = cpl_vector_get_size(rotations);
00369         KMO_TRY_CHECK_ERROR_STATE();
00370 
00371         KMO_TRY_ASSURE((size == 1) || (size == KMOS_NR_IFUS),
00372                        CPL_ERROR_ILLEGAL_INPUT,
00373                        "rotations parameter must have either one or 24 elements!");
00374 
00375         ifu = kmo_dfs_get_parameter_int(parlist, "kmos.kmo_rotate.ifu");
00376         KMO_TRY_CHECK_ERROR_STATE();
00377         KMO_TRY_EXIT_IF_ERROR(
00378             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_rotate.ifu"));
00379 
00380         if (ifu == 0) {
00381             // rotate all IFUs the same or different amounts
00382             KMO_TRY_ASSURE((size == 1) || (size == KMOS_NR_IFUS),
00383                            CPL_ERROR_ILLEGAL_INPUT,
00384                            "rotations parameter must have exactly 1 elements"
00385                            "(rotate all IFUs the same amount) or 24 elements "
00386                            "(rotate all IFUs individually)!");
00387         } else {
00388             // rotate only one specific IFU
00389             KMO_TRY_ASSURE(size == 1,
00390                            CPL_ERROR_ILLEGAL_INPUT,
00391                            "rotations parameter must have exactly one elements "
00392                            "to rotate a single IFU!");
00393         }
00394 
00395         // setup a vector of length 24 regardless of how many IFUs to rotate
00396         if (size == KMOS_NR_IFUS) {
00397             KMO_TRY_EXIT_IF_NULL(
00398                 rotations2 = cpl_vector_duplicate(rotations));
00399         } else {
00400             KMO_TRY_EXIT_IF_NULL(
00401                 rotations2 = cpl_vector_new(KMOS_NR_IFUS));
00402             KMO_TRY_EXIT_IF_NULL(
00403                 protations2 = cpl_vector_get_data_const(rotations));
00404             for (i = 0; i < KMOS_NR_IFUS; i++) {
00405                 cpl_vector_set(rotations2, i, protations2[0]);
00406             }
00407         }
00408 
00409         KMO_TRY_EXIT_IF_NULL(
00410                 protations2 = cpl_vector_get_data_const(rotations2));
00411 
00412         KMO_TRY_ASSURE((strcmp(method, "NN") == 0) ||
00413                        (strcmp(method, "BCS") == 0)
00414                        /*(strcmp(method, "kriging") == 0) ||
00415                        (strcmp(method, "cubic") == 0) ||
00416                        (strcmp(method, "shepard") == 0) ||
00417                        (strcmp(method, "drizzle") == 0)*/,
00418                        CPL_ERROR_ILLEGAL_INPUT,
00419                        "method must be \"BCS\"!");
00420 
00421         flux = kmo_dfs_get_parameter_bool(parlist,
00422                                           "kmos.kmo_rotate.flux");
00423         KMO_TRY_CHECK_ERROR_STATE();
00424         KMO_TRY_EXIT_IF_ERROR(
00425             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_rotate.flux"));
00426 
00427         cpl_msg_info("", "-------------------------------------------");
00428 
00429         KMO_TRY_ASSURE((flux == 0) ||
00430                        (flux == 1),
00431                        CPL_ERROR_ILLEGAL_INPUT,
00432                        "flux must be either 0 or 1 !");
00433 
00434         // load descriptor of first operand
00435         KMO_TRY_EXIT_IF_NULL(
00436             frame = kmo_dfs_get_frame(frameset, "0"));
00437 
00438         desc1 = kmo_identify_fits_header(
00439                     cpl_frame_get_filename(frame));
00440         KMO_TRY_CHECK_ERROR_STATE_MSG("Provided fits file doesn't seem to be "
00441                                       "in KMOS-format!");
00442 
00443         KMO_TRY_ASSURE(desc1.fits_type == f3i_fits,
00444                        CPL_ERROR_ILLEGAL_INPUT,
00445                        "First input file hasn't correct data type "
00446                        "(KMOSTYPE must be F3I)!");
00447 
00448         // --- load, update & save primary header ---
00449         KMO_TRY_EXIT_IF_ERROR(
00450             kmo_dfs_save_main_header(frameset, ROTATE, "", frame,
00451                                      NULL, parlist, cpl_func));
00452 
00453         // --- load data ---
00454         if (desc1.ex_noise == TRUE) {
00455             nr_devices = desc1.nr_ext / 2;
00456         } else {
00457             nr_devices = desc1.nr_ext;
00458         }
00459 
00460         for (i = 1; i <= nr_devices; i++) {
00461             if (desc1.ex_noise == FALSE) {
00462                 devnr = desc1.sub_desc[i - 1].device_nr;
00463             } else {
00464                 devnr = desc1.sub_desc[2 * i - 1].device_nr;
00465             }
00466 
00467             if (desc1.ex_badpix == FALSE) {
00468                 index_data = kmo_identify_index_desc(desc1, devnr, FALSE);
00469             } else {
00470                 index_data = kmo_identify_index_desc(desc1, devnr, 2);
00471             }
00472             KMO_TRY_CHECK_ERROR_STATE();
00473 
00474             if (desc1.ex_noise) {
00475                 index_noise = kmo_identify_index_desc(desc1, devnr, TRUE);
00476             }
00477             KMO_TRY_CHECK_ERROR_STATE();
00478 
00479             KMO_TRY_EXIT_IF_NULL(
00480                 sub_header_data = kmo_dfs_load_sub_header(frameset, "0", devnr,
00481                                                           FALSE));
00482 
00483             // check if IFU is valid
00484             valid_ifu = FALSE;
00485             if (desc1.sub_desc[index_data-1].valid_data == TRUE) {
00486                 valid_ifu = TRUE;
00487             }
00488 
00489             if (desc1.ex_noise) {
00490                 // load noise anyway since we have to save it in the output
00491                 KMO_TRY_EXIT_IF_NULL(
00492                     sub_header_noise = kmo_dfs_load_sub_header(frameset, "0",
00493                                                                devnr, TRUE));
00494             }
00495 
00496             if (valid_ifu) {
00497                 // load data
00498                 KMO_TRY_EXIT_IF_NULL(
00499                     data = kmo_dfs_load_cube(frameset, "0", devnr, FALSE));
00500 
00501                 // load noise, if existing
00502                 if (desc1.ex_noise && desc1.sub_desc[index_noise-1].valid_data) {
00503                     KMO_TRY_EXIT_IF_NULL(
00504                         noise = kmo_dfs_load_cube(frameset, "0", devnr, TRUE));
00505                 }
00506 
00507                 if ((ifu == 0) || (ifu == devnr)) {
00508                     // process here
00509                     KMO_TRY_EXIT_IF_ERROR(
00510                         kmo_priv_rotate(&data, &noise,
00511                                         &sub_header_data, &sub_header_noise,
00512                                         protations2[i-1],
00513                                         flux, devnr, method, extrapol_enum));
00514                 } else {
00515                     // leave data and noise as they are and
00516                     // save them again unrotated
00517                 }
00518 
00519                 // save data and noise (if existing)
00520                 KMO_TRY_EXIT_IF_ERROR(
00521                     kmo_dfs_save_cube(data, ROTATE, "", sub_header_data, 0./0.));
00522 
00523                 if (desc1.ex_noise) {
00524                     KMO_TRY_EXIT_IF_ERROR(
00525                         kmo_dfs_save_cube(noise, ROTATE, "", sub_header_noise,
00526                                           0./0.));
00527                 }
00528 
00529                 // free memory
00530                 cpl_imagelist_delete(data); data = NULL;
00531                 cpl_imagelist_delete(noise); noise = NULL;
00532             } else {
00533                 // invalid IFU, just save sub_headers
00534                 KMO_TRY_EXIT_IF_ERROR(
00535                     kmo_dfs_save_sub_header(ROTATE, "", sub_header_data));
00536 
00537                 if (desc1.ex_noise) {
00538                     KMO_TRY_EXIT_IF_ERROR(
00539                         kmo_dfs_save_sub_header(ROTATE, "", sub_header_noise));
00540                 }
00541             }
00542 
00543             // free memory
00544             cpl_propertylist_delete(sub_header_data); sub_header_data = NULL;
00545             cpl_propertylist_delete(sub_header_noise); sub_header_noise = NULL;
00546         }
00547     }
00548     KMO_CATCH
00549     {
00550         KMO_CATCH_MSG();
00551         ret_val = -1;
00552     }
00553 
00554     kmo_free_fits_desc(&desc1);
00555     cpl_propertylist_delete(sub_header_data); sub_header_data = NULL;
00556     cpl_propertylist_delete(sub_header_noise); sub_header_noise = NULL;
00557     cpl_imagelist_delete(data); data = NULL;
00558     cpl_imagelist_delete(noise); noise = NULL;
00559     cpl_vector_delete(rotations); rotations = NULL;
00560     cpl_vector_delete(rotations2); rotations2 = NULL;
00561 
00562     return ret_val;
00563 }
00564