KMOS Pipeline Reference Manual  1.3.0
kmo_shift.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 #include <string.h>
00025 
00026 #include <cpl.h>
00027 
00028 #include <kmo_debug.h>
00029 #include <kmo_utils.h>
00030 #include <kmo_dfs.h>
00031 #include <kmo_error.h>
00032 #include <kmo_priv_functions.h>
00033 #include <kmo_cpl_extensions.h>
00034 #include <kmo_constants.h>
00035 #include <kmo_priv_shift.h>
00036 
00037 static int kmo_shift_create(cpl_plugin *);
00038 static int kmo_shift_exec(cpl_plugin *);
00039 static int kmo_shift_destroy(cpl_plugin *);
00040 static int kmo_shift(cpl_parameterlist *, cpl_frameset *);
00041 
00042 static char kmo_shift_description[] =
00043 "This recipe shifts a cube spatially. A positive x-shift shifts the data to the\n"
00044 "left, a positive y-shift shifts upwards, where a shift of one pixel equals\n"
00045 "0.2arcsec. The output will still have the same dimensions, but the borders \n"
00046 "will be filled with NaNs accordingly.\n"
00047 "To adjust only the WCS without moving the data the --wcs-only parameter has to\n"
00048 "be set to TRUE. The WCS is updated in the same way as if the data would have\n"
00049 "moved as well. This means that the point at (x,y) has the same coordinates as\n"
00050 "the point (x+1,y+1) after updating the WCS (the WCS moved in the opposite\n"
00051 "direction).\n"
00052 "\n"
00053 "BASIC PARAMETERS:\n"
00054 "-----------------\n"
00055 "--shifts\n"
00056 "This parameter must be supplied. It contains the amount of shift to apply. The\n"
00057 "unit is in arcsec. If the --shifts parameter contains only two values (x,y),\n"
00058 "all IFUs will be shifted by the same amount. If it contains 48 values\n"
00059 "(x1,y1;x2,y2;...;x24,y24), the IFUs are shifted individually.\n"
00060 "\n"
00061 "--imethod\n"
00062 "The interpolation method to apply when the shift value isn’t a multiple of the\n"
00063 "pixel scale. There are two methods available:\n"
00064 "   * BCS: Bicubic spline\n"
00065 "   * NN:  Nearest Neighbor\n"
00066 "\n"
00067 "--ifu\n"
00068 "If a single IFU should be shifted, it can be defined using the --ifu parameter\n"
00069 "(--shifts parameter contains only two values).\n"
00070 "\n"
00071 "ADVANCED PARAMETERS\n"
00072 "-------------------\n"
00073 "--flux\n"
00074 "Specify if flux conservation should be applied.\n"
00075 "\n"
00076 "--extrapolate\n"
00077 "By default no extrapolation is applied. This means that the output frame will\n"
00078 "shrink at most one pixel, because the data is shifted out of the frame. When\n"
00079 "turning extrapolation on, the size of the output frame stays the same as for\n"
00080 "the input frame.\n"
00081 "\n"
00082 "--wcs-only\n"
00083 "By default data and WCS are shifted in sync. If this parameter is set to TRUE\n"
00084 "only the WCS is updated (i.e. if someone thinks that the IFU isn't pointing\n"
00085 "exactly to the correct coordinates.)\n"
00086 "\n"
00087 "-------------------------------------------------------------------------------\n"
00088 "  Input files:\n"
00089 "\n"
00090 "   DO                    KMOS                                                  \n"
00091 "   category              Type   Explanation                    Required #Frames\n"
00092 "   --------              -----  -----------                    -------- -------\n"
00093 "   <none or any>         F3I    data frame                        Y        1   \n"
00094 "\n"
00095 "  Output files:\n"
00096 "\n"
00097 "   DO                    KMOS\n"
00098 "   category              Type   Explanation\n"
00099 "   --------              -----  -----------\n"
00100 "   SHIFT                 F3I    Shifted data cube\n"
00101 "-------------------------------------------------------------------------------\n"
00102 "\n";
00103 
00120 int cpl_plugin_get_info(cpl_pluginlist *list)
00121 {
00122     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00123     cpl_plugin *plugin = &recipe->interface;
00124 
00125     cpl_plugin_init(plugin,
00126                         CPL_PLUGIN_API,
00127                         KMOS_BINARY_VERSION,
00128                         CPL_PLUGIN_TYPE_RECIPE,
00129                         "kmo_shift",
00130                         "Shift a cube spatially",
00131                         kmo_shift_description,
00132                         "Alex Agudo Berbel",
00133                         "usd-help@eso.org",
00134                         kmos_get_license(),
00135                         kmo_shift_create,
00136                         kmo_shift_exec,
00137                         kmo_shift_destroy);
00138 
00139     cpl_pluginlist_append(list, plugin);
00140 
00141     return 0;
00142 }
00143 
00151 static int kmo_shift_create(cpl_plugin *plugin)
00152 {
00153     cpl_recipe *recipe;
00154     cpl_parameter *p;
00155 
00156     /* Check that the plugin is part of a valid recipe */
00157     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00158         recipe = (cpl_recipe *)plugin;
00159     else
00160         return -1;
00161 
00162     /* Create the parameters list in the cpl_recipe object */
00163     recipe->parameters = cpl_parameterlist_new();
00164 
00165     /* Fill the parameters list */
00166     /* --imethod */
00167     p = cpl_parameter_new_value("kmos.kmo_shift.imethod",
00168                                 CPL_TYPE_STRING,
00169                                 "Method to use for interpolation.\n"
00170                                 "[\"BCS\" (bicubic spline, default), "
00171                                 "\"NN\" (nearest neighbor)]",
00172                                 "kmos.kmo_shift",
00173                                 "BCS");
00174     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "imethod");
00175     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00176     cpl_parameterlist_append(recipe->parameters, p);
00177 
00178     /* --extrapolate */
00179     p = cpl_parameter_new_value("kmos.kmo_shift.extrapolate",
00180                                 CPL_TYPE_BOOL,
00181                                 "Applies only to 'method=BCS' when doing sub-"
00182                                 "pixel shifts: "
00183                                 "FALSE: shifted IFU will be filled with NaN's "
00184                                 "at the borders,"
00185                                 "TRUE: shifted IFU will be extrapolated at "
00186                                 "the borders",
00187                                 "kmos.kmo_shift",
00188                                 FALSE);
00189     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extrapolate");
00190     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00191     cpl_parameterlist_append(recipe->parameters, p);
00192 
00193     /* --shifts */
00194     p = cpl_parameter_new_value("kmos.kmo_shift.shifts",
00195                                 CPL_TYPE_STRING,
00196                                 "The shifts for each spatial dimension for all "
00197                                 "specified IFUs."
00198                                 "\"x1,y1;x2,y2;...\" (arcsec)",
00199                                 "kmos.kmo_shift",
00200                                 "");
00201     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "shifts");
00202     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00203     cpl_parameterlist_append(recipe->parameters, p);
00204 
00205     /* --ifu */
00206     p = cpl_parameter_new_value("kmos.kmo_shift.ifu",
00207                                 CPL_TYPE_INT,
00208                                 "The IFU to shift [1 to 24] or shift all IFUs "
00209                                 "Default value of 0 applies shift to all IFUs.",
00210                                 "kmos.kmo_shift",
00211                                 0);
00212     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ifu");
00213     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00214     cpl_parameterlist_append(recipe->parameters, p);
00215 
00216     /* --flux */
00217     p = cpl_parameter_new_value("kmos.kmo_shift.flux",
00218                                 CPL_TYPE_BOOL,
00219                                 "Apply flux conservation: "
00220                                 "(TRUE (apply) or "
00221                                 "FALSE (don't apply)",
00222                                 "kmos.kmo_shift",
00223                                 FALSE);
00224     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux");
00225     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00226     cpl_parameterlist_append(recipe->parameters, p);
00227 
00228     /* --wcs-only */
00229     p = cpl_parameter_new_value("kmos.kmo_shift.wcs-only",
00230                                 CPL_TYPE_BOOL,
00231                                 "FALSE: if data and wcs should be updated."
00232                                 "TRUE: if only wcs should be corrected",
00233                                 "kmos.kmo_shift",
00234                                 0);
00235     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcs-only");
00236     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00237     cpl_parameterlist_append(recipe->parameters, p);
00238 
00239     return 0;
00240 }
00241 
00247 static int kmo_shift_exec(cpl_plugin *plugin)
00248 {
00249     cpl_recipe  *recipe;
00250 
00251     /* Get the recipe out of the plugin */
00252     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00253         recipe = (cpl_recipe *)plugin;
00254     else return -1 ;
00255 
00256     return kmo_shift(recipe->parameters, recipe->frames);
00257 }
00258 
00264 static int kmo_shift_destroy(cpl_plugin *plugin)
00265 {
00266     cpl_recipe *recipe;
00267 
00268     /* Get the recipe out of the plugin */
00269     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00270         recipe = (cpl_recipe *)plugin;
00271     else return -1 ;
00272 
00273     cpl_parameterlist_delete(recipe->parameters);
00274     return 0 ;
00275 }
00276 
00291 static int kmo_shift(cpl_parameterlist *parlist, cpl_frameset *frameset)
00292 {
00293     const char       *method             = NULL,
00294                      *shifts_txt         = NULL;
00295 
00296     cpl_imagelist    *data               = NULL,
00297                      *noise              = NULL;
00298 
00299     cpl_vector       *shifts             = NULL,
00300                      *shifts2            = NULL;
00301 
00302     int              ret_val             = 0,
00303                      nr_devices          = 0,
00304                      i                   = 0,
00305                      valid_ifu           = FALSE,
00306                      flux                = FALSE,
00307                      size                = 0,
00308                      ifu                 = 0,
00309                      extrapolate         = 0,
00310                      wcs_only            = FALSE,
00311                      devnr               = 0,
00312                      index_data          = 0,
00313                      index_noise         = 0;
00314 
00315     enum extrapolationType extrapol_enum = 0;
00316 
00317     const double     *pshifts2           = NULL;
00318 
00319     cpl_propertylist *sub_header_data    = NULL,
00320                      *sub_header_noise   = NULL;
00321 
00322     cpl_frame        *frame              = NULL;
00323 
00324     main_fits_desc   desc1;
00325 
00326     KMO_TRY
00327     {
00328         kmo_init_fits_desc(&desc1);
00329 
00330         /* --- check input --- */
00331         KMO_TRY_ASSURE((parlist != NULL) &&
00332                        (frameset != NULL),
00333                        CPL_ERROR_NULL_INPUT,
00334                        "Not all input data is provided!");
00335 
00336         KMO_TRY_ASSURE(cpl_frameset_get_size(frameset) == 1,
00337                        CPL_ERROR_NULL_INPUT,
00338                        "A cube must be provided!");
00339 
00340         KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_shift") == 1,
00341                        CPL_ERROR_ILLEGAL_INPUT,
00342                        "Cannot identify RAW and CALIB frames!");
00343 
00344         cpl_msg_info("", "--- Parameter setup for kmo_shift ---------");
00345 
00346         KMO_TRY_EXIT_IF_NULL(
00347             method = kmo_dfs_get_parameter_string(parlist,
00348                                            "kmos.kmo_shift.imethod"));
00349         KMO_TRY_EXIT_IF_ERROR(
00350             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_shift.imethod"));
00351 
00352         extrapolate = kmo_dfs_get_parameter_bool(parlist,
00353                                                 "kmos.kmo_shift.extrapolate");
00354         KMO_TRY_CHECK_ERROR_STATE();
00355 
00356         if (strcmp(method, "NN") == 0) {
00357             extrapol_enum = NONE_NANS;
00358         } else if (strcmp(method, "BCS") == 0) {
00359             if (extrapolate == FALSE) {
00360                 extrapol_enum = NONE_NANS;
00361             } else if (extrapolate == TRUE) {
00362                 extrapol_enum = BCS_NATURAL;
00363             } else {
00364                 KMO_TRY_ASSURE(1 == 0,
00365                                CPL_ERROR_ILLEGAL_INPUT,
00366                                "extrapolate must either FALSE or TRUE!");
00367             }
00368         } else {
00369             KMO_TRY_ASSURE(1 == 0,
00370                            CPL_ERROR_ILLEGAL_INPUT,
00371                            "method must be either \"BCS\" or \"NN\" !");
00372         }
00373 
00374         KMO_TRY_EXIT_IF_ERROR(
00375             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_shift.extrapolate"));
00376 
00377         shifts_txt = kmo_dfs_get_parameter_string(parlist,
00378                                                   "kmos.kmo_shift.shifts");
00379         KMO_TRY_CHECK_ERROR_STATE();
00380         KMO_TRY_EXIT_IF_ERROR(
00381             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_shift.shifts"));
00382 
00383         KMO_TRY_ASSURE(strcmp(shifts_txt, "") != 0,
00384                        CPL_ERROR_ILLEGAL_INPUT,
00385                        "At least two values for --shifts parameter must be "
00386                        "provided!");
00387 
00388         shifts = kmo_identify_ranges(shifts_txt);
00389         KMO_TRY_CHECK_ERROR_STATE();
00390 
00391         size = cpl_vector_get_size(shifts);
00392         KMO_TRY_CHECK_ERROR_STATE();
00393 
00394         KMO_TRY_ASSURE((size % 2) == 0,
00395                        CPL_ERROR_ILLEGAL_INPUT,
00396                        "shifts parameter must have an even number of elements!");
00397 
00398         ifu = kmo_dfs_get_parameter_int(parlist, "kmos.kmo_shift.ifu");
00399         KMO_TRY_CHECK_ERROR_STATE();
00400         KMO_TRY_EXIT_IF_ERROR(
00401             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_shift.ifu"));
00402 
00403         if (ifu == 0) {
00404             // shift all IFUs the same or different amounts
00405             KMO_TRY_ASSURE((size == 2) || (size == 2*KMOS_NR_IFUS),
00406                            CPL_ERROR_ILLEGAL_INPUT,
00407                            "shifts parameter must have exactly 2 elements"
00408                            "(shift all IFUs the same amount) or 48 elements "
00409                            "(shift all IFUs individually)!");
00410         } else {
00411             // shift only one specific IFU
00412             KMO_TRY_ASSURE(size == 2,
00413                            CPL_ERROR_ILLEGAL_INPUT,
00414                            "shifts parameter must have exactly 2 elements to "
00415                            "shift a single IFU!");
00416         }
00417 
00418         // setup a vector of length 48 regardless of how many IFUs to shift
00419         if (size == 2*KMOS_NR_IFUS) {
00420             KMO_TRY_EXIT_IF_NULL(
00421                 shifts2 = cpl_vector_duplicate(shifts));
00422         } else {
00423             KMO_TRY_EXIT_IF_NULL(
00424                 shifts2 = cpl_vector_new(2*KMOS_NR_IFUS));
00425             KMO_TRY_EXIT_IF_NULL(
00426                 pshifts2 = cpl_vector_get_data_const(shifts));
00427             for (i = 0; i < KMOS_NR_IFUS; i++) {
00428                 cpl_vector_set(shifts2, 2*i, pshifts2[0]);
00429                 cpl_vector_set(shifts2, 2*i+1, pshifts2[1]);
00430             }
00431         }
00432 
00433         KMO_TRY_EXIT_IF_NULL(
00434                 pshifts2 = cpl_vector_get_data_const(shifts2));
00435 
00436         flux = kmo_dfs_get_parameter_bool(parlist,
00437                                           "kmos.kmo_shift.flux");
00438         KMO_TRY_CHECK_ERROR_STATE();
00439         KMO_TRY_EXIT_IF_ERROR(
00440             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_shift.flux"));
00441 
00442         KMO_TRY_ASSURE((flux == TRUE) || (flux == FALSE),
00443                        CPL_ERROR_ILLEGAL_INPUT,
00444                        "flux must be TRUE or FALSE!");
00445 
00446         wcs_only = kmo_dfs_get_parameter_bool(parlist, "kmos.kmo_shift.wcs-only");
00447         KMO_TRY_CHECK_ERROR_STATE();
00448         KMO_TRY_EXIT_IF_ERROR(
00449             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_shift.wcs-only"));
00450 
00451         KMO_TRY_ASSURE((wcs_only == TRUE) || (wcs_only == FALSE),
00452                        CPL_ERROR_NULL_INPUT,
00453                        "wcs_only must be TRUE or FALSE!");
00454 
00455         cpl_msg_info("", "-------------------------------------------");
00456 
00457         KMO_TRY_ASSURE((flux == 0) ||
00458                        (flux == 1),
00459                        CPL_ERROR_ILLEGAL_INPUT,
00460                        "flux must be either 0 or 1 !");
00461 
00462         // load descriptor of first operand
00463         KMO_TRY_EXIT_IF_NULL(
00464             frame = kmo_dfs_get_frame(frameset, "0"));
00465 
00466         desc1 = kmo_identify_fits_header(
00467                     cpl_frame_get_filename(frame));
00468         KMO_TRY_CHECK_ERROR_STATE_MSG("Provided fits file doesn't seem to be "
00469                                       "in KMOS-format!");
00470 
00471         KMO_TRY_ASSURE(desc1.fits_type == f3i_fits,
00472                        CPL_ERROR_ILLEGAL_INPUT,
00473                        "First input file hasn't correct data type "
00474                        "(KMOSTYPE must be F3I)!");
00475 
00476         // --- load, update & save primary header ---
00477         KMO_TRY_EXIT_IF_ERROR(
00478             kmo_dfs_save_main_header(frameset, SHIFT, "", frame, NULL,
00479                                      parlist, cpl_func));
00480 
00481         // --- load data ---
00482         if (desc1.ex_noise == TRUE) {
00483             nr_devices = desc1.nr_ext / 2;
00484         } else {
00485             nr_devices = desc1.nr_ext;
00486         }
00487 
00488         for (i = 1; i <= nr_devices; i++) {
00489             if (desc1.ex_noise == FALSE) {
00490                 devnr = desc1.sub_desc[i - 1].device_nr;
00491             } else {
00492                 devnr = desc1.sub_desc[2 * i - 1].device_nr;
00493             }
00494 
00495             if (desc1.ex_badpix == FALSE) {
00496                 index_data = kmo_identify_index_desc(desc1, devnr, FALSE);
00497             } else {
00498                 index_data = kmo_identify_index_desc(desc1, devnr, 2);
00499             }
00500             KMO_TRY_CHECK_ERROR_STATE();
00501 
00502             if (desc1.ex_noise) {
00503                 index_noise = kmo_identify_index_desc(desc1, devnr, TRUE);
00504             }
00505             KMO_TRY_CHECK_ERROR_STATE();
00506 
00507             KMO_TRY_EXIT_IF_NULL(
00508                 sub_header_data = kmo_dfs_load_sub_header(frameset, "0", devnr,
00509                                                           FALSE));
00510 
00511             // check if IFU is valid
00512             valid_ifu = FALSE;
00513             if (desc1.sub_desc[index_data-1].valid_data == TRUE) {
00514                 valid_ifu = TRUE;
00515             }
00516 
00517             if (desc1.ex_noise) {
00518                 // load noise anyway since we have to save it in the output
00519                 KMO_TRY_EXIT_IF_NULL(
00520                     sub_header_noise = kmo_dfs_load_sub_header(frameset, "0",
00521                                                                devnr, TRUE));
00522             }
00523 
00524             if (valid_ifu) {
00525                 // load data
00526                 KMO_TRY_EXIT_IF_NULL(
00527                     data = kmo_dfs_load_cube(frameset, "0", devnr, FALSE));
00528 
00529                 // load noise, if existing
00530                 if (desc1.ex_noise && desc1.sub_desc[index_noise-1].valid_data) {
00531                     KMO_TRY_EXIT_IF_NULL(
00532                         noise = kmo_dfs_load_cube(frameset, "0", devnr, TRUE));
00533                 }
00534 
00535                 if ((ifu == 0) || (ifu == devnr)) {
00536                     // process here
00537                     KMO_TRY_EXIT_IF_ERROR(
00538                         kmo_priv_shift(&data, &noise,
00539                                        &sub_header_data, &sub_header_noise,
00540                                        pshifts2[2*i-2] / KMOS_PIX_RESOLUTION,
00541                                        pshifts2[2*i-1] / KMOS_PIX_RESOLUTION,
00542                                        flux, devnr, method, extrapol_enum,
00543                                        wcs_only));
00544                 } else {
00545                     // leave data and noise as they are and
00546                     // save them again unshifted
00547                 }
00548 
00549                 // save data and noise (if existing)
00550                 KMO_TRY_EXIT_IF_ERROR(
00551                     kmo_dfs_save_cube(data, SHIFT, "", sub_header_data, 0./0.));
00552 
00553                 if (desc1.ex_noise) {
00554                     KMO_TRY_EXIT_IF_ERROR(
00555                         kmo_dfs_save_cube(noise, SHIFT, "", sub_header_noise, 0./0.));
00556                 }
00557 
00558                 // free memory
00559                 cpl_imagelist_delete(data); data = NULL;
00560                 cpl_imagelist_delete(noise); noise = NULL;
00561             } else {
00562                 // invalid IFU, just save sub_headers
00563                 KMO_TRY_EXIT_IF_ERROR(
00564                     kmo_dfs_save_sub_header(SHIFT, "", sub_header_data));
00565 
00566                 if (desc1.ex_noise == TRUE) {
00567                     KMO_TRY_EXIT_IF_ERROR(
00568                         kmo_dfs_save_sub_header(SHIFT, "", sub_header_noise));
00569                 }
00570             }
00571 
00572             // free memory
00573             cpl_propertylist_delete(sub_header_data); sub_header_data = NULL;
00574             cpl_propertylist_delete(sub_header_noise); sub_header_noise = NULL;
00575         }
00576     }
00577     KMO_CATCH
00578     {
00579         KMO_CATCH_MSG();
00580         ret_val = -1;
00581     }
00582 
00583     kmo_free_fits_desc(&desc1);
00584     cpl_propertylist_delete(sub_header_data); sub_header_data = NULL;
00585     cpl_propertylist_delete(sub_header_noise); sub_header_noise = NULL;
00586     cpl_imagelist_delete(data); data = NULL;
00587     cpl_imagelist_delete(noise); noise = NULL;
00588     cpl_vector_delete(shifts); shifts = NULL;
00589     cpl_vector_delete(shifts2); shifts2 = NULL;
00590 
00591     return ret_val;
00592 }
00593