36#include "kmo_priv_extract_spec.h"
37#include "kmo_priv_functions.h"
38#include "kmo_cpl_extensions.h"
39#include "kmo_constants.h"
40#include "kmo_priv_fit_profile.h"
47static int kmos_extract_spec_create(cpl_plugin *);
48static int kmos_extract_spec_exec(cpl_plugin *);
49static int kmos_extract_spec_destroy(cpl_plugin *);
50static int kmos_extract_spec(cpl_parameterlist *, cpl_frameset *);
56static char kmos_extract_spec_description[] =
57"This recipe extracts a spectrum from a datacube. The datacube is with or \n"
58"without noise). The output will be a similarly formatted FITS file.\n"
60"---------------------------------------------------------------------------\n"
64" category Type Explanation Required #Frames\n"
65" -------- ----- ----------- -------- -------\n"
66" <none or any> F3I The datacubes Y 1 \n"
67" <none or any> F2I The mask N 0,1 \n"
72" category Type Explanation\n"
73" -------- ----- -----------\n"
74" EXTRACT_SPEC F1I Extracted spectrum \n"
75" EXTRACT_SPEC_MASK F2I (optional, if --save_mask=true and \n"
76" --mask_method='optimal': The calculated mask) \n"
77"---------------------------------------------------------------------------\n"
104 cpl_recipe *recipe = cpl_calloc(1,
sizeof *recipe);
105 cpl_plugin *plugin = &recipe->interface;
107 cpl_plugin_init(plugin,
110 CPL_PLUGIN_TYPE_RECIPE,
112 "Extract a spectrum from a cube",
113 kmos_extract_spec_description,
114 "Alex Agudo Berbel, Y. Jung",
115 "https://support.eso.org/",
117 kmos_extract_spec_create,
118 kmos_extract_spec_exec,
119 kmos_extract_spec_destroy);
121 cpl_pluginlist_append(list, plugin);
134static int kmos_extract_spec_create(cpl_plugin *plugin)
140 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
141 recipe = (cpl_recipe *)plugin;
146 recipe->parameters = cpl_parameterlist_new();
150 p = cpl_parameter_new_value(
"kmos.kmos_extract_spec.mask_method",
151 CPL_TYPE_STRING,
"Method used : mask, integrated or optimal",
152 "kmos.kmos_extract_spec",
"integrated");
153 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"mask_method");
154 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
155 cpl_parameterlist_append(recipe->parameters, p);
158 p = cpl_parameter_new_value(
"kmos.kmos_extract_spec.centre",
159 CPL_TYPE_STRING,
"The centre of the circular mask (pixel)",
160 "kmos.kmos_extract_spec",
"7.5,7.5");
161 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"centre");
162 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
163 cpl_parameterlist_append(recipe->parameters, p);
166 p = cpl_parameter_new_value(
"kmos.kmos_extract_spec.radius",
167 CPL_TYPE_DOUBLE,
"The radius of the circular mask (pixel)",
168 "kmos.kmos_extract_spec", 3.0);
169 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"radius");
170 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
171 cpl_parameterlist_append(recipe->parameters, p);
174 p = cpl_parameter_new_value(
"kmos.kmos_extract_spec.save_mask",
175 CPL_TYPE_BOOL,
"Flag to save the mask",
"kmos.kmos_extract_spec",
177 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"save_mask");
178 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
179 cpl_parameterlist_append(recipe->parameters, p);
182 p = cpl_parameter_new_value(
"kmos.kmos_extract_spec.extra_outputs",
183 CPL_TYPE_BOOL,
"Flag to save extra outputs",
184 "kmos.kmos_extract_spec", FALSE);
185 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"extra_outputs");
186 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
187 cpl_parameterlist_append(recipe->parameters, p);
189 return kmos_combine_pars_create(recipe->parameters,
190 "kmos.kmos_extract_spec", DEF_REJ_METHOD, FALSE);
200static int kmos_extract_spec_exec(cpl_plugin *plugin)
205 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
206 recipe = (cpl_recipe *)plugin;
209 return kmos_extract_spec(recipe->parameters, recipe->frames);
219static int kmos_extract_spec_destroy(cpl_plugin *plugin)
224 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
225 recipe = (cpl_recipe *)plugin;
228 cpl_parameterlist_delete(recipe->parameters);
247static int kmos_extract_spec(
248 cpl_parameterlist * parlist,
249 cpl_frameset * frameset)
251 const cpl_parameter * par ;
252 const char * mask_method ;
253 const char * cmethod ;
254 const char * centre_txt ;
255 cpl_vector * centre ;
256 int cmin, cmax, valid_ifu, citer, save_mask,
257 devnr1, extra_outputs;
261 double cpos_rej, cneg_rej, r, x_lo, y_lo,
262 x_hi, y_hi, loc_cen_x, loc_cen_y ;
263 double cen_x = 0., cen_y = 0., radius = -1;
264 cpl_size auto_cen_x, auto_cen_y ;
265 cpl_imagelist * data_in ;
266 cpl_imagelist * noise_in ;
268 cpl_image * made_data_img ;
269 cpl_vector * spec_data_out ;
270 cpl_vector * spec_noise_out ;
271 cpl_vector * fit_par ;
272 cpl_propertylist * sub_header_data ;
273 cpl_propertylist * sub_header_noise = NULL ;
274 cpl_propertylist * sub_header_mask ;
275 cpl_propertylist * fit_pl ;
276 cpl_frame * op1_frame ;
277 cpl_frame * op2_frame ;
279 main_fits_desc desc1, desc2;
283 if (parlist == NULL || frameset == NULL) {
284 cpl_msg_error(__func__,
"Null Inputs") ;
285 cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
290 spec_data_out = spec_noise_out = NULL ;
293 par = cpl_parameterlist_find_const(parlist,
294 "kmos.kmos_extract_spec.save_mask");
295 save_mask = cpl_parameter_get_bool(par);
296 par = cpl_parameterlist_find_const(parlist,
297 "kmos.kmos_extract_spec.extra_outputs");
298 extra_outputs = cpl_parameter_get_bool(par);
299 par = cpl_parameterlist_find_const(parlist,
300 "kmos.kmos_extract_spec.mask_method");
301 mask_method = cpl_parameter_get_string(par) ;
302 if (!strcmp(mask_method,
"integrated")) {
303 par = cpl_parameterlist_find_const(parlist,
304 "kmos.kmos_extract_spec.centre");
305 centre_txt = cpl_parameter_get_string(par) ;
306 centre = kmo_identify_ranges(centre_txt);
307 if (cpl_vector_get_size(centre) != 2) {
308 cpl_msg_error(__func__,
"centre must have 2 values like a,b") ;
309 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
312 cen_x = cpl_vector_get(centre, 0);
313 cen_y = cpl_vector_get(centre, 1);
314 cpl_vector_delete(centre);
315 par = cpl_parameterlist_find_const(parlist,
316 "kmos.kmos_extract_spec.radius");
317 radius = cpl_parameter_get_double(par) ;
319 cpl_msg_error(__func__,
"radius must be greater than 0.0") ;
320 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
323 }
else if (strcmp(mask_method,
"mask") == 0) {
324 }
else if (strcmp(mask_method,
"optimal") == 0) {
325 kmos_combine_pars_load(parlist,
"kmos.kmos_extract_spec", &cmethod,
326 &cpos_rej, &cneg_rej, &citer, &cmin, &cmax, FALSE);
328 cpl_msg_error(__func__,
"Unsupported mask method: %s", mask_method) ;
329 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
334 if (kmo_dfs_set_groups(frameset) != 1) {
335 cpl_msg_error(__func__,
"Cannot identify RAW and CALIB frames") ;
336 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
341 if (cpl_frameset_get_size(frameset) != 1 &&
342 cpl_frameset_get_size(frameset) != 2) {
343 cpl_msg_error(__func__,
"1 or 2 frames expected") ;
344 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
349 op1_frame = kmo_dfs_get_frame(frameset,
"0");
350 kmo_init_fits_desc(&desc1);
351 kmo_init_fits_desc(&desc2);
352 desc1 = kmo_identify_fits_header(cpl_frame_get_filename(op1_frame));
353 if (cpl_frameset_get_size(frameset) == 2) {
354 op2_frame = kmo_dfs_get_frame(frameset,
"1");
355 desc2 = kmo_identify_fits_header(cpl_frame_get_filename(op2_frame));
361 cpl_propertylist * mh =
362 cpl_propertylist_load(cpl_frame_get_filename(op1_frame), 0) ;
363 kmo_dfs_save_main_header(frameset, EXTRACT_SPEC,
"", op1_frame, mh,
365 cpl_propertylist_delete(mh) ;
368 kmo_dfs_save_main_header(frameset, EXTRACT_SPEC_MASK,
"", op1_frame,
369 NULL, parlist, cpl_func);
373 if (desc1.ex_noise == TRUE) {
374 nr_devices = desc1.nr_ext / 2;
376 nr_devices = desc1.nr_ext;
380 for (i = 1; i <= nr_devices ; i++) {
381 if (desc1.ex_noise == FALSE) {
382 devnr1 = desc1.sub_desc[i - 1].device_nr;
384 devnr1 = desc1.sub_desc[2 * i - 1].device_nr;
387 if (desc1.ex_badpix == FALSE) {
388 index_data = kmo_identify_index_desc(desc1, devnr1, FALSE);
390 index_data = kmo_identify_index_desc(desc1, devnr1, 2);
392 if (desc1.ex_noise) {
393 index_noise = kmo_identify_index_desc(desc1, devnr1, TRUE);
397 sub_header_data = kmo_dfs_load_sub_header(frameset,
"0", devnr1, FALSE);
401 if (desc1.sub_desc[index_data-1].valid_data == TRUE) {
402 if ((strcmp(mask_method,
"mask") != 0) ||
403 ((strcmp(mask_method,
"mask") == 0) &&
404 (desc2.sub_desc[i - 1].valid_data == TRUE))) valid_ifu = TRUE;
406 if (desc1.ex_noise) {
407 sub_header_noise = kmo_dfs_load_sub_header(frameset,
"0", devnr1,
413 data_in = kmo_dfs_load_cube(frameset,
"0", devnr1, FALSE);
416 if (desc1.ex_noise && desc1.sub_desc[index_noise-1].valid_data) {
417 noise_in = kmo_dfs_load_cube(frameset,
"0", devnr1, TRUE);
423 if (!strcmp(mask_method,
"mask")) {
424 mask = kmo_dfs_load_image(frameset,
"1",
425 desc2.sub_desc[i - 1].device_nr, FALSE, FALSE, NULL);
426 }
else if (!strcmp(mask_method,
"optimal")) {
427 kmclipm_make_image(data_in, NULL, &made_data_img, NULL, NULL,
428 cmethod, cpos_rej, cneg_rej, citer, cmax, cmin);
429 fit_par = kmo_fit_profile_2D(made_data_img, NULL,
"gauss",
433 cpl_propertylist_append(sub_header_data, fit_pl);
434 cpl_propertylist_delete(fit_pl);
437 cpl_image_subtract_scalar(mask, cpl_vector_get(fit_par, 0));
438 cpl_image_divide_scalar(mask, cpl_vector_get(fit_par, 1));
439 cpl_vector_delete(fit_par);
440 cpl_image_delete(made_data_img);
441 }
else if (!strcmp(mask_method,
"integrated")) {
442 if (cen_x < 1.0 || cen_y < 1.0) {
443 kmclipm_make_image(data_in, NULL, &made_data_img, NULL,
444 NULL,
"median", 3.0, 3.0, 3, 1, 1);
445 cpl_image_get_maxpos(made_data_img,&auto_cen_x,&auto_cen_y);
446 loc_cen_x = (double)auto_cen_x - 1.0 ;
447 loc_cen_y = (double)auto_cen_y - 1.0 ;
448 cpl_image_delete(made_data_img);
450 loc_cen_x = cen_x - 1.0 ;
451 loc_cen_y = cen_y - 1.0 ;
453 mask = cpl_image_new(desc1.naxis1, desc1.naxis2,CPL_TYPE_FLOAT);
454 kmo_image_fill(mask,0.0);
455 pmask = cpl_image_get_data_float(mask);
458 x_lo = floor(loc_cen_x - radius);
459 if (x_lo < 0) x_lo = 0;
460 y_lo = floor(loc_cen_y - radius);
461 if (y_lo < 0) y_lo = 0;
462 x_hi = ceil(loc_cen_x + radius);
463 if (x_hi > desc1.naxis1) x_hi = desc1.naxis1;
464 y_hi = ceil(loc_cen_y + radius);
465 if (y_hi > desc1.naxis2) y_hi = desc1.naxis2;
466 for (x = x_lo; x < x_hi; x++) {
467 for (y = y_lo; y < y_hi; y++) {
468 r = sqrt(pow(x - loc_cen_x,2) + pow(y - loc_cen_y,2));
469 if (r <= radius) pmask[x + y * desc1.naxis1] = 1.0;
475 kmo_priv_extract_spec(data_in, noise_in, mask, &spec_data_out,
478 sub_header_mask = cpl_propertylist_duplicate(sub_header_data);
481 sub_header_data = kmo_priv_update_header(sub_header_data);
483 kmclipm_vector *ddd = kmclipm_vector_create(spec_data_out);
484 kmo_dfs_save_vector(ddd, EXTRACT_SPEC,
"", sub_header_data, 0./0.);
485 kmclipm_vector_delete(ddd);
488 cpl_propertylist_erase(sub_header_mask, CRPIX3);
489 cpl_propertylist_erase(sub_header_mask, CRVAL3);
490 cpl_propertylist_erase(sub_header_mask, CDELT3);
491 cpl_propertylist_erase(sub_header_mask, CTYPE3);
492 cpl_propertylist_erase(sub_header_mask, CD1_3);
493 cpl_propertylist_erase(sub_header_mask, CD2_3);
494 cpl_propertylist_erase(sub_header_mask, CD3_3);
495 cpl_propertylist_erase(sub_header_mask, CD3_1);
496 cpl_propertylist_erase(sub_header_mask, CD3_2);
497 kmo_dfs_save_image(mask, EXTRACT_SPEC_MASK,
"",
498 sub_header_mask, 0.);
500 cpl_propertylist_delete(sub_header_mask);
503 if (desc1.ex_noise && sub_header_noise) {
504 kmclipm_vector *nnn = NULL;
505 if (spec_noise_out != NULL) {
506 nnn = kmclipm_vector_create(spec_noise_out);
508 sub_header_noise = kmo_priv_update_header(sub_header_noise);
510 kmo_dfs_save_vector(nnn, EXTRACT_SPEC,
"", sub_header_noise,
512 kmclipm_vector_delete(nnn);
514 cpl_imagelist_delete(data_in);
515 cpl_imagelist_delete(noise_in);
516 cpl_image_delete(mask);
519 kmo_dfs_save_sub_header(EXTRACT_SPEC,
"", sub_header_data);
520 if (desc1.ex_noise) {
521 kmo_dfs_save_sub_header(EXTRACT_SPEC,
"", sub_header_noise);
524 cpl_propertylist_delete(sub_header_data);
525 if (desc1.ex_noise && sub_header_noise) {
526 cpl_propertylist_delete(sub_header_noise);
529 kmo_free_fits_desc(&desc1);
530 kmo_free_fits_desc(&desc2);
534 kmos_idp_save_extra_outputs(frameset, parlist, cpl_func, EXTRACT_SPEC) ;