VISIR Pipeline Reference Manual  4.1.7
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  cpl_propertylist_delete(plist);
508  return;
509  }
510  *t_max_filewrite =
511  CX_MAX(cpl_propertylist_get_double(plist, "ESO DRS DATE"),
512  *t_max_filewrite);
513  *t_min_obsstart =
514  CX_MIN(cpl_propertylist_get_double(plist, "ESO DRS DATE-OBS"),
515  *t_min_obsstart);
516  cpl_propertylist_delete(plist);
517 }
518 
519 /*----------------------------------------------------------------------------*/
526 /*----------------------------------------------------------------------------*/
527 static int visir_util_undistort(cpl_frameset * framelist,
528  const cpl_parameterlist * parlist)
529 {
530  cpl_errorstate cleanstate = cpl_errorstate_get();
531  const cpl_frame * bpmframe = cpl_frameset_find_const
532  (framelist, VISIR_CALIB_STATIC_MASK);
533  irplib_framelist * allframes = NULL;
534  irplib_framelist * rawframes = NULL;
535  irplib_framelist * rawframes_a = NULL;
536  irplib_framelist * rawframes_b = NULL;
537  cpl_image * imbpm = NULL;
538  cpl_mask * bpm = NULL;
539 
540 #ifdef _OPENMP
541  omp_set_num_threads(visir_get_num_threads(CPL_FALSE));
542 #endif
543 
544  const cpl_boolean bkgcorrect =
545  irplib_parameterlist_get_bool(parlist, PACKAGE,
546  RECIPE_STRING, "bkgcorrect");
547 
548  /* The angles are given in degrees and then converted to radians */
549 
550  double ksi = visir_parameterlist_get_double(parlist, RECIPE_STRING,
551  VISIR_PARAM_SPECSKEW)
552  * CPL_MATH_RAD_DEG;
553  double eps = visir_parameterlist_get_double(parlist, RECIPE_STRING,
554  VISIR_PARAM_VERTARC);
555  double delta = visir_parameterlist_get_double(parlist, RECIPE_STRING,
556  VISIR_PARAM_HORIARC);
557  double phi = visir_parameterlist_get_double(parlist, RECIPE_STRING,
558  VISIR_PARAM_SLITSKEW)
559  * CPL_MATH_RAD_DEG;
560 
561  const cpl_size xl = irplib_parameterlist_get_int(parlist, PACKAGE,
562  RECIPE_STRING, "xl");
563  const cpl_size yl = irplib_parameterlist_get_int(parlist, PACKAGE,
564  RECIPE_STRING, "yl");
565  const cpl_size xh = irplib_parameterlist_get_int(parlist, PACKAGE,
566  RECIPE_STRING, "xh");
567  const cpl_size yh = irplib_parameterlist_get_int(parlist, PACKAGE,
568  RECIPE_STRING, "yh");
569 
570  visir_imglist * aon = visir_imglist_new(100, NULL);
571  visir_imglist * aoff = visir_imglist_new(100, NULL);
572  visir_imglist * bon = visir_imglist_new(100, NULL);
573  visir_imglist * boff = visir_imglist_new(100, NULL);
574 
575  cpl_frameset * usedframes = cpl_frameset_new();
576  cpl_image * base = NULL;
577  cpl_propertylist * plist = NULL;
578  visir_spc_resol resol;
579  visir_data_type data_type;
580  double wlen;
581 
582  /* Identify the RAW and CALIB frames in the input frameset */
583  skip_if (visir_dfs_set_groups(framelist));
584 
585  error_if(xl < 1 || yl < 1, CPL_ERROR_ILLEGAL_INPUT,
586  "Sky region %d/%d must be larger than 1", (int)xl, (int)yl);
587 
588  /* Objects observation */
589  allframes = irplib_framelist_cast(framelist);
590  skip_if(allframes == NULL);
591 
592  rawframes = irplib_framelist_extract_regexp(allframes, "^("
593  VISIR_UTIL_REPACK_A_ON_PROCATG "|"
594  VISIR_UTIL_REPACK_A_OFF_PROCATG "|"
595  VISIR_UTIL_REPACK_B_ON_PROCATG "|"
596  VISIR_UTIL_REPACK_B_OFF_PROCATG
597  ")$", CPL_FALSE);
598  skip_if(irplib_framelist_load_propertylist_all(rawframes, 0, ".*", 0));
599  plist = irplib_framelist_get_propertylist(rawframes, 0);
600  skip_if(check_rawframes(rawframes, plist));
601 
602  {
603  double pslitw, ptemp, pfwhm;
604  const cpl_frame * frm = irplib_framelist_get_const(rawframes, 0);
605  skip_if(visir_get_data_type(frm, plist, &data_type, NULL));
606  resol = visir_spc_get_res_wl(rawframes, &wlen, &pslitw, &ptemp, &pfwhm,
607  visir_data_is_aqu(data_type));
608  skip_if(0);
609  }
610 
611  if (visir_data_is_drs(data_type)) {
612  /* if parameters are (aqu) defaults and drs data use old parameters */
613  const cpl_parameter * par =
614  cpl_parameterlist_find_const(parlist, PACKAGE "." RECIPE_STRING ".ksi");
615  if (ksi == cpl_parameter_get_default_double(par) * CPL_MATH_RAD_DEG) {
616  ksi = VISIR_DRS_DIST_KSI;
617  }
618  par = cpl_parameterlist_find_const(parlist, PACKAGE "." RECIPE_STRING ".eps");
619  if (eps == cpl_parameter_get_default_double(par)) {
620  eps = VISIR_DRS_DIST_EPS;
621  }
622  par = cpl_parameterlist_find_const(parlist, PACKAGE "." RECIPE_STRING ".delta");
623  if (delta == cpl_parameter_get_default_double(par)) {
624  delta = VISIR_DRS_DIST_DELTA;
625  }
626  par = cpl_parameterlist_find_const(parlist, PACKAGE "." RECIPE_STRING ".phi");
627  if (phi == cpl_parameter_get_default_double(par) * CPL_MATH_RAD_DEG) {
628  phi = VISIR_DRS_DIST_PHI;
629  }
630  }
631 
632  rawframes_a = irplib_framelist_extract_regexp(allframes, "^("
633  VISIR_UTIL_REPACK_A_ON_PROCATG "|"
634  VISIR_UTIL_REPACK_A_OFF_PROCATG
635  ")$", CPL_FALSE);
636  cpl_errorstate_set(cleanstate);
637 
638  rawframes_b = irplib_framelist_extract_regexp(allframes, "^("
639  VISIR_UTIL_REPACK_B_ON_PROCATG "|"
640  VISIR_UTIL_REPACK_B_OFF_PROCATG
641  ")$", CPL_FALSE);
642  cpl_errorstate_set(cleanstate);
643 
644  error_if (rawframes_a == NULL && rawframes_b == NULL,
645  CPL_ERROR_DATA_NOT_FOUND, "No frames with tags "
646  VISIR_UTIL_REPACK_A_ON_PROCATG "|"
647  VISIR_UTIL_REPACK_A_OFF_PROCATG "|"
648  VISIR_UTIL_REPACK_B_ON_PROCATG "|"
649  VISIR_UTIL_REPACK_B_OFF_PROCATG " found");
650 
651  if (bpmframe != NULL) {
652  /* Load any static mask here to avoid that the file is loaded
653  multiple times */
654  const char * badpix = cpl_frame_get_filename(bpmframe);
655 
656 
657  bpm = cpl_mask_load(badpix, 0, 0);
658  skip_if (bpm == NULL);
659  }
660  double t_min_obsstart = 1e300;
661  double t_max_filewrite = 0;
662 
663  if (rawframes_a) {
664  cx_list * on_frames = sort_framelist(rawframes_a, "^("
665  VISIR_UTIL_REPACK_A_ON_PROCATG
666  ")$");
667  cx_list * off_frames = sort_framelist(rawframes_a, "^("
668  VISIR_UTIL_REPACK_A_OFF_PROCATG
669  ")$");
670  FOR_EACH_T(cpl_frame * frm, on_frames) {
671  update_exectime(frm, &t_min_obsstart, &t_max_filewrite);
672  vimglist_append(aon, load_images(frm, bpm));
673  cpl_frame_set_group(frm, CPL_FRAME_GROUP_RAW);
674  cpl_frameset_insert(usedframes, cpl_frame_duplicate(frm));
675  }
676  cx_list_destroy(on_frames, (visir_free)cpl_frame_delete);
677  FOR_EACH_T(cpl_frame * frm, off_frames) {
678  update_exectime(frm, &t_min_obsstart, &t_max_filewrite);
679  vimglist_append(aoff, load_images(frm, bpm));
680  cpl_frame_set_group(frm, CPL_FRAME_GROUP_RAW);
681  cpl_frameset_insert(usedframes, cpl_frame_duplicate(frm));
682  }
683  cx_list_destroy(off_frames, (visir_free)cpl_frame_delete);
684 
685  base = cpl_image_duplicate(visir_imglist_get_img(aoff, 0));
686  if (visir_data_is_aqu(data_type))
687  overscan_correct(base);
688  skip_if(handle_images(aon, base, xl, yl, xh, yh,
689  phi, ksi, eps, delta, data_type));
690  skip_if(handle_images(aoff, base, xl, yl, xh, yh,
691  phi, ksi, eps, delta, data_type));
692  }
693  if (rawframes_b){
694  cx_list * on_frames = sort_framelist(rawframes_b, "^("
695  VISIR_UTIL_REPACK_B_ON_PROCATG
696  ")$");
697  cx_list * off_frames = sort_framelist(rawframes_b, "^("
698  VISIR_UTIL_REPACK_B_OFF_PROCATG
699  ")$");
700  FOR_EACH_T(cpl_frame * frm, on_frames) {
701  update_exectime(frm, &t_min_obsstart, &t_max_filewrite);
702  vimglist_append(bon, load_images(frm, bpm));
703  cpl_frame_set_group(frm, CPL_FRAME_GROUP_RAW);
704  cpl_frameset_insert(usedframes, cpl_frame_duplicate(frm));
705  }
706  cx_list_destroy(on_frames, (visir_free)cpl_frame_delete);
707  FOR_EACH_T(cpl_frame * frm, off_frames) {
708  update_exectime(frm, &t_min_obsstart, &t_max_filewrite);
709  vimglist_append(boff, load_images(frm, bpm));
710  cpl_frame_set_group(frm, CPL_FRAME_GROUP_RAW);
711  cpl_frameset_insert(usedframes, cpl_frame_duplicate(frm));
712  }
713  cx_list_destroy(off_frames, (visir_free)cpl_frame_delete);
714 
715  if (base == NULL) {
716  base = cpl_image_duplicate(visir_imglist_get_img(boff, 0));
717  if (visir_data_is_aqu(data_type))
718  overscan_correct(base);
719  }
720 
721  skip_if(handle_images(bon, base, xl, yl, xh, yh,
722  phi, ksi, eps, delta, data_type));
723  skip_if(handle_images(boff, base, xl, yl, xh, yh,
724  phi, ksi, eps, delta, data_type));
725  }
726 
727  if (bkgcorrect && rawframes_a && rawframes_b) {
728  cpl_imagelist * laon = visir_imglist_get_imglist(aon);
729  cpl_imagelist * laoff = visir_imglist_get_imglist(aoff);
730  cpl_imagelist_subtract(laon, laoff);
731 
732  cpl_imagelist * lbon = visir_imglist_get_imglist(bon);
733  cpl_imagelist * lboff = visir_imglist_get_imglist(boff);
734  cpl_imagelist_subtract(lbon, lboff);
735 
736  cpl_imagelist_subtract(laon, lbon);
737 
738  visir_imglist * l = visir_imglist_new(100, NULL);
739 
740  {
741  cpl_image * img = cpl_imagelist_collapse_create(laon);
742  cpl_image * flipped;
743  const cpl_size nx = cpl_image_get_size_x(img);
744  const cpl_size ny = cpl_image_get_size_y(img);
745 
746  if (resol == VISIR_SPC_R_LRP) {
747  /* remove unilluminated parts that disturb wcal */
748  /* FIXME: remove hardcoding ? */
749  flipped = cpl_image_extract(img, 30, 25, nx - 30, ny - 25);
750  cpl_image_delete(img);
751  img = flipped;
752  /* FIXME: assumes center is in middle */
753  visir_spc_det_warp(&img, 1, 0., 0., phi, ksi, eps, delta);
754  }
755  flipped = visir_spc_flip(img, wlen, resol, data_type);
756  cpl_image_delete(img);
757  img = flipped;
758 
759  visir_imglist_append(l, img, NULL);
760  }
761 
762  cpl_propertylist_append_double(plist, "ESO QC EXECTIME",
763  (t_max_filewrite - t_min_obsstart) * 24 * 3600);
764  save_images(l, framelist, usedframes, plist, parlist);
765  visir_imglist_delete(l, NULL);
766  skip_if(0);
767  }
768  else {
769  bug_if(bkgcorrect); /* FIXME */
770  save_images(aon, framelist, usedframes, plist, parlist);
771  save_images(aoff, framelist, usedframes, plist, parlist);
772  save_images(bon, framelist, usedframes, plist, parlist);
773  save_images(boff, framelist, usedframes, plist, parlist);
774  }
775 
776  {
777  /* remove unilluminated parts that disturb wcal */
778  /* FIXME: remove hardcoding ? */
779  cpl_image * flipped;
780  const cpl_size nx = cpl_image_get_size_x(base);
781  const cpl_size ny = cpl_image_get_size_y(base);
782 
783  if (resol == VISIR_SPC_R_LRP) {
784  flipped = cpl_image_extract(base, 30, 25, nx - 30, ny - 25);
785  cpl_image_delete(base);
786  base = flipped;
787  }
788  skip_if(visir_spc_det_warp(&base, 1, 0., 0., phi, ksi, eps, delta));
789  flipped = visir_spc_flip(base, wlen, resol, data_type);
790  cpl_image_delete(base);
791  base = flipped;
792  }
793  skip_if(irplib_dfs_save_image(framelist, parlist, usedframes,
794  base, CPL_TYPE_UNSPECIFIED,
795  RECIPE_STRING,
796  "SPEC_OBS_LMR_SKYFRAME", NULL, NULL,
797  visir_pipe_id, "skyframe.fits"));
798 
799  end_skip;
800 
801  irplib_framelist_delete(allframes);
802  irplib_framelist_delete(rawframes);
803  irplib_framelist_delete(rawframes_a);
804  irplib_framelist_delete(rawframes_b);
805  cpl_image_delete(imbpm);
806  cpl_mask_delete(bpm);
807  cpl_image_delete(base);
808  visir_imglist_delete(aon, NULL);
809  visir_imglist_delete(aoff, NULL);
810  visir_imglist_delete(bon, NULL);
811  visir_imglist_delete(boff, NULL);
812  cpl_frameset_delete(usedframes);
813 
814  return cpl_error_get_code();
815 }
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.