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