KMOS Pipeline Reference Manual
1.3.0
|
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_rotate.h> 00036 00037 static int kmo_rotate_create(cpl_plugin *); 00038 static int kmo_rotate_exec(cpl_plugin *); 00039 static int kmo_rotate_destroy(cpl_plugin *); 00040 static int kmo_rotate(cpl_parameterlist *, cpl_frameset *); 00041 00042 static char kmo_rotate_description[] = 00043 "This recipe rotates a cube spatially (CCW). If the rotation angle isn't\n" 00044 "a multiple of 90 degrees, the output cube will be interpolated and get larger\n" 00045 "accordingly.\n" 00046 "By default all IFUs will be rotated.\n" 00047 "\n" 00048 "BASIC PARAMETERS:\n" 00049 "-----------------\n" 00050 "--rotations\n" 00051 "This parameter must be supplied. It contains the amount of rotation to apply.\n" 00052 "The unit is in degrees. If it contains one value (e.g. “3.5”) all IFUs are\n" 00053 "rotated by the same amount. If 24 values are supplied each IFU is rotated\n" 00054 "individually (e.g. “2.3;15.7;…;-3.3”).\n" 00055 "\n" 00056 "--imethod\n" 00057 "The interpolation method to apply when rotating an angle not being a multiple\n" 00058 "of 90. There are two methods available:\n" 00059 " * BCS: Bicubic spline\n" 00060 " * NN: Nearest Neighbor (currently disabled)\n" 00061 "\n" 00062 "--ifu\n" 00063 "If a single IFU should be rotated, it can be defined using the --ifu parameter\n" 00064 "(--rotations parameter contains only one value).\n" 00065 "\n" 00066 "ADVANCED PARAMETERS\n" 00067 "-------------------\n" 00068 "--flux\n" 00069 "Specify if flux conservation should be applied.\n" 00070 "\n" 00071 "--extrapolate\n" 00072 "By default the output frame grows when rotating an angle not being a multiple\n" 00073 "of 90. In this case none of the input data is lost. When it is desired to keep\n" 00074 "the same size as the input frame this parameter can be set to TRUE and the\n" 00075 "data will be clipped.\n" 00076 "\n" 00077 "-------------------------------------------------------------------------------\n" 00078 " Input files:\n" 00079 "\n" 00080 " DO KMOS \n" 00081 " category Type Explanation Required #Frames\n" 00082 " -------- ----- ----------- -------- -------\n" 00083 " <none or any> F3I data frame Y 1 \n" 00084 "\n" 00085 " Output files:\n" 00086 "\n" 00087 " DO KMOS\n" 00088 " category Type Explanation\n" 00089 " -------- ----- -----------\n" 00090 " ROTATE F3I Rotated data cube\n" 00091 "-------------------------------------------------------------------------------\n" 00092 "\n"; 00093 00110 int cpl_plugin_get_info(cpl_pluginlist *list) 00111 { 00112 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe); 00113 cpl_plugin *plugin = &recipe->interface; 00114 00115 cpl_plugin_init(plugin, 00116 CPL_PLUGIN_API, 00117 KMOS_BINARY_VERSION, 00118 CPL_PLUGIN_TYPE_RECIPE, 00119 "kmo_rotate", 00120 "Rotate a cube spatially", 00121 kmo_rotate_description, 00122 "Alex Agudo Berbel", 00123 "usd-help@eso.org", 00124 kmos_get_license(), 00125 kmo_rotate_create, 00126 kmo_rotate_exec, 00127 kmo_rotate_destroy); 00128 00129 cpl_pluginlist_append(list, plugin); 00130 00131 return 0; 00132 } 00133 00141 static int kmo_rotate_create(cpl_plugin *plugin) 00142 { 00143 cpl_recipe *recipe; 00144 cpl_parameter *p; 00145 00146 /* Check that the plugin is part of a valid recipe */ 00147 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00148 recipe = (cpl_recipe *)plugin; 00149 else 00150 return -1; 00151 00152 /* Create the parameters list in the cpl_recipe object */ 00153 recipe->parameters = cpl_parameterlist_new(); 00154 00155 /* Fill the parameters list */ 00156 /* --imethod */ 00157 p = cpl_parameter_new_value("kmos.kmo_rotate.imethod", 00158 CPL_TYPE_STRING, 00159 "Method to use for interpolation: " 00160 "[\"BCS\" (bicubic spline, default), " 00161 "\"NN\" (nearest neighbor), not implemented yet]", 00162 "kmos.kmo_rotate", 00163 "BCS"); 00164 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "imethod"); 00165 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00166 cpl_parameterlist_append(recipe->parameters, p); 00167 00168 /* --extrapolate */ 00169 p = cpl_parameter_new_value("kmos.kmo_rotate.extrapolate", 00170 CPL_TYPE_BOOL, 00171 "Applies only when rotation angle is different " 00172 "from multiples of 90 degrees: " 00173 "FALSE: Output IFU will be larger than the input " 00174 "(Default), " 00175 "TRUE: The size of input and output IFU remains " 00176 "the same. Data will be clipped.", 00177 "kmos.kmo_rotate", 00178 FALSE); 00179 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extrapolate"); 00180 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00181 cpl_parameterlist_append(recipe->parameters, p); 00182 00183 /* --rotations */ 00184 p = cpl_parameter_new_value("kmos.kmo_rotate.rotations", 00185 CPL_TYPE_STRING, 00186 "The rotations for all specified IFUs. " 00187 "\"rot1;rot2;...\" (degrees)", 00188 "kmos.kmo_rotate", 00189 ""); 00190 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rotations"); 00191 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00192 cpl_parameterlist_append(recipe->parameters, p); 00193 00194 /* --ifu */ 00195 p = cpl_parameter_new_value("kmos.kmo_rotate.ifu", 00196 CPL_TYPE_INT, 00197 "The IFU to rotate [1 to 24] or rotate all IFUs " 00198 "[0, default].", 00199 "kmos.kmo_rotate", 00200 0); 00201 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ifu"); 00202 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00203 cpl_parameterlist_append(recipe->parameters, p); 00204 00205 /* --flux */ 00206 p = cpl_parameter_new_value("kmos.kmo_rotate.flux", 00207 CPL_TYPE_BOOL, 00208 "Apply flux conservation: " 00209 "(TRUE (apply) or " 00210 "FALSE (don't apply)", 00211 "kmos.kmo_rotate", 00212 FALSE); 00213 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux"); 00214 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00215 cpl_parameterlist_append(recipe->parameters, p); 00216 00217 return 0; 00218 } 00219 00225 static int kmo_rotate_exec(cpl_plugin *plugin) 00226 { 00227 cpl_recipe *recipe; 00228 00229 /* Get the recipe out of the plugin */ 00230 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00231 recipe = (cpl_recipe *)plugin; 00232 else return -1 ; 00233 00234 return kmo_rotate(recipe->parameters, recipe->frames); 00235 } 00236 00242 static int kmo_rotate_destroy(cpl_plugin *plugin) 00243 { 00244 cpl_recipe *recipe; 00245 00246 /* Get the recipe out of the plugin */ 00247 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00248 recipe = (cpl_recipe *)plugin; 00249 else return -1 ; 00250 00251 cpl_parameterlist_delete(recipe->parameters); 00252 return 0 ; 00253 } 00254 00269 static int kmo_rotate(cpl_parameterlist *parlist, cpl_frameset *frameset) 00270 { 00271 const char *method = NULL, 00272 *rotations_txt = NULL; 00273 00274 cpl_imagelist *data = NULL, 00275 *noise = NULL; 00276 00277 cpl_vector *rotations = NULL, 00278 *rotations2 = NULL; 00279 00280 int ret_val = 0, 00281 nr_devices = 0, 00282 i = 0, 00283 valid_ifu = FALSE, 00284 flux = 0, 00285 size = 0, 00286 ifu = 0, 00287 extrapolate = 0, 00288 devnr = 0, 00289 index_data = 0, 00290 index_noise = 0; 00291 00292 enum extrapolationType extrapol_enum = 0; 00293 00294 const double *protations2 = NULL; 00295 00296 cpl_propertylist *sub_header_data = NULL, 00297 *sub_header_noise = NULL; 00298 00299 cpl_frame *frame = NULL; 00300 00301 main_fits_desc desc1; 00302 00303 KMO_TRY 00304 { 00305 kmo_init_fits_desc(&desc1); 00306 00307 /* --- check input --- */ 00308 KMO_TRY_ASSURE((parlist != NULL) && 00309 (frameset != NULL), 00310 CPL_ERROR_NULL_INPUT, 00311 "Not all input data is provided!"); 00312 00313 KMO_TRY_ASSURE(cpl_frameset_get_size(frameset) == 1, 00314 CPL_ERROR_NULL_INPUT, 00315 "A cube must be provided!"); 00316 00317 KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_rotate") == 1, 00318 CPL_ERROR_ILLEGAL_INPUT, 00319 "Cannot identify RAW and CALIB frames!"); 00320 00321 cpl_msg_info("", "--- Parameter setup for kmo_rotate --------"); 00322 00323 KMO_TRY_EXIT_IF_NULL( 00324 method = kmo_dfs_get_parameter_string(parlist, 00325 "kmos.kmo_rotate.imethod")); 00326 KMO_TRY_EXIT_IF_ERROR( 00327 kmo_dfs_print_parameter_help(parlist, "kmos.kmo_rotate.imethod")); 00328 00329 extrapolate = kmo_dfs_get_parameter_bool(parlist, 00330 "kmos.kmo_rotate.extrapolate"); 00331 KMO_TRY_CHECK_ERROR_STATE(); 00332 00333 if (extrapolate == 1) { 00334 extrapol_enum = NONE_NANS; 00335 } else if (extrapolate == 0) { 00336 extrapol_enum = RESIZE_NANS; 00337 } else { 00338 KMO_TRY_ASSURE(1 == 0, 00339 CPL_ERROR_ILLEGAL_INPUT, 00340 "extrapolate must be 1 or 0!"); 00341 } 00342 00343 KMO_TRY_EXIT_IF_ERROR( 00344 kmo_dfs_print_parameter_help(parlist, "kmos.kmo_rotate.extrapolate")); 00345 00346 rotations_txt = kmo_dfs_get_parameter_string(parlist, 00347 "kmos.kmo_rotate.rotations"); 00348 KMO_TRY_CHECK_ERROR_STATE(); 00349 KMO_TRY_EXIT_IF_ERROR( 00350 kmo_dfs_print_parameter_help(parlist, "kmos.kmo_rotate.rotations")); 00351 00352 KMO_TRY_ASSURE(strcmp(rotations_txt, "") != 0, 00353 CPL_ERROR_ILLEGAL_INPUT, 00354 "At least one value for --rotations parameter must be " 00355 "provided!"); 00356 00357 rotations = kmo_identify_values(rotations_txt); 00358 KMO_TRY_CHECK_ERROR_STATE(); 00359 00360 size = cpl_vector_get_size(rotations); 00361 KMO_TRY_CHECK_ERROR_STATE(); 00362 00363 KMO_TRY_ASSURE((size == 1) || (size == KMOS_NR_IFUS), 00364 CPL_ERROR_ILLEGAL_INPUT, 00365 "rotations parameter must have either one or 24 elements!"); 00366 00367 ifu = kmo_dfs_get_parameter_int(parlist, "kmos.kmo_rotate.ifu"); 00368 KMO_TRY_CHECK_ERROR_STATE(); 00369 KMO_TRY_EXIT_IF_ERROR( 00370 kmo_dfs_print_parameter_help(parlist, "kmos.kmo_rotate.ifu")); 00371 00372 if (ifu == 0) { 00373 // rotate all IFUs the same or different amounts 00374 KMO_TRY_ASSURE((size == 1) || (size == KMOS_NR_IFUS), 00375 CPL_ERROR_ILLEGAL_INPUT, 00376 "rotations parameter must have exactly 1 elements" 00377 "(rotate all IFUs the same amount) or 24 elements " 00378 "(rotate all IFUs individually)!"); 00379 } else { 00380 // rotate only one specific IFU 00381 KMO_TRY_ASSURE(size == 1, 00382 CPL_ERROR_ILLEGAL_INPUT, 00383 "rotations parameter must have exactly one elements " 00384 "to rotate a single IFU!"); 00385 } 00386 00387 // setup a vector of length 24 regardless of how many IFUs to rotate 00388 if (size == KMOS_NR_IFUS) { 00389 KMO_TRY_EXIT_IF_NULL( 00390 rotations2 = cpl_vector_duplicate(rotations)); 00391 } else { 00392 KMO_TRY_EXIT_IF_NULL( 00393 rotations2 = cpl_vector_new(KMOS_NR_IFUS)); 00394 KMO_TRY_EXIT_IF_NULL( 00395 protations2 = cpl_vector_get_data_const(rotations)); 00396 for (i = 0; i < KMOS_NR_IFUS; i++) { 00397 cpl_vector_set(rotations2, i, protations2[0]); 00398 } 00399 } 00400 00401 KMO_TRY_EXIT_IF_NULL( 00402 protations2 = cpl_vector_get_data_const(rotations2)); 00403 00404 KMO_TRY_ASSURE((strcmp(method, "NN") == 0) || 00405 (strcmp(method, "BCS") == 0) 00406 /*(strcmp(method, "kriging") == 0) || 00407 (strcmp(method, "cubic") == 0) || 00408 (strcmp(method, "shepard") == 0) || 00409 (strcmp(method, "drizzle") == 0)*/, 00410 CPL_ERROR_ILLEGAL_INPUT, 00411 "method must be \"BCS\"!"); 00412 00413 flux = kmo_dfs_get_parameter_bool(parlist, 00414 "kmos.kmo_rotate.flux"); 00415 KMO_TRY_CHECK_ERROR_STATE(); 00416 KMO_TRY_EXIT_IF_ERROR( 00417 kmo_dfs_print_parameter_help(parlist, "kmos.kmo_rotate.flux")); 00418 00419 cpl_msg_info("", "-------------------------------------------"); 00420 00421 KMO_TRY_ASSURE((flux == 0) || 00422 (flux == 1), 00423 CPL_ERROR_ILLEGAL_INPUT, 00424 "flux must be either 0 or 1 !"); 00425 00426 // load descriptor of first operand 00427 KMO_TRY_EXIT_IF_NULL( 00428 frame = kmo_dfs_get_frame(frameset, "0")); 00429 00430 desc1 = kmo_identify_fits_header( 00431 cpl_frame_get_filename(frame)); 00432 KMO_TRY_CHECK_ERROR_STATE_MSG("Provided fits file doesn't seem to be " 00433 "in KMOS-format!"); 00434 00435 KMO_TRY_ASSURE(desc1.fits_type == f3i_fits, 00436 CPL_ERROR_ILLEGAL_INPUT, 00437 "First input file hasn't correct data type " 00438 "(KMOSTYPE must be F3I)!"); 00439 00440 // --- load, update & save primary header --- 00441 KMO_TRY_EXIT_IF_ERROR( 00442 kmo_dfs_save_main_header(frameset, ROTATE, "", frame, 00443 NULL, parlist, cpl_func)); 00444 00445 // --- load data --- 00446 if (desc1.ex_noise == TRUE) { 00447 nr_devices = desc1.nr_ext / 2; 00448 } else { 00449 nr_devices = desc1.nr_ext; 00450 } 00451 00452 for (i = 1; i <= nr_devices; i++) { 00453 if (desc1.ex_noise == FALSE) { 00454 devnr = desc1.sub_desc[i - 1].device_nr; 00455 } else { 00456 devnr = desc1.sub_desc[2 * i - 1].device_nr; 00457 } 00458 00459 if (desc1.ex_badpix == FALSE) { 00460 index_data = kmo_identify_index_desc(desc1, devnr, FALSE); 00461 } else { 00462 index_data = kmo_identify_index_desc(desc1, devnr, 2); 00463 } 00464 KMO_TRY_CHECK_ERROR_STATE(); 00465 00466 if (desc1.ex_noise) { 00467 index_noise = kmo_identify_index_desc(desc1, devnr, TRUE); 00468 } 00469 KMO_TRY_CHECK_ERROR_STATE(); 00470 00471 KMO_TRY_EXIT_IF_NULL( 00472 sub_header_data = kmo_dfs_load_sub_header(frameset, "0", devnr, 00473 FALSE)); 00474 00475 // check if IFU is valid 00476 valid_ifu = FALSE; 00477 if (desc1.sub_desc[index_data-1].valid_data == TRUE) { 00478 valid_ifu = TRUE; 00479 } 00480 00481 if (desc1.ex_noise) { 00482 // load noise anyway since we have to save it in the output 00483 KMO_TRY_EXIT_IF_NULL( 00484 sub_header_noise = kmo_dfs_load_sub_header(frameset, "0", 00485 devnr, TRUE)); 00486 } 00487 00488 if (valid_ifu) { 00489 // load data 00490 KMO_TRY_EXIT_IF_NULL( 00491 data = kmo_dfs_load_cube(frameset, "0", devnr, FALSE)); 00492 00493 // load noise, if existing 00494 if (desc1.ex_noise && desc1.sub_desc[index_noise-1].valid_data) { 00495 KMO_TRY_EXIT_IF_NULL( 00496 noise = kmo_dfs_load_cube(frameset, "0", devnr, TRUE)); 00497 } 00498 00499 if ((ifu == 0) || (ifu == devnr)) { 00500 // process here 00501 KMO_TRY_EXIT_IF_ERROR( 00502 kmo_priv_rotate(&data, &noise, 00503 &sub_header_data, &sub_header_noise, 00504 protations2[i-1], 00505 flux, devnr, method, extrapol_enum)); 00506 } else { 00507 // leave data and noise as they are and 00508 // save them again unrotated 00509 } 00510 00511 // save data and noise (if existing) 00512 KMO_TRY_EXIT_IF_ERROR( 00513 kmo_dfs_save_cube(data, ROTATE, "", sub_header_data, 0./0.)); 00514 00515 if (desc1.ex_noise) { 00516 KMO_TRY_EXIT_IF_ERROR( 00517 kmo_dfs_save_cube(noise, ROTATE, "", sub_header_noise, 00518 0./0.)); 00519 } 00520 00521 // free memory 00522 cpl_imagelist_delete(data); data = NULL; 00523 cpl_imagelist_delete(noise); noise = NULL; 00524 } else { 00525 // invalid IFU, just save sub_headers 00526 KMO_TRY_EXIT_IF_ERROR( 00527 kmo_dfs_save_sub_header(ROTATE, "", sub_header_data)); 00528 00529 if (desc1.ex_noise) { 00530 KMO_TRY_EXIT_IF_ERROR( 00531 kmo_dfs_save_sub_header(ROTATE, "", sub_header_noise)); 00532 } 00533 } 00534 00535 // free memory 00536 cpl_propertylist_delete(sub_header_data); sub_header_data = NULL; 00537 cpl_propertylist_delete(sub_header_noise); sub_header_noise = NULL; 00538 } 00539 } 00540 KMO_CATCH 00541 { 00542 KMO_CATCH_MSG(); 00543 ret_val = -1; 00544 } 00545 00546 kmo_free_fits_desc(&desc1); 00547 cpl_propertylist_delete(sub_header_data); sub_header_data = NULL; 00548 cpl_propertylist_delete(sub_header_noise); sub_header_noise = NULL; 00549 cpl_imagelist_delete(data); data = NULL; 00550 cpl_imagelist_delete(noise); noise = NULL; 00551 cpl_vector_delete(rotations); rotations = NULL; 00552 cpl_vector_delete(rotations2); rotations2 = NULL; 00553 00554 return ret_val; 00555 } 00556