32#include <kmo_priv_functions.h>
33#include <kmo_cpl_extensions.h>
34#include <kmo_constants.h>
35#include <kmo_priv_shift.h>
37static int kmo_shift_create(cpl_plugin *);
38static int kmo_shift_exec(cpl_plugin *);
39static int kmo_shift_destroy(cpl_plugin *);
40static int kmo_shift(cpl_parameterlist *, cpl_frameset *);
42static char kmo_shift_description[] =
43"This recipe shifts a cube spatially. A positive x-shift shifts the data to the\n"
44"left, a positive y-shift shifts upwards, where a shift of one pixel equals\n"
45"0.2arcsec. The output will still have the same dimensions, but the borders \n"
46"will be filled with NaNs accordingly.\n"
51"This parameter must be supplied. It contains the amount of shift to apply. The\n"
52"unit is in arcsec. If the --shifts parameter contains only two values (x,y),\n"
53"all IFUs will be shifted by the same amount. If it contains 48 values\n"
54"(x1,y1;x2,y2;...;x24,y24), the IFUs are shifted individually.\n"
57"The interpolation method to apply when the shift value isn’t a multiple of the\n"
58"pixel scale. There are two methods available:\n"
59" * BCS: Bicubic spline\n"
60" * NN: Nearest Neighbor\n"
63"If a single IFU should be shifted, it can be defined using the --ifu parameter\n"
64"(--shifts parameter contains only two values).\n"
66"ADVANCED PARAMETERS\n"
67"-------------------\n"
69"Specify if flux conservation should be applied.\n"
72"By default no extrapolation is applied. This means that the output frame will\n"
73"shrink at most one pixel, because the data is shifted out of the frame. When\n"
74"turning extrapolation on, the size of the output frame stays the same as for\n"
77"-------------------------------------------------------------------------------\n"
81" category Type Explanation Required #Frames\n"
82" -------- ----- ----------- -------- -------\n"
83" <none or any> F3I data frame Y 1 \n"
88" category Type Explanation\n"
89" -------- ----- -----------\n"
90" SHIFT F3I Shifted data cube\n"
91"-------------------------------------------------------------------------------\n"
112 cpl_recipe *recipe = cpl_calloc(1,
sizeof *recipe);
113 cpl_plugin *plugin = &recipe->interface;
115 cpl_plugin_init(plugin,
118 CPL_PLUGIN_TYPE_RECIPE,
120 "Shift a cube spatially",
121 kmo_shift_description,
123 "https://support.eso.org/",
129 cpl_pluginlist_append(list, plugin);
141static int kmo_shift_create(cpl_plugin *plugin)
147 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
148 recipe = (cpl_recipe *)plugin;
153 recipe->parameters = cpl_parameterlist_new();
157 p = cpl_parameter_new_value(
"kmos.kmo_shift.imethod",
159 "Method to use for interpolation.\n"
160 "[\"BCS\" (bicubic spline, default), "
161 "\"NN\" (nearest neighbor)]",
164 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"imethod");
165 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
166 cpl_parameterlist_append(recipe->parameters, p);
169 p = cpl_parameter_new_value(
"kmos.kmo_shift.extrapolate",
171 "Applies only to 'method=BCS' when doing sub-"
173 "FALSE: shifted IFU will be filled with NaN's "
175 "TRUE: shifted IFU will be extrapolated at "
179 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"extrapolate");
180 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
181 cpl_parameterlist_append(recipe->parameters, p);
184 p = cpl_parameter_new_value(
"kmos.kmo_shift.shifts",
186 "The shifts for each spatial dimension for all "
188 "\"x1,y1;x2,y2;...\" (arcsec)",
191 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"shifts");
192 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
193 cpl_parameterlist_append(recipe->parameters, p);
196 p = cpl_parameter_new_value(
"kmos.kmo_shift.ifu",
198 "The IFU to shift [1 to 24] or shift all IFUs "
199 "Default value of 0 applies shift to all IFUs.",
202 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ifu");
203 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
204 cpl_parameterlist_append(recipe->parameters, p);
207 p = cpl_parameter_new_value(
"kmos.kmo_shift.flux",
209 "Apply flux conservation: "
211 "FALSE (don't apply)",
214 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"flux");
215 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
216 cpl_parameterlist_append(recipe->parameters, p);
226static int kmo_shift_exec(cpl_plugin *plugin)
231 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
232 recipe = (cpl_recipe *)plugin;
235 return kmo_shift(recipe->parameters, recipe->frames);
243static int kmo_shift_destroy(cpl_plugin *plugin)
248 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
249 recipe = (cpl_recipe *)plugin;
252 cpl_parameterlist_delete(recipe->parameters);
270static int kmo_shift(cpl_parameterlist *parlist, cpl_frameset *frameset)
272 const char *method = NULL,
275 cpl_imagelist *data = NULL,
278 cpl_vector *shifts = NULL,
293 enum extrapolationType extrapol_enum = 0;
295 const double *pshifts2 = NULL;
297 cpl_propertylist *sub_header_data = NULL,
298 *sub_header_noise = NULL;
300 cpl_frame *frame = NULL;
302 main_fits_desc desc1;
306 kmo_init_fits_desc(&desc1);
309 KMO_TRY_ASSURE((parlist != NULL) &&
311 CPL_ERROR_NULL_INPUT,
312 "Not all input data is provided!");
314 KMO_TRY_ASSURE(cpl_frameset_get_size(frameset) == 1,
315 CPL_ERROR_NULL_INPUT,
316 "A cube must be provided!");
318 KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset) == 1,
319 CPL_ERROR_ILLEGAL_INPUT,
320 "Cannot identify RAW and CALIB frames!");
322 cpl_msg_info(
"",
"--- Parameter setup for kmo_shift ---------");
324 KMO_TRY_EXIT_IF_NULL(
325 method = kmo_dfs_get_parameter_string(parlist,
326 "kmos.kmo_shift.imethod"));
327 KMO_TRY_EXIT_IF_ERROR(
328 kmo_dfs_print_parameter_help(parlist,
"kmos.kmo_shift.imethod"));
330 extrapolate = kmo_dfs_get_parameter_bool(parlist,
331 "kmos.kmo_shift.extrapolate");
332 KMO_TRY_CHECK_ERROR_STATE();
334 if (strcmp(method,
"NN") == 0) {
335 extrapol_enum = NONE_NANS;
336 }
else if (strcmp(method,
"BCS") == 0) {
337 if (extrapolate == FALSE) {
338 extrapol_enum = NONE_NANS;
339 }
else if (extrapolate == TRUE) {
340 extrapol_enum = BCS_NATURAL;
342 KMO_TRY_ASSURE(1 == 0,
343 CPL_ERROR_ILLEGAL_INPUT,
344 "extrapolate must either FALSE or TRUE!");
347 KMO_TRY_ASSURE(1 == 0,
348 CPL_ERROR_ILLEGAL_INPUT,
349 "method must be either \"BCS\" or \"NN\" !");
352 KMO_TRY_EXIT_IF_ERROR(
353 kmo_dfs_print_parameter_help(parlist,
"kmos.kmo_shift.extrapolate"));
355 shifts_txt = kmo_dfs_get_parameter_string(parlist,
356 "kmos.kmo_shift.shifts");
357 KMO_TRY_CHECK_ERROR_STATE();
358 KMO_TRY_EXIT_IF_ERROR(
359 kmo_dfs_print_parameter_help(parlist,
"kmos.kmo_shift.shifts"));
361 KMO_TRY_ASSURE(strcmp(shifts_txt,
"") != 0,
362 CPL_ERROR_ILLEGAL_INPUT,
363 "At least two values for --shifts parameter must be "
366 shifts = kmo_identify_ranges(shifts_txt);
367 KMO_TRY_CHECK_ERROR_STATE();
369 size = cpl_vector_get_size(shifts);
370 KMO_TRY_CHECK_ERROR_STATE();
372 KMO_TRY_ASSURE((size % 2) == 0,
373 CPL_ERROR_ILLEGAL_INPUT,
374 "shifts parameter must have an even number of elements!");
376 ifu = kmo_dfs_get_parameter_int(parlist,
"kmos.kmo_shift.ifu");
377 KMO_TRY_CHECK_ERROR_STATE();
378 KMO_TRY_EXIT_IF_ERROR(
379 kmo_dfs_print_parameter_help(parlist,
"kmos.kmo_shift.ifu"));
383 KMO_TRY_ASSURE((size == 2) || (size == 2*KMOS_NR_IFUS),
384 CPL_ERROR_ILLEGAL_INPUT,
385 "shifts parameter must have exactly 2 elements"
386 "(shift all IFUs the same amount) or 48 elements "
387 "(shift all IFUs individually)!");
390 KMO_TRY_ASSURE(size == 2,
391 CPL_ERROR_ILLEGAL_INPUT,
392 "shifts parameter must have exactly 2 elements to "
393 "shift a single IFU!");
397 if (size == 2*KMOS_NR_IFUS) {
398 KMO_TRY_EXIT_IF_NULL(
399 shifts2 = cpl_vector_duplicate(shifts));
401 KMO_TRY_EXIT_IF_NULL(
402 shifts2 = cpl_vector_new(2*KMOS_NR_IFUS));
403 KMO_TRY_EXIT_IF_NULL(
404 pshifts2 = cpl_vector_get_data_const(shifts));
405 for (i = 0; i < KMOS_NR_IFUS; i++) {
406 cpl_vector_set(shifts2, 2*i, pshifts2[0]);
407 cpl_vector_set(shifts2, 2*i+1, pshifts2[1]);
411 KMO_TRY_EXIT_IF_NULL(
412 pshifts2 = cpl_vector_get_data_const(shifts2));
414 flux = kmo_dfs_get_parameter_bool(parlist,
415 "kmos.kmo_shift.flux");
416 KMO_TRY_CHECK_ERROR_STATE();
417 KMO_TRY_EXIT_IF_ERROR(
418 kmo_dfs_print_parameter_help(parlist,
"kmos.kmo_shift.flux"));
420 KMO_TRY_ASSURE((flux == TRUE) || (flux == FALSE),
421 CPL_ERROR_ILLEGAL_INPUT,
422 "flux must be TRUE or FALSE!");
424 KMO_TRY_CHECK_ERROR_STATE();
426 cpl_msg_info(
"",
"-------------------------------------------");
428 KMO_TRY_ASSURE((flux == 0) ||
430 CPL_ERROR_ILLEGAL_INPUT,
431 "flux must be either 0 or 1 !");
434 KMO_TRY_EXIT_IF_NULL(
435 frame = kmo_dfs_get_frame(frameset,
"0"));
437 desc1 = kmo_identify_fits_header(
438 cpl_frame_get_filename(frame));
439 KMO_TRY_CHECK_ERROR_STATE_MSG(
"Provided fits file doesn't seem to be "
442 KMO_TRY_ASSURE(desc1.fits_type == f3i_fits,
443 CPL_ERROR_ILLEGAL_INPUT,
444 "First input file hasn't correct data type "
445 "(KMOSTYPE must be F3I)!");
448 KMO_TRY_EXIT_IF_ERROR(
449 kmo_dfs_save_main_header(frameset, SHIFT,
"", frame, NULL,
453 if (desc1.ex_noise == TRUE) {
454 nr_devices = desc1.nr_ext / 2;
456 nr_devices = desc1.nr_ext;
459 for (i = 1; i <= nr_devices; i++) {
460 if (desc1.ex_noise == FALSE) {
461 devnr = desc1.sub_desc[i - 1].device_nr;
463 devnr = desc1.sub_desc[2 * i - 1].device_nr;
466 if (desc1.ex_badpix == FALSE) {
467 index_data = kmo_identify_index_desc(desc1, devnr, FALSE);
469 index_data = kmo_identify_index_desc(desc1, devnr, 2);
471 KMO_TRY_CHECK_ERROR_STATE();
473 if (desc1.ex_noise) {
474 index_noise = kmo_identify_index_desc(desc1, devnr, TRUE);
476 KMO_TRY_CHECK_ERROR_STATE();
478 KMO_TRY_EXIT_IF_NULL(
479 sub_header_data = kmo_dfs_load_sub_header(frameset,
"0", devnr,
484 if (desc1.sub_desc[index_data-1].valid_data == TRUE) {
488 if (desc1.ex_noise) {
490 KMO_TRY_EXIT_IF_NULL(
491 sub_header_noise = kmo_dfs_load_sub_header(frameset,
"0",
497 KMO_TRY_EXIT_IF_NULL(
498 data = kmo_dfs_load_cube(frameset,
"0", devnr, FALSE));
501 if (desc1.ex_noise && desc1.sub_desc[index_noise-1].valid_data) {
502 KMO_TRY_EXIT_IF_NULL(
503 noise = kmo_dfs_load_cube(frameset,
"0", devnr, TRUE));
506 if ((ifu == 0) || (ifu == devnr)) {
508 KMO_TRY_EXIT_IF_ERROR(
509 kmo_priv_shift(&data, &noise,
510 &sub_header_data, &sub_header_noise,
511 pshifts2[2*i-2] / KMOS_PIX_RESOLUTION,
512 pshifts2[2*i-1] / KMOS_PIX_RESOLUTION,
513 flux, method, extrapol_enum));
520 KMO_TRY_EXIT_IF_ERROR(
521 kmo_dfs_save_cube(data, SHIFT,
"", sub_header_data, 0./0.));
523 if (desc1.ex_noise) {
524 KMO_TRY_EXIT_IF_ERROR(
525 kmo_dfs_save_cube(noise, SHIFT,
"", sub_header_noise, 0./0.));
529 cpl_imagelist_delete(data); data = NULL;
530 cpl_imagelist_delete(noise); noise = NULL;
533 KMO_TRY_EXIT_IF_ERROR(
534 kmo_dfs_save_sub_header(SHIFT,
"", sub_header_data));
536 if (desc1.ex_noise == TRUE) {
537 KMO_TRY_EXIT_IF_ERROR(
538 kmo_dfs_save_sub_header(SHIFT,
"", sub_header_noise));
543 cpl_propertylist_delete(sub_header_data); sub_header_data = NULL;
544 cpl_propertylist_delete(sub_header_noise); sub_header_noise = NULL;
553 kmo_free_fits_desc(&desc1);
554 cpl_propertylist_delete(sub_header_data); sub_header_data = NULL;
555 cpl_propertylist_delete(sub_header_noise); sub_header_noise = NULL;
556 cpl_imagelist_delete(data); data = NULL;
557 cpl_imagelist_delete(noise); noise = NULL;
558 cpl_vector_delete(shifts); shifts = NULL;
559 cpl_vector_delete(shifts2); shifts2 = NULL;
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.