HAWKI Pipeline Reference Manual  1.8.12
hawki_step_combine.c
1 /* $Id: hawki_step_combine.c,v 1.26 2013/01/14 15:18:44 cgarcia Exp $
2  *
3  * This file is part of the HAWKI Pipeline
4  * Copyright (C) 2002,2003 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: cgarcia $
23  * $Date: 2013/01/14 15:18:44 $
24  * $Revision: 1.26 $
25  * $Name: hawki-1_8_12 $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 /*-----------------------------------------------------------------------------
33  Includes
34  -----------------------------------------------------------------------------*/
35 
36 #include <math.h>
37 #include <cpl.h>
38 #include <string.h>
39 
40 #include "irplib_utils.h"
41 #include "irplib_calib.h"
42 
43 #include "hawki_utils.h"
44 #include "hawki_calib.h"
45 #include "hawki_load.h"
46 #include "hawki_save.h"
47 #include "hawki_pfits.h"
48 #include "hawki_dfs.h"
49 #include "hawki_saa.h"
50 #include "hawki_bkg.h"
51 #include "hawki_distortion.h"
52 #include "hawki_properties_tel.h"
53 #include "hawki_image_stats.h"
54 
55 /*-----------------------------------------------------------------------------
56  Functions prototypes
57  -----------------------------------------------------------------------------*/
58 
59 #ifdef __cplusplus
60 extern "C"
61 #endif
62 int cpl_plugin_get_info(cpl_pluginlist * list);
63 
64 static int hawki_step_combine_create(cpl_plugin *) ;
65 static int hawki_step_combine_exec(cpl_plugin *) ;
66 static int hawki_step_combine_destroy(cpl_plugin *) ;
67 static int hawki_step_combine(cpl_parameterlist *, cpl_frameset *) ;
68 
69 static int hawki_step_combine_retrieve_input_param
70 (cpl_parameterlist * parlist);
71 static cpl_image ** hawki_step_combine_apply_comb
72 (cpl_frameset * obj,
73  cpl_frameset * offsets,
74  cpl_frameset * bpm,
75  cpl_frameset * bkg_bpm_frames);
76 static cpl_image ** hawki_step_combine_chip
77 (cpl_imagelist * in,
78  cpl_bivector * offsets,
79  double * pos_x,
80  double * pos_y);
81 static int hawki_step_combine_interpolate_badpix
82 (cpl_image * image);
83 static int hawki_step_combine_save
84 (cpl_image ** combined,
85  cpl_image ** contrib_map,
86  cpl_frameset * used_frames,
87  cpl_parameterlist * parlist,
88  cpl_frameset * recipe_frameset);
89 
90 /*-----------------------------------------------------------------------------
91  Static variables
92  -----------------------------------------------------------------------------*/
93 
94 static struct
95 {
96  /* Inputs */
97  int offset_max ;
98  int borders ;
99  cpl_geom_combine comb_meth ;
100  int rej_low;
101  int rej_high;
102  cpl_kernel resamp_kernel;
103 } hawki_step_combine_config;
104 
105 static struct
106 {
107  /* Outputs */
108  double mean_airmass;
109  double combined_pos_x[HAWKI_NB_DETECTORS];
110  double combined_pos_y[HAWKI_NB_DETECTORS];
111  double combined_cumoffset_x[HAWKI_NB_DETECTORS];
112  double combined_cumoffset_y[HAWKI_NB_DETECTORS];
113 } hawki_step_combine_output;
114 
115 static char hawki_step_combine_description[] =
116 "hawki_step_combine -- hawki combine jitter images.\n"
117 "The files listed in the Set Of Frames (sof-file) must be tagged:\n"
118 "science-file.fits "HAWKI_CALPRO_DIST_CORRECTED" or\n"
119 "science-file.fits "HAWKI_CALPRO_BKG_SUBTRACTED" or\n"
120 "bpm-file.fits "HAWKI_CALPRO_BPM" (optional) \n"
121 "bkg_bpm-file.fits "HAWKI_CALPRO_BKGBPM" (optional) \n"
122 "offsets-file.fits "HAWKI_CALPRO_OFFSETS" (optional) \n"
123 "The recipe creates as an output:\n"
124 "hawki_step_combine.fits ("HAWKI_CALPRO_COMBINED"): \n"
125 "The recipe does the following steps:\n"
126 "-Allocate an image with the proper combined size \n"
127 " (depends on parameters --comb_meth and --borders)\n"
128 "-Retrieve the offsets either from the offsets-file.fits or from the header\n"
129 "-For each combined pixel, the contribution of each individual frame \n"
130 " is added using a resampling kernel. If any of the pixels involved in\n"
131 " the resampling is a bad pixel (defined in bpm-file.fits), it is not\n"
132 " taken into account.\n"
133 " With the remaining pixels a minmax rejection is performed\n"
134 "Return code:\n"
135 "esorex exits with an error code of 0 if the recipe completes successfully\n"
136 "or 1 otherwise";
137 
138 /*-----------------------------------------------------------------------------
139  Functions code
140  -----------------------------------------------------------------------------*/
141 
142 /*----------------------------------------------------------------------------*/
150 /*----------------------------------------------------------------------------*/
151 int cpl_plugin_get_info(cpl_pluginlist * list)
152 {
153  cpl_recipe * recipe = cpl_calloc(1, sizeof(*recipe)) ;
154  cpl_plugin * plugin = &recipe->interface ;
155 
156  cpl_plugin_init(plugin,
157  CPL_PLUGIN_API,
158  HAWKI_BINARY_VERSION,
159  CPL_PLUGIN_TYPE_RECIPE,
160  "hawki_step_combine",
161  "Jitter image combination recipe",
162  hawki_step_combine_description,
163  "Cesar Enrique Garcia Dabo",
164  PACKAGE_BUGREPORT,
166  hawki_step_combine_create,
167  hawki_step_combine_exec,
168  hawki_step_combine_destroy) ;
169 
170  cpl_pluginlist_append(list, plugin) ;
171 
172  return 0;
173 }
174 
175 /*----------------------------------------------------------------------------*/
184 /*----------------------------------------------------------------------------*/
185 static int hawki_step_combine_create(cpl_plugin * plugin)
186 {
187  cpl_recipe * recipe ;
188  cpl_parameter * p ;
189 
190  /* Get the recipe out of the plugin */
191  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
192  recipe = (cpl_recipe *)plugin ;
193  else return -1 ;
194 
195  /* Create the parameters list in the cpl_recipe object */
196  recipe->parameters = cpl_parameterlist_new() ;
197  if (recipe->parameters == NULL)
198  return 1;
199 
200  /* Fill the parameters list */
201  /* --offset_max */
202  p = cpl_parameter_new_value("hawki.hawki_step_combine.offset_max",
203  CPL_TYPE_INT,
204  "Maximum offset allowed",
205  "hawki.hawki_step_combine",
206  1500) ;
207  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "offset_max") ;
208  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
209  cpl_parameterlist_append(recipe->parameters, p) ;
210 
211  /* --comb_meth */
212  p = cpl_parameter_new_value("hawki.hawki_step_combine.comb_meth",
213  CPL_TYPE_STRING,
214  "Final size of combination (union / inter / first)",
215  "hawki.hawki_step_combine",
216  "union") ;
217  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "comb_meth") ;
218  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
219  cpl_parameterlist_append(recipe->parameters, p) ;
220 
221  /* --rej */
222  p = cpl_parameter_new_value("hawki.hawki_step_combine.rej",
223  CPL_TYPE_STRING,
224  "Low and high number of rejected values",
225  "hawki.hawki_step_combine",
226  "1,1") ;
227  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rej") ;
228  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
229  cpl_parameterlist_append(recipe->parameters, p) ;
230 
231  /* --borders */
232  p = cpl_parameter_new_value("hawki.hawki_step_combine.borders",
233  CPL_TYPE_INT,
234  "Border pixels trimmed",
235  "hawki.hawki_step_combine",
236  4) ;
237  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "borders") ;
238  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
239  cpl_parameterlist_append(recipe->parameters, p) ;
240 
241  /* --resamp_kernel */
242  p = cpl_parameter_new_value("hawki.hawki_step_combine.resamp_kernel",
243  CPL_TYPE_STRING,
244  "Resampling kernel (default/tanh/sinc/sinc2/lanczos/hamming/hann)",
245  "hawki.hawki_step_combine",
246  "default") ;
247  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "resamp_kernel") ;
248  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
249  cpl_parameterlist_append(recipe->parameters, p) ;
250 
251  /* Return */
252  return 0;
253 }
254 
255 /*----------------------------------------------------------------------------*/
261 /*----------------------------------------------------------------------------*/
262 static int hawki_step_combine_exec(cpl_plugin * plugin)
263 {
264  cpl_recipe * recipe ;
265 
266  /* Get the recipe out of the plugin */
267  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
268  recipe = (cpl_recipe *)plugin ;
269  else return -1 ;
270 
271  /* Issue a banner */
273 
274  return hawki_step_combine(recipe->parameters, recipe->frames) ;
275 }
276 
277 /*----------------------------------------------------------------------------*/
283 /*----------------------------------------------------------------------------*/
284 static int hawki_step_combine_destroy(cpl_plugin * plugin)
285 {
286  cpl_recipe * recipe ;
287 
288  /* Get the recipe out of the plugin */
289  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
290  recipe = (cpl_recipe *)plugin ;
291  else return -1 ;
292 
293  cpl_parameterlist_delete(recipe->parameters) ;
294  return 0 ;
295 }
296 
297 /*----------------------------------------------------------------------------*/
304 /*----------------------------------------------------------------------------*/
305 static int hawki_step_combine(
306  cpl_parameterlist * parlist,
307  cpl_frameset * framelist)
308 {
309  cpl_frameset * objframes ;
310  cpl_frameset * offsets;
311  cpl_frameset * bpm;
312  cpl_frameset * bpmbkg;
313  cpl_frameset * used_frames;
314  cpl_image ** combined_contrib;
315  cpl_image ** combined;
316  cpl_image ** contrib_map;
317  int idet;
318 
319  /* Retrieve input parameters */
320  if(hawki_step_combine_retrieve_input_param(parlist))
321  {
322  cpl_msg_error(__func__, "Wrong parameters");
323  return -1;
324  }
325 
326  /* Identify the RAW and CALIB frames in the input frameset */
327  if (hawki_dfs_set_groups(framelist)) {
328  cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
329  return -1 ;
330  }
331 
332  /* Retrieve raw frames */
333  objframes = hawki_extract_frameset(framelist, HAWKI_CALPRO_DIST_CORRECTED);
334  if (objframes == NULL)
335  {
336  objframes = hawki_extract_frameset
337  (framelist, HAWKI_CALPRO_BKG_SUBTRACTED);
338  if (objframes == NULL)
339  {
340  cpl_msg_error(__func__,"Cannot find objs frames in the input list (%s or %s)",
341  HAWKI_CALPRO_DIST_CORRECTED, HAWKI_CALPRO_BKG_SUBTRACTED);
342  return -1 ;
343  }
344  }
345  /* Check that pointing is the same for all the frames */
348  {
349  cpl_msg_error(__func__, "Not all input science frames belong to the "
350  "same pointing/target. Check keywords TEL TARG ALPHA/DELTA");
351  cpl_frameset_delete(objframes);
352  return -1;
353  }
354  used_frames = cpl_frameset_duplicate(objframes);
355 
356  /* Retrieve the refined offsets, if provided */
357  offsets = hawki_extract_frameset(framelist, HAWKI_CALPRO_OFFSETS);
358  if(offsets)
359  cpl_frameset_insert(used_frames, cpl_frame_duplicate(
360  cpl_frameset_get_position(offsets, 0)));
361 
362  /* Retrieve the general bad pixel mask, if provided */
363  bpm = hawki_extract_frameset(framelist, HAWKI_CALPRO_BPM);
364  if(bpm)
365  cpl_frameset_insert(used_frames, cpl_frame_duplicate(
366  cpl_frameset_get_position(bpm, 0)));
367 
368  /* Retrieve the background bad pixel masks, if provided */
369  bpmbkg = hawki_extract_frameset(framelist, HAWKI_CALPRO_BKGBPM);
370  if(bpmbkg)
371  {
372  int iframe;
373  for(iframe=0; iframe < cpl_frameset_get_size(bpmbkg); iframe++)
374  cpl_frameset_insert(used_frames, cpl_frame_duplicate(
375  cpl_frameset_get_frame(bpmbkg,iframe)));
376  if(cpl_frameset_get_size(bpmbkg) != cpl_frameset_get_size(objframes))
377  {
378  cpl_msg_error(__func__,"Incompatible number of science and bad bkg"
379  " images.");
380  cpl_msg_error(__func__,"Supply as many bad bkg images as objects");
381  cpl_frameset_delete(objframes);
382  cpl_frameset_delete(used_frames);
383  cpl_frameset_delete(offsets);
384  cpl_frameset_delete(bpm);
385  cpl_frameset_delete(bpmbkg);
386  return -1;
387  }
388  }
389 
390  /* Apply the combination */
391  cpl_msg_info(__func__, "Apply the data recombination");
392  cpl_msg_indent_more() ;
393  if ((combined_contrib = hawki_step_combine_apply_comb
394  (objframes, offsets, bpm, bpmbkg)) == NULL)
395  {
396  cpl_msg_error(__func__, "Cannot combine the data");
397  cpl_frameset_delete(objframes);
398  cpl_frameset_delete(used_frames);
399  if(offsets != NULL)
400  cpl_frameset_delete(offsets);
401  if(bpm != NULL)
402  cpl_frameset_delete(bpm);
403  cpl_msg_indent_less() ;
404  return -1 ;
405  }
406 
407  /* Get both the combination and the contribution map */
408  combined = combined_contrib;
409  contrib_map = combined_contrib + HAWKI_NB_DETECTORS;
410  cpl_msg_indent_less() ;
411  cpl_frameset_delete(objframes);
412  if(offsets != NULL)
413  cpl_frameset_delete(offsets);
414  if(bpm != NULL)
415  cpl_frameset_delete(bpm);
416  if(bpmbkg != NULL)
417  cpl_frameset_delete(bpmbkg);
418 
419  /* Save the products */
420  cpl_msg_info(__func__, "Save the products") ;
421  cpl_msg_indent_more() ;
422  if (hawki_step_combine_save(combined, contrib_map,
423  used_frames, parlist, framelist) != 0)
424  {
425  cpl_msg_warning(__func__, "Some error happened saving the data. "
426  "Check permisions or disk space") ;
427  for(idet=0; idet< 2 * HAWKI_NB_DETECTORS; ++idet)
428  cpl_image_delete(combined_contrib[idet]);
429  cpl_frameset_delete(used_frames);
430  cpl_free(combined_contrib);
431  cpl_msg_indent_less() ;
432  return -1 ;
433  }
434  cpl_msg_indent_less() ;
435 
436  /* Return */
437  for(idet=0; idet< 2 * HAWKI_NB_DETECTORS; ++idet)
438  cpl_image_delete(combined_contrib[idet]);
439  cpl_free(combined_contrib);
440  cpl_frameset_delete(used_frames);
441 
442  /* Return */
443  if (cpl_error_get_code())
444  {
445  cpl_msg_error(__func__,
446  "HAWK-I pipeline could not recover from previous errors");
447  return -1 ;
448  }
449  else return 0 ;
450 }
451 
452 int hawki_step_combine_retrieve_input_param
453 (cpl_parameterlist * parlist)
454 {
455  cpl_parameter * par ;
456  const char * sval ;
457  par = NULL ;
458  par = cpl_parameterlist_find(parlist,
459  "hawki.hawki_step_combine.offset_max");
460  hawki_step_combine_config.offset_max = cpl_parameter_get_int(par);
461  par = cpl_parameterlist_find(parlist,
462  "hawki.hawki_step_combine.comb_meth");
463  sval = cpl_parameter_get_string(par);
464  if (!strcmp(sval, "union"))
465  hawki_step_combine_config.comb_meth = CPL_GEOM_UNION;
466  else if (!strcmp(sval, "inter"))
467  hawki_step_combine_config.comb_meth = CPL_GEOM_INTERSECT;
468  else if (!strcmp(sval, "first"))
469  hawki_step_combine_config.comb_meth = CPL_GEOM_FIRST;
470  else
471  {
472  cpl_msg_error(__func__, "Invalid combine method specified");
473  return -1;
474  }
475  par = cpl_parameterlist_find(parlist,
476  "hawki.hawki_step_combine.borders");
477  hawki_step_combine_config.borders = cpl_parameter_get_int(par);
478  if(hawki_step_combine_config.borders < 0 )
479  {
480  cpl_msg_error(__func__, "Borders cannot be less than zero");
481  return -1;
482  }
483  par = cpl_parameterlist_find(parlist,
484  "hawki.hawki_step_combine.rej");
485  sval = cpl_parameter_get_string(par);
486  if (sscanf(sval, "%d,%d",
487  &hawki_step_combine_config.rej_low,
488  &hawki_step_combine_config.rej_high)!=2)
489  {
490  return -1;
491  }
492  par = cpl_parameterlist_find(parlist,
493  "hawki.hawki_step_combine.resamp_kernel");
494  sval = cpl_parameter_get_string(par);
495  if (!strcmp(sval, "tanh"))
496  hawki_step_combine_config.resamp_kernel = CPL_KERNEL_TANH;
497  else if (!strcmp(sval, "sinc"))
498  hawki_step_combine_config.resamp_kernel = CPL_KERNEL_SINC;
499  else if (!strcmp(sval, "sinc2"))
500  hawki_step_combine_config.resamp_kernel = CPL_KERNEL_SINC2;
501  else if (!strcmp(sval, "lanczos"))
502  hawki_step_combine_config.resamp_kernel = CPL_KERNEL_LANCZOS;
503  else if (!strcmp(sval, "hamming"))
504  hawki_step_combine_config.resamp_kernel = CPL_KERNEL_HAMMING;
505  else if (!strcmp(sval, "hann"))
506  hawki_step_combine_config.resamp_kernel = CPL_KERNEL_HANN;
507  else if (!strcmp(sval, "default"))
508  hawki_step_combine_config.resamp_kernel = CPL_KERNEL_DEFAULT;
509  else
510  {
511  cpl_msg_error(__func__, "Invalid resampling kernel specified");
512  return -1;
513  }
514 
515  return 0;
516 }
517 
518 
519 
520 /*----------------------------------------------------------------------------*/
526 /*----------------------------------------------------------------------------*/
527 static cpl_image ** hawki_step_combine_apply_comb
528 (cpl_frameset * obj,
529  cpl_frameset * offsets_frames,
530  cpl_frameset * bpm_frame,
531  cpl_frameset * bkg_bpm_frames)
532 {
533  cpl_image ** combined_contrib;
534  cpl_bivector ** offsets;
535  cpl_mask * bpm_masks[HAWKI_NB_DETECTORS];
536  int idet;
537  int ioff;
538 
539  if(offsets_frames == NULL)
540  {
541  cpl_bivector * offsets_single_chip;
542  if ((offsets_single_chip = hawki_get_header_tel_offsets(obj)) == NULL)
543  {
544  cpl_msg_error(__func__, "Cannot load the header offsets");
545  return NULL;
546  }
547  offsets = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_bivector *));
548  for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
549  offsets[idet] = cpl_bivector_duplicate(offsets_single_chip);
550  cpl_bivector_delete(offsets_single_chip);
551  }
552  else
553  {
555  (cpl_frameset_get_first(offsets_frames));
556  if(offsets == NULL)
557  {
558  cpl_msg_error(__func__, "Cannot load the refined offsets");
559  return NULL;
560  }
561  }
562  /* Get the oposite offsets. This is to change from
563  * telescope convention to cpl convention
564  * WARNING: It may appear that the img_jitter function
565  * does not apply the multiplication by -1, but it really does it in
566  * hawki_img_jitter_saa instead of when it reads the offsets */
567  for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
568  {
569  cpl_vector_multiply_scalar(cpl_bivector_get_x(offsets[idet]), -1.0);
570  cpl_vector_multiply_scalar(cpl_bivector_get_y(offsets[idet]), -1.0);
571  }
572 
573  /* Load the bpm */
574  if(bpm_frame != NULL)
575  {
576  cpl_imagelist * bpm_images = NULL;
577  bpm_images = hawki_load_frame
578  (cpl_frameset_get_first(bpm_frame), CPL_TYPE_INT);
579  if(bpm_images == NULL)
580  {
581  cpl_msg_error(__func__, "Cannot load the bad pixel mask");
582  return NULL;
583  }
584  for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
585  {
586  bpm_masks[idet] = cpl_mask_threshold_image_create
587  (cpl_imagelist_get(bpm_images, idet), 0.5, 1.5);
588  }
589  cpl_imagelist_delete(bpm_images);
590  }
591 
592  /* Create output object */
593  combined_contrib = cpl_malloc(2 * HAWKI_NB_DETECTORS * sizeof(cpl_image *));
594 
595  /* Loop on the detectors */
596  for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
597  {
598  cpl_imagelist * in ;
599  cpl_imagelist * bpm_bkg_im = NULL;
600  cpl_image ** comb_contrib_chip ;
601  double * offs_est_x ;
602  double * offs_est_y ;
603  double max_x, max_y ;
604  double off_0_x;
605  double off_0_y;
606  int jdet;
607  int iframe;
608 
609  cpl_msg_info(__func__, "Combine chip number %d", idet+1) ;
610  cpl_msg_indent_more() ;
611 
612  /* Print the offsets */
613  offs_est_x = cpl_bivector_get_x_data(offsets[idet]) ;
614  offs_est_y = cpl_bivector_get_y_data(offsets[idet]) ;
615  for (ioff=0 ; ioff<cpl_bivector_get_size(offsets[idet]) ; ioff++) {
616  cpl_msg_info(__func__,"Telescope offsets (Frame %d): %g %g", ioff+1,
617  -offs_est_x[ioff], -offs_est_y[ioff]) ;
618  }
619 
620  /* Subtract the first offset to all offsets */
621  max_x = max_y = 0.0 ;
622  off_0_x = offs_est_x[0];
623  off_0_y = offs_est_y[0];
624  for (ioff=1 ; ioff<cpl_bivector_get_size(offsets[idet]) ; ioff++)
625  {
626  offs_est_x[ioff] -= offs_est_x[0] ;
627  offs_est_y[ioff] -= offs_est_y[0] ;
628  if (fabs(offs_est_x[ioff]) > max_x) max_x = fabs(offs_est_x[ioff]);
629  if (fabs(offs_est_y[ioff]) > max_y) max_y = fabs(offs_est_y[ioff]);
630  }
631  offs_est_x[0] = offs_est_y[0] = 0.00 ;
632 
633  /* Check if the max offset is not too big */
634  if (max_x > hawki_step_combine_config.offset_max ||
635  max_y > hawki_step_combine_config.offset_max)
636  {
637  cpl_msg_error(__func__,"Sorry, no support for offsets larger than %d",
638  hawki_step_combine_config.offset_max);
639  for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
640  {
641  cpl_bivector_delete(offsets[idet]);
642  if(bpm_frame != NULL)
643  cpl_mask_delete(bpm_masks[idet]);
644  }
645  for(jdet = 0; jdet < idet; ++jdet)
646  {
647  cpl_image_delete(combined_contrib[idet]);
648  cpl_image_delete(combined_contrib[idet+HAWKI_NB_DETECTORS]);
649  }
650  cpl_free(combined_contrib);
651  return NULL ;
652  }
653 
654  /* Load the input data */
655  cpl_msg_info(__func__, "Load the input data") ;
656  cpl_msg_indent_more();
657  if ((in = hawki_load_detector(obj, idet+1, CPL_TYPE_FLOAT)) == NULL) {
658  cpl_msg_error(__func__, "Cannot load chip %d",idet+1);
659  //TODO: there is probably a memory leak here. It should be checked.
660  for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
661  {
662  cpl_bivector_delete(offsets[idet]);
663  if(bpm_frame != NULL)
664  cpl_mask_delete(bpm_masks[idet]);
665  }
666  for(jdet = 0; jdet < idet; ++jdet)
667  {
668  cpl_image_delete(combined_contrib[idet]);
669  cpl_image_delete(combined_contrib[idet+HAWKI_NB_DETECTORS]);
670  }
671  cpl_free(combined_contrib);
672  cpl_free(offsets);
673  cpl_msg_indent_less() ;
674  cpl_msg_indent_less() ;
675  return NULL ;
676  }
677 
678  /* Load the bad bkg images */
679  if(bkg_bpm_frames != NULL)
680  {
681  cpl_msg_info(__func__, "Load the bad bkg images");
682  cpl_msg_indent_more() ;
683  if ((bpm_bkg_im = hawki_load_detector(bkg_bpm_frames, idet+1,
684  CPL_TYPE_FLOAT)) == NULL)
685  {
686  cpl_msg_error(__func__, "Cannot load chip %d",idet+1);
687  for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
688  {
689  cpl_bivector_delete(offsets[idet]);
690  if(bpm_frame != NULL)
691  cpl_mask_delete(bpm_masks[idet]);
692  }
693  for(jdet = 0; jdet < idet; ++jdet)
694  {
695  cpl_image_delete(combined_contrib[idet]);
696  cpl_image_delete(combined_contrib[idet+HAWKI_NB_DETECTORS]);
697  }
698  cpl_free(combined_contrib);
699  cpl_imagelist_delete(in);
700  cpl_free(offsets);
701  cpl_msg_indent_less() ;
702  cpl_msg_indent_less() ;
703  return NULL ;
704  }
705  cpl_msg_indent_less() ;
706  }
707  cpl_msg_indent_less() ;
708 
709  /* Add the general bpm or background bpms in case they were specified */
710  if(bpm_frame != NULL || bkg_bpm_frames != NULL)
711  {
712  for(iframe = 0 ; iframe <cpl_imagelist_get_size(in) ; ++iframe)
713  {
714  cpl_mask * final_mask;
715  cpl_image * target_image = cpl_imagelist_get(in, iframe);
716  final_mask = cpl_mask_new(cpl_image_get_size_x(target_image),
717  cpl_image_get_size_y(target_image));
718  //Add the common bpm
719  if(bpm_frame != NULL)
720  cpl_mask_or(final_mask, bpm_masks[idet]);
721  //Add the background mask if provided
722  if(bkg_bpm_frames != NULL)
723  {
724  cpl_mask * bpm_bkg_mask =
725  cpl_mask_threshold_image_create
726  (cpl_imagelist_get(bpm_bkg_im, iframe), 0.5, FLT_MAX);
727  cpl_mask_or(final_mask, bpm_bkg_mask);
728  cpl_mask_delete(bpm_bkg_mask);
729  }
730  cpl_image_reject_from_mask(target_image, final_mask);
731  cpl_mask_delete(final_mask);
732  }
733  }
734 
735  if(bkg_bpm_frames != NULL)
736  cpl_imagelist_delete(bpm_bkg_im);
737 
738  /* Apply the shift and add */
739  cpl_msg_info(__func__, "Shift and add") ;
740  cpl_msg_indent_more() ;
741  comb_contrib_chip = hawki_step_combine_chip(in, offsets[idet],
742  &(hawki_step_combine_output.combined_pos_x[idet]),
743  &(hawki_step_combine_output.combined_pos_y[idet])) ;
744  if (comb_contrib_chip == NULL)
745  {
746  cpl_msg_error(__func__, "Cannot apply the shift and add") ;
747  cpl_imagelist_delete(in) ;
748  for(jdet = 0; jdet < HAWKI_NB_DETECTORS; ++jdet)
749  cpl_bivector_delete(offsets[jdet]);
750  {
751  cpl_image_delete(combined_contrib[idet]);
752  cpl_image_delete(combined_contrib[idet+HAWKI_NB_DETECTORS]);
753  }
754  cpl_free(combined_contrib);
755  cpl_free(offsets);
756  cpl_msg_indent_less() ;
757  cpl_msg_indent_less() ;
758  return NULL ;
759  }
760 
761  /* The cumoffset have the opposite criteria as cpl */
762  hawki_step_combine_output.combined_cumoffset_x[idet] =
763  hawki_step_combine_output.combined_pos_x[idet] - off_0_x;
764  hawki_step_combine_output.combined_cumoffset_y[idet] =
765  hawki_step_combine_output.combined_pos_y[idet] - off_0_y;
766  cpl_imagelist_delete(in) ;
767  cpl_msg_indent_less() ;
768 
769  /* Interpolate bad pixels */
770  hawki_step_combine_interpolate_badpix(comb_contrib_chip[0]);
771 
772  /* Put the results in the image list */
773  combined_contrib[idet] = comb_contrib_chip[0];
774  combined_contrib[idet+HAWKI_NB_DETECTORS] = comb_contrib_chip[1];
775  cpl_free(comb_contrib_chip);
776  cpl_msg_indent_less() ;
777  }
778 
779  /* Compute the mean airmass */
780  hawki_step_combine_output.mean_airmass = hawki_get_mean_airmass(obj);
781 
782  for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
783  {
784  cpl_bivector_delete(offsets[idet]);
785  if(bpm_frame != NULL)
786  cpl_mask_delete(bpm_masks[idet]);
787  }
788  cpl_free(offsets);
789  return combined_contrib;
790 }
791 
792 /*----------------------------------------------------------------------------*/
801 /*----------------------------------------------------------------------------*/
802 static cpl_image ** hawki_step_combine_chip(
803  cpl_imagelist * in,
804  cpl_bivector * offsets,
805  double * pos_x,
806  double * pos_y)
807 {
808  cpl_image ** combined_contrib;
809  cpl_imagelist * in_ext ;
810  cpl_image * tmp1 ;
811  cpl_image * tmp2 ;
812  int nfiles, nx, ny ;
813  int i;
814 
815  /* Check entries */
816  if (pos_x == NULL || pos_y == NULL) return NULL ;
817  if (offsets == NULL) return NULL ;
818 
819  /* Get the number of images */
820  nfiles = cpl_imagelist_get_size(in) ;
821  if (cpl_bivector_get_size(offsets) != nfiles) {
822  cpl_msg_error(__func__, "Number of refined offsets in table """
823  "is different than number of frames to combine");
824  return NULL ;
825  }
826 
827  /* Discard the pixels on the sides */
828  if (hawki_step_combine_config.borders > 0) {
829  nx = cpl_image_get_size_x(cpl_imagelist_get(in, 0)) ;
830  ny = cpl_image_get_size_y(cpl_imagelist_get(in, 0)) ;
831  in_ext = cpl_imagelist_new() ;
832  for (i=0 ; i<cpl_imagelist_get_size(in) ; i++) {
833  tmp1 = cpl_imagelist_get(in, i) ;
834  tmp2 = cpl_image_extract(tmp1,
835  hawki_step_combine_config.borders+1,
836  hawki_step_combine_config.borders+1,
837  nx-hawki_step_combine_config.borders,
838  ny-hawki_step_combine_config.borders) ;
839  cpl_imagelist_set(in_ext, tmp2, i) ;
840  }
841  }
842  else
843  {
844  in_ext = cpl_imagelist_duplicate(in);
845  }
846 
847  /* Apply the shift & add */
848  cpl_msg_info(__func__, "Recombine the images set") ;
849  cpl_msg_indent_more() ;
850  if ((combined_contrib=cpl_geom_img_offset_saa(in_ext, offsets,
851  hawki_step_combine_config.resamp_kernel,
852  hawki_step_combine_config.rej_low,
853  hawki_step_combine_config.rej_high,
854  hawki_step_combine_config.comb_meth,
855  pos_x, pos_y)) == NULL) {
856  cpl_msg_error(cpl_func, "Cannot apply the shift and add") ;
857  cpl_msg_indent_less();
858  return NULL;
859  }
860  cpl_msg_indent_less();
861  *pos_x -= hawki_step_combine_config.borders;
862  *pos_y -= hawki_step_combine_config.borders;
863 
864  /* Free and return */
865  cpl_imagelist_delete(in_ext);
866  return combined_contrib;
867 }
868 
869 /*----------------------------------------------------------------------------*/
875 /*----------------------------------------------------------------------------*/
876 static int hawki_step_combine_interpolate_badpix
877 (cpl_image * image)
878 {
879  int nbadpixels = cpl_image_count_rejected(image);
880  if(nbadpixels !=0)
881  cpl_msg_info(__func__,"Number of pixels with no combined value available: %d ",
882  nbadpixels);
883  if(cpl_image_count_rejected(image) > 0)
884  {
885  //I use this even if DFS08929 is still not solved
886  cpl_detector_interpolate_rejected(image);
887  }
888  return 0;
889 }
890 
891 /*----------------------------------------------------------------------------*/
900 /*----------------------------------------------------------------------------*/
901 static int hawki_step_combine_save
902 (cpl_image ** combined,
903  cpl_image ** contrib_map,
904  cpl_frameset * used_frames,
905  cpl_parameterlist * parlist,
906  cpl_frameset * recipe_frameset)
907 {
908  cpl_propertylist ** extproplists ;
909  const cpl_frame * ref_frame ;
910  cpl_propertylist * wcslist ;
911  cpl_propertylist * inputlist ;
912  double crpix1, crpix2 ;
913  int ext_nb ;
914  const char * recipe_name = "hawki_step_combine" ;
915  int idet;
916  cpl_errorstate error_prevstate = cpl_errorstate_get();
917 
918  /* Get a reference frame for the WCS keys */
919  ref_frame = irplib_frameset_get_first_from_group
920  (recipe_frameset, CPL_FRAME_GROUP_RAW) ;
921 
922  if(ref_frame == NULL)
923  {
924  cpl_msg_error(__func__, "Cannot get a reference frame");
925  return -1;
926  }
927 
928  /* Create the QC lists */
929  extproplists = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_propertylist*)) ;
930  for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
931  {
932 
933  /* Initialize qclists */
934  extproplists[idet] = cpl_propertylist_new() ;
935 
936  /* Get the extension number */
937  ext_nb=hawki_get_ext_from_detector(cpl_frame_get_filename(ref_frame), idet+1);
938 
939  /* Handle WCS keys */
940  wcslist = cpl_propertylist_load_regexp(
941  cpl_frame_get_filename(ref_frame), ext_nb, HAWKI_HEADER_WCS, 0);
942 
943  /* Update WCS and write them */
944  crpix1 = cpl_propertylist_get_double(wcslist, "CRPIX1");
945  crpix1 += hawki_step_combine_output.combined_pos_x[idet];
946  cpl_propertylist_update_double(wcslist, "CRPIX1", crpix1) ;
947  crpix2 = cpl_propertylist_get_double(wcslist, "CRPIX2");
948  crpix2 += hawki_step_combine_output.combined_pos_y[idet] ;
949  cpl_propertylist_update_double(wcslist, "CRPIX2", crpix2) ;
950  cpl_propertylist_copy_property_regexp
951  (extproplists[idet], wcslist, HAWKI_HEADER_WCS, 0);
952  cpl_propertylist_delete(wcslist) ;
953 
954  /* Keywords for the relative position of the combined image */
955  cpl_propertylist_append_double
956  (extproplists[idet], "ESO QC COMBINED CUMOFFSETX",
957  hawki_step_combine_output.combined_cumoffset_x[idet]);
958  cpl_propertylist_append_double
959  (extproplists[idet], "ESO QC COMBINED CUMOFFSETY",
960  hawki_step_combine_output.combined_cumoffset_y[idet]);
961  cpl_propertylist_append_double
962  (extproplists[idet], "ESO QC COMBINED POSX",
963  hawki_step_combine_output.combined_pos_x[idet]);
964  cpl_propertylist_append_double
965  (extproplists[idet], "ESO QC COMBINED POSY",
966  hawki_step_combine_output.combined_pos_y[idet]);
967  cpl_propertylist_append_double
968  (extproplists[idet], "ESO QC AIRMASS MEAN",
969  hawki_step_combine_output.mean_airmass);
970 
971  /* Propagate some keywords from input raw frame extensions */
972  inputlist = cpl_propertylist_load_regexp(
973  cpl_frame_get_filename(ref_frame), ext_nb,
974  HAWKI_HEADER_EXT_FORWARD, 0) ;
975  cpl_propertylist_append(extproplists[idet], inputlist);
976  cpl_propertylist_delete(inputlist) ;
977  }
978 
979  /* Write the combined image */
980  if(hawki_images_save(recipe_frameset,
981  parlist,
982  used_frames,
983  (const cpl_image **)combined,
984  recipe_name,
985  HAWKI_CALPRO_COMBINED,
986  HAWKI_PROTYPE_COMBINED,
987  NULL,
988  (const cpl_propertylist**)extproplists,
989  "hawki_step_combine.fits") != 0)
990  {
991  for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++) {
992  cpl_propertylist_delete(extproplists[idet]) ;
993  }
994  cpl_free(extproplists) ;
995  return -1;
996  }
997 
998  /* Write the contrib map */
999  if(hawki_images_save(recipe_frameset,
1000  parlist,
1001  used_frames,
1002  (const cpl_image **)contrib_map,
1003  recipe_name,
1004  HAWKI_CALPRO_COMB_CONTRIB_MAP,
1005  HAWKI_PROTYPE_COMB_CONTRIB_MAP,
1006  NULL,
1007  (const cpl_propertylist**)extproplists,
1008  "hawki_step_combine_contrib_map.fits") != 0)
1009  {
1010  for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++) {
1011  cpl_propertylist_delete(extproplists[idet]);
1012  }
1013  cpl_free(extproplists) ;
1014  return -1;
1015  }
1016 
1017  /* Free and return */
1018  for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++) {
1019  cpl_propertylist_delete(extproplists[idet]) ;
1020  }
1021  cpl_free(extproplists) ;
1022 
1023  if(!cpl_errorstate_is_equal(error_prevstate))
1024  {
1025  cpl_errorstate_set(CPL_ERROR_NONE);
1026  return 1;
1027  }
1028 
1029  return 0;
1030 }
1031