VISIR Pipeline Reference Manual  4.1.0
visir_util_undistort.c
1 /* $Id: visir_util_undistort.c,v 1.30 2013-05-13 16:05:04 jtaylor Exp $
2  *
3  * This file is part of the VISIR 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., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: jtaylor $
23  * $Date: 2013-05-13 16:05:04 $
24  * $Revision: 1.30 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 /*-----------------------------------------------------------------------------
33  Includes
34  -----------------------------------------------------------------------------*/
35 
36 #include "visir_recipe.h"
37 
38 #include "visir_spc_distortion.h"
39 #include "visir_cpl_compat.h"
40 #include "visir_utils.h"
41 #include <cxlist.h>
42 #ifdef _OPENMP
43 #include <omp.h>
44 #endif
45 
46 /*-----------------------------------------------------------------------------
47  Defines
48  -----------------------------------------------------------------------------*/
49 
50 #define RECIPE_STRING "visir_util_undistort"
51 
52 /*-----------------------------------------------------------------------------
53  Private Functions prototypes
54  -----------------------------------------------------------------------------*/
55 
56 #ifdef VISIR_CHAIN
57 #define cpl_plugin_get_info visir_util_undistort_get_info
58 #endif
59 cpl_recipe_define(visir_util_undistort, VISIR_BINARY_VERSION,
60  "Lars Lundin", PACKAGE_BUGREPORT, "2011",
61  "Correct the distortion in spectral data",
62  "The files listed in the Set Of Frames (sof-file) "
63  "must be tagged:\n"
64  "VISIR-chopnod-corrected-file.fits " VISIR_UTIL_UNDISTORT_RAW
65  "\nOptionally, a bad pixel map may be provided:\n"
66  "VISIR-bpm-file.fits " VISIR_CALIB_STATIC_MASK "\n"
67  "\nThe product(s) will have a FITS card\n"
68  "'HIERARCH ESO PRO CATG' with a value of:\n"
69  VISIR_UTIL_UNDISTORT_PROCATG "\n"
70 #ifdef VISIR_UTIL_UNDISTORT_AUTO_REJECT
71 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE > CPL_VERSION(5, 4, 0)
72  "If no bad pixel map is provided, the recipe will "
73  "automatically flag input intensities greater than or equal "
74  "to 32767 as bad.\n"
75 #endif
76 #endif
77  "The recipe default values for the transformation are only "
78  "valid for spectral data taken in Low resolution mode");
79 
80 /*----------------------------------------------------------------------------*/
84 /*----------------------------------------------------------------------------*/
85 
86 /*-----------------------------------------------------------------------------
87  Functions code
88  -----------------------------------------------------------------------------*/
89 
90 
91 /*----------------------------------------------------------------------------*/
99 /*----------------------------------------------------------------------------*/
100 static cpl_error_code
101 visir_util_undistort_fill_parameterlist(cpl_parameterlist * self)
102 {
103  cpl_error_code err;
104  const char * context = PACKAGE "." RECIPE_STRING;
105 
106  /* --bkgcorrect */
107  err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
108  "bkgcorrect", CPL_TRUE, NULL, context,
109  "Cho-nod correct the data");
110  cpl_ensure_code(!err, err);
111 
112  /* --xl */
113  err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
114  "xl", 117, NULL, context,
115  "Coordinate in spatial direction. "
116  "Together with yl it defines the "
117  "lower point of a rectangle containing "
118  "only skylines for the "
119  "wavelength shift detection");
120  cpl_ensure_code(!err, err);
121 
122  /* --yl */
123  err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
124  "yl", 110, NULL, context,
125  "Coordinate in wavelength direction. "
126  "See xl");
127  cpl_ensure_code(!err, err);
128 
129  /* --xh */
130  err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
131  "xh", 125, NULL, context,
132  "Coordinate in spatial direction. "
133  "Together with yl it defines the "
134  "higher point of a rectangle containing "
135  "only skylines for the "
136  "wavelength shift detection");
137  cpl_ensure_code(!err, err);
138 
139  /* --yh */
140  err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
141  "yh", 150, NULL, context,
142  "Coordinate in wavelength direction. "
143  "See xh");
144  cpl_ensure_code(!err, err);
145 
146  return visir_parameter_set(self, RECIPE_STRING, VISIR_PARAM_SLITSKEW |
147  VISIR_PARAM_SPECSKEW | VISIR_PARAM_VERTARC |
148  VISIR_PARAM_HORIARC)
149  ? cpl_error_set_where(cpl_func) : CPL_ERROR_NONE;
150 }
151 
152 /*----------------------------------------------------------------------------*/
162 /*----------------------------------------------------------------------------*/
163 static void
164 shift_data(double * out, const double * in, size_t n, double shift)
165 {
166  /* FIXME: larger smoothing kernel would be better for this purpose */
167  if (shift < 0) {
168  out[0] = in[0];
169  for (size_t i = 1; i < n; i++)
170  out[i] = (in[i] - in[i - 1]) * shift + in[i];
171  }
172  else {
173  out[n - 1] = in[n - 1];
174  for (size_t i = 0; i < n - 1; i++)
175  out[i] = (in[i + 1] - in[i]) * shift + in[i];
176  }
177 }
178 
179 /*----------------------------------------------------------------------------*/
201 /*----------------------------------------------------------------------------*/
202 static double
203 get_grating_shift(const cpl_image * a, const cpl_image * b,
204  cpl_size xl, cpl_size yl, cpl_size xh, cpl_size yh)
205 {
206  cpl_image * aslice = cpl_image_extract(a, xl, yl, xh, yh);
207  cpl_image * bslice = cpl_image_extract(b, xl, yl, xh, yh);
208  const size_t n = yh - yl;
209  double adata[n];
210  double bdata[n];
211  cpl_vector * vb;
212  cpl_vector * va;
213  double minsum = DBL_MAX;
214  double best_shift = 0;
215  const int step = 5000;
216  /* +- shift search range */
217  const double range = 1;
218 
219  /* extract median of the rows */
220  for (size_t i = 0; i < n; i++) {
221  va = cpl_vector_new_from_image_row(aslice, i + 1);
222  vb = cpl_vector_new_from_image_row(bslice, i + 1);
223  adata[i] = cpl_vector_get_median(va);
224  bdata[i] = cpl_vector_get_median(vb);
225  cpl_vector_delete(va);
226  cpl_vector_delete(vb);
227  }
228  va = cpl_vector_wrap(n, adata);
229  vb = cpl_vector_wrap(n, bdata);
230  /* correct for intensity offsets */
231  cpl_vector_subtract_scalar(va, cpl_vector_get_median_const(va));
232  cpl_vector_subtract_scalar(vb, cpl_vector_get_median_const(vb));
233 
234  /* real subtraction */
235  cpl_vector_subtract(vb, va);
236 
237  /* FIXME: can be speed up by doing a coarse grain search first */
238  /* brute force search for the best shift */
239  for (int i = 0; i < step; i++) {
240  const double shift = (double)(i - (step / 2)) / step * range * 2;
241  double ashifted[n];
242  double sum = 0.;
243 
244  shift_data(ashifted, adata, n, shift);
245 
246  /* compare squared difference of shifted to real subtraction */
247  for (size_t j = 0; j < n; j++) {
248  const double tmp = (ashifted[j] - adata[j]) - bdata[j];
249  sum += tmp * tmp;
250  }
251 
252  if (sum < minsum) {
253  best_shift = shift;
254  minsum = sum;
255  }
256  }
257 
258  cpl_vector_unwrap(va);
259  cpl_vector_unwrap(vb);
260  cpl_image_delete(aslice);
261  cpl_image_delete(bslice);
262 
263  cpl_msg_info(cpl_func, "Grating shift: %.3f", best_shift);
264 
265  return best_shift;
266 }
267 
268 static void
269 vimglist_append(visir_imglist * a, visir_imglist * b)
270 {
271  for (cpl_size i = 0; i < visir_imglist_get_size(b); i++) {
272  visir_imglist_append(a, visir_imglist_get_img(b, i),
273  visir_imglist_get_data(b, i));
274  }
275  visir_imglist_unwrap(b, NULL);
276 }
277 
278 static visir_imglist *
279 load_images(cpl_frame * frame, const cpl_mask * bpm)
280 {
281  const int next = cpl_frame_get_nextensions(frame);
282  const char * filename = cpl_frame_get_filename(frame);
283  cpl_image * img = NULL;
284  visir_imglist * res = visir_imglist_new(next, NULL);
285 
286  for (int iext = 0; iext < next + 1; iext++) {
287  cpl_errorstate prestate = cpl_errorstate_get();
288 
289  img = cpl_image_load(filename, CPL_TYPE_FLOAT, 0, iext);
290  if (img == NULL) {
291  cpl_msg_debug(cpl_func, "No image-data in extension %d", iext);
292  cpl_errorstate_set(prestate);
293  continue;
294  }
295 
296  if (bpm != NULL) {
297  skip_if(cpl_image_reject_from_mask(img, bpm));
298  visir_interpolate_rejected(img, NULL, NULL);
299  }
300 
301  visir_imglist_append(res, img, NULL);
302  }
303 
304  end_skip;
305 
306  return res;
307 }
308 
309 
310 /*----------------------------------------------------------------------------*/
318 /*----------------------------------------------------------------------------*/
319 static cpl_error_code
320 overscan_correct(cpl_image * img)
321 {
322  const cpl_size nx = cpl_image_get_size_x(img);
323  const cpl_size ny = cpl_image_get_size_y(img);
324  for (cpl_size x = 1; x < nx + 1; x++) {
325  /* FIXME: remove hardcoding, maybe use window keys from fits */
326  cpl_image * top = cpl_image_extract(img, 1, ny - 7, nx, ny);
327  cpl_image * bot = cpl_image_extract(img, 1, 7, nx, 13);
328  cpl_vector * t = cpl_vector_new_from_image_column(top, x);
329  cpl_vector * b = cpl_vector_new_from_image_column(bot, x);
330  double topmed = cpl_vector_get_median(t);
331  double botmed = cpl_vector_get_median(b);
332  for (cpl_size y = 1; y < ny / 2 + 1; y++) {
333  int d;
334  cpl_image_set(img, x, y, cpl_image_get(img, x, y, &d) - botmed);
335  }
336  for (cpl_size y = ny / 2 + 1; y < ny + 1; y++) {
337  int d;
338  cpl_image_set(img, x, y, cpl_image_get(img, x, y, &d) - topmed);
339  }
340  cpl_vector_delete(t);
341  cpl_vector_delete(b);
342  cpl_image_delete(top);
343  cpl_image_delete(bot);
344  }
345 
346  return cpl_error_get_code();
347 }
348 
349 
350 static cpl_error_code
351 handle_images(visir_imglist * list, const cpl_image * base,
352  cpl_size xl, cpl_size yl, cpl_size xh, cpl_size yh,
353  double phi, double ksi, double eps, double delta,
354  const visir_data_type dtype)
355 {
356  const cpl_size n = visir_imglist_get_size(list);
357  const cpl_size nx = cpl_image_get_size_x(visir_imglist_get_img(list, 0));
358  const cpl_size ny = cpl_image_get_size_y(visir_imglist_get_img(list, 0));
359  error_if(xh > nx || yh > ny, CPL_ERROR_ILLEGAL_INPUT,
360  "Sky region %d/%d larger than image %d/%d", (int)xh, (int)yh,
361  (int)nx, (int)ny);
362 
363 #ifdef _OPENMP
364 #pragma omp parallel for
365 #endif
366  for (cpl_size i = 0; i < n; i++) {
367  cpl_image * img = visir_imglist_get_img(list, i);
368 
369  /* undistort only average for aquarius
370  * FIXME: correction required? */
371  if (visir_data_is_drs(dtype)) {
372  double shift = get_grating_shift(base, img, xl, yl, xh, yh);
373  visir_spc_det_warp(&img, 1, 0., shift, phi, ksi, eps, delta);
374  }
375  else
376  overscan_correct(img);
377  }
378 
379  end_skip;
380 
381  return cpl_error_get_code();
382 }
383 
384 
385 static cpl_error_code
386 save_images(visir_imglist * imgs, cpl_frameset * products,
387  cpl_frameset * usedframes, const cpl_propertylist * plist,
388  const cpl_parameterlist * parlist)
389 {
390  static int j = 0;
391  char * proname = cpl_sprintf(RECIPE_STRING "_%03d" CPL_DFS_FITS, j++);
392 
393  skip_if(irplib_dfs_save_propertylist(products, parlist, usedframes,
394  RECIPE_STRING,
395  VISIR_UTIL_UNDISTORT_PROCATG,
396  plist, NULL,
397  visir_pipe_id, proname));
398  for (cpl_size i = 0; i < visir_imglist_get_size(imgs); i++) {
399  cpl_image * img = visir_imglist_get_img(imgs, i);
400  cpl_image_save(img, proname, CPL_BPP_IEEE_FLOAT, NULL, CPL_IO_EXTEND);
401  }
402 
403  end_skip;
404  cpl_free(proname);
405 
406  return cpl_error_get_code();
407 }
408 
409 static inline int
410 comp_expno(cpl_frame * a, cpl_frame * b)
411 {
412  const char * fna = cpl_frame_get_filename(a);
413  const char * fnb = cpl_frame_get_filename(b);
414  cpl_propertylist * alist = cpl_propertylist_load(fna, 0);
415  cpl_propertylist * blist = cpl_propertylist_load(fnb, 0);
416 
417  int expa = cpl_propertylist_get_int(alist, "ESO TPL EXPNO");
418  int expb = cpl_propertylist_get_int(blist, "ESO TPL EXPNO");
419  int ret = 0;
420 
421  if (expa < expb)
422  ret = -1;
423  if (expa > expb)
424  ret = 1;
425 
426  cpl_propertylist_delete(alist);
427  cpl_propertylist_delete(blist);
428  return ret;
429 }
430 
431 static cx_list *
432 sort_framelist(irplib_framelist * allframes, const char * tag)
433 {
434  irplib_framelist * on =
435  irplib_framelist_extract_regexp(allframes, tag, CPL_FALSE);
436  cx_list * frames = cx_list_new();
437 
438  for (int i = irplib_framelist_get_size(on); i-- > 0;)
439  cx_list_push_back(frames, irplib_framelist_unset(on, i, NULL));
440 
441  /* FIXME: optimize */
442  cx_list_sort(frames, (cx_compare_func)comp_expno);
443 
445 
446  return frames;
447 }
448 
449 
450 cpl_error_code
451 check_rawframes(const irplib_framelist * rawframes,
452  cpl_propertylist * plist)
453 {
454  cpl_errorstate cleanstate = cpl_errorstate_get();
455  const char * dit_key = VISIR_PFITS_DOUBLE_DIT;
456  if (cpl_propertylist_has(plist, VISIR_PFITS_DOUBLE_SEQ1_DIT))
457  dit_key = VISIR_PFITS_DOUBLE_SEQ1_DIT;
458 
459  /* DIT must be present every where */
460  skip_if(irplib_framelist_contains(rawframes, dit_key,
461  CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
462  if(irplib_framelist_contains(rawframes, dit_key,
463  CPL_TYPE_DOUBLE, CPL_TRUE, 1e-5)) {
464  /* Allow 0.1 ms difference - or warn */
465  /* FIXME: The recipe does not properly handle non-uniform DITSs */
466  visir_error_reset("DIT differs by more than %g", 1e-5);
467  }
468 
469  /* FIXME: Verify the angular distance */
470  skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_DOUBLE_RA,
471  CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
472 
473  /* FIXME: Allow 1 degree difference */
474  skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_DOUBLE_DEC,
475  CPL_TYPE_DOUBLE, CPL_TRUE, 1.0));
476 
477  skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_INT_CHOP_NCYCLES,
478  CPL_TYPE_INT, CPL_TRUE, 0.0));
479 
480  skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_INT_NDIT,
481  CPL_TYPE_INT, CPL_TRUE, 0.0));
482 
483  if (irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_STARNAME,
484  CPL_TYPE_STRING, CPL_TRUE, 0.0)) {
485  visir_error_reset("Rawframe(s) missing standard star name");
486  }
487 
488  int nnod = irplib_framelist_get_size(rawframes);
489  /* frames not chop corrected, so divide the chop factor away again */
490  double exptime = visir_utils_get_exptime(nnod, plist) / 2.;
491  skip_if(0);
492 
493  cpl_propertylist_append_double(plist, "ESO QC EXPTIME", exptime);
494 
495  end_skip;
496 
497  return cpl_error_get_code();
498 }
499 
500 
501 static void update_exectime(const cpl_frame * frm, double * t_min_obsstart,
502  double * t_max_filewrite)
503 {
504  cpl_propertylist * plist = cpl_propertylist_load(cpl_frame_get_filename(frm), 0);
505  if (plist == NULL || !cpl_propertylist_has(plist, "ESO DRS DATE") ||
506  !cpl_propertylist_has(plist, "ESO DRS DATE-OBS")) {
507  return;
508  }
509  *t_max_filewrite =
510  CX_MAX(cpl_propertylist_get_double(plist, "ESO DRS DATE"),
511  *t_max_filewrite);
512  *t_min_obsstart =
513  CX_MIN(cpl_propertylist_get_double(plist, "ESO DRS DATE-OBS"),
514  *t_min_obsstart);
515 }
516 
517 /*----------------------------------------------------------------------------*/
524 /*----------------------------------------------------------------------------*/
525 static int visir_util_undistort(cpl_frameset * framelist,
526  const cpl_parameterlist * parlist)
527 {
528  cpl_errorstate cleanstate = cpl_errorstate_get();
529  const cpl_frame * bpmframe = cpl_frameset_find_const
530  (framelist, VISIR_CALIB_STATIC_MASK);
531  irplib_framelist * allframes = NULL;
532  irplib_framelist * rawframes = NULL;
533  irplib_framelist * rawframes_a = NULL;
534  irplib_framelist * rawframes_b = NULL;
535  cpl_image * imbpm = NULL;
536  cpl_mask * bpm = NULL;
537 
538 #ifdef _OPENMP
539  omp_set_num_threads(visir_get_num_threads(CPL_FALSE));
540 #endif
541 
542  const cpl_boolean bkgcorrect =
543  irplib_parameterlist_get_bool(parlist, PACKAGE,
544  RECIPE_STRING, "bkgcorrect");
545 
546  /* The angles are given in degrees and then converted to radians */
547 
548  double ksi = visir_parameterlist_get_double(parlist, RECIPE_STRING,
549  VISIR_PARAM_SPECSKEW)
550  * CPL_MATH_RAD_DEG;
551  double eps = visir_parameterlist_get_double(parlist, RECIPE_STRING,
552  VISIR_PARAM_VERTARC);
553  double delta = visir_parameterlist_get_double(parlist, RECIPE_STRING,
554  VISIR_PARAM_HORIARC);
555  double phi = visir_parameterlist_get_double(parlist, RECIPE_STRING,
556  VISIR_PARAM_SLITSKEW)
557  * CPL_MATH_RAD_DEG;
558 
559  const cpl_size xl = irplib_parameterlist_get_int(parlist, PACKAGE,
560  RECIPE_STRING, "xl");
561  const cpl_size yl = irplib_parameterlist_get_int(parlist, PACKAGE,
562  RECIPE_STRING, "yl");
563  const cpl_size xh = irplib_parameterlist_get_int(parlist, PACKAGE,
564  RECIPE_STRING, "xh");
565  const cpl_size yh = irplib_parameterlist_get_int(parlist, PACKAGE,
566  RECIPE_STRING, "yh");
567 
568  visir_imglist * aon = visir_imglist_new(100, NULL);
569  visir_imglist * aoff = visir_imglist_new(100, NULL);
570  visir_imglist * bon = visir_imglist_new(100, NULL);
571  visir_imglist * boff = visir_imglist_new(100, NULL);
572 
573  cpl_frameset * usedframes = cpl_frameset_new();
574  cpl_image * base = NULL;
575  cpl_propertylist * plist = NULL;
576  visir_spc_resol resol;
577  visir_data_type data_type;
578  double wlen;
579 
580  /* Identify the RAW and CALIB frames in the input frameset */
581  skip_if (visir_dfs_set_groups(framelist));
582 
583  error_if(xl < 1 || yl < 1, CPL_ERROR_ILLEGAL_INPUT,
584  "Sky region %d/%d must be larger than 1", (int)xl, (int)yl);
585 
586  /* Objects observation */
587  allframes = irplib_framelist_cast(framelist);
588  skip_if(allframes == NULL);
589 
590  rawframes = irplib_framelist_extract_regexp(allframes, "^("
591  VISIR_UTIL_REPACK_A_ON_PROCATG "|"
592  VISIR_UTIL_REPACK_A_OFF_PROCATG "|"
593  VISIR_UTIL_REPACK_B_ON_PROCATG "|"
594  VISIR_UTIL_REPACK_B_OFF_PROCATG
595  ")$", CPL_FALSE);
596  skip_if(irplib_framelist_load_propertylist_all(rawframes, 0, ".*", 0));
597  plist = irplib_framelist_get_propertylist(rawframes, 0);
598  skip_if(check_rawframes(rawframes, plist));
599 
600  {
601  double pslitw, ptemp, pfwhm;
602  const cpl_frame * frm = irplib_framelist_get_const(rawframes, 0);
603  skip_if(visir_get_data_type(frm, plist, &data_type, NULL));
604  resol = visir_spc_get_res_wl(rawframes, &wlen, &pslitw, &ptemp, &pfwhm,
605  visir_data_is_aqu(data_type));
606  skip_if(0);
607  }
608 
609  if (visir_data_is_drs(data_type)) {
610  /* if parameters are (aqu) defaults and drs data use old parameters */
611  const cpl_parameter * par =
612  cpl_parameterlist_find_const(parlist, PACKAGE "." RECIPE_STRING ".ksi");
613  if (ksi == cpl_parameter_get_default_double(par) * CPL_MATH_RAD_DEG) {
614  ksi = VISIR_DRS_DIST_KSI;
615  }
616  par = cpl_parameterlist_find_const(parlist, PACKAGE "." RECIPE_STRING ".eps");
617  if (eps == cpl_parameter_get_default_double(par)) {
618  eps = VISIR_DRS_DIST_EPS;
619  }
620  par = cpl_parameterlist_find_const(parlist, PACKAGE "." RECIPE_STRING ".delta");
621  if (delta == cpl_parameter_get_default_double(par)) {
622  delta = VISIR_DRS_DIST_DELTA;
623  }
624  par = cpl_parameterlist_find_const(parlist, PACKAGE "." RECIPE_STRING ".phi");
625  if (phi == cpl_parameter_get_default_double(par) * CPL_MATH_RAD_DEG) {
626  phi = VISIR_DRS_DIST_PHI;
627  }
628  }
629 
630  rawframes_a = irplib_framelist_extract_regexp(allframes, "^("
631  VISIR_UTIL_REPACK_A_ON_PROCATG "|"
632  VISIR_UTIL_REPACK_A_OFF_PROCATG
633  ")$", CPL_FALSE);
634  cpl_errorstate_set(cleanstate);
635 
636  rawframes_b = irplib_framelist_extract_regexp(allframes, "^("
637  VISIR_UTIL_REPACK_B_ON_PROCATG "|"
638  VISIR_UTIL_REPACK_B_OFF_PROCATG
639  ")$", CPL_FALSE);
640  cpl_errorstate_set(cleanstate);
641 
642  error_if (rawframes_a == NULL && rawframes_b == NULL,
643  CPL_ERROR_DATA_NOT_FOUND, "No frames with tags "
644  VISIR_UTIL_REPACK_A_ON_PROCATG "|"
645  VISIR_UTIL_REPACK_A_OFF_PROCATG "|"
646  VISIR_UTIL_REPACK_B_ON_PROCATG "|"
647  VISIR_UTIL_REPACK_B_OFF_PROCATG " found");
648 
649  if (bpmframe != NULL) {
650  /* Load any static mask here to avoid that the file is loaded
651  multiple times */
652  const char * badpix = cpl_frame_get_filename(bpmframe);
653 
654 
655  bpm = cpl_mask_load(badpix, 0, 0);
656  skip_if (bpm == NULL);
657  }
658  double t_min_obsstart = 1e300;
659  double t_max_filewrite = 0;
660 
661  if (rawframes_a) {
662  cx_list * on_frames = sort_framelist(rawframes_a, "^("
663  VISIR_UTIL_REPACK_A_ON_PROCATG
664  ")$");
665  cx_list * off_frames = sort_framelist(rawframes_a, "^("
666  VISIR_UTIL_REPACK_A_OFF_PROCATG
667  ")$");
668  FOR_EACH_T(cpl_frame * frm, on_frames) {
669  update_exectime(frm, &t_min_obsstart, &t_max_filewrite);
670  vimglist_append(aon, load_images(frm, bpm));
671  cpl_frame_set_group(frm, CPL_FRAME_GROUP_RAW);
672  cpl_frameset_insert(usedframes, cpl_frame_duplicate(frm));
673  }
674  FOR_EACH_T(cpl_frame * frm, off_frames) {
675  update_exectime(frm, &t_min_obsstart, &t_max_filewrite);
676  vimglist_append(aoff, load_images(frm, bpm));
677  cpl_frame_set_group(frm, CPL_FRAME_GROUP_RAW);
678  cpl_frameset_insert(usedframes, cpl_frame_duplicate(frm));
679  }
680 
681  base = cpl_image_duplicate(visir_imglist_get_img(aoff, 0));
682  if (visir_data_is_aqu(data_type))
683  overscan_correct(base);
684  skip_if(handle_images(aon, base, xl, yl, xh, yh,
685  phi, ksi, eps, delta, data_type));
686  skip_if(handle_images(aoff, base, xl, yl, xh, yh,
687  phi, ksi, eps, delta, data_type));
688  }
689  if (rawframes_b){
690  cx_list * on_frames = sort_framelist(rawframes_b, "^("
691  VISIR_UTIL_REPACK_B_ON_PROCATG
692  ")$");
693  cx_list * off_frames = sort_framelist(rawframes_b, "^("
694  VISIR_UTIL_REPACK_B_OFF_PROCATG
695  ")$");
696  FOR_EACH_T(cpl_frame * frm, on_frames) {
697  update_exectime(frm, &t_min_obsstart, &t_max_filewrite);
698  vimglist_append(bon, load_images(frm, bpm));
699  cpl_frame_set_group(frm, CPL_FRAME_GROUP_RAW);
700  cpl_frameset_insert(usedframes, cpl_frame_duplicate(frm));
701  }
702  FOR_EACH_T(cpl_frame * frm, off_frames) {
703  update_exectime(frm, &t_min_obsstart, &t_max_filewrite);
704  vimglist_append(boff, load_images(frm, bpm));
705  cpl_frame_set_group(frm, CPL_FRAME_GROUP_RAW);
706  cpl_frameset_insert(usedframes, cpl_frame_duplicate(frm));
707  }
708  if (base == NULL) {
709  base = cpl_image_duplicate(visir_imglist_get_img(boff, 0));
710  if (visir_data_is_aqu(data_type))
711  overscan_correct(base);
712  }
713 
714  skip_if(handle_images(bon, base, xl, yl, xh, yh,
715  phi, ksi, eps, delta, data_type));
716  skip_if(handle_images(boff, base, xl, yl, xh, yh,
717  phi, ksi, eps, delta, data_type));
718  }
719 
720  if (bkgcorrect && rawframes_a && rawframes_b) {
721  cpl_imagelist * laon = visir_imglist_get_imglist(aon);
722  cpl_imagelist * laoff = visir_imglist_get_imglist(aoff);
723  cpl_imagelist_subtract(laon, laoff);
724 
725  cpl_imagelist * lbon = visir_imglist_get_imglist(bon);
726  cpl_imagelist * lboff = visir_imglist_get_imglist(boff);
727  cpl_imagelist_subtract(lbon, lboff);
728 
729  cpl_imagelist_subtract(laon, lbon);
730 
731  visir_imglist * l = visir_imglist_new(100, NULL);
732 
733  {
734  cpl_image * img = cpl_imagelist_collapse_create(laon);
735  cpl_image * flipped;
736  const cpl_size nx = cpl_image_get_size_x(img);
737  const cpl_size ny = cpl_image_get_size_y(img);
738 
739  if (resol == VISIR_SPC_R_LRP) {
740  /* remove unilluminated parts that disturb wcal */
741  /* FIXME: remove hardcoding ? */
742  flipped = cpl_image_extract(img, 30, 25, nx - 30, ny - 25);
743  cpl_image_delete(img);
744  img = flipped;
745  /* FIXME: assumes center is in middle */
746  visir_spc_det_warp(&img, 1, 0., 0., phi, ksi, eps, delta);
747  }
748  flipped = visir_spc_flip(img, wlen, resol, data_type);
749  cpl_image_delete(img);
750  img = flipped;
751 
752  visir_imglist_append(l, img, NULL);
753  }
754 
755  cpl_propertylist_append_double(plist, "ESO QC EXECTIME",
756  (t_max_filewrite - t_min_obsstart) * 24 * 3600);
757  save_images(l, framelist, usedframes, plist, parlist);
758  visir_imglist_delete(l, NULL);
759  skip_if(0);
760  }
761  else {
762  bug_if(bkgcorrect); /* FIXME */
763  save_images(aon, framelist, usedframes, plist, parlist);
764  save_images(aoff, framelist, usedframes, plist, parlist);
765  save_images(bon, framelist, usedframes, plist, parlist);
766  save_images(boff, framelist, usedframes, plist, parlist);
767  }
768 
769  {
770  /* remove unilluminated parts that disturb wcal */
771  /* FIXME: remove hardcoding ? */
772  cpl_image * flipped;
773  const cpl_size nx = cpl_image_get_size_x(base);
774  const cpl_size ny = cpl_image_get_size_y(base);
775 
776  if (resol == VISIR_SPC_R_LRP) {
777  flipped = cpl_image_extract(base, 30, 25, nx - 30, ny - 25);
778  cpl_image_delete(base);
779  base = flipped;
780  }
781  skip_if(visir_spc_det_warp(&base, 1, 0., 0., phi, ksi, eps, delta));
782  flipped = visir_spc_flip(base, wlen, resol, data_type);
783  cpl_image_delete(base);
784  base = flipped;
785  }
786  skip_if(irplib_dfs_save_image(framelist, parlist, usedframes,
787  base, CPL_TYPE_UNSPECIFIED,
788  RECIPE_STRING,
789  "SPEC_OBS_LMR_SKYFRAME", NULL, NULL,
790  visir_pipe_id, "skyframe.fits"));
791 
792  end_skip;
793 
794  irplib_framelist_delete(allframes);
795  irplib_framelist_delete(rawframes);
796  irplib_framelist_delete(rawframes_a);
797  irplib_framelist_delete(rawframes_b);
798  cpl_image_delete(imbpm);
799  cpl_mask_delete(bpm);
800  cpl_image_delete(base);
801  visir_imglist_delete(aon, NULL);
802  visir_imglist_delete(aoff, NULL);
803  visir_imglist_delete(bon, NULL);
804  visir_imglist_delete(boff, NULL);
805  cpl_frameset_delete(usedframes);
806 
807  return cpl_error_get_code();
808 }
double visir_parameterlist_get_double(const cpl_parameterlist *self, const char *recipe, visir_parameter bitmask)
Retrieve the value of a VISIR parameter of type double.
cpl_error_code visir_parameter_set(cpl_parameterlist *self, const char *recipe, visir_parameter bitmask)
Define the specified parameters.
cpl_error_code irplib_dfs_save_propertylist(cpl_frameset *allframes, const cpl_parameterlist *parlist, const cpl_frameset *usedframes, const char *recipe, const char *procat, const cpl_propertylist *applist, const char *remregexp, const char *pipe_id, const char *filename)
Save a propertylist as a DFS-compliant pipeline product.
Definition: irplib_utils.c:240
irplib_framelist * irplib_framelist_extract_regexp(const irplib_framelist *self, const char *regexp, cpl_boolean invert)
Extract the frames with the given tag from a framelist.
cpl_error_code irplib_dfs_save_image(cpl_frameset *allframes, const cpl_parameterlist *parlist, const cpl_frameset *usedframes, const cpl_image *image, cpl_type_bpp bpp, const char *recipe, const char *procat, const cpl_propertylist *applist, const char *remregexp, const char *pipe_id, const char *filename)
Save an image as a DFS-compliant pipeline product.
Definition: irplib_utils.c:192
cpl_error_code irplib_framelist_load_propertylist_all(irplib_framelist *self, int ind, const char *regexp, cpl_boolean invert)
Load the propertylists of all frames in the framelist.
cpl_frame * irplib_framelist_unset(irplib_framelist *self, int pos, cpl_propertylist **plist)
Erase a frame from a framelist and return it to the caller.
int visir_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
Definition: visir_dfs.c:72
const cpl_frame * irplib_framelist_get_const(const irplib_framelist *self, int pos)
Get the specified frame from the framelist.
void irplib_framelist_delete(irplib_framelist *self)
Deallocate an irplib_framelist with its frames and properties.
cpl_error_code irplib_framelist_contains(const irplib_framelist *self, const char *key, cpl_type type, cpl_boolean is_equal, double fp_tol)
Verify that a property is present for all frames.
cpl_propertylist * irplib_framelist_get_propertylist(irplib_framelist *self, int pos)
Get the propertylist of the specified frame in the framelist.
irplib_framelist * irplib_framelist_cast(const cpl_frameset *frameset)
Create an irplib_framelist from a cpl_framelist.
int irplib_framelist_get_size(const irplib_framelist *self)
Get the size of a framelist.